1use thiserror::Error;
6
7pub type SaTokenResult<T> = Result<T, SaTokenError>;
8
9#[derive(Debug, Error)]
10pub enum SaTokenError {
11 #[error("Token not found or expired")]
13 TokenNotFound,
14
15 #[error("Token is invalid: {0}")]
16 InvalidToken(String),
17
18 #[error("Token has expired")]
19 TokenExpired,
20
21 #[error("User not logged in")]
23 NotLogin,
24
25 #[error("Token is inactive")]
26 TokenInactive,
27
28 #[error("Permission denied")]
30 PermissionDenied,
31
32 #[error("Permission denied: missing permission '{0}'")]
33 PermissionDeniedDetail(String),
34
35 #[error("Role denied: missing role '{0}'")]
36 RoleDenied(String),
37
38 #[error("Account is banned until {0}")]
40 AccountBanned(String),
41
42 #[error("Account is kicked out")]
43 AccountKickedOut,
44
45 #[error("Account login has been replaced on another device")]
46 AccountReplaced,
47
48 #[error("Secondary authentication required for service '{0}'")]
49 NotSafe(String),
50
51 #[error("Account is disabled for service '{service}' at level {level}")]
52 DisableService { service: String, level: i32 },
53
54 #[error("Session not found")]
56 SessionNotFound,
57
58 #[error("Nonce has been used, possible replay attack detected")]
60 NonceAlreadyUsed,
61
62 #[error("Invalid nonce format")]
63 InvalidNonceFormat,
64
65 #[error("Nonce timestamp is invalid or expired")]
66 InvalidNonceTimestamp,
67
68 #[error("Refresh token not found or expired")]
70 RefreshTokenNotFound,
71
72 #[error("Invalid refresh token data")]
73 RefreshTokenInvalidData,
74
75 #[error("Missing login_id in refresh token")]
76 RefreshTokenMissingLoginId,
77
78 #[error("Invalid expire time format in refresh token")]
79 RefreshTokenInvalidExpireTime,
80
81 #[error("Token is empty")]
83 TokenEmpty,
84
85 #[error("Token is too short")]
86 TokenTooShort,
87
88 #[error("Login ID is not a valid number")]
89 LoginIdNotNumber,
90
91 #[error("OAuth2 client not found")]
93 OAuth2ClientNotFound,
94
95 #[error("Invalid client credentials")]
96 OAuth2InvalidCredentials,
97
98 #[error("Client ID mismatch")]
99 OAuth2ClientIdMismatch,
100
101 #[error("Redirect URI mismatch")]
102 OAuth2RedirectUriMismatch,
103
104 #[error("Authorization code not found or expired")]
105 OAuth2CodeNotFound,
106
107 #[error("Access token not found or expired")]
108 OAuth2AccessTokenNotFound,
109
110 #[error("Refresh token not found or expired")]
111 OAuth2RefreshTokenNotFound,
112
113 #[error("Invalid refresh token data")]
114 OAuth2InvalidRefreshToken,
115
116 #[error("Invalid scope data")]
117 OAuth2InvalidScope,
118
119 #[error("SSO ticket not found or invalid")]
121 InvalidTicket,
122
123 #[error("SSO ticket has expired")]
124 TicketExpired,
125
126 #[error("Service URL mismatch")]
127 ServiceMismatch,
128
129 #[error("SSO session not found")]
130 SsoSessionNotFound,
131
132 #[error("Storage error: {0}")]
134 StorageError(String),
135
136 #[error("Configuration error: {0}")]
137 ConfigError(String),
138
139 #[error("Serialization error: {0}")]
140 SerializationError(#[from] serde_json::Error),
141
142 #[error("Internal error: {0}")]
143 InternalError(String),
144}
145
146impl SaTokenError {
147 pub fn message(&self) -> String {
159 self.to_string()
160 }
161
162 pub fn is_auth_error(&self) -> bool {
166 matches!(
167 self,
168 Self::NotLogin
169 | Self::TokenNotFound
170 | Self::TokenExpired
171 | Self::TokenInactive
172 | Self::InvalidToken(_)
173 | Self::AccountKickedOut
174 | Self::AccountReplaced
175 )
176 }
177
178 pub fn is_authz_error(&self) -> bool {
182 matches!(
183 self,
184 Self::PermissionDenied
185 | Self::PermissionDeniedDetail(_)
186 | Self::RoleDenied(_)
187 )
188 }
189}
190
191pub mod messages {
205 pub const INVALID_CREDENTIALS: &str = "Invalid username or password";
207
208 pub const LOGIN_FAILED: &str = "Login failed";
210
211 pub const AUTH_ERROR: &str = "Authentication error";
213
214 pub const PERMISSION_REQUIRED: &str = "Permission required";
216
217 pub const ROLE_REQUIRED: &str = "Role required";
219}