use crate::errors::{ErrorSeverity, UserFriendlyError};
use thiserror::Error;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum AuthenticationError {
#[error("Invalid credentials provided")]
InvalidCredentials,
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum AuthnError {
#[error("Authentication error: {error}")]
Authentication {
#[source]
error: AuthenticationError,
context: Option<String>,
},
}
impl AuthnError {
pub fn from_authentication(error: AuthenticationError, context: Option<String>) -> Self {
AuthnError::Authentication { error, context }
}
pub fn invalid_credentials(context: Option<String>) -> Self {
Self::from_authentication(AuthenticationError::InvalidCredentials, context)
}
fn support_code_inner(&self) -> String {
match self {
AuthnError::Authentication { error, .. } => match error {
AuthenticationError::InvalidCredentials => "AUTHN-INVALID-CREDS".to_string(),
},
}
}
}
impl UserFriendlyError for AuthnError {
fn user_message(&self) -> String {
match self {
AuthnError::Authentication { error, .. } => match error {
AuthenticationError::InvalidCredentials => {
"The username or password you entered is incorrect. Please check your credentials and try again.".to_string()
}
},
}
}
fn developer_message(&self) -> String {
match self {
AuthnError::Authentication { error, context } => {
let context_info = context
.as_ref()
.map(|c| format!(" Context: {}", c))
.unwrap_or_default();
format!("Authentication failure: {}.{}", error, context_info)
}
}
}
fn support_code(&self) -> String {
self.support_code_inner()
}
fn severity(&self) -> ErrorSeverity {
match self {
AuthnError::Authentication { error, .. } => match error {
AuthenticationError::InvalidCredentials => ErrorSeverity::Warning,
},
}
}
fn suggested_actions(&self) -> Vec<String> {
match self {
AuthnError::Authentication { error, .. } => match error {
AuthenticationError::InvalidCredentials => vec![
"Double-check your username and password for typos".to_string(),
"Ensure Caps Lock is not accidentally enabled".to_string(),
"Use the 'Forgot Password' link if you can't remember your password"
.to_string(),
"Contact support if you're sure your credentials are correct".to_string(),
],
},
}
}
fn is_retryable(&self) -> bool {
match self {
AuthnError::Authentication { error, .. } => match error {
AuthenticationError::InvalidCredentials => true,
},
}
}
}