wascap/
errors.rs

1// Copyright 2015-2018 Capital One Services, LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{error::Error as StdError, fmt};
16
17use wasmparser::BinaryReaderError;
18
19/// An error that can contain wascap-specific context
20#[derive(Debug)]
21pub struct Error(Box<ErrorKind>);
22
23pub(crate) fn new(kind: ErrorKind) -> Error {
24    Error(Box::new(kind))
25}
26
27#[derive(Debug)]
28pub enum ErrorKind {
29    Serialize(serde_json::error::Error),
30    Encryption(nkeys::error::Error),
31    Decode(data_encoding::DecodeError),
32    UTF8(std::string::FromUtf8Error),
33    Token(String),
34    InvalidCapability,
35    WasmElement(String),
36    IO(std::io::Error),
37    InvalidModuleHash,
38    ExpiredToken,
39    TokenTooEarly,
40    InvalidAlgorithm,
41    MissingIssuer,
42    MissingSubject,
43}
44
45impl Error {
46    #[must_use]
47    pub fn kind(&self) -> &ErrorKind {
48        &self.0
49    }
50
51    #[must_use]
52    pub fn into_kind(self) -> ErrorKind {
53        *self.0
54    }
55}
56
57impl StdError for Error {
58    fn description(&self) -> &str {
59        match *self.0 {
60            ErrorKind::Serialize(_) => "Serialization failure",
61            ErrorKind::Encryption(_) => "Encryption failure",
62            ErrorKind::Decode(_) => "Decode failure",
63            ErrorKind::UTF8(_) => "UTF8 failure",
64            ErrorKind::Token(_) => "JWT failure",
65            ErrorKind::InvalidCapability => "Invalid Capability",
66            ErrorKind::WasmElement(_) => "WebAssembly element",
67            ErrorKind::IO(_) => "I/O error",
68            ErrorKind::InvalidModuleHash => "Invalid Module Hash",
69            ErrorKind::ExpiredToken => "Token has expired",
70            ErrorKind::TokenTooEarly => "Token cannot be used yet",
71            ErrorKind::InvalidAlgorithm => "Invalid JWT algorithm",
72            ErrorKind::MissingIssuer => "Missing issuer claim",
73            ErrorKind::MissingSubject => "Missing sub claim",
74        }
75    }
76
77    fn cause(&self) -> Option<&dyn StdError> {
78        match *self.0 {
79            ErrorKind::Serialize(ref err) => Some(err),
80            ErrorKind::Encryption(ref err) => Some(err),
81            ErrorKind::Decode(ref err) => Some(err),
82            ErrorKind::UTF8(ref err) => Some(err),
83            ErrorKind::IO(ref err) => Some(err),
84            ErrorKind::Token(_)
85            | ErrorKind::InvalidCapability
86            | ErrorKind::WasmElement(_)
87            | ErrorKind::InvalidModuleHash
88            | ErrorKind::ExpiredToken
89            | ErrorKind::TokenTooEarly
90            | ErrorKind::InvalidAlgorithm
91            | ErrorKind::MissingIssuer
92            | ErrorKind::MissingSubject => None,
93        }
94    }
95}
96
97impl fmt::Display for Error {
98    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99        match *self.0 {
100            ErrorKind::Serialize(ref err) => write!(f, "Serialization error: {err}"),
101            ErrorKind::Encryption(ref err) => write!(f, "Encryption error: {err}"),
102            ErrorKind::Decode(ref err) => write!(f, "Decode error: {err}"),
103            ErrorKind::UTF8(ref err) => write!(f, "UTF8 error: {err}"),
104            ErrorKind::Token(ref err) => write!(f, "JWT error: {err}"),
105            ErrorKind::InvalidCapability => write!(f, "Invalid capability"),
106            ErrorKind::WasmElement(ref err) => write!(f, "Wasm Element error: {err}"),
107            ErrorKind::IO(ref err) => write!(f, "I/O error: {err}"),
108            ErrorKind::InvalidModuleHash => write!(f, "Invalid module hash"),
109            ErrorKind::ExpiredToken => write!(f, "Module token has expired"),
110            ErrorKind::TokenTooEarly => write!(f, "Module cannot be used yet"),
111            ErrorKind::InvalidAlgorithm => {
112                write!(f, "Invalid JWT algorithm. WASCAP only supports Ed25519")
113            }
114            ErrorKind::MissingIssuer => {
115                write!(
116                    f,
117                    "Invalid JWT. WASCAP requires an issuer claim to be present"
118                )
119            }
120            ErrorKind::MissingSubject => {
121                write!(f, "Invalid JWT. WASCAP requires a sub claim to be present")
122            }
123        }
124    }
125}
126
127impl From<std::io::Error> for Error {
128    fn from(source: std::io::Error) -> Error {
129        Error(Box::new(ErrorKind::IO(source)))
130    }
131}
132
133impl From<BinaryReaderError> for Error {
134    fn from(source: BinaryReaderError) -> Error {
135        let io_error = ::std::io::Error::other(source.to_string());
136        Error(Box::new(ErrorKind::IO(io_error)))
137    }
138}
139
140impl From<serde_json::error::Error> for Error {
141    fn from(source: serde_json::error::Error) -> Error {
142        Error(Box::new(ErrorKind::Serialize(source)))
143    }
144}
145
146impl From<data_encoding::DecodeError> for Error {
147    fn from(source: data_encoding::DecodeError) -> Error {
148        Error(Box::new(ErrorKind::Decode(source)))
149    }
150}
151
152impl From<nkeys::error::Error> for Error {
153    fn from(source: nkeys::error::Error) -> Error {
154        Error(Box::new(ErrorKind::Encryption(source)))
155    }
156}
157
158impl From<std::string::FromUtf8Error> for Error {
159    fn from(source: std::string::FromUtf8Error) -> Error {
160        Error(Box::new(ErrorKind::UTF8(source)))
161    }
162}