use aes_gcm::Error as AesGcmError;
use argon2::password_hash::Error as PwhError;
use base64::DecodeError as Base64DecodeError;
use chrono::{DateTime, Utc};
use serde_json::Error as JsonError;
use std::string::FromUtf8Error;
use std::{error::Error as StdError, fmt};
#[derive(Debug)]
pub enum Error {
Expired(DateTime<Utc>),
JsonSerialize(JsonError),
JsonDeserialize(JsonError),
InvalidExpirationSeconds(i64),
ExpirationOutOfRange(i64),
PasswordHash(PwhError),
MissingHash,
AesGcm(AesGcmError),
Base64Decode(Base64DecodeError),
Utf8(FromUtf8Error),
InvalidDataLength(usize),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Expired(dt) => write!(f, "token expired at `{dt:#?}`"),
Error::JsonSerialize(e) => write!(f, "failed to serialize payload to JSON: {e}"),
Error::JsonDeserialize(e) => write!(f, "failed to parse JSON payload: {e}"),
Error::InvalidExpirationSeconds(secs) => write!(
f,
"invalid expiration {secs}s: must be greater than 1 second"
),
Error::ExpirationOutOfRange(ts) => write!(
f,
"expiration timestamp {ts} is out of range for a UTC DateTime"
),
Error::PasswordHash(e) => write!(f, "password hashing failed: {e}"),
Error::MissingHash => write!(f, "failed to extract raw hash bytes from PHC string"),
Error::AesGcm(e) => write!(f, "AES‑GCM error: {e}"),
Error::Base64Decode(e) => write!(f, "Base64 decode error: {e:#?}"),
Error::Utf8(e) => write!(f, "UTF‑8 conversion error: {e:#?}"),
Error::InvalidDataLength(got) => {
let needed = 16 + 12;
write!(
f,
"invalid encrypted data length: expected at least {needed} bytes but got {got}"
)
}
}
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Error::PasswordHash(e) => Some(e),
Error::AesGcm(e) => Some(e),
Error::Base64Decode(e) => Some(e),
Error::Utf8(e) => Some(e),
_ => None,
}
}
}
impl From<PwhError> for Error {
fn from(e: PwhError) -> Error {
Error::PasswordHash(e)
}
}
impl From<AesGcmError> for Error {
fn from(e: AesGcmError) -> Error {
Error::AesGcm(e)
}
}
impl From<Base64DecodeError> for Error {
fn from(e: Base64DecodeError) -> Error {
Error::Base64Decode(e)
}
}
impl From<FromUtf8Error> for Error {
fn from(e: FromUtf8Error) -> Error {
Error::Utf8(e)
}
}
impl From<JsonError> for Error {
fn from(e: JsonError) -> Self {
Error::JsonSerialize(e)
}
}