1use reifydb_value::{
5 error::{Diagnostic, Error, IntoDiagnostic},
6 fragment::Fragment,
7};
8
9pub type Result<T> = std::result::Result<T, Error>;
10
11#[derive(Debug, thiserror::Error)]
12pub enum AuthError {
13 #[error("password is required for password authentication")]
14 PasswordRequired,
15
16 #[error("stored authentication is missing hash")]
17 MissingHash,
18
19 #[error("stored authentication is missing salt")]
20 MissingSalt,
21
22 #[error("stored authentication is missing token")]
23 MissingToken,
24
25 #[error("unknown authentication method: {method}")]
26 UnknownMethod {
27 method: String,
28 },
29
30 #[error("failed to serialize authentication properties: {reason}")]
31 SerializeProperties {
32 reason: String,
33 },
34
35 #[error("password hashing failed: {reason}")]
36 HashingFailed {
37 reason: String,
38 },
39
40 #[error("stored hash is invalid or corrupted: {reason}")]
41 InvalidHash {
42 reason: String,
43 },
44
45 #[error("password verification failed: {reason}")]
46 VerificationFailed {
47 reason: String,
48 },
49}
50
51#[derive(Debug, thiserror::Error)]
52pub enum SolanaError {
53 #[error("public key is required for solana authentication")]
54 MissingPublicKey,
55
56 #[error("invalid public key: {reason}")]
57 InvalidPublicKey {
58 reason: String,
59 },
60
61 #[error("invalid signature: {reason}")]
62 InvalidSignature {
63 reason: String,
64 },
65
66 #[error("challenge payload is missing the sign-in message")]
67 MissingChallengeMessage,
68}
69
70#[derive(Debug, thiserror::Error)]
71pub enum GithubError {
72 #[error("user_id is required for github authentication")]
73 MissingUserId,
74
75 #[error("invalid github user_id: {reason}")]
76 InvalidUserId {
77 reason: String,
78 },
79
80 #[error("github oauth code exchange failed: {reason}")]
81 ExchangeFailed {
82 reason: String,
83 },
84
85 #[error("github api request failed: {reason}")]
86 ApiFailed {
87 reason: String,
88 },
89}
90
91impl IntoDiagnostic for AuthError {
92 fn into_diagnostic(self) -> Diagnostic {
93 match self {
94 AuthError::PasswordRequired => Diagnostic {
95 code: "AU_001".to_string(),
96 rql: None,
97 message: "password is required for password authentication".to_string(),
98 fragment: Fragment::None,
99 label: Some("missing password".to_string()),
100 help: Some("provide a password in the authentication configuration".to_string()),
101 column: None,
102 notes: vec![],
103 cause: None,
104 operator_chain: None,
105 },
106
107 AuthError::MissingHash => Diagnostic {
108 code: "AU_002".to_string(),
109 rql: None,
110 message: "stored authentication is missing hash".to_string(),
111 fragment: Fragment::None,
112 label: Some("missing hash".to_string()),
113 help: Some("the stored authentication record is corrupted or incomplete".to_string()),
114 column: None,
115 notes: vec![],
116 cause: None,
117 operator_chain: None,
118 },
119
120 AuthError::MissingSalt => Diagnostic {
121 code: "AU_003".to_string(),
122 rql: None,
123 message: "stored authentication is missing salt".to_string(),
124 fragment: Fragment::None,
125 label: Some("missing salt".to_string()),
126 help: Some("the stored authentication record is corrupted or incomplete".to_string()),
127 column: None,
128 notes: vec![],
129 cause: None,
130 operator_chain: None,
131 },
132
133 AuthError::MissingToken => Diagnostic {
134 code: "AU_004".to_string(),
135 rql: None,
136 message: "stored authentication is missing token".to_string(),
137 fragment: Fragment::None,
138 label: Some("missing token".to_string()),
139 help: Some("the stored authentication record is corrupted or incomplete".to_string()),
140 column: None,
141 notes: vec![],
142 cause: None,
143 operator_chain: None,
144 },
145
146 AuthError::SerializeProperties {
147 reason,
148 } => Diagnostic {
149 code: "AU_006".to_string(),
150 rql: None,
151 message: format!("failed to serialize authentication properties: {}", reason),
152 fragment: Fragment::None,
153 label: Some("serialization failed".to_string()),
154 help: Some("ensure authentication properties are valid".to_string()),
155 column: None,
156 notes: vec![],
157 cause: None,
158 operator_chain: None,
159 },
160
161 AuthError::UnknownMethod {
162 method,
163 } => Diagnostic {
164 code: "AU_005".to_string(),
165 rql: None,
166 message: format!("unknown authentication method: {}", method),
167 fragment: Fragment::None,
168 label: Some("unknown method".to_string()),
169 help: Some("supported authentication methods are: password, token, solana, github"
170 .to_string()),
171 column: None,
172 notes: vec![],
173 cause: None,
174 operator_chain: None,
175 },
176
177 AuthError::HashingFailed {
178 reason,
179 } => Diagnostic {
180 code: "AU_007".to_string(),
181 rql: None,
182 message: format!("password hashing failed: {}", reason),
183 fragment: Fragment::None,
184 label: Some("hashing failed".to_string()),
185 help: Some("an internal error occurred during password hashing".to_string()),
186 column: None,
187 notes: vec![],
188 cause: None,
189 operator_chain: None,
190 },
191
192 AuthError::InvalidHash {
193 reason,
194 } => Diagnostic {
195 code: "AU_008".to_string(),
196 rql: None,
197 message: format!("stored hash is invalid or corrupted: {}", reason),
198 fragment: Fragment::None,
199 label: Some("invalid hash".to_string()),
200 help: Some("the stored authentication record is corrupted or incomplete".to_string()),
201 column: None,
202 notes: vec![],
203 cause: None,
204 operator_chain: None,
205 },
206
207 AuthError::VerificationFailed {
208 reason,
209 } => Diagnostic {
210 code: "AU_009".to_string(),
211 rql: None,
212 message: format!("password verification failed: {}", reason),
213 fragment: Fragment::None,
214 label: Some("verification failed".to_string()),
215 help: Some("an internal error occurred during password verification".to_string()),
216 column: None,
217 notes: vec![],
218 cause: None,
219 operator_chain: None,
220 },
221 }
222 }
223}
224
225impl From<AuthError> for Error {
226 fn from(err: AuthError) -> Self {
227 Error(Box::new(err.into_diagnostic()))
228 }
229}
230
231impl IntoDiagnostic for SolanaError {
232 fn into_diagnostic(self) -> Diagnostic {
233 match self {
234 SolanaError::MissingPublicKey => Diagnostic {
235 code: "AU_010".to_string(),
236 rql: None,
237 message: "public key is required for solana authentication".to_string(),
238 fragment: Fragment::None,
239 label: Some("missing public key".to_string()),
240 help: Some("provide a public_key in the authentication configuration".to_string()),
241 column: None,
242 notes: vec![],
243 cause: None,
244 operator_chain: None,
245 },
246
247 SolanaError::InvalidPublicKey {
248 reason,
249 } => Diagnostic {
250 code: "AU_011".to_string(),
251 rql: None,
252 message: format!("invalid public key: {}", reason),
253 fragment: Fragment::None,
254 label: Some("invalid public key".to_string()),
255 help: Some("provide a valid base58-encoded 32-byte Solana public key".to_string()),
256 column: None,
257 notes: vec![],
258 cause: None,
259 operator_chain: None,
260 },
261
262 SolanaError::InvalidSignature {
263 reason,
264 } => Diagnostic {
265 code: "AU_012".to_string(),
266 rql: None,
267 message: format!("invalid signature: {}", reason),
268 fragment: Fragment::None,
269 label: Some("invalid signature".to_string()),
270 help: Some("provide a valid base58-encoded 64-byte ed25519 signature".to_string()),
271 column: None,
272 notes: vec![],
273 cause: None,
274 operator_chain: None,
275 },
276
277 SolanaError::MissingChallengeMessage => Diagnostic {
278 code: "AU_017".to_string(),
279 rql: None,
280 message: "challenge payload is missing the sign-in message".to_string(),
281 fragment: Fragment::None,
282 label: Some("missing challenge message".to_string()),
283 help: Some("the stored sign-in challenge is corrupted or incomplete".to_string()),
284 column: None,
285 notes: vec![],
286 cause: None,
287 operator_chain: None,
288 },
289 }
290 }
291}
292
293impl From<SolanaError> for Error {
294 fn from(err: SolanaError) -> Self {
295 Error(Box::new(err.into_diagnostic()))
296 }
297}
298
299impl IntoDiagnostic for GithubError {
300 fn into_diagnostic(self) -> Diagnostic {
301 match self {
302 GithubError::MissingUserId => Diagnostic {
303 code: "AU_013".to_string(),
304 rql: None,
305 message: "user_id is required for github authentication".to_string(),
306 fragment: Fragment::None,
307 label: Some("missing user_id".to_string()),
308 help: Some("provide a user_id in the authentication configuration".to_string()),
309 column: None,
310 notes: vec![],
311 cause: None,
312 operator_chain: None,
313 },
314
315 GithubError::InvalidUserId {
316 reason,
317 } => Diagnostic {
318 code: "AU_014".to_string(),
319 rql: None,
320 message: format!("invalid github user_id: {}", reason),
321 fragment: Fragment::None,
322 label: Some("invalid user_id".to_string()),
323 help: Some("provide the numeric github account id as user_id".to_string()),
324 column: None,
325 notes: vec![],
326 cause: None,
327 operator_chain: None,
328 },
329
330 GithubError::ExchangeFailed {
331 reason,
332 } => Diagnostic {
333 code: "AU_015".to_string(),
334 rql: None,
335 message: format!("github oauth code exchange failed: {}", reason),
336 fragment: Fragment::None,
337 label: Some("code exchange failed".to_string()),
338 help: Some("verify the github oauth client id, client secret, and redirect uri"
339 .to_string()),
340 column: None,
341 notes: vec![],
342 cause: None,
343 operator_chain: None,
344 },
345
346 GithubError::ApiFailed {
347 reason,
348 } => Diagnostic {
349 code: "AU_016".to_string(),
350 rql: None,
351 message: format!("github api request failed: {}", reason),
352 fragment: Fragment::None,
353 label: Some("github api failed".to_string()),
354 help: Some("github may be unreachable; retry the sign-in".to_string()),
355 column: None,
356 notes: vec![],
357 cause: None,
358 operator_chain: None,
359 },
360 }
361 }
362}
363
364impl From<GithubError> for Error {
365 fn from(err: GithubError) -> Self {
366 Error(Box::new(err.into_diagnostic()))
367 }
368}