diff --git a/src/db/models/two_factor.rs b/src/db/models/two_factor.rs index ff353ac2..530e35b4 100644 --- a/src/db/models/two_factor.rs +++ b/src/db/models/two_factor.rs @@ -147,4 +147,73 @@ impl TwoFactor { .map_res("Error deleting twofactors") }} } + + pub async fn migrate_u2f_to_webauthn(conn: &mut DbConn) -> EmptyResult { + let u2f_factors = db_run! { conn: { + twofactor::table + .filter(twofactor::atype.eq(TwoFactorType::U2f as i32)) + .load::(conn) + .expect("Error loading twofactor") + .from_db() + }}; + + use crate::api::core::two_factor::webauthn::U2FRegistration; + use crate::api::core::two_factor::webauthn::{get_webauthn_registrations, WebauthnRegistration}; + use webauthn_rs::proto::*; + + for mut u2f in u2f_factors { + let mut regs: Vec = serde_json::from_str(&u2f.data)?; + // If there are no registrations or they are migrated (we do the migration in batch so we can consider them all migrated when the first one is) + if regs.is_empty() || regs[0].migrated == Some(true) { + continue; + } + + let (_, mut webauthn_regs) = get_webauthn_registrations(&u2f.user_uuid, conn).await?; + + // If the user already has webauthn registrations saved, don't overwrite them + if !webauthn_regs.is_empty() { + continue; + } + + for reg in &mut regs { + let x: [u8; 32] = reg.reg.pub_key[1..33].try_into().unwrap(); + let y: [u8; 32] = reg.reg.pub_key[33..65].try_into().unwrap(); + + let key = COSEKey { + type_: COSEAlgorithm::ES256, + key: COSEKeyType::EC_EC2(COSEEC2Key { + curve: ECDSACurve::SECP256R1, + x, + y, + }), + }; + + let new_reg = WebauthnRegistration { + id: reg.id, + migrated: true, + name: reg.name.clone(), + credential: Credential { + counter: reg.counter, + verified: false, + cred: key, + cred_id: reg.reg.key_handle.clone(), + registration_policy: UserVerificationPolicy::Discouraged, + }, + }; + + webauthn_regs.push(new_reg); + + reg.migrated = Some(true); + } + + u2f.data = serde_json::to_string(®s)?; + u2f.save(conn).await?; + + TwoFactor::new(u2f.user_uuid.clone(), TwoFactorType::Webauthn, serde_json::to_string(&webauthn_regs)?) + .save(conn) + .await?; + } + + Ok(()) + } } diff --git a/src/main.rs b/src/main.rs index f9fc68ff..7b8bf37a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -88,6 +88,7 @@ async fn main() -> Result<(), Error> { let pool = create_db_pool().await; schedule_jobs(pool.clone()); + crate::db::models::TwoFactor::migrate_u2f_to_webauthn(&mut pool.get().await.unwrap()).await.unwrap(); launch_rocket(pool, extra_debug).await // Blocks until program termination. }