use std::fmt;
use std::io;
use crate::{wfl, wlnfl};
#[cfg(feature = "plugin")]
use age_core::format::Stanza;
#[cfg(feature = "plugin")]
#[cfg_attr(docsrs, doc(cfg(feature = "plugin")))]
#[derive(Clone, Debug)]
pub enum PluginError {
Identity {
binary_name: String,
message: String,
},
Recipient {
binary_name: String,
recipient: String,
message: String,
},
Other {
kind: String,
metadata: Vec<String>,
message: String,
},
}
#[cfg(feature = "plugin")]
impl From<Stanza> for PluginError {
fn from(mut s: Stanza) -> Self {
assert!(s.tag == "error");
let kind = s.args.remove(0);
PluginError::Other {
kind,
metadata: s.args,
message: String::from_utf8_lossy(&s.body).to_string(),
}
}
}
#[cfg(feature = "plugin")]
impl fmt::Display for PluginError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PluginError::Identity {
binary_name,
message,
} => wfl!(
f,
"err-plugin-identity",
plugin_name = binary_name.as_str(),
message = message.as_str(),
),
PluginError::Recipient {
binary_name,
recipient,
message,
} => wfl!(
f,
"err-plugin-recipient",
plugin_name = binary_name.as_str(),
recipient = recipient.as_str(),
message = message.as_str(),
),
PluginError::Other {
kind,
metadata,
message,
} => {
write!(f, "({}", kind)?;
for d in metadata {
write!(f, " {}", d)?;
}
write!(f, ")")?;
if !message.is_empty() {
write!(f, " {}", message)?;
}
Ok(())
}
}
}
}
#[derive(Debug)]
pub enum EncryptError {
EncryptedIdentities(DecryptError),
Io(io::Error),
#[cfg(feature = "plugin")]
#[cfg_attr(docsrs, doc(cfg(feature = "plugin")))]
MissingPlugin {
binary_name: String,
},
#[cfg(feature = "plugin")]
#[cfg_attr(docsrs, doc(cfg(feature = "plugin")))]
Plugin(Vec<PluginError>),
}
impl From<io::Error> for EncryptError {
fn from(e: io::Error) -> Self {
EncryptError::Io(e)
}
}
impl Clone for EncryptError {
fn clone(&self) -> Self {
match self {
Self::EncryptedIdentities(e) => Self::EncryptedIdentities(e.clone()),
Self::Io(e) => Self::Io(io::Error::new(e.kind(), e.to_string())),
#[cfg(feature = "plugin")]
Self::MissingPlugin { binary_name } => Self::MissingPlugin {
binary_name: binary_name.clone(),
},
#[cfg(feature = "plugin")]
Self::Plugin(e) => Self::Plugin(e.clone()),
}
}
}
impl fmt::Display for EncryptError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EncryptError::EncryptedIdentities(e) => e.fmt(f),
EncryptError::Io(e) => e.fmt(f),
#[cfg(feature = "plugin")]
EncryptError::MissingPlugin { binary_name } => {
wlnfl!(f, "err-missing-plugin", plugin_name = binary_name.as_str())?;
wfl!(f, "rec-missing-plugin")
}
#[cfg(feature = "plugin")]
EncryptError::Plugin(errors) => match &errors[..] {
[] => unreachable!(),
[e] => write!(f, "{}", e),
_ => {
wlnfl!(f, "err-plugin-multiple")?;
for e in errors {
writeln!(f, "- {}", e)?;
}
Ok(())
}
},
}
}
}
impl std::error::Error for EncryptError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
EncryptError::EncryptedIdentities(inner) => Some(inner),
EncryptError::Io(inner) => Some(inner),
#[cfg(feature = "plugin")]
_ => None,
}
}
}
#[derive(Debug)]
pub enum DecryptError {
DecryptionFailed,
ExcessiveWork {
required: u8,
target: u8,
},
InvalidHeader,
InvalidMac,
Io(io::Error),
KeyDecryptionFailed,
#[cfg(feature = "plugin")]
#[cfg_attr(docsrs, doc(cfg(feature = "plugin")))]
MissingPlugin {
binary_name: String,
},
NoMatchingKeys,
#[cfg(feature = "plugin")]
#[cfg_attr(docsrs, doc(cfg(feature = "plugin")))]
Plugin(Vec<PluginError>),
UnknownFormat,
}
impl Clone for DecryptError {
fn clone(&self) -> Self {
match self {
Self::DecryptionFailed => Self::DecryptionFailed,
Self::ExcessiveWork { required, target } => Self::ExcessiveWork {
required: *required,
target: *target,
},
Self::InvalidHeader => Self::InvalidHeader,
Self::InvalidMac => Self::InvalidMac,
Self::Io(e) => Self::Io(io::Error::new(e.kind(), e.to_string())),
Self::KeyDecryptionFailed => Self::KeyDecryptionFailed,
#[cfg(feature = "plugin")]
Self::MissingPlugin { binary_name } => Self::MissingPlugin {
binary_name: binary_name.clone(),
},
Self::NoMatchingKeys => Self::NoMatchingKeys,
#[cfg(feature = "plugin")]
Self::Plugin(e) => Self::Plugin(e.clone()),
Self::UnknownFormat => Self::UnknownFormat,
}
}
}
impl fmt::Display for DecryptError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DecryptError::DecryptionFailed => wfl!(f, "err-decryption-failed"),
DecryptError::ExcessiveWork { required, target } => {
wlnfl!(f, "err-excessive-work")?;
wfl!(
f,
"rec-excessive-work",
duration = (1 << (required - target)),
)
}
DecryptError::InvalidHeader => wfl!(f, "err-header-invalid"),
DecryptError::InvalidMac => wfl!(f, "err-header-mac-invalid"),
DecryptError::Io(e) => e.fmt(f),
DecryptError::KeyDecryptionFailed => wfl!(f, "err-key-decryption"),
#[cfg(feature = "plugin")]
DecryptError::MissingPlugin { binary_name } => {
wlnfl!(f, "err-missing-plugin", plugin_name = binary_name.as_str())?;
wfl!(f, "rec-missing-plugin")
}
DecryptError::NoMatchingKeys => wfl!(f, "err-no-matching-keys"),
#[cfg(feature = "plugin")]
DecryptError::Plugin(errors) => match &errors[..] {
[] => unreachable!(),
[e] => write!(f, "{}", e),
_ => {
wlnfl!(f, "err-plugin-multiple")?;
for e in errors {
writeln!(f, "- {}", e)?;
}
Ok(())
}
},
DecryptError::UnknownFormat => {
wlnfl!(f, "err-unknown-format")?;
wfl!(f, "rec-unknown-format")
}
}
}
}
impl From<chacha20poly1305::aead::Error> for DecryptError {
fn from(_: chacha20poly1305::aead::Error) -> Self {
DecryptError::DecryptionFailed
}
}
impl From<io::Error> for DecryptError {
fn from(e: io::Error) -> Self {
DecryptError::Io(e)
}
}
impl From<hmac::digest::MacError> for DecryptError {
fn from(_: hmac::digest::MacError) -> Self {
DecryptError::InvalidMac
}
}
#[cfg(feature = "ssh")]
#[cfg_attr(docsrs, doc(cfg(feature = "ssh")))]
impl From<rsa::errors::Error> for DecryptError {
fn from(_: rsa::errors::Error) -> Self {
DecryptError::DecryptionFailed
}
}
impl std::error::Error for DecryptError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
DecryptError::Io(inner) => Some(inner),
_ => None,
}
}
}