diff --git a/Cargo.lock b/Cargo.lock index 5518d1464..4573778c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -459,7 +459,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "base64urlsafedata" version = "0.1.3" -source = "git+https://github.com/kanidm/webauthn-rs.git?rev=2218d2055c0c900ef57b398423eee5e8d5521f4c#2218d2055c0c900ef57b398423eee5e8d5521f4c" +source = "git+https://github.com/kanidm/webauthn-rs.git?rev=5f4db4172f8e22aedc68c282d177e98db2b1892f#5f4db4172f8e22aedc68c282d177e98db2b1892f" dependencies = [ "base64 0.21.5", "paste 1.0.14", @@ -2830,9 +2830,9 @@ dependencies = [ [[package]] name = "implicit-clone" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c6ecbd987bb94f1f3c76c6787879756cf4b6f73bfff48d79308e8c56b46f65f" +checksum = "cfd6201e7c30ccb24773cac7efa6fec1e06189d414b7439ce756a481c8bfbf53" dependencies = [ "indexmap 1.9.3", ] @@ -5550,7 +5550,7 @@ checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" [[package]] name = "sshkey-attest" version = "0.5.0-dev" -source = "git+https://github.com/kanidm/webauthn-rs.git?rev=2218d2055c0c900ef57b398423eee5e8d5521f4c#2218d2055c0c900ef57b398423eee5e8d5521f4c" +source = "git+https://github.com/kanidm/webauthn-rs.git?rev=5f4db4172f8e22aedc68c282d177e98db2b1892f#5f4db4172f8e22aedc68c282d177e98db2b1892f" dependencies = [ "base64urlsafedata", "nom", @@ -6466,9 +6466,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -6477,7 +6477,7 @@ dependencies = [ [[package]] name = "webauthn-attestation-ca" version = "0.1.0" -source = "git+https://github.com/kanidm/webauthn-rs.git?rev=2218d2055c0c900ef57b398423eee5e8d5521f4c#2218d2055c0c900ef57b398423eee5e8d5521f4c" +source = "git+https://github.com/kanidm/webauthn-rs.git?rev=5f4db4172f8e22aedc68c282d177e98db2b1892f#5f4db4172f8e22aedc68c282d177e98db2b1892f" dependencies = [ "base64urlsafedata", "openssl", @@ -6489,7 +6489,7 @@ dependencies = [ [[package]] name = "webauthn-authenticator-rs" version = "0.5.0-dev" -source = "git+https://github.com/kanidm/webauthn-rs.git?rev=2218d2055c0c900ef57b398423eee5e8d5521f4c#2218d2055c0c900ef57b398423eee5e8d5521f4c" +source = "git+https://github.com/kanidm/webauthn-rs.git?rev=5f4db4172f8e22aedc68c282d177e98db2b1892f#5f4db4172f8e22aedc68c282d177e98db2b1892f" dependencies = [ "async-stream", "async-trait", @@ -6521,7 +6521,7 @@ dependencies = [ [[package]] name = "webauthn-rs" version = "0.5.0-dev" -source = "git+https://github.com/kanidm/webauthn-rs.git?rev=2218d2055c0c900ef57b398423eee5e8d5521f4c#2218d2055c0c900ef57b398423eee5e8d5521f4c" +source = "git+https://github.com/kanidm/webauthn-rs.git?rev=5f4db4172f8e22aedc68c282d177e98db2b1892f#5f4db4172f8e22aedc68c282d177e98db2b1892f" dependencies = [ "base64urlsafedata", "serde", @@ -6534,7 +6534,7 @@ dependencies = [ [[package]] name = "webauthn-rs-core" version = "0.5.0-dev" -source = "git+https://github.com/kanidm/webauthn-rs.git?rev=2218d2055c0c900ef57b398423eee5e8d5521f4c#2218d2055c0c900ef57b398423eee5e8d5521f4c" +source = "git+https://github.com/kanidm/webauthn-rs.git?rev=5f4db4172f8e22aedc68c282d177e98db2b1892f#5f4db4172f8e22aedc68c282d177e98db2b1892f" dependencies = [ "base64 0.21.5", "base64urlsafedata", @@ -6558,7 +6558,7 @@ dependencies = [ [[package]] name = "webauthn-rs-proto" version = "0.5.0-dev" -source = "git+https://github.com/kanidm/webauthn-rs.git?rev=2218d2055c0c900ef57b398423eee5e8d5521f4c#2218d2055c0c900ef57b398423eee5e8d5521f4c" +source = "git+https://github.com/kanidm/webauthn-rs.git?rev=5f4db4172f8e22aedc68c282d177e98db2b1892f#5f4db4172f8e22aedc68c282d177e98db2b1892f" dependencies = [ "base64urlsafedata", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index 285729ea2..5dc03e240 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,12 +61,12 @@ repository = "https://github.com/kanidm/kanidm/" # scim_proto = { path = "../scim/proto" } # scim_proto = { git = "https://github.com/kanidm/scim.git" } -base64urlsafedata = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "2218d2055c0c900ef57b398423eee5e8d5521f4c" } -webauthn-authenticator-rs = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "2218d2055c0c900ef57b398423eee5e8d5521f4c" } -webauthn-rs = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "2218d2055c0c900ef57b398423eee5e8d5521f4c" } -webauthn-rs-core = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "2218d2055c0c900ef57b398423eee5e8d5521f4c" } -webauthn-rs-proto = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "2218d2055c0c900ef57b398423eee5e8d5521f4c" } -sshkey-attest = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "2218d2055c0c900ef57b398423eee5e8d5521f4c" } +base64urlsafedata = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "5f4db4172f8e22aedc68c282d177e98db2b1892f" } +webauthn-authenticator-rs = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "5f4db4172f8e22aedc68c282d177e98db2b1892f" } +webauthn-rs = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "5f4db4172f8e22aedc68c282d177e98db2b1892f" } +webauthn-rs-core = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "5f4db4172f8e22aedc68c282d177e98db2b1892f" } +webauthn-rs-proto = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "5f4db4172f8e22aedc68c282d177e98db2b1892f" } +sshkey-attest = { git = "https://github.com/kanidm/webauthn-rs.git", rev = "5f4db4172f8e22aedc68c282d177e98db2b1892f" } # base64urlsafedata = { path = "../webauthn-rs/base64urlsafedata" } # webauthn-authenticator-rs = { path = "../webauthn-rs/webauthn-authenticator-rs" } diff --git a/libs/client/src/group.rs b/libs/client/src/group.rs index 74c527500..905faa556 100644 --- a/libs/client/src/group.rs +++ b/libs/client/src/group.rs @@ -56,4 +56,16 @@ impl KanidmClient { ) .await } + + pub async fn group_account_policy_webauthn_attestation_set( + &self, + id: &str, + att_ca_list: &str, + ) -> Result<(), ClientError> { + self.perform_put_request( + &format!("/v1/group/{}/_attr/webauthn_attestation_ca_list", id), + vec![att_ca_list.to_string()], + ) + .await + } } diff --git a/libs/client/src/lib.rs b/libs/client/src/lib.rs index 2749f68f5..237e38ede 100644 --- a/libs/client/src/lib.rs +++ b/libs/client/src/lib.rs @@ -1784,6 +1784,36 @@ impl KanidmClient { .await } + pub async fn idm_account_credential_update_attested_passkey_init( + &self, + session_token: &CUSessionToken, + ) -> Result { + let scr = CURequest::AttestedPasskeyInit; + self.perform_simple_post_request("/v1/credential/_update", &(scr, &session_token)) + .await + } + + pub async fn idm_account_credential_update_attested_passkey_finish( + &self, + session_token: &CUSessionToken, + label: String, + registration: RegisterPublicKeyCredential, + ) -> Result { + let scr = CURequest::AttestedPasskeyFinish(label, registration); + self.perform_simple_post_request("/v1/credential/_update", &(scr, &session_token)) + .await + } + + pub async fn idm_account_credential_update_attested_passkey_remove( + &self, + session_token: &CUSessionToken, + uuid: Uuid, + ) -> Result { + let scr = CURequest::AttestedPasskeyRemove(uuid); + self.perform_simple_post_request("/v1/credential/_update", &(scr, &session_token)) + .await + } + pub async fn idm_account_credential_update_commit( &self, session_token: &CUSessionToken, diff --git a/proto/src/constants.rs b/proto/src/constants.rs index 4e33928d6..4f724fee8 100644 --- a/proto/src/constants.rs +++ b/proto/src/constants.rs @@ -52,6 +52,7 @@ pub const ATTR_ACP_RECEIVER: &str = "acp_receiver"; pub const ATTR_ACP_SEARCH_ATTR: &str = "acp_search_attr"; pub const ATTR_ACP_TARGET_SCOPE: &str = "acp_targetscope"; pub const ATTR_API_TOKEN_SESSION: &str = "api_token_session"; +pub const ATTR_ATTESTED_PASSKEYS: &str = "attested_passkeys"; pub const ATTR_ATTR: &str = "attr"; pub const ATTR_ATTRIBUTENAME: &str = "attributename"; pub const ATTR_ATTRIBUTETYPE: &str = "attributetype"; @@ -67,7 +68,6 @@ pub const ATTR_CREDENTIAL_UPDATE_INTENT_TOKEN: &str = "credential_update_intent_ pub const ATTR_CREDENTIAL_TYPE_MINIMUM: &str = "credential_type_minimum"; pub const ATTR_DENIED_NAME: &str = "denied_name"; pub const ATTR_DESCRIPTION: &str = "description"; -pub const ATTR_DEVICEKEYS: &str = "devicekeys"; pub const ATTR_DIRECTMEMBEROF: &str = "directmemberof"; pub const ATTR_DISPLAYNAME: &str = "displayname"; pub const ATTR_DN: &str = "dn"; @@ -176,6 +176,7 @@ pub const ATTR_USERID: &str = "userid"; pub const ATTR_USERPASSWORD: &str = "userpassword"; pub const ATTR_UUID: &str = "uuid"; pub const ATTR_VERSION: &str = "version"; +pub const ATTR_WEBAUTHN_ATTESTATION_CA_LIST: &str = "webauthn_attestation_ca_list"; pub const OAUTH2_SCOPE_EMAIL: &str = ATTR_EMAIL; pub const OAUTH2_SCOPE_GROUPS: &str = "groups"; diff --git a/proto/src/v1.rs b/proto/src/v1.rs index e3794d9ef..4effb71f6 100644 --- a/proto/src/v1.rs +++ b/proto/src/v1.rs @@ -289,6 +289,9 @@ pub enum OperationError { /// When a name is denied by the system config ValueDenyName, // What about something like this for unique errors? + // Credential Update Errors + CU0001WebauthnAttestationNotTrusted, + CU0002WebauthnRegistrationError, // ValueSet errors VS0001IncomingReplSshPublicKey, // Value Errors @@ -1161,6 +1164,9 @@ pub enum CURequest { PasskeyInit, PasskeyFinish(String, RegisterPublicKeyCredential), PasskeyRemove(Uuid), + AttestedPasskeyInit, + AttestedPasskeyFinish(String, RegisterPublicKeyCredential), + AttestedPasskeyRemove(Uuid), } impl fmt::Debug for CURequest { @@ -1178,6 +1184,9 @@ impl fmt::Debug for CURequest { CURequest::PasskeyInit => "CURequest::PasskeyInit", CURequest::PasskeyFinish(_, _) => "CURequest::PasskeyFinish", CURequest::PasskeyRemove(_) => "CURequest::PasskeyRemove", + CURequest::AttestedPasskeyInit => "CURequest::AttestedPasskeyInit", + CURequest::AttestedPasskeyFinish(_, _) => "CURequest::AttestedPasskeyFinish", + CURequest::AttestedPasskeyRemove(_) => "CURequest::AttestedPasskeyRemove", }; writeln!(f, "{}", t) } @@ -1192,6 +1201,7 @@ pub enum CURegState { TotpInvalidSha1, BackupCodes(Vec), Passkey(CreationChallengeResponse), + AttestedPasskey(CreationChallengeResponse), } #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] @@ -1201,9 +1211,10 @@ pub enum CUExtPortal { Some(Url), } -#[derive(Debug, Clone, Copy, Serialize, Deserialize, ToSchema)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, ToSchema, PartialEq)] pub enum CUCredState { Modifiable, + DeleteOnly, AccessDeny, PolicyDeny, // Disabled, @@ -1213,7 +1224,10 @@ pub enum CUCredState { pub enum CURegWarning { MfaRequired, PasskeyRequired, + AttestedPasskeyRequired, + AttestedResidentKeyRequired, Unsatisfiable, + WebauthnAttestationUnsatisfiable, } #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] @@ -1231,6 +1245,9 @@ pub struct CUStatus { pub primary_state: CUCredState, pub passkeys: Vec, pub passkeys_state: CUCredState, + pub attested_passkeys: Vec, + pub attested_passkeys_state: CUCredState, + pub attested_passkeys_allowed_devices: Vec, } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, ToSchema)] diff --git a/server/core/src/actors/v1_read.rs b/server/core/src/actors/v1_read.rs index 99b82ffea..1080c37f4 100644 --- a/server/core/src/actors/v1_read.rs +++ b/server/core/src/actors/v1_read.rs @@ -1251,7 +1251,7 @@ impl QueryServerReadV1 { .map_err(|e| { admin_error!( err = ?e, - "Failed to begin credential_passkey_init", + "Failed to begin credential_passkey_finish", ); e }), @@ -1260,7 +1260,34 @@ impl QueryServerReadV1 { .map_err(|e| { admin_error!( err = ?e, - "Failed to begin credential_passkey_init", + "Failed to begin credential_passkey_remove", + ); + e + }), + CURequest::AttestedPasskeyInit => idms_cred_update + .credential_attested_passkey_init(&session_token, ct) + .map_err(|e| { + admin_error!( + err = ?e, + "Failed to begin credential_attested_passkey_init", + ); + e + }), + CURequest::AttestedPasskeyFinish(label, rpkc) => idms_cred_update + .credential_attested_passkey_finish(&session_token, ct, label, &rpkc) + .map_err(|e| { + admin_error!( + err = ?e, + "Failed to begin credential_attested_passkey_finish", + ); + e + }), + CURequest::AttestedPasskeyRemove(uuid) => idms_cred_update + .credential_attested_passkey_remove(&session_token, ct, uuid) + .map_err(|e| { + admin_error!( + err = ?e, + "Failed to begin credential_attested_passkey_remove", ); e }), diff --git a/server/lib/src/be/dbvalue.rs b/server/lib/src/be/dbvalue.rs index a812a3855..a73174d6b 100644 --- a/server/lib/src/be/dbvalue.rs +++ b/server/lib/src/be/dbvalue.rs @@ -8,7 +8,8 @@ use serde_with::skip_serializing_none; use url::Url; use uuid::Uuid; use webauthn_rs::prelude::{ - AttestedPasskey as DeviceKeyV4, Passkey as PasskeyV4, SecurityKey as SecurityKeyV4, + AttestationCaList, AttestedPasskey as AttestedPasskeyV4, Passkey as PasskeyV4, + SecurityKey as SecurityKeyV4, }; use webauthn_rs_core::proto::{COSEKey, UserVerificationPolicy}; @@ -60,6 +61,8 @@ pub enum DbValueIntentTokenStateV1 { #[serde(default)] passkeys_can_edit: bool, #[serde(default)] + attested_passkeys_can_edit: bool, + #[serde(default)] unixcred_can_edit: bool, #[serde(default)] sshpubkey_can_edit: bool, @@ -76,6 +79,8 @@ pub enum DbValueIntentTokenStateV1 { #[serde(default)] passkeys_can_edit: bool, #[serde(default)] + attested_passkeys_can_edit: bool, + #[serde(default)] unixcred_can_edit: bool, #[serde(default)] sshpubkey_can_edit: bool, @@ -347,8 +352,12 @@ pub enum DbValuePasskeyV1 { } #[derive(Serialize, Deserialize, Debug)] -pub enum DbValueDeviceKeyV1 { - V4 { u: Uuid, t: String, k: DeviceKeyV4 }, +pub enum DbValueAttestedPasskeyV1 { + V4 { + u: Uuid, + t: String, + k: AttestedPasskeyV4, + }, } #[derive(Serialize, Deserialize, Debug)] @@ -674,7 +683,7 @@ pub enum DbValueSetV2 { #[serde(rename = "PK")] Passkey(Vec), #[serde(rename = "DK")] - DeviceKey(Vec), + AttestedPasskey(Vec), #[serde(rename = "TE")] TrustedDeviceEnrollment(Vec), #[serde(rename = "AS")] @@ -699,6 +708,8 @@ pub enum DbValueSetV2 { Image(Vec), #[serde(rename = "CT")] CredentialType(Vec), + #[serde(rename = "WC")] + WebauthnAttestationCaList { ca_list: AttestationCaList }, } impl DbValueSetV2 { @@ -732,7 +743,7 @@ impl DbValueSetV2 { DbValueSetV2::RestrictedString(set) => set.len(), DbValueSetV2::IntentToken(set) => set.len(), DbValueSetV2::Passkey(set) => set.len(), - DbValueSetV2::DeviceKey(set) => set.len(), + DbValueSetV2::AttestedPasskey(set) => set.len(), DbValueSetV2::TrustedDeviceEnrollment(set) => set.len(), DbValueSetV2::Session(set) => set.len(), DbValueSetV2::ApiToken(set) => set.len(), @@ -746,6 +757,7 @@ impl DbValueSetV2 { DbValueSetV2::EcKeyPrivate(_key) => 1, // here we have to hard code it because the Vec // represents the bytes of SINGLE(!) key DbValueSetV2::CredentialType(set) => set.len(), + DbValueSetV2::WebauthnAttestationCaList { ca_list } => ca_list.len(), } } diff --git a/server/lib/src/constants/acp.rs b/server/lib/src/constants/acp.rs index 45fdca286..97eb405fd 100644 --- a/server/lib/src/constants/acp.rs +++ b/server/lib/src/constants/acp.rs @@ -208,7 +208,7 @@ lazy_static! { Attribute::PrimaryCredential, Attribute::UserAuthTokenSession, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, ], ..Default::default() }; @@ -241,7 +241,7 @@ lazy_static! { Attribute::SshPublicKey, Attribute::UnixPassword, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, Attribute::UserAuthTokenSession, ], modify_present_attrs: vec![ @@ -253,7 +253,7 @@ lazy_static! { Attribute::SshPublicKey, Attribute::UnixPassword, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, ], ..Default::default() }; @@ -442,7 +442,7 @@ lazy_static! { Attribute::AccountExpire, Attribute::AccountValidFrom, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, ], create_classes: vec![EntryClass::Object, EntryClass::Account, EntryClass::Person,], ..Default::default() @@ -695,7 +695,7 @@ lazy_static! { Attribute::AccountExpire, Attribute::AccountValidFrom, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, Attribute::ApiTokenSession, Attribute::UserAuthTokenSession, ], @@ -729,7 +729,7 @@ lazy_static! { Attribute::AccountExpire, Attribute::AccountValidFrom, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, Attribute::ApiTokenSession, Attribute::UserAuthTokenSession, Attribute::IdVerificationEcKey, @@ -743,7 +743,7 @@ lazy_static! { Attribute::AccountExpire, Attribute::AccountValidFrom, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, Attribute::ApiTokenSession, ], ..Default::default() @@ -779,7 +779,7 @@ lazy_static! { Attribute::AccountExpire, Attribute::AccountValidFrom, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, ], create_classes: vec![ EntryClass::Object, @@ -895,7 +895,7 @@ lazy_static! { Attribute::AccountExpire, Attribute::AccountValidFrom, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, Attribute::ApiTokenSession, Attribute::UserAuthTokenSession, ], @@ -925,7 +925,7 @@ lazy_static! { Attribute::AccountExpire, Attribute::AccountValidFrom, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, Attribute::ApiTokenSession, Attribute::UserAuthTokenSession, Attribute::IdVerificationEcKey, @@ -938,7 +938,7 @@ lazy_static! { Attribute::AccountExpire, Attribute::AccountValidFrom, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, Attribute::ApiTokenSession, ], ..Default::default() @@ -1275,6 +1275,7 @@ lazy_static! { Attribute::AuthPasswordMinimumLength, Attribute::CredentialTypeMinimum, Attribute::PrivilegeExpiry, + Attribute::WebauthnAttestationCaList, ], modify_removed_attrs: vec![ Attribute::Class, @@ -1282,6 +1283,7 @@ lazy_static! { Attribute::AuthPasswordMinimumLength, Attribute::CredentialTypeMinimum, Attribute::PrivilegeExpiry, + Attribute::WebauthnAttestationCaList, ], modify_present_attrs: vec![ Attribute::Class, @@ -1289,6 +1291,7 @@ lazy_static! { Attribute::AuthPasswordMinimumLength, Attribute::CredentialTypeMinimum, Attribute::PrivilegeExpiry, + Attribute::WebauthnAttestationCaList, ], modify_classes: vec![ EntryClass::AccountPolicy, @@ -1329,7 +1332,7 @@ lazy_static! { Attribute::AccountExpire, Attribute::AccountValidFrom, Attribute::PassKeys, - Attribute::DeviceKeys, + Attribute::AttestedPasskeys, ], create_classes: vec![ EntryClass::Object, diff --git a/server/lib/src/constants/entries.rs b/server/lib/src/constants/entries.rs index a7a559a86..c8ca43815 100644 --- a/server/lib/src/constants/entries.rs +++ b/server/lib/src/constants/entries.rs @@ -50,6 +50,7 @@ pub enum Attribute { AcpSearchAttr, AcpTargetScope, ApiTokenSession, + AttestedPasskeys, Attr, AttributeName, AttributeType, @@ -65,7 +66,6 @@ pub enum Attribute { CredentialTypeMinimum, DeniedName, Description, - DeviceKeys, DirectMemberOf, DisplayName, Dn, @@ -173,6 +173,7 @@ pub enum Attribute { UserPassword, Uuid, Version, + WebauthnAttestationCaList, #[cfg(any(debug_assertions, test))] NonExist, @@ -232,6 +233,7 @@ impl TryFrom for Attribute { ATTR_ACP_SEARCH_ATTR => Attribute::AcpSearchAttr, ATTR_ACP_TARGET_SCOPE => Attribute::AcpTargetScope, ATTR_API_TOKEN_SESSION => Attribute::ApiTokenSession, + ATTR_ATTESTED_PASSKEYS => Attribute::AttestedPasskeys, ATTR_ATTR => Attribute::Attr, ATTR_ATTRIBUTENAME => Attribute::AttributeName, ATTR_ATTRIBUTETYPE => Attribute::AttributeType, @@ -247,7 +249,6 @@ impl TryFrom for Attribute { ATTR_CREDENTIAL_TYPE_MINIMUM => Attribute::CredentialTypeMinimum, ATTR_DENIED_NAME => Attribute::DeniedName, ATTR_DESCRIPTION => Attribute::Description, - ATTR_DEVICEKEYS => Attribute::DeviceKeys, ATTR_DIRECTMEMBEROF => Attribute::DirectMemberOf, ATTR_DISPLAYNAME => Attribute::DisplayName, ATTR_DN => Attribute::Dn, @@ -353,6 +354,7 @@ impl TryFrom for Attribute { ATTR_USERPASSWORD => Attribute::UserPassword, ATTR_UUID => Attribute::Uuid, ATTR_VERSION => Attribute::Version, + ATTR_WEBAUTHN_ATTESTATION_CA_LIST => Attribute::WebauthnAttestationCaList, #[cfg(any(debug_assertions, test))] TEST_ATTR_NON_EXIST => Attribute::NonExist, @@ -390,6 +392,7 @@ impl From for &'static str { Attribute::AcpSearchAttr => ATTR_ACP_SEARCH_ATTR, Attribute::AcpTargetScope => ATTR_ACP_TARGET_SCOPE, Attribute::ApiTokenSession => ATTR_API_TOKEN_SESSION, + Attribute::AttestedPasskeys => ATTR_ATTESTED_PASSKEYS, Attribute::Attr => ATTR_ATTR, Attribute::AttributeName => ATTR_ATTRIBUTENAME, Attribute::AttributeType => ATTR_ATTRIBUTETYPE, @@ -405,7 +408,6 @@ impl From for &'static str { Attribute::CredentialTypeMinimum => ATTR_CREDENTIAL_TYPE_MINIMUM, Attribute::DeniedName => ATTR_DENIED_NAME, Attribute::Description => ATTR_DESCRIPTION, - Attribute::DeviceKeys => ATTR_DEVICEKEYS, Attribute::DirectMemberOf => ATTR_DIRECTMEMBEROF, Attribute::DisplayName => ATTR_DISPLAYNAME, Attribute::Dn => ATTR_DN, @@ -511,6 +513,7 @@ impl From for &'static str { Attribute::UserPassword => ATTR_USERPASSWORD, Attribute::Uuid => ATTR_UUID, Attribute::Version => ATTR_VERSION, + Attribute::WebauthnAttestationCaList => ATTR_WEBAUTHN_ATTESTATION_CA_LIST, #[cfg(any(debug_assertions, test))] Attribute::NonExist => TEST_ATTR_NON_EXIST, diff --git a/server/lib/src/constants/schema.rs b/server/lib/src/constants/schema.rs index de85da2f7..c989c4b69 100644 --- a/server/lib/src/constants/schema.rs +++ b/server/lib/src/constants/schema.rs @@ -251,7 +251,7 @@ pub static ref SCHEMA_ATTR_LOGINSHELL: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_UNIX_PASSWORD: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_UNIX_PASSWORD, name: Attribute::UnixPassword.into(), - description: "A POSIX user's UNIX login password.to_string().".to_string(), + description: "A POSIX user's UNIX login password.".to_string(), index: vec![IndexType::Presence], syntax: SyntaxType::Credential, @@ -273,7 +273,7 @@ pub static ref SCHEMA_ATTR_NSUNIQUEID: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_ACCOUNT_EXPIRE: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_ACCOUNT_EXPIRE, name: Attribute::AccountExpire.into(), - description: "The datetime after which this account no longer may authenticate.to_string().".to_string(), + description: "The datetime after which this account no longer may authenticate.".to_string(), sync_allowed: true, syntax: SyntaxType::DateTime, @@ -283,13 +283,22 @@ pub static ref SCHEMA_ATTR_ACCOUNT_EXPIRE: SchemaAttribute = SchemaAttribute { pub static ref SCHEMA_ATTR_ACCOUNT_VALID_FROM: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_ACCOUNT_VALID_FROM, name: Attribute::AccountValidFrom.into(), - description: "The datetime after which this account may commence authenticating.to_string().".to_string(), + description: "The datetime after which this account may commence authenticating.".to_string(), sync_allowed: true, syntax: SyntaxType::DateTime, ..Default::default() }; +pub static ref SCHEMA_ATTR_WEBAUTHN_ATTESTATION_CA_LIST: SchemaAttribute = SchemaAttribute { + uuid: UUID_SCHEMA_ATTR_WEBAUTHN_ATTESTATION_CA_LIST, + name: Attribute::WebauthnAttestationCaList.into(), + description: "A set of CA's that limit devices that can be used with webauthn.".to_string(), + syntax: SyntaxType::WebauthnAttestationCaList, + multivalue: true, + ..Default::default() +}; + pub static ref SCHEMA_ATTR_OAUTH2_RS_NAME: SchemaAttribute = SchemaAttribute { uuid: UUID_SCHEMA_ATTR_OAUTH2_RS_NAME, name: Attribute::OAuth2RsName.into(), @@ -461,15 +470,15 @@ pub static ref SCHEMA_ATTR_PASSKEYS: SchemaAttribute = SchemaAttribute { ..Default::default() }; -pub static ref SCHEMA_ATTR_DEVICEKEYS: SchemaAttribute = SchemaAttribute { - uuid: UUID_SCHEMA_ATTR_DEVICEKEYS, - name: Attribute::DeviceKeys.into(), +pub static ref SCHEMA_ATTR_ATTESTED_PASSKEYS: SchemaAttribute = SchemaAttribute { + uuid: UUID_SCHEMA_ATTR_ATTESTED_PASSKEYS, + name: Attribute::AttestedPasskeys.into(), description: "A set of registered device keys".to_string(), index: vec![IndexType::Equality], multivalue: true, sync_allowed: true, - syntax: SyntaxType::DeviceKey, + syntax: SyntaxType::AttestedPasskey, ..Default::default() }; @@ -657,7 +666,8 @@ pub static ref SCHEMA_CLASS_ACCOUNT_POLICY: SchemaClass = SchemaClass { Attribute::AuthSessionExpiry.into(), Attribute::PrivilegeExpiry.into(), Attribute::AuthPasswordMinimumLength.into(), - Attribute::CredentialTypeMinimum.into() + Attribute::CredentialTypeMinimum.into(), + Attribute::WebauthnAttestationCaList.into(), ], systemsupplements: vec![Attribute::Group.into()], ..Default::default() @@ -672,7 +682,7 @@ pub static ref SCHEMA_CLASS_ACCOUNT: SchemaClass = SchemaClass { systemmay: vec![ Attribute::PrimaryCredential.into(), Attribute::PassKeys.into(), - Attribute::DeviceKeys.into(), + Attribute::AttestedPasskeys.into(), Attribute::CredentialUpdateIntentToken.into(), Attribute::SshPublicKey.into(), Attribute::RadiusSecret.into(), diff --git a/server/lib/src/constants/uuids.rs b/server/lib/src/constants/uuids.rs index 60aa04e18..e95bd7be7 100644 --- a/server/lib/src/constants/uuids.rs +++ b/server/lib/src/constants/uuids.rs @@ -184,7 +184,7 @@ pub const UUID_SCHEMA_ATTR_OAUTH2_CONSENT_SCOPE_MAP: Uuid = pub const UUID_SCHEMA_ATTR_DOMAIN_DISPLAY_NAME: Uuid = uuid!("00000000-0000-0000-0000-ffff00000098"); pub const UUID_SCHEMA_ATTR_PASSKEYS: Uuid = uuid!("00000000-0000-0000-0000-ffff00000099"); -pub const UUID_SCHEMA_ATTR_DEVICEKEYS: Uuid = uuid!("00000000-0000-0000-0000-ffff00000100"); +pub const UUID_SCHEMA_ATTR_ATTESTED_PASSKEYS: Uuid = uuid!("00000000-0000-0000-0000-ffff00000100"); pub const UUID_SCHEMA_ATTR_SYSTEMSUPPLEMENTS: Uuid = uuid!("00000000-0000-0000-0000-ffff00000101"); pub const UUID_SCHEMA_ATTR_SUPPLEMENTS: Uuid = uuid!("00000000-0000-0000-0000-ffff00000102"); @@ -252,6 +252,8 @@ pub const UUID_SCHEMA_ATTR_CREDENTIAL_TYPE_MINIMUM: Uuid = pub const UUID_SCHEMA_ATTR_SUDOHOST: Uuid = uuid!("00000000-0000-0000-0000-ffff00000149"); pub const UUID_SCHEMA_ATTR_UID: Uuid = uuid!("00000000-0000-0000-0000-ffff00000150"); pub const UUID_SCHEMA_ATTR_GECOS: Uuid = uuid!("00000000-0000-0000-0000-ffff00000151"); +pub const UUID_SCHEMA_ATTR_WEBAUTHN_ATTESTATION_CA_LIST: Uuid = + uuid!("00000000-0000-0000-0000-ffff00000152"); // System and domain infos // I'd like to strongly criticise william of the past for making poor choices about these allocations. diff --git a/server/lib/src/entry.rs b/server/lib/src/entry.rs index 2c8e3dc40..1736099c3 100644 --- a/server/lib/src/entry.rs +++ b/server/lib/src/entry.rs @@ -43,7 +43,9 @@ use smartstring::alias::String as AttrString; use time::OffsetDateTime; use tracing::trace; use uuid::Uuid; -use webauthn_rs::prelude::{AttestedPasskey as DeviceKeyV4, Passkey as PasskeyV4}; +use webauthn_rs::prelude::{ + AttestationCaList, AttestedPasskey as AttestedPasskeyV4, Passkey as PasskeyV4, +}; use crate::be::dbentry::{DbEntry, DbEntryVers}; use crate::be::dbvalue::DbValueSetV2; @@ -2733,13 +2735,13 @@ impl Entry { #[inline(always)] /// Get the set of devicekeys on this account, if any are present. - pub fn get_ava_devicekeys( + pub fn get_ava_attestedpasskeys( &self, attr: Attribute, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { self.attrs .get(attr.as_ref()) - .and_then(|vs| vs.as_devicekey_map()) + .and_then(|vs| vs.as_attestedpasskey_map()) } #[inline(always)] @@ -2851,6 +2853,16 @@ impl Entry { .get(attr.as_ref()) .and_then(|vs| vs.to_eckey_public_single()) } + + pub fn get_ava_webauthn_attestation_ca_list( + &self, + attr: Attribute, + ) -> Option<&AttestationCaList> { + self.attrs + .get(attr.as_ref()) + .and_then(|vs| vs.as_webauthn_attestation_ca_list()) + } + #[inline(always)] /// Return a single security principle name, if valid to transform this value. pub(crate) fn generate_spn(&self, domain_name: &str) -> Option { diff --git a/server/lib/src/idm/account.rs b/server/lib/src/idm/account.rs index 9b2cf62bd..c9f0c331e 100644 --- a/server/lib/src/idm/account.rs +++ b/server/lib/src/idm/account.rs @@ -8,7 +8,7 @@ use kanidm_proto::v1::{ use time::OffsetDateTime; use uuid::Uuid; use webauthn_rs::prelude::{ - AttestedPasskey as DeviceKeyV4, AuthenticationResult, CredentialID, Passkey as PasskeyV4, + AttestedPasskey as AttestedPasskeyV4, AuthenticationResult, CredentialID, Passkey as PasskeyV4, }; use super::accountpolicy::ResolvedAccountPolicy; @@ -57,7 +57,7 @@ pub struct Account { pub groups: Vec, pub primary: Option, pub passkeys: BTreeMap, - pub devicekeys: BTreeMap, + pub attested_passkeys: BTreeMap, pub valid_from: Option, pub expire: Option, pub radius_secret: Option, @@ -106,8 +106,8 @@ macro_rules! try_from_entry { .cloned() .unwrap_or_default(); - let devicekeys = $value - .get_ava_devicekeys(Attribute::DeviceKeys) + let attested_passkeys = $value + .get_ava_attestedpasskeys(Attribute::AttestedPasskeys) .cloned() .unwrap_or_default(); @@ -206,7 +206,7 @@ macro_rules! try_from_entry { groups, primary, passkeys, - devicekeys, + attested_passkeys, valid_from, expire, radius_secret, @@ -522,6 +522,21 @@ impl Account { } }); + // Is it an attested passkey? + self.attested_passkeys.iter_mut().for_each(|(u, (t, k))| { + if let Some(true) = k.update_credential(auth_result) { + ml.push(Modify::Removed( + Attribute::AttestedPasskeys.into(), + PartialValue::AttestedPasskey(*u), + )); + + ml.push(Modify::Present( + Attribute::AttestedPasskeys.into(), + Value::AttestedPasskey(*u, t.clone(), k.clone()), + )); + } + }); + if ml.is_empty() { Ok(None) } else { @@ -641,6 +656,8 @@ impl Account { true } (SessionState::RevokedAt(_), _) => { + // William, if you have added a new type of credential, and end up here, you + // need to look at session consistency plugin. security_info!("Session has been revoked"); false } diff --git a/server/lib/src/idm/accountpolicy.rs b/server/lib/src/idm/accountpolicy.rs index f033336d2..01f9115a5 100644 --- a/server/lib/src/idm/accountpolicy.rs +++ b/server/lib/src/idm/accountpolicy.rs @@ -1,5 +1,6 @@ use crate::prelude::*; use crate::value::CredentialType; +use webauthn_rs::prelude::AttestationCaList; // use crate::idm::server::IdmServerProxyWriteTransaction; #[derive(Clone)] @@ -8,6 +9,7 @@ pub(crate) struct AccountPolicy { authsession_expiry: u32, pw_min_length: u32, credential_policy: CredentialType, + webauthn_att_ca_list: Option, } impl From<&EntrySealedCommitted> for Option { @@ -22,9 +24,11 @@ impl From<&EntrySealedCommitted> for Option { let authsession_expiry = val .get_ava_single_uint32(Attribute::AuthSessionExpiry) .unwrap_or(MAXIMUM_AUTH_SESSION_EXPIRY); + let privilege_expiry = val .get_ava_single_uint32(Attribute::PrivilegeExpiry) .unwrap_or(MAXIMUM_AUTH_PRIVILEGE_EXPIRY); + let pw_min_length = val .get_ava_single_uint32(Attribute::AuthPasswordMinimumLength) .unwrap_or(PW_MIN_LENGTH); @@ -33,11 +37,16 @@ impl From<&EntrySealedCommitted> for Option { .get_ava_single_credential_type(Attribute::CredentialTypeMinimum) .unwrap_or(CredentialType::Any); + let webauthn_att_ca_list = val + .get_ava_webauthn_attestation_ca_list(Attribute::WebauthnAttestationCaList) + .cloned(); + Some(AccountPolicy { privilege_expiry, authsession_expiry, pw_min_length, credential_policy, + webauthn_att_ca_list, }) } } @@ -49,6 +58,7 @@ pub(crate) struct ResolvedAccountPolicy { authsession_expiry: u32, pw_min_length: u32, credential_policy: CredentialType, + webauthn_att_ca_list: Option, } impl ResolvedAccountPolicy { @@ -62,6 +72,7 @@ impl ResolvedAccountPolicy { authsession_expiry: MAXIMUM_AUTH_SESSION_EXPIRY, pw_min_length: PW_MIN_LENGTH, credential_policy: CredentialType::Any, + webauthn_att_ca_list: None, }; iter.for_each(|acc_pol| { @@ -84,6 +95,14 @@ impl ResolvedAccountPolicy { if acc_pol.credential_policy > accumulate.credential_policy { accumulate.credential_policy = acc_pol.credential_policy } + + if let Some(acc_pol_w_att_ca) = acc_pol.webauthn_att_ca_list { + if let Some(res_w_att_ca) = accumulate.webauthn_att_ca_list.as_mut() { + res_w_att_ca.intersection(&acc_pol_w_att_ca); + } else { + accumulate.webauthn_att_ca_list = Some(acc_pol_w_att_ca); + } + } }); accumulate @@ -104,27 +123,107 @@ impl ResolvedAccountPolicy { pub(crate) fn credential_policy(&self) -> CredentialType { self.credential_policy } + + pub(crate) fn webauthn_attestation_ca_list(&self) -> Option<&AttestationCaList> { + self.webauthn_att_ca_list.as_ref() + } } #[cfg(test)] mod tests { use super::{AccountPolicy, CredentialType, ResolvedAccountPolicy}; - // use crate::prelude::*; + use crate::prelude::*; + use webauthn_rs_core::proto::AttestationCaListBuilder; #[test] fn test_idm_account_policy_resolve() { + sketching::test_init(); + + // Yubico U2F Root CA Serial 457200631 + let ca_root_a: &[u8] = b"-----BEGIN CERTIFICATE----- +MIIDHjCCAgagAwIBAgIEG0BT9zANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ +dWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAw +MDBaGA8yMDUwMDkwNDAwMDAwMFowLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290 +IENBIFNlcmlhbCA0NTcyMDA2MzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC/jwYuhBVlqaiYWEMsrWFisgJ+PtM91eSrpI4TK7U53mwCIawSDHy8vUmk +5N2KAj9abvT9NP5SMS1hQi3usxoYGonXQgfO6ZXyUA9a+KAkqdFnBnlyugSeCOep +8EdZFfsaRFtMjkwz5Gcz2Py4vIYvCdMHPtwaz0bVuzneueIEz6TnQjE63Rdt2zbw +nebwTG5ZybeWSwbzy+BJ34ZHcUhPAY89yJQXuE0IzMZFcEBbPNRbWECRKgjq//qT +9nmDOFVlSRCt2wiqPSzluwn+v+suQEBsUjTGMEd25tKXXTkNW21wIWbxeSyUoTXw +LvGS6xlwQSgNpk2qXYwf8iXg7VWZAgMBAAGjQjBAMB0GA1UdDgQWBBQgIvz0bNGJ +hjgpToksyKpP9xv9oDAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAN +BgkqhkiG9w0BAQsFAAOCAQEAjvjuOMDSa+JXFCLyBKsycXtBVZsJ4Ue3LbaEsPY4 +MYN/hIQ5ZM5p7EjfcnMG4CtYkNsfNHc0AhBLdq45rnT87q/6O3vUEtNMafbhU6kt +hX7Y+9XFN9NpmYxr+ekVY5xOxi8h9JDIgoMP4VB1uS0aunL1IGqrNooL9mmFnL2k +LVVee6/VR6C5+KSTCMCWppMuJIZII2v9o4dkoZ8Y7QRjQlLfYzd3qGtKbw7xaF1U +sG/5xUb/Btwb2X2g4InpiB/yt/3CpQXpiWX/K4mBvUKiGn05ZsqeY1gx4g0xLBqc +U9psmyPzK+Vsgw2jeRQ5JlKDyqE0hebfC1tvFu0CCrJFcw== +-----END CERTIFICATE-----"; + + // Defunct Apple WebAuthn Root CA + let ca_root_b: &[u8] = b"-----BEGIN CERTIFICATE----- +MIICEjCCAZmgAwIBAgIQaB0BbHo84wIlpQGUKEdXcTAKBggqhkjOPQQDAzBLMR8w +HQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ +bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MjEzMloXDTQ1MDMx +NTAwMDAwMFowSzEfMB0GA1UEAwwWQXBwbGUgV2ViQXV0aG4gUm9vdCBDQTETMBEG +A1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABCJCQ2pTVhzjl4Wo6IhHtMSAzO2cv+H9DQKev3//fG59G11k +xu9eI0/7o6V5uShBpe1u6l6mS19S1FEh6yGljnZAJ+2GNP1mi/YK2kSXIuTHjxA/ +pcoRf7XkOtO4o1qlcaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJtdk +2cV4wlpn0afeaxLQG2PxxtcwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA +MGQCMFrZ+9DsJ1PW9hfNdBywZDsWDbWFp28it1d/5w2RPkRX3Bbn/UbDTNLx7Jr3 +jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B +1bWeT0vT +-----END CERTIFICATE-----"; + + let aaguid_a = Uuid::new_v4(); + let aaguid_b = Uuid::new_v4(); + let aaguid_c = Uuid::new_v4(); + let aaguid_d = Uuid::new_v4(); + let aaguid_e = Uuid::new_v4(); + + let mut att_ca_builder = AttestationCaListBuilder::new(); + + att_ca_builder + .insert_device_pem(ca_root_a, aaguid_a, "A".to_string(), Default::default()) + .unwrap(); + att_ca_builder + .insert_device_pem(ca_root_a, aaguid_b, "B".to_string(), Default::default()) + .unwrap(); + att_ca_builder + .insert_device_pem(ca_root_a, aaguid_c, "C".to_string(), Default::default()) + .unwrap(); + att_ca_builder + .insert_device_pem(ca_root_b, aaguid_d, "D".to_string(), Default::default()) + .unwrap(); + + let att_ca_list_a = att_ca_builder.build(); + let policy_a = AccountPolicy { privilege_expiry: 100, authsession_expiry: 100, pw_min_length: 11, credential_policy: CredentialType::Mfa, + webauthn_att_ca_list: Some(att_ca_list_a), }; + let mut att_ca_builder = AttestationCaListBuilder::new(); + + att_ca_builder + .insert_device_pem(ca_root_a, aaguid_b, "B".to_string(), Default::default()) + .unwrap(); + att_ca_builder + .insert_device_pem(ca_root_b, aaguid_e, "E".to_string(), Default::default()) + .unwrap(); + + let att_ca_list_b = att_ca_builder.build(); + let policy_b = AccountPolicy { privilege_expiry: 150, authsession_expiry: 50, pw_min_length: 15, credential_policy: CredentialType::Passkey, + webauthn_att_ca_list: Some(att_ca_list_b), }; let rap = ResolvedAccountPolicy::fold_from([policy_a, policy_b].into_iter()); @@ -133,15 +232,15 @@ mod tests { assert_eq!(rap.authsession_expiry(), 50); assert_eq!(rap.pw_min_length(), 15); assert_eq!(rap.credential_policy, CredentialType::Passkey); - } - /* - #[idm_test] - async fn test_idm_account_policy_load( - idms: &IdmServer, - _idms_delayed: &mut IdmServerDelayed, - ) { - todo!(); + let mut att_ca_builder = AttestationCaListBuilder::new(); + + att_ca_builder + .insert_device_pem(ca_root_a, aaguid_b, "B".to_string(), Default::default()) + .unwrap(); + + let att_ca_list_ex = att_ca_builder.build(); + + assert_eq!(rap.webauthn_att_ca_list, Some(att_ca_list_ex)); } - */ } diff --git a/server/lib/src/idm/authsession.rs b/server/lib/src/idm/authsession.rs index d257c0b4b..69604e5f8 100644 --- a/server/lib/src/idm/authsession.rs +++ b/server/lib/src/idm/authsession.rs @@ -15,10 +15,10 @@ use kanidm_proto::v1::{ use nonempty::{nonempty, NonEmpty}; use tokio::sync::mpsc::UnboundedSender as Sender; use uuid::Uuid; -use webauthn_rs::prelude::Passkey as PasskeyV4; use webauthn_rs::prelude::{ - CredentialID, PasskeyAuthentication, RequestChallengeResponse, SecurityKeyAuthentication, - Webauthn, + AttestationCaList, AttestedPasskey as AttestedPasskeyV4, AttestedPasskeyAuthentication, + CredentialID, Passkey as PasskeyV4, PasskeyAuthentication, RequestChallengeResponse, + SecurityKeyAuthentication, Webauthn, }; use crate::credential::totp::Totp; @@ -43,6 +43,7 @@ use super::accountpolicy::ResolvedAccountPolicy; const BAD_PASSWORD_MSG: &str = "incorrect password"; const BAD_TOTP_MSG: &str = "incorrect totp"; const BAD_WEBAUTHN_MSG: &str = "invalid webauthn authentication"; +const BAD_ACCOUNT_POLICY: &str = "the credential no longer meets account policy requirements"; const BAD_BACKUPCODE_MSG: &str = "invalid backup code"; const BAD_AUTH_TYPE_MSG: &str = "invalid authentication method in this context"; const BAD_CREDENTIALS: &str = "invalid credential message"; @@ -56,6 +57,7 @@ pub enum AuthType { GeneratedPassword, PasswordMfa, Passkey, + AttestedPasskey, } impl fmt::Display for AuthType { @@ -66,6 +68,7 @@ impl fmt::Display for AuthType { AuthType::GeneratedPassword => write!(f, "generatedpassword"), AuthType::PasswordMfa => write!(f, "passwordmfa"), AuthType::Passkey => write!(f, "passkey"), + AuthType::AttestedPasskey => write!(f, "attested_passkey"), } } } @@ -108,13 +111,21 @@ struct CredMfa { } #[derive(Clone, Debug)] -/// The state of a webauthn credential during authentication -struct CredWebauthn { +/// The state of a passkey during authentication +struct CredPasskey { chal: RequestChallengeResponse, wan_state: PasskeyAuthentication, state: CredVerifyState, } +#[derive(Clone, Debug)] +/// The state of an attested passkey during authentication +struct CredAttestedPasskey { + chal: RequestChallengeResponse, + wan_state: AttestedPasskeyAuthentication, + state: CredVerifyState, +} + /// The current active handler for this authentication session. This is determined from what credentials /// are possible from the account, and what the user selected as the preferred authentication /// mechanism. @@ -133,9 +144,16 @@ enum CredHandler { cred_id: Uuid, }, Passkey { - c_wan: CredWebauthn, + c_wan: CredPasskey, cred_ids: BTreeMap, }, + AttestedPasskey { + c_wan: CredAttestedPasskey, + // To verify the attestation post auth + att_ca_list: AttestationCaList, + // AP does `PartialEq` on cred_id + creds: BTreeMap, + }, } impl TryFrom<(&Credential, &Webauthn)> for CredHandler { @@ -205,7 +223,7 @@ impl TryFrom<(&Credential, &Webauthn)> for CredHandler { webauthn .start_passkey_authentication(&pks) .map(|(chal, wan_state)| CredHandler::Passkey { - c_wan: CredWebauthn { + c_wan: CredPasskey { chal, wan_state, state: CredVerifyState::Init, @@ -221,31 +239,32 @@ impl TryFrom<(&Credential, &Webauthn)> for CredHandler { } } -impl TryFrom<(&BTreeMap, &Webauthn)> for CredHandler { - type Error = (); - +impl CredHandler { /// Given a credential and some external configuration, Generate the credential handler /// that will be used for this session. This credential handler is a "self contained" /// unit that defines what is possible to use during this authentication session to prevent /// inconsistency. - fn try_from( - (wan, webauthn): (&BTreeMap, &Webauthn), - ) -> Result { - if wan.is_empty() { - security_info!("Account does not have any passkeys"); - return Err(()); + fn build_from_set_passkey( + wan: impl Iterator, + webauthn: &Webauthn, + ) -> Result { + let mut pks = Vec::with_capacity(wan.size_hint().0); + let mut cred_ids = BTreeMap::default(); + + for (uuid, pk) in wan { + cred_ids.insert(pk.cred_id().clone(), uuid); + pks.push(pk); } - let pks: Vec<_> = wan.values().map(|(_, k)| k).cloned().collect(); - let cred_ids: BTreeMap<_, _> = wan - .iter() - .map(|(u, (_, k))| (k.cred_id().clone(), *u)) - .collect(); + if pks.is_empty() { + security_info!("Account does not have any passkeys"); + return Err(()); + }; webauthn .start_passkey_authentication(&pks) .map(|(chal, wan_state)| CredHandler::Passkey { - c_wan: CredWebauthn { + c_wan: CredPasskey { chal, wan_state, state: CredVerifyState::Init, @@ -260,20 +279,19 @@ impl TryFrom<(&BTreeMap, &Webauthn)> for CredHandler // maps to unit. }) } -} -impl TryFrom<(Uuid, &PasskeyV4, &Webauthn)> for CredHandler { - type Error = (); - fn try_from( - (cred_id, pk, webauthn): (Uuid, &PasskeyV4, &Webauthn), - ) -> Result { + fn build_from_single_passkey( + cred_id: Uuid, + pk: PasskeyV4, + webauthn: &Webauthn, + ) -> Result { let cred_ids = btreemap!((pk.cred_id().clone(), cred_id)); - let pks = vec![pk.clone()]; + let pks = vec![pk]; webauthn .start_passkey_authentication(pks.as_slice()) .map(|(chal, wan_state)| CredHandler::Passkey { - c_wan: CredWebauthn { + c_wan: CredPasskey { chal, wan_state, state: CredVerifyState::Init, @@ -288,9 +306,69 @@ impl TryFrom<(Uuid, &PasskeyV4, &Webauthn)> for CredHandler { // maps to unit. }) } -} -impl CredHandler { + fn build_from_set_attested_pk( + wan: &BTreeMap, + att_ca_list: &AttestationCaList, + webauthn: &Webauthn, + ) -> Result { + if wan.is_empty() { + security_info!("Account does not have any attested passkeys"); + return Err(()); + }; + + let pks: Vec<_> = wan.values().map(|(_, k)| k).cloned().collect(); + let creds: BTreeMap<_, _> = wan.iter().map(|(u, (_, k))| (k.clone(), *u)).collect(); + + webauthn + .start_attested_passkey_authentication(&pks) + .map(|(chal, wan_state)| CredHandler::AttestedPasskey { + c_wan: CredAttestedPasskey { + chal, + wan_state, + state: CredVerifyState::Init, + }, + att_ca_list: att_ca_list.clone(), + creds, + }) + .map_err(|e| { + security_info!( + ?e, + "Unable to create attested passkey webauthn authentication challenge" + ); + // maps to unit. + }) + } + + fn build_from_single_attested_pk( + cred_id: Uuid, + pk: &AttestedPasskeyV4, + att_ca_list: &AttestationCaList, + webauthn: &Webauthn, + ) -> Result { + let creds = btreemap!((pk.clone(), cred_id)); + let pks = vec![pk.clone()]; + + webauthn + .start_attested_passkey_authentication(pks.as_slice()) + .map(|(chal, wan_state)| CredHandler::AttestedPasskey { + c_wan: CredAttestedPasskey { + chal, + wan_state, + state: CredVerifyState::Init, + }, + att_ca_list: att_ca_list.clone(), + creds, + }) + .map_err(|e| { + security_info!( + ?e, + "Unable to create attested passkey webauthn authentication challenge" + ); + // maps to unit. + }) + } + /// Determine if this password factor requires an upgrade of it's cryptographic type. If /// so, send an asynchronous event into the queue that will allow the password to have it's /// content upgraded later. @@ -527,10 +605,10 @@ impl CredHandler { // end CredHandler::PasswordMfa /// Validate a webauthn authentication attempt - pub fn validate_webauthn( + pub fn validate_passkey( cred: &AuthCredential, cred_ids: &BTreeMap, - wan_cred: &mut CredWebauthn, + wan_cred: &mut CredPasskey, webauthn: &Webauthn, who: Uuid, async_tx: &Sender, @@ -591,6 +669,82 @@ impl CredHandler { } } + /// Validate a webauthn authentication attempt + pub fn validate_attested_passkey( + cred: &AuthCredential, + creds: &BTreeMap, + wan_cred: &mut CredAttestedPasskey, + webauthn: &Webauthn, + who: Uuid, + async_tx: &Sender, + att_ca_list: &AttestationCaList, + ) -> CredState { + if wan_cred.state != CredVerifyState::Init { + security_error!("Handler::Webauthn -> Result::Denied - Internal State Already Fail"); + return CredState::Denied(BAD_WEBAUTHN_MSG); + } + + match cred { + AuthCredential::Passkey(resp) => { + // lets see how we go. + match webauthn.finish_attested_passkey_authentication(resp, &wan_cred.wan_state) { + Ok(auth_result) => { + if let Some((apk, cred_id)) = creds.get_key_value(auth_result.cred_id()) { + // Verify attestation of the key. + + if let Err(webauthn_err) = apk.verify_attestation(att_ca_list) { + wan_cred.state = CredVerifyState::Fail; + // Denied. + debug!(?webauthn_err); + security_error!("Handler::Webauthn -> Result::Denied - webauthn credential fails attestation"); + return CredState::Denied(BAD_ACCOUNT_POLICY); + } + + wan_cred.state = CredVerifyState::Success; + // Success. Determine if we need to update the counter + // async from r. + if auth_result.needs_update() { + // Do async + if let Err(_e) = + async_tx.send(DelayedAction::WebauthnCounterIncrement( + WebauthnCounterIncrement { + target_uuid: who, + auth_result, + }, + )) + { + admin_warn!("unable to queue delayed webauthn property update, continuing ... "); + }; + }; + + CredState::Success { + auth_type: AuthType::AttestedPasskey, + cred_id: *cred_id, + } + } else { + wan_cred.state = CredVerifyState::Fail; + // Denied. + security_error!("Handler::Webauthn -> Result::Denied - webauthn credential id not found"); + CredState::Denied(BAD_WEBAUTHN_MSG) + } + } + Err(e) => { + wan_cred.state = CredVerifyState::Fail; + // Denied. + security_error!(?e, "Handler::Webauthn -> Result::Denied - webauthn error"); + CredState::Denied(BAD_WEBAUTHN_MSG) + } + } + } + _ => { + security_error!( + "Handler::Webauthn -> Result::Denied - invalid cred type for handler" + ); + CredState::Denied(BAD_AUTH_TYPE_MSG) + } + } + } + #[allow(clippy::too_many_arguments)] /// Given the current handler, proceed to authenticate the attempted credential step. pub fn validate( @@ -633,7 +787,20 @@ impl CredHandler { CredHandler::Passkey { ref mut c_wan, cred_ids, - } => Self::validate_webauthn(cred, cred_ids, c_wan, webauthn, who, async_tx), + } => Self::validate_passkey(cred, cred_ids, c_wan, webauthn, who, async_tx), + CredHandler::AttestedPasskey { + ref mut c_wan, + ref att_ca_list, + creds, + } => Self::validate_attested_passkey( + cred, + creds, + c_wan, + webauthn, + who, + async_tx, + att_ca_list, + ), } } @@ -659,6 +826,9 @@ impl CredHandler { ) .collect(), CredHandler::Passkey { c_wan, .. } => vec![AuthAllowed::Passkey(c_wan.chal.clone())], + CredHandler::AttestedPasskey { c_wan, .. } => { + vec![AuthAllowed::Passkey(c_wan.chal.clone())] + } } } @@ -668,7 +838,8 @@ impl CredHandler { (CredHandler::Anonymous { .. }, AuthMech::Anonymous) | (CredHandler::Password { .. }, AuthMech::Password) | (CredHandler::PasswordMfa { .. }, AuthMech::PasswordMfa) - | (CredHandler::Passkey { .. }, AuthMech::Passkey) => true, + | (CredHandler::Passkey { .. }, AuthMech::Passkey) + | (CredHandler::AttestedPasskey { .. }, AuthMech::Passkey) => true, (_, _) => false, } } @@ -679,6 +850,7 @@ impl CredHandler { CredHandler::Password { .. } => AuthMech::Password, CredHandler::PasswordMfa { .. } => AuthMech::PasswordMfa, CredHandler::Passkey { .. } => AuthMech::Passkey, + CredHandler::AttestedPasskey { .. } => AuthMech::Passkey, } } } @@ -767,9 +939,13 @@ impl AuthSession { // What's valid to use in this context? let mut handlers = Vec::new(); + // TODO: We can't yet fully enforce account policy on auth, there is a bit of work + // to do to be able to check for pw / mfa etc. + // A possible gotcha is service accounts which can't be affected by these policies? + + // let cred_type_min = asd.account_policy.credential_policy(); + if let Some(cred) = &asd.account.primary { - // TODO: Make it possible to have multiple creds. - // Probably means new authsession has to be failable if let Ok(ch) = CredHandler::try_from((cred, asd.webauthn)) { handlers.push(ch); } else { @@ -779,8 +955,33 @@ impl AuthSession { } } - if let Ok(ch) = CredHandler::try_from((&asd.account.passkeys, asd.webauthn)) { - handlers.push(ch); + // Important - if attested is present, don't use passkeys + if let Some(att_ca_list) = asd.account_policy.webauthn_attestation_ca_list() { + if let Ok(ch) = CredHandler::build_from_set_attested_pk( + &asd.account.attested_passkeys, + att_ca_list, + asd.webauthn, + ) { + handlers.push(ch); + } + } else { + let credential_iter = asd + .account + .passkeys + .iter() + .map(|(u, (_, pk))| (*u, pk.clone())) + .chain( + asd.account + .attested_passkeys + .iter() + .map(|(u, (_, pk))| (*u, pk.into())), + ); + + if let Ok(ch) = + CredHandler::build_from_set_passkey(credential_iter, asd.webauthn) + { + handlers.push(ch); + } }; if let Some(non_empty_handlers) = NonEmpty::collect(handlers) { @@ -847,6 +1048,9 @@ impl AuthSession { // Do we need to double check for anon here? I don't think so since the // anon cred_id won't ever exist on an account. + // We can't yet fully enforce account policy on auth, there is a bit of work + // to do to be able to check the credential types match what we expect. + let mut cred_handler = None; if let Some(primary) = asd.account.primary.as_ref() { @@ -863,13 +1067,51 @@ impl AuthSession { } } - if let Some(pk) = asd.account.passkeys.get(&cred_id).map(|(_, pk)| pk) { - if let Ok(ch) = CredHandler::try_from((cred_id, pk, asd.webauthn)) { - // Update it. - debug_assert!(cred_handler.is_none()); - cred_handler = Some(ch); - } else { - security_critical!("corrupt credentials, unable to start primary credhandler"); + // Do we have an attestation ca list? If so, we only accept attested + // passkeys. + if let Some(att_ca_list) = asd.account_policy.webauthn_attestation_ca_list() { + if let Some(pk) = asd + .account + .attested_passkeys + .get(&cred_id) + .map(|(_, pk)| pk) + { + if let Ok(ch) = CredHandler::build_from_single_attested_pk( + cred_id, + pk, + att_ca_list, + asd.webauthn, + ) { + // Update it. + debug_assert!(cred_handler.is_none()); + cred_handler = Some(ch); + } else { + security_critical!( + "corrupt credentials, unable to start attested passkey credhandler" + ); + } + } + } else { + // Scan both attested and passkeys for the possible credential. + let maybe_pk: Option = asd + .account + .attested_passkeys + .get(&cred_id) + .map(|(_, apk)| apk.into()) + .or_else(|| asd.account.passkeys.get(&cred_id).map(|(_, pk)| pk.clone())); + + if let Some(pk) = maybe_pk { + if let Ok(ch) = + CredHandler::build_from_single_passkey(cred_id, pk, asd.webauthn) + { + // Update it. + debug_assert!(cred_handler.is_none()); + cred_handler = Some(ch); + } else { + security_critical!( + "corrupt credentials, unable to start passkey credhandler" + ); + } } } @@ -932,7 +1174,8 @@ impl AuthSession { Ok(Some(*cred_id)) } AuthSessionState::InProgress(CredHandler::Anonymous { .. }) - | AuthSessionState::InProgress(CredHandler::Passkey { .. }) => Ok(None), + | AuthSessionState::InProgress(CredHandler::Passkey { .. }) + | AuthSessionState::InProgress(CredHandler::AttestedPasskey { .. }) => Ok(None), _ => Err(OperationError::InvalidState), } } @@ -1126,7 +1369,10 @@ impl AuthSession { let scope = match auth_type { AuthType::Anonymous => SessionScope::ReadOnly, AuthType::GeneratedPassword => SessionScope::ReadWrite, - AuthType::Password | AuthType::PasswordMfa | AuthType::Passkey => { + AuthType::Password + | AuthType::PasswordMfa + | AuthType::Passkey + | AuthType::AttestedPasskey => { if privileged { SessionScope::ReadWrite } else { @@ -1161,7 +1407,8 @@ impl AuthSession { AuthType::Password | AuthType::GeneratedPassword | AuthType::PasswordMfa - | AuthType::Passkey => { + | AuthType::Passkey + | AuthType::AttestedPasskey => { trace!("⚠️ Queued AuthSessionRecord for {}", self.account.uuid); async_tx.send(DelayedAction::AuthSessionRecord(AuthSessionRecord { target_uuid: self.account.uuid, @@ -1194,9 +1441,10 @@ impl AuthSession { error!("AuthType used in Reauth is not valid for session re-issuance. Rejecting"); return Err(OperationError::InvalidState); } - AuthType::Password | AuthType::PasswordMfa | AuthType::Passkey => { - SessionScope::PrivilegeCapable - } + AuthType::Password + | AuthType::PasswordMfa + | AuthType::Passkey + | AuthType::AttestedPasskey => SessionScope::PrivilegeCapable, }; let uat = self diff --git a/server/lib/src/idm/credupdatesession.rs b/server/lib/src/idm/credupdatesession.rs index d141c8d48..2254c0b92 100644 --- a/server/lib/src/idm/credupdatesession.rs +++ b/server/lib/src/idm/credupdatesession.rs @@ -14,8 +14,8 @@ use kanidm_proto::v1::{ use serde::{Deserialize, Serialize}; use time::OffsetDateTime; use webauthn_rs::prelude::{ - AttestedPasskey as DeviceKeyV4, CreationChallengeResponse, Passkey as PasskeyV4, - PasskeyRegistration, RegisterPublicKeyCredential, + AttestedPasskey as AttestedPasskeyV4, AttestedPasskeyRegistration, CreationChallengeResponse, + Passkey as PasskeyV4, PasskeyRegistration, RegisterPublicKeyCredential, WebauthnError, }; use crate::credential::totp::{Totp, TOTP_DEFAULT_STEP}; @@ -70,6 +70,8 @@ enum MfaRegState { TotpTryAgain(Totp), TotpInvalidSha1(Totp, Totp, String), Passkey(Box, PasskeyRegistration), + #[allow(dead_code)] + AttestedPasskey(Box, AttestedPasskeyRegistration), } impl fmt::Debug for MfaRegState { @@ -80,6 +82,7 @@ impl fmt::Debug for MfaRegState { MfaRegState::TotpTryAgain(_) => "MfaRegState::TotpTryAgain", MfaRegState::TotpInvalidSha1(_, _, _) => "MfaRegState::TotpInvalidSha1", MfaRegState::Passkey(_, _) => "MfaRegState::Passkey", + MfaRegState::AttestedPasskey(_, _) => "MfaRegState::AttestedPasskey", }; write!(f, "{t}") } @@ -88,6 +91,7 @@ impl fmt::Debug for MfaRegState { #[derive(Debug, Clone, Copy)] enum CredentialState { Modifiable, + DeleteOnly, AccessDeny, PolicyDeny, // Disabled, @@ -97,6 +101,7 @@ impl From for CUCredState { fn from(val: CredentialState) -> CUCredState { match val { CredentialState::Modifiable => CUCredState::Modifiable, + CredentialState::DeleteOnly => CUCredState::DeleteOnly, CredentialState::AccessDeny => CUCredState::AccessDeny, CredentialState::PolicyDeny => CUCredState::PolicyDeny, // CredentialState::Disabled => CUCredState::Disabled , @@ -133,9 +138,9 @@ pub(crate) struct CredentialUpdateSession { passkeys: BTreeMap, passkeys_state: CredentialState, - // Devicekeys - _devicekeys: BTreeMap, - _devicekeys_can_edit: bool, + // Attested Passkeys + attested_passkeys: BTreeMap, + attested_passkeys_state: CredentialState, // Internal reg state of any inprogress totp or webauthn credentials. mfaregstate: MfaRegState, @@ -152,6 +157,14 @@ impl fmt::Debug for CredentialUpdateSession { uuid: *uuid, }) .collect(); + let attested_passkeys: Vec = self + .attested_passkeys + .iter() + .map(|(uuid, (tag, _pk))| PasskeyDetail { + tag: tag.clone(), + uuid: *uuid, + }) + .collect(); f.debug_struct("CredentialUpdateSession") .field("account.spn", &self.account.spn) .field("account.unix", &self.account.unix_extn().is_some()) @@ -161,16 +174,16 @@ impl fmt::Debug for CredentialUpdateSession { .field("primary.state", &self.primary_state) .field("passkeys.list()", &passkeys) .field("passkeys.state", &self.passkeys_state) + .field("attested_passkeys.list()", &attested_passkeys) + .field("attested_passkeys.state", &self.attested_passkeys_state) .field("mfaregstate", &self.mfaregstate) .finish() } } impl CredentialUpdateSession { - // In future this should be a Vec of the issues with the current session so that UI's can highlight - // properly how to proceed. + // Vec of the issues with the current session so that UI's can highlight properly how to proceed. fn can_commit(&self) -> (bool, Vec) { - // Should be it's own PR and use account policy let mut warnings = Vec::with_capacity(0); let cred_type_min = self.resolved_account_policy.credential_policy(); @@ -198,15 +211,35 @@ impl CredentialUpdateSession { warnings.push(CredentialUpdateSessionStatusWarnings::PasskeyRequired); } } - // For now these error too. - CredentialType::AttestedPasskey - | CredentialType::AttestedResidentkey - | CredentialType::Invalid => { + CredentialType::AttestedPasskey => { + // Also unreachable - during these sessions, there will be no values present here. + if !self.passkeys.is_empty() || self.primary.is_some() { + warnings.push(CredentialUpdateSessionStatusWarnings::AttestedPasskeyRequired); + } + } + CredentialType::AttestedResidentkey => { + // Also unreachable - during these sessions, there will be no values present here. + if !self.attested_passkeys.is_empty() + || !self.passkeys.is_empty() + || self.primary.is_some() + { + warnings + .push(CredentialUpdateSessionStatusWarnings::AttestedResidentKeyRequired); + } + } + CredentialType::Invalid => { // special case, must always deny all changes. warnings.push(CredentialUpdateSessionStatusWarnings::Unsatisfiable) } } + if let Some(att_ca_list) = self.resolved_account_policy.webauthn_attestation_ca_list() { + if att_ca_list.is_empty() { + warnings + .push(CredentialUpdateSessionStatusWarnings::WebauthnAttestationUnsatisfiable) + } + } + (warnings.is_empty(), warnings) } } @@ -219,6 +252,7 @@ pub enum MfaRegStateStatus { TotpInvalidSha1, BackupCodes(HashSet), Passkey(CreationChallengeResponse), + AttestedPasskey(CreationChallengeResponse), } impl fmt::Debug for MfaRegStateStatus { @@ -230,6 +264,7 @@ impl fmt::Debug for MfaRegStateStatus { MfaRegStateStatus::TotpInvalidSha1 => "MfaRegStateStatus::TotpInvalidSha1", MfaRegStateStatus::BackupCodes(_) => "MfaRegStateStatus::BackupCodes", MfaRegStateStatus::Passkey(_) => "MfaRegStateStatus::Passkey", + MfaRegStateStatus::AttestedPasskey(_) => "MfaRegStateStatus::AttestedPasskey", }; write!(f, "{t}") } @@ -239,7 +274,10 @@ impl fmt::Debug for MfaRegStateStatus { pub enum CredentialUpdateSessionStatusWarnings { MfaRequired, PasskeyRequired, + AttestedPasskeyRequired, + AttestedResidentKeyRequired, Unsatisfiable, + WebauthnAttestationUnsatisfiable, } impl From for CURegWarning { @@ -247,7 +285,16 @@ impl From for CURegWarning { match val { CredentialUpdateSessionStatusWarnings::MfaRequired => CURegWarning::MfaRequired, CredentialUpdateSessionStatusWarnings::PasskeyRequired => CURegWarning::PasskeyRequired, + CredentialUpdateSessionStatusWarnings::AttestedPasskeyRequired => { + CURegWarning::AttestedPasskeyRequired + } + CredentialUpdateSessionStatusWarnings::AttestedResidentKeyRequired => { + CURegWarning::AttestedResidentKeyRequired + } CredentialUpdateSessionStatusWarnings::Unsatisfiable => CURegWarning::Unsatisfiable, + CredentialUpdateSessionStatusWarnings::WebauthnAttestationUnsatisfiable => { + CURegWarning::WebauthnAttestationUnsatisfiable + } } } } @@ -267,6 +314,9 @@ pub struct CredentialUpdateSessionStatus { primary_state: CredentialState, passkeys: Vec, passkeys_state: CredentialState, + attested_passkeys: Vec, + attested_passkeys_state: CredentialState, + attested_passkeys_allowed_devices: Vec, } impl CredentialUpdateSessionStatus { @@ -297,6 +347,7 @@ impl Into for CredentialUpdateSessionStatus { CURegState::BackupCodes(s.into_iter().collect()) } MfaRegStateStatus::Passkey(r) => CURegState::Passkey(r), + MfaRegStateStatus::AttestedPasskey(r) => CURegState::AttestedPasskey(r), }, can_commit: self.can_commit, warnings: self.warnings.into_iter().map(|w| w.into()).collect(), @@ -304,6 +355,9 @@ impl Into for CredentialUpdateSessionStatus { primary_state: self.primary_state.into(), passkeys: self.passkeys, passkeys_state: self.passkeys_state.into(), + attested_passkeys: self.attested_passkeys, + attested_passkeys_state: self.attested_passkeys_state.into(), + attested_passkeys_allowed_devices: self.attested_passkeys_allowed_devices, } } } @@ -312,6 +366,19 @@ impl From<&CredentialUpdateSession> for CredentialUpdateSessionStatus { fn from(session: &CredentialUpdateSession) -> Self { let (can_commit, warnings) = session.can_commit(); + let attested_passkeys_allowed_devices: Vec = session + .resolved_account_policy + .webauthn_attestation_ca_list() + .iter() + .flat_map(|att_ca_list| { + att_ca_list.cas().values().flat_map(|ca| { + ca.aaguids() + .values() + .map(|device| device.description_en().to_string()) + }) + }) + .collect(); + CredentialUpdateSessionStatus { spn: session.account.spn.clone(), displayname: session.account.displayname.clone(), @@ -329,6 +396,16 @@ impl From<&CredentialUpdateSession> for CredentialUpdateSessionStatus { }) .collect(), passkeys_state: session.passkeys_state, + attested_passkeys: session + .attested_passkeys + .iter() + .map(|(uuid, (tag, _pk))| PasskeyDetail { + tag: tag.clone(), + uuid: *uuid, + }) + .collect(), + attested_passkeys_state: session.attested_passkeys_state, + attested_passkeys_allowed_devices, mfaregstate: match &session.mfaregstate { MfaRegState::None => MfaRegStateStatus::None, MfaRegState::TotpInit(token) => MfaRegStateStatus::TotpCheck( @@ -337,6 +414,9 @@ impl From<&CredentialUpdateSession> for CredentialUpdateSessionStatus { MfaRegState::TotpTryAgain(_) => MfaRegStateStatus::TotpTryAgain, MfaRegState::TotpInvalidSha1(_, _, _) => MfaRegStateStatus::TotpInvalidSha1, MfaRegState::Passkey(r, _) => MfaRegStateStatus::Passkey(r.as_ref().clone()), + MfaRegState::AttestedPasskey(r, _) => { + MfaRegStateStatus::AttestedPasskey(r.as_ref().clone()) + } }, } } @@ -431,6 +511,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { Some(btreeset![ Attribute::PrimaryCredential.into(), Attribute::PassKeys.into(), + Attribute::AttestedPasskeys.into(), Attribute::UnixPassword.into(), Attribute::SshPublicKey.into() ]), @@ -491,6 +572,28 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let passkeys_can_edit = eperm_search_passkeys && eperm_mod_passkeys && eperm_rem_passkeys; + let eperm_search_attested_passkeys = match &eperm.search { + Access::Denied => false, + Access::Grant => true, + Access::Allow(attrs) => attrs.contains(Attribute::AttestedPasskeys.as_ref()), + }; + + let eperm_mod_attested_passkeys = match &eperm.modify_pres { + Access::Denied => false, + Access::Grant => true, + Access::Allow(attrs) => attrs.contains(Attribute::AttestedPasskeys.as_ref()), + }; + + let eperm_rem_attested_passkeys = match &eperm.modify_rem { + Access::Denied => false, + Access::Grant => true, + Access::Allow(attrs) => attrs.contains(Attribute::AttestedPasskeys.as_ref()), + }; + + let attested_passkeys_can_edit = eperm_search_attested_passkeys + && eperm_mod_attested_passkeys + && eperm_rem_attested_passkeys; + let eperm_search_unixcred = match &eperm.search { Access::Denied => false, Access::Grant => true, @@ -567,6 +670,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { // At lease *one* must be modifiable OR visible. if !(primary_can_edit || passkeys_can_edit + || attested_passkeys_can_edit || ext_cred_portal_can_view || sshpubkey_can_edit || unixcred_can_edit) @@ -581,6 +685,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { CredUpdateSessionPerms { ext_cred_portal_can_view, passkeys_can_edit, + attested_passkeys_can_edit, primary_can_edit, unixcred_can_edit, sshpubkey_can_edit, @@ -604,6 +709,13 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { let cred_type_min = resolved_account_policy.credential_policy(); + // We can't decide this based on CredentialType alone since we may have CredentialType::Mfa + // and still need attestation. As a result, we have to decide this based on presence of + // the attestation policy. + let passkey_attestation_required = resolved_account_policy + .webauthn_attestation_ca_list() + .is_some(); + let primary_state = if cred_type_min > CredentialType::Mfa { CredentialState::PolicyDeny } else if perms.primary_can_edit { @@ -612,10 +724,24 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { CredentialState::AccessDeny }; - let passkeys_state = if cred_type_min > CredentialType::Passkey { + let passkeys_state = + if cred_type_min > CredentialType::Passkey || passkey_attestation_required { + CredentialState::PolicyDeny + } else if perms.passkeys_can_edit { + CredentialState::Modifiable + } else { + CredentialState::AccessDeny + }; + + let attested_passkeys_state = if cred_type_min > CredentialType::AttestedPasskey { CredentialState::PolicyDeny - } else if perms.passkeys_can_edit { - CredentialState::Modifiable + } else if perms.attested_passkeys_can_edit { + if passkey_attestation_required { + CredentialState::Modifiable + } else { + // User can only delete, no police available to add more keys. + CredentialState::DeleteOnly + } } else { CredentialState::AccessDeny }; @@ -648,8 +774,37 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { BTreeMap::default() }; - // let devicekeys = account.devicekeys.clone(); - let devicekeys = BTreeMap::default(); + // Before we start, we pre-filter out anything that no longer conforms to policy. + // These would already be failing authentication, so they should have the appearance + // of "being removed". + let attested_passkeys = if matches!(attested_passkeys_state, CredentialState::Modifiable) + || matches!(attested_passkeys_state, CredentialState::DeleteOnly) + { + if let Some(att_ca_list) = resolved_account_policy.webauthn_attestation_ca_list() { + let mut attested_passkeys = BTreeMap::default(); + + for (uuid, (label, apk)) in account.attested_passkeys.iter() { + match apk.verify_attestation(att_ca_list) { + Ok(_) => { + // Good to go + attested_passkeys.insert(*uuid, (label.clone(), apk.clone())); + } + Err(e) => { + warn!(eclass=?e, emsg=%e, "credential no longer meets attestation criteria"); + } + } + } + + attested_passkeys + } else { + // Seems weird here to be skipping filtering of the credentials. The reason is that + // if an account had registered attested passkeys in the past we can delete them, but + // not add new ones. Situation only occurs when policy isn't present on the account. + account.attested_passkeys.clone() + } + } else { + BTreeMap::default() + }; // Get the external credential portal, if any. let ext_cred_portal = match (account.sync_parent_uuid, ext_cred_portal_can_view) { @@ -683,8 +838,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { sshpubkey_can_edit, passkeys, passkeys_state, - _devicekeys: devicekeys, - _devicekeys_can_edit: false, + attested_passkeys, + attested_passkeys_state, mfaregstate: MfaRegState::None, }; @@ -1149,15 +1304,14 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { modlist.push_mod(Modify::Present(Attribute::PrimaryCredential.into(), vcred)); }; } - CredentialState::PolicyDeny => { + CredentialState::DeleteOnly | CredentialState::PolicyDeny => { modlist.push_mod(Modify::Purged(Attribute::PrimaryCredential.into())); } - // CredentialState::Disabled | CredentialState::AccessDeny => {} }; match session.passkeys_state { - CredentialState::Modifiable => { + CredentialState::DeleteOnly | CredentialState::Modifiable => { modlist.push_mod(Modify::Purged(Attribute::PassKeys.into())); // Add all the passkeys. If none, nothing will be added! This handles // the delete case quite cleanly :) @@ -1169,6 +1323,25 @@ impl<'a> IdmServerProxyWriteTransaction<'a> { CredentialState::PolicyDeny => { modlist.push_mod(Modify::Purged(Attribute::PassKeys.into())); } + CredentialState::AccessDeny => {} + }; + + match session.attested_passkeys_state { + CredentialState::DeleteOnly | CredentialState::Modifiable => { + modlist.push_mod(Modify::Purged(Attribute::AttestedPasskeys.into())); + // Add all the passkeys. If none, nothing will be added! This handles + // the delete case quite cleanly :) + session + .attested_passkeys + .iter() + .for_each(|(uuid, (tag, pk))| { + let v_pk = Value::AttestedPasskey(*uuid, tag.clone(), pk.clone()); + modlist.push_mod(Modify::Present(Attribute::AttestedPasskeys.into(), v_pk)); + }); + } + CredentialState::PolicyDeny => { + modlist.push_mod(Modify::Purged(Attribute::AttestedPasskeys.into())); + } // CredentialState::Disabled | CredentialState::AccessDeny => {} }; @@ -1848,7 +2021,7 @@ impl<'a> IdmServerCredUpdateTransaction<'a> { trace!(?session); if !matches!(session.passkeys_state, CredentialState::Modifiable) { - error!("Session does not have permission to modify primary credential"); + error!("Session does not have permission to modify passkeys"); return Err(OperationError::AccessDenied); }; @@ -1890,25 +2063,28 @@ impl<'a> IdmServerCredUpdateTransaction<'a> { trace!(?session); if !matches!(session.passkeys_state, CredentialState::Modifiable) { - error!("Session does not have permission to modify primary credential"); + error!("Session does not have permission to modify passkeys"); return Err(OperationError::AccessDenied); }; match &session.mfaregstate { MfaRegState::Passkey(_ccr, pk_reg) => { - let passkey = self + let result = self .webauthn .finish_passkey_registration(reg, pk_reg) .map_err(|e| { - error!(eclass=?e, emsg=%e, "Unable to start passkey registration"); + error!(eclass=?e, emsg=%e, "Unable to complete passkey registration"); OperationError::Webauthn - })?; + }); + + // The reg is done. Clean up state before returning errors. + session.mfaregstate = MfaRegState::None; + + let passkey = result?; + let pk_id = Uuid::new_v4(); session.passkeys.insert(pk_id, (label, passkey)); - // The reg is done. - session.mfaregstate = MfaRegState::None; - Ok(session.deref().into()) } _ => Err(OperationError::InvalidRequestState), @@ -1928,8 +2104,10 @@ impl<'a> IdmServerCredUpdateTransaction<'a> { })?; trace!(?session); - if !matches!(session.passkeys_state, CredentialState::Modifiable) { - error!("Session does not have permission to modify primary credential"); + if !(matches!(session.passkeys_state, CredentialState::Modifiable) + || matches!(session.passkeys_state, CredentialState::DeleteOnly)) + { + error!("Session does not have permission to modify passkeys"); return Err(OperationError::AccessDenied); }; @@ -1939,6 +2117,138 @@ impl<'a> IdmServerCredUpdateTransaction<'a> { Ok(session.deref().into()) } + pub fn credential_attested_passkey_init( + &self, + cust: &CredentialUpdateSessionToken, + ct: Duration, + ) -> Result { + let session_handle = self.get_current_session(cust, ct)?; + let mut session = session_handle.try_lock().map_err(|_| { + error!("Session already locked, unable to proceed."); + OperationError::InvalidState + })?; + trace!(?session); + + if !matches!(session.attested_passkeys_state, CredentialState::Modifiable) { + error!("Session does not have permission to modify attested passkeys"); + return Err(OperationError::AccessDenied); + }; + + if !matches!(session.mfaregstate, MfaRegState::None) { + info!("Invalid Attested Passkey Init state, another update is in progress"); + return Err(OperationError::InvalidState); + } + + let att_ca_list = session + .resolved_account_policy + .webauthn_attestation_ca_list() + .cloned() + .ok_or_else(|| { + error!( + "No attestation CA list is available, can not proceed with attested passkeys." + ); + OperationError::AccessDenied + })?; + + let (ccr, pk_reg) = self + .webauthn + .start_attested_passkey_registration( + session.account.uuid, + &session.account.spn, + &session.account.displayname, + session.account.existing_credential_id_list(), + att_ca_list, + None, + ) + .map_err(|e| { + error!(eclass=?e, emsg=%e, "Unable to start passkey registration"); + OperationError::Webauthn + })?; + + session.mfaregstate = MfaRegState::AttestedPasskey(Box::new(ccr), pk_reg); + // Now that it's in the state, it'll be in the status when returned. + Ok(session.deref().into()) + } + + pub fn credential_attested_passkey_finish( + &self, + cust: &CredentialUpdateSessionToken, + ct: Duration, + label: String, + reg: &RegisterPublicKeyCredential, + ) -> Result { + let session_handle = self.get_current_session(cust, ct)?; + let mut session = session_handle.try_lock().map_err(|_| { + admin_error!("Session already locked, unable to proceed."); + OperationError::InvalidState + })?; + trace!(?session); + + if !matches!(session.attested_passkeys_state, CredentialState::Modifiable) { + error!("Session does not have permission to modify attested passkeys"); + return Err(OperationError::AccessDenied); + }; + + match &session.mfaregstate { + MfaRegState::AttestedPasskey(_ccr, pk_reg) => { + let result = self + .webauthn + .finish_attested_passkey_registration(reg, pk_reg) + .map_err(|e| { + error!(eclass=?e, emsg=%e, "Unable to complete passkey registration"); + + match e { + WebauthnError::AttestationChainNotTrusted(_) + | WebauthnError::AttestationNotVerifiable => { + OperationError::CU0001WebauthnAttestationNotTrusted + } + _ => OperationError::CU0002WebauthnRegistrationError, + } + }); + + // The reg is done. Clean up state before returning errors. + session.mfaregstate = MfaRegState::None; + + let passkey = result?; + trace!(?passkey); + + let pk_id = Uuid::new_v4(); + session.attested_passkeys.insert(pk_id, (label, passkey)); + + trace!(?session.attested_passkeys); + + Ok(session.deref().into()) + } + _ => Err(OperationError::InvalidRequestState), + } + } + + pub fn credential_attested_passkey_remove( + &self, + cust: &CredentialUpdateSessionToken, + ct: Duration, + uuid: Uuid, + ) -> Result { + let session_handle = self.get_current_session(cust, ct)?; + let mut session = session_handle.try_lock().map_err(|_| { + admin_error!("Session already locked, unable to proceed."); + OperationError::InvalidState + })?; + trace!(?session); + + if !(matches!(session.attested_passkeys_state, CredentialState::Modifiable) + || matches!(session.attested_passkeys_state, CredentialState::DeleteOnly)) + { + error!("Session does not have permission to modify attested passkeys"); + return Err(OperationError::AccessDenied); + }; + + // No-op if not present + session.attested_passkeys.remove(&uuid); + + Ok(session.deref().into()) + } + pub fn credential_update_cancel_mfareg( &self, cust: &CredentialUpdateSessionToken, @@ -1966,7 +2276,9 @@ impl<'a> IdmServerCredUpdateTransaction<'a> { })?; trace!(?session); - if !matches!(session.primary_state, CredentialState::Modifiable) { + if !(matches!(session.primary_state, CredentialState::Modifiable) + || matches!(session.primary_state, CredentialState::DeleteOnly)) + { error!("Session does not have permission to modify primary credential"); return Err(OperationError::AccessDenied); }; @@ -1988,7 +2300,9 @@ mod tests { }; use uuid::uuid; use webauthn_authenticator_rs::softpasskey::SoftPasskey; - use webauthn_authenticator_rs::WebauthnAuthenticator; + use webauthn_authenticator_rs::softtoken::{self, SoftToken}; + use webauthn_authenticator_rs::{AuthenticatorBackend, WebauthnAuthenticator}; + use webauthn_rs::prelude::AttestationCaListBuilder; use super::{ CredentialState, CredentialUpdateSessionStatus, CredentialUpdateSessionStatusWarnings, @@ -1997,6 +2311,7 @@ mod tests { }; use crate::credential::totp::Totp; use crate::event::CreateEvent; + use crate::idm::audit::AuditEvent; use crate::idm::delayed::DelayedAction; use crate::idm::event::{AuthEvent, AuthResult, RegenerateRadiusSecretEvent}; use crate::idm::server::{IdmServer, IdmServerCredUpdateTransaction, IdmServerDelayed}; @@ -2185,6 +2500,8 @@ mod tests { ct, ); + trace!(renew_test_session_result = ?cur); + idms_prox_write.commit().expect("Failed to commit txn"); cur.expect("Failed to start update") @@ -2371,10 +2688,10 @@ mod tests { } } - async fn check_testperson_passkey( + async fn check_testperson_passkey( idms: &IdmServer, idms_delayed: &mut IdmServerDelayed, - wa: &mut WebauthnAuthenticator, + wa: &mut WebauthnAuthenticator, origin: Url, ct: Duration, ) -> Option { @@ -3167,7 +3484,7 @@ mod tests { let c_status = cutxn .credential_passkey_remove(&cust, ct, pk_uuid) - .expect("Failed to delete the primary cred"); + .expect("Failed to delete the passkey"); trace!(?c_status); assert!(c_status.primary.is_none()); @@ -3254,11 +3571,18 @@ mod tests { primary_state, passkeys: _, passkeys_state, + attested_passkeys: _, + attested_passkeys_state, + attested_passkeys_allowed_devices: _, } = custatus; assert!(matches!(ext_cred_portal, CUExtPortal::Hidden)); assert!(matches!(primary_state, CredentialState::AccessDeny)); assert!(matches!(passkeys_state, CredentialState::AccessDeny)); + assert!(matches!( + attested_passkeys_state, + CredentialState::AccessDeny + )); let cutxn = idms.cred_update_transaction().await; @@ -3515,11 +3839,461 @@ mod tests { commit_session(idms, ct, cust).await; } - // enroll trusted device - // remove trusted device. - // trusted device flag changes? + // Attested passkey types - // Any policy checks we care about? + #[idm_test] + async fn test_idm_credential_update_account_policy_attested_passkey_required( + idms: &IdmServer, + idms_delayed: &mut IdmServerDelayed, + ) { + let ct = Duration::from_secs(TEST_CURRENT_TIME); - // Others in the future + // Create the attested soft token we will use in this test. + let (soft_token_valid, ca_root) = SoftToken::new(true).unwrap(); + let mut wa_token_valid = WebauthnAuthenticator::new(soft_token_valid); + + // Create it's associated policy. + let mut att_ca_builder = AttestationCaListBuilder::new(); + att_ca_builder + .insert_device_x509( + ca_root, + softtoken::AAGUID, + "softtoken".to_string(), + Default::default(), + ) + .unwrap(); + let att_ca_list = att_ca_builder.build(); + + let mut idms_prox_write = idms.proxy_write(ct).await; + + let modlist = ModifyList::new_purge_and_set( + Attribute::WebauthnAttestationCaList, + Value::WebauthnAttestationCaList(att_ca_list), + ); + idms_prox_write + .qs_write + .internal_modify_uuid(UUID_IDM_ALL_ACCOUNTS, &modlist) + .expect("Unable to change webauthn attestation policy"); + + assert!(idms_prox_write.commit().is_ok()); + + // Create the invalid tokens + let (soft_token_invalid, _) = SoftToken::new(true).unwrap(); + let mut wa_token_invalid = WebauthnAuthenticator::new(soft_token_invalid); + + let mut wa_passkey_invalid = WebauthnAuthenticator::new(SoftPasskey::new(true)); + + // Setup the cred update session. + + let (cust, _) = setup_test_session(idms, ct).await; + let cutxn = idms.cred_update_transaction().await; + let origin = cutxn.get_origin().clone(); + + // Our status needs the correct device names for UI hinting. + let c_status = cutxn + .credential_update_status(&cust, ct) + .expect("Failed to get the current session status."); + + trace!(?c_status); + assert!(c_status.attested_passkeys.is_empty()); + assert_eq!( + c_status.attested_passkeys_allowed_devices, + vec!["softtoken".to_string()] + ); + + // ------------------------------------------------------- + // Unable to add an passkey when attestation is requested. + let err = cutxn.credential_passkey_init(&cust, ct).unwrap_err(); + assert!(matches!(err, OperationError::AccessDenied)); + + // ------------------------------------------------------- + // Reject a credential that lacks attestation + let c_status = cutxn + .credential_attested_passkey_init(&cust, ct) + .expect("Failed to initiate attested passkey registration"); + + let passkey_chal = match c_status.mfaregstate { + MfaRegStateStatus::AttestedPasskey(c) => Some(c), + _ => None, + } + .expect("Unable to access passkey challenge, invalid state"); + + let passkey_resp = wa_passkey_invalid + .do_registration(origin.clone(), passkey_chal) + .expect("Failed to create soft passkey"); + + // Finish the registration + let label = "softtoken".to_string(); + let err = cutxn + .credential_attested_passkey_finish(&cust, ct, label, &passkey_resp) + .unwrap_err(); + + assert!(matches!( + err, + OperationError::CU0001WebauthnAttestationNotTrusted + )); + + // ------------------------------------------------------- + // Reject a credential with wrong CA / correct aaguid + let c_status = cutxn + .credential_attested_passkey_init(&cust, ct) + .expect("Failed to initiate attested passkey registration"); + + let passkey_chal = match c_status.mfaregstate { + MfaRegStateStatus::AttestedPasskey(c) => Some(c), + _ => None, + } + .expect("Unable to access passkey challenge, invalid state"); + + let passkey_resp = wa_token_invalid + .do_registration(origin.clone(), passkey_chal) + .expect("Failed to create soft passkey"); + + // Finish the registration + let label = "softtoken".to_string(); + let err = cutxn + .credential_attested_passkey_finish(&cust, ct, label, &passkey_resp) + .unwrap_err(); + + assert!(matches!( + err, + OperationError::CU0001WebauthnAttestationNotTrusted + )); + + // ------------------------------------------------------- + // Accept credential with correct CA/aaguid + let c_status = cutxn + .credential_attested_passkey_init(&cust, ct) + .expect("Failed to initiate attested passkey registration"); + + let passkey_chal = match c_status.mfaregstate { + MfaRegStateStatus::AttestedPasskey(c) => Some(c), + _ => None, + } + .expect("Unable to access passkey challenge, invalid state"); + + let passkey_resp = wa_token_valid + .do_registration(origin.clone(), passkey_chal) + .expect("Failed to create soft passkey"); + + // Finish the registration + let label = "softtoken".to_string(); + let c_status = cutxn + .credential_attested_passkey_finish(&cust, ct, label, &passkey_resp) + .expect("Failed to initiate passkey registration"); + + assert!(matches!(c_status.mfaregstate, MfaRegStateStatus::None)); + trace!(?c_status); + assert_eq!(c_status.attested_passkeys.len(), 1); + + let pk_uuid = c_status + .attested_passkeys + .first() + .map(|pkd| pkd.uuid) + .unwrap(); + + drop(cutxn); + commit_session(idms, ct, cust).await; + + // Assert that auth works. + assert!(check_testperson_passkey( + idms, + idms_delayed, + &mut wa_token_valid, + origin.clone(), + ct + ) + .await + .is_some()); + + // Remove attested passkey works. + let (cust, _) = renew_test_session(idms, ct).await; + let cutxn = idms.cred_update_transaction().await; + + trace!(?c_status); + assert!(c_status.primary.is_none()); + assert!(c_status.passkeys.is_empty()); + assert!(c_status.attested_passkeys.len() == 1); + + let c_status = cutxn + .credential_attested_passkey_remove(&cust, ct, pk_uuid) + .expect("Failed to delete the attested passkey"); + + trace!(?c_status); + assert!(c_status.primary.is_none()); + assert!(c_status.passkeys.is_empty()); + assert!(c_status.attested_passkeys.is_empty()); + + drop(cutxn); + commit_session(idms, ct, cust).await; + + // Must fail now! + assert!( + check_testperson_passkey(idms, idms_delayed, &mut wa_token_valid, origin, ct) + .await + .is_none() + ); + } + + #[idm_test(audit)] + async fn test_idm_credential_update_account_policy_attested_passkey_changed( + idms: &IdmServer, + idms_delayed: &mut IdmServerDelayed, + idms_audit: &mut IdmServerAudit, + ) { + let ct = Duration::from_secs(TEST_CURRENT_TIME); + + // Setup the policy. + let (soft_token_1, ca_root_1) = SoftToken::new(true).unwrap(); + let mut wa_token_1 = WebauthnAuthenticator::new(soft_token_1); + + let (_soft_token_2, ca_root_2) = SoftToken::new(true).unwrap(); + + let mut att_ca_builder = AttestationCaListBuilder::new(); + att_ca_builder + .insert_device_x509( + ca_root_1.clone(), + softtoken::AAGUID, + "softtoken_1".to_string(), + Default::default(), + ) + .unwrap(); + let att_ca_list = att_ca_builder.build(); + + trace!(?att_ca_list); + + let mut idms_prox_write = idms.proxy_write(ct).await; + + let modlist = ModifyList::new_purge_and_set( + Attribute::WebauthnAttestationCaList, + Value::WebauthnAttestationCaList(att_ca_list), + ); + idms_prox_write + .qs_write + .internal_modify_uuid(UUID_IDM_ALL_ACCOUNTS, &modlist) + .expect("Unable to change webauthn attestation policy"); + + assert!(idms_prox_write.commit().is_ok()); + + // Setup the policy for later that lacks token 2. + let mut att_ca_builder = AttestationCaListBuilder::new(); + att_ca_builder + .insert_device_x509( + ca_root_2, + softtoken::AAGUID, + "softtoken_2".to_string(), + Default::default(), + ) + .unwrap(); + let att_ca_list_post = att_ca_builder.build(); + + // Enroll the attested keys + let (cust, _) = setup_test_session(idms, ct).await; + let cutxn = idms.cred_update_transaction().await; + let origin = cutxn.get_origin().clone(); + + // ------------------------------------------------------- + let c_status = cutxn + .credential_attested_passkey_init(&cust, ct) + .expect("Failed to initiate attested passkey registration"); + + let passkey_chal = match c_status.mfaregstate { + MfaRegStateStatus::AttestedPasskey(c) => Some(c), + _ => None, + } + .expect("Unable to access passkey challenge, invalid state"); + + let passkey_resp = wa_token_1 + .do_registration(origin.clone(), passkey_chal) + .expect("Failed to create soft passkey"); + + // Finish the registration + let label = "softtoken".to_string(); + let c_status = cutxn + .credential_attested_passkey_finish(&cust, ct, label, &passkey_resp) + .expect("Failed to initiate passkey registration"); + + assert!(matches!(c_status.mfaregstate, MfaRegStateStatus::None)); + trace!(?c_status); + assert_eq!(c_status.attested_passkeys.len(), 1); + + // ------------------------------------------------------- + // Commit + drop(cutxn); + commit_session(idms, ct, cust).await; + + // Check auth works + assert!( + check_testperson_passkey(idms, idms_delayed, &mut wa_token_1, origin.clone(), ct) + .await + .is_some() + ); + + // Change policy + let mut idms_prox_write = idms.proxy_write(ct).await; + + let modlist = ModifyList::new_purge_and_set( + Attribute::WebauthnAttestationCaList, + Value::WebauthnAttestationCaList(att_ca_list_post), + ); + idms_prox_write + .qs_write + .internal_modify_uuid(UUID_IDM_ALL_ACCOUNTS, &modlist) + .expect("Unable to change webauthn attestation policy"); + + assert!(idms_prox_write.commit().is_ok()); + + // Auth fail + assert!( + check_testperson_passkey(idms, idms_delayed, &mut wa_token_1, origin.clone(), ct) + .await + .is_none() + ); + + // This gives an auth denied because the attested passkey still exists but it no longer + // meets criteria. + match idms_audit.audit_rx().try_recv() { + Ok(AuditEvent::AuthenticationDenied { .. }) => {} + _ => assert!(false), + } + + // Update creds + let (cust, _) = renew_test_session(idms, ct).await; + let cutxn = idms.cred_update_transaction().await; + + // Invalid key removed + let c_status = cutxn + .credential_update_status(&cust, ct) + .expect("Failed to get the current session status."); + + trace!(?c_status); + assert!(c_status.attested_passkeys.is_empty()); + + drop(cutxn); + commit_session(idms, ct, cust).await; + + // Auth fail + assert!( + check_testperson_passkey(idms, idms_delayed, &mut wa_token_1, origin.clone(), ct) + .await + .is_none() + ); + } + + // Test that when attestation policy is removed, the apk downgrades to passkey and still works. + #[idm_test] + async fn test_idm_credential_update_account_policy_attested_passkey_downgrade( + idms: &IdmServer, + idms_delayed: &mut IdmServerDelayed, + ) { + let ct = Duration::from_secs(TEST_CURRENT_TIME); + + // Setup the policy. + let (soft_token_1, ca_root_1) = SoftToken::new(true).unwrap(); + let mut wa_token_1 = WebauthnAuthenticator::new(soft_token_1); + + let mut att_ca_builder = AttestationCaListBuilder::new(); + att_ca_builder + .insert_device_x509( + ca_root_1.clone(), + softtoken::AAGUID, + "softtoken_1".to_string(), + Default::default(), + ) + .unwrap(); + let att_ca_list = att_ca_builder.build(); + + trace!(?att_ca_list); + + let mut idms_prox_write = idms.proxy_write(ct).await; + + let modlist = ModifyList::new_purge_and_set( + Attribute::WebauthnAttestationCaList, + Value::WebauthnAttestationCaList(att_ca_list), + ); + idms_prox_write + .qs_write + .internal_modify_uuid(UUID_IDM_ALL_ACCOUNTS, &modlist) + .expect("Unable to change webauthn attestation policy"); + + assert!(idms_prox_write.commit().is_ok()); + + // Enroll the attested keys + let (cust, _) = setup_test_session(idms, ct).await; + let cutxn = idms.cred_update_transaction().await; + let origin = cutxn.get_origin().clone(); + + // ------------------------------------------------------- + let c_status = cutxn + .credential_attested_passkey_init(&cust, ct) + .expect("Failed to initiate attested passkey registration"); + + let passkey_chal = match c_status.mfaregstate { + MfaRegStateStatus::AttestedPasskey(c) => Some(c), + _ => None, + } + .expect("Unable to access passkey challenge, invalid state"); + + let passkey_resp = wa_token_1 + .do_registration(origin.clone(), passkey_chal) + .expect("Failed to create soft passkey"); + + // Finish the registration + let label = "softtoken".to_string(); + let c_status = cutxn + .credential_attested_passkey_finish(&cust, ct, label, &passkey_resp) + .expect("Failed to initiate passkey registration"); + + assert!(matches!(c_status.mfaregstate, MfaRegStateStatus::None)); + trace!(?c_status); + assert_eq!(c_status.attested_passkeys.len(), 1); + + // ------------------------------------------------------- + // Commit + drop(cutxn); + commit_session(idms, ct, cust).await; + + // Check auth works + assert!( + check_testperson_passkey(idms, idms_delayed, &mut wa_token_1, origin.clone(), ct) + .await + .is_some() + ); + + // Change policy + let mut idms_prox_write = idms.proxy_write(ct).await; + + let modlist = ModifyList::new_purge(Attribute::WebauthnAttestationCaList); + idms_prox_write + .qs_write + .internal_modify_uuid(UUID_IDM_ALL_ACCOUNTS, &modlist) + .expect("Unable to change webauthn attestation policy"); + + assert!(idms_prox_write.commit().is_ok()); + + // Auth still passes, key was downgraded. + assert!( + check_testperson_passkey(idms, idms_delayed, &mut wa_token_1, origin.clone(), ct) + .await + .is_some() + ); + + // Show it still exists, but can only be deleted now. + let (cust, _) = renew_test_session(idms, ct).await; + let cutxn = idms.cred_update_transaction().await; + + let c_status = cutxn + .credential_update_status(&cust, ct) + .expect("Failed to get the current session status."); + + trace!(?c_status); + assert_eq!(c_status.attested_passkeys.len(), 1); + assert!(matches!( + c_status.attested_passkeys_state, + CredentialState::DeleteOnly + )); + + drop(cutxn); + commit_session(idms, ct, cust).await; + } } diff --git a/server/lib/src/plugins/protected.rs b/server/lib/src/plugins/protected.rs index 1b70bc23d..76dcddf02 100644 --- a/server/lib/src/plugins/protected.rs +++ b/server/lib/src/plugins/protected.rs @@ -36,6 +36,7 @@ lazy_static! { m.insert(Attribute::AuthSessionExpiry); m.insert(Attribute::PrivilegeExpiry); m.insert(Attribute::CredentialTypeMinimum); + m.insert(Attribute::WebauthnAttestationCaList); m }; } diff --git a/server/lib/src/plugins/session.rs b/server/lib/src/plugins/session.rs index 77726f339..16662eeda 100644 --- a/server/lib/src/plugins/session.rs +++ b/server/lib/src/plugins/session.rs @@ -64,7 +64,12 @@ impl SessionConsistency { .chain( entry.get_ava_passkeys(Attribute::PassKeys) .iter() - .flat_map(|pks| pks.keys().copied() ) + .flat_map(|pks| pks.keys().copied()) + ) + .chain( + entry.get_ava_attestedpasskeys(Attribute::AttestedPasskeys) + .iter() + .flat_map(|pks| pks.keys().copied()) ) .collect(); diff --git a/server/lib/src/repl/proto.rs b/server/lib/src/repl/proto.rs index cfe11bae2..1276623ec 100644 --- a/server/lib/src/repl/proto.rs +++ b/server/lib/src/repl/proto.rs @@ -11,7 +11,8 @@ use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet}; use webauthn_rs::prelude::{ - AttestedPasskey as DeviceKeyV4, Passkey as PasskeyV4, SecurityKey as SecurityKeyV4, + AttestationCaList, AttestedPasskey as AttestedPasskeyV4, Passkey as PasskeyV4, + SecurityKey as SecurityKeyV4, }; // Re-export this for our own usage. @@ -156,6 +157,8 @@ pub enum ReplIntentTokenV1 { #[serde(default)] passkeys_can_edit: bool, #[serde(default)] + attested_passkeys_can_edit: bool, + #[serde(default)] unixcred_can_edit: bool, #[serde(default)] sshpubkey_can_edit: bool, @@ -172,6 +175,8 @@ pub enum ReplIntentTokenV1 { #[serde(default)] passkeys_can_edit: bool, #[serde(default)] + attested_passkeys_can_edit: bool, + #[serde(default)] unixcred_can_edit: bool, #[serde(default)] sshpubkey_can_edit: bool, @@ -212,15 +217,15 @@ impl PartialEq for ReplPasskeyV4V1 { } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct ReplDeviceKeyV4V1 { +pub struct ReplAttestedPasskeyV4V1 { pub uuid: Uuid, pub tag: String, - pub key: DeviceKeyV4, + pub key: AttestedPasskeyV4, } -impl Eq for ReplDeviceKeyV4V1 {} +impl Eq for ReplAttestedPasskeyV4V1 {} -impl PartialEq for ReplDeviceKeyV4V1 { +impl PartialEq for ReplAttestedPasskeyV4V1 { fn eq(&self, other: &Self) -> bool { self.uuid == other.uuid && self.key.cred_id() == other.key.cred_id() } @@ -325,8 +330,8 @@ pub enum ReplAttrV1 { Passkey { set: Vec, }, - DeviceKey { - set: Vec, + AttestedPasskey { + set: Vec, }, DateTime { set: Vec, @@ -415,6 +420,9 @@ pub enum ReplAttrV1 { CredentialType { set: Vec, }, + WebauthnAttestationCaList { + ca_list: AttestationCaList, + }, } #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] diff --git a/server/lib/src/schema.rs b/server/lib/src/schema.rs index ad42e1c5c..17c31e32f 100644 --- a/server/lib/src/schema.rs +++ b/server/lib/src/schema.rs @@ -216,7 +216,7 @@ impl SchemaAttribute { SyntaxType::PrivateBinary => matches!(v, PartialValue::PrivateBinary), SyntaxType::IntentToken => matches!(v, PartialValue::IntentToken(_)), SyntaxType::Passkey => matches!(v, PartialValue::Passkey(_)), - SyntaxType::DeviceKey => matches!(v, PartialValue::DeviceKey(_)), + SyntaxType::AttestedPasskey => matches!(v, PartialValue::AttestedPasskey(_)), // Allow refer types. SyntaxType::Session => matches!(v, PartialValue::Refer(_)), SyntaxType::ApiToken => matches!(v, PartialValue::Refer(_)), @@ -231,6 +231,7 @@ impl SchemaAttribute { SyntaxType::AuditLogString => matches!(v, PartialValue::Utf8(_)), SyntaxType::Image => matches!(v, PartialValue::Utf8(_)), SyntaxType::CredentialType => matches!(v, PartialValue::CredentialType(_)), + SyntaxType::WebauthnAttestationCaList => false, }; if r { Ok(()) @@ -272,7 +273,7 @@ impl SchemaAttribute { SyntaxType::PrivateBinary => matches!(v, Value::PrivateBinary(_)), SyntaxType::IntentToken => matches!(v, Value::IntentToken(_, _)), SyntaxType::Passkey => matches!(v, Value::Passkey(_, _, _)), - SyntaxType::DeviceKey => matches!(v, Value::DeviceKey(_, _, _)), + SyntaxType::AttestedPasskey => matches!(v, Value::AttestedPasskey(_, _, _)), SyntaxType::Session => matches!(v, Value::Session(_, _)), SyntaxType::ApiToken => matches!(v, Value::ApiToken(_, _)), SyntaxType::Oauth2Session => matches!(v, Value::Oauth2Session(_, _)), @@ -284,6 +285,9 @@ impl SchemaAttribute { SyntaxType::EcKeyPrivate => matches!(v, Value::EcKeyPrivate(_)), SyntaxType::Image => matches!(v, Value::Image(_)), SyntaxType::CredentialType => matches!(v, Value::CredentialType(_)), + SyntaxType::WebauthnAttestationCaList => { + matches!(v, Value::WebauthnAttestationCaList(_)) + } }; if r { Ok(()) diff --git a/server/lib/src/server/migrations.rs b/server/lib/src/server/migrations.rs index bd1bd0b20..10c5dfbee 100644 --- a/server/lib/src/server/migrations.rs +++ b/server/lib/src/server/migrations.rs @@ -566,7 +566,7 @@ impl<'a> QueryServerWriteTransaction<'a> { SCHEMA_ATTR_AUTH_PASSWORD_MINIMUM_LENGTH.clone().into(), SCHEMA_ATTR_BADLIST_PASSWORD.clone().into(), SCHEMA_ATTR_CREDENTIAL_UPDATE_INTENT_TOKEN.clone().into(), - SCHEMA_ATTR_DEVICEKEYS.clone().into(), + SCHEMA_ATTR_ATTESTED_PASSKEYS.clone().into(), SCHEMA_ATTR_DISPLAYNAME.clone().into(), SCHEMA_ATTR_DOMAIN_DISPLAY_NAME.clone().into(), SCHEMA_ATTR_DOMAIN_LDAP_BASEDN.clone().into(), @@ -613,6 +613,7 @@ impl<'a> QueryServerWriteTransaction<'a> { SCHEMA_ATTR_USER_AUTH_TOKEN_SESSION.clone().into(), SCHEMA_ATTR_DENIED_NAME.clone().into(), SCHEMA_ATTR_CREDENTIAL_TYPE_MINIMUM.clone().into(), + SCHEMA_ATTR_WEBAUTHN_ATTESTATION_CA_LIST.clone().into(), ]; let r = idm_schema diff --git a/server/lib/src/server/mod.rs b/server/lib/src/server/mod.rs index b9498da9c..ae24da268 100644 --- a/server/lib/src/server/mod.rs +++ b/server/lib/src/server/mod.rs @@ -577,11 +577,13 @@ pub trait QueryServerTransaction<'a> { .ok_or_else(|| OperationError::InvalidAttribute("Invalid Url (whatwg/url) syntax".to_string())), SyntaxType::OauthScope => Value::new_oauthscope(value) .ok_or_else(|| OperationError::InvalidAttribute("Invalid Oauth Scope syntax".to_string())), + SyntaxType::WebauthnAttestationCaList => Value::new_webauthn_attestation_ca_list(value) + .ok_or_else(|| OperationError::InvalidAttribute("Invalid Webauthn Attestation CA List".to_string())), SyntaxType::OauthScopeMap => Err(OperationError::InvalidAttribute("Oauth Scope Maps can not be supplied through modification - please use the IDM api".to_string())), SyntaxType::PrivateBinary => Err(OperationError::InvalidAttribute("Private Binary Values can not be supplied through modification".to_string())), SyntaxType::IntentToken => Err(OperationError::InvalidAttribute("Intent Token Values can not be supplied through modification".to_string())), SyntaxType::Passkey => Err(OperationError::InvalidAttribute("Passkey Values can not be supplied through modification".to_string())), - SyntaxType::DeviceKey => Err(OperationError::InvalidAttribute("DeviceKey Values can not be supplied through modification".to_string())), + SyntaxType::AttestedPasskey => Err(OperationError::InvalidAttribute("AttestedPasskey Values can not be supplied through modification".to_string())), SyntaxType::Session => Err(OperationError::InvalidAttribute("Session Values can not be supplied through modification".to_string())), SyntaxType::ApiToken => Err(OperationError::InvalidAttribute("ApiToken Values can not be supplied through modification".to_string())), SyntaxType::JwsKeyEs256 => Err(OperationError::InvalidAttribute("JwsKeyEs256 Values can not be supplied through modification".to_string())), @@ -634,7 +636,7 @@ pub trait QueryServerTransaction<'a> { .map(PartialValue::CredentialType) .map_err(|()| { OperationError::InvalidAttribute( - "Invalid CredentialType syntax".to_string(), + "Invalid credentialtype syntax".to_string(), ) }), SyntaxType::Uuid => { @@ -694,13 +696,12 @@ pub trait QueryServerTransaction<'a> { SyntaxType::Passkey => PartialValue::new_passkey_s(value).ok_or_else(|| { OperationError::InvalidAttribute("Invalid Passkey UUID syntax".to_string()) }), - SyntaxType::DeviceKey => { - PartialValue::new_devicekey_s(value).ok_or_else(|| { + SyntaxType::AttestedPasskey => PartialValue::new_attested_passkey_s(value) + .ok_or_else(|| { OperationError::InvalidAttribute( - "Invalid DeviceKey UUID syntax".to_string(), + "Invalid AttestedPasskey UUID syntax".to_string(), ) - }) - } + }), SyntaxType::UiHint => UiHint::from_str(value) .map(PartialValue::UiHint) .map_err(|()| { @@ -709,6 +710,9 @@ pub trait QueryServerTransaction<'a> { SyntaxType::AuditLogString => Ok(PartialValue::new_utf8s(value)), SyntaxType::EcKeyPrivate => Ok(PartialValue::SecretValue), SyntaxType::Image => Ok(PartialValue::new_utf8s(value)), + SyntaxType::WebauthnAttestationCaList => Err(OperationError::InvalidAttribute( + "Invalid - unable to query attestation CA list".to_string(), + )), } } None => { diff --git a/server/lib/src/value.rs b/server/lib/src/value.rs index 74b51a273..e23b52277 100644 --- a/server/lib/src/value.rs +++ b/server/lib/src/value.rs @@ -27,7 +27,9 @@ use sshkey_attest::proto::PublicKey as SshPublicKey; use time::OffsetDateTime; use url::Url; use uuid::Uuid; -use webauthn_rs::prelude::{AttestedPasskey as DeviceKeyV4, Passkey as PasskeyV4}; +use webauthn_rs::prelude::{ + AttestationCaList, AttestedPasskey as AttestedPasskeyV4, Passkey as PasskeyV4, +}; use crate::be::dbentry::DbIdentSpn; use crate::credential::{totp::Totp, Credential}; @@ -124,6 +126,7 @@ pub struct CredUpdateSessionPerms { pub ext_cred_portal_can_view: bool, pub primary_can_edit: bool, pub passkeys_can_edit: bool, + pub attested_passkeys_can_edit: bool, pub unixcred_can_edit: bool, pub sshpubkey_can_edit: bool, } @@ -248,7 +251,7 @@ pub enum SyntaxType { PrivateBinary = 21, IntentToken = 22, Passkey = 23, - DeviceKey = 24, + AttestedPasskey = 24, Session = 25, JwsKeyEs256 = 26, JwsKeyRs256 = 27, @@ -260,6 +263,7 @@ pub enum SyntaxType { EcKeyPrivate = 33, Image = 34, CredentialType = 35, + WebauthnAttestationCaList = 36, } impl TryFrom<&str> for SyntaxType { @@ -293,7 +297,7 @@ impl TryFrom<&str> for SyntaxType { "PRIVATE_BINARY" => Ok(SyntaxType::PrivateBinary), "INTENT_TOKEN" => Ok(SyntaxType::IntentToken), "PASSKEY" => Ok(SyntaxType::Passkey), - "DEVICEKEY" => Ok(SyntaxType::DeviceKey), + "ATTESTED_PASSKEY" => Ok(SyntaxType::AttestedPasskey), "SESSION" => Ok(SyntaxType::Session), "JWS_KEY_ES256" => Ok(SyntaxType::JwsKeyEs256), "JWS_KEY_RS256" => Ok(SyntaxType::JwsKeyRs256), @@ -304,6 +308,7 @@ impl TryFrom<&str> for SyntaxType { "AUDIT_LOG_STRING" => Ok(SyntaxType::AuditLogString), "EC_KEY_PRIVATE" => Ok(SyntaxType::EcKeyPrivate), "CREDENTIAL_TYPE" => Ok(SyntaxType::CredentialType), + "WEBAUTHN_ATTESTATION_CA_LIST" => Ok(SyntaxType::WebauthnAttestationCaList), _ => Err(()), } } @@ -336,7 +341,7 @@ impl fmt::Display for SyntaxType { SyntaxType::PrivateBinary => "PRIVATE_BINARY", SyntaxType::IntentToken => "INTENT_TOKEN", SyntaxType::Passkey => "PASSKEY", - SyntaxType::DeviceKey => "DEVICEKEY", + SyntaxType::AttestedPasskey => "ATTESTED_PASSKEY", SyntaxType::Session => "SESSION", SyntaxType::JwsKeyEs256 => "JWS_KEY_ES256", SyntaxType::JwsKeyRs256 => "JWS_KEY_RS256", @@ -348,6 +353,7 @@ impl fmt::Display for SyntaxType { SyntaxType::EcKeyPrivate => "EC_KEY_PRIVATE", SyntaxType::Image => "IMAGE", SyntaxType::CredentialType => "CREDENTIAL_TYPE", + SyntaxType::WebauthnAttestationCaList => "WEBAUTHN_ATTESTATION_CA_LIST", }) } } @@ -461,7 +467,7 @@ pub enum PartialValue { IntentToken(String), UiHint(UiHint), Passkey(Uuid), - DeviceKey(Uuid), + AttestedPasskey(Uuid), /// We compare on the value hash Image(String), CredentialType(CredentialType), @@ -776,8 +782,8 @@ impl PartialValue { Uuid::parse_str(us).map(PartialValue::Passkey).ok() } - pub fn new_devicekey_s(us: &str) -> Option { - Uuid::parse_str(us).map(PartialValue::DeviceKey).ok() + pub fn new_attested_passkey_s(us: &str) -> Option { + Uuid::parse_str(us).map(PartialValue::AttestedPasskey).ok() } pub fn new_image(input: &str) -> Self { @@ -809,7 +815,7 @@ impl PartialValue { | PartialValue::EmailAddress(s) | PartialValue::RestrictedString(s) => s.clone(), PartialValue::Passkey(u) - | PartialValue::DeviceKey(u) + | PartialValue::AttestedPasskey(u) | PartialValue::Refer(u) | PartialValue::Uuid(u) => u.as_hyphenated().to_string(), PartialValue::Bool(b) => b.to_string(), @@ -1023,7 +1029,7 @@ pub enum Value { RestrictedString(String), IntentToken(String, IntentTokenState), Passkey(Uuid, String, PasskeyV4), - DeviceKey(Uuid, String, DeviceKeyV4), + AttestedPasskey(Uuid, String, AttestedPasskeyV4), Session(Uuid, Session), ApiToken(Uuid, ApiToken), @@ -1039,6 +1045,7 @@ pub enum Value { Image(ImageValue), CredentialType(CredentialType), + WebauthnAttestationCaList(AttestationCaList), } impl PartialEq for Value { @@ -1538,6 +1545,15 @@ impl Value { Value::RestrictedString(s) } + pub fn new_webauthn_attestation_ca_list(s: &str) -> Option { + serde_json::from_str(s) + .map(Value::WebauthnAttestationCaList) + .map_err(|err| { + debug!(?err, ?s); + }) + .ok() + } + #[allow(clippy::unreachable)] pub(crate) fn to_db_ident_spn(&self) -> DbIdentSpn { // This has to clone due to how the backend works. @@ -1788,7 +1804,7 @@ impl Value { | Value::PublicBinary(s, _) | Value::IntentToken(s, _) | Value::Passkey(_, s, _) - | Value::DeviceKey(_, s, _) + | Value::AttestedPasskey(_, s, _) | Value::TotpSecret(s, _) => { Value::validate_str_escapes(s) && Value::validate_singleline(s) } @@ -1846,7 +1862,8 @@ impl Value { | Value::JwsKeyRs256(_) | Value::EcKeyPrivate(_) | Value::UiHint(_) - | Value::CredentialType(_) => true, + | Value::CredentialType(_) + | Value::WebauthnAttestationCaList(_) => true, } } diff --git a/server/lib/src/valueset/cred.rs b/server/lib/src/valueset/cred.rs index b57f34627..2de252426 100644 --- a/server/lib/src/valueset/cred.rs +++ b/server/lib/src/valueset/cred.rs @@ -2,15 +2,17 @@ use smolset::SmolSet; use std::collections::btree_map::Entry as BTreeEntry; use std::collections::BTreeMap; -use webauthn_rs::prelude::{AttestedPasskey as DeviceKeyV4, Passkey as PasskeyV4}; +use webauthn_rs::prelude::{ + AttestationCaList, AttestedPasskey as AttestedPasskeyV4, Passkey as PasskeyV4, +}; use crate::be::dbvalue::{ - DbValueCredV1, DbValueDeviceKeyV1, DbValueIntentTokenStateV1, DbValuePasskeyV1, + DbValueAttestedPasskeyV1, DbValueCredV1, DbValueIntentTokenStateV1, DbValuePasskeyV1, }; use crate::credential::Credential; use crate::prelude::*; use crate::repl::proto::{ - ReplAttrV1, ReplCredV1, ReplDeviceKeyV4V1, ReplIntentTokenV1, ReplPasskeyV4V1, + ReplAttestedPasskeyV4V1, ReplAttrV1, ReplCredV1, ReplIntentTokenV1, ReplPasskeyV4V1, }; use crate::schema::SchemaAttribute; use crate::value::{CredUpdateSessionPerms, CredentialType, IntentTokenState}; @@ -230,6 +232,7 @@ impl ValueSetIntentToken { ext_cred_portal_can_view, primary_can_edit, passkeys_can_edit, + attested_passkeys_can_edit, unixcred_can_edit, sshpubkey_can_edit, } => IntentTokenState::Valid { @@ -238,6 +241,7 @@ impl ValueSetIntentToken { ext_cred_portal_can_view, primary_can_edit, passkeys_can_edit, + attested_passkeys_can_edit, unixcred_can_edit, sshpubkey_can_edit, }, @@ -249,6 +253,7 @@ impl ValueSetIntentToken { ext_cred_portal_can_view, primary_can_edit, passkeys_can_edit, + attested_passkeys_can_edit, unixcred_can_edit, sshpubkey_can_edit, } => IntentTokenState::InProgress { @@ -259,6 +264,7 @@ impl ValueSetIntentToken { ext_cred_portal_can_view, primary_can_edit, passkeys_can_edit, + attested_passkeys_can_edit, unixcred_can_edit, sshpubkey_can_edit, }, @@ -283,6 +289,7 @@ impl ValueSetIntentToken { ext_cred_portal_can_view, primary_can_edit, passkeys_can_edit, + attested_passkeys_can_edit, unixcred_can_edit, sshpubkey_can_edit, } => ( @@ -293,6 +300,7 @@ impl ValueSetIntentToken { ext_cred_portal_can_view: *ext_cred_portal_can_view, primary_can_edit: *primary_can_edit, passkeys_can_edit: *passkeys_can_edit, + attested_passkeys_can_edit: *attested_passkeys_can_edit, unixcred_can_edit: *unixcred_can_edit, sshpubkey_can_edit: *sshpubkey_can_edit, }, @@ -306,6 +314,7 @@ impl ValueSetIntentToken { ext_cred_portal_can_view, primary_can_edit, passkeys_can_edit, + attested_passkeys_can_edit, unixcred_can_edit, sshpubkey_can_edit, } => ( @@ -318,6 +327,7 @@ impl ValueSetIntentToken { ext_cred_portal_can_view: *ext_cred_portal_can_view, primary_can_edit: *primary_can_edit, passkeys_can_edit: *passkeys_can_edit, + attested_passkeys_can_edit: *attested_passkeys_can_edit, unixcred_can_edit: *unixcred_can_edit, sshpubkey_can_edit: *sshpubkey_can_edit, }, @@ -435,6 +445,7 @@ impl ValueSetT for ValueSetIntentToken { ext_cred_portal_can_view, primary_can_edit, passkeys_can_edit, + attested_passkeys_can_edit, unixcred_can_edit, sshpubkey_can_edit, }, @@ -443,6 +454,7 @@ impl ValueSetT for ValueSetIntentToken { ext_cred_portal_can_view: *ext_cred_portal_can_view, primary_can_edit: *primary_can_edit, passkeys_can_edit: *passkeys_can_edit, + attested_passkeys_can_edit: *attested_passkeys_can_edit, unixcred_can_edit: *unixcred_can_edit, sshpubkey_can_edit: *sshpubkey_can_edit, }, @@ -455,6 +467,7 @@ impl ValueSetT for ValueSetIntentToken { ext_cred_portal_can_view, primary_can_edit, passkeys_can_edit, + attested_passkeys_can_edit, unixcred_can_edit, sshpubkey_can_edit, }, @@ -465,6 +478,7 @@ impl ValueSetT for ValueSetIntentToken { ext_cred_portal_can_view: *ext_cred_portal_can_view, primary_can_edit: *primary_can_edit, passkeys_can_edit: *passkeys_can_edit, + attested_passkeys_can_edit: *attested_passkeys_can_edit, unixcred_can_edit: *unixcred_can_edit, sshpubkey_can_edit: *sshpubkey_can_edit, }, @@ -491,6 +505,7 @@ impl ValueSetT for ValueSetIntentToken { ext_cred_portal_can_view, primary_can_edit, passkeys_can_edit, + attested_passkeys_can_edit, unixcred_can_edit, sshpubkey_can_edit, }, @@ -500,6 +515,7 @@ impl ValueSetT for ValueSetIntentToken { ext_cred_portal_can_view: *ext_cred_portal_can_view, primary_can_edit: *primary_can_edit, passkeys_can_edit: *passkeys_can_edit, + attested_passkeys_can_edit: *attested_passkeys_can_edit, unixcred_can_edit: *unixcred_can_edit, sshpubkey_can_edit: *sshpubkey_can_edit, }, @@ -512,6 +528,7 @@ impl ValueSetT for ValueSetIntentToken { ext_cred_portal_can_view, primary_can_edit, passkeys_can_edit, + attested_passkeys_can_edit, unixcred_can_edit, sshpubkey_can_edit, }, @@ -523,6 +540,7 @@ impl ValueSetT for ValueSetIntentToken { ext_cred_portal_can_view: *ext_cred_portal_can_view, primary_can_edit: *primary_can_edit, passkeys_can_edit: *passkeys_can_edit, + attested_passkeys_can_edit: *attested_passkeys_can_edit, unixcred_can_edit: *unixcred_can_edit, sshpubkey_can_edit: *sshpubkey_can_edit, }, @@ -768,38 +786,38 @@ impl ValueSetT for ValueSetPasskey { } #[derive(Debug, Clone)] -pub struct ValueSetDeviceKey { - map: BTreeMap, +pub struct ValueSetAttestedPasskey { + map: BTreeMap, } -impl ValueSetDeviceKey { - pub fn new(u: Uuid, t: String, k: DeviceKeyV4) -> Box { +impl ValueSetAttestedPasskey { + pub fn new(u: Uuid, t: String, k: AttestedPasskeyV4) -> Box { let mut map = BTreeMap::new(); map.insert(u, (t, k)); - Box::new(ValueSetDeviceKey { map }) + Box::new(ValueSetAttestedPasskey { map }) } - pub fn push(&mut self, u: Uuid, t: String, k: DeviceKeyV4) -> bool { + pub fn push(&mut self, u: Uuid, t: String, k: AttestedPasskeyV4) -> bool { self.map.insert(u, (t, k)).is_none() } - pub fn from_dbvs2(data: Vec) -> Result { + pub fn from_dbvs2(data: Vec) -> Result { let map = data .into_iter() .map(|k| match k { - DbValueDeviceKeyV1::V4 { u, t, k } => Ok((u, (t, k))), + DbValueAttestedPasskeyV1::V4 { u, t, k } => Ok((u, (t, k))), }) .collect::>()?; - Ok(Box::new(ValueSetDeviceKey { map })) + Ok(Box::new(ValueSetAttestedPasskey { map })) } - pub fn from_repl_v1(data: &[ReplDeviceKeyV4V1]) -> Result { + pub fn from_repl_v1(data: &[ReplAttestedPasskeyV4V1]) -> Result { let map = data .iter() .cloned() - .map(|ReplDeviceKeyV4V1 { uuid, tag, key }| Ok((uuid, (tag, key)))) + .map(|ReplAttestedPasskeyV4V1 { uuid, tag, key }| Ok((uuid, (tag, key)))) .collect::>()?; - Ok(Box::new(ValueSetDeviceKey { map })) + Ok(Box::new(ValueSetAttestedPasskey { map })) } // We need to allow this, because rust doesn't allow us to impl FromIterator on foreign @@ -807,17 +825,17 @@ impl ValueSetDeviceKey { #[allow(clippy::should_implement_trait)] pub fn from_iter(iter: T) -> Option> where - T: IntoIterator, + T: IntoIterator, { let map = iter.into_iter().map(|(u, t, k)| (u, (t, k))).collect(); - Some(Box::new(ValueSetDeviceKey { map })) + Some(Box::new(ValueSetAttestedPasskey { map })) } } -impl ValueSetT for ValueSetDeviceKey { +impl ValueSetT for ValueSetAttestedPasskey { fn insert_checked(&mut self, value: Value) -> Result { match value { - Value::DeviceKey(u, t, k) => { + Value::AttestedPasskey(u, t, k) => { if let BTreeEntry::Vacant(e) = self.map.entry(u) { e.insert((t, k)); Ok(true) @@ -835,14 +853,14 @@ impl ValueSetT for ValueSetDeviceKey { fn remove(&mut self, pv: &PartialValue, _cid: &Cid) -> bool { match pv { - PartialValue::DeviceKey(u) => self.map.remove(u).is_some(), + PartialValue::AttestedPasskey(u) => self.map.remove(u).is_some(), _ => false, } } fn contains(&self, pv: &PartialValue) -> bool { match pv { - PartialValue::DeviceKey(u) => self.map.contains_key(u), + PartialValue::AttestedPasskey(u) => self.map.contains_key(u), _ => false, } } @@ -875,7 +893,7 @@ impl ValueSetT for ValueSetDeviceKey { } fn syntax(&self) -> SyntaxType { - SyntaxType::DeviceKey + SyntaxType::AttestedPasskey } fn validate(&self, _schema_attr: &SchemaAttribute) -> bool { @@ -889,10 +907,10 @@ impl ValueSetT for ValueSetDeviceKey { } fn to_db_valueset_v2(&self) -> DbValueSetV2 { - DbValueSetV2::DeviceKey( + DbValueSetV2::AttestedPasskey( self.map .iter() - .map(|(u, (t, k))| DbValueDeviceKeyV1::V4 { + .map(|(u, (t, k))| DbValueAttestedPasskeyV1::V4 { u: *u, t: t.clone(), k: k.clone(), @@ -902,11 +920,11 @@ impl ValueSetT for ValueSetDeviceKey { } fn to_repl_v1(&self) -> ReplAttrV1 { - ReplAttrV1::DeviceKey { + ReplAttrV1::AttestedPasskey { set: self .map .iter() - .map(|(u, (t, k))| ReplDeviceKeyV4V1 { + .map(|(u, (t, k))| ReplAttestedPasskeyV4V1 { uuid: *u, tag: t.clone(), key: k.clone(), @@ -916,20 +934,20 @@ impl ValueSetT for ValueSetDeviceKey { } fn to_partialvalue_iter(&self) -> Box + '_> { - Box::new(self.map.keys().copied().map(PartialValue::DeviceKey)) + Box::new(self.map.keys().copied().map(PartialValue::AttestedPasskey)) } fn to_value_iter(&self) -> Box + '_> { Box::new( self.map .iter() - .map(|(u, (t, k))| Value::DeviceKey(*u, t.clone(), k.clone())), + .map(|(u, (t, k))| Value::AttestedPasskey(*u, t.clone(), k.clone())), ) } fn equal(&self, other: &ValueSet) -> bool { // Looks like we may not need this? - if let Some(other) = other.as_devicekey_map() { + if let Some(other) = other.as_attestedpasskey_map() { &self.map == other } else { // debug_assert!(false); @@ -938,7 +956,7 @@ impl ValueSetT for ValueSetDeviceKey { } fn merge(&mut self, other: &ValueSet) -> Result<(), OperationError> { - if let Some(b) = other.as_devicekey_map() { + if let Some(b) = other.as_attestedpasskey_map() { mergemaps!(self.map, b) } else { debug_assert!(false); @@ -946,15 +964,17 @@ impl ValueSetT for ValueSetDeviceKey { } } - fn to_devicekey_single(&self) -> Option<&DeviceKeyV4> { + /* + fn to_attestedpasskey_single(&self) -> Option<&AttestedPasskeyV4> { if self.map.len() == 1 { self.map.values().take(1).next().map(|(_, k)| k) } else { None } } + */ - fn as_devicekey_map(&self) -> Option<&BTreeMap> { + fn as_attestedpasskey_map(&self) -> Option<&BTreeMap> { Some(&self.map) } } @@ -1115,3 +1135,175 @@ impl ValueSetT for ValueSetCredentialType { Some(&self.set) } } + +#[derive(Debug, Clone)] +pub struct ValueSetWebauthnAttestationCaList { + ca_list: AttestationCaList, +} + +impl ValueSetWebauthnAttestationCaList { + pub fn new(ca_list: AttestationCaList) -> Box { + Box::new(ValueSetWebauthnAttestationCaList { ca_list }) + } + + /* + pub fn push(&mut self, u: CredentialType) -> bool { + self.set.insert(u) + } + */ + + pub fn from_dbvs2(ca_list: AttestationCaList) -> Result { + Ok(Box::new(ValueSetWebauthnAttestationCaList { ca_list })) + } + + pub fn from_repl_v1(ca_list: &AttestationCaList) -> Result { + Ok(Box::new(ValueSetWebauthnAttestationCaList { + ca_list: ca_list.clone(), + })) + } + + /* + // We need to allow this, because rust doesn't allow us to impl FromIterator on foreign + // types, and uuid is foreign. + #[allow(clippy::should_implement_trait)] + pub fn from_iter(iter: T) -> Option> + where + T: IntoIterator, + { + let set = iter.into_iter().collect(); + Some(Box::new(ValueSetCredentialType { set })) + } + */ +} + +impl ValueSetT for ValueSetWebauthnAttestationCaList { + fn insert_checked(&mut self, value: Value) -> Result { + match value { + Value::WebauthnAttestationCaList(u) => { + self.ca_list.union(&u); + Ok(true) + } + _ => { + debug_assert!(false); + Err(OperationError::InvalidValueState) + } + } + } + + fn clear(&mut self) { + self.ca_list.clear(); + } + + fn remove(&mut self, _pv: &PartialValue, _cid: &Cid) -> bool { + /* + match pv { + _ => { + debug_assert!(false); + true + } + } + */ + debug_assert!(false); + true + } + + fn contains(&self, _pv: &PartialValue) -> bool { + /* + match pv { + PartialValue::CredentialType(u) => self.set.contains(u), + _ => false, + } + */ + false + } + + fn substring(&self, _pv: &PartialValue) -> bool { + false + } + + fn startswith(&self, _pv: &PartialValue) -> bool { + false + } + + fn endswith(&self, _pv: &PartialValue) -> bool { + false + } + + fn lessthan(&self, _pv: &PartialValue) -> bool { + false + } + + fn len(&self) -> usize { + self.ca_list.len() + } + + fn generate_idx_eq_keys(&self) -> Vec { + // self.set.iter().map(|u| u.to_string()).collect() + Vec::with_capacity(0) + } + + fn syntax(&self) -> SyntaxType { + SyntaxType::WebauthnAttestationCaList + } + + fn validate(&self, _schema_attr: &SchemaAttribute) -> bool { + // Should we actually be looking through the ca-list as given and eliminate + // known vuln devices? + true + } + + fn to_proto_string_clone_iter(&self) -> Box + '_> { + Box::new( + self.ca_list + .cas() + .values() + .flat_map(|att_ca| att_ca.aaguids().values()) + .map(|device| device.description_en().to_string()), + ) + } + + fn to_db_valueset_v2(&self) -> DbValueSetV2 { + DbValueSetV2::WebauthnAttestationCaList { + ca_list: self.ca_list.clone(), + } + } + + fn to_repl_v1(&self) -> ReplAttrV1 { + ReplAttrV1::WebauthnAttestationCaList { + ca_list: self.ca_list.clone(), + } + } + + fn to_partialvalue_iter(&self) -> Box + '_> { + Box::new(std::iter::empty::()) + } + + fn to_value_iter(&self) -> Box + '_> { + Box::new(std::iter::once(Value::WebauthnAttestationCaList( + self.ca_list.clone(), + ))) + } + + fn equal(&self, other: &ValueSet) -> bool { + if let Some(other) = other.as_webauthn_attestation_ca_list() { + &self.ca_list == other + } else { + debug_assert!(false); + false + } + } + + fn merge(&mut self, other: &ValueSet) -> Result<(), OperationError> { + if let Some(b) = other.as_webauthn_attestation_ca_list() { + self.ca_list.union(b); + Ok(()) + } else { + debug_assert!(false); + Err(OperationError::InvalidValueState) + } + } + + fn as_webauthn_attestation_ca_list(&self) -> Option<&AttestationCaList> { + Some(&self.ca_list) + } +} diff --git a/server/lib/src/valueset/mod.rs b/server/lib/src/valueset/mod.rs index d8a4457d8..0c44e2fbd 100644 --- a/server/lib/src/valueset/mod.rs +++ b/server/lib/src/valueset/mod.rs @@ -8,10 +8,10 @@ use openssl::ec::EcKey; use openssl::pkey::Private; use openssl::pkey::Public; use smolset::SmolSet; -use time::OffsetDateTime; -// use std::fmt::Debug; use sshkey_attest::proto::PublicKey as SshPublicKey; -use webauthn_rs::prelude::AttestedPasskey as DeviceKeyV4; +use time::OffsetDateTime; +use webauthn_rs::prelude::AttestationCaList; +use webauthn_rs::prelude::AttestedPasskey as AttestedPasskeyV4; use webauthn_rs::prelude::Passkey as PasskeyV4; use kanidm_proto::v1::Filter as ProtoFilter; @@ -30,8 +30,8 @@ pub use self::binary::{ValueSetPrivateBinary, ValueSetPublicBinary}; pub use self::bool::ValueSetBool; pub use self::cid::ValueSetCid; pub use self::cred::{ - ValueSetCredential, ValueSetCredentialType, ValueSetDeviceKey, ValueSetIntentToken, - ValueSetPasskey, + ValueSetAttestedPasskey, ValueSetCredential, ValueSetCredentialType, ValueSetIntentToken, + ValueSetPasskey, ValueSetWebauthnAttestationCaList, }; pub use self::datetime::ValueSetDateTime; pub use self::eckey::ValueSetEcKeyPrivate; @@ -355,7 +355,12 @@ pub trait ValueSetT: std::fmt::Debug + DynClone { None } - fn as_devicekey_map(&self) -> Option<&BTreeMap> { + fn as_attestedpasskey_map(&self) -> Option<&BTreeMap> { + debug_assert!(false); + None + } + + fn as_webauthn_attestation_ca_list(&self) -> Option<&AttestationCaList> { debug_assert!(false); None } @@ -507,11 +512,6 @@ pub trait ValueSetT: std::fmt::Debug + DynClone { None } - fn to_devicekey_single(&self) -> Option<&DeviceKeyV4> { - debug_assert!(false); - None - } - fn as_session_map(&self) -> Option<&BTreeMap> { debug_assert!(false); None @@ -668,9 +668,10 @@ pub fn from_result_value_iter( Value::EcKeyPrivate(k) => ValueSetEcKeyPrivate::new(&k), Value::Image(imagevalue) => image::ValueSetImage::new(imagevalue), Value::CredentialType(c) => ValueSetCredentialType::new(c), - Value::PhoneNumber(_, _) + Value::WebauthnAttestationCaList(_) + | Value::PhoneNumber(_, _) | Value::Passkey(_, _, _) - | Value::DeviceKey(_, _, _) + | Value::AttestedPasskey(_, _, _) | Value::TotpSecret(_, _) | Value::Session(_, _) | Value::ApiToken(_, _) @@ -724,7 +725,7 @@ pub fn from_value_iter(mut iter: impl Iterator) -> Result ValueSetIntentToken::new(u, s), Value::EmailAddress(a, _) => ValueSetEmailAddress::new(a), Value::Passkey(u, t, k) => ValueSetPasskey::new(u, t, k), - Value::DeviceKey(u, t, k) => ValueSetDeviceKey::new(u, t, k), + Value::AttestedPasskey(u, t, k) => ValueSetAttestedPasskey::new(u, t, k), Value::JwsKeyEs256(k) => ValueSetJwsKeyEs256::new(k), Value::JwsKeyRs256(k) => ValueSetJwsKeyRs256::new(k), Value::Session(u, m) => ValueSetSession::new(u, m), @@ -736,6 +737,9 @@ pub fn from_value_iter(mut iter: impl Iterator) -> Result ValueSetEcKeyPrivate::new(&k), Value::Image(imagevalue) => image::ValueSetImage::new(imagevalue), Value::CredentialType(c) => ValueSetCredentialType::new(c), + Value::WebauthnAttestationCaList(ca_list) => { + ValueSetWebauthnAttestationCaList::new(ca_list) + } Value::PhoneNumber(_, _) => { debug_assert!(false); return Err(OperationError::InvalidValueState); @@ -777,7 +781,7 @@ pub fn from_db_valueset_v2(dbvs: DbValueSetV2) -> Result ValueSetIntentToken::from_dbvs2(set), DbValueSetV2::EmailAddress(primary, set) => ValueSetEmailAddress::from_dbvs2(primary, set), DbValueSetV2::Passkey(set) => ValueSetPasskey::from_dbvs2(set), - DbValueSetV2::DeviceKey(set) => ValueSetDeviceKey::from_dbvs2(set), + DbValueSetV2::AttestedPasskey(set) => ValueSetAttestedPasskey::from_dbvs2(set), DbValueSetV2::Session(set) => ValueSetSession::from_dbvs2(set), DbValueSetV2::ApiToken(set) => ValueSetApiToken::from_dbvs2(set), DbValueSetV2::Oauth2Session(set) => ValueSetOauth2Session::from_dbvs2(set), @@ -793,6 +797,9 @@ pub fn from_db_valueset_v2(dbvs: DbValueSetV2) -> Result ValueSetImage::from_dbvs2(&set), DbValueSetV2::CredentialType(set) => ValueSetCredentialType::from_dbvs2(set), + DbValueSetV2::WebauthnAttestationCaList { ca_list } => { + ValueSetWebauthnAttestationCaList::from_dbvs2(ca_list) + } } } @@ -823,7 +830,7 @@ pub fn from_repl_v1(rv1: &ReplAttrV1) -> Result { ReplAttrV1::Credential { set } => ValueSetCredential::from_repl_v1(set), ReplAttrV1::IntentToken { set } => ValueSetIntentToken::from_repl_v1(set), ReplAttrV1::Passkey { set } => ValueSetPasskey::from_repl_v1(set), - ReplAttrV1::DeviceKey { set } => ValueSetDeviceKey::from_repl_v1(set), + ReplAttrV1::AttestedPasskey { set } => ValueSetAttestedPasskey::from_repl_v1(set), ReplAttrV1::DateTime { set } => ValueSetDateTime::from_repl_v1(set), ReplAttrV1::Url { set } => ValueSetUrl::from_repl_v1(set), ReplAttrV1::NsUniqueId { set } => ValueSetNsUniqueId::from_repl_v1(set), @@ -839,5 +846,8 @@ pub fn from_repl_v1(rv1: &ReplAttrV1) -> Result { ReplAttrV1::EcKeyPrivate { key } => ValueSetEcKeyPrivate::from_repl_v1(key), ReplAttrV1::Image { set } => ValueSetImage::from_repl_v1(set), ReplAttrV1::CredentialType { set } => ValueSetCredentialType::from_repl_v1(set), + ReplAttrV1::WebauthnAttestationCaList { ca_list } => { + ValueSetWebauthnAttestationCaList::from_repl_v1(ca_list) + } } } diff --git a/server/web_ui/pkg/external/bootstrap.bundle.min.js.br b/server/web_ui/pkg/external/bootstrap.bundle.min.js.br index 14c0556b9..bf494deb6 100644 Binary files a/server/web_ui/pkg/external/bootstrap.bundle.min.js.br and b/server/web_ui/pkg/external/bootstrap.bundle.min.js.br differ diff --git a/server/web_ui/pkg/external/bootstrap.bundle.min.js.map.br b/server/web_ui/pkg/external/bootstrap.bundle.min.js.map.br index 8f5bd296c..0c26cf823 100644 Binary files a/server/web_ui/pkg/external/bootstrap.bundle.min.js.map.br and b/server/web_ui/pkg/external/bootstrap.bundle.min.js.map.br differ diff --git a/server/web_ui/pkg/external/bootstrap.min.css.map.br b/server/web_ui/pkg/external/bootstrap.min.css.map.br index e533032ac..fbd11f9e2 100644 Binary files a/server/web_ui/pkg/external/bootstrap.min.css.map.br and b/server/web_ui/pkg/external/bootstrap.min.css.map.br differ diff --git a/server/web_ui/pkg/img/icon-accounts.svg.br b/server/web_ui/pkg/img/icon-accounts.svg.br index d792e15c8..93a0e1c3c 100644 Binary files a/server/web_ui/pkg/img/icon-accounts.svg.br and b/server/web_ui/pkg/img/icon-accounts.svg.br differ diff --git a/server/web_ui/pkg/img/icon-groups.svg.br b/server/web_ui/pkg/img/icon-groups.svg.br index d91c09ed5..b6bbe5d20 100644 Binary files a/server/web_ui/pkg/img/icon-groups.svg.br and b/server/web_ui/pkg/img/icon-groups.svg.br differ diff --git a/server/web_ui/pkg/kanidmd_web_ui_admin.js b/server/web_ui/pkg/kanidmd_web_ui_admin.js index 419b088f7..005a853b0 100644 --- a/server/web_ui/pkg/kanidmd_web_ui_admin.js +++ b/server/web_ui/pkg/kanidmd_web_ui_admin.js @@ -223,19 +223,19 @@ function addBorrowedObject(obj) { } function __wbg_adapter_38(arg0, arg1, arg2) { try { - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h3e88c381a9b0da08(arg0, arg1, addBorrowedObject(arg2)); + wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hecf49fd8e934d63d(arg0, arg1, addBorrowedObject(arg2)); } finally { heap[stack_pointer++] = undefined; } } function __wbg_adapter_41(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h71282a39cf9f54cc(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hbb91bcb76d7d57c6(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_44(arg0, arg1, arg2) { try { - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h49ac351fd82edf13(arg0, arg1, addBorrowedObject(arg2)); + wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hf15c46d581e6d848(arg0, arg1, addBorrowedObject(arg2)); } finally { heap[stack_pointer++] = undefined; } @@ -397,6 +397,11 @@ function __wbg_get_imports() { getInt32Memory0()[arg0 / 4 + 1] = isLikeNone(ret) ? 0 : ret; getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); }; + imports.wbg.__wbg_cachekey_b61393159c57fd7b = function(arg0, arg1) { + const ret = getObject(arg1).__yew_subtree_cache_key; + getInt32Memory0()[arg0 / 4 + 1] = isLikeNone(ret) ? 0 : ret; + getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); + }; imports.wbg.__wbg_subtreeid_e348577f7ef777e3 = function(arg0, arg1) { const ret = getObject(arg1).__yew_subtree_id; getInt32Memory0()[arg0 / 4 + 1] = isLikeNone(ret) ? 0 : ret; @@ -405,11 +410,6 @@ function __wbg_get_imports() { imports.wbg.__wbg_setsubtreeid_d32e6327eef1f7fc = function(arg0, arg1) { getObject(arg0).__yew_subtree_id = arg1 >>> 0; }; - imports.wbg.__wbg_cachekey_b61393159c57fd7b = function(arg0, arg1) { - const ret = getObject(arg1).__yew_subtree_cache_key; - getInt32Memory0()[arg0 / 4 + 1] = isLikeNone(ret) ? 0 : ret; - getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); - }; imports.wbg.__wbg_setcachekey_80183b7cfc421143 = function(arg0, arg1) { getObject(arg0).__yew_subtree_cache_key = arg1 >>> 0; }; @@ -435,10 +435,10 @@ function __wbg_get_imports() { wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); } }; - imports.wbg.__wbg_queueMicrotask_e5949c35d772a669 = function(arg0) { + imports.wbg.__wbg_queueMicrotask_4d890031a6a5a50c = function(arg0) { queueMicrotask(getObject(arg0)); }; - imports.wbg.__wbg_queueMicrotask_2be8b97a81fe4d00 = function(arg0) { + imports.wbg.__wbg_queueMicrotask_adae4bc085237231 = function(arg0) { const ret = getObject(arg0).queueMicrotask; return addHeapObject(ret); }; @@ -468,27 +468,27 @@ function __wbg_get_imports() { wasm.__wbindgen_free(arg0, arg1 * 4, 4); console.log(...v0); }; - imports.wbg.__wbg_body_11da0c1aa9610cb3 = function(arg0) { + imports.wbg.__wbg_body_64abc9aba1891e91 = function(arg0) { const ret = getObject(arg0).body; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_createElement_9ce3fdea8322ff34 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_createElement_fdd5c113cb84539e = function() { return handleError(function (arg0, arg1, arg2) { const ret = getObject(arg0).createElement(getStringFromWasm0(arg1, arg2)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_createElementNS_6a08d8f33e767e18 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_createElementNS_524b05a6070757b6 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { const ret = getObject(arg0).createElementNS(arg1 === 0 ? undefined : getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_createTextNode_01a7250c5ca46b04 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_createTextNode_7ff0c034b2855f66 = function(arg0, arg1, arg2) { const ret = getObject(arg0).createTextNode(getStringFromWasm0(arg1, arg2)); return addHeapObject(ret); }; - imports.wbg.__wbg_querySelector_391afe271b8236d5 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_querySelector_c72dce5ac4b6bc3e = function() { return handleError(function (arg0, arg1, arg2) { const ret = getObject(arg0).querySelector(getStringFromWasm0(arg1, arg2)); return isLikeNone(ret) ? 0 : addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_instanceof_Window_cde2416cf5126a72 = function(arg0) { + imports.wbg.__wbg_instanceof_Window_3e5cd1f48c152d01 = function(arg0) { let result; try { result = getObject(arg0) instanceof Window; @@ -498,31 +498,31 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_document_183cf1eecfdbffee = function(arg0) { + imports.wbg.__wbg_document_d609202d16c38224 = function(arg0) { const ret = getObject(arg0).document; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_location_61ca61017633c753 = function(arg0) { + imports.wbg.__wbg_location_176c34e89c2c9d80 = function(arg0) { const ret = getObject(arg0).location; return addHeapObject(ret); }; - imports.wbg.__wbg_history_56dc869560201113 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_history_80998b7456bf367e = function() { return handleError(function (arg0) { const ret = getObject(arg0).history; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_localStorage_e11f72e996a4f5d9 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_localStorage_8c507fd281456944 = function() { return handleError(function (arg0) { const ret = getObject(arg0).localStorage; return isLikeNone(ret) ? 0 : addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_sessionStorage_071949dc646bfd35 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_sessionStorage_adb12b0c8ea06c48 = function() { return handleError(function (arg0) { const ret = getObject(arg0).sessionStorage; return isLikeNone(ret) ? 0 : addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_fetch_8cebc656dc6b11b1 = function(arg0, arg1) { + imports.wbg.__wbg_fetch_6c415b3a07763878 = function(arg0, arg1) { const ret = getObject(arg0).fetch(getObject(arg1)); return addHeapObject(ret); }; - imports.wbg.__wbg_instanceof_Element_6c7af07f5e6c8d69 = function(arg0) { + imports.wbg.__wbg_instanceof_Element_3f326a19cc457941 = function(arg0) { let result; try { result = getObject(arg0) instanceof Element; @@ -532,201 +532,127 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_namespaceURI_2dd94d0147ffddf2 = function(arg0, arg1) { + imports.wbg.__wbg_namespaceURI_7cc7ef157e398356 = function(arg0, arg1) { const ret = getObject(arg1).namespaceURI; var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_classList_7fd39dc155235d8a = function(arg0) { + imports.wbg.__wbg_classList_82893a9100db6428 = function(arg0) { const ret = getObject(arg0).classList; return addHeapObject(ret); }; - imports.wbg.__wbg_setinnerHTML_b88bf159b62c2334 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setinnerHTML_ce0d6527ce4086f2 = function(arg0, arg1, arg2) { getObject(arg0).innerHTML = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_outerHTML_72dcf3aa34725f10 = function(arg0, arg1) { + imports.wbg.__wbg_outerHTML_b5a8d952b5615778 = function(arg0, arg1) { const ret = getObject(arg1).outerHTML; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_children_af5a3246832628b1 = function(arg0) { + imports.wbg.__wbg_children_990f38c4f4d5c721 = function(arg0) { const ret = getObject(arg0).children; return addHeapObject(ret); }; - imports.wbg.__wbg_removeAttribute_dbd76981f9bb9f59 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_removeAttribute_2e200daefb9f3ed4 = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).removeAttribute(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_setAttribute_aebcae2169f2f869 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_setAttribute_e7b72a5e7cfcb5a3 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).setAttribute(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); }, arguments) }; - imports.wbg.__wbg_getItem_c81cd3ae30cd579a = function() { return handleError(function (arg0, arg1, arg2, arg3) { + imports.wbg.__wbg_getItem_5395a7e200c31e89 = function() { return handleError(function (arg0, arg1, arg2, arg3) { const ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3)); var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_removeItem_58a487fe7fc070f0 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_removeItem_c84f914587f36b1a = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).removeItem(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_setItem_fe04f524052a3839 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_setItem_3786c4c8dd0c9bd0 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); }, arguments) }; - imports.wbg.__wbg_setchecked_5757666239434ecd = function(arg0, arg1) { + imports.wbg.__wbg_setchecked_c1d5c3726082e274 = function(arg0, arg1) { getObject(arg0).checked = arg1 !== 0; }; - imports.wbg.__wbg_value_5e860795f53217cd = function(arg0, arg1) { + imports.wbg.__wbg_value_e024243a9dae20bc = function(arg0, arg1) { const ret = getObject(arg1).value; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_setvalue_7d187f6cc23d8192 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setvalue_5b3442ff620b4a5d = function(arg0, arg1, arg2) { getObject(arg0).value = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_addEventListener_51709b9747ad8980 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4)); - }, arguments) }; - imports.wbg.__wbg_removeEventListener_5b1e762a7951280a = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), arg4 !== 0); - }, arguments) }; - imports.wbg.__wbg_state_78eaa7b6ff3123a0 = function() { return handleError(function (arg0) { - const ret = getObject(arg0).state; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_pushState_8eaca41f86b13910 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) { - getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5)); - }, arguments) }; - imports.wbg.__wbg_href_92490614763f3f7c = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg1).href; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }, arguments) }; - imports.wbg.__wbg_sethref_2c377515f8ddd13a = function() { return handleError(function (arg0, arg1, arg2) { - getObject(arg0).href = getStringFromWasm0(arg1, arg2); - }, arguments) }; - imports.wbg.__wbg_pathname_cd5a90c8f3ab524a = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg1).pathname; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }, arguments) }; - imports.wbg.__wbg_search_08fbba2309a249da = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg1).search; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }, arguments) }; - imports.wbg.__wbg_hash_ced9ee31706e591d = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg1).hash; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }, arguments) }; - imports.wbg.__wbg_headers_4711243cf3bffca0 = function(arg0) { - const ret = getObject(arg0).headers; - return addHeapObject(ret); - }; - imports.wbg.__wbg_newwithstrandinit_29038da14d09e330 = function() { return handleError(function (arg0, arg1, arg2) { - const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_instanceof_Response_944e2745b5db71f5 = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof Response; - } catch (_) { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_status_7841bb47be2a8f16 = function(arg0) { - const ret = getObject(arg0).status; - return ret; - }; - imports.wbg.__wbg_headers_ea7ef583d1564b08 = function(arg0) { - const ret = getObject(arg0).headers; - return addHeapObject(ret); - }; - imports.wbg.__wbg_json_7f96c90903ae4155 = function() { return handleError(function (arg0) { - const ret = getObject(arg0).json(); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_bubbles_c27af65192eb3569 = function(arg0) { + imports.wbg.__wbg_bubbles_f1cdd0584446cad0 = function(arg0) { const ret = getObject(arg0).bubbles; return ret; }; - imports.wbg.__wbg_cancelBubble_ee3f70328e901584 = function(arg0) { + imports.wbg.__wbg_cancelBubble_976cfdf7ac449a6c = function(arg0) { const ret = getObject(arg0).cancelBubble; return ret; }; - imports.wbg.__wbg_composedPath_ee37eece046b69a2 = function(arg0) { + imports.wbg.__wbg_composedPath_12a068e57a98cf90 = function(arg0) { const ret = getObject(arg0).composedPath(); return addHeapObject(ret); }; - imports.wbg.__wbg_preventDefault_9299867e06da6909 = function(arg0) { + imports.wbg.__wbg_preventDefault_7f821f72e7c6b5d4 = function(arg0) { getObject(arg0).preventDefault(); }; - imports.wbg.__wbg_get_9470c6584bbde430 = function() { return handleError(function (arg0, arg1, arg2, arg3) { + imports.wbg.__wbg_get_0231cdd369e04a1d = function() { return handleError(function (arg0, arg1, arg2, arg3) { const ret = getObject(arg1).get(getStringFromWasm0(arg2, arg3)); var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_set_2912c891505cbc22 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_set_27f236f6d7a28c29 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); }, arguments) }; - imports.wbg.__wbg_parentNode_e1c214fc3f362af0 = function(arg0) { + imports.wbg.__wbg_parentNode_92a7017b3a4fad43 = function(arg0) { const ret = getObject(arg0).parentNode; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_parentElement_592cb54944d3d002 = function(arg0) { + imports.wbg.__wbg_parentElement_72e144c2e8d9e0b5 = function(arg0) { const ret = getObject(arg0).parentElement; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_lastChild_b17b3c7498d25bd7 = function(arg0) { + imports.wbg.__wbg_lastChild_a62e3fbaab87f734 = function(arg0) { const ret = getObject(arg0).lastChild; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_nextSibling_d029031876ed1b1b = function(arg0) { + imports.wbg.__wbg_nextSibling_bafccd3347d24543 = function(arg0) { const ret = getObject(arg0).nextSibling; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_setnodeValue_321840a6762ab272 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setnodeValue_630c6470d05b600e = function(arg0, arg1, arg2) { getObject(arg0).nodeValue = arg1 === 0 ? undefined : getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_textContent_d69d000f6081b514 = function(arg0, arg1) { + imports.wbg.__wbg_textContent_2f37235e13f8484b = function(arg0, arg1) { const ret = getObject(arg1).textContent; var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_appendChild_2e6a6c9d1f0d443d = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_appendChild_d30e6b83791d04c0 = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).appendChild(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_insertBefore_bdaeec8969497673 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_insertBefore_726c1640c419e940 = function() { return handleError(function (arg0, arg1, arg2) { const ret = getObject(arg0).insertBefore(getObject(arg1), getObject(arg2)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_removeChild_a63022ebbfa6ebf5 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_removeChild_942eb9c02243d84d = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).removeChild(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_instanceof_ShadowRoot_f85f709c953844de = function(arg0) { + imports.wbg.__wbg_instanceof_ShadowRoot_0bd39e89ab117f86 = function(arg0) { let result; try { result = getObject(arg0) instanceof ShadowRoot; @@ -736,141 +662,215 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_host_73c8e95bf9b31ccd = function(arg0) { + imports.wbg.__wbg_host_09eee5e3d9cf59a1 = function(arg0) { const ret = getObject(arg0).host; return addHeapObject(ret); }; - imports.wbg.__wbg_add_dc5c00591ed65268 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_addEventListener_374cbfd2bbc19ccf = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4)); + }, arguments) }; + imports.wbg.__wbg_removeEventListener_9ece7e86d1135657 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), arg4 !== 0); + }, arguments) }; + imports.wbg.__wbg_state_ba77b2c3ee29c912 = function() { return handleError(function (arg0) { + const ret = getObject(arg0).state; + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_pushState_e159043fce8f87bc = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) { + getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5)); + }, arguments) }; + imports.wbg.__wbg_href_160af2ae1328d7b7 = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg1).href; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, arguments) }; + imports.wbg.__wbg_sethref_90b000c8b01f96b1 = function() { return handleError(function (arg0, arg1, arg2) { + getObject(arg0).href = getStringFromWasm0(arg1, arg2); + }, arguments) }; + imports.wbg.__wbg_pathname_1ab7e82aaa4511ff = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg1).pathname; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, arguments) }; + imports.wbg.__wbg_search_9f7ca8896c2d0804 = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg1).search; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, arguments) }; + imports.wbg.__wbg_hash_be2940ca236b5efc = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg1).hash; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, arguments) }; + imports.wbg.__wbg_headers_d135d2bb8cc60413 = function(arg0) { + const ret = getObject(arg0).headers; + return addHeapObject(ret); + }; + imports.wbg.__wbg_newwithstrandinit_f581dff0d19a8b03 = function() { return handleError(function (arg0, arg1, arg2) { + const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2)); + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_instanceof_Response_4c3b1446206114d1 = function(arg0) { + let result; + try { + result = getObject(arg0) instanceof Response; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }; + imports.wbg.__wbg_status_d6d47ad2837621eb = function(arg0) { + const ret = getObject(arg0).status; + return ret; + }; + imports.wbg.__wbg_headers_24def508a7518df9 = function(arg0) { + const ret = getObject(arg0).headers; + return addHeapObject(ret); + }; + imports.wbg.__wbg_json_34535d9848f043eb = function() { return handleError(function (arg0) { + const ret = getObject(arg0).json(); + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_add_e0f3c5b6e421c311 = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).add(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_href_7f944b48b612250e = function(arg0, arg1) { + imports.wbg.__wbg_href_e9aac3826080dcaa = function(arg0, arg1) { const ret = getObject(arg1).href; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_pathname_a83d8f2ebefa6791 = function(arg0, arg1) { + imports.wbg.__wbg_pathname_aeafa820be91c325 = function(arg0, arg1) { const ret = getObject(arg1).pathname; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_search_8c5f74fa2d11377e = function(arg0, arg1) { + imports.wbg.__wbg_search_f6e95882a48d3f69 = function(arg0, arg1) { const ret = getObject(arg1).search; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_setsearch_a168105ad9dbdb8b = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setsearch_4f7d084e0d811add = function(arg0, arg1, arg2) { getObject(arg0).search = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_hash_f468e7d38a21a76a = function(arg0, arg1) { + imports.wbg.__wbg_hash_0087751acddc8f2a = function(arg0, arg1) { const ret = getObject(arg1).hash; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_sethash_7c3032584865b2bd = function(arg0, arg1, arg2) { + imports.wbg.__wbg_sethash_bfc9db317a77305c = function(arg0, arg1, arg2) { getObject(arg0).hash = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_new_d7cd05d9de7d4000 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_new_9e08fd37c1c53142 = function() { return handleError(function (arg0, arg1) { const ret = new URL(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_newwithbase_604e8dfd42d25665 = function() { return handleError(function (arg0, arg1, arg2, arg3) { + imports.wbg.__wbg_newwithbase_f4989aa5bbd5cc29 = function() { return handleError(function (arg0, arg1, arg2, arg3) { const ret = new URL(getStringFromWasm0(arg0, arg1), getStringFromWasm0(arg2, arg3)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_href_2777cc28ba3aac82 = function(arg0, arg1) { + imports.wbg.__wbg_href_f21dc804d4da134a = function(arg0, arg1) { const ret = getObject(arg1).href; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_value_539db729f551be3a = function(arg0, arg1) { + imports.wbg.__wbg_value_57e57170f6952449 = function(arg0, arg1) { const ret = getObject(arg1).value; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_setvalue_15231c60278dee22 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setvalue_a11f3069fd7a1805 = function(arg0, arg1, arg2) { getObject(arg0).value = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_get_4a9aa5157afeb382 = function(arg0, arg1) { + imports.wbg.__wbg_get_f01601b5a68d10e3 = function(arg0, arg1) { const ret = getObject(arg0)[arg1 >>> 0]; return addHeapObject(ret); }; - imports.wbg.__wbg_length_cace2e0b3ddc0502 = function(arg0) { + imports.wbg.__wbg_length_1009b1af0c481d7b = function(arg0) { const ret = getObject(arg0).length; return ret; }; - imports.wbg.__wbg_newnoargs_ccdcae30fd002262 = function(arg0, arg1) { + imports.wbg.__wbg_newnoargs_c62ea9419c21fbac = function(arg0, arg1) { const ret = new Function(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }; - imports.wbg.__wbg_next_15da6a3df9290720 = function(arg0) { + imports.wbg.__wbg_next_9b877f231f476d01 = function(arg0) { const ret = getObject(arg0).next; return addHeapObject(ret); }; - imports.wbg.__wbg_next_1989a20442400aaa = function() { return handleError(function (arg0) { + imports.wbg.__wbg_next_6529ee0cca8d57ed = function() { return handleError(function (arg0) { const ret = getObject(arg0).next(); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_done_bc26bf4ada718266 = function(arg0) { + imports.wbg.__wbg_done_5fe336b092d60cf2 = function(arg0) { const ret = getObject(arg0).done; return ret; }; - imports.wbg.__wbg_value_0570714ff7d75f35 = function(arg0) { + imports.wbg.__wbg_value_0c248a78fdc8e19f = function(arg0) { const ret = getObject(arg0).value; return addHeapObject(ret); }; - imports.wbg.__wbg_iterator_7ee1a391d310f8e4 = function() { + imports.wbg.__wbg_iterator_db7ca081358d4fb2 = function() { const ret = Symbol.iterator; return addHeapObject(ret); }; - imports.wbg.__wbg_get_2aff440840bb6202 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_get_7b48513de5dc5ea4 = function() { return handleError(function (arg0, arg1) { const ret = Reflect.get(getObject(arg0), getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_call_669127b9d730c650 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_call_90c26b09837aba1c = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).call(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_new_c728d68b8b34487e = function() { + imports.wbg.__wbg_new_9fb8d994e1c0aaac = function() { const ret = new Object(); return addHeapObject(ret); }; - imports.wbg.__wbg_self_3fad056edded10bd = function() { return handleError(function () { + imports.wbg.__wbg_self_f0e34d89f33b99fd = function() { return handleError(function () { const ret = self.self; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_window_a4f46c98a61d4089 = function() { return handleError(function () { + imports.wbg.__wbg_window_d3b084224f4774d7 = function() { return handleError(function () { const ret = window.window; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_globalThis_17eff828815f7d84 = function() { return handleError(function () { + imports.wbg.__wbg_globalThis_9caa27ff917c6860 = function() { return handleError(function () { const ret = globalThis.globalThis; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_global_46f939f6541643c5 = function() { return handleError(function () { + imports.wbg.__wbg_global_35dfdd59a4da3e74 = function() { return handleError(function () { const ret = global.global; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_from_ba72c50feaf1d8c0 = function(arg0) { + imports.wbg.__wbg_from_71add2e723d1f1b2 = function(arg0) { const ret = Array.from(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_isArray_38525be7442aa21e = function(arg0) { + imports.wbg.__wbg_isArray_74fb723e24f76012 = function(arg0) { const ret = Array.isArray(getObject(arg0)); return ret; }; - imports.wbg.__wbg_instanceof_ArrayBuffer_c7cc317e5c29cc0d = function(arg0) { + imports.wbg.__wbg_instanceof_ArrayBuffer_e7d53d51371448e2 = function(arg0) { let result; try { result = getObject(arg0) instanceof ArrayBuffer; @@ -880,7 +880,7 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_instanceof_Error_9f5881c3c4149389 = function(arg0) { + imports.wbg.__wbg_instanceof_Error_31ca8d97f188bfbc = function(arg0) { let result; try { result = getObject(arg0) instanceof Error; @@ -890,58 +890,58 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_message_35f9b952e1b922e2 = function(arg0) { + imports.wbg.__wbg_message_55b9ea8030688597 = function(arg0) { const ret = getObject(arg0).message; return addHeapObject(ret); }; - imports.wbg.__wbg_name_e1152a59269f79e5 = function(arg0) { + imports.wbg.__wbg_name_e5eede664187fed6 = function(arg0) { const ret = getObject(arg0).name; return addHeapObject(ret); }; - imports.wbg.__wbg_toString_d0cefe4046ecb265 = function(arg0) { + imports.wbg.__wbg_toString_a44236e90224e279 = function(arg0) { const ret = getObject(arg0).toString(); return addHeapObject(ret); }; - imports.wbg.__wbg_isSafeInteger_c38b0a16d0c7cef7 = function(arg0) { + imports.wbg.__wbg_isSafeInteger_f93fde0dca9820f8 = function(arg0) { const ret = Number.isSafeInteger(getObject(arg0)); return ret; }; - imports.wbg.__wbg_entries_6d727b73ee02b7ce = function(arg0) { + imports.wbg.__wbg_entries_9e2e2aa45aa5094a = function(arg0) { const ret = Object.entries(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_is_c74aa9bb973d6109 = function(arg0, arg1) { + imports.wbg.__wbg_is_ff7acd231c75c0e4 = function(arg0, arg1) { const ret = Object.is(getObject(arg0), getObject(arg1)); return ret; }; - imports.wbg.__wbg_resolve_a3252b2860f0a09e = function(arg0) { + imports.wbg.__wbg_resolve_6e1c6553a82f85b7 = function(arg0) { const ret = Promise.resolve(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_then_89e1c559530b85cf = function(arg0, arg1) { + imports.wbg.__wbg_then_3ab08cd4fbb91ae9 = function(arg0, arg1) { const ret = getObject(arg0).then(getObject(arg1)); return addHeapObject(ret); }; - imports.wbg.__wbg_then_1bbc9edafd859b06 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_then_8371cc12cfedc5a2 = function(arg0, arg1, arg2) { const ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); return addHeapObject(ret); }; - imports.wbg.__wbg_buffer_344d9b41efe96da7 = function(arg0) { + imports.wbg.__wbg_buffer_a448f833075b71ba = function(arg0) { const ret = getObject(arg0).buffer; return addHeapObject(ret); }; - imports.wbg.__wbg_new_d8a000788389a31e = function(arg0) { + imports.wbg.__wbg_new_8f67e318f15d7254 = function(arg0) { const ret = new Uint8Array(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_set_dcfd613a3420f908 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_set_2357bf09366ee480 = function(arg0, arg1, arg2) { getObject(arg0).set(getObject(arg1), arg2 >>> 0); }; - imports.wbg.__wbg_length_a5587d6cd79ab197 = function(arg0) { + imports.wbg.__wbg_length_1d25fa9e4ac21ce7 = function(arg0) { const ret = getObject(arg0).length; return ret; }; - imports.wbg.__wbg_instanceof_Uint8Array_19e6f142a5e7e1e1 = function(arg0) { + imports.wbg.__wbg_instanceof_Uint8Array_bced6f43aed8c1aa = function(arg0) { let result; try { result = getObject(arg0) instanceof Uint8Array; @@ -951,7 +951,7 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_set_40f7786a25a9cc7e = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_set_759f75cd92b612d2 = function() { return handleError(function (arg0, arg1, arg2) { const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); return ret; }, arguments) }; @@ -969,16 +969,16 @@ function __wbg_get_imports() { const ret = wasm.memory; return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper1235 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 558, __wbg_adapter_38); + imports.wbg.__wbindgen_closure_wrapper1222 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 541, __wbg_adapter_38); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper1369 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 624, __wbg_adapter_41); + imports.wbg.__wbindgen_closure_wrapper1337 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 593, __wbg_adapter_41); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper1450 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 655, __wbg_adapter_44); + imports.wbg.__wbindgen_closure_wrapper1417 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 622, __wbg_adapter_44); return addHeapObject(ret); }; diff --git a/server/web_ui/pkg/kanidmd_web_ui_admin.js.br b/server/web_ui/pkg/kanidmd_web_ui_admin.js.br index 74af90a1a..a9456bd77 100644 Binary files a/server/web_ui/pkg/kanidmd_web_ui_admin.js.br and b/server/web_ui/pkg/kanidmd_web_ui_admin.js.br differ diff --git a/server/web_ui/pkg/kanidmd_web_ui_admin_bg.wasm b/server/web_ui/pkg/kanidmd_web_ui_admin_bg.wasm index a396fc3d6..2c9abc149 100644 Binary files a/server/web_ui/pkg/kanidmd_web_ui_admin_bg.wasm and b/server/web_ui/pkg/kanidmd_web_ui_admin_bg.wasm differ diff --git a/server/web_ui/pkg/kanidmd_web_ui_admin_bg.wasm.br b/server/web_ui/pkg/kanidmd_web_ui_admin_bg.wasm.br index a69e7efe4..6fd412919 100644 Binary files a/server/web_ui/pkg/kanidmd_web_ui_admin_bg.wasm.br and b/server/web_ui/pkg/kanidmd_web_ui_admin_bg.wasm.br differ diff --git a/server/web_ui/pkg/kanidmd_web_ui_login_flows.js b/server/web_ui/pkg/kanidmd_web_ui_login_flows.js index 9410cfbb3..6d15399af 100644 --- a/server/web_ui/pkg/kanidmd_web_ui_login_flows.js +++ b/server/web_ui/pkg/kanidmd_web_ui_login_flows.js @@ -232,19 +232,19 @@ function addBorrowedObject(obj) { } function __wbg_adapter_48(arg0, arg1, arg2) { try { - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h3592199ac636c7ab(arg0, arg1, addBorrowedObject(arg2)); + wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hcd8161c254227fe4(arg0, arg1, addBorrowedObject(arg2)); } finally { heap[stack_pointer++] = undefined; } } function __wbg_adapter_51(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h71282a39cf9f54cc(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hbb91bcb76d7d57c6(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_54(arg0, arg1, arg2) { try { - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h0e38a66b2b075f9c(arg0, arg1, addBorrowedObject(arg2)); + wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h8e106c18de4fadc7(arg0, arg1, addBorrowedObject(arg2)); } finally { heap[stack_pointer++] = undefined; } @@ -346,6 +346,15 @@ function __wbg_get_imports() { getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; + imports.wbg.__wbindgen_cb_drop = function(arg0) { + const obj = takeObject(arg0).original; + if (obj.cnt-- == 1) { + obj.a = 0; + return true; + } + const ret = false; + return ret; + }; imports.wbg.__wbindgen_boolean_get = function(arg0) { const v = getObject(arg0); const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2; @@ -390,23 +399,14 @@ function __wbg_get_imports() { const ret = getObject(arg0) === undefined; return ret; }; - imports.wbg.__wbindgen_cb_drop = function(arg0) { - const obj = takeObject(arg0).original; - if (obj.cnt-- == 1) { - obj.a = 0; - return true; - } - const ret = false; - return ret; + imports.wbg.__wbindgen_object_clone_ref = function(arg0) { + const ret = getObject(arg0); + return addHeapObject(ret); }; imports.wbg.__wbindgen_error_new = function(arg0, arg1) { const ret = new Error(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }; - imports.wbg.__wbindgen_object_clone_ref = function(arg0) { - const ret = getObject(arg0); - return addHeapObject(ret); - }; imports.wbg.__wbg_setlistenerid_3183aae8fa5840fb = function(arg0, arg1) { getObject(arg0).__yew_listener_id = arg1 >>> 0; }; @@ -464,10 +464,10 @@ function __wbg_get_imports() { imports.wbg.__wbg_set_20cbc34131e76824 = function(arg0, arg1, arg2) { getObject(arg0)[takeObject(arg1)] = takeObject(arg2); }; - imports.wbg.__wbg_queueMicrotask_e5949c35d772a669 = function(arg0) { + imports.wbg.__wbg_queueMicrotask_4d890031a6a5a50c = function(arg0) { queueMicrotask(getObject(arg0)); }; - imports.wbg.__wbg_queueMicrotask_2be8b97a81fe4d00 = function(arg0) { + imports.wbg.__wbg_queueMicrotask_adae4bc085237231 = function(arg0) { const ret = getObject(arg0).queueMicrotask; return addHeapObject(ret); }; @@ -507,31 +507,31 @@ function __wbg_get_imports() { wasm.__wbindgen_free(arg0, arg1 * 4, 4); console.warn(...v0); }; - imports.wbg.__wbg_body_11da0c1aa9610cb3 = function(arg0) { + imports.wbg.__wbg_body_64abc9aba1891e91 = function(arg0) { const ret = getObject(arg0).body; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_createElement_9ce3fdea8322ff34 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_createElement_fdd5c113cb84539e = function() { return handleError(function (arg0, arg1, arg2) { const ret = getObject(arg0).createElement(getStringFromWasm0(arg1, arg2)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_createElementNS_6a08d8f33e767e18 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_createElementNS_524b05a6070757b6 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { const ret = getObject(arg0).createElementNS(arg1 === 0 ? undefined : getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_createTextNode_01a7250c5ca46b04 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_createTextNode_7ff0c034b2855f66 = function(arg0, arg1, arg2) { const ret = getObject(arg0).createTextNode(getStringFromWasm0(arg1, arg2)); return addHeapObject(ret); }; - imports.wbg.__wbg_getElementById_328f8c4a5bb51ba8 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_getElementById_65b9547a428b5eb4 = function(arg0, arg1, arg2) { const ret = getObject(arg0).getElementById(getStringFromWasm0(arg1, arg2)); return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_querySelector_391afe271b8236d5 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_querySelector_c72dce5ac4b6bc3e = function() { return handleError(function (arg0, arg1, arg2) { const ret = getObject(arg0).querySelector(getStringFromWasm0(arg1, arg2)); return isLikeNone(ret) ? 0 : addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_instanceof_Window_cde2416cf5126a72 = function(arg0) { + imports.wbg.__wbg_instanceof_Window_3e5cd1f48c152d01 = function(arg0) { let result; try { result = getObject(arg0) instanceof Window; @@ -541,35 +541,35 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_document_183cf1eecfdbffee = function(arg0) { + imports.wbg.__wbg_document_d609202d16c38224 = function(arg0) { const ret = getObject(arg0).document; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_location_61ca61017633c753 = function(arg0) { + imports.wbg.__wbg_location_176c34e89c2c9d80 = function(arg0) { const ret = getObject(arg0).location; return addHeapObject(ret); }; - imports.wbg.__wbg_history_56dc869560201113 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_history_80998b7456bf367e = function() { return handleError(function (arg0) { const ret = getObject(arg0).history; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_navigator_7078da62d92ff5ad = function(arg0) { + imports.wbg.__wbg_navigator_96ba491902f8f083 = function(arg0) { const ret = getObject(arg0).navigator; return addHeapObject(ret); }; - imports.wbg.__wbg_localStorage_e11f72e996a4f5d9 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_localStorage_8c507fd281456944 = function() { return handleError(function (arg0) { const ret = getObject(arg0).localStorage; return isLikeNone(ret) ? 0 : addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_sessionStorage_071949dc646bfd35 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_sessionStorage_adb12b0c8ea06c48 = function() { return handleError(function (arg0) { const ret = getObject(arg0).sessionStorage; return isLikeNone(ret) ? 0 : addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_fetch_8cebc656dc6b11b1 = function(arg0, arg1) { + imports.wbg.__wbg_fetch_6c415b3a07763878 = function(arg0, arg1) { const ret = getObject(arg0).fetch(getObject(arg1)); return addHeapObject(ret); }; - imports.wbg.__wbg_instanceof_Element_6c7af07f5e6c8d69 = function(arg0) { + imports.wbg.__wbg_instanceof_Element_3f326a19cc457941 = function(arg0) { let result; try { result = getObject(arg0) instanceof Element; @@ -579,38 +579,38 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_namespaceURI_2dd94d0147ffddf2 = function(arg0, arg1) { + imports.wbg.__wbg_namespaceURI_7cc7ef157e398356 = function(arg0, arg1) { const ret = getObject(arg1).namespaceURI; var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_classList_7fd39dc155235d8a = function(arg0) { + imports.wbg.__wbg_classList_82893a9100db6428 = function(arg0) { const ret = getObject(arg0).classList; return addHeapObject(ret); }; - imports.wbg.__wbg_setinnerHTML_b88bf159b62c2334 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setinnerHTML_ce0d6527ce4086f2 = function(arg0, arg1, arg2) { getObject(arg0).innerHTML = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_outerHTML_72dcf3aa34725f10 = function(arg0, arg1) { + imports.wbg.__wbg_outerHTML_b5a8d952b5615778 = function(arg0, arg1) { const ret = getObject(arg1).outerHTML; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_children_af5a3246832628b1 = function(arg0) { + imports.wbg.__wbg_children_990f38c4f4d5c721 = function(arg0) { const ret = getObject(arg0).children; return addHeapObject(ret); }; - imports.wbg.__wbg_removeAttribute_dbd76981f9bb9f59 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_removeAttribute_2e200daefb9f3ed4 = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).removeAttribute(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_setAttribute_aebcae2169f2f869 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_setAttribute_e7b72a5e7cfcb5a3 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).setAttribute(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); }, arguments) }; - imports.wbg.__wbg_instanceof_HtmlElement_d9fe655ad4f1046c = function(arg0) { + imports.wbg.__wbg_instanceof_HtmlElement_55a0f0f0f0f0118e = function(arg0) { let result; try { result = getObject(arg0) instanceof HTMLElement; @@ -620,86 +620,86 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_focus_bab0841297cb9142 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_focus_6d3d2b6776d06f7f = function() { return handleError(function (arg0) { getObject(arg0).focus(); }, arguments) }; - imports.wbg.__wbg_get_be3f61d062825ba1 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_get_41904a8f394b5093 = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).get(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_credentials_6a08cfc972615f5c = function(arg0) { + imports.wbg.__wbg_credentials_cef3aa4d1e919496 = function(arg0) { const ret = getObject(arg0).credentials; return addHeapObject(ret); }; - imports.wbg.__wbg_getItem_c81cd3ae30cd579a = function() { return handleError(function (arg0, arg1, arg2, arg3) { + imports.wbg.__wbg_getItem_5395a7e200c31e89 = function() { return handleError(function (arg0, arg1, arg2, arg3) { const ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3)); var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_removeItem_58a487fe7fc070f0 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_removeItem_c84f914587f36b1a = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).removeItem(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_setItem_fe04f524052a3839 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_setItem_3786c4c8dd0c9bd0 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); }, arguments) }; - imports.wbg.__wbg_addEventListener_51709b9747ad8980 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_addEventListener_374cbfd2bbc19ccf = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4)); }, arguments) }; - imports.wbg.__wbg_removeEventListener_5b1e762a7951280a = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_removeEventListener_9ece7e86d1135657 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), arg4 !== 0); }, arguments) }; - imports.wbg.__wbg_state_78eaa7b6ff3123a0 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_state_ba77b2c3ee29c912 = function() { return handleError(function (arg0) { const ret = getObject(arg0).state; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_pushState_8eaca41f86b13910 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) { + imports.wbg.__wbg_pushState_e159043fce8f87bc = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) { getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5)); }, arguments) }; - imports.wbg.__wbg_href_92490614763f3f7c = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_href_160af2ae1328d7b7 = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg1).href; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_sethref_2c377515f8ddd13a = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_sethref_90b000c8b01f96b1 = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).href = getStringFromWasm0(arg1, arg2); }, arguments) }; - imports.wbg.__wbg_pathname_cd5a90c8f3ab524a = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_pathname_1ab7e82aaa4511ff = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg1).pathname; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_search_08fbba2309a249da = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_search_9f7ca8896c2d0804 = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg1).search; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_hash_ced9ee31706e591d = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_hash_be2940ca236b5efc = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg1).hash; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_replace_4f50b38e38ea7fd6 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_replace_c73ceee21ffa44ab = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).replace(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_headers_4711243cf3bffca0 = function(arg0) { + imports.wbg.__wbg_headers_d135d2bb8cc60413 = function(arg0) { const ret = getObject(arg0).headers; return addHeapObject(ret); }; - imports.wbg.__wbg_newwithstrandinit_29038da14d09e330 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_newwithstrandinit_f581dff0d19a8b03 = function() { return handleError(function (arg0, arg1, arg2) { const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_instanceof_Response_944e2745b5db71f5 = function(arg0) { + imports.wbg.__wbg_instanceof_Response_4c3b1446206114d1 = function(arg0) { let result; try { result = getObject(arg0) instanceof Response; @@ -709,57 +709,57 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_status_7841bb47be2a8f16 = function(arg0) { + imports.wbg.__wbg_status_d6d47ad2837621eb = function(arg0) { const ret = getObject(arg0).status; return ret; }; - imports.wbg.__wbg_headers_ea7ef583d1564b08 = function(arg0) { + imports.wbg.__wbg_headers_24def508a7518df9 = function(arg0) { const ret = getObject(arg0).headers; return addHeapObject(ret); }; - imports.wbg.__wbg_json_7f96c90903ae4155 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_json_34535d9848f043eb = function() { return handleError(function (arg0) { const ret = getObject(arg0).json(); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_parentNode_e1c214fc3f362af0 = function(arg0) { + imports.wbg.__wbg_parentNode_92a7017b3a4fad43 = function(arg0) { const ret = getObject(arg0).parentNode; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_parentElement_592cb54944d3d002 = function(arg0) { + imports.wbg.__wbg_parentElement_72e144c2e8d9e0b5 = function(arg0) { const ret = getObject(arg0).parentElement; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_lastChild_b17b3c7498d25bd7 = function(arg0) { + imports.wbg.__wbg_lastChild_a62e3fbaab87f734 = function(arg0) { const ret = getObject(arg0).lastChild; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_nextSibling_d029031876ed1b1b = function(arg0) { + imports.wbg.__wbg_nextSibling_bafccd3347d24543 = function(arg0) { const ret = getObject(arg0).nextSibling; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_setnodeValue_321840a6762ab272 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setnodeValue_630c6470d05b600e = function(arg0, arg1, arg2) { getObject(arg0).nodeValue = arg1 === 0 ? undefined : getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_textContent_d69d000f6081b514 = function(arg0, arg1) { + imports.wbg.__wbg_textContent_2f37235e13f8484b = function(arg0, arg1) { const ret = getObject(arg1).textContent; var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_appendChild_2e6a6c9d1f0d443d = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_appendChild_d30e6b83791d04c0 = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).appendChild(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_insertBefore_bdaeec8969497673 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_insertBefore_726c1640c419e940 = function() { return handleError(function (arg0, arg1, arg2) { const ret = getObject(arg0).insertBefore(getObject(arg1), getObject(arg2)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_removeChild_a63022ebbfa6ebf5 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_removeChild_942eb9c02243d84d = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).removeChild(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_instanceof_ShadowRoot_f85f709c953844de = function(arg0) { + imports.wbg.__wbg_instanceof_ShadowRoot_0bd39e89ab117f86 = function(arg0) { let result; try { result = getObject(arg0) instanceof ShadowRoot; @@ -769,63 +769,63 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_host_73c8e95bf9b31ccd = function(arg0) { + imports.wbg.__wbg_host_09eee5e3d9cf59a1 = function(arg0) { const ret = getObject(arg0).host; return addHeapObject(ret); }; - imports.wbg.__wbg_getClientExtensionResults_d4b9b581db88e947 = function(arg0) { + imports.wbg.__wbg_getClientExtensionResults_8da1aa123f3b7c0b = function(arg0) { const ret = getObject(arg0).getClientExtensionResults(); return addHeapObject(ret); }; - imports.wbg.__wbg_log_7811587c4c6d2844 = function(arg0) { + imports.wbg.__wbg_log_a4530b4fe289336f = function(arg0) { console.log(getObject(arg0)); }; - imports.wbg.__wbg_add_dc5c00591ed65268 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_add_e0f3c5b6e421c311 = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).add(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_remove_9517d3139a6031f1 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_remove_c6ba26a0a6906129 = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).remove(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_href_7f944b48b612250e = function(arg0, arg1) { + imports.wbg.__wbg_href_e9aac3826080dcaa = function(arg0, arg1) { const ret = getObject(arg1).href; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_pathname_a83d8f2ebefa6791 = function(arg0, arg1) { + imports.wbg.__wbg_pathname_aeafa820be91c325 = function(arg0, arg1) { const ret = getObject(arg1).pathname; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_search_8c5f74fa2d11377e = function(arg0, arg1) { + imports.wbg.__wbg_search_f6e95882a48d3f69 = function(arg0, arg1) { const ret = getObject(arg1).search; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_hash_f468e7d38a21a76a = function(arg0, arg1) { + imports.wbg.__wbg_hash_0087751acddc8f2a = function(arg0, arg1) { const ret = getObject(arg1).hash; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_sethash_7c3032584865b2bd = function(arg0, arg1, arg2) { + imports.wbg.__wbg_sethash_bfc9db317a77305c = function(arg0, arg1, arg2) { getObject(arg0).hash = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_new_d7cd05d9de7d4000 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_new_9e08fd37c1c53142 = function() { return handleError(function (arg0, arg1) { const ret = new URL(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_newwithbase_604e8dfd42d25665 = function() { return handleError(function (arg0, arg1, arg2, arg3) { + imports.wbg.__wbg_newwithbase_f4989aa5bbd5cc29 = function() { return handleError(function (arg0, arg1, arg2, arg3) { const ret = new URL(getStringFromWasm0(arg0, arg1), getStringFromWasm0(arg2, arg3)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_instanceof_HtmlInputElement_8f81a6600ceb1918 = function(arg0) { + imports.wbg.__wbg_instanceof_HtmlInputElement_e7869aaef9cbb0e6 = function(arg0) { let result; try { result = getObject(arg0) instanceof HTMLInputElement; @@ -835,149 +835,149 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_checked_1ce2f33e2ed42870 = function(arg0) { + imports.wbg.__wbg_checked_f46acdc11342a4bd = function(arg0) { const ret = getObject(arg0).checked; return ret; }; - imports.wbg.__wbg_setchecked_5757666239434ecd = function(arg0, arg1) { + imports.wbg.__wbg_setchecked_c1d5c3726082e274 = function(arg0, arg1) { getObject(arg0).checked = arg1 !== 0; }; - imports.wbg.__wbg_value_5e860795f53217cd = function(arg0, arg1) { + imports.wbg.__wbg_value_e024243a9dae20bc = function(arg0, arg1) { const ret = getObject(arg1).value; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_setvalue_7d187f6cc23d8192 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setvalue_5b3442ff620b4a5d = function(arg0, arg1, arg2) { getObject(arg0).value = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_bubbles_c27af65192eb3569 = function(arg0) { + imports.wbg.__wbg_bubbles_f1cdd0584446cad0 = function(arg0) { const ret = getObject(arg0).bubbles; return ret; }; - imports.wbg.__wbg_cancelBubble_ee3f70328e901584 = function(arg0) { + imports.wbg.__wbg_cancelBubble_976cfdf7ac449a6c = function(arg0) { const ret = getObject(arg0).cancelBubble; return ret; }; - imports.wbg.__wbg_composedPath_ee37eece046b69a2 = function(arg0) { + imports.wbg.__wbg_composedPath_12a068e57a98cf90 = function(arg0) { const ret = getObject(arg0).composedPath(); return addHeapObject(ret); }; - imports.wbg.__wbg_preventDefault_9299867e06da6909 = function(arg0) { + imports.wbg.__wbg_preventDefault_7f821f72e7c6b5d4 = function(arg0) { getObject(arg0).preventDefault(); }; - imports.wbg.__wbg_get_9470c6584bbde430 = function() { return handleError(function (arg0, arg1, arg2, arg3) { + imports.wbg.__wbg_get_0231cdd369e04a1d = function() { return handleError(function (arg0, arg1, arg2, arg3) { const ret = getObject(arg1).get(getStringFromWasm0(arg2, arg3)); var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_set_2912c891505cbc22 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_set_27f236f6d7a28c29 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); }, arguments) }; - imports.wbg.__wbg_href_2777cc28ba3aac82 = function(arg0, arg1) { + imports.wbg.__wbg_href_f21dc804d4da134a = function(arg0, arg1) { const ret = getObject(arg1).href; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_value_539db729f551be3a = function(arg0, arg1) { + imports.wbg.__wbg_value_57e57170f6952449 = function(arg0, arg1) { const ret = getObject(arg1).value; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_setvalue_15231c60278dee22 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setvalue_a11f3069fd7a1805 = function(arg0, arg1, arg2) { getObject(arg0).value = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_get_4a9aa5157afeb382 = function(arg0, arg1) { + imports.wbg.__wbg_get_f01601b5a68d10e3 = function(arg0, arg1) { const ret = getObject(arg0)[arg1 >>> 0]; return addHeapObject(ret); }; - imports.wbg.__wbg_length_cace2e0b3ddc0502 = function(arg0) { + imports.wbg.__wbg_length_1009b1af0c481d7b = function(arg0) { const ret = getObject(arg0).length; return ret; }; - imports.wbg.__wbg_new_08236689f0afb357 = function() { + imports.wbg.__wbg_new_ffc6d4d085022169 = function() { const ret = new Array(); return addHeapObject(ret); }; - imports.wbg.__wbg_newnoargs_ccdcae30fd002262 = function(arg0, arg1) { + imports.wbg.__wbg_newnoargs_c62ea9419c21fbac = function(arg0, arg1) { const ret = new Function(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }; - imports.wbg.__wbg_new_1b94180eeb48f2a2 = function() { + imports.wbg.__wbg_new_bfd4534b584a9593 = function() { const ret = new Map(); return addHeapObject(ret); }; - imports.wbg.__wbg_next_15da6a3df9290720 = function(arg0) { + imports.wbg.__wbg_next_9b877f231f476d01 = function(arg0) { const ret = getObject(arg0).next; return addHeapObject(ret); }; - imports.wbg.__wbg_next_1989a20442400aaa = function() { return handleError(function (arg0) { + imports.wbg.__wbg_next_6529ee0cca8d57ed = function() { return handleError(function (arg0) { const ret = getObject(arg0).next(); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_done_bc26bf4ada718266 = function(arg0) { + imports.wbg.__wbg_done_5fe336b092d60cf2 = function(arg0) { const ret = getObject(arg0).done; return ret; }; - imports.wbg.__wbg_value_0570714ff7d75f35 = function(arg0) { + imports.wbg.__wbg_value_0c248a78fdc8e19f = function(arg0) { const ret = getObject(arg0).value; return addHeapObject(ret); }; - imports.wbg.__wbg_iterator_7ee1a391d310f8e4 = function() { + imports.wbg.__wbg_iterator_db7ca081358d4fb2 = function() { const ret = Symbol.iterator; return addHeapObject(ret); }; - imports.wbg.__wbg_get_2aff440840bb6202 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_get_7b48513de5dc5ea4 = function() { return handleError(function (arg0, arg1) { const ret = Reflect.get(getObject(arg0), getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_call_669127b9d730c650 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_call_90c26b09837aba1c = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).call(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_new_c728d68b8b34487e = function() { + imports.wbg.__wbg_new_9fb8d994e1c0aaac = function() { const ret = new Object(); return addHeapObject(ret); }; - imports.wbg.__wbg_self_3fad056edded10bd = function() { return handleError(function () { + imports.wbg.__wbg_self_f0e34d89f33b99fd = function() { return handleError(function () { const ret = self.self; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_window_a4f46c98a61d4089 = function() { return handleError(function () { + imports.wbg.__wbg_window_d3b084224f4774d7 = function() { return handleError(function () { const ret = window.window; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_globalThis_17eff828815f7d84 = function() { return handleError(function () { + imports.wbg.__wbg_globalThis_9caa27ff917c6860 = function() { return handleError(function () { const ret = globalThis.globalThis; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_global_46f939f6541643c5 = function() { return handleError(function () { + imports.wbg.__wbg_global_35dfdd59a4da3e74 = function() { return handleError(function () { const ret = global.global; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_set_0ac78a2bc07da03c = function(arg0, arg1, arg2) { + imports.wbg.__wbg_set_f2740edb12e318cd = function(arg0, arg1, arg2) { getObject(arg0)[arg1 >>> 0] = takeObject(arg2); }; - imports.wbg.__wbg_from_ba72c50feaf1d8c0 = function(arg0) { + imports.wbg.__wbg_from_71add2e723d1f1b2 = function(arg0) { const ret = Array.from(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_isArray_38525be7442aa21e = function(arg0) { + imports.wbg.__wbg_isArray_74fb723e24f76012 = function(arg0) { const ret = Array.isArray(getObject(arg0)); return ret; }; - imports.wbg.__wbg_push_fd3233d09cf81821 = function(arg0, arg1) { + imports.wbg.__wbg_push_901f3914205d44de = function(arg0, arg1) { const ret = getObject(arg0).push(getObject(arg1)); return ret; }; - imports.wbg.__wbg_instanceof_ArrayBuffer_c7cc317e5c29cc0d = function(arg0) { + imports.wbg.__wbg_instanceof_ArrayBuffer_e7d53d51371448e2 = function(arg0) { let result; try { result = getObject(arg0) instanceof ArrayBuffer; @@ -987,7 +987,7 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_instanceof_Error_9f5881c3c4149389 = function(arg0) { + imports.wbg.__wbg_instanceof_Error_31ca8d97f188bfbc = function(arg0) { let result; try { result = getObject(arg0) instanceof Error; @@ -997,66 +997,66 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_message_35f9b952e1b922e2 = function(arg0) { + imports.wbg.__wbg_message_55b9ea8030688597 = function(arg0) { const ret = getObject(arg0).message; return addHeapObject(ret); }; - imports.wbg.__wbg_name_e1152a59269f79e5 = function(arg0) { + imports.wbg.__wbg_name_e5eede664187fed6 = function(arg0) { const ret = getObject(arg0).name; return addHeapObject(ret); }; - imports.wbg.__wbg_toString_d0cefe4046ecb265 = function(arg0) { + imports.wbg.__wbg_toString_a44236e90224e279 = function(arg0) { const ret = getObject(arg0).toString(); return addHeapObject(ret); }; - imports.wbg.__wbg_set_3355b9f2d3092e3b = function(arg0, arg1, arg2) { + imports.wbg.__wbg_set_d257c6f2da008627 = function(arg0, arg1, arg2) { const ret = getObject(arg0).set(getObject(arg1), getObject(arg2)); return addHeapObject(ret); }; - imports.wbg.__wbg_isSafeInteger_c38b0a16d0c7cef7 = function(arg0) { + imports.wbg.__wbg_isSafeInteger_f93fde0dca9820f8 = function(arg0) { const ret = Number.isSafeInteger(getObject(arg0)); return ret; }; - imports.wbg.__wbg_entries_6d727b73ee02b7ce = function(arg0) { + imports.wbg.__wbg_entries_9e2e2aa45aa5094a = function(arg0) { const ret = Object.entries(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_is_c74aa9bb973d6109 = function(arg0, arg1) { + imports.wbg.__wbg_is_ff7acd231c75c0e4 = function(arg0, arg1) { const ret = Object.is(getObject(arg0), getObject(arg1)); return ret; }; - imports.wbg.__wbg_resolve_a3252b2860f0a09e = function(arg0) { + imports.wbg.__wbg_resolve_6e1c6553a82f85b7 = function(arg0) { const ret = Promise.resolve(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_then_89e1c559530b85cf = function(arg0, arg1) { + imports.wbg.__wbg_then_3ab08cd4fbb91ae9 = function(arg0, arg1) { const ret = getObject(arg0).then(getObject(arg1)); return addHeapObject(ret); }; - imports.wbg.__wbg_then_1bbc9edafd859b06 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_then_8371cc12cfedc5a2 = function(arg0, arg1, arg2) { const ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); return addHeapObject(ret); }; - imports.wbg.__wbg_buffer_344d9b41efe96da7 = function(arg0) { + imports.wbg.__wbg_buffer_a448f833075b71ba = function(arg0) { const ret = getObject(arg0).buffer; return addHeapObject(ret); }; - imports.wbg.__wbg_newwithbyteoffsetandlength_2dc04d99088b15e3 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_newwithbyteoffsetandlength_d0482f893617af71 = function(arg0, arg1, arg2) { const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); return addHeapObject(ret); }; - imports.wbg.__wbg_new_d8a000788389a31e = function(arg0) { + imports.wbg.__wbg_new_8f67e318f15d7254 = function(arg0) { const ret = new Uint8Array(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_set_dcfd613a3420f908 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_set_2357bf09366ee480 = function(arg0, arg1, arg2) { getObject(arg0).set(getObject(arg1), arg2 >>> 0); }; - imports.wbg.__wbg_length_a5587d6cd79ab197 = function(arg0) { + imports.wbg.__wbg_length_1d25fa9e4ac21ce7 = function(arg0) { const ret = getObject(arg0).length; return ret; }; - imports.wbg.__wbg_instanceof_Uint8Array_19e6f142a5e7e1e1 = function(arg0) { + imports.wbg.__wbg_instanceof_Uint8Array_bced6f43aed8c1aa = function(arg0) { let result; try { result = getObject(arg0) instanceof Uint8Array; @@ -1066,11 +1066,11 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_set_40f7786a25a9cc7e = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_set_759f75cd92b612d2 = function() { return handleError(function (arg0, arg1, arg2) { const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); return ret; }, arguments) }; - imports.wbg.__wbg_stringify_4039297315a25b00 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_stringify_e1b19966d964d242 = function() { return handleError(function (arg0) { const ret = JSON.stringify(getObject(arg0)); return addHeapObject(ret); }, arguments) }; @@ -1094,16 +1094,16 @@ function __wbg_get_imports() { const ret = wasm.memory; return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper1388 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 488, __wbg_adapter_48); + imports.wbg.__wbindgen_closure_wrapper1297 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 459, __wbg_adapter_48); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper1773 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 630, __wbg_adapter_51); + imports.wbg.__wbindgen_closure_wrapper1737 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 601, __wbg_adapter_51); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper1855 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 661, __wbg_adapter_54); + imports.wbg.__wbindgen_closure_wrapper1822 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 632, __wbg_adapter_54); return addHeapObject(ret); }; diff --git a/server/web_ui/pkg/kanidmd_web_ui_login_flows.js.br b/server/web_ui/pkg/kanidmd_web_ui_login_flows.js.br index be9f340d0..148f6d0dc 100644 Binary files a/server/web_ui/pkg/kanidmd_web_ui_login_flows.js.br and b/server/web_ui/pkg/kanidmd_web_ui_login_flows.js.br differ diff --git a/server/web_ui/pkg/kanidmd_web_ui_login_flows_bg.wasm b/server/web_ui/pkg/kanidmd_web_ui_login_flows_bg.wasm index 0495e4bb5..ee3eac894 100644 Binary files a/server/web_ui/pkg/kanidmd_web_ui_login_flows_bg.wasm and b/server/web_ui/pkg/kanidmd_web_ui_login_flows_bg.wasm differ diff --git a/server/web_ui/pkg/kanidmd_web_ui_login_flows_bg.wasm.br b/server/web_ui/pkg/kanidmd_web_ui_login_flows_bg.wasm.br index 92001759d..35f2cad0e 100644 Binary files a/server/web_ui/pkg/kanidmd_web_ui_login_flows_bg.wasm.br and b/server/web_ui/pkg/kanidmd_web_ui_login_flows_bg.wasm.br differ diff --git a/server/web_ui/pkg/kanidmd_web_ui_user.js b/server/web_ui/pkg/kanidmd_web_ui_user.js index ca4400726..33612c78b 100644 --- a/server/web_ui/pkg/kanidmd_web_ui_user.js +++ b/server/web_ui/pkg/kanidmd_web_ui_user.js @@ -225,7 +225,7 @@ function makeMutClosure(arg0, arg1, dtor, f) { return real; } function __wbg_adapter_48(arg0, arg1) { - wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h4b3f7f6f56bc064a(arg0, arg1); + wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h0c62d2840bb83f65(arg0, arg1); } let stack_pointer = 128; @@ -237,19 +237,19 @@ function addBorrowedObject(obj) { } function __wbg_adapter_51(arg0, arg1, arg2) { try { - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__ha7af6bbd80504275(arg0, arg1, addBorrowedObject(arg2)); + wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h703c5e695d9d8aa0(arg0, arg1, addBorrowedObject(arg2)); } finally { heap[stack_pointer++] = undefined; } } function __wbg_adapter_54(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h71282a39cf9f54cc(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hbb91bcb76d7d57c6(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_57(arg0, arg1, arg2) { try { - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__he72980a19bbd8d74(arg0, arg1, addBorrowedObject(arg2)); + wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h16a1b64144cde668(arg0, arg1, addBorrowedObject(arg2)); } finally { heap[stack_pointer++] = undefined; } @@ -403,14 +403,14 @@ function __wbg_get_imports() { const ret = false; return ret; }; - imports.wbg.__wbindgen_error_new = function(arg0, arg1) { - const ret = new Error(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); - }; imports.wbg.__wbindgen_object_clone_ref = function(arg0) { const ret = getObject(arg0); return addHeapObject(ret); }; + imports.wbg.__wbindgen_error_new = function(arg0, arg1) { + const ret = new Error(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }; imports.wbg.__wbg_clearTimeout_541ac0980ffcef74 = function(arg0) { const ret = clearTimeout(takeObject(arg0)); return addHeapObject(ret); @@ -476,10 +476,10 @@ function __wbg_get_imports() { wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); } }; - imports.wbg.__wbg_queueMicrotask_e5949c35d772a669 = function(arg0) { + imports.wbg.__wbg_queueMicrotask_4d890031a6a5a50c = function(arg0) { queueMicrotask(getObject(arg0)); }; - imports.wbg.__wbg_queueMicrotask_2be8b97a81fe4d00 = function(arg0) { + imports.wbg.__wbg_queueMicrotask_adae4bc085237231 = function(arg0) { const ret = getObject(arg0).queueMicrotask; return addHeapObject(ret); }; @@ -520,38 +520,38 @@ function __wbg_get_imports() { imports.wbg.__wbg_set_20cbc34131e76824 = function(arg0, arg1, arg2) { getObject(arg0)[takeObject(arg1)] = takeObject(arg2); }; - imports.wbg.__wbg_documentURI_0b154b59e1e400a6 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_documentURI_5d5237c96f11d7e6 = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg1).documentURI; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_body_11da0c1aa9610cb3 = function(arg0) { + imports.wbg.__wbg_body_64abc9aba1891e91 = function(arg0) { const ret = getObject(arg0).body; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_createElement_9ce3fdea8322ff34 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_createElement_fdd5c113cb84539e = function() { return handleError(function (arg0, arg1, arg2) { const ret = getObject(arg0).createElement(getStringFromWasm0(arg1, arg2)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_createElementNS_6a08d8f33e767e18 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_createElementNS_524b05a6070757b6 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { const ret = getObject(arg0).createElementNS(arg1 === 0 ? undefined : getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_createTextNode_01a7250c5ca46b04 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_createTextNode_7ff0c034b2855f66 = function(arg0, arg1, arg2) { const ret = getObject(arg0).createTextNode(getStringFromWasm0(arg1, arg2)); return addHeapObject(ret); }; - imports.wbg.__wbg_getElementById_328f8c4a5bb51ba8 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_getElementById_65b9547a428b5eb4 = function(arg0, arg1, arg2) { const ret = getObject(arg0).getElementById(getStringFromWasm0(arg1, arg2)); return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_querySelector_391afe271b8236d5 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_querySelector_c72dce5ac4b6bc3e = function() { return handleError(function (arg0, arg1, arg2) { const ret = getObject(arg0).querySelector(getStringFromWasm0(arg1, arg2)); return isLikeNone(ret) ? 0 : addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_instanceof_Window_cde2416cf5126a72 = function(arg0) { + imports.wbg.__wbg_instanceof_Window_3e5cd1f48c152d01 = function(arg0) { let result; try { result = getObject(arg0) instanceof Window; @@ -561,35 +561,35 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_document_183cf1eecfdbffee = function(arg0) { + imports.wbg.__wbg_document_d609202d16c38224 = function(arg0) { const ret = getObject(arg0).document; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_location_61ca61017633c753 = function(arg0) { + imports.wbg.__wbg_location_176c34e89c2c9d80 = function(arg0) { const ret = getObject(arg0).location; return addHeapObject(ret); }; - imports.wbg.__wbg_history_56dc869560201113 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_history_80998b7456bf367e = function() { return handleError(function (arg0) { const ret = getObject(arg0).history; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_navigator_7078da62d92ff5ad = function(arg0) { + imports.wbg.__wbg_navigator_96ba491902f8f083 = function(arg0) { const ret = getObject(arg0).navigator; return addHeapObject(ret); }; - imports.wbg.__wbg_localStorage_e11f72e996a4f5d9 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_localStorage_8c507fd281456944 = function() { return handleError(function (arg0) { const ret = getObject(arg0).localStorage; return isLikeNone(ret) ? 0 : addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_sessionStorage_071949dc646bfd35 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_sessionStorage_adb12b0c8ea06c48 = function() { return handleError(function (arg0) { const ret = getObject(arg0).sessionStorage; return isLikeNone(ret) ? 0 : addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_fetch_8cebc656dc6b11b1 = function(arg0, arg1) { + imports.wbg.__wbg_fetch_6c415b3a07763878 = function(arg0, arg1) { const ret = getObject(arg0).fetch(getObject(arg1)); return addHeapObject(ret); }; - imports.wbg.__wbg_instanceof_Element_6c7af07f5e6c8d69 = function(arg0) { + imports.wbg.__wbg_instanceof_Element_3f326a19cc457941 = function(arg0) { let result; try { result = getObject(arg0) instanceof Element; @@ -599,38 +599,38 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_namespaceURI_2dd94d0147ffddf2 = function(arg0, arg1) { + imports.wbg.__wbg_namespaceURI_7cc7ef157e398356 = function(arg0, arg1) { const ret = getObject(arg1).namespaceURI; var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_classList_7fd39dc155235d8a = function(arg0) { + imports.wbg.__wbg_classList_82893a9100db6428 = function(arg0) { const ret = getObject(arg0).classList; return addHeapObject(ret); }; - imports.wbg.__wbg_setinnerHTML_b88bf159b62c2334 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setinnerHTML_ce0d6527ce4086f2 = function(arg0, arg1, arg2) { getObject(arg0).innerHTML = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_outerHTML_72dcf3aa34725f10 = function(arg0, arg1) { + imports.wbg.__wbg_outerHTML_b5a8d952b5615778 = function(arg0, arg1) { const ret = getObject(arg1).outerHTML; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_children_af5a3246832628b1 = function(arg0) { + imports.wbg.__wbg_children_990f38c4f4d5c721 = function(arg0) { const ret = getObject(arg0).children; return addHeapObject(ret); }; - imports.wbg.__wbg_removeAttribute_dbd76981f9bb9f59 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_removeAttribute_2e200daefb9f3ed4 = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).removeAttribute(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_setAttribute_aebcae2169f2f869 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_setAttribute_e7b72a5e7cfcb5a3 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).setAttribute(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); }, arguments) }; - imports.wbg.__wbg_instanceof_HtmlElement_d9fe655ad4f1046c = function(arg0) { + imports.wbg.__wbg_instanceof_HtmlElement_55a0f0f0f0f0118e = function(arg0) { let result; try { result = getObject(arg0) instanceof HTMLElement; @@ -640,193 +640,137 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_focus_bab0841297cb9142 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_focus_6d3d2b6776d06f7f = function() { return handleError(function (arg0) { getObject(arg0).focus(); }, arguments) }; - imports.wbg.__wbg_credentials_6a08cfc972615f5c = function(arg0) { + imports.wbg.__wbg_credentials_cef3aa4d1e919496 = function(arg0) { const ret = getObject(arg0).credentials; return addHeapObject(ret); }; - imports.wbg.__wbg_getItem_c81cd3ae30cd579a = function() { return handleError(function (arg0, arg1, arg2, arg3) { + imports.wbg.__wbg_getItem_5395a7e200c31e89 = function() { return handleError(function (arg0, arg1, arg2, arg3) { const ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3)); var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_removeItem_58a487fe7fc070f0 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_removeItem_c84f914587f36b1a = function() { return handleError(function (arg0, arg1, arg2) { getObject(arg0).removeItem(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_setItem_fe04f524052a3839 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_setItem_3786c4c8dd0c9bd0 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); }, arguments) }; - imports.wbg.__wbg_href_7f944b48b612250e = function(arg0, arg1) { + imports.wbg.__wbg_href_e9aac3826080dcaa = function(arg0, arg1) { const ret = getObject(arg1).href; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_pathname_a83d8f2ebefa6791 = function(arg0, arg1) { + imports.wbg.__wbg_pathname_aeafa820be91c325 = function(arg0, arg1) { const ret = getObject(arg1).pathname; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_search_8c5f74fa2d11377e = function(arg0, arg1) { + imports.wbg.__wbg_search_f6e95882a48d3f69 = function(arg0, arg1) { const ret = getObject(arg1).search; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_setsearch_a168105ad9dbdb8b = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setsearch_4f7d084e0d811add = function(arg0, arg1, arg2) { getObject(arg0).search = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_hash_f468e7d38a21a76a = function(arg0, arg1) { + imports.wbg.__wbg_hash_0087751acddc8f2a = function(arg0, arg1) { const ret = getObject(arg1).hash; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_sethash_7c3032584865b2bd = function(arg0, arg1, arg2) { + imports.wbg.__wbg_sethash_bfc9db317a77305c = function(arg0, arg1, arg2) { getObject(arg0).hash = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_new_d7cd05d9de7d4000 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_new_9e08fd37c1c53142 = function() { return handleError(function (arg0, arg1) { const ret = new URL(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_newwithbase_604e8dfd42d25665 = function() { return handleError(function (arg0, arg1, arg2, arg3) { + imports.wbg.__wbg_newwithbase_f4989aa5bbd5cc29 = function() { return handleError(function (arg0, arg1, arg2, arg3) { const ret = new URL(getStringFromWasm0(arg0, arg1), getStringFromWasm0(arg2, arg3)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_href_2777cc28ba3aac82 = function(arg0, arg1) { + imports.wbg.__wbg_href_f21dc804d4da134a = function(arg0, arg1) { const ret = getObject(arg1).href; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_value_539db729f551be3a = function(arg0, arg1) { + imports.wbg.__wbg_value_57e57170f6952449 = function(arg0, arg1) { const ret = getObject(arg1).value; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_setvalue_15231c60278dee22 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setvalue_a11f3069fd7a1805 = function(arg0, arg1, arg2) { getObject(arg0).value = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_target_6efb4504c149139f = function(arg0) { + imports.wbg.__wbg_target_52ddf6955f636bf5 = function(arg0) { const ret = getObject(arg0).target; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_bubbles_c27af65192eb3569 = function(arg0) { + imports.wbg.__wbg_bubbles_f1cdd0584446cad0 = function(arg0) { const ret = getObject(arg0).bubbles; return ret; }; - imports.wbg.__wbg_cancelBubble_ee3f70328e901584 = function(arg0) { + imports.wbg.__wbg_cancelBubble_976cfdf7ac449a6c = function(arg0) { const ret = getObject(arg0).cancelBubble; return ret; }; - imports.wbg.__wbg_composedPath_ee37eece046b69a2 = function(arg0) { + imports.wbg.__wbg_composedPath_12a068e57a98cf90 = function(arg0) { const ret = getObject(arg0).composedPath(); return addHeapObject(ret); }; - imports.wbg.__wbg_preventDefault_9299867e06da6909 = function(arg0) { + imports.wbg.__wbg_preventDefault_7f821f72e7c6b5d4 = function(arg0) { getObject(arg0).preventDefault(); }; - imports.wbg.__wbg_get_9470c6584bbde430 = function() { return handleError(function (arg0, arg1, arg2, arg3) { + imports.wbg.__wbg_get_0231cdd369e04a1d = function() { return handleError(function (arg0, arg1, arg2, arg3) { const ret = getObject(arg1).get(getStringFromWasm0(arg2, arg3)); var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_set_2912c891505cbc22 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + imports.wbg.__wbg_set_27f236f6d7a28c29 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); }, arguments) }; - imports.wbg.__wbg_getClientExtensionResults_d4b9b581db88e947 = function(arg0) { + imports.wbg.__wbg_getClientExtensionResults_8da1aa123f3b7c0b = function(arg0) { const ret = getObject(arg0).getClientExtensionResults(); return addHeapObject(ret); }; - imports.wbg.__wbg_addEventListener_51709b9747ad8980 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4)); - }, arguments) }; - imports.wbg.__wbg_removeEventListener_5b1e762a7951280a = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), arg4 !== 0); - }, arguments) }; - imports.wbg.__wbg_state_78eaa7b6ff3123a0 = function() { return handleError(function (arg0) { - const ret = getObject(arg0).state; + imports.wbg.__wbg_create_413706d5496ca07c = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg0).create(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_pushState_8eaca41f86b13910 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) { - getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5)); + imports.wbg.__wbg_add_e0f3c5b6e421c311 = function() { return handleError(function (arg0, arg1, arg2) { + getObject(arg0).add(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_href_92490614763f3f7c = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg1).href; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; + imports.wbg.__wbg_remove_c6ba26a0a6906129 = function() { return handleError(function (arg0, arg1, arg2) { + getObject(arg0).remove(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_sethref_2c377515f8ddd13a = function() { return handleError(function (arg0, arg1, arg2) { - getObject(arg0).href = getStringFromWasm0(arg1, arg2); + imports.wbg.__wbg_newwithform_f67de494d7d454b2 = function() { return handleError(function (arg0) { + const ret = new FormData(getObject(arg0)); + return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_pathname_cd5a90c8f3ab524a = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg1).pathname; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }, arguments) }; - imports.wbg.__wbg_search_08fbba2309a249da = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg1).search; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }, arguments) }; - imports.wbg.__wbg_hash_ced9ee31706e591d = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg1).hash; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }, arguments) }; - imports.wbg.__wbg_headers_4711243cf3bffca0 = function(arg0) { - const ret = getObject(arg0).headers; + imports.wbg.__wbg_get_d5bbacfdbebebc6e = function(arg0, arg1, arg2) { + const ret = getObject(arg0).get(getStringFromWasm0(arg1, arg2)); return addHeapObject(ret); }; - imports.wbg.__wbg_newwithstrandinit_29038da14d09e330 = function() { return handleError(function (arg0, arg1, arg2) { - const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_instanceof_Response_944e2745b5db71f5 = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof Response; - } catch (_) { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_status_7841bb47be2a8f16 = function(arg0) { - const ret = getObject(arg0).status; - return ret; - }; - imports.wbg.__wbg_headers_ea7ef583d1564b08 = function(arg0) { - const ret = getObject(arg0).headers; - return addHeapObject(ret); - }; - imports.wbg.__wbg_json_7f96c90903ae4155 = function() { return handleError(function (arg0) { - const ret = getObject(arg0).json(); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_instanceof_HtmlInputElement_8f81a6600ceb1918 = function(arg0) { + imports.wbg.__wbg_instanceof_HtmlInputElement_e7869aaef9cbb0e6 = function(arg0) { let result; try { result = getObject(arg0) instanceof HTMLInputElement; @@ -836,38 +780,94 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_setchecked_5757666239434ecd = function(arg0, arg1) { + imports.wbg.__wbg_setchecked_c1d5c3726082e274 = function(arg0, arg1) { getObject(arg0).checked = arg1 !== 0; }; - imports.wbg.__wbg_value_5e860795f53217cd = function(arg0, arg1) { + imports.wbg.__wbg_value_e024243a9dae20bc = function(arg0, arg1) { const ret = getObject(arg1).value; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_setvalue_7d187f6cc23d8192 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setvalue_5b3442ff620b4a5d = function(arg0, arg1, arg2) { getObject(arg0).value = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_create_3e99c3ed46cd9f00 = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg0).create(getObject(arg1)); + imports.wbg.__wbg_addEventListener_374cbfd2bbc19ccf = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4)); + }, arguments) }; + imports.wbg.__wbg_removeEventListener_9ece7e86d1135657 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), arg4 !== 0); + }, arguments) }; + imports.wbg.__wbg_state_ba77b2c3ee29c912 = function() { return handleError(function (arg0) { + const ret = getObject(arg0).state; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_add_dc5c00591ed65268 = function() { return handleError(function (arg0, arg1, arg2) { - getObject(arg0).add(getStringFromWasm0(arg1, arg2)); + imports.wbg.__wbg_pushState_e159043fce8f87bc = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) { + getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5)); }, arguments) }; - imports.wbg.__wbg_remove_9517d3139a6031f1 = function() { return handleError(function (arg0, arg1, arg2) { - getObject(arg0).remove(getStringFromWasm0(arg1, arg2)); + imports.wbg.__wbg_href_160af2ae1328d7b7 = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg1).href; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, arguments) }; - imports.wbg.__wbg_newwithform_e7fc7c06976f3c8f = function() { return handleError(function (arg0) { - const ret = new FormData(getObject(arg0)); - return addHeapObject(ret); + imports.wbg.__wbg_sethref_90b000c8b01f96b1 = function() { return handleError(function (arg0, arg1, arg2) { + getObject(arg0).href = getStringFromWasm0(arg1, arg2); }, arguments) }; - imports.wbg.__wbg_get_9e3c11077651eda8 = function(arg0, arg1, arg2) { - const ret = getObject(arg0).get(getStringFromWasm0(arg1, arg2)); + imports.wbg.__wbg_pathname_1ab7e82aaa4511ff = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg1).pathname; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, arguments) }; + imports.wbg.__wbg_search_9f7ca8896c2d0804 = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg1).search; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, arguments) }; + imports.wbg.__wbg_hash_be2940ca236b5efc = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg1).hash; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, arguments) }; + imports.wbg.__wbg_headers_d135d2bb8cc60413 = function(arg0) { + const ret = getObject(arg0).headers; return addHeapObject(ret); }; - imports.wbg.__wbg_instanceof_HtmlFormElement_eb100a9bdacc9fe6 = function(arg0) { + imports.wbg.__wbg_newwithstrandinit_f581dff0d19a8b03 = function() { return handleError(function (arg0, arg1, arg2) { + const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2)); + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_instanceof_Response_4c3b1446206114d1 = function(arg0) { + let result; + try { + result = getObject(arg0) instanceof Response; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }; + imports.wbg.__wbg_status_d6d47ad2837621eb = function(arg0) { + const ret = getObject(arg0).status; + return ret; + }; + imports.wbg.__wbg_headers_24def508a7518df9 = function(arg0) { + const ret = getObject(arg0).headers; + return addHeapObject(ret); + }; + imports.wbg.__wbg_json_34535d9848f043eb = function() { return handleError(function (arg0) { + const ret = getObject(arg0).json(); + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_instanceof_HtmlFormElement_7d89e65c39841f5c = function(arg0) { let result; try { result = getObject(arg0) instanceof HTMLFormElement; @@ -877,45 +877,45 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_parentNode_e1c214fc3f362af0 = function(arg0) { + imports.wbg.__wbg_parentNode_92a7017b3a4fad43 = function(arg0) { const ret = getObject(arg0).parentNode; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_parentElement_592cb54944d3d002 = function(arg0) { + imports.wbg.__wbg_parentElement_72e144c2e8d9e0b5 = function(arg0) { const ret = getObject(arg0).parentElement; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_lastChild_b17b3c7498d25bd7 = function(arg0) { + imports.wbg.__wbg_lastChild_a62e3fbaab87f734 = function(arg0) { const ret = getObject(arg0).lastChild; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_nextSibling_d029031876ed1b1b = function(arg0) { + imports.wbg.__wbg_nextSibling_bafccd3347d24543 = function(arg0) { const ret = getObject(arg0).nextSibling; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_setnodeValue_321840a6762ab272 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_setnodeValue_630c6470d05b600e = function(arg0, arg1, arg2) { getObject(arg0).nodeValue = arg1 === 0 ? undefined : getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_textContent_d69d000f6081b514 = function(arg0, arg1) { + imports.wbg.__wbg_textContent_2f37235e13f8484b = function(arg0, arg1) { const ret = getObject(arg1).textContent; var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_appendChild_2e6a6c9d1f0d443d = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_appendChild_d30e6b83791d04c0 = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).appendChild(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_insertBefore_bdaeec8969497673 = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_insertBefore_726c1640c419e940 = function() { return handleError(function (arg0, arg1, arg2) { const ret = getObject(arg0).insertBefore(getObject(arg1), getObject(arg2)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_removeChild_a63022ebbfa6ebf5 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_removeChild_942eb9c02243d84d = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).removeChild(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_instanceof_ShadowRoot_f85f709c953844de = function(arg0) { + imports.wbg.__wbg_instanceof_ShadowRoot_0bd39e89ab117f86 = function(arg0) { let result; try { result = getObject(arg0) instanceof ShadowRoot; @@ -925,94 +925,94 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_host_73c8e95bf9b31ccd = function(arg0) { + imports.wbg.__wbg_host_09eee5e3d9cf59a1 = function(arg0) { const ret = getObject(arg0).host; return addHeapObject(ret); }; - imports.wbg.__wbg_get_4a9aa5157afeb382 = function(arg0, arg1) { + imports.wbg.__wbg_get_f01601b5a68d10e3 = function(arg0, arg1) { const ret = getObject(arg0)[arg1 >>> 0]; return addHeapObject(ret); }; - imports.wbg.__wbg_length_cace2e0b3ddc0502 = function(arg0) { + imports.wbg.__wbg_length_1009b1af0c481d7b = function(arg0) { const ret = getObject(arg0).length; return ret; }; - imports.wbg.__wbg_new_08236689f0afb357 = function() { + imports.wbg.__wbg_new_ffc6d4d085022169 = function() { const ret = new Array(); return addHeapObject(ret); }; - imports.wbg.__wbg_newnoargs_ccdcae30fd002262 = function(arg0, arg1) { + imports.wbg.__wbg_newnoargs_c62ea9419c21fbac = function(arg0, arg1) { const ret = new Function(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }; - imports.wbg.__wbg_new_1b94180eeb48f2a2 = function() { + imports.wbg.__wbg_new_bfd4534b584a9593 = function() { const ret = new Map(); return addHeapObject(ret); }; - imports.wbg.__wbg_next_15da6a3df9290720 = function(arg0) { + imports.wbg.__wbg_next_9b877f231f476d01 = function(arg0) { const ret = getObject(arg0).next; return addHeapObject(ret); }; - imports.wbg.__wbg_next_1989a20442400aaa = function() { return handleError(function (arg0) { + imports.wbg.__wbg_next_6529ee0cca8d57ed = function() { return handleError(function (arg0) { const ret = getObject(arg0).next(); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_done_bc26bf4ada718266 = function(arg0) { + imports.wbg.__wbg_done_5fe336b092d60cf2 = function(arg0) { const ret = getObject(arg0).done; return ret; }; - imports.wbg.__wbg_value_0570714ff7d75f35 = function(arg0) { + imports.wbg.__wbg_value_0c248a78fdc8e19f = function(arg0) { const ret = getObject(arg0).value; return addHeapObject(ret); }; - imports.wbg.__wbg_iterator_7ee1a391d310f8e4 = function() { + imports.wbg.__wbg_iterator_db7ca081358d4fb2 = function() { const ret = Symbol.iterator; return addHeapObject(ret); }; - imports.wbg.__wbg_get_2aff440840bb6202 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_get_7b48513de5dc5ea4 = function() { return handleError(function (arg0, arg1) { const ret = Reflect.get(getObject(arg0), getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_call_669127b9d730c650 = function() { return handleError(function (arg0, arg1) { + imports.wbg.__wbg_call_90c26b09837aba1c = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).call(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_new_c728d68b8b34487e = function() { + imports.wbg.__wbg_new_9fb8d994e1c0aaac = function() { const ret = new Object(); return addHeapObject(ret); }; - imports.wbg.__wbg_self_3fad056edded10bd = function() { return handleError(function () { + imports.wbg.__wbg_self_f0e34d89f33b99fd = function() { return handleError(function () { const ret = self.self; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_window_a4f46c98a61d4089 = function() { return handleError(function () { + imports.wbg.__wbg_window_d3b084224f4774d7 = function() { return handleError(function () { const ret = window.window; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_globalThis_17eff828815f7d84 = function() { return handleError(function () { + imports.wbg.__wbg_globalThis_9caa27ff917c6860 = function() { return handleError(function () { const ret = globalThis.globalThis; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_global_46f939f6541643c5 = function() { return handleError(function () { + imports.wbg.__wbg_global_35dfdd59a4da3e74 = function() { return handleError(function () { const ret = global.global; return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_set_0ac78a2bc07da03c = function(arg0, arg1, arg2) { + imports.wbg.__wbg_set_f2740edb12e318cd = function(arg0, arg1, arg2) { getObject(arg0)[arg1 >>> 0] = takeObject(arg2); }; - imports.wbg.__wbg_from_ba72c50feaf1d8c0 = function(arg0) { + imports.wbg.__wbg_from_71add2e723d1f1b2 = function(arg0) { const ret = Array.from(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_isArray_38525be7442aa21e = function(arg0) { + imports.wbg.__wbg_isArray_74fb723e24f76012 = function(arg0) { const ret = Array.isArray(getObject(arg0)); return ret; }; - imports.wbg.__wbg_push_fd3233d09cf81821 = function(arg0, arg1) { + imports.wbg.__wbg_push_901f3914205d44de = function(arg0, arg1) { const ret = getObject(arg0).push(getObject(arg1)); return ret; }; - imports.wbg.__wbg_instanceof_ArrayBuffer_c7cc317e5c29cc0d = function(arg0) { + imports.wbg.__wbg_instanceof_ArrayBuffer_e7d53d51371448e2 = function(arg0) { let result; try { result = getObject(arg0) instanceof ArrayBuffer; @@ -1022,7 +1022,7 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_instanceof_Error_9f5881c3c4149389 = function(arg0) { + imports.wbg.__wbg_instanceof_Error_31ca8d97f188bfbc = function(arg0) { let result; try { result = getObject(arg0) instanceof Error; @@ -1032,78 +1032,78 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_message_35f9b952e1b922e2 = function(arg0) { + imports.wbg.__wbg_message_55b9ea8030688597 = function(arg0) { const ret = getObject(arg0).message; return addHeapObject(ret); }; - imports.wbg.__wbg_name_e1152a59269f79e5 = function(arg0) { + imports.wbg.__wbg_name_e5eede664187fed6 = function(arg0) { const ret = getObject(arg0).name; return addHeapObject(ret); }; - imports.wbg.__wbg_toString_d0cefe4046ecb265 = function(arg0) { + imports.wbg.__wbg_toString_a44236e90224e279 = function(arg0) { const ret = getObject(arg0).toString(); return addHeapObject(ret); }; - imports.wbg.__wbg_set_3355b9f2d3092e3b = function(arg0, arg1, arg2) { + imports.wbg.__wbg_set_d257c6f2da008627 = function(arg0, arg1, arg2) { const ret = getObject(arg0).set(getObject(arg1), getObject(arg2)); return addHeapObject(ret); }; - imports.wbg.__wbg_isSafeInteger_c38b0a16d0c7cef7 = function(arg0) { + imports.wbg.__wbg_isSafeInteger_f93fde0dca9820f8 = function(arg0) { const ret = Number.isSafeInteger(getObject(arg0)); return ret; }; - imports.wbg.__wbg_new0_ad75dd38f92424e2 = function() { + imports.wbg.__wbg_new0_622c21a64f3d83ea = function() { const ret = new Date(); return addHeapObject(ret); }; - imports.wbg.__wbg_now_4579335d3581594c = function() { + imports.wbg.__wbg_now_096aa89623f72d50 = function() { const ret = Date.now(); return ret; }; - imports.wbg.__wbg_toISOString_a6b87a1eaae248de = function(arg0) { + imports.wbg.__wbg_toISOString_0f6525214134a4b6 = function(arg0) { const ret = getObject(arg0).toISOString(); return addHeapObject(ret); }; - imports.wbg.__wbg_entries_6d727b73ee02b7ce = function(arg0) { + imports.wbg.__wbg_entries_9e2e2aa45aa5094a = function(arg0) { const ret = Object.entries(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_is_c74aa9bb973d6109 = function(arg0, arg1) { + imports.wbg.__wbg_is_ff7acd231c75c0e4 = function(arg0, arg1) { const ret = Object.is(getObject(arg0), getObject(arg1)); return ret; }; - imports.wbg.__wbg_resolve_a3252b2860f0a09e = function(arg0) { + imports.wbg.__wbg_resolve_6e1c6553a82f85b7 = function(arg0) { const ret = Promise.resolve(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_then_89e1c559530b85cf = function(arg0, arg1) { + imports.wbg.__wbg_then_3ab08cd4fbb91ae9 = function(arg0, arg1) { const ret = getObject(arg0).then(getObject(arg1)); return addHeapObject(ret); }; - imports.wbg.__wbg_then_1bbc9edafd859b06 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_then_8371cc12cfedc5a2 = function(arg0, arg1, arg2) { const ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); return addHeapObject(ret); }; - imports.wbg.__wbg_buffer_344d9b41efe96da7 = function(arg0) { + imports.wbg.__wbg_buffer_a448f833075b71ba = function(arg0) { const ret = getObject(arg0).buffer; return addHeapObject(ret); }; - imports.wbg.__wbg_newwithbyteoffsetandlength_2dc04d99088b15e3 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_newwithbyteoffsetandlength_d0482f893617af71 = function(arg0, arg1, arg2) { const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); return addHeapObject(ret); }; - imports.wbg.__wbg_new_d8a000788389a31e = function(arg0) { + imports.wbg.__wbg_new_8f67e318f15d7254 = function(arg0) { const ret = new Uint8Array(getObject(arg0)); return addHeapObject(ret); }; - imports.wbg.__wbg_set_dcfd613a3420f908 = function(arg0, arg1, arg2) { + imports.wbg.__wbg_set_2357bf09366ee480 = function(arg0, arg1, arg2) { getObject(arg0).set(getObject(arg1), arg2 >>> 0); }; - imports.wbg.__wbg_length_a5587d6cd79ab197 = function(arg0) { + imports.wbg.__wbg_length_1d25fa9e4ac21ce7 = function(arg0) { const ret = getObject(arg0).length; return ret; }; - imports.wbg.__wbg_instanceof_Uint8Array_19e6f142a5e7e1e1 = function(arg0) { + imports.wbg.__wbg_instanceof_Uint8Array_bced6f43aed8c1aa = function(arg0) { let result; try { result = getObject(arg0) instanceof Uint8Array; @@ -1113,11 +1113,11 @@ function __wbg_get_imports() { const ret = result; return ret; }; - imports.wbg.__wbg_set_40f7786a25a9cc7e = function() { return handleError(function (arg0, arg1, arg2) { + imports.wbg.__wbg_set_759f75cd92b612d2 = function() { return handleError(function (arg0, arg1, arg2) { const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); return ret; }, arguments) }; - imports.wbg.__wbg_stringify_4039297315a25b00 = function() { return handleError(function (arg0) { + imports.wbg.__wbg_stringify_e1b19966d964d242 = function() { return handleError(function (arg0) { const ret = JSON.stringify(getObject(arg0)); return addHeapObject(ret); }, arguments) }; @@ -1141,20 +1141,20 @@ function __wbg_get_imports() { const ret = wasm.memory; return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper1393 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 770, __wbg_adapter_48); + imports.wbg.__wbindgen_closure_wrapper1150 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 572, __wbg_adapter_48); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper3682 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1704, __wbg_adapter_51); + imports.wbg.__wbindgen_closure_wrapper3558 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1660, __wbg_adapter_51); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper3781 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1746, __wbg_adapter_54); + imports.wbg.__wbindgen_closure_wrapper3751 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1707, __wbg_adapter_54); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper3863 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1777, __wbg_adapter_57); + imports.wbg.__wbindgen_closure_wrapper3835 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1738, __wbg_adapter_57); return addHeapObject(ret); }; diff --git a/server/web_ui/pkg/kanidmd_web_ui_user.js.br b/server/web_ui/pkg/kanidmd_web_ui_user.js.br index b5d6845bc..41a9ce07c 100644 Binary files a/server/web_ui/pkg/kanidmd_web_ui_user.js.br and b/server/web_ui/pkg/kanidmd_web_ui_user.js.br differ diff --git a/server/web_ui/pkg/kanidmd_web_ui_user_bg.wasm b/server/web_ui/pkg/kanidmd_web_ui_user_bg.wasm index 574c85615..412fc0841 100644 Binary files a/server/web_ui/pkg/kanidmd_web_ui_user_bg.wasm and b/server/web_ui/pkg/kanidmd_web_ui_user_bg.wasm differ diff --git a/server/web_ui/pkg/kanidmd_web_ui_user_bg.wasm.br b/server/web_ui/pkg/kanidmd_web_ui_user_bg.wasm.br index 280b8bb1f..caaa5d848 100644 Binary files a/server/web_ui/pkg/kanidmd_web_ui_user_bg.wasm.br and b/server/web_ui/pkg/kanidmd_web_ui_user_bg.wasm.br differ diff --git a/server/web_ui/user/src/credential/passkey.rs b/server/web_ui/user/src/credential/passkey.rs index 70f52f3f1..1f1c65f97 100644 --- a/server/web_ui/user/src/credential/passkey.rs +++ b/server/web_ui/user/src/credential/passkey.rs @@ -8,7 +8,7 @@ use wasm_bindgen::UnwrapThrowExt; use wasm_bindgen_futures::JsFuture; use yew::prelude::*; -use super::reset::{EventBusMsg, ModalProps}; +use super::reset::{EventBusMsg, PasskeyClass, PasskeyModalProps}; use kanidmd_web_ui_shared::{do_request, utils, RequestMethod}; pub struct PasskeyModalApp { @@ -87,7 +87,9 @@ impl PasskeyModalApp { emsg: "Invalid Passkey reg state response".to_string(), kopid, }, - CURegState::Passkey(challenge) => Msg::ChallengeReady(challenge), + CURegState::AttestedPasskey(challenge) | CURegState::Passkey(challenge) => { + Msg::ChallengeReady(challenge) + } CURegState::None => Msg::Success, }) } else { @@ -99,7 +101,7 @@ impl PasskeyModalApp { impl Component for PasskeyModalApp { type Message = Msg; - type Properties = ModalProps; + type Properties = PasskeyModalProps; fn create(_ctx: &Context) -> Self { console::debug!("passkey modal create"); @@ -128,14 +130,13 @@ impl Component for PasskeyModalApp { // Init a fetch to get the challenge. let token_c = ctx.props().token.clone(); + let req = match &ctx.props().class { + PasskeyClass::Any => CURequest::PasskeyFinish(label, rpkc), + PasskeyClass::Attested => CURequest::AttestedPasskeyFinish(label, rpkc), + }; + ctx.link().send_future(async { - match Self::submit_passkey_update( - token_c, - CURequest::PasskeyFinish(label, rpkc), - cb, - ) - .await - { + match Self::submit_passkey_update(token_c, req, cb).await { Ok(v) => v, Err(v) => v.into(), } @@ -152,8 +153,13 @@ impl Component for PasskeyModalApp { // Init a fetch to get the challenge. let token_c = ctx.props().token.clone(); + let req = match &ctx.props().class { + PasskeyClass::Any => CURequest::PasskeyInit, + PasskeyClass::Attested => CURequest::AttestedPasskeyInit, + }; + ctx.link().send_future(async { - match Self::submit_passkey_update(token_c, CURequest::PasskeyInit, cb).await { + match Self::submit_passkey_update(token_c, req, cb).await { Ok(v) => v, Err(v) => v.into(), } @@ -175,6 +181,9 @@ impl Component for PasskeyModalApp { .navigator() .credentials() .create_with_options(&c_options) + .map_err(|e| { + console::error!(format!("error -> {:?}", e).as_str()); + }) .expect_throw("Unable to create promise"); let fut = JsFuture::from(promise); @@ -248,16 +257,39 @@ impl Component for PasskeyModalApp { } } State::ChallengeReady(_challenge) => { + let allowed_devices = ctx.props().allowed_devices.clone(); // This works around a bug in safari :( html! { - + + } } State::CredentialReady(_) => { diff --git a/server/web_ui/user/src/credential/passkeyremove.rs b/server/web_ui/user/src/credential/passkeyremove.rs index 01c687fd5..d486c64ec 100644 --- a/server/web_ui/user/src/credential/passkeyremove.rs +++ b/server/web_ui/user/src/credential/passkeyremove.rs @@ -6,7 +6,7 @@ use uuid::Uuid; use wasm_bindgen::UnwrapThrowExt; use yew::prelude::*; -use super::reset::{EventBusMsg, PasskeyRemoveModalProps}; +use super::reset::{EventBusMsg, PasskeyClass, PasskeyRemoveModalProps}; use kanidmd_web_ui_shared::{do_request, error::FetchError, utils, RequestMethod}; pub struct PasskeyRemoveModalApp { @@ -91,6 +91,7 @@ impl PasskeyRemoveModalApp { | CURegState::TotpTryAgain | CURegState::TotpInvalidSha1 | CURegState::Passkey(_) + | CURegState::AttestedPasskey(_) | CURegState::BackupCodes(_) => Msg::Error { emsg: "Invalid Passkey reg state response".to_string(), kopid, @@ -140,12 +141,16 @@ impl Component for PasskeyRemoveModalApp { // Do the call back. let token_c = ctx.props().token.clone(); + let class = &ctx.props().class; let uuid = self.uuid; + let request = match class { + PasskeyClass::Any => CURequest::PasskeyRemove(uuid), + PasskeyClass::Attested => CURequest::AttestedPasskeyRemove(uuid), + }; + ctx.link().send_future(async move { - match Self::submit_passkey_update(token_c, CURequest::PasskeyRemove(uuid), cb) - .await - { + match Self::submit_passkey_update(token_c, request, cb).await { Ok(v) => v, Err(v) => v.into(), } diff --git a/server/web_ui/user/src/credential/reset.rs b/server/web_ui/user/src/credential/reset.rs index 5f3a3a9b7..31aaffaea 100644 --- a/server/web_ui/user/src/credential/reset.rs +++ b/server/web_ui/user/src/credential/reset.rs @@ -44,9 +44,24 @@ pub struct TotpRemoveProps { pub cb: Callback, } +#[derive(PartialEq)] +pub enum PasskeyClass { + Any, + Attested, +} + +#[derive(PartialEq, Properties)] +pub struct PasskeyModalProps { + pub token: CUSessionToken, + pub class: PasskeyClass, + pub allowed_devices: Option>, + pub cb: Callback, +} + #[derive(PartialEq, Properties)] pub struct PasskeyRemoveModalProps { pub token: CUSessionToken, + pub class: PasskeyClass, pub tag: String, pub uuid: Uuid, pub cb: Callback, @@ -356,6 +371,9 @@ impl CredentialResetApp { primary_state, passkeys, passkeys_state, + attested_passkeys, + attested_passkeys_state, + attested_passkeys_allowed_devices, } = status; let displayname = displayname.clone(); @@ -382,6 +400,12 @@ impl CredentialResetApp { let pw_html = self.view_primary(token, primary, *primary_state); let passkey_html = self.view_passkeys(token, passkeys, *passkeys_state); + let attested_passkey_html = self.view_attested_passkeys( + token, + attested_passkeys, + *attested_passkeys_state, + attested_passkeys_allowed_devices.as_slice(), + ); let warnings_html = if warnings.is_empty() { html! { <> } @@ -403,6 +427,22 @@ impl CredentialResetApp {

{ "Passkeys are required for your account." }

}, + CURegWarning::AttestedPasskeyRequired => html! { + + }, + CURegWarning::AttestedResidentKeyRequired => html! { + + }, + CURegWarning::WebauthnAttestationUnsatisfiable => html! { + + }, CURegWarning::Unsatisfiable => html! {