kanidm_proto/internal/
error.rs

1use std::fmt::{Display, Formatter};
2
3use serde::{Deserialize, Serialize};
4use utoipa::ToSchema;
5use uuid::Uuid;
6
7use super::credupdate::PasswordFeedback;
8use crate::attribute::Attribute;
9
10/* ===== errors ===== */
11#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, ToSchema)]
12#[serde(rename_all = "lowercase")]
13pub enum SchemaError {
14    NotImplemented,
15    NoClassFound,
16    InvalidClass(Vec<String>),
17    MissingMustAttribute(Vec<Attribute>),
18    InvalidAttribute(String),
19    InvalidAttributeSyntax(String),
20    AttributeNotValidForClass(String),
21    SupplementsNotSatisfied(Vec<String>),
22    ExcludesNotSatisfied(Vec<String>),
23    EmptyFilter,
24    Corrupted,
25    PhantomAttribute(String),
26}
27
28#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, ToSchema)]
29#[serde(rename_all = "lowercase")]
30pub enum PluginError {
31    AttrUnique(String),
32    Base(String),
33    ReferentialIntegrity(String),
34    CredImport(String),
35    Oauth2Secrets,
36}
37
38#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, ToSchema)]
39#[serde(rename_all = "lowercase")]
40pub enum ConsistencyError {
41    Unknown,
42    // Class, Attribute
43    SchemaClassMissingAttribute(String, String),
44    SchemaClassPhantomAttribute(String, String),
45    SchemaUuidNotUnique(Uuid),
46    QueryServerSearchFailure,
47    EntryUuidCorrupt(u64),
48    UuidIndexCorrupt(String),
49    UuidNotUnique(String),
50    RefintNotUpheld(u64),
51    MemberOfInvalid(u64),
52    InvalidAttributeType(String),
53    DuplicateUniqueAttribute,
54    InvalidSpn(u64),
55    SqliteIntegrityFailure,
56    BackendAllIdsSync,
57    BackendIndexSync,
58    ChangelogDesynchronised(u64),
59    ChangeStateDesynchronised(u64),
60    RuvInconsistent(String),
61    DeniedName(Uuid),
62    KeyProviderUuidMissing { key_object: Uuid },
63    KeyProviderNoKeys { key_object: Uuid },
64    KeyProviderNotFound { key_object: Uuid, provider: Uuid },
65}
66
67#[derive(Serialize, Deserialize, Debug, ToSchema)]
68#[serde(rename_all = "lowercase")]
69pub enum OperationError {
70    // Logic errors, or "soft" errors.
71    SessionExpired,
72    DuplicateKey,
73    DuplicateLabel,
74    EmptyRequest,
75    Backend,
76    NoMatchingEntries,
77    NoMatchingAttributes,
78    UniqueConstraintViolation,
79    CorruptedEntry(u64),
80    CorruptedIndex(String),
81    ConsistencyError(Vec<ConsistencyError>),
82    SchemaViolation(SchemaError),
83    Plugin(PluginError),
84    FilterGeneration,
85    FilterParseError,
86    FilterUuidResolution,
87    InvalidAttributeName(String),
88    InvalidAttribute(String),
89    InvalidLabel,
90    InvalidDbState,
91    InvalidCacheState,
92    InvalidValueState,
93    InvalidEntryId,
94    InvalidRequestState,
95    InvalidSyncState,
96    InvalidState,
97    InvalidEntryState,
98    InvalidUuid,
99    InvalidReplChangeId,
100    InvalidAcpState(String),
101    InvalidSchemaState(String),
102    InvalidAccountState(String),
103    // This really oughta be EntryClass but its not in proto...
104    // It should at least be &'static str but we
105    // Serialize & Deserialize this enum...
106    MissingClass(String),
107    MissingAttribute(Attribute),
108    MissingEntries,
109    ModifyAssertionFailed,
110    BackendEngine,
111    SqliteError, //(RusqliteError)
112    FsError,
113    SerdeJsonError,
114    SerdeCborError,
115    AccessDenied,
116    NotAuthenticated,
117    NotAuthorised,
118    InvalidAuthState(String),
119    InvalidSessionState,
120    SystemProtectedObject,
121    SystemProtectedAttribute,
122    PasswordQuality(Vec<PasswordFeedback>),
123    CryptographyError,
124    ResourceLimit,
125    QueueDisconnected,
126    Webauthn,
127    #[serde(with = "time::serde::timestamp")]
128    Wait(time::OffsetDateTime),
129    ReplReplayFailure,
130    ReplEntryNotChanged,
131    ReplInvalidRUVState,
132    ReplDomainLevelUnsatisfiable,
133    ReplDomainUuidMismatch,
134    ReplServerUuidSplitDataState,
135    TransactionAlreadyCommitted,
136    CannotStartMFADuringOngoingMFASession,
137    /// when you ask for a gid that overlaps a system reserved range
138    /// When a name is denied by the system config
139    ValueDenyName,
140    /// When the DB is potentially over-loaded a timeout can occur starting
141    /// your operation.
142    DatabaseLockAcquisitionTimeout,
143
144    // Specific internal errors.
145    AU0001InvalidState,
146    AU0002JwsSerialisation,
147    AU0003JwsSignature,
148    AU0004UserAuthTokenInvalid,
149    AU0005DelayedProcessFailure,
150    AU0006CredentialMayNotReauthenticate,
151    AU0007UserAuthTokenInvalid,
152
153    // Kanidm Generic Errors
154    KG001TaskTimeout,
155    KG002TaskCommFailure,
156    KG003CacheClearFailed,
157
158    // Credential Update Errors
159    CU0001WebauthnAttestationNotTrusted,
160    CU0002WebauthnRegistrationError,
161    CU0003WebauthnUserNotVerified,
162
163    // The session is inconsistent and can't be committed, but the errors
164    // can be resolved.
165    CU0004SessionInconsistent,
166    // Another session used this intent token, and so it can't be committed.
167    CU0005IntentTokenConflict,
168    // The intent token was invalidated before we could commit.
169    CU0006IntentTokenInvalidated,
170
171    // ValueSet errors
172    VS0001IncomingReplSshPublicKey,
173    VS0002CertificatePublicKeyDigest,
174    VS0003CertificateDerDecode,
175    VS0004CertificatePublicKeyDigest,
176    VS0005CertificatePublicKeyDigest,
177    // Value Errors
178    VL0001ValueSshPublicKeyString,
179
180    // LDAP Errors
181    LD0001AnonymousNotAllowed,
182
183    // DB low level errors.
184    DB0001MismatchedRestoreVersion,
185    DB0002MismatchedRestoreVersion,
186    DB0003FilterResolveCacheBuild,
187    DB0004DatabaseTooOld,
188
189    // SCIM
190    SC0001IncomingSshPublicKey,
191    SC0002ReferenceSyntaxInvalid,
192    SC0003MailSyntaxInvalid,
193    SC0004UuidSyntaxInvalid,
194    SC0005BoolSyntaxInvalid,
195    SC0006Uint32SyntaxInvalid,
196    SC0007UrlSyntaxInvalid,
197    SC0008SyntaxTypeSyntaxInvalid,
198    SC0009IndexTypeSyntaxInvalid,
199    SC0010DateTimeSyntaxInvalid,
200    SC0011AddressSyntaxInvalid,
201    SC0012CertificateSyntaxInvalid,
202    SC0013CertificateInvalidDer,
203    SC0014CertificateInvalidDigest,
204    SC0015CredentialTypeSyntaxInvalid,
205    SC0016InameSyntaxInvalid,
206    SC0017Iutf8SyntaxInvalid,
207    SC0018NsUniqueIdSyntaxInvalid,
208    SC0019Oauth2ScopeSyntaxInvalid,
209    SC0020Oauth2ScopeMapSyntaxInvalid,
210    SC0021Oauth2ScopeMapMissingGroupIdentifier,
211    SC0022Oauth2ClaimMapSyntaxInvalid,
212    SC0023Oauth2ClaimMapMissingGroupIdentifier,
213    SC0024SshPublicKeySyntaxInvalid,
214    SC0025UiHintSyntaxInvalid,
215    SC0026Utf8SyntaxInvalid,
216    SC0027ClassSetInvalid,
217    SC0028CreatedUuidsInvalid,
218    // Migration
219    MG0001InvalidReMigrationLevel,
220    MG0002RaiseDomainLevelExceedsMaximum,
221    MG0003ServerPhaseInvalidForMigration,
222    MG0004DomainLevelInDevelopment,
223    MG0005GidConstraintsNotMet,
224    MG0006SKConstraintsNotMet,
225    MG0007Oauth2StrictConstraintsNotMet,
226    MG0008SkipUpgradeAttempted,
227    MG0009InvalidTargetLevelForBootstrap,
228    //
229    KP0001KeyProviderNotLoaded,
230    KP0002KeyProviderInvalidClass,
231    KP0003KeyProviderInvalidType,
232    KP0004KeyProviderMissingAttributeName,
233    KP0005KeyProviderDuplicate,
234    KP0006KeyObjectJwtEs256Generation,
235    KP0007KeyProviderDefaultNotAvailable,
236    KP0008KeyObjectMissingUuid,
237    KP0009KeyObjectPrivateToDer,
238    KP0010KeyObjectSignerToVerifier,
239    KP0011KeyObjectMissingClass,
240    KP0012KeyObjectMissingProvider,
241    KP0012KeyProviderNotLoaded,
242    KP0013KeyObjectJwsEs256DerInvalid,
243    KP0014KeyObjectSignerToVerifier,
244    KP0015KeyObjectJwsEs256DerInvalid,
245    KP0016KeyObjectJwsEs256DerInvalid,
246    KP0017KeyProviderNoSuchKey,
247    KP0018KeyProviderNoSuchKey,
248    KP0019KeyProviderUnsupportedAlgorithm,
249    KP0020KeyObjectNoActiveSigningKeys,
250    KP0021KeyObjectJwsEs256Signature,
251    KP0022KeyObjectJwsNotAssociated,
252    KP0023KeyObjectJwsKeyRevoked,
253    KP0024KeyObjectJwsInvalid,
254    KP0025KeyProviderNotAvailable,
255    KP0026KeyObjectNoSuchKey,
256    KP0027KeyObjectPublicToDer,
257    KP0028KeyObjectImportJwsEs256DerInvalid,
258    KP0029KeyObjectSignerToVerifier,
259    KP0030KeyObjectPublicToDer,
260    KP0031KeyObjectNotFound,
261    KP0032KeyProviderNoSuchKey,
262    KP0033KeyProviderNoSuchKey,
263    KP0034KeyProviderUnsupportedAlgorithm,
264    KP0035KeyObjectJweA128GCMGeneration,
265    KP0036KeyObjectPrivateToBytes,
266    KP0037KeyObjectImportJweA128GCMInvalid,
267    KP0038KeyObjectImportJweA128GCMInvalid,
268    KP0039KeyObjectJweNotAssociated,
269    KP0040KeyObjectJweInvalid,
270    KP0041KeyObjectJweRevoked,
271    KP0042KeyObjectNoActiveEncryptionKeys,
272    KP0043KeyObjectJweA128GCMEncryption,
273    KP0044KeyObjectJwsPublicJwk,
274
275    KP0045KeyObjectImportJwsRs256DerInvalid,
276    KP0046KeyObjectSignerToVerifier,
277    KP0047KeyObjectPublicToDer,
278    KP0048KeyObjectJwtRs256Generation,
279    KP0049KeyObjectSignerToVerifier,
280    KP0050KeyObjectPrivateToDer,
281    KP0051KeyObjectPublicToDer,
282    KP0052KeyObjectJwsRs256DerInvalid,
283    KP0053KeyObjectSignerToVerifier,
284    KP0054KeyObjectJwsRs256DerInvalid,
285    KP0055KeyObjectJwsRs256DerInvalid,
286    KP0056KeyObjectJwsRs256Signature,
287    KP0057KeyObjectJwsNotAssociated,
288    KP0058KeyObjectJwsInvalid,
289    KP0059KeyObjectJwsKeyRevoked,
290    KP0060KeyObjectJwsPublicJwk,
291    KP0061KeyObjectNoActiveSigningKeys,
292    KP0062KeyProviderNoSuchKey,
293
294    // Plugins
295    PL0001GidOverlapsSystemRange,
296
297    // Web UI
298    UI0001ChallengeSerialisation,
299    UI0002InvalidState,
300    UI0003InvalidOauth2Resume,
301
302    // Unixd Things
303    KU001InitWhileSessionActive,
304    KU002ContinueWhileSessionInActive,
305    KU003PamAuthFailed,
306    KU004PamInitFailed,
307    KU005ErrorCheckingAccount,
308    KU006OnlyRootAllowed,
309}
310
311impl PartialEq for OperationError {
312    fn eq(&self, other: &Self) -> bool {
313        // We do this to avoid InvalidPassword being checked as it's not
314        // derive PartialEq. Generally we only use the PartialEq for TESTING
315        // anyway.
316        std::mem::discriminant(self) == std::mem::discriminant(other)
317    }
318}
319
320impl Display for OperationError {
321    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
322        let mut output = format!("{:?}", self)
323            .split("::")
324            .last()
325            .unwrap_or("")
326            .to_string();
327
328        if let Some(msg) = self.message() {
329            output += &format!(" - {}", msg);
330        };
331        f.write_str(&output)
332    }
333}
334
335impl OperationError {
336    /// Return the message associated with the error if there is one.
337    pub fn message(&self) -> Option<String> {
338        match self {
339            Self::SessionExpired => None,
340            Self::EmptyRequest => None,
341            Self::Backend => None,
342            Self::NoMatchingEntries => None,
343            Self::NoMatchingAttributes => None,
344            Self::UniqueConstraintViolation => Some("A unique constraint was violated resulting in multiple conflicting results.".into()),
345            Self::CorruptedEntry(_) => None,
346            Self::CorruptedIndex(_) => None,
347            Self::ConsistencyError(_) => None,
348            Self::SchemaViolation(_) => None,
349            Self::Plugin(_) => None,
350            Self::FilterGeneration => None,
351            Self::FilterParseError => None,
352            Self::FilterUuidResolution => None,
353            Self::InvalidAttributeName(_) => None,
354            Self::InvalidAttribute(_) => None,
355            Self::InvalidLabel => Some("The submitted label for this item is invalid.".into()),
356            Self::DuplicateLabel => Some("The submitted label for this item is already in use.".into()),
357            Self::DuplicateKey => Some("The submitted key already exists.".into()),
358            Self::InvalidDbState => None,
359            Self::InvalidCacheState => None,
360            Self::InvalidValueState => None,
361            Self::InvalidEntryId => None,
362            Self::InvalidRequestState => None,
363            Self::InvalidSyncState => None,
364            Self::InvalidState => None,
365            Self::InvalidEntryState => None,
366            Self::InvalidUuid => None,
367            Self::InvalidReplChangeId => None,
368            Self::InvalidAcpState(_) => None,
369            Self::InvalidSchemaState(_) => None,
370            Self::InvalidAccountState(val) => Some(format!("Invalid account state: {}", val)),
371            Self::MissingClass(val) => Some(format!("Missing class: {}", val)),
372            Self::MissingAttribute(val) => Some(format!("Missing attribute: {}", val)),
373            Self::MissingEntries => None,
374            Self::ModifyAssertionFailed => None,
375            Self::BackendEngine => None,
376            Self::SqliteError => None,
377            Self::FsError => None,
378            Self::SerdeJsonError => None,
379            Self::SerdeCborError => None,
380            Self::AccessDenied => None,
381            Self::NotAuthenticated => None,
382            Self::NotAuthorised => None,
383            Self::InvalidAuthState(_) => None,
384            Self::InvalidSessionState => None,
385            Self::SystemProtectedObject => None,
386            Self::SystemProtectedAttribute => None,
387            Self::PasswordQuality(_) => None,
388            Self::CryptographyError => None,
389            Self::ResourceLimit => None,
390            Self::QueueDisconnected => None,
391            Self::Webauthn => None,
392            Self::Wait(_) => None,
393            Self::CannotStartMFADuringOngoingMFASession => Some("Cannot start a new MFA authentication flow when there already is one active.".into()),
394            Self::ReplReplayFailure => None,
395            Self::ReplEntryNotChanged => None,
396            Self::ReplInvalidRUVState => None,
397            Self::ReplDomainLevelUnsatisfiable => None,
398            Self::ReplDomainUuidMismatch => None,
399            Self::ReplServerUuidSplitDataState => None,
400            Self::TransactionAlreadyCommitted => None,
401            Self::ValueDenyName => None,
402            Self::DatabaseLockAcquisitionTimeout => Some("Unable to acquire a database lock - the current server may be too busy. Try again later.".into()),
403
404    Self::AU0001InvalidState => Some("Invalid authentication session state for request".into()),
405    Self::AU0002JwsSerialisation => Some("JWS serialisation failed".into()),
406    Self::AU0003JwsSignature => Some("JWS signature failed".into()),
407    Self::AU0004UserAuthTokenInvalid => Some("User auth token was unable to be generated".into()),
408    Self::AU0005DelayedProcessFailure => Some("Delaying processing failure, unable to proceed".into()),
409    Self::AU0006CredentialMayNotReauthenticate => Some("Credential may not reauthenticate".into()),
410    Self::AU0007UserAuthTokenInvalid => Some("User auth token was unable to be generated".into()),
411
412            Self::CU0001WebauthnAttestationNotTrusted => None,
413            Self::CU0002WebauthnRegistrationError => None,
414            Self::CU0003WebauthnUserNotVerified => Some("User Verification bit not set while registering credential, you may need to configure a PIN on this device.".into()),
415
416            Self::CU0004SessionInconsistent => Some("The session is unable to be committed due to unresolved warnings.".into()),
417            Self::CU0005IntentTokenConflict => Some("The intent token used to create this session has been reused in another browser/tab and may not proceed.".into()),
418            Self::CU0006IntentTokenInvalidated => Some("The intent token has been invalidated/revoked before the commit could be accepted. Has it been used in another browser or tab?".into()),
419
420            Self::DB0001MismatchedRestoreVersion => None,
421            Self::DB0002MismatchedRestoreVersion => None,
422            Self::DB0003FilterResolveCacheBuild => None,
423            Self::DB0004DatabaseTooOld => Some("The database is too old to be migrated.".into()),
424            Self::KG001TaskTimeout => Some("Task timed out".into()),
425            Self::KG002TaskCommFailure => Some("Inter-Task communication failure".into()),
426            Self::KG003CacheClearFailed => Some("Failed to clear cache".into()),
427            Self::KP0001KeyProviderNotLoaded => None,
428            Self::KP0002KeyProviderInvalidClass => None,
429            Self::KP0003KeyProviderInvalidType => None,
430            Self::KP0004KeyProviderMissingAttributeName => None,
431            Self::KP0005KeyProviderDuplicate => None,
432            Self::KP0006KeyObjectJwtEs256Generation => None,
433            Self::KP0007KeyProviderDefaultNotAvailable => None,
434            Self::KP0008KeyObjectMissingUuid => None,
435            Self::KP0009KeyObjectPrivateToDer => None,
436            Self::KP0010KeyObjectSignerToVerifier => None,
437            Self::KP0011KeyObjectMissingClass => None,
438            Self::KP0012KeyObjectMissingProvider => None,
439            Self::KP0012KeyProviderNotLoaded => None,
440            Self::KP0013KeyObjectJwsEs256DerInvalid => None,
441            Self::KP0014KeyObjectSignerToVerifier => None,
442            Self::KP0015KeyObjectJwsEs256DerInvalid => None,
443            Self::KP0016KeyObjectJwsEs256DerInvalid => None,
444            Self::KP0017KeyProviderNoSuchKey => None,
445            Self::KP0018KeyProviderNoSuchKey => None,
446            Self::KP0019KeyProviderUnsupportedAlgorithm => None,
447            Self::KP0020KeyObjectNoActiveSigningKeys => None,
448            Self::KP0021KeyObjectJwsEs256Signature => None,
449            Self::KP0022KeyObjectJwsNotAssociated => None,
450            Self::KP0023KeyObjectJwsKeyRevoked => None,
451            Self::KP0024KeyObjectJwsInvalid => None,
452            Self::KP0025KeyProviderNotAvailable => None,
453            Self::KP0026KeyObjectNoSuchKey => None,
454            Self::KP0027KeyObjectPublicToDer => None,
455            Self::KP0028KeyObjectImportJwsEs256DerInvalid => None,
456            Self::KP0029KeyObjectSignerToVerifier => None,
457            Self::KP0030KeyObjectPublicToDer => None,
458            Self::KP0031KeyObjectNotFound => None,
459            Self::KP0032KeyProviderNoSuchKey => None,
460            Self::KP0033KeyProviderNoSuchKey => None,
461            Self::KP0034KeyProviderUnsupportedAlgorithm => None,
462            Self::KP0035KeyObjectJweA128GCMGeneration => None,
463            Self::KP0036KeyObjectPrivateToBytes => None,
464            Self::KP0037KeyObjectImportJweA128GCMInvalid => None,
465            Self::KP0038KeyObjectImportJweA128GCMInvalid => None,
466            Self::KP0039KeyObjectJweNotAssociated => None,
467            Self::KP0040KeyObjectJweInvalid => None,
468            Self::KP0041KeyObjectJweRevoked => None,
469            Self::KP0042KeyObjectNoActiveEncryptionKeys => None,
470            Self::KP0043KeyObjectJweA128GCMEncryption => None,
471            Self::KP0044KeyObjectJwsPublicJwk => None,
472
473            Self::KP0045KeyObjectImportJwsRs256DerInvalid => None,
474            Self::KP0046KeyObjectSignerToVerifier => None,
475            Self::KP0047KeyObjectPublicToDer => None,
476            Self::KP0048KeyObjectJwtRs256Generation => None,
477            Self::KP0049KeyObjectSignerToVerifier => None,
478            Self::KP0050KeyObjectPrivateToDer => None,
479            Self::KP0051KeyObjectPublicToDer => None,
480            Self::KP0052KeyObjectJwsRs256DerInvalid => None,
481            Self::KP0053KeyObjectSignerToVerifier => None,
482            Self::KP0054KeyObjectJwsRs256DerInvalid => None,
483            Self::KP0055KeyObjectJwsRs256DerInvalid => None,
484            Self::KP0056KeyObjectJwsRs256Signature => None,
485            Self::KP0057KeyObjectJwsNotAssociated => None,
486            Self::KP0058KeyObjectJwsInvalid => None,
487            Self::KP0059KeyObjectJwsKeyRevoked => None,
488            Self::KP0060KeyObjectJwsPublicJwk => None,
489            Self::KP0061KeyObjectNoActiveSigningKeys => None,
490            Self::KP0062KeyProviderNoSuchKey => None,
491
492            Self::KU001InitWhileSessionActive => Some("The session was active when the init function was called.".into()),
493            Self::KU002ContinueWhileSessionInActive => Some("Attempted to continue auth session while current session is inactive".into()),
494            Self::KU003PamAuthFailed => Some("Failed PAM account authentication step".into()),
495            Self::KU004PamInitFailed => Some("Failed to initialise PAM authentication".into()),
496            Self::KU005ErrorCheckingAccount => Some("Error checking account".into()),
497            Self::KU006OnlyRootAllowed => Some("Only root is allowed to perform this operation".into()),
498            Self::LD0001AnonymousNotAllowed => Some("Anonymous is not allowed to access LDAP with this method.".into()),
499            Self::MG0001InvalidReMigrationLevel => None,
500            Self::MG0002RaiseDomainLevelExceedsMaximum => None,
501            Self::MG0003ServerPhaseInvalidForMigration => None,
502            Self::MG0004DomainLevelInDevelopment => None,
503            Self::MG0005GidConstraintsNotMet => None,
504            Self::MG0006SKConstraintsNotMet => Some("Migration Constraints Not Met - Security Keys should not be present.".into()),
505            Self::MG0007Oauth2StrictConstraintsNotMet => Some("Migration Constraints Not Met - All OAuth2 clients must have strict-redirect-uri mode enabled.".into()),
506            Self::MG0008SkipUpgradeAttempted => Some("Skip Upgrade Attempted.".into()),
507            Self::MG0009InvalidTargetLevelForBootstrap => Some("The request target domain level was not valid for bootstrapping a new server instance".into()),
508            Self::PL0001GidOverlapsSystemRange => None,
509            Self::SC0001IncomingSshPublicKey => None,
510            Self::SC0002ReferenceSyntaxInvalid => Some("A SCIM Reference Set contained invalid syntax and can not be processed.".into()),
511            Self::SC0003MailSyntaxInvalid => Some("A SCIM Mail Address contained invalid syntax".into()),
512            Self::SC0004UuidSyntaxInvalid => Some("A SCIM Uuid contained invalid syntax".into()),
513            Self::SC0005BoolSyntaxInvalid => Some("A SCIM boolean contained invalid syntax".into()),
514            Self::SC0006Uint32SyntaxInvalid => Some("A SCIM Uint32 contained invalid syntax".into()),
515            Self::SC0007UrlSyntaxInvalid => Some("A SCIM Url contained invalid syntax".into()),
516            Self::SC0008SyntaxTypeSyntaxInvalid => Some("A SCIM SyntaxType contained invalid syntax".into()),
517            Self::SC0009IndexTypeSyntaxInvalid => Some("A SCIM IndexType contained invalid syntax".into()),
518            Self::SC0010DateTimeSyntaxInvalid => Some("A SCIM DateTime contained invalid syntax".into()),
519
520            Self::SC0011AddressSyntaxInvalid => Some("A SCIM Address contained invalid syntax".into()),
521            Self::SC0012CertificateSyntaxInvalid => Some("A SCIM Certificate contained invalid binary data".into()),
522            Self::SC0013CertificateInvalidDer => Some("A SCIM Certificate did not contain valid DER".into()),
523            Self::SC0014CertificateInvalidDigest => Some("A SCIM Certificate was unable to be digested".into()),
524            Self::SC0015CredentialTypeSyntaxInvalid => Some("A SCIM CredentialType contained invalid syntax".into()),
525            Self::SC0016InameSyntaxInvalid => Some("A SCIM Iname string contained invalid syntax".into()),
526            Self::SC0017Iutf8SyntaxInvalid => Some("A SCIM Iutf8 string contained invalid syntax".into()),
527            Self::SC0018NsUniqueIdSyntaxInvalid => Some("A SCIM NsUniqueID contained invalid syntax".into()),
528            Self::SC0019Oauth2ScopeSyntaxInvalid => Some("A SCIM Oauth2 Scope contained invalid syntax".into()),
529            Self::SC0020Oauth2ScopeMapSyntaxInvalid => Some("A SCIM Oauth2 Scope Map contained invalid syntax".into()),
530            Self::SC0021Oauth2ScopeMapMissingGroupIdentifier => Some("A SCIM Oauth2 Scope Map was missing a group name or uuid".into()),
531            Self::SC0022Oauth2ClaimMapSyntaxInvalid => Some("A SCIM Oauth2 Claim Map contained invalid syntax".into()),
532            Self::SC0023Oauth2ClaimMapMissingGroupIdentifier => Some("A SCIM Claim Map was missing a group name or uuid".into()),
533            Self::SC0024SshPublicKeySyntaxInvalid => Some("A SCIM Ssh Public Key contained invalid syntax".into()),
534            Self::SC0025UiHintSyntaxInvalid => Some("A SCIM UiHint contained invalid syntax".into()),
535            Self::SC0026Utf8SyntaxInvalid => Some("A SCIM Utf8 String Scope Map contained invalid syntax".into()),
536            Self::SC0027ClassSetInvalid => Some("The internal set of class templates used in this create operation was invalid. THIS IS A BUG.".into()),
537            Self::SC0028CreatedUuidsInvalid => Some("The internal create query did not return the set of created UUIDs. THIS IS A BUG".into()),
538
539            Self::UI0001ChallengeSerialisation => Some("The WebAuthn challenge was unable to be serialised.".into()),
540            Self::UI0002InvalidState => Some("The credential update process returned an invalid state transition.".into()),
541            Self::UI0003InvalidOauth2Resume => Some("The server attemped to resume OAuth2, but no OAuth2 session is in progress.".into()),
542            Self::VL0001ValueSshPublicKeyString => None,
543            Self::VS0001IncomingReplSshPublicKey => None,
544            Self::VS0002CertificatePublicKeyDigest |
545            Self::VS0003CertificateDerDecode => Some("Decoding the stored certificate from DER failed.".into()),
546            Self::VS0004CertificatePublicKeyDigest |
547            Self::VS0005CertificatePublicKeyDigest => Some("The certificates public key is unabled to be digested.".into()),
548        }
549    }
550}
551
552#[test]
553fn test_operationerror_as_nice_string() {
554    assert_eq!(
555        OperationError::CU0001WebauthnAttestationNotTrusted.to_string(),
556        "CU0001WebauthnAttestationNotTrusted".to_string()
557    );
558    assert_eq!(
559        OperationError::CU0003WebauthnUserNotVerified.to_string(),
560        "CU0003WebauthnUserNotVerified - User Verification bit not set while registering credential, you may need to configure a PIN on this device.".to_string()
561    );
562    assert_eq!(
563        OperationError::SessionExpired.to_string(),
564        "SessionExpired".to_string()
565    );
566    assert_eq!(
567        OperationError::CorruptedEntry(12345).to_string(),
568        "CorruptedEntry(12345)".to_string()
569    );
570}