#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ErrorKind {
InvalidKeyfile,
DecryptionFailure,
DeserializationError,
SecretNotFound,
UnsupportedVaultVersion,
IoError,
InvalidStore,
}
pub(crate) type StdError = dyn std::error::Error + Send + Sync + 'static;
#[derive(Debug)]
pub struct Error {
inner: Option<Box<StdError>>,
kind: ErrorKind,
}
impl Error {
pub fn kind(&self) -> ErrorKind {
self.kind
}
pub fn inner(&self) -> Option<&StdError> {
self.inner.as_deref()
}
pub(crate) fn from_inner<E>(kind: ErrorKind, inner: E) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
Error {
kind,
inner: Some(Box::new(inner)),
}
}
}
impl PartialEq for Error {
fn eq(&self, rhs: &Self) -> bool {
self.kind == rhs.kind && self.inner.is_some() == self.inner.is_some()
}
}
impl std::convert::From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error { kind, inner: None }
}
}
impl<R> std::convert::From<Error> for Result<R, Error> {
fn from(error: Error) -> Self {
Err(error)
}
}
impl<R> std::convert::From<ErrorKind> for Result<R, Error> {
fn from(kind: ErrorKind) -> Self {
Err(kind.into())
}
}
impl std::convert::From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error {
inner: Some(Box::new(e)),
kind: ErrorKind::IoError,
}
}
}
impl std::convert::From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Error {
Error {
inner: Some(Box::new(e)),
kind: ErrorKind::InvalidStore,
}
}
}
#[cfg(not(feature = "rustls"))]
impl std::convert::From<openssl::error::ErrorStack> for Error {
fn from(e: openssl::error::ErrorStack) -> Error {
Error {
inner: Some(Box::new(e)),
kind: ErrorKind::DecryptionFailure,
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self.kind() {
ErrorKind::InvalidKeyfile => "An invalid key file was supplied",
ErrorKind::DecryptionFailure => "There was an error decrypting the secrets store. Check the password or key file and verify the store has not been tampered with",
ErrorKind::SecretNotFound => "No secret was found with the specified name",
ErrorKind::UnsupportedVaultVersion => "An attempt was made to open a vault with an unsupported version",
ErrorKind::IoError => "An IO error occurred reading or writing from/to the secrets store",
ErrorKind::DeserializationError => "An error occured in the type converter deserializing the secret to the requested type",
ErrorKind::InvalidStore => "The contents of the store did not match what was expected",
};
match &self.inner {
Some(inner) => write!(fmt, "{}: {}", s, inner),
None => write!(fmt, "{}.", s),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.inner
.as_ref()
.map(|err| err.as_ref() as &dyn std::error::Error)
}
}