use base64urlsafedata::Base64UrlSafeData;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Clone, Copy, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[repr(u8)]
pub enum CredentialProtectionPolicy {
UserVerificationOptional = 0x1,
UserVerificationOptionalWithCredentialIDList = 0x2,
UserVerificationRequired = 0x3,
}
impl TryFrom<u8> for CredentialProtectionPolicy {
type Error = &'static str;
fn try_from(v: u8) -> Result<Self, Self::Error> {
use CredentialProtectionPolicy::*;
match v {
0x1 => Ok(UserVerificationOptional),
0x2 => Ok(UserVerificationOptionalWithCredentialIDList),
0x3 => Ok(UserVerificationRequired),
_ => Err("Invalid policy number"),
}
}
}
#[derive(Debug, Serialize, Clone, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct CredProtect {
pub credential_protection_policy: CredentialProtectionPolicy,
#[serde(skip_serializing_if = "Option::is_none")]
pub enforce_credential_protection_policy: Option<bool>,
}
#[derive(Debug, Serialize, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RequestRegistrationExtensions {
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub cred_protect: Option<CredProtect>,
#[serde(skip_serializing_if = "Option::is_none")]
pub uvm: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cred_props: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub min_pin_length: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hmac_create_secret: Option<bool>,
}
impl Default for RequestRegistrationExtensions {
fn default() -> Self {
RequestRegistrationExtensions {
cred_protect: None,
uvm: Some(true),
cred_props: Some(true),
min_pin_length: None,
hmac_create_secret: None,
}
}
}
#[allow(clippy::from_over_into)]
#[cfg(feature = "wasm")]
impl Into<js_sys::Object> for &RequestRegistrationExtensions {
fn into(self) -> js_sys::Object {
use js_sys::Object;
use wasm_bindgen::JsValue;
let RequestRegistrationExtensions {
cred_protect,
uvm,
cred_props,
min_pin_length,
hmac_create_secret,
} = self;
let obj = Object::new();
if let Some(cred_protect) = cred_protect {
let jsv = serde_wasm_bindgen::to_value(&cred_protect).unwrap();
js_sys::Reflect::set(&obj, &"credProtect".into(), &jsv).unwrap();
}
if let Some(uvm) = uvm {
js_sys::Reflect::set(&obj, &"uvm".into(), &JsValue::from_bool(*uvm)).unwrap();
}
if let Some(cred_props) = cred_props {
js_sys::Reflect::set(&obj, &"credProps".into(), &JsValue::from_bool(*cred_props))
.unwrap();
}
if let Some(min_pin_length) = min_pin_length {
js_sys::Reflect::set(
&obj,
&"minPinLength".into(),
&JsValue::from_bool(*min_pin_length),
)
.unwrap();
}
if let Some(hmac_create_secret) = hmac_create_secret {
js_sys::Reflect::set(
&obj,
&"hmacCreateSecret".into(),
&JsValue::from_bool(*hmac_create_secret),
)
.unwrap();
}
obj
}
}
#[derive(Debug, Serialize, Clone, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct HmacGetSecretInput {
pub output1: Base64UrlSafeData,
pub output2: Option<Base64UrlSafeData>,
}
#[derive(Debug, Serialize, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RequestAuthenticationExtensions {
#[serde(skip_serializing_if = "Option::is_none")]
pub appid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub uvm: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hmac_get_secret: Option<HmacGetSecretInput>,
}
#[allow(clippy::from_over_into)]
#[cfg(feature = "wasm")]
impl Into<js_sys::Object> for &RequestAuthenticationExtensions {
fn into(self) -> js_sys::Object {
use js_sys::{Object, Uint8Array};
use wasm_bindgen::JsValue;
let RequestAuthenticationExtensions {
appid: _,
uvm,
hmac_get_secret,
} = self;
let obj = Object::new();
if let Some(uvm) = uvm {
js_sys::Reflect::set(&obj, &"uvm".into(), &JsValue::from_bool(*uvm)).unwrap();
}
if let Some(HmacGetSecretInput { output1, output2 }) = hmac_get_secret {
let hmac = Object::new();
let o1 = Uint8Array::from(output1.0.as_slice());
js_sys::Reflect::set(&hmac, &"output1".into(), &o1).unwrap();
if let Some(output2) = output2 {
let o2 = Uint8Array::from(output2.0.as_slice());
js_sys::Reflect::set(&hmac, &"output2".into(), &o2).unwrap();
}
js_sys::Reflect::set(&obj, &"hmacGetSecret".into(), &hmac).unwrap();
}
obj
}
}
#[derive(Debug, Serialize, Clone, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct HmacGetSecretOutput {
pub output1: Base64UrlSafeData,
pub output2: Option<Base64UrlSafeData>,
}
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
pub struct AuthenticationExtensionsClientOutputs {
#[serde(default)]
pub appid: Option<bool>,
#[serde(default)]
pub hmac_get_secret: Option<HmacGetSecretOutput>,
}
#[cfg(feature = "wasm")]
impl From<web_sys::AuthenticationExtensionsClientOutputs>
for AuthenticationExtensionsClientOutputs
{
fn from(
ext: web_sys::AuthenticationExtensionsClientOutputs,
) -> AuthenticationExtensionsClientOutputs {
use js_sys::Uint8Array;
let appid = js_sys::Reflect::get(&ext, &"appid".into())
.ok()
.and_then(|jv| jv.as_bool());
let hmac_get_secret = js_sys::Reflect::get(&ext, &"hmacGetSecret".into())
.ok()
.and_then(|jv| {
let output2 = js_sys::Reflect::get(&jv, &"output2".into())
.map(|v| Uint8Array::new(&v).to_vec())
.map(Base64UrlSafeData)
.ok();
let output1 = js_sys::Reflect::get(&jv, &"output1".into())
.map(|v| Uint8Array::new(&v).to_vec())
.map(Base64UrlSafeData)
.ok();
output1.map(|output1| HmacGetSecretOutput { output1, output2 })
});
AuthenticationExtensionsClientOutputs {
appid,
hmac_get_secret,
}
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct CredProps {
rk: bool,
}
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
pub struct RegistrationExtensionsClientOutputs {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub appid: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cred_props: Option<CredProps>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub hmac_secret: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cred_protect: Option<CredentialProtectionPolicy>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub min_pin_length: Option<u32>,
}
#[cfg(feature = "wasm")]
impl From<web_sys::AuthenticationExtensionsClientOutputs> for RegistrationExtensionsClientOutputs {
fn from(
ext: web_sys::AuthenticationExtensionsClientOutputs,
) -> RegistrationExtensionsClientOutputs {
let appid = js_sys::Reflect::get(&ext, &"appid".into())
.ok()
.and_then(|jv| jv.as_bool());
let cred_props = js_sys::Reflect::get(&ext, &"credProps".into())
.ok()
.and_then(|cred_props_struct| {
js_sys::Reflect::get(&cred_props_struct, &"rk".into())
.ok()
.and_then(|jv| jv.as_bool())
.map(|rk| CredProps { rk })
});
let hmac_secret = js_sys::Reflect::get(&ext, &"hmac-secret".into())
.ok()
.and_then(|jv| jv.as_bool());
let cred_protect = js_sys::Reflect::get(&ext, &"credProtect".into())
.ok()
.and_then(|jv| jv.as_f64())
.and_then(|f| CredentialProtectionPolicy::try_from(f as u8).ok());
let min_pin_length = js_sys::Reflect::get(&ext, &"minPinLength".into())
.ok()
.and_then(|jv| jv.as_f64())
.map(|f| f as u32);
RegistrationExtensionsClientOutputs {
appid,
cred_props,
hmac_secret,
cred_protect,
min_pin_length,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ExtnState<T>
where
T: Clone + std::fmt::Debug,
{
NotRequested,
Ignored,
Set(T),
Unsolicited(T),
Unsigned(T),
}
impl<T> Default for ExtnState<T>
where
T: Clone + std::fmt::Debug,
{
fn default() -> Self {
ExtnState::NotRequested
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredExtensions {
#[serde(default)]
pub cred_protect: ExtnState<CredentialProtectionPolicy>,
#[serde(default)]
pub hmac_create_secret: ExtnState<bool>,
#[serde(default)]
pub appid: ExtnState<bool>,
#[serde(default)]
pub cred_props: ExtnState<CredProps>,
}
impl RegisteredExtensions {
pub fn none() -> Self {
RegisteredExtensions {
cred_protect: ExtnState::NotRequested,
hmac_create_secret: ExtnState::NotRequested,
appid: ExtnState::NotRequested,
cred_props: ExtnState::NotRequested,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticationExtensions {}