smart_account_auth/
credential.rs

1use saa_schema::{saa_derivable, saa_type};
2use saa_common::{Binary, String, CredentialId};
3
4pub use saa_auth::caller::Caller;
5#[cfg(feature = "ethereum")]
6pub use saa_auth::eth::EthPersonalSign;
7#[cfg(feature = "cosmos")]
8pub use saa_auth::cosmos::CosmosArbitrary;
9#[cfg(feature = "passkeys")]
10pub use saa_auth::passkey::PasskeyCredential;
11#[cfg(feature = "ed25519")]
12pub use saa_curves::ed25519::Ed25519;
13#[cfg(feature = "curves")]
14pub use saa_curves::{secp256k1::Secp256k1, secp256r1::Secp256r1};
15
16
17
18#[saa_derivable(name(CredentialName))]
19pub enum Credential {
20    Native(Caller),
21
22    #[cfg(feature = "ethereum")]
23    EthPersonalSign(EthPersonalSign),
24
25    #[cfg(feature = "cosmos")]
26    CosmosArbitrary(CosmosArbitrary),
27
28    #[cfg(feature = "passkeys")]
29    Passkey(PasskeyCredential),
30
31    #[cfg(feature = "ed25519")]
32    Ed25519(Ed25519),
33
34    #[cfg(feature = "curves")]
35    Secp256k1(Secp256k1),
36
37    #[cfg(feature = "curves")]
38    Secp256r1(Secp256r1),
39}
40
41
42
43
44
45
46#[saa_type]
47pub struct CredentialInfo {
48    /// name of the used credential
49    pub name: CredentialName,
50    /// human readable prefix to encode from a public key
51    pub hrp: Option<String>,
52    /// extension data
53    pub extension: Option<Binary>,
54}
55
56
57
58pub type CredentialRecord = (CredentialId, CredentialInfo);
59
60
61
62#[allow(unused, dead_code)]
63#[cfg(feature = "wasm")]
64pub fn build_credential(
65    record      : CredentialRecord,
66    msg         : crate::msgs::SignedDataMsg,
67    extension   : Option<Binary>,
68) -> Result<Credential, saa_common::AuthError> {
69    let (id, info) = record;
70    let message = msg.data;
71    let signature = msg.signature;
72    let name = info.name;
73    
74    let credential = match name {
75
76        CredentialName::Native => Credential::Native(Caller(id)),
77
78        #[cfg(feature = "ethereum")]
79        CredentialName::EthPersonalSign => Credential::EthPersonalSign(EthPersonalSign {
80                message,
81                signature,
82                signer: id,
83            }
84        ),
85
86        #[cfg(feature = "cosmos")]
87        CredentialName::CosmosArbitrary => Credential::CosmosArbitrary(CosmosArbitrary {
88            pubkey: Binary::from_base64(&id)?,
89            message,
90            signature,
91            hrp: info.hrp,
92        }),
93
94        #[cfg(feature = "passkeys")]
95        CredentialName::Passkey => {
96            use saa_auth::passkey::{
97                ClientData, PasskeyInfo, PasskeyPayload, utils::base64_to_url
98            };
99
100            let stored_info  = info.extension
101                .map(|e| saa_common::from_json::<PasskeyInfo>(e).ok() )
102                .flatten()
103                .ok_or_else(|| saa_common::AuthError::generic("Missing passkey info"))?;
104            
105            let (origin, other_keys) = match extension
106                .map(|e| saa_common::from_json::<PasskeyPayload>(e).ok())
107                .flatten()
108            {
109                Some(payload) => (payload.origin, payload.other_keys),
110                None => (None, None),
111            };
112            
113            let client_data = ClientData::new(
114                "webauthn.get",
115                base64_to_url(message.to_base64().as_str()),
116                origin.unwrap_or(stored_info.origin),
117                stored_info.cross_origin,
118                other_keys
119            );
120
121            Credential::Passkey(PasskeyCredential {
122                id,
123                signature,
124                client_data,
125                pubkey: Some(stored_info.pubkey),
126                authenticator_data: stored_info.authenticator_data,
127                user_handle: stored_info.user_handle,
128            })
129        },
130        #[cfg(feature = "ed25519")]
131        CredentialName::Ed25519 => Credential::Ed25519(Ed25519 {
132            pubkey: Binary::from_base64(&id)?,
133            signature,
134            message,
135        }),
136        #[cfg(feature = "curves")]
137        curves => {
138            let pubkey = Binary::from_base64(&id)?;
139            match curves {
140                CredentialName::Secp256k1 => Credential::Secp256k1(Secp256k1 {
141                    pubkey,
142                    signature,
143                    message,
144                    hrp: info.hrp,
145                }),
146                _ => return Err(saa_common::AuthError::generic("Unsupported curve")),
147            }
148        }
149    };
150    Ok(credential)
151}