1use hashbrown::HashSet;
2use kanidm_proto::internal::ImageType;
3use serde::{Deserialize, Serialize};
4use serde_with::skip_serializing_none;
5use std::collections::{BTreeMap, BTreeSet};
6use std::fmt;
7use std::time::Duration;
8use url::Url;
9use uuid::Uuid;
10use webauthn_rs::prelude::{
11    AttestationCaList, AttestedPasskey as AttestedPasskeyV4, Passkey as PasskeyV4,
12    SecurityKey as SecurityKeyV4,
13};
14use webauthn_rs_core::proto::{COSEKey, UserVerificationPolicy};
15use crate::repl::cid::Cid;
17use crypto_glue::traits::Zeroizing;
18pub use kanidm_lib_crypto::DbPasswordV1;
19
20#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, PartialEq, Eq, Clone)]
21pub struct DbCidV1 {
22    #[serde(rename = "t")]
23    pub timestamp: Duration,
24    #[serde(rename = "s")]
25    pub server_id: Uuid,
26}
27
28impl From<Cid> for DbCidV1 {
29    fn from(Cid { s_uuid, ts }: Cid) -> Self {
30        DbCidV1 {
31            timestamp: ts,
32            server_id: s_uuid,
33        }
34    }
35}
36
37impl From<&Cid> for DbCidV1 {
38    fn from(&Cid { s_uuid, ts }: &Cid) -> Self {
39        DbCidV1 {
40            timestamp: ts,
41            server_id: s_uuid,
42        }
43    }
44}
45
46impl fmt::Display for DbCidV1 {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        write!(f, "{:032}-{}", self.timestamp.as_nanos(), self.server_id)
49    }
50}
51
52#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
53pub enum DbValueIntentTokenStateV1 {
54    #[serde(rename = "v")]
55    Valid {
56        max_ttl: Duration,
57        #[serde(default)]
58        ext_cred_portal_can_view: bool,
59        #[serde(default)]
60        primary_can_edit: bool,
61        #[serde(default)]
62        passkeys_can_edit: bool,
63        #[serde(default)]
64        attested_passkeys_can_edit: bool,
65        #[serde(default)]
66        unixcred_can_edit: bool,
67        #[serde(default)]
68        sshpubkey_can_edit: bool,
69    },
70    #[serde(rename = "p")]
71    InProgress {
72        max_ttl: Duration,
73        session_id: Uuid,
74        session_ttl: Duration,
75        #[serde(default)]
76        ext_cred_portal_can_view: bool,
77        #[serde(default)]
78        primary_can_edit: bool,
79        #[serde(default)]
80        passkeys_can_edit: bool,
81        #[serde(default)]
82        attested_passkeys_can_edit: bool,
83        #[serde(default)]
84        unixcred_can_edit: bool,
85        #[serde(default)]
86        sshpubkey_can_edit: bool,
87    },
88    #[serde(rename = "c")]
89    Consumed { max_ttl: Duration },
90}
91
92#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
93pub enum DbTotpAlgoV1 {
94    S1,
95    S256,
96    S512,
97}
98
99#[derive(Serialize, Deserialize, PartialEq, Eq)]
100pub struct DbTotpV1 {
101    #[serde(rename = "l")]
102    pub label: String,
103    #[serde(rename = "k")]
104    pub key: Vec<u8>,
105    #[serde(rename = "s")]
106    pub step: u64,
107    #[serde(rename = "a")]
108    pub algo: DbTotpAlgoV1,
109    #[serde(rename = "d", default)]
110    pub digits: Option<u8>,
111}
112
113impl std::fmt::Debug for DbTotpV1 {
114    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
115        f.debug_struct("DbTotpV1")
116            .field("label", &self.label)
117            .field("step", &self.step)
118            .field("algo", &self.algo)
119            .finish()
120    }
121}
122
123#[derive(Serialize, Deserialize, Debug)]
124pub struct DbWebauthnV1 {
125    #[serde(rename = "l")]
126    pub label: String,
127    #[serde(rename = "i")]
128    pub id: Vec<u8>,
129    #[serde(rename = "c")]
130    pub cred: COSEKey,
131    #[serde(rename = "t")]
132    pub counter: u32,
133    #[serde(rename = "v")]
134    pub verified: bool,
135    #[serde(rename = "p", default)]
136    pub registration_policy: UserVerificationPolicy,
137}
138
139#[derive(Serialize, Deserialize, PartialEq, Eq)]
140pub struct DbBackupCodeV1 {
141    pub code_set: HashSet<String>, }
143
144impl std::fmt::Debug for DbBackupCodeV1 {
145    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
146        write!(f, "codes remaining: {}", self.code_set.len())
147    }
148}
149
150#[skip_serializing_none]
157#[derive(Serialize, Deserialize, Debug)]
158#[serde(tag = "type_")]
159pub enum DbCred {
160    Pw {
162        password: Option<DbPasswordV1>,
163        webauthn: Option<Vec<DbWebauthnV1>>,
164        totp: Option<DbTotpV1>,
165        backup_code: Option<DbBackupCodeV1>,
166        claims: Vec<String>,
167        uuid: Uuid,
168    },
169    GPw {
170        password: Option<DbPasswordV1>,
171        webauthn: Option<Vec<DbWebauthnV1>>,
172        totp: Option<DbTotpV1>,
173        backup_code: Option<DbBackupCodeV1>,
174        claims: Vec<String>,
175        uuid: Uuid,
176    },
177    PwMfa {
178        password: Option<DbPasswordV1>,
179        webauthn: Option<Vec<DbWebauthnV1>>,
180        totp: Option<DbTotpV1>,
181        backup_code: Option<DbBackupCodeV1>,
182        claims: Vec<String>,
183        uuid: Uuid,
184    },
185    Wn {
186        password: Option<DbPasswordV1>,
187        webauthn: Option<Vec<DbWebauthnV1>>,
188        totp: Option<DbTotpV1>,
189        backup_code: Option<DbBackupCodeV1>,
190        claims: Vec<String>,
191        uuid: Uuid,
192    },
193
194    TmpWn {
195        webauthn: Vec<(String, PasskeyV4)>,
196        uuid: Uuid,
197    },
198
199    #[serde(rename = "V2PwMfa")]
200    V2PasswordMfa {
201        password: DbPasswordV1,
202        totp: Option<DbTotpV1>,
203        backup_code: Option<DbBackupCodeV1>,
204        webauthn: Vec<(String, SecurityKeyV4)>,
205        uuid: Uuid,
206    },
207
208    #[serde(rename = "V2Pw")]
210    V2Password { password: DbPasswordV1, uuid: Uuid },
211    #[serde(rename = "V2GPw")]
212    V2GenPassword { password: DbPasswordV1, uuid: Uuid },
213    #[serde(rename = "V3PwMfa")]
214    V3PasswordMfa {
215        password: DbPasswordV1,
216        totp: Vec<(String, DbTotpV1)>,
217        backup_code: Option<DbBackupCodeV1>,
218        webauthn: Vec<(String, SecurityKeyV4)>,
219        uuid: Uuid,
220    },
221}
222
223impl DbCred {
224    fn uuid(&self) -> Uuid {
225        match self {
226            DbCred::Pw { uuid, .. }
227            | DbCred::GPw { uuid, .. }
228            | DbCred::PwMfa { uuid, .. }
229            | DbCred::Wn { uuid, .. }
230            | DbCred::TmpWn { uuid, .. }
231            | DbCred::V2PasswordMfa { uuid, .. }
232            | DbCred::V2Password { uuid, .. }
233            | DbCred::V2GenPassword { uuid, .. }
234            | DbCred::V3PasswordMfa { uuid, .. } => *uuid,
235        }
236    }
237}
238
239impl Eq for DbCred {}
240
241impl PartialEq for DbCred {
242    fn eq(&self, other: &Self) -> bool {
243        self.uuid() == other.uuid()
244    }
245}
246
247impl fmt::Display for DbCred {
248    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249        match self {
250            DbCred::Pw {
251                password,
252                webauthn,
253                totp,
254                backup_code,
255                claims,
256                uuid,
257            } => write!(
258                f,
259                "Pw (p {}, w {}, t {}, b {}, c {}, u {})",
260                password.is_some(),
261                webauthn.is_some(),
262                totp.is_some(),
263                backup_code.is_some(),
264                claims.len(),
265                uuid
266            ),
267            DbCred::GPw {
268                password,
269                webauthn,
270                totp,
271                backup_code,
272                claims,
273                uuid,
274            } => write!(
275                f,
276                "GPw (p {}, w {}, t {}, b {}, c {}, u {})",
277                password.is_some(),
278                webauthn.is_some(),
279                totp.is_some(),
280                backup_code.is_some(),
281                claims.len(),
282                uuid
283            ),
284            DbCred::PwMfa {
285                password,
286                webauthn,
287                totp,
288                backup_code,
289                claims,
290                uuid,
291            } => write!(
292                f,
293                "PwMfa (p {}, w {}, t {}, b {}, c {}, u {})",
294                password.is_some(),
295                webauthn.is_some(),
296                totp.is_some(),
297                backup_code.is_some(),
298                claims.len(),
299                uuid
300            ),
301            DbCred::Wn {
302                password,
303                webauthn,
304                totp,
305                backup_code,
306                claims,
307                uuid,
308            } => write!(
309                f,
310                "Wn (p {}, w {}, t {}, b {}, c {}, u {})",
311                password.is_some(),
312                webauthn.is_some(),
313                totp.is_some(),
314                backup_code.is_some(),
315                claims.len(),
316                uuid
317            ),
318            DbCred::TmpWn { webauthn, uuid } => {
319                write!(f, "TmpWn ( w {}, u {} )", webauthn.len(), uuid)
320            }
321            DbCred::V2Password { password: _, uuid } => write!(f, "V2Pw ( u {uuid} )"),
322            DbCred::V2GenPassword { password: _, uuid } => write!(f, "V2GPw ( u {uuid} )"),
323            DbCred::V2PasswordMfa {
324                password: _,
325                totp,
326                backup_code,
327                webauthn,
328                uuid,
329            } => write!(
330                f,
331                "V2PwMfa (p true, w {}, t {}, b {}, u {})",
332                webauthn.len(),
333                totp.is_some(),
334                backup_code.is_some(),
335                uuid
336            ),
337            DbCred::V3PasswordMfa {
338                password: _,
339                totp,
340                backup_code,
341                webauthn,
342                uuid,
343            } => write!(
344                f,
345                "V3PwMfa (p true, w {}, t {}, b {}, u {})",
346                webauthn.len(),
347                totp.len(),
348                backup_code.is_some(),
349                uuid
350            ),
351        }
352    }
353}
354
355#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
356pub struct DbValueCredV1 {
357    #[serde(rename = "t")]
358    pub tag: String,
359    #[serde(rename = "d")]
360    pub data: DbCred,
361}
362
363#[derive(Serialize, Deserialize, Debug)]
364pub enum DbValuePasskeyV1 {
365    V4 { u: Uuid, t: String, k: PasskeyV4 },
366}
367
368impl Eq for DbValuePasskeyV1 {}
369
370impl PartialEq for DbValuePasskeyV1 {
371    fn eq(&self, other: &Self) -> bool {
372        match (self, other) {
373            (
374                DbValuePasskeyV1::V4 {
375                    u: self_uuid,
376                    k: self_key,
377                    t: _,
378                },
379                DbValuePasskeyV1::V4 {
380                    u: other_uuid,
381                    k: other_key,
382                    t: _,
383                },
384            ) => self_uuid == other_uuid && self_key.cred_id() == other_key.cred_id(),
385        }
386    }
387}
388
389#[derive(Serialize, Deserialize, Debug)]
390pub enum DbValueAttestedPasskeyV1 {
391    V4 {
392        u: Uuid,
393        t: String,
394        k: AttestedPasskeyV4,
395    },
396}
397
398impl Eq for DbValueAttestedPasskeyV1 {}
399
400impl PartialEq for DbValueAttestedPasskeyV1 {
401    fn eq(&self, other: &Self) -> bool {
402        match (self, other) {
403            (
404                DbValueAttestedPasskeyV1::V4 {
405                    u: self_uuid,
406                    k: self_key,
407                    t: _,
408                },
409                DbValueAttestedPasskeyV1::V4 {
410                    u: other_uuid,
411                    k: other_key,
412                    t: _,
413                },
414            ) => self_uuid == other_uuid && self_key.cred_id() == other_key.cred_id(),
415        }
416    }
417}
418
419#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
420pub struct DbValueTaggedStringV1 {
421    #[serde(rename = "t")]
422    pub tag: String,
423    #[serde(rename = "d")]
424    pub data: String,
425}
426
427#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
428pub struct DbValueAddressV1 {
429    #[serde(rename = "f")]
430    pub formatted: String,
431    #[serde(rename = "s")]
432    pub street_address: String,
433    #[serde(rename = "l")]
434    pub locality: String,
435    #[serde(rename = "r")]
436    pub region: String,
437    #[serde(rename = "p")]
438    pub postal_code: String,
439    #[serde(rename = "c")]
440    pub country: String,
441}
442
443#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
444pub enum DbValueOauthClaimMapJoinV1 {
445    #[serde(rename = "c")]
446    CommaSeparatedValue,
447    #[serde(rename = "s")]
448    SpaceSeparatedValue,
449    #[serde(rename = "a")]
450    JsonArray,
451}
452
453#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
454pub enum DbValueOauthClaimMap {
455    V1 {
456        #[serde(rename = "n")]
457        name: String,
458        #[serde(rename = "j")]
459        join: DbValueOauthClaimMapJoinV1,
460        #[serde(rename = "d")]
461        values: BTreeMap<Uuid, BTreeSet<String>>,
462    },
463}
464
465#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
466pub struct DbValueOauthScopeMapV1 {
467    #[serde(rename = "u")]
468    pub refer: Uuid,
469    #[serde(rename = "m")]
470    pub data: Vec<String>,
471}
472
473#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
474pub enum DbValueAccessScopeV1 {
475    #[serde(rename = "i")]
476    IdentityOnly,
477    #[serde(rename = "r")]
478    #[default]
479    ReadOnly,
480    #[serde(rename = "w")]
481    ReadWrite,
482    #[serde(rename = "p")]
483    PrivilegeCapable,
484    #[serde(rename = "s")]
485    Synchronise,
486}
487
488#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
489#[allow(clippy::enum_variant_names)]
490pub enum DbValueIdentityId {
491    #[serde(rename = "v1i")]
492    V1Internal,
493    #[serde(rename = "v1u")]
494    V1Uuid(Uuid),
495    #[serde(rename = "v1s")]
496    V1Sync(Uuid),
497}
498
499#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
500pub enum DbValueSessionStateV1 {
501    #[serde(rename = "ea")]
502    ExpiresAt(String),
503    #[serde(rename = "nv")]
504    Never,
505    #[serde(rename = "ra")]
506    RevokedAt(DbCidV1),
507}
508
509#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
510pub enum DbValueAuthTypeV1 {
511    #[serde(rename = "an")]
512    Anonymous,
513    #[serde(rename = "po")]
514    Password,
515    #[serde(rename = "pg")]
516    GeneratedPassword,
517    #[serde(rename = "pt")]
518    PasswordTotp,
519    #[serde(rename = "pb")]
520    PasswordBackupCode,
521    #[serde(rename = "ps")]
522    PasswordSecurityKey,
523    #[serde(rename = "as")]
524    Passkey,
525    #[serde(rename = "ap")]
526    AttestedPasskey,
527}
528
529#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
530pub enum DbValueSession {
531    V1 {
532        #[serde(rename = "u")]
533        refer: Uuid,
534        #[serde(rename = "l")]
535        label: String,
536        #[serde(rename = "e")]
537        expiry: Option<String>,
538        #[serde(rename = "i")]
539        issued_at: String,
540        #[serde(rename = "b")]
541        issued_by: DbValueIdentityId,
542        #[serde(rename = "s", default)]
543        scope: DbValueAccessScopeV1,
544    },
545    V2 {
546        #[serde(rename = "u")]
547        refer: Uuid,
548        #[serde(rename = "l")]
549        label: String,
550        #[serde(rename = "e")]
551        expiry: Option<String>,
552        #[serde(rename = "i")]
553        issued_at: String,
554        #[serde(rename = "b")]
555        issued_by: DbValueIdentityId,
556        #[serde(rename = "c")]
557        cred_id: Uuid,
558        #[serde(rename = "s", default)]
559        scope: DbValueAccessScopeV1,
560    },
561    V3 {
562        #[serde(rename = "u")]
563        refer: Uuid,
564        #[serde(rename = "l")]
565        label: String,
566        #[serde(rename = "e")]
567        state: DbValueSessionStateV1,
568        #[serde(rename = "i")]
569        issued_at: String,
570        #[serde(rename = "b")]
571        issued_by: DbValueIdentityId,
572        #[serde(rename = "c")]
573        cred_id: Uuid,
574        #[serde(rename = "s", default)]
575        scope: DbValueAccessScopeV1,
576    },
577    V4 {
578        #[serde(rename = "u")]
579        refer: Uuid,
580        #[serde(rename = "l")]
581        label: String,
582        #[serde(rename = "e")]
583        state: DbValueSessionStateV1,
584        #[serde(rename = "i")]
585        issued_at: String,
586        #[serde(rename = "b")]
587        issued_by: DbValueIdentityId,
588        #[serde(rename = "c")]
589        cred_id: Uuid,
590        #[serde(rename = "s", default)]
591        scope: DbValueAccessScopeV1,
592        #[serde(rename = "t")]
593        type_: DbValueAuthTypeV1,
594    },
595}
596
597#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
598pub enum DbValueApiTokenScopeV1 {
599    #[serde(rename = "r")]
600    #[default]
601    ReadOnly,
602    #[serde(rename = "w")]
603    ReadWrite,
604    #[serde(rename = "s")]
605    Synchronise,
606}
607
608#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
609pub enum DbValueApiToken {
610    V1 {
611        #[serde(rename = "u")]
612        refer: Uuid,
613        #[serde(rename = "l")]
614        label: String,
615        #[serde(rename = "e")]
616        expiry: Option<String>,
617        #[serde(rename = "i")]
618        issued_at: String,
619        #[serde(rename = "b")]
620        issued_by: DbValueIdentityId,
621        #[serde(rename = "s", default)]
622        scope: DbValueApiTokenScopeV1,
623    },
624}
625
626#[skip_serializing_none]
627#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
628pub enum DbValueOauth2Session {
629    V1 {
630        #[serde(rename = "u")]
631        refer: Uuid,
632        #[serde(rename = "p")]
633        parent: Uuid,
634        #[serde(rename = "e")]
635        expiry: Option<String>,
636        #[serde(rename = "i")]
637        issued_at: String,
638        #[serde(rename = "r")]
639        rs_uuid: Uuid,
640    },
641    V2 {
642        #[serde(rename = "u")]
643        refer: Uuid,
644        #[serde(rename = "p")]
645        parent: Uuid,
646        #[serde(rename = "e")]
647        state: DbValueSessionStateV1,
648        #[serde(rename = "i")]
649        issued_at: String,
650        #[serde(rename = "r")]
651        rs_uuid: Uuid,
652    },
653    V3 {
654        #[serde(rename = "u")]
655        refer: Uuid,
656        #[serde(rename = "p")]
657        parent: Option<Uuid>,
658        #[serde(rename = "e")]
659        state: DbValueSessionStateV1,
660        #[serde(rename = "i")]
661        issued_at: String,
662        #[serde(rename = "r")]
663        rs_uuid: Uuid,
664    },
665}
666
667#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
669pub enum DbValueImage {
670    V1 {
671        filename: String,
672        filetype: ImageType,
673        contents: Vec<u8>,
674    },
675}
676
677#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
678pub enum DbValueKeyUsage {
679    JwsEs256,
680    JwsHs256,
681    JwsRs256,
682    JweA128GCM,
683}
684
685#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
686pub enum DbValueKeyStatus {
687    Valid,
688    Retained,
689    Revoked,
690}
691
692#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
693pub enum DbValueKeyInternal {
694    V1 {
695        id: String,
696        usage: DbValueKeyUsage,
697        valid_from: u64,
698        status: DbValueKeyStatus,
699        status_cid: DbCidV1,
700        der: Zeroizing<Vec<u8>>,
701    },
702}
703
704#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
705pub enum DbValueCertificate {
706    V1 { certificate_der: Vec<u8> },
707}
708
709#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
710pub enum DbValueApplicationPassword {
711    V1 {
712        #[serde(rename = "u")]
713        refer: Uuid,
714        #[serde(rename = "a")]
715        application_refer: Uuid,
716        #[serde(rename = "l")]
717        label: String,
718        #[serde(rename = "p")]
719        password: DbPasswordV1,
720    },
721}
722
723#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
724pub enum DbValueSetV2 {
725    #[serde(rename = "U8")]
726    Utf8(Vec<String>),
727    #[serde(rename = "I8")]
728    Iutf8(Vec<String>),
729    #[serde(rename = "N8")]
730    Iname(Vec<String>),
731    #[serde(rename = "UU")]
732    Uuid(Vec<Uuid>),
733    #[serde(rename = "BO")]
734    Bool(Vec<bool>),
735    #[serde(rename = "SY")]
736    SyntaxType(Vec<u16>),
737    #[serde(rename = "IN")]
738    IndexType(Vec<u16>),
739    #[serde(rename = "RF")]
740    Reference(Vec<Uuid>),
741    #[serde(rename = "JF")]
742    JsonFilter(Vec<String>),
743    #[serde(rename = "CR")]
744    Credential(Vec<DbValueCredV1>),
745    #[serde(rename = "RU")]
746    SecretValue(Vec<String>),
747    #[serde(rename = "SK")]
748    SshKey(Vec<DbValueTaggedStringV1>),
749    #[serde(rename = "SP")]
750    Spn(Vec<(String, String)>),
751    #[serde(rename = "UI")]
752    Uint32(Vec<u32>),
753    #[serde(rename = "CI")]
754    Cid(Vec<DbCidV1>),
755    #[serde(rename = "NU")]
756    NsUniqueId(Vec<String>),
757    #[serde(rename = "DT")]
758    DateTime(Vec<String>),
759    #[serde(rename = "EM")]
760    EmailAddress(String, Vec<String>),
761    #[serde(rename = "PN")]
762    PhoneNumber(String, Vec<String>),
763    #[serde(rename = "AD")]
764    Address(Vec<DbValueAddressV1>),
765    #[serde(rename = "UR")]
766    Url(Vec<Url>),
767    #[serde(rename = "OS")]
768    OauthScope(Vec<String>),
769    #[serde(rename = "OM")]
770    OauthScopeMap(Vec<DbValueOauthScopeMapV1>),
771    #[serde(rename = "OC")]
772    OauthClaimMap(Vec<DbValueOauthClaimMap>),
773    #[serde(rename = "E2")]
774    PrivateBinary(Vec<Vec<u8>>),
775    #[serde(rename = "PB")]
776    PublicBinary(Vec<(String, Vec<u8>)>),
777    #[serde(rename = "RS")]
778    RestrictedString(Vec<String>),
779    #[serde(rename = "IT")]
780    IntentToken(Vec<(String, DbValueIntentTokenStateV1)>),
781    #[serde(rename = "PK")]
782    Passkey(Vec<DbValuePasskeyV1>),
783    #[serde(rename = "DK")]
784    AttestedPasskey(Vec<DbValueAttestedPasskeyV1>),
785    #[serde(rename = "TE")]
786    TrustedDeviceEnrollment(Vec<Uuid>),
787    #[serde(rename = "AS")]
788    Session(Vec<DbValueSession>),
789    #[serde(rename = "JE")]
790    JwsKeyEs256(Vec<Zeroizing<Vec<u8>>>),
791    #[serde(rename = "JR")]
792    JwsKeyRs256(Vec<Zeroizing<Vec<u8>>>),
793    #[serde(rename = "OZ")]
794    Oauth2Session(Vec<DbValueOauth2Session>),
795    #[serde(rename = "UH")]
796    UiHint(Vec<u16>),
797    #[serde(rename = "TO")]
798    TotpSecret(Vec<(String, DbTotpV1)>),
799    #[serde(rename = "AT")]
800    ApiToken(Vec<DbValueApiToken>),
801    #[serde(rename = "SA")]
802    AuditLogString(Vec<(Cid, String)>),
803    #[serde(rename = "EK")]
804    EcKeyPrivate(Vec<u8>),
805    #[serde(rename = "IM")]
806    Image(Vec<DbValueImage>),
807    #[serde(rename = "CT")]
808    CredentialType(Vec<u16>),
809    #[serde(rename = "WC")]
810    WebauthnAttestationCaList { ca_list: AttestationCaList },
811    #[serde(rename = "KI")]
812    KeyInternal(Vec<DbValueKeyInternal>),
813    #[serde(rename = "HS")]
814    HexString(Vec<String>),
815    #[serde(rename = "X509")]
816    Certificate(Vec<DbValueCertificate>),
817    #[serde(rename = "AP")]
818    ApplicationPassword(Vec<DbValueApplicationPassword>),
819}
820
821impl DbValueSetV2 {
822    pub fn len(&self) -> usize {
823        match self {
824            DbValueSetV2::Utf8(set)
825            | DbValueSetV2::Iutf8(set)
826            | DbValueSetV2::HexString(set)
827            | DbValueSetV2::Iname(set) => set.len(),
828            DbValueSetV2::Uuid(set) => set.len(),
829            DbValueSetV2::Bool(set) => set.len(),
830            DbValueSetV2::SyntaxType(set) => set.len(),
831            DbValueSetV2::IndexType(set) => set.len(),
832            DbValueSetV2::Reference(set) => set.len(),
833            DbValueSetV2::JsonFilter(set) => set.len(),
834            DbValueSetV2::Credential(set) => set.len(),
835            DbValueSetV2::SecretValue(set) => set.len(),
836            DbValueSetV2::SshKey(set) => set.len(),
837            DbValueSetV2::Spn(set) => set.len(),
838            DbValueSetV2::Uint32(set) => set.len(),
839            DbValueSetV2::Cid(set) => set.len(),
840            DbValueSetV2::NsUniqueId(set) => set.len(),
841            DbValueSetV2::DateTime(set) => set.len(),
842            DbValueSetV2::EmailAddress(_primary, set) => set.len(),
843            DbValueSetV2::PhoneNumber(_primary, set) => set.len(),
844            DbValueSetV2::Address(set) => set.len(),
845            DbValueSetV2::Url(set) => set.len(),
846            DbValueSetV2::OauthClaimMap(set) => set.len(),
847            DbValueSetV2::OauthScope(set) => set.len(),
848            DbValueSetV2::OauthScopeMap(set) => set.len(),
849            DbValueSetV2::PrivateBinary(set) => set.len(),
850            DbValueSetV2::PublicBinary(set) => set.len(),
851            DbValueSetV2::RestrictedString(set) => set.len(),
852            DbValueSetV2::IntentToken(set) => set.len(),
853            DbValueSetV2::Passkey(set) => set.len(),
854            DbValueSetV2::AttestedPasskey(set) => set.len(),
855            DbValueSetV2::TrustedDeviceEnrollment(set) => set.len(),
856            DbValueSetV2::Session(set) => set.len(),
857            DbValueSetV2::ApiToken(set) => set.len(),
858            DbValueSetV2::Oauth2Session(set) => set.len(),
859            DbValueSetV2::JwsKeyEs256(set) => set.len(),
860            DbValueSetV2::JwsKeyRs256(set) => set.len(),
861            DbValueSetV2::UiHint(set) => set.len(),
862            DbValueSetV2::TotpSecret(set) => set.len(),
863            DbValueSetV2::AuditLogString(set) => set.len(),
864            DbValueSetV2::Image(set) => set.len(),
865            DbValueSetV2::EcKeyPrivate(_key) => 1, DbValueSetV2::CredentialType(set) => set.len(),
868            DbValueSetV2::WebauthnAttestationCaList { ca_list } => ca_list.len(),
869            DbValueSetV2::KeyInternal(set) => set.len(),
870            DbValueSetV2::Certificate(set) => set.len(),
871            DbValueSetV2::ApplicationPassword(set) => set.len(),
872        }
873    }
874
875    pub fn is_empty(&self) -> bool {
876        self.len() == 0
877    }
878}
879
880#[cfg(test)]
881mod tests {
882    use base64::{engine::general_purpose, Engine as _};
883    use serde::{Deserialize, Serialize};
884    use serde_with::skip_serializing_none;
885    use uuid::Uuid;
886
887    use super::{DbBackupCodeV1, DbCred, DbPasswordV1, DbTotpV1, DbWebauthnV1};
888
889    fn dbcred_type_default_pw() -> DbCredTypeV1 {
890        DbCredTypeV1::Pw
891    }
892
893    #[derive(Serialize, Deserialize, Debug)]
894    pub enum DbCredTypeV1 {
895        Pw,
896        GPw,
897        PwMfa,
898        Wn,
900        }
903
904    #[skip_serializing_none]
905    #[derive(Serialize, Deserialize, Debug)]
906    pub struct DbCredV1 {
907        #[serde(default = "dbcred_type_default_pw")]
908        pub type_: DbCredTypeV1,
909        pub password: Option<DbPasswordV1>,
910        pub webauthn: Option<Vec<DbWebauthnV1>>,
911        pub totp: Option<DbTotpV1>,
912        pub backup_code: Option<DbBackupCodeV1>,
913        pub claims: Vec<String>,
914        pub uuid: Uuid,
915    }
916
917    #[test]
918    fn test_dbcred_pre_totp_decode() {
919        let s = "o2hwYXNzd29yZKFmUEJLREYygwCBAIEAZmNsYWltc4BkdXVpZFAjkHFm4q5M86UcNRi4hBjN";
931        let data = general_purpose::STANDARD.decode(s).unwrap();
932        let dbcred: DbCredV1 = serde_cbor::from_slice(data.as_slice()).unwrap();
933
934        let x = vec![dbcred];
936
937        let json = serde_json::to_string(&x).unwrap();
938        eprintln!("{json}");
939
940        let _e_dbcred: Vec<DbCred> = serde_json::from_str(&json).unwrap();
941
942        }
944}