mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-06-18 09:20:08 +00:00
add basic migration impl
This commit is contained in:
parent
cbf9a2a519
commit
17385f0fd9
2 changed files with 59 additions and 9 deletions
|
@ -133,12 +133,15 @@ async fn generate_webauthn_challenge(data: Json<PasswordOrOtpData>, headers: Hea
|
||||||
Some(registrations),
|
Some(registrations),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// TODO is there a nicer way to do this?
|
|
||||||
// this is done since `start_passkey_registration()` always sets this to `Required` which shouldn't be needed for 2FA
|
// this is done since `start_passkey_registration()` always sets this to `Required` which shouldn't be needed for 2FA
|
||||||
challenge.public_key.authenticator_selection = challenge.public_key.authenticator_selection.map(|mut a| {
|
challenge.public_key.extensions = None;
|
||||||
a.user_verification = UserVerificationPolicy::Discouraged_DO_NOT_USE;
|
if let Some(asc) = challenge.public_key.authenticator_selection.as_mut() {
|
||||||
a
|
asc.user_verification = UserVerificationPolicy::Discouraged_DO_NOT_USE;
|
||||||
});
|
}
|
||||||
|
|
||||||
|
let mut state = serde_json::to_value(&state)?;
|
||||||
|
state["rs"]["policy"] = Value::String("discouraged".to_string());
|
||||||
|
state["rs"]["extensions"].as_object_mut().unwrap().clear();
|
||||||
|
|
||||||
let type_ = TwoFactorType::WebauthnRegisterChallenge;
|
let type_ = TwoFactorType::WebauthnRegisterChallenge;
|
||||||
TwoFactor::new(user.uuid.clone(), type_, serde_json::to_string(&state)?).save(&mut conn).await?;
|
TwoFactor::new(user.uuid.clone(), type_, serde_json::to_string(&state)?).save(&mut conn).await?;
|
||||||
|
@ -368,10 +371,12 @@ pub async fn generate_webauthn_login(user_id: &UserId, webauthn: Webauthn2FaConf
|
||||||
|
|
||||||
// Generate a challenge based on the credentials
|
// Generate a challenge based on the credentials
|
||||||
let (mut response, state) = webauthn.start_passkey_authentication(&creds)?;
|
let (mut response, state) = webauthn.start_passkey_authentication(&creds)?;
|
||||||
response.public_key.user_verification = UserVerificationPolicy::Discouraged_DO_NOT_USE;
|
|
||||||
|
|
||||||
// TODO does the appid extension matter? As far as I understand, this was only put into the authentication state anyway
|
// Modify to discourage user verification
|
||||||
// let ext = RequestAuthenticationExtensions::builder().appid(format!("{}/app-id.json", &CONFIG.domain())).build();
|
let mut state = serde_json::to_value(&state)?;
|
||||||
|
state["ast"]["policy"] = Value::String("discouraged".to_string());
|
||||||
|
state["ast"]["appid"] = Value::String(format!("{}/app-id.json", &CONFIG.domain()));
|
||||||
|
response.public_key.user_verification = UserVerificationPolicy::Discouraged_DO_NOT_USE;
|
||||||
|
|
||||||
// Save the challenge state for later validation
|
// Save the challenge state for later validation
|
||||||
TwoFactor::new(user_id.clone(), TwoFactorType::WebauthnLoginChallenge, serde_json::to_string(&state)?)
|
TwoFactor::new(user_id.clone(), TwoFactorType::WebauthnLoginChallenge, serde_json::to_string(&state)?)
|
||||||
|
|
|
@ -3,6 +3,7 @@ use webauthn_rs::prelude::{Credential, ParsedAttestation};
|
||||||
use webauthn_rs_proto::{AttestationFormat, RegisteredExtensions};
|
use webauthn_rs_proto::{AttestationFormat, RegisteredExtensions};
|
||||||
use super::UserId;
|
use super::UserId;
|
||||||
use crate::{api::EmptyResult, db::DbConn, error::MapResult};
|
use crate::{api::EmptyResult, db::DbConn, error::MapResult};
|
||||||
|
use crate::api::core::two_factor::webauthn::WebauthnRegistration;
|
||||||
|
|
||||||
db_object! {
|
db_object! {
|
||||||
#[derive(Identifiable, Queryable, Insertable, AsChangeset)]
|
#[derive(Identifiable, Queryable, Insertable, AsChangeset)]
|
||||||
|
@ -45,7 +46,27 @@ mod webauthn_0_3 {
|
||||||
use webauthn_rs::prelude::ParsedAttestation;
|
use webauthn_rs::prelude::ParsedAttestation;
|
||||||
use webauthn_rs_proto::{AttestationFormat, RegisteredExtensions};
|
use webauthn_rs_proto::{AttestationFormat, RegisteredExtensions};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct WebauthnRegistration {
|
||||||
|
pub id: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub migrated: bool,
|
||||||
|
pub credential: Credential,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<WebauthnRegistration> for crate::api::core::two_factor::webauthn::WebauthnRegistration {
|
||||||
|
fn from(value: WebauthnRegistration) -> Self {
|
||||||
|
Self {
|
||||||
|
id: value.id,
|
||||||
|
name: value.name,
|
||||||
|
migrated: value.migrated,
|
||||||
|
credential: webauthn_rs::prelude::Credential::from(value.credential).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Copied from https://docs.rs/webauthn-rs/0.3.2/src/webauthn_rs/proto.rs.html#316-339
|
// Copied from https://docs.rs/webauthn-rs/0.3.2/src/webauthn_rs/proto.rs.html#316-339
|
||||||
|
#[derive(Deserialize)]
|
||||||
pub struct Credential {
|
pub struct Credential {
|
||||||
pub cred_id: Vec<u8>,
|
pub cred_id: Vec<u8>,
|
||||||
pub cred: COSEKey,
|
pub cred: COSEKey,
|
||||||
|
@ -329,7 +350,31 @@ impl TwoFactor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn migrate_credential_to_passkey(conn: &mut DbConn) -> EmptyResult {
|
pub async fn migrate_credential_to_passkey(conn: &mut DbConn) -> EmptyResult {
|
||||||
todo!()
|
let webauthn_factors = db_run! { conn: {
|
||||||
|
twofactor::table
|
||||||
|
.filter(twofactor::atype.eq(TwoFactorType::Webauthn as i32))
|
||||||
|
.load::<TwoFactorDb>(conn)
|
||||||
|
.expect("Error loading twofactor")
|
||||||
|
.from_db()
|
||||||
|
}};
|
||||||
|
|
||||||
|
for webauthn_factor in webauthn_factors {
|
||||||
|
// assume that a failure to parse into the old struct, means that it was already converted
|
||||||
|
// alternatively this could also be checked via an extra field in the db
|
||||||
|
let Ok(regs) = serde_json::from_str::<Vec<webauthn_0_3::WebauthnRegistration>>(&webauthn_factor.data) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let regs = regs.into_iter()
|
||||||
|
.map(|r| r.into())
|
||||||
|
.collect::<Vec<WebauthnRegistration>>();
|
||||||
|
|
||||||
|
TwoFactor::new(webauthn_factor.user_uuid.clone(), TwoFactorType::Webauthn, serde_json::to_string(®s)?)
|
||||||
|
.save(conn)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue