use crate::SingleOrMultiple;
use chrono::Duration;
use std::{error, fmt, io, str, string};
#[derive(Debug)]
pub enum Error {
GenericError(String),
DecodeError(DecodeError),
ValidationError(ValidationError),
JsonError(serde_json::error::Error),
DecodeBase64(data_encoding::DecodeError),
Utf8(str::Utf8Error),
IOError(io::Error),
KeyRejected(ring::error::KeyRejected),
WrongKeyType {
expected: String,
actual: String,
},
WrongEncryptionOptions {
expected: String,
actual: String,
},
UnspecifiedCryptographicError,
UnsupportedOperation,
}
#[derive(Debug)]
pub enum DecodeError {
InvalidToken,
PartsLengthError {
expected: usize,
actual: usize,
},
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum ValidationError {
InvalidSignature,
WrongAlgorithmHeader,
MissingRequiredClaims(Vec<String>),
Expired(Duration),
NotYetValid(Duration),
TooOld(Duration),
InvalidIssuer(String),
InvalidAudience(SingleOrMultiple<String>),
KidMissing,
KeyNotFound,
UnsupportedKeyAlgorithm,
MissingAlgorithm,
}
macro_rules! impl_from_error {
($f:ty, $e:expr) => {
impl From<$f> for Error {
fn from(f: $f) -> Error {
$e(f)
}
}
};
}
impl_from_error!(String, Error::GenericError);
impl_from_error!(serde_json::error::Error, Error::JsonError);
impl_from_error!(data_encoding::DecodeError, Error::DecodeBase64);
impl_from_error!(str::Utf8Error, Error::Utf8);
impl_from_error!(ValidationError, Error::ValidationError);
impl_from_error!(DecodeError, Error::DecodeError);
impl_from_error!(io::Error, Error::IOError);
impl_from_error!(ring::error::KeyRejected, Error::KeyRejected);
impl From<ring::error::Unspecified> for Error {
fn from(_: ring::error::Unspecified) -> Self {
Error::UnspecifiedCryptographicError
}
}
impl From<string::FromUtf8Error> for Error {
fn from(e: string::FromUtf8Error) -> Self {
Error::Utf8(e.utf8_error())
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::Error::*;
match *self {
GenericError(ref err) => fmt::Display::fmt(err, f),
JsonError(ref err) => fmt::Display::fmt(err, f),
DecodeBase64(ref err) => fmt::Display::fmt(err, f),
Utf8(ref err) => fmt::Display::fmt(err, f),
DecodeError(ref err) => fmt::Display::fmt(err, f),
ValidationError(ref err) => fmt::Display::fmt(err, f),
IOError(ref err) => fmt::Display::fmt(err, f),
KeyRejected(ref err) => fmt::Display::fmt(err, f),
WrongKeyType {
ref actual,
ref expected,
} => write!(
f,
"{} was expected for this cryptographic operation but {} was provided",
expected, actual
),
WrongEncryptionOptions {
ref actual,
ref expected,
} => write!(
f,
"{} was expected for this cryptographic operation but {} was provided",
expected, actual
),
UnspecifiedCryptographicError => write!(f, "An unspecified cryptographic error"),
UnsupportedOperation => write!(f, "This operation is not supported"),
}
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
use crate::Error::*;
match *self {
JsonError(ref err) => Some(err),
DecodeBase64(ref err) => Some(err),
Utf8(ref err) => Some(err),
DecodeError(ref err) => Some(err),
ValidationError(ref err) => Some(err),
IOError(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::DecodeError::*;
match *self {
InvalidToken => write!(f, "Invalid token"),
PartsLengthError { expected, actual } => write!(
f,
"Expected {} parts in Compact JSON representation but got {}",
expected, actual
),
}
}
}
impl error::Error for DecodeError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
impl fmt::Display for ValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::ValidationError::*;
match *self {
MissingRequiredClaims(ref fields) => write!(
f,
"The following claims are required, but missing: {:?}",
fields
),
Expired(ago) => write!(f, "Token expired {} seconds ago", ago.num_seconds()),
NotYetValid(nyv_for) => write!(
f,
"Token will be valid in {} seconds",
nyv_for.num_seconds()
),
TooOld(duration) => write!(
f,
"Token has been considered too old for {} seconds",
duration.num_seconds()
),
InvalidIssuer(ref iss) => write!(f, "Issuer of token is invalid: {:?}", iss),
InvalidAudience(ref aud) => write!(f, "Audience of token is invalid: {:?}", aud),
InvalidSignature => write!(f, "Invalid signature"),
WrongAlgorithmHeader => write!(
f,
"Token provided was signed or encrypted with an unexpected algorithm"
),
KidMissing => write!(f, "Header is missing kid"),
KeyNotFound => write!(f, "Key not found in JWKS"),
UnsupportedKeyAlgorithm => write!(f, "Algorithm of JWK not supported"),
MissingAlgorithm => write!(
f,
"An algorithm is needed for verification but was not provided"
),
}
}
}
impl error::Error for ValidationError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}