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