use coset::{CoseKeyBuilder, iana};
use p256::{SecretKey, ecdsa::SigningKey};
use crate::{Passkey, StoredHmacSecret, rand::random_vec};
pub struct PasskeyBuilder {
inner: Passkey,
}
impl PasskeyBuilder {
pub(super) fn new(rp_id: String) -> Self {
let private_key = {
let mut rng = rand::thread_rng();
SecretKey::random(&mut rng)
};
let public_key = SigningKey::from(&private_key)
.verifying_key()
.to_encoded_point(false);
#[allow(deprecated)]
let x = public_key.x().unwrap().as_slice().to_vec();
#[allow(deprecated)]
let y = public_key.y().unwrap().as_slice().to_vec();
let private = CoseKeyBuilder::new_ec2_priv_key(
iana::EllipticCurve::P_256,
x,
y,
private_key.to_bytes().to_vec(),
)
.algorithm(iana::Algorithm::ES256)
.build();
Self {
inner: Passkey {
key: private,
credential_id: random_vec(16).into(),
rp_id,
user_handle: None,
username: None,
user_display_name: None,
counter: None,
extensions: Default::default(),
},
}
}
pub fn credential_id(mut self, len: usize) -> Self {
self.inner.credential_id = random_vec(len).into();
self
}
pub fn user_handle(mut self, len: Option<usize>) -> Self {
self.inner.user_handle = Some(random_vec(len.unwrap_or(16)).into());
self
}
pub fn username(mut self, username: String) -> Self {
self.inner.username = Some(username);
self
}
pub fn user_display_name(mut self, user_display_name: String) -> Self {
self.inner.user_display_name = Some(user_display_name);
self
}
pub fn counter(mut self, counter: u32) -> Self {
self.inner.counter = Some(counter);
self
}
pub fn hmac_secret(mut self, hmac_secret: StoredHmacSecret) -> Self {
self.inner.extensions.hmac_secret = Some(hmac_secret);
self
}
pub fn build(self) -> Passkey {
self.inner
}
}