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