use serde::Serialize;
use super::Base64UrlString;
#[derive(Debug, Clone, Copy, Default)]
pub enum JsonFormat {
#[default]
Minified,
Prettified,
}
#[derive(thiserror::Error, Debug)]
pub enum ResponseSerializationError {
#[error("Failed to serialize authenticator data: {0}")]
AuthenticatorDataError(String),
#[error("Failed to serialize attestation object: {0}")]
AttestationObjectError(String),
#[error("Failed to serialize public key: {0}")]
PublicKeyError(String),
#[error("Failed to serialize to JSON: {0}")]
JsonError(#[from] serde_json::Error),
#[error("Failed to serialize to CBOR: {0}")]
CborError(String),
}
pub trait WebAuthnIDLResponse: Sized {
type IdlModel: Serialize;
type Context;
fn to_idl_model(
&self,
ctx: &Self::Context,
) -> Result<Self::IdlModel, ResponseSerializationError>;
fn to_json_value(
&self,
ctx: &Self::Context,
) -> Result<serde_json::Value, ResponseSerializationError> {
let model = self.to_idl_model(ctx)?;
Ok(serde_json::to_value(&model)?)
}
fn to_json_string(
&self,
ctx: &Self::Context,
format: JsonFormat,
) -> Result<String, ResponseSerializationError> {
let value = self.to_json_value(ctx)?;
match format {
JsonFormat::Minified => Ok(serde_json::to_string(&value)?),
JsonFormat::Prettified => Ok(serde_json::to_string_pretty(&value)?),
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RegistrationResponseJSON {
pub id: String,
pub raw_id: Base64UrlString,
pub response: AuthenticatorAttestationResponseJSON,
#[serde(skip_serializing_if = "Option::is_none")]
pub authenticator_attachment: Option<String>,
pub client_extension_results: AuthenticationExtensionsClientOutputsJSON,
pub r#type: String,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthenticatorAttestationResponseJSON {
#[serde(rename = "clientDataJSON")]
pub client_data_json: Base64UrlString,
pub authenticator_data: Base64UrlString,
pub transports: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub public_key: Option<Base64UrlString>,
pub public_key_algorithm: i64,
pub attestation_object: Base64UrlString,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthenticationResponseJSON {
pub id: String,
pub raw_id: Base64UrlString,
pub response: AuthenticatorAssertionResponseJSON,
#[serde(skip_serializing_if = "Option::is_none")]
pub authenticator_attachment: Option<String>,
pub client_extension_results: AuthenticationExtensionsClientOutputsJSON,
pub r#type: String,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthenticatorAssertionResponseJSON {
#[serde(rename = "clientDataJSON")]
pub client_data_json: Base64UrlString,
pub authenticator_data: Base64UrlString,
pub signature: Base64UrlString,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_handle: Option<Base64UrlString>,
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthenticationExtensionsClientOutputsJSON {
#[serde(skip_serializing_if = "Option::is_none")]
pub appid: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cred_props: Option<CredentialPropertiesOutputJSON>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hmac_create_secret: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hmac_get_secret: Option<HMACGetSecretOutputJSON>,
#[serde(skip_serializing_if = "Option::is_none")]
pub large_blob: Option<LargeBlobOutputJSON>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prf: Option<PRFOutputJSON>,
#[serde(flatten)]
pub unsigned_extension_outputs: serde_json::Map<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CredentialPropertiesOutputJSON {
#[serde(skip_serializing_if = "Option::is_none")]
pub rk: Option<bool>,
}
#[derive(Debug, Clone, Serialize)]
pub struct HMACGetSecretOutputJSON {
pub output1: Base64UrlString,
#[serde(skip_serializing_if = "Option::is_none")]
pub output2: Option<Base64UrlString>,
}
#[derive(Debug, Clone, Serialize)]
pub struct LargeBlobOutputJSON {
#[serde(skip_serializing_if = "Option::is_none")]
pub supported: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub blob: Option<Base64UrlString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub written: Option<bool>,
}
#[derive(Debug, Clone, Serialize)]
pub struct PRFOutputJSON {
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub results: Option<PRFValuesJSON>,
}
#[derive(Debug, Clone, Serialize)]
pub struct PRFValuesJSON {
pub first: Base64UrlString,
#[serde(skip_serializing_if = "Option::is_none")]
pub second: Option<Base64UrlString>,
}