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#[allow(clippy::trivially_copy_pass_by_ref)]
152fn is_false(b: &bool) -> bool {
153 !b
154}
155
156#[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 DbValueEmailAddressV1 {
429 pub d: String,
430 #[serde(skip_serializing_if = "is_false", default)]
431 pub p: bool,
432}
433
434#[derive(Serialize, Deserialize, Debug)]
435pub struct DbValuePhoneNumberV1 {
436 pub d: String,
437 #[serde(skip_serializing_if = "is_false", default)]
438 pub p: bool,
439}
440
441#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
442pub struct DbValueAddressV1 {
443 #[serde(rename = "f")]
444 pub formatted: String,
445 #[serde(rename = "s")]
446 pub street_address: String,
447 #[serde(rename = "l")]
448 pub locality: String,
449 #[serde(rename = "r")]
450 pub region: String,
451 #[serde(rename = "p")]
452 pub postal_code: String,
453 #[serde(rename = "c")]
454 pub country: String,
455}
456
457#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
458pub enum DbValueOauthClaimMapJoinV1 {
459 #[serde(rename = "c")]
460 CommaSeparatedValue,
461 #[serde(rename = "s")]
462 SpaceSeparatedValue,
463 #[serde(rename = "a")]
464 JsonArray,
465}
466
467#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
468pub enum DbValueOauthClaimMap {
469 V1 {
470 #[serde(rename = "n")]
471 name: String,
472 #[serde(rename = "j")]
473 join: DbValueOauthClaimMapJoinV1,
474 #[serde(rename = "d")]
475 values: BTreeMap<Uuid, BTreeSet<String>>,
476 },
477}
478
479#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
480pub struct DbValueOauthScopeMapV1 {
481 #[serde(rename = "u")]
482 pub refer: Uuid,
483 #[serde(rename = "m")]
484 pub data: Vec<String>,
485}
486
487#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
488pub enum DbValueAccessScopeV1 {
489 #[serde(rename = "i")]
490 IdentityOnly,
491 #[serde(rename = "r")]
492 #[default]
493 ReadOnly,
494 #[serde(rename = "w")]
495 ReadWrite,
496 #[serde(rename = "p")]
497 PrivilegeCapable,
498 #[serde(rename = "s")]
499 Synchronise,
500}
501
502#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
503#[allow(clippy::enum_variant_names)]
504pub enum DbValueIdentityId {
505 #[serde(rename = "v1i")]
506 V1Internal,
507 #[serde(rename = "v1u")]
508 V1Uuid(Uuid),
509 #[serde(rename = "v1s")]
510 V1Sync(Uuid),
511}
512
513#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
514pub enum DbValueSessionStateV1 {
515 #[serde(rename = "ea")]
516 ExpiresAt(String),
517 #[serde(rename = "nv")]
518 Never,
519 #[serde(rename = "ra")]
520 RevokedAt(DbCidV1),
521}
522
523#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
524pub enum DbValueAuthTypeV1 {
525 #[serde(rename = "an")]
526 Anonymous,
527 #[serde(rename = "po")]
528 Password,
529 #[serde(rename = "pg")]
530 GeneratedPassword,
531 #[serde(rename = "pt")]
532 PasswordTotp,
533 #[serde(rename = "pb")]
534 PasswordBackupCode,
535 #[serde(rename = "ps")]
536 PasswordSecurityKey,
537 #[serde(rename = "as")]
538 Passkey,
539 #[serde(rename = "ap")]
540 AttestedPasskey,
541}
542
543#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
544pub enum DbValueSession {
545 V1 {
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 = "s", default)]
557 scope: DbValueAccessScopeV1,
558 },
559 V2 {
560 #[serde(rename = "u")]
561 refer: Uuid,
562 #[serde(rename = "l")]
563 label: String,
564 #[serde(rename = "e")]
565 expiry: Option<String>,
566 #[serde(rename = "i")]
567 issued_at: String,
568 #[serde(rename = "b")]
569 issued_by: DbValueIdentityId,
570 #[serde(rename = "c")]
571 cred_id: Uuid,
572 #[serde(rename = "s", default)]
573 scope: DbValueAccessScopeV1,
574 },
575 V3 {
576 #[serde(rename = "u")]
577 refer: Uuid,
578 #[serde(rename = "l")]
579 label: String,
580 #[serde(rename = "e")]
581 state: DbValueSessionStateV1,
582 #[serde(rename = "i")]
583 issued_at: String,
584 #[serde(rename = "b")]
585 issued_by: DbValueIdentityId,
586 #[serde(rename = "c")]
587 cred_id: Uuid,
588 #[serde(rename = "s", default)]
589 scope: DbValueAccessScopeV1,
590 },
591 V4 {
592 #[serde(rename = "u")]
593 refer: Uuid,
594 #[serde(rename = "l")]
595 label: String,
596 #[serde(rename = "e")]
597 state: DbValueSessionStateV1,
598 #[serde(rename = "i")]
599 issued_at: String,
600 #[serde(rename = "b")]
601 issued_by: DbValueIdentityId,
602 #[serde(rename = "c")]
603 cred_id: Uuid,
604 #[serde(rename = "s", default)]
605 scope: DbValueAccessScopeV1,
606 #[serde(rename = "t")]
607 type_: DbValueAuthTypeV1,
608 },
609}
610
611#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
612pub enum DbValueApiTokenScopeV1 {
613 #[serde(rename = "r")]
614 #[default]
615 ReadOnly,
616 #[serde(rename = "w")]
617 ReadWrite,
618 #[serde(rename = "s")]
619 Synchronise,
620}
621
622#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
623pub enum DbValueApiToken {
624 V1 {
625 #[serde(rename = "u")]
626 refer: Uuid,
627 #[serde(rename = "l")]
628 label: String,
629 #[serde(rename = "e")]
630 expiry: Option<String>,
631 #[serde(rename = "i")]
632 issued_at: String,
633 #[serde(rename = "b")]
634 issued_by: DbValueIdentityId,
635 #[serde(rename = "s", default)]
636 scope: DbValueApiTokenScopeV1,
637 },
638}
639
640#[skip_serializing_none]
641#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
642pub enum DbValueOauth2Session {
643 V1 {
644 #[serde(rename = "u")]
645 refer: Uuid,
646 #[serde(rename = "p")]
647 parent: Uuid,
648 #[serde(rename = "e")]
649 expiry: Option<String>,
650 #[serde(rename = "i")]
651 issued_at: String,
652 #[serde(rename = "r")]
653 rs_uuid: Uuid,
654 },
655 V2 {
656 #[serde(rename = "u")]
657 refer: Uuid,
658 #[serde(rename = "p")]
659 parent: Uuid,
660 #[serde(rename = "e")]
661 state: DbValueSessionStateV1,
662 #[serde(rename = "i")]
663 issued_at: String,
664 #[serde(rename = "r")]
665 rs_uuid: Uuid,
666 },
667 V3 {
668 #[serde(rename = "u")]
669 refer: Uuid,
670 #[serde(rename = "p")]
671 parent: Option<Uuid>,
672 #[serde(rename = "e")]
673 state: DbValueSessionStateV1,
674 #[serde(rename = "i")]
675 issued_at: String,
676 #[serde(rename = "r")]
677 rs_uuid: Uuid,
678 },
679}
680
681#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
683pub enum DbValueImage {
684 V1 {
685 filename: String,
686 filetype: ImageType,
687 contents: Vec<u8>,
688 },
689}
690
691#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
692pub enum DbValueKeyUsage {
693 JwsEs256,
694 JwsHs256,
695 JwsRs256,
696 JweA128GCM,
697}
698
699#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
700pub enum DbValueKeyStatus {
701 Valid,
702 Retained,
703 Revoked,
704}
705
706#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
707pub enum DbValueKeyInternal {
708 V1 {
709 id: String,
710 usage: DbValueKeyUsage,
711 valid_from: u64,
712 status: DbValueKeyStatus,
713 status_cid: DbCidV1,
714 der: Zeroizing<Vec<u8>>,
715 },
716}
717
718#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
719pub enum DbValueCertificate {
720 V1 { certificate_der: Vec<u8> },
721}
722
723#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
724pub enum DbValueApplicationPassword {
725 V1 {
726 #[serde(rename = "u")]
727 refer: Uuid,
728 #[serde(rename = "a")]
729 application_refer: Uuid,
730 #[serde(rename = "l")]
731 label: String,
732 #[serde(rename = "p")]
733 password: DbPasswordV1,
734 },
735}
736
737#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
738pub enum DbValueSetV2 {
739 #[serde(rename = "U8")]
740 Utf8(Vec<String>),
741 #[serde(rename = "I8")]
742 Iutf8(Vec<String>),
743 #[serde(rename = "N8")]
744 Iname(Vec<String>),
745 #[serde(rename = "UU")]
746 Uuid(Vec<Uuid>),
747 #[serde(rename = "BO")]
748 Bool(Vec<bool>),
749 #[serde(rename = "SY")]
750 SyntaxType(Vec<u16>),
751 #[serde(rename = "IN")]
752 IndexType(Vec<u16>),
753 #[serde(rename = "RF")]
754 Reference(Vec<Uuid>),
755 #[serde(rename = "JF")]
756 JsonFilter(Vec<String>),
757 #[serde(rename = "CR")]
758 Credential(Vec<DbValueCredV1>),
759 #[serde(rename = "RU")]
760 SecretValue(Vec<String>),
761 #[serde(rename = "SK")]
762 SshKey(Vec<DbValueTaggedStringV1>),
763 #[serde(rename = "SP")]
764 Spn(Vec<(String, String)>),
765 #[serde(rename = "UI")]
766 Uint32(Vec<u32>),
767 #[serde(rename = "CI")]
768 Cid(Vec<DbCidV1>),
769 #[serde(rename = "NU")]
770 NsUniqueId(Vec<String>),
771 #[serde(rename = "DT")]
772 DateTime(Vec<String>),
773 #[serde(rename = "EM")]
774 EmailAddress(String, Vec<String>),
775 #[serde(rename = "PN")]
776 PhoneNumber(String, Vec<String>),
777 #[serde(rename = "AD")]
778 Address(Vec<DbValueAddressV1>),
779 #[serde(rename = "UR")]
780 Url(Vec<Url>),
781 #[serde(rename = "OS")]
782 OauthScope(Vec<String>),
783 #[serde(rename = "OM")]
784 OauthScopeMap(Vec<DbValueOauthScopeMapV1>),
785 #[serde(rename = "OC")]
786 OauthClaimMap(Vec<DbValueOauthClaimMap>),
787 #[serde(rename = "E2")]
788 PrivateBinary(Vec<Vec<u8>>),
789 #[serde(rename = "PB")]
790 PublicBinary(Vec<(String, Vec<u8>)>),
791 #[serde(rename = "RS")]
792 RestrictedString(Vec<String>),
793 #[serde(rename = "IT")]
794 IntentToken(Vec<(String, DbValueIntentTokenStateV1)>),
795 #[serde(rename = "PK")]
796 Passkey(Vec<DbValuePasskeyV1>),
797 #[serde(rename = "DK")]
798 AttestedPasskey(Vec<DbValueAttestedPasskeyV1>),
799 #[serde(rename = "TE")]
800 TrustedDeviceEnrollment(Vec<Uuid>),
801 #[serde(rename = "AS")]
802 Session(Vec<DbValueSession>),
803 #[serde(rename = "JE")]
804 JwsKeyEs256(Vec<Zeroizing<Vec<u8>>>),
805 #[serde(rename = "JR")]
806 JwsKeyRs256(Vec<Zeroizing<Vec<u8>>>),
807 #[serde(rename = "OZ")]
808 Oauth2Session(Vec<DbValueOauth2Session>),
809 #[serde(rename = "UH")]
810 UiHint(Vec<u16>),
811 #[serde(rename = "TO")]
812 TotpSecret(Vec<(String, DbTotpV1)>),
813 #[serde(rename = "AT")]
814 ApiToken(Vec<DbValueApiToken>),
815 #[serde(rename = "SA")]
816 AuditLogString(Vec<(Cid, String)>),
817 #[serde(rename = "EK")]
818 EcKeyPrivate(Vec<u8>),
819 #[serde(rename = "IM")]
820 Image(Vec<DbValueImage>),
821 #[serde(rename = "CT")]
822 CredentialType(Vec<u16>),
823 #[serde(rename = "WC")]
824 WebauthnAttestationCaList { ca_list: AttestationCaList },
825 #[serde(rename = "KI")]
826 KeyInternal(Vec<DbValueKeyInternal>),
827 #[serde(rename = "HS")]
828 HexString(Vec<String>),
829 #[serde(rename = "X509")]
830 Certificate(Vec<DbValueCertificate>),
831 #[serde(rename = "AP")]
832 ApplicationPassword(Vec<DbValueApplicationPassword>),
833}
834
835impl DbValueSetV2 {
836 pub fn len(&self) -> usize {
837 match self {
838 DbValueSetV2::Utf8(set)
839 | DbValueSetV2::Iutf8(set)
840 | DbValueSetV2::HexString(set)
841 | DbValueSetV2::Iname(set) => set.len(),
842 DbValueSetV2::Uuid(set) => set.len(),
843 DbValueSetV2::Bool(set) => set.len(),
844 DbValueSetV2::SyntaxType(set) => set.len(),
845 DbValueSetV2::IndexType(set) => set.len(),
846 DbValueSetV2::Reference(set) => set.len(),
847 DbValueSetV2::JsonFilter(set) => set.len(),
848 DbValueSetV2::Credential(set) => set.len(),
849 DbValueSetV2::SecretValue(set) => set.len(),
850 DbValueSetV2::SshKey(set) => set.len(),
851 DbValueSetV2::Spn(set) => set.len(),
852 DbValueSetV2::Uint32(set) => set.len(),
853 DbValueSetV2::Cid(set) => set.len(),
854 DbValueSetV2::NsUniqueId(set) => set.len(),
855 DbValueSetV2::DateTime(set) => set.len(),
856 DbValueSetV2::EmailAddress(_primary, set) => set.len(),
857 DbValueSetV2::PhoneNumber(_primary, set) => set.len(),
858 DbValueSetV2::Address(set) => set.len(),
859 DbValueSetV2::Url(set) => set.len(),
860 DbValueSetV2::OauthClaimMap(set) => set.len(),
861 DbValueSetV2::OauthScope(set) => set.len(),
862 DbValueSetV2::OauthScopeMap(set) => set.len(),
863 DbValueSetV2::PrivateBinary(set) => set.len(),
864 DbValueSetV2::PublicBinary(set) => set.len(),
865 DbValueSetV2::RestrictedString(set) => set.len(),
866 DbValueSetV2::IntentToken(set) => set.len(),
867 DbValueSetV2::Passkey(set) => set.len(),
868 DbValueSetV2::AttestedPasskey(set) => set.len(),
869 DbValueSetV2::TrustedDeviceEnrollment(set) => set.len(),
870 DbValueSetV2::Session(set) => set.len(),
871 DbValueSetV2::ApiToken(set) => set.len(),
872 DbValueSetV2::Oauth2Session(set) => set.len(),
873 DbValueSetV2::JwsKeyEs256(set) => set.len(),
874 DbValueSetV2::JwsKeyRs256(set) => set.len(),
875 DbValueSetV2::UiHint(set) => set.len(),
876 DbValueSetV2::TotpSecret(set) => set.len(),
877 DbValueSetV2::AuditLogString(set) => set.len(),
878 DbValueSetV2::Image(set) => set.len(),
879 DbValueSetV2::EcKeyPrivate(_key) => 1, DbValueSetV2::CredentialType(set) => set.len(),
882 DbValueSetV2::WebauthnAttestationCaList { ca_list } => ca_list.len(),
883 DbValueSetV2::KeyInternal(set) => set.len(),
884 DbValueSetV2::Certificate(set) => set.len(),
885 DbValueSetV2::ApplicationPassword(set) => set.len(),
886 }
887 }
888
889 pub fn is_empty(&self) -> bool {
890 self.len() == 0
891 }
892}
893
894#[cfg(test)]
895mod tests {
896 use base64::{engine::general_purpose, Engine as _};
897 use serde::{Deserialize, Serialize};
898 use serde_with::skip_serializing_none;
899 use uuid::Uuid;
900
901 use super::{DbBackupCodeV1, DbCred, DbPasswordV1, DbTotpV1, DbWebauthnV1};
902
903 fn dbcred_type_default_pw() -> DbCredTypeV1 {
904 DbCredTypeV1::Pw
905 }
906
907 #[derive(Serialize, Deserialize, Debug)]
908 pub enum DbCredTypeV1 {
909 Pw,
910 GPw,
911 PwMfa,
912 Wn,
914 }
917
918 #[skip_serializing_none]
919 #[derive(Serialize, Deserialize, Debug)]
920 pub struct DbCredV1 {
921 #[serde(default = "dbcred_type_default_pw")]
922 pub type_: DbCredTypeV1,
923 pub password: Option<DbPasswordV1>,
924 pub webauthn: Option<Vec<DbWebauthnV1>>,
925 pub totp: Option<DbTotpV1>,
926 pub backup_code: Option<DbBackupCodeV1>,
927 pub claims: Vec<String>,
928 pub uuid: Uuid,
929 }
930
931 #[test]
932 fn test_dbcred_pre_totp_decode() {
933 let s = "o2hwYXNzd29yZKFmUEJLREYygwCBAIEAZmNsYWltc4BkdXVpZFAjkHFm4q5M86UcNRi4hBjN";
945 let data = general_purpose::STANDARD.decode(s).unwrap();
946 let dbcred: DbCredV1 = serde_cbor::from_slice(data.as_slice()).unwrap();
947
948 let x = vec![dbcred];
950
951 let json = serde_json::to_string(&x).unwrap();
952 eprintln!("{json}");
953
954 let _e_dbcred: Vec<DbCred> = serde_json::from_str(&json).unwrap();
955
956 }
958}