api_keys_simplified/
error.rs1use thiserror::Error;
2
3#[derive(Debug, Error)]
9pub enum Error {
10 #[error("Invalid input")]
12 InvalidFormat,
13
14 #[error("Operation failed")]
23 OperationFailed(
24 #[source]
25 #[from]
26 OperationError,
27 ),
28}
29
30#[derive(Debug, Error)]
32pub enum ConfigError {
33 #[error("Prefix must be between 1 and 20 characters")]
34 InvalidPrefixLength,
35
36 #[error("Prefix must contain only alphanumeric characters or underscores")]
37 InvalidPrefixCharacters,
38
39 #[error("Prefix must not contain {0} substring")]
40 InvalidPrefixSubstring(String),
41
42 #[error("Prefix cannot look like a version number (e.g., 'v1', 'v2', 'v42')")]
43 InvalidPrefixVersionLike,
44
45 #[error("String must not be empty")]
46 EmptyString,
47
48 #[error("Entropy must be at least 16 bytes (128 bits)")]
49 EntropyTooLow,
50
51 #[error("Entropy cannot exceed 64 bytes (512 bits)")]
52 EntropyTooHigh,
53
54 #[error("Invalid Argon2 parameters")]
55 InvalidHashParams,
56
57 #[error("Invalid Argon2 hash. Please raise an issue at https://github.com/gpmcp/api-keys-simplified/issues/new"
58 )]
59 InvalidArgon2Hash,
60
61 #[error("Minium checksum length should be 32 bits")]
62 ChecksumLenTooSmall,
63
64 #[error("Checksum length should be at MOST 128 bits")]
65 ChecksumLenTooLarge,
66}
67
68#[derive(Debug, Error)]
70pub enum OperationError {
71 #[error("Key generation failed: {0}")]
72 Generation(String),
73
74 #[error("Hashing failed: {0}")]
75 Hashing(String),
76
77 #[error("Verification failed: {0}")]
78 Verification(String),
79}
80
81pub type Result<T> = std::result::Result<T, Error>;
82
83#[derive(Debug, Error)]
86pub enum InitError {
87 #[error(transparent)]
89 Config(#[from] ConfigError),
90
91 #[error(transparent)]
93 Operation(#[from] Error),
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_display_is_generic() {
102 let err =
103 Error::OperationFailed(OperationError::Hashing("detailed salt error".to_string()));
104 assert_eq!(err.to_string(), "Operation failed");
106
107 let debug_str = format!("{:?}", err);
109 assert!(debug_str.contains("Hashing"));
110 assert!(debug_str.contains("salt"));
111 }
112
113 #[test]
114 fn test_error_chaining() {
115 let err = Error::OperationFailed(OperationError::Verification(
116 "argon2 param error".to_string(),
117 ));
118 if let Error::OperationFailed(source) = err {
120 assert!(source.to_string().contains("argon2"));
121 }
122 }
123
124 #[test]
125 fn test_format_errors_are_generic() {
126 let err = Error::InvalidFormat;
127 assert_eq!(err.to_string(), "Invalid input");
128 }
129}