use super::WebAuthnService;
use crate::error::OauthResult as Result;
use crate::repository::WebAuthnCredentialParams;
use systemprompt_identifiers::UserId;
use uuid::Uuid;
use webauthn_rs::prelude::*;
impl WebAuthnService {
pub(super) async fn store_credential(
&self,
user_id: &UserId,
sk: &Passkey,
display_name: &str,
) -> Result<()> {
let credential_id = sk.cred_id().clone();
let public_key = serde_json::to_vec(sk)?;
let counter = 0u32;
let id = Uuid::new_v4().to_string();
let transports: Vec<String> = {
let passkey_json = serde_json::to_value(sk)?;
passkey_json
.get("cred")
.and_then(|cred| cred.get("transports"))
.and_then(|t| t.as_array())
.map_or_else(
|| vec!["internal".to_string()],
|arr| {
arr.iter()
.filter_map(|v| v.as_str().map(str::to_lowercase))
.collect()
},
)
};
let params = WebAuthnCredentialParams::builder(
&id,
user_id.as_str(),
&credential_id,
&public_key,
counter,
)
.with_display_name(display_name)
.with_device_type("platform")
.with_transports(&transports)
.build();
self.oauth_repo.store_webauthn_credential(params).await
}
pub(super) async fn get_user_credentials(&self, user_id: &UserId) -> Result<Vec<Passkey>> {
let credentials = self.oauth_repo.get_webauthn_credentials(user_id).await?;
let mut passkeys = Vec::new();
for cred in credentials {
let mut passkey_json: serde_json::Value = serde_json::from_slice(&cred.public_key)?;
if let Some(credential) = passkey_json.get_mut("cred") {
let transports_json: Vec<String> = cred
.transports
.iter()
.map(|t| {
t.to_lowercase()
.replace("internal", "Internal")
.replace("usb", "Usb")
.replace("nfc", "Nfc")
.replace("ble", "Ble")
.replace("hybrid", "Hybrid")
})
.collect();
credential["transports"] = serde_json::json!(transports_json);
}
let passkey: Passkey = serde_json::from_value(passkey_json)?;
passkeys.push(passkey);
}
Ok(passkeys)
}
pub(super) async fn get_user_credentials_by_email(&self, email: &str) -> Result<Vec<Passkey>> {
if let Some(user) = self.oauth_repo.find_user_by_email(email).await? {
self.get_user_credentials(&user.id).await
} else {
Ok(Vec::new())
}
}
pub(super) async fn update_credential_counter(
&self,
credential_id: &[u8],
counter: u32,
) -> Result<()> {
self.oauth_repo
.update_webauthn_credential_counter(credential_id, counter)
.await
}
}