1use std::error::Error as StdError;
2use std::fmt;
3use std::result;
4
5pub(crate) fn new_error(kind: ErrorKind) -> Error {
7    Error(Box::new(kind))
8}
9
10pub type Result<T> = result::Result<T, Error>;
12
13#[derive(Debug)]
15pub struct Error(Box<ErrorKind>);
16
17impl Error {
18    pub fn kind(&self) -> &ErrorKind {
20        &self.0
21    }
22
23    pub fn into_kind(self) -> ErrorKind {
25        *self.0
26    }
27}
28
29#[derive(Debug)]
31pub enum ErrorKind {
32    InvalidToken,
34    InvalidSignature,
36    InvalidEcdsaKey,
38    InvalidRsaKey,
40    InvalidAlgorithmName,
42    InvalidKeyFormat,
44
45    ExpiredSignature,
48    InvalidIssuer,
50    InvalidAudience,
52    InvalidSubject,
54    ImmatureSignature,
56    InvalidAlgorithm,
59
60    Base64(base64::DecodeError),
63    Json(serde_json::Error),
65    Utf8(::std::string::FromUtf8Error),
67    Crypto(::ring::error::Unspecified),
69
70    #[doc(hidden)]
76    __Nonexhaustive,
77}
78
79impl StdError for Error {
80    fn cause(&self) -> Option<&dyn StdError> {
81        match *self.0 {
82            ErrorKind::InvalidToken => None,
83            ErrorKind::InvalidSignature => None,
84            ErrorKind::InvalidEcdsaKey => None,
85            ErrorKind::InvalidRsaKey => None,
86            ErrorKind::ExpiredSignature => None,
87            ErrorKind::InvalidIssuer => None,
88            ErrorKind::InvalidAudience => None,
89            ErrorKind::InvalidSubject => None,
90            ErrorKind::ImmatureSignature => None,
91            ErrorKind::InvalidAlgorithm => None,
92            ErrorKind::InvalidAlgorithmName => None,
93            ErrorKind::InvalidKeyFormat => None,
94            ErrorKind::Base64(ref err) => Some(err),
95            ErrorKind::Json(ref err) => Some(err),
96            ErrorKind::Utf8(ref err) => Some(err),
97            ErrorKind::Crypto(ref err) => Some(err),
98            ErrorKind::__Nonexhaustive => None,
99        }
100    }
101}
102
103impl fmt::Display for Error {
104    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105        match *self.0 {
106            ErrorKind::InvalidToken
107            | ErrorKind::InvalidSignature
108            | ErrorKind::InvalidEcdsaKey
109            | ErrorKind::InvalidRsaKey
110            | ErrorKind::ExpiredSignature
111            | ErrorKind::InvalidIssuer
112            | ErrorKind::InvalidAudience
113            | ErrorKind::InvalidSubject
114            | ErrorKind::ImmatureSignature
115            | ErrorKind::InvalidAlgorithm
116            | ErrorKind::InvalidKeyFormat
117            | ErrorKind::InvalidAlgorithmName => write!(f, "{:?}", self.0),
118            ErrorKind::Json(ref err) => write!(f, "JSON error: {}", err),
119            ErrorKind::Utf8(ref err) => write!(f, "UTF-8 error: {}", err),
120            ErrorKind::Crypto(ref err) => write!(f, "Crypto error: {}", err),
121            ErrorKind::Base64(ref err) => write!(f, "Base64 error: {}", err),
122            ErrorKind::__Nonexhaustive => write!(f, "Unknown error"),
123        }
124    }
125}
126
127impl From<base64::DecodeError> for Error {
128    fn from(err: base64::DecodeError) -> Error {
129        new_error(ErrorKind::Base64(err))
130    }
131}
132
133impl From<serde_json::Error> for Error {
134    fn from(err: serde_json::Error) -> Error {
135        new_error(ErrorKind::Json(err))
136    }
137}
138
139impl From<::std::string::FromUtf8Error> for Error {
140    fn from(err: ::std::string::FromUtf8Error) -> Error {
141        new_error(ErrorKind::Utf8(err))
142    }
143}
144
145impl From<::ring::error::Unspecified> for Error {
146    fn from(err: ::ring::error::Unspecified) -> Error {
147        new_error(ErrorKind::Crypto(err))
148    }
149}
150
151impl From<::ring::error::KeyRejected> for Error {
152    fn from(_err: ::ring::error::KeyRejected) -> Error {
153        new_error(ErrorKind::InvalidEcdsaKey)
154    }
155}
156
157impl From<ErrorKind> for Error {
158    fn from(kind: ErrorKind) -> Error {
159        new_error(kind)
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166
167    #[test]
168    fn test_error_rendering() {
169        assert_eq!(
170            "InvalidAlgorithmName",
171            Error::from(ErrorKind::InvalidAlgorithmName).to_string()
172        );
173    }
174}