1use crate::core::Capability;
4use thiserror::Error;
5
6pub trait AuthsErrorInfo {
12 fn error_code(&self) -> &'static str;
14
15 fn suggestion(&self) -> Option<&'static str>;
17}
18
19#[derive(Error, Debug)]
21pub enum AttestationError {
22 #[error("Signature verification failed: {0}")]
24 VerificationError(String),
25
26 #[error("Missing required capability: required {required:?}, available {available:?}")]
28 MissingCapability {
29 required: Capability,
31 available: Vec<Capability>,
33 },
34
35 #[error("Signing failed: {0}")]
37 SigningError(String),
38
39 #[error("DID resolution failed: {0}")]
41 DidResolutionError(String),
42
43 #[error("Serialization error: {0}")]
45 SerializationError(String),
46
47 #[error("Invalid input: {0}")]
49 InvalidInput(String),
50
51 #[error("Crypto error: {0}")]
53 CryptoError(String),
54
55 #[error("Input too large: {0}")]
57 InputTooLarge(String),
58
59 #[error("Internal error: {0}")]
61 InternalError(String),
62
63 #[error("Organizational Attestation verification failed: {0}")]
65 OrgVerificationFailed(String),
66
67 #[error("Organizational Attestation expired")]
69 OrgAttestationExpired,
70
71 #[error("Organizational DID resolution failed: {0}")]
73 OrgDidResolutionFailed(String),
74
75 #[error("Bundle is {age_secs}s old (max {max_secs}s). Refresh with: auths id export-bundle")]
77 BundleExpired {
78 age_secs: u64,
80 max_secs: u64,
82 },
83}
84
85impl AuthsErrorInfo for AttestationError {
86 fn error_code(&self) -> &'static str {
87 match self {
88 Self::VerificationError(_) => "AUTHS_VERIFICATION_ERROR",
89 Self::MissingCapability { .. } => "AUTHS_MISSING_CAPABILITY",
90 Self::SigningError(_) => "AUTHS_SIGNING_ERROR",
91 Self::DidResolutionError(_) => "AUTHS_DID_RESOLUTION_ERROR",
92 Self::SerializationError(_) => "AUTHS_SERIALIZATION_ERROR",
93 Self::InputTooLarge(_) => "AUTHS_INPUT_TOO_LARGE",
94 Self::InvalidInput(_) => "AUTHS_INVALID_INPUT",
95 Self::CryptoError(_) => "AUTHS_CRYPTO_ERROR",
96 Self::InternalError(_) => "AUTHS_INTERNAL_ERROR",
97 Self::OrgVerificationFailed(_) => "AUTHS_ORG_VERIFICATION_FAILED",
98 Self::OrgAttestationExpired => "AUTHS_ORG_ATTESTATION_EXPIRED",
99 Self::OrgDidResolutionFailed(_) => "AUTHS_ORG_DID_RESOLUTION_FAILED",
100 Self::BundleExpired { .. } => "AUTHS_BUNDLE_EXPIRED",
101 }
102 }
103
104 fn suggestion(&self) -> Option<&'static str> {
105 match self {
106 Self::VerificationError(_) => {
107 Some("Verify the attestation was signed with the correct key")
108 }
109 Self::MissingCapability { .. } => {
110 Some("Request an attestation with the required capability")
111 }
112 Self::DidResolutionError(_) => Some("Check that the DID is valid and resolvable"),
113 Self::OrgVerificationFailed(_) => {
114 Some("Verify organizational identity is properly configured")
115 }
116 Self::OrgAttestationExpired => {
117 Some("Request a new organizational attestation from the admin")
118 }
119 Self::OrgDidResolutionFailed(_) => {
120 Some("Check that the organization's DID is correctly configured")
121 }
122 Self::InputTooLarge(_) => {
124 Some("Reduce the size of the JSON input or split into smaller batches")
125 }
126 Self::BundleExpired { .. } => Some(
127 "Re-export the bundle: auths id export-bundle --alias <ALIAS> --output bundle.json --max-age-secs <SECS>",
128 ),
129 Self::SigningError(_)
130 | Self::SerializationError(_)
131 | Self::InvalidInput(_)
132 | Self::CryptoError(_)
133 | Self::InternalError(_) => None,
134 }
135 }
136}