1use crate::be::dbvalue::DbValueSetV2;
2use crate::credential::{apppwd::ApplicationPassword, totp::Totp, Credential};
3use crate::prelude::*;
4use crate::repl::cid::Cid;
5use crate::schema::SchemaAttribute;
6use crate::server::keys::KeyId;
7use crate::value::{
8 Address, ApiToken, CredentialType, IntentTokenState, Oauth2Session, OauthClaimMapJoin, Session,
9};
10use compact_jwt::{crypto::JwsRs256Signer, JwsEs256Signer};
11use dyn_clone::DynClone;
12use hashbrown::HashSet;
13use kanidm_lib_crypto::{x509_cert::Certificate, Sha256Digest};
14use kanidm_proto::internal::ImageValue;
15use kanidm_proto::internal::{Filter as ProtoFilter, UiHint};
16use kanidm_proto::scim_v1::JsonValue;
17use kanidm_proto::scim_v1::ScimOauth2ClaimMapJoinChar;
18use openssl::ec::EcKey;
19use openssl::pkey::Private;
20use openssl::pkey::Public;
21use smolset::SmolSet;
22use sshkey_attest::proto::PublicKey as SshPublicKey;
23use std::cmp::Ordering;
24use std::collections::{BTreeMap, BTreeSet};
25use time::OffsetDateTime;
26use webauthn_rs::prelude::AttestationCaList;
27use webauthn_rs::prelude::AttestedPasskey as AttestedPasskeyV4;
28use webauthn_rs::prelude::Passkey as PasskeyV4;
29
30pub use self::address::{ValueSetAddress, ValueSetEmailAddress};
31use self::apppwd::ValueSetApplicationPassword;
32pub use self::auditlogstring::{ValueSetAuditLogString, AUDIT_LOG_STRING_CAPACITY};
33pub use self::binary::{ValueSetPrivateBinary, ValueSetPublicBinary};
34pub use self::bool::ValueSetBool;
35pub use self::certificate::ValueSetCertificate;
36pub use self::cid::ValueSetCid;
37pub use self::cred::{
38 ValueSetAttestedPasskey, ValueSetCredential, ValueSetCredentialType, ValueSetIntentToken,
39 ValueSetPasskey, ValueSetWebauthnAttestationCaList,
40};
41pub use self::datetime::ValueSetDateTime;
42pub use self::eckey::ValueSetEcKeyPrivate;
43pub use self::hexstring::ValueSetHexString;
44use self::image::ValueSetImage;
45pub use self::iname::ValueSetIname;
46pub use self::index::ValueSetIndex;
47pub use self::iutf8::ValueSetIutf8;
48pub use self::json::ValueSetJsonFilter;
49pub use self::jws::{ValueSetJwsKeyEs256, ValueSetJwsKeyRs256};
50pub use self::key_internal::{KeyInternalData, ValueSetKeyInternal};
51pub use self::nsuniqueid::ValueSetNsUniqueId;
52pub use self::oauth::{
53 OauthClaimMapping, ValueSetOauthClaimMap, ValueSetOauthScope, ValueSetOauthScopeMap,
54};
55pub use self::restricted::ValueSetRestricted;
56pub use self::secret::ValueSetSecret;
57pub use self::session::{ValueSetApiToken, ValueSetOauth2Session, ValueSetSession};
58pub use self::spn::ValueSetSpn;
59pub use self::ssh::ValueSetSshKey;
60pub use self::syntax::ValueSetSyntax;
61pub use self::totp::ValueSetTotpSecret;
62pub use self::uihint::ValueSetUiHint;
63pub use self::uint32::ValueSetUint32;
64pub use self::url::ValueSetUrl;
65pub use self::utf8::ValueSetUtf8;
66pub use self::uuid::{ValueSetRefer, ValueSetUuid};
67
68mod address;
69mod apppwd;
70mod auditlogstring;
71mod binary;
72mod bool;
73mod certificate;
74mod cid;
75mod cred;
76mod datetime;
77pub mod eckey;
78mod hexstring;
79pub mod image;
80mod iname;
81mod index;
82mod iutf8;
83mod json;
84mod jws;
85mod key_internal;
86mod nsuniqueid;
87mod oauth;
88mod restricted;
89mod secret;
90mod session;
91mod spn;
92mod ssh;
93mod syntax;
94mod totp;
95mod uihint;
96mod uint32;
97mod url;
98mod utf8;
99mod uuid;
100
101pub type ValueSet = Box<dyn ValueSetT + Send + Sync + 'static>;
102
103dyn_clone::clone_trait_object!(ValueSetT);
104
105pub trait ValueSetT: std::fmt::Debug + DynClone {
106 fn insert_checked(&mut self, value: Value) -> Result<bool, OperationError>;
111
112 fn clear(&mut self);
113
114 fn remove(&mut self, pv: &PartialValue, cid: &Cid) -> bool;
115
116 fn purge(&mut self, _cid: &Cid) -> bool {
117 true
119 }
120
121 fn trim(&mut self, _trim_cid: &Cid) {
122 }
124
125 fn contains(&self, pv: &PartialValue) -> bool;
126
127 fn substring(&self, pv: &PartialValue) -> bool;
128
129 fn startswith(&self, pv: &PartialValue) -> bool;
130
131 fn endswith(&self, pv: &PartialValue) -> bool;
132
133 fn lessthan(&self, pv: &PartialValue) -> bool;
134
135 fn len(&self) -> usize;
136
137 fn generate_idx_eq_keys(&self) -> Vec<String>;
138
139 fn generate_idx_sub_keys(&self) -> Vec<String> {
140 Vec::with_capacity(0)
141 }
142
143 fn syntax(&self) -> SyntaxType;
144
145 fn validate(&self, schema_attr: &SchemaAttribute) -> bool;
146
147 fn to_proto_string_clone_iter(&self) -> Box<dyn Iterator<Item = String> + '_>;
148
149 fn to_scim_value(&self) -> Option<ScimResolveStatus>;
150
151 fn to_db_valueset_v2(&self) -> DbValueSetV2;
152
153 fn to_partialvalue_iter(&self) -> Box<dyn Iterator<Item = PartialValue> + '_>;
154
155 fn to_value_iter(&self) -> Box<dyn Iterator<Item = Value> + '_>;
156
157 fn equal(&self, other: &ValueSet) -> bool;
158
159 fn cmp(&self, _other: &ValueSet) -> Ordering {
160 error!("cmp should not be called on {:?}", self.syntax());
164 debug_assert!(false);
165 Ordering::Equal
166 }
167
168 fn merge(&mut self, other: &ValueSet) -> Result<(), OperationError>;
169
170 fn is_empty(&self) -> bool {
171 self.len() == 0
172 }
173
174 fn migrate_iutf8_iname(&self) -> Result<Option<ValueSet>, OperationError> {
175 debug_assert!(false);
176 Ok(None)
177 }
178
179 fn get_ssh_tag(&self, _tag: &str) -> Option<&SshPublicKey> {
180 None
181 }
182
183 fn as_ref_uuid_iter(&self) -> Option<Box<dyn Iterator<Item = Uuid> + '_>> {
184 None
185 }
186
187 fn as_utf8_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
188 error!("as_utf8_iter should not be called on {:?}", self.syntax());
189 debug_assert!(false);
190 None
191 }
192
193 fn as_iutf8_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
194 error!("as_iutf8_iter should not be called on {:?}", self.syntax());
195 debug_assert!(false);
196 None
197 }
198
199 fn as_iname_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
200 error!("as_iname_iter should not be called on {:?}", self.syntax());
201 debug_assert!(false);
202 None
203 }
204
205 fn as_indextype_iter(&self) -> Option<Box<dyn Iterator<Item = IndexType> + '_>> {
206 error!(
207 "as_indextype_set should not be called on {:?}",
208 self.syntax()
209 );
210 None
211 }
212
213 fn as_restricted_string_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
214 error!(
215 "as_restricted_string_iter should not be called on {:?}",
216 self.syntax()
217 );
218 None
219 }
220
221 fn as_oauthscope_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
222 error!(
223 "as_oauthscope_iter should not be called on {:?}",
224 self.syntax()
225 );
226 None
227 }
228
229 fn as_sshpubkey_string_iter(&self) -> Option<Box<dyn Iterator<Item = String> + '_>> {
230 None
231 }
232
233 fn as_email_str_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
234 None
235 }
236
237 fn as_utf8_set(&self) -> Option<&BTreeSet<String>> {
238 debug_assert!(false);
239 None
240 }
241
242 fn as_iutf8_set(&self) -> Option<&BTreeSet<String>> {
243 debug_assert!(false);
244 None
245 }
246
247 fn as_iname_set(&self) -> Option<&BTreeSet<String>> {
248 debug_assert!(false);
249 None
250 }
251
252 fn as_uuid_set(&self) -> Option<&SmolSet<[Uuid; 1]>> {
253 None
254 }
255
256 fn as_refer_set(&self) -> Option<&BTreeSet<Uuid>> {
257 None
258 }
259
260 fn as_refer_set_mut(&mut self) -> Option<&mut BTreeSet<Uuid>> {
261 debug_assert!(false);
262 None
263 }
264
265 fn as_bool_set(&self) -> Option<&SmolSet<[bool; 1]>> {
266 debug_assert!(false);
267 None
268 }
269
270 fn as_uint32_set(&self) -> Option<&SmolSet<[u32; 1]>> {
271 debug_assert!(false);
272 None
273 }
274
275 fn as_syntax_set(&self) -> Option<&SmolSet<[SyntaxType; 1]>> {
276 debug_assert!(false);
277 None
278 }
279
280 fn as_index_set(&self) -> Option<&SmolSet<[IndexType; 3]>> {
281 debug_assert!(false);
282 None
283 }
284
285 fn as_secret_set(&self) -> Option<&SmolSet<[String; 1]>> {
286 debug_assert!(false);
287 None
288 }
289
290 fn as_restricted_string_set(&self) -> Option<&BTreeSet<String>> {
291 debug_assert!(false);
292 None
293 }
294
295 fn as_spn_set(&self) -> Option<&SmolSet<[(String, String); 1]>> {
296 debug_assert!(false);
297 None
298 }
299
300 fn as_cid_set(&self) -> Option<&SmolSet<[Cid; 1]>> {
301 debug_assert!(false);
302 None
303 }
304
305 fn as_json_filter_set(&self) -> Option<&SmolSet<[ProtoFilter; 1]>> {
306 debug_assert!(false);
307 None
308 }
309
310 fn as_nsuniqueid_set(&self) -> Option<&SmolSet<[String; 1]>> {
311 debug_assert!(false);
312 None
313 }
314
315 fn as_url_set(&self) -> Option<&SmolSet<[Url; 1]>> {
316 debug_assert!(false);
317 None
318 }
319
320 fn as_datetime_set(&self) -> Option<&SmolSet<[OffsetDateTime; 1]>> {
321 debug_assert!(false);
322 None
323 }
324
325 fn as_private_binary_set(&self) -> Option<&SmolSet<[Vec<u8>; 1]>> {
326 debug_assert!(false);
327 None
328 }
329
330 fn as_oauthscope_set(&self) -> Option<&BTreeSet<String>> {
331 debug_assert!(false);
332 None
333 }
334
335 fn as_address_set(&self) -> Option<&SmolSet<[Address; 1]>> {
336 debug_assert!(false);
337 None
338 }
339
340 fn as_credential_map(&self) -> Option<&BTreeMap<String, Credential>> {
341 debug_assert!(false);
342 None
343 }
344
345 fn as_totp_map(&self) -> Option<&BTreeMap<String, Totp>> {
346 debug_assert!(false);
347 None
348 }
349
350 fn as_emailaddress_set(&self) -> Option<(&String, &BTreeSet<String>)> {
351 debug_assert!(false);
352 None
353 }
354
355 fn as_sshkey_map(&self) -> Option<&BTreeMap<String, SshPublicKey>> {
356 None
357 }
358
359 fn as_oauthscopemap(&self) -> Option<&BTreeMap<Uuid, BTreeSet<String>>> {
360 None
367 }
368
369 fn as_publicbinary_map(&self) -> Option<&BTreeMap<String, Vec<u8>>> {
370 debug_assert!(false);
371 None
372 }
373
374 fn as_intenttoken_map(&self) -> Option<&BTreeMap<String, IntentTokenState>> {
375 debug_assert!(false);
376 None
377 }
378
379 fn as_passkey_map(&self) -> Option<&BTreeMap<Uuid, (String, PasskeyV4)>> {
380 debug_assert!(false);
381 None
382 }
383
384 fn as_attestedpasskey_map(&self) -> Option<&BTreeMap<Uuid, (String, AttestedPasskeyV4)>> {
385 debug_assert!(false);
386 None
387 }
388
389 fn as_webauthn_attestation_ca_list(&self) -> Option<&AttestationCaList> {
390 debug_assert!(false);
391 None
392 }
393
394 fn as_oauthclaim_map(&self) -> Option<&BTreeMap<String, OauthClaimMapping>> {
395 None
396 }
397
398 fn as_key_internal_map(&self) -> Option<&BTreeMap<KeyId, KeyInternalData>> {
399 debug_assert!(false);
400 None
401 }
402
403 fn as_hexstring_set(&self) -> Option<&BTreeSet<String>> {
404 debug_assert!(false);
405 None
406 }
407
408 fn as_application_password_map(&self) -> Option<&BTreeMap<Uuid, Vec<ApplicationPassword>>> {
409 debug_assert!(false);
410 None
411 }
412
413 fn to_value_single(&self) -> Option<Value> {
414 if self.len() != 1 {
415 None
416 } else {
417 self.to_value_iter().take(1).next()
418 }
419 }
420
421 fn to_proto_string_single(&self) -> Option<String> {
422 if self.len() != 1 {
423 None
424 } else {
425 self.to_proto_string_clone_iter().take(1).next()
426 }
427 }
428
429 fn to_uuid_single(&self) -> Option<Uuid> {
430 error!("to_uuid_single should not be called on {:?}", self.syntax());
431 None
432 }
433
434 fn to_cid_single(&self) -> Option<Cid> {
435 error!("to_cid_single should not be called on {:?}", self.syntax());
436 None
437 }
438
439 fn to_refer_single(&self) -> Option<Uuid> {
440 error!(
441 "to_refer_single should not be called on {:?}",
442 self.syntax()
443 );
444 debug_assert!(false);
445 None
446 }
447
448 fn to_bool_single(&self) -> Option<bool> {
449 error!("to_bool_single should not be called on {:?}", self.syntax());
450 None
451 }
452
453 fn to_uint32_single(&self) -> Option<u32> {
454 error!(
455 "to_uint32_single should not be called on {:?}",
456 self.syntax()
457 );
458 debug_assert!(false);
459 None
460 }
461
462 fn to_syntaxtype_single(&self) -> Option<SyntaxType> {
463 error!(
464 "to_syntaxtype_single should not be called on {:?}",
465 self.syntax()
466 );
467 None
468 }
469
470 fn to_credential_single(&self) -> Option<&Credential> {
471 error!(
472 "to_credential_single should not be called on {:?}",
473 self.syntax()
474 );
475 debug_assert!(false);
476 None
477 }
478
479 fn to_secret_single(&self) -> Option<&str> {
480 error!(
481 "to_secret_single should not be called on {:?}",
482 self.syntax()
483 );
484 debug_assert!(false);
485 None
486 }
487
488 fn to_restricted_string_single(&self) -> Option<&str> {
489 error!(
490 "to_restricted_string_single should not be called on {:?}",
491 self.syntax()
492 );
493 debug_assert!(false);
494 None
495 }
496
497 fn to_utf8_single(&self) -> Option<&str> {
498 error!("to_utf8_single should not be called on {:?}", self.syntax());
499 debug_assert!(false);
500 None
501 }
502
503 fn to_iutf8_single(&self) -> Option<&str> {
504 error!(
505 "to_iutf8_single should not be called on {:?}",
506 self.syntax()
507 );
508 debug_assert!(false);
509 None
510 }
511
512 fn to_iname_single(&self) -> Option<&str> {
513 error!(
514 "to_iname_single should not be called on {:?}",
515 self.syntax()
516 );
517 debug_assert!(false);
518 None
519 }
520
521 fn to_datetime_single(&self) -> Option<OffsetDateTime> {
522 error!(
523 "to_datetime_single should not be called on {:?}",
524 self.syntax()
525 );
526 debug_assert!(false);
527 None
528 }
529
530 fn to_url_single(&self) -> Option<&Url> {
531 error!("to_url_single should not be called on {:?}", self.syntax());
532 debug_assert!(false);
533 None
534 }
535
536 fn to_json_filter_single(&self) -> Option<&ProtoFilter> {
537 error!(
538 "to_json_filter_single should not be called on {:?}",
539 self.syntax()
540 );
541 None
543 }
544
545 fn to_email_address_primary_str(&self) -> Option<&str> {
546 debug_assert!(false);
547 None
548 }
549
550 fn to_private_binary_single(&self) -> Option<&[u8]> {
551 debug_assert!(false);
552 None
553 }
554
555 fn to_passkey_single(&self) -> Option<&PasskeyV4> {
556 debug_assert!(false);
557 None
558 }
559
560 fn as_session_map(&self) -> Option<&BTreeMap<Uuid, Session>> {
561 debug_assert!(false);
562 None
563 }
564
565 fn as_apitoken_map(&self) -> Option<&BTreeMap<Uuid, ApiToken>> {
566 debug_assert!(false);
567 None
568 }
569
570 fn as_oauth2session_map(&self) -> Option<&BTreeMap<Uuid, Oauth2Session>> {
571 debug_assert!(false);
572 None
573 }
574
575 fn to_jws_key_es256_single(&self) -> Option<&JwsEs256Signer> {
576 debug_assert!(false);
577 None
578 }
579
580 fn to_eckey_private_single(&self) -> Option<&EcKey<Private>> {
581 debug_assert!(false);
582 None
583 }
584
585 fn to_eckey_public_single(&self) -> Option<&EcKey<Public>> {
586 debug_assert!(false);
587 None
588 }
589
590 fn as_jws_key_es256_set(&self) -> Option<&HashSet<JwsEs256Signer>> {
591 debug_assert!(false);
592 None
593 }
594
595 fn to_jws_key_rs256_single(&self) -> Option<&JwsRs256Signer> {
596 debug_assert!(false);
597 None
598 }
599
600 fn as_jws_key_rs256_set(&self) -> Option<&HashSet<JwsRs256Signer>> {
601 debug_assert!(false);
602 None
603 }
604
605 fn as_uihint_set(&self) -> Option<&BTreeSet<UiHint>> {
606 debug_assert!(false);
607 None
608 }
609
610 fn as_uihint_iter(&self) -> Option<Box<dyn Iterator<Item = UiHint> + '_>> {
611 debug_assert!(false);
612 None
613 }
614
615 fn as_audit_log_string(&self) -> Option<&BTreeMap<Cid, String>> {
616 debug_assert!(false);
617 None
618 }
619
620 fn as_ec_key_private(&self) -> Option<&EcKey<Private>> {
621 debug_assert!(false);
622 None
623 }
624
625 fn as_imageset(&self) -> Option<&HashSet<ImageValue>> {
626 debug_assert!(false);
627 None
628 }
629
630 fn to_credentialtype_single(&self) -> Option<CredentialType> {
631 debug_assert!(false);
632 None
633 }
634
635 fn as_credentialtype_set(&self) -> Option<&SmolSet<[CredentialType; 1]>> {
636 debug_assert!(false);
637 None
638 }
639
640 fn to_certificate_single(&self) -> Option<&Certificate> {
641 debug_assert!(false);
642 None
643 }
644
645 fn as_certificate_set(&self) -> Option<&BTreeMap<Sha256Digest, Box<Certificate>>> {
646 debug_assert!(false);
647 None
648 }
649
650 fn repl_merge_valueset(
651 &self,
652 _older: &ValueSet,
653 _trim_cid: &Cid, ) -> Option<ValueSet> {
655 None
671 }
672}
673
674pub trait ValueSetScimPut {
675 fn from_scim_json_put(value: JsonValue) -> Result<ValueSetResolveStatus, OperationError>;
676}
677
678impl PartialEq for ValueSet {
679 fn eq(&self, other: &ValueSet) -> bool {
680 self.equal(other)
681 }
682}
683
684pub struct UnresolvedScimValueOauth2ClaimMap {
685 pub group_uuid: Uuid,
686 pub claim: String,
687 pub join_char: ScimOauth2ClaimMapJoinChar,
688 pub values: BTreeSet<String>,
689}
690
691pub struct UnresolvedScimValueOauth2ScopeMap {
692 pub group_uuid: Uuid,
693 pub scopes: BTreeSet<String>,
694}
695
696pub enum ScimValueIntermediate {
697 References(Vec<Uuid>),
698 Oauth2ClaimMap(Vec<UnresolvedScimValueOauth2ClaimMap>),
699 Oauth2ScopeMap(Vec<UnresolvedScimValueOauth2ScopeMap>),
700}
701
702pub enum ScimResolveStatus {
703 Resolved(ScimValueKanidm),
704 NeedsResolution(ScimValueIntermediate),
705}
706
707impl<T> From<T> for ScimResolveStatus
708where
709 T: Into<ScimValueKanidm>,
710{
711 fn from(v: T) -> Self {
712 Self::Resolved(v.into())
713 }
714}
715
716#[cfg(test)]
717impl ScimResolveStatus {
718 pub fn assume_resolved(self) -> ScimValueKanidm {
719 match self {
720 ScimResolveStatus::Resolved(v) => v,
721 ScimResolveStatus::NeedsResolution(_) => {
722 panic!("assume_resolved called on NeedsResolution")
723 }
724 }
725 }
726
727 pub fn assume_unresolved(self) -> ScimValueIntermediate {
728 match self {
729 ScimResolveStatus::Resolved(_) => panic!("assume_unresolved called on Resolved"),
730 ScimResolveStatus::NeedsResolution(svi) => svi,
731 }
732 }
733}
734
735pub enum ValueSetResolveStatus {
736 Resolved(ValueSet),
737 NeedsResolution(ValueSetIntermediate),
738}
739
740#[cfg(test)]
741impl ValueSetResolveStatus {
742 pub fn assume_resolved(self) -> ValueSet {
743 match self {
744 ValueSetResolveStatus::Resolved(v) => v,
745 ValueSetResolveStatus::NeedsResolution(_) => {
746 panic!("assume_resolved called on NeedsResolution")
747 }
748 }
749 }
750
751 pub fn assume_unresolved(self) -> ValueSetIntermediate {
752 match self {
753 ValueSetResolveStatus::Resolved(_) => panic!("assume_unresolved called on Resolved"),
754 ValueSetResolveStatus::NeedsResolution(svi) => svi,
755 }
756 }
757}
758
759pub enum ValueSetIntermediate {
760 References {
761 resolved: BTreeSet<Uuid>,
762 unresolved: Vec<String>,
763 },
764 Oauth2ClaimMap {
765 resolved: Vec<ResolvedValueSetOauth2ClaimMap>,
766 unresolved: Vec<UnresolvedValueSetOauth2ClaimMap>,
767 },
768 Oauth2ScopeMap {
769 resolved: Vec<ResolvedValueSetOauth2ScopeMap>,
770 unresolved: Vec<UnresolvedValueSetOauth2ScopeMap>,
771 },
772}
773
774pub struct UnresolvedValueSetOauth2ClaimMap {
775 pub group_name: String,
776 pub claim: String,
777 pub join_char: OauthClaimMapJoin,
778 pub claim_values: BTreeSet<String>,
779}
780
781pub struct ResolvedValueSetOauth2ClaimMap {
782 pub group_uuid: Uuid,
783 pub claim: String,
784 pub join_char: OauthClaimMapJoin,
785 pub claim_values: BTreeSet<String>,
786}
787
788pub struct UnresolvedValueSetOauth2ScopeMap {
789 pub group_name: String,
790 pub scopes: BTreeSet<String>,
791}
792
793pub struct ResolvedValueSetOauth2ScopeMap {
794 pub group_uuid: Uuid,
795 pub scopes: BTreeSet<String>,
796}
797
798pub fn uuid_to_proto_string(u: Uuid) -> String {
799 u.as_hyphenated().to_string()
800}
801
802pub fn from_result_value_iter(
803 mut iter: impl Iterator<Item = Result<Value, OperationError>>,
804) -> Result<ValueSet, OperationError> {
805 let Some(init) = iter.next() else {
806 trace!("Empty value iterator");
807 return Err(OperationError::InvalidValueState);
808 };
809
810 let init = init?;
811
812 let mut vs: ValueSet = match init {
813 Value::Utf8(s) => ValueSetUtf8::new(s),
814 Value::Iutf8(s) => ValueSetIutf8::new(&s),
815 Value::Iname(s) => ValueSetIname::new(&s),
816 Value::Uuid(u) => ValueSetUuid::new(u),
817 Value::Refer(u) => ValueSetRefer::new(u),
818 Value::Bool(u) => ValueSetBool::new(u),
819 Value::Uint32(u) => ValueSetUint32::new(u),
820 Value::Syntax(u) => ValueSetSyntax::new(u),
821 Value::Index(u) => ValueSetIndex::new(u),
822 Value::SecretValue(u) => ValueSetSecret::new(u),
823 Value::RestrictedString(u) => ValueSetRestricted::new(u),
824 Value::Spn(n, d) => ValueSetSpn::new((n, d)),
825 Value::Cid(u) => ValueSetCid::new(u),
826 Value::JsonFilt(u) => ValueSetJsonFilter::new(u),
827 Value::Nsuniqueid(u) => ValueSetNsUniqueId::new(u),
828 Value::Url(u) => ValueSetUrl::new(u),
829 Value::DateTime(u) => ValueSetDateTime::new(u),
830 Value::PrivateBinary(u) => ValueSetPrivateBinary::new(u),
831 Value::OauthScope(u) => ValueSetOauthScope::new(u),
832 Value::Address(u) => ValueSetAddress::new(u),
833 Value::Cred(t, c) => ValueSetCredential::new(t, c),
834 Value::SshKey(t, k) => ValueSetSshKey::new(t, k),
835 Value::OauthScopeMap(u, m) => ValueSetOauthScopeMap::new(u, m),
836 Value::PublicBinary(t, b) => ValueSetPublicBinary::new(t, b),
837 Value::IntentToken(u, s) => ValueSetIntentToken::new(u, s),
838 Value::EmailAddress(a, _) => ValueSetEmailAddress::new(a),
839 Value::UiHint(u) => ValueSetUiHint::new(u),
840 Value::AuditLogString(c, s) => ValueSetAuditLogString::new((c, s)),
841 Value::EcKeyPrivate(k) => ValueSetEcKeyPrivate::new(&k),
842 Value::Image(imagevalue) => image::ValueSetImage::new(imagevalue),
843 Value::CredentialType(c) => ValueSetCredentialType::new(c),
844 Value::Certificate(c) => ValueSetCertificate::new(c)?,
845 Value::WebauthnAttestationCaList(_)
846 | Value::PhoneNumber(_, _)
847 | Value::ApplicationPassword(_)
848 | Value::Passkey(_, _, _)
849 | Value::AttestedPasskey(_, _, _)
850 | Value::TotpSecret(_, _)
851 | Value::Session(_, _)
852 | Value::ApiToken(_, _)
853 | Value::Oauth2Session(_, _)
854 | Value::OauthClaimMap(_, _)
855 | Value::OauthClaimValue(_, _, _)
856 | Value::JwsKeyEs256(_)
857 | Value::JwsKeyRs256(_)
858 | Value::HexString(_)
859 | Value::KeyInternal { .. } => {
860 debug_assert!(false);
861 return Err(OperationError::InvalidValueState);
862 }
863 };
864
865 for maybe_v in iter {
866 let v = maybe_v?;
867 vs.insert_checked(v)?;
869 }
870 Ok(vs)
871}
872
873pub fn from_value_iter(mut iter: impl Iterator<Item = Value>) -> Result<ValueSet, OperationError> {
874 let Some(init) = iter.next() else {
875 trace!("Empty value iterator");
876 return Err(OperationError::InvalidValueState);
877 };
878
879 let mut vs: ValueSet = match init {
880 Value::Utf8(s) => ValueSetUtf8::new(s),
881 Value::Iutf8(s) => ValueSetIutf8::new(&s),
882 Value::Iname(s) => ValueSetIname::new(&s),
883 Value::Uuid(u) => ValueSetUuid::new(u),
884 Value::Refer(u) => ValueSetRefer::new(u),
885 Value::Bool(u) => ValueSetBool::new(u),
886 Value::Uint32(u) => ValueSetUint32::new(u),
887 Value::Syntax(u) => ValueSetSyntax::new(u),
888 Value::Index(u) => ValueSetIndex::new(u),
889 Value::SecretValue(u) => ValueSetSecret::new(u),
890 Value::RestrictedString(u) => ValueSetRestricted::new(u),
891 Value::Spn(n, d) => ValueSetSpn::new((n, d)),
892 Value::Cid(u) => ValueSetCid::new(u),
893 Value::JsonFilt(u) => ValueSetJsonFilter::new(u),
894 Value::Nsuniqueid(u) => ValueSetNsUniqueId::new(u),
895 Value::Url(u) => ValueSetUrl::new(u),
896 Value::DateTime(u) => ValueSetDateTime::new(u),
897 Value::PrivateBinary(u) => ValueSetPrivateBinary::new(u),
898 Value::OauthScope(u) => ValueSetOauthScope::new(u),
899 Value::Address(u) => ValueSetAddress::new(u),
900 Value::Cred(t, c) => ValueSetCredential::new(t, c),
901 Value::SshKey(t, k) => ValueSetSshKey::new(t, k),
902 Value::OauthScopeMap(u, m) => ValueSetOauthScopeMap::new(u, m),
903 Value::PublicBinary(t, b) => ValueSetPublicBinary::new(t, b),
904 Value::IntentToken(u, s) => ValueSetIntentToken::new(u, s),
905 Value::EmailAddress(a, _) => ValueSetEmailAddress::new(a),
906 Value::Passkey(u, t, k) => ValueSetPasskey::new(u, t, k),
907 Value::AttestedPasskey(u, t, k) => ValueSetAttestedPasskey::new(u, t, k),
908 Value::JwsKeyEs256(k) => ValueSetJwsKeyEs256::new(k),
909 Value::JwsKeyRs256(k) => ValueSetJwsKeyRs256::new(k),
910 Value::Session(u, m) => ValueSetSession::new(u, m),
911 Value::ApiToken(u, m) => ValueSetApiToken::new(u, m),
912 Value::Oauth2Session(u, m) => ValueSetOauth2Session::new(u, m),
913 Value::UiHint(u) => ValueSetUiHint::new(u),
914 Value::TotpSecret(l, t) => ValueSetTotpSecret::new(l, t),
915 Value::AuditLogString(c, s) => ValueSetAuditLogString::new((c, s)),
916 Value::EcKeyPrivate(k) => ValueSetEcKeyPrivate::new(&k),
917 Value::Image(imagevalue) => image::ValueSetImage::new(imagevalue),
918 Value::CredentialType(c) => ValueSetCredentialType::new(c),
919 Value::WebauthnAttestationCaList(ca_list) => {
920 ValueSetWebauthnAttestationCaList::new(ca_list)
921 }
922 Value::OauthClaimMap(name, join) => ValueSetOauthClaimMap::new(name, join),
923 Value::OauthClaimValue(name, group, claims) => {
924 ValueSetOauthClaimMap::new_value(name, group, claims)
925 }
926 Value::HexString(s) => ValueSetHexString::new(s),
927
928 Value::KeyInternal {
929 id,
930 usage,
931 valid_from,
932 status,
933 status_cid,
934 der,
935 } => ValueSetKeyInternal::new(id, usage, valid_from, status, status_cid, der),
936 Value::Certificate(certificate) => ValueSetCertificate::new(certificate)?,
937
938 Value::PhoneNumber(_, _) => {
939 debug_assert!(false);
940 return Err(OperationError::InvalidValueState);
941 }
942 Value::ApplicationPassword(ap) => ValueSetApplicationPassword::new(ap),
943 };
944
945 for v in iter {
946 vs.insert_checked(v)?;
947 }
948 Ok(vs)
949}
950
951pub fn from_db_valueset_v2(dbvs: DbValueSetV2) -> Result<ValueSet, OperationError> {
952 match dbvs {
953 DbValueSetV2::Utf8(set) => ValueSetUtf8::from_dbvs2(set),
954 DbValueSetV2::Iutf8(set) => ValueSetIutf8::from_dbvs2(set),
955 DbValueSetV2::Iname(set) => ValueSetIname::from_dbvs2(set),
956 DbValueSetV2::Uuid(set) => ValueSetUuid::from_dbvs2(set),
957 DbValueSetV2::Reference(set) => ValueSetRefer::from_dbvs2(set),
958 DbValueSetV2::Bool(set) => ValueSetBool::from_dbvs2(set),
959 DbValueSetV2::Uint32(set) => ValueSetUint32::from_dbvs2(set),
960 DbValueSetV2::SyntaxType(set) => ValueSetSyntax::from_dbvs2(set),
961 DbValueSetV2::IndexType(set) => ValueSetIndex::from_dbvs2(set),
962 DbValueSetV2::SecretValue(set) => ValueSetSecret::from_dbvs2(set),
963 DbValueSetV2::RestrictedString(set) => ValueSetRestricted::from_dbvs2(set),
964 DbValueSetV2::Spn(set) => ValueSetSpn::from_dbvs2(set),
965 DbValueSetV2::Cid(set) => ValueSetCid::from_dbvs2(set),
966 DbValueSetV2::JsonFilter(set) => ValueSetJsonFilter::from_dbvs2(&set),
967 DbValueSetV2::NsUniqueId(set) => ValueSetNsUniqueId::from_dbvs2(set),
968 DbValueSetV2::Url(set) => ValueSetUrl::from_dbvs2(set),
969 DbValueSetV2::DateTime(set) => ValueSetDateTime::from_dbvs2(set),
970 DbValueSetV2::PrivateBinary(set) => ValueSetPrivateBinary::from_dbvs2(set),
971 DbValueSetV2::OauthScope(set) => ValueSetOauthScope::from_dbvs2(set),
972 DbValueSetV2::Address(set) => ValueSetAddress::from_dbvs2(set),
973 DbValueSetV2::Credential(set) => ValueSetCredential::from_dbvs2(set),
974 DbValueSetV2::SshKey(set) => ValueSetSshKey::from_dbvs2(set),
975 DbValueSetV2::OauthScopeMap(set) => ValueSetOauthScopeMap::from_dbvs2(set),
976 DbValueSetV2::PublicBinary(set) => ValueSetPublicBinary::from_dbvs2(set),
977 DbValueSetV2::IntentToken(set) => ValueSetIntentToken::from_dbvs2(set),
978 DbValueSetV2::EmailAddress(primary, set) => ValueSetEmailAddress::from_dbvs2(primary, set),
979 DbValueSetV2::Passkey(set) => ValueSetPasskey::from_dbvs2(set),
980 DbValueSetV2::AttestedPasskey(set) => ValueSetAttestedPasskey::from_dbvs2(set),
981 DbValueSetV2::Session(set) => ValueSetSession::from_dbvs2(&set),
982 DbValueSetV2::ApiToken(set) => ValueSetApiToken::from_dbvs2(set),
983 DbValueSetV2::Oauth2Session(set) => ValueSetOauth2Session::from_dbvs2(set),
984 DbValueSetV2::JwsKeyEs256(set) => ValueSetJwsKeyEs256::from_dbvs2(&set),
985 DbValueSetV2::JwsKeyRs256(set) => ValueSetJwsKeyEs256::from_dbvs2(&set),
986 DbValueSetV2::UiHint(set) => ValueSetUiHint::from_dbvs2(set),
987 DbValueSetV2::TotpSecret(set) => ValueSetTotpSecret::from_dbvs2(set),
988 DbValueSetV2::AuditLogString(set) => ValueSetAuditLogString::from_dbvs2(set),
989 DbValueSetV2::EcKeyPrivate(key) => ValueSetEcKeyPrivate::from_dbvs2(&key),
990 DbValueSetV2::PhoneNumber(_, _) | DbValueSetV2::TrustedDeviceEnrollment(_) => {
991 debug_assert!(false);
992 Err(OperationError::InvalidValueState)
993 }
994 DbValueSetV2::Image(set) => ValueSetImage::from_dbvs2(&set),
995 DbValueSetV2::CredentialType(set) => ValueSetCredentialType::from_dbvs2(set),
996 DbValueSetV2::WebauthnAttestationCaList { ca_list } => {
997 ValueSetWebauthnAttestationCaList::from_dbvs2(ca_list)
998 }
999 DbValueSetV2::OauthClaimMap(set) => ValueSetOauthClaimMap::from_dbvs2(set),
1000 DbValueSetV2::KeyInternal(set) => ValueSetKeyInternal::from_dbvs2(set),
1001 DbValueSetV2::HexString(set) => ValueSetHexString::from_dbvs2(set),
1002 DbValueSetV2::Certificate(set) => ValueSetCertificate::from_dbvs2(set),
1003 DbValueSetV2::ApplicationPassword(set) => ValueSetApplicationPassword::from_dbvs2(set),
1004 }
1005}
1006
1007#[cfg(test)]
1008pub(crate) fn scim_json_reflexive(vs: &ValueSet, data: &str) {
1009 let scim_value = vs.to_scim_value().unwrap().assume_resolved();
1010
1011 let strout = serde_json::to_string_pretty(&scim_value).unwrap();
1012 eprintln!("{strout}");
1013
1014 let json_value: serde_json::Value = serde_json::to_value(&scim_value).unwrap();
1015
1016 eprintln!("{data}");
1017 let expect: serde_json::Value = serde_json::from_str(data).unwrap();
1018
1019 assert_eq!(json_value, expect);
1020}
1021
1022#[cfg(test)]
1023pub(crate) fn scim_json_reflexive_unresolved(
1024 write_txn: &mut QueryServerWriteTransaction,
1025 vs: &ValueSet,
1026 data: &str,
1027) {
1028 let scim_int_value = vs.to_scim_value().unwrap().assume_unresolved();
1029 let scim_value = write_txn.resolve_scim_interim(scim_int_value).unwrap();
1030
1031 let strout = serde_json::to_string_pretty(&scim_value).expect("Failed to serialize");
1032 eprintln!("{strout}");
1033
1034 let json_value: serde_json::Value =
1035 serde_json::to_value(&scim_value).expect("Failed to convert to JSON");
1036
1037 let expect: serde_json::Value =
1038 serde_json::from_str(data).expect("Failed to parse expected JSON");
1039
1040 assert_eq!(json_value, expect);
1041}
1042
1043#[cfg(test)]
1044pub(crate) fn scim_json_put_reflexive<T: ValueSetScimPut>(
1045 expect_vs: &ValueSet,
1046 additional_tests: &[(JsonValue, ValueSet)],
1047) {
1048 let scim_value = expect_vs.to_scim_value().unwrap().assume_resolved();
1049
1050 let strout = serde_json::to_string_pretty(&scim_value).unwrap();
1051 eprintln!("{strout}");
1052
1053 let generic = serde_json::to_value(scim_value).unwrap();
1054 let vs = T::from_scim_json_put(generic).unwrap().assume_resolved();
1056 assert_eq!(&vs, expect_vs);
1057
1058 for (jv, expect_vs) in additional_tests {
1060 let vs = T::from_scim_json_put(jv.clone()).unwrap().assume_resolved();
1061 assert_eq!(&vs, expect_vs);
1062 }
1063}
1064
1065#[cfg(test)]
1066pub(crate) fn scim_json_put_reflexive_unresolved<T: ValueSetScimPut>(
1067 write_txn: &mut QueryServerWriteTransaction,
1068 expect_vs: &ValueSet,
1069 additional_tests: &[(JsonValue, ValueSet)],
1070) {
1071 let scim_int_value = expect_vs.to_scim_value().unwrap().assume_unresolved();
1072 let scim_value = write_txn.resolve_scim_interim(scim_int_value).unwrap();
1073
1074 let generic = serde_json::to_value(scim_value).unwrap();
1075 let vs_inter = T::from_scim_json_put(generic).unwrap().assume_unresolved();
1077 let vs = write_txn.resolve_valueset_intermediate(vs_inter).unwrap();
1078 assert_eq!(&vs, expect_vs);
1079
1080 for (jv, expect_vs) in additional_tests {
1082 let vs_inter = T::from_scim_json_put(jv.clone())
1083 .unwrap()
1084 .assume_unresolved();
1085 let vs = write_txn.resolve_valueset_intermediate(vs_inter).unwrap();
1086 assert_eq!(&vs, expect_vs);
1087 }
1088}