1use std::fmt;
2use std::time::Duration;
3
4use hashbrown::HashSet;
5use kanidm_proto::internal::ImageType;
6use serde::{Deserialize, Serialize};
7use serde_with::skip_serializing_none;
8use std::collections::{BTreeMap, BTreeSet};
9use url::Url;
10use uuid::Uuid;
11use webauthn_rs::prelude::{
12 AttestationCaList, AttestedPasskey as AttestedPasskeyV4, Passkey as PasskeyV4,
13 SecurityKey as SecurityKeyV4,
14};
15use webauthn_rs_core::proto::{COSEKey, UserVerificationPolicy};
16
17use crate::repl::cid::Cid;
19pub use kanidm_lib_crypto::DbPasswordV1;
20
21#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, PartialEq, Eq, Clone)]
22pub struct DbCidV1 {
23 #[serde(rename = "t")]
24 pub timestamp: Duration,
25 #[serde(rename = "s")]
26 pub server_id: Uuid,
27}
28
29impl From<Cid> for DbCidV1 {
30 fn from(Cid { s_uuid, ts }: Cid) -> Self {
31 DbCidV1 {
32 timestamp: ts,
33 server_id: s_uuid,
34 }
35 }
36}
37
38impl From<&Cid> for DbCidV1 {
39 fn from(&Cid { s_uuid, ts }: &Cid) -> Self {
40 DbCidV1 {
41 timestamp: ts,
42 server_id: s_uuid,
43 }
44 }
45}
46
47impl fmt::Display for DbCidV1 {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 write!(f, "{:032}-{}", self.timestamp.as_nanos(), self.server_id)
50 }
51}
52
53#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
54pub enum DbValueIntentTokenStateV1 {
55 #[serde(rename = "v")]
56 Valid {
57 max_ttl: Duration,
58 #[serde(default)]
59 ext_cred_portal_can_view: bool,
60 #[serde(default)]
61 primary_can_edit: bool,
62 #[serde(default)]
63 passkeys_can_edit: bool,
64 #[serde(default)]
65 attested_passkeys_can_edit: bool,
66 #[serde(default)]
67 unixcred_can_edit: bool,
68 #[serde(default)]
69 sshpubkey_can_edit: bool,
70 },
71 #[serde(rename = "p")]
72 InProgress {
73 max_ttl: Duration,
74 session_id: Uuid,
75 session_ttl: Duration,
76 #[serde(default)]
77 ext_cred_portal_can_view: bool,
78 #[serde(default)]
79 primary_can_edit: bool,
80 #[serde(default)]
81 passkeys_can_edit: bool,
82 #[serde(default)]
83 attested_passkeys_can_edit: bool,
84 #[serde(default)]
85 unixcred_can_edit: bool,
86 #[serde(default)]
87 sshpubkey_can_edit: bool,
88 },
89 #[serde(rename = "c")]
90 Consumed { max_ttl: Duration },
91}
92
93#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
94pub enum DbTotpAlgoV1 {
95 S1,
96 S256,
97 S512,
98}
99
100#[derive(Serialize, Deserialize, PartialEq, Eq)]
101pub struct DbTotpV1 {
102 #[serde(rename = "l")]
103 pub label: String,
104 #[serde(rename = "k")]
105 pub key: Vec<u8>,
106 #[serde(rename = "s")]
107 pub step: u64,
108 #[serde(rename = "a")]
109 pub algo: DbTotpAlgoV1,
110 #[serde(rename = "d", default)]
111 pub digits: Option<u8>,
112}
113
114impl std::fmt::Debug for DbTotpV1 {
115 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
116 f.debug_struct("DbTotpV1")
117 .field("label", &self.label)
118 .field("step", &self.step)
119 .field("algo", &self.algo)
120 .finish()
121 }
122}
123
124#[derive(Serialize, Deserialize, Debug)]
125pub struct DbWebauthnV1 {
126 #[serde(rename = "l")]
127 pub label: String,
128 #[serde(rename = "i")]
129 pub id: Vec<u8>,
130 #[serde(rename = "c")]
131 pub cred: COSEKey,
132 #[serde(rename = "t")]
133 pub counter: u32,
134 #[serde(rename = "v")]
135 pub verified: bool,
136 #[serde(rename = "p", default)]
137 pub registration_policy: UserVerificationPolicy,
138}
139
140#[derive(Serialize, Deserialize, PartialEq, Eq)]
141pub struct DbBackupCodeV1 {
142 pub code_set: HashSet<String>, }
144
145impl std::fmt::Debug for DbBackupCodeV1 {
146 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
147 write!(f, "codes remaining: {}", self.code_set.len())
148 }
149}
150
151#[allow(clippy::trivially_copy_pass_by_ref)]
153fn is_false(b: &bool) -> bool {
154 !b
155}
156
157#[skip_serializing_none]
158#[derive(Serialize, Deserialize, Debug)]
159#[serde(tag = "type_")]
160pub enum DbCred {
161 Pw {
163 password: Option<DbPasswordV1>,
164 webauthn: Option<Vec<DbWebauthnV1>>,
165 totp: Option<DbTotpV1>,
166 backup_code: Option<DbBackupCodeV1>,
167 claims: Vec<String>,
168 uuid: Uuid,
169 },
170 GPw {
171 password: Option<DbPasswordV1>,
172 webauthn: Option<Vec<DbWebauthnV1>>,
173 totp: Option<DbTotpV1>,
174 backup_code: Option<DbBackupCodeV1>,
175 claims: Vec<String>,
176 uuid: Uuid,
177 },
178 PwMfa {
179 password: Option<DbPasswordV1>,
180 webauthn: Option<Vec<DbWebauthnV1>>,
181 totp: Option<DbTotpV1>,
182 backup_code: Option<DbBackupCodeV1>,
183 claims: Vec<String>,
184 uuid: Uuid,
185 },
186 Wn {
187 password: Option<DbPasswordV1>,
188 webauthn: Option<Vec<DbWebauthnV1>>,
189 totp: Option<DbTotpV1>,
190 backup_code: Option<DbBackupCodeV1>,
191 claims: Vec<String>,
192 uuid: Uuid,
193 },
194
195 TmpWn {
196 webauthn: Vec<(String, PasskeyV4)>,
197 uuid: Uuid,
198 },
199
200 #[serde(rename = "V2PwMfa")]
201 V2PasswordMfa {
202 password: DbPasswordV1,
203 totp: Option<DbTotpV1>,
204 backup_code: Option<DbBackupCodeV1>,
205 webauthn: Vec<(String, SecurityKeyV4)>,
206 uuid: Uuid,
207 },
208
209 #[serde(rename = "V2Pw")]
211 V2Password { password: DbPasswordV1, uuid: Uuid },
212 #[serde(rename = "V2GPw")]
213 V2GenPassword { password: DbPasswordV1, uuid: Uuid },
214 #[serde(rename = "V3PwMfa")]
215 V3PasswordMfa {
216 password: DbPasswordV1,
217 totp: Vec<(String, DbTotpV1)>,
218 backup_code: Option<DbBackupCodeV1>,
219 webauthn: Vec<(String, SecurityKeyV4)>,
220 uuid: Uuid,
221 },
222}
223
224impl DbCred {
225 fn uuid(&self) -> Uuid {
226 match self {
227 DbCred::Pw { uuid, .. }
228 | DbCred::GPw { uuid, .. }
229 | DbCred::PwMfa { uuid, .. }
230 | DbCred::Wn { uuid, .. }
231 | DbCred::TmpWn { uuid, .. }
232 | DbCred::V2PasswordMfa { uuid, .. }
233 | DbCred::V2Password { uuid, .. }
234 | DbCred::V2GenPassword { uuid, .. }
235 | DbCred::V3PasswordMfa { uuid, .. } => *uuid,
236 }
237 }
238}
239
240impl Eq for DbCred {}
241
242impl PartialEq for DbCred {
243 fn eq(&self, other: &Self) -> bool {
244 self.uuid() == other.uuid()
245 }
246}
247
248impl fmt::Display for DbCred {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 match self {
251 DbCred::Pw {
252 password,
253 webauthn,
254 totp,
255 backup_code,
256 claims,
257 uuid,
258 } => write!(
259 f,
260 "Pw (p {}, w {}, t {}, b {}, c {}, u {})",
261 password.is_some(),
262 webauthn.is_some(),
263 totp.is_some(),
264 backup_code.is_some(),
265 claims.len(),
266 uuid
267 ),
268 DbCred::GPw {
269 password,
270 webauthn,
271 totp,
272 backup_code,
273 claims,
274 uuid,
275 } => write!(
276 f,
277 "GPw (p {}, w {}, t {}, b {}, c {}, u {})",
278 password.is_some(),
279 webauthn.is_some(),
280 totp.is_some(),
281 backup_code.is_some(),
282 claims.len(),
283 uuid
284 ),
285 DbCred::PwMfa {
286 password,
287 webauthn,
288 totp,
289 backup_code,
290 claims,
291 uuid,
292 } => write!(
293 f,
294 "PwMfa (p {}, w {}, t {}, b {}, c {}, u {})",
295 password.is_some(),
296 webauthn.is_some(),
297 totp.is_some(),
298 backup_code.is_some(),
299 claims.len(),
300 uuid
301 ),
302 DbCred::Wn {
303 password,
304 webauthn,
305 totp,
306 backup_code,
307 claims,
308 uuid,
309 } => write!(
310 f,
311 "Wn (p {}, w {}, t {}, b {}, c {}, u {})",
312 password.is_some(),
313 webauthn.is_some(),
314 totp.is_some(),
315 backup_code.is_some(),
316 claims.len(),
317 uuid
318 ),
319 DbCred::TmpWn { webauthn, uuid } => {
320 write!(f, "TmpWn ( w {}, u {} )", webauthn.len(), uuid)
321 }
322 DbCred::V2Password { password: _, uuid } => write!(f, "V2Pw ( u {uuid} )"),
323 DbCred::V2GenPassword { password: _, uuid } => write!(f, "V2GPw ( u {uuid} )"),
324 DbCred::V2PasswordMfa {
325 password: _,
326 totp,
327 backup_code,
328 webauthn,
329 uuid,
330 } => write!(
331 f,
332 "V2PwMfa (p true, w {}, t {}, b {}, u {})",
333 webauthn.len(),
334 totp.is_some(),
335 backup_code.is_some(),
336 uuid
337 ),
338 DbCred::V3PasswordMfa {
339 password: _,
340 totp,
341 backup_code,
342 webauthn,
343 uuid,
344 } => write!(
345 f,
346 "V3PwMfa (p true, w {}, t {}, b {}, u {})",
347 webauthn.len(),
348 totp.len(),
349 backup_code.is_some(),
350 uuid
351 ),
352 }
353 }
354}
355
356#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
357pub struct DbValueCredV1 {
358 #[serde(rename = "t")]
359 pub tag: String,
360 #[serde(rename = "d")]
361 pub data: DbCred,
362}
363
364#[derive(Serialize, Deserialize, Debug)]
365pub enum DbValuePasskeyV1 {
366 V4 { u: Uuid, t: String, k: PasskeyV4 },
367}
368
369impl Eq for DbValuePasskeyV1 {}
370
371impl PartialEq for DbValuePasskeyV1 {
372 fn eq(&self, other: &Self) -> bool {
373 match (self, other) {
374 (
375 DbValuePasskeyV1::V4 {
376 u: self_uuid,
377 k: self_key,
378 t: _,
379 },
380 DbValuePasskeyV1::V4 {
381 u: other_uuid,
382 k: other_key,
383 t: _,
384 },
385 ) => self_uuid == other_uuid && self_key.cred_id() == other_key.cred_id(),
386 }
387 }
388}
389
390#[derive(Serialize, Deserialize, Debug)]
391pub enum DbValueAttestedPasskeyV1 {
392 V4 {
393 u: Uuid,
394 t: String,
395 k: AttestedPasskeyV4,
396 },
397}
398
399impl Eq for DbValueAttestedPasskeyV1 {}
400
401impl PartialEq for DbValueAttestedPasskeyV1 {
402 fn eq(&self, other: &Self) -> bool {
403 match (self, other) {
404 (
405 DbValueAttestedPasskeyV1::V4 {
406 u: self_uuid,
407 k: self_key,
408 t: _,
409 },
410 DbValueAttestedPasskeyV1::V4 {
411 u: other_uuid,
412 k: other_key,
413 t: _,
414 },
415 ) => self_uuid == other_uuid && self_key.cred_id() == other_key.cred_id(),
416 }
417 }
418}
419
420#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
421pub struct DbValueTaggedStringV1 {
422 #[serde(rename = "t")]
423 pub tag: String,
424 #[serde(rename = "d")]
425 pub data: String,
426}
427
428#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
429pub struct DbValueEmailAddressV1 {
430 pub d: String,
431 #[serde(skip_serializing_if = "is_false", default)]
432 pub p: bool,
433}
434
435#[derive(Serialize, Deserialize, Debug)]
436pub struct DbValuePhoneNumberV1 {
437 pub d: String,
438 #[serde(skip_serializing_if = "is_false", default)]
439 pub p: bool,
440}
441
442#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
443pub struct DbValueAddressV1 {
444 #[serde(rename = "f")]
445 pub formatted: String,
446 #[serde(rename = "s")]
447 pub street_address: String,
448 #[serde(rename = "l")]
449 pub locality: String,
450 #[serde(rename = "r")]
451 pub region: String,
452 #[serde(rename = "p")]
453 pub postal_code: String,
454 #[serde(rename = "c")]
455 pub country: String,
456}
457
458#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
459pub enum DbValueOauthClaimMapJoinV1 {
460 #[serde(rename = "c")]
461 CommaSeparatedValue,
462 #[serde(rename = "s")]
463 SpaceSeparatedValue,
464 #[serde(rename = "a")]
465 JsonArray,
466}
467
468#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
469pub enum DbValueOauthClaimMap {
470 V1 {
471 #[serde(rename = "n")]
472 name: String,
473 #[serde(rename = "j")]
474 join: DbValueOauthClaimMapJoinV1,
475 #[serde(rename = "d")]
476 values: BTreeMap<Uuid, BTreeSet<String>>,
477 },
478}
479
480#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
481pub struct DbValueOauthScopeMapV1 {
482 #[serde(rename = "u")]
483 pub refer: Uuid,
484 #[serde(rename = "m")]
485 pub data: Vec<String>,
486}
487
488#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
489pub enum DbValueAccessScopeV1 {
490 #[serde(rename = "i")]
491 IdentityOnly,
492 #[serde(rename = "r")]
493 #[default]
494 ReadOnly,
495 #[serde(rename = "w")]
496 ReadWrite,
497 #[serde(rename = "p")]
498 PrivilegeCapable,
499 #[serde(rename = "s")]
500 Synchronise,
501}
502
503#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
504#[allow(clippy::enum_variant_names)]
505pub enum DbValueIdentityId {
506 #[serde(rename = "v1i")]
507 V1Internal,
508 #[serde(rename = "v1u")]
509 V1Uuid(Uuid),
510 #[serde(rename = "v1s")]
511 V1Sync(Uuid),
512}
513
514#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
515pub enum DbValueSessionStateV1 {
516 #[serde(rename = "ea")]
517 ExpiresAt(String),
518 #[serde(rename = "nv")]
519 Never,
520 #[serde(rename = "ra")]
521 RevokedAt(DbCidV1),
522}
523
524#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
525pub enum DbValueAuthTypeV1 {
526 #[serde(rename = "an")]
527 Anonymous,
528 #[serde(rename = "po")]
529 Password,
530 #[serde(rename = "pg")]
531 GeneratedPassword,
532 #[serde(rename = "pt")]
533 PasswordTotp,
534 #[serde(rename = "pb")]
535 PasswordBackupCode,
536 #[serde(rename = "ps")]
537 PasswordSecurityKey,
538 #[serde(rename = "as")]
539 Passkey,
540 #[serde(rename = "ap")]
541 AttestedPasskey,
542}
543
544#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
545pub enum DbValueSession {
546 V1 {
547 #[serde(rename = "u")]
548 refer: Uuid,
549 #[serde(rename = "l")]
550 label: String,
551 #[serde(rename = "e")]
552 expiry: Option<String>,
553 #[serde(rename = "i")]
554 issued_at: String,
555 #[serde(rename = "b")]
556 issued_by: DbValueIdentityId,
557 #[serde(rename = "s", default)]
558 scope: DbValueAccessScopeV1,
559 },
560 V2 {
561 #[serde(rename = "u")]
562 refer: Uuid,
563 #[serde(rename = "l")]
564 label: String,
565 #[serde(rename = "e")]
566 expiry: Option<String>,
567 #[serde(rename = "i")]
568 issued_at: String,
569 #[serde(rename = "b")]
570 issued_by: DbValueIdentityId,
571 #[serde(rename = "c")]
572 cred_id: Uuid,
573 #[serde(rename = "s", default)]
574 scope: DbValueAccessScopeV1,
575 },
576 V3 {
577 #[serde(rename = "u")]
578 refer: Uuid,
579 #[serde(rename = "l")]
580 label: String,
581 #[serde(rename = "e")]
582 state: DbValueSessionStateV1,
583 #[serde(rename = "i")]
584 issued_at: String,
585 #[serde(rename = "b")]
586 issued_by: DbValueIdentityId,
587 #[serde(rename = "c")]
588 cred_id: Uuid,
589 #[serde(rename = "s", default)]
590 scope: DbValueAccessScopeV1,
591 },
592 V4 {
593 #[serde(rename = "u")]
594 refer: Uuid,
595 #[serde(rename = "l")]
596 label: String,
597 #[serde(rename = "e")]
598 state: DbValueSessionStateV1,
599 #[serde(rename = "i")]
600 issued_at: String,
601 #[serde(rename = "b")]
602 issued_by: DbValueIdentityId,
603 #[serde(rename = "c")]
604 cred_id: Uuid,
605 #[serde(rename = "s", default)]
606 scope: DbValueAccessScopeV1,
607 #[serde(rename = "t")]
608 type_: DbValueAuthTypeV1,
609 },
610}
611
612#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
613pub enum DbValueApiTokenScopeV1 {
614 #[serde(rename = "r")]
615 #[default]
616 ReadOnly,
617 #[serde(rename = "w")]
618 ReadWrite,
619 #[serde(rename = "s")]
620 Synchronise,
621}
622
623#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
624pub enum DbValueApiToken {
625 V1 {
626 #[serde(rename = "u")]
627 refer: Uuid,
628 #[serde(rename = "l")]
629 label: String,
630 #[serde(rename = "e")]
631 expiry: Option<String>,
632 #[serde(rename = "i")]
633 issued_at: String,
634 #[serde(rename = "b")]
635 issued_by: DbValueIdentityId,
636 #[serde(rename = "s", default)]
637 scope: DbValueApiTokenScopeV1,
638 },
639}
640
641#[skip_serializing_none]
642#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
643pub enum DbValueOauth2Session {
644 V1 {
645 #[serde(rename = "u")]
646 refer: Uuid,
647 #[serde(rename = "p")]
648 parent: Uuid,
649 #[serde(rename = "e")]
650 expiry: Option<String>,
651 #[serde(rename = "i")]
652 issued_at: String,
653 #[serde(rename = "r")]
654 rs_uuid: Uuid,
655 },
656 V2 {
657 #[serde(rename = "u")]
658 refer: Uuid,
659 #[serde(rename = "p")]
660 parent: Uuid,
661 #[serde(rename = "e")]
662 state: DbValueSessionStateV1,
663 #[serde(rename = "i")]
664 issued_at: String,
665 #[serde(rename = "r")]
666 rs_uuid: Uuid,
667 },
668 V3 {
669 #[serde(rename = "u")]
670 refer: Uuid,
671 #[serde(rename = "p")]
672 parent: Option<Uuid>,
673 #[serde(rename = "e")]
674 state: DbValueSessionStateV1,
675 #[serde(rename = "i")]
676 issued_at: String,
677 #[serde(rename = "r")]
678 rs_uuid: Uuid,
679 },
680}
681
682#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
684pub enum DbValueImage {
685 V1 {
686 filename: String,
687 filetype: ImageType,
688 contents: Vec<u8>,
689 },
690}
691
692#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
693pub enum DbValueKeyUsage {
694 JwsEs256,
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: 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<Vec<u8>>),
805 #[serde(rename = "JR")]
806 JwsKeyRs256(Vec<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}