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