use std::fmt;
use std::io;
macro_rules! wfl {
($f:ident, $message_id:literal) => {
write!($f, "{}", $crate::fl!($message_id))
};
($f:ident, $message_id:literal, $($args:expr),* $(,)?) => {
write!($f, "{}", $crate::fl!($message_id, $($args), *))
};
}
macro_rules! wlnfl {
($f:ident, $message_id:literal) => {
writeln!($f, "{}", $crate::fl!($message_id))
};
($f:ident, $message_id:literal, $($args:expr),* $(,)?) => {
writeln!($f, "{}", $crate::fl!($message_id, $($args), *))
};
}
pub(crate) enum EncryptError {
Age(anubis_age::EncryptError),
BrokenPipe {
is_stdout: bool,
source: io::Error,
},
IdentityRead(anubis_age::cli_common::ReadError),
Io(io::Error),
MixedIdentityAndPassphrase,
MixedRecipientAndPassphrase,
MixedRecipientsFileAndPassphrase,
MissingSigningKey,
PassphraseDisabled,
PassphraseTimedOut,
#[cfg(not(unix))]
PassphraseWithoutFileArgument,
PluginNameFlag,
SigningError(String),
}
impl From<anubis_age::EncryptError> for EncryptError {
fn from(e: anubis_age::EncryptError) -> Self {
match e {
anubis_age::EncryptError::Io(e) => EncryptError::Io(e),
_ => EncryptError::Age(e),
}
}
}
impl From<anubis_age::cli_common::ReadError> for EncryptError {
fn from(e: anubis_age::cli_common::ReadError) -> Self {
EncryptError::IdentityRead(e)
}
}
impl From<io::Error> for EncryptError {
fn from(e: io::Error) -> Self {
EncryptError::Io(e)
}
}
impl fmt::Display for EncryptError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EncryptError::Age(e @ anubis_age::EncryptError::MissingRecipients) => {
writeln!(f, "{}", e)?;
wfl!(f, "rec-enc-missing-recipients")
}
EncryptError::Age(e) => write!(f, "{}", e),
EncryptError::BrokenPipe { is_stdout, source } => {
if *is_stdout {
wlnfl!(f, "err-enc-broken-stdout", err = source.to_string())?;
wfl!(f, "rec-enc-broken-stdout")
} else {
wfl!(f, "err-enc-broken-file", err = source.to_string())
}
}
EncryptError::IdentityRead(e) => write!(f, "{}", e),
EncryptError::Io(e) => write!(f, "{}", e),
EncryptError::MixedIdentityAndPassphrase => {
wfl!(f, "err-enc-mixed-identity-passphrase")
}
EncryptError::MixedRecipientAndPassphrase => {
wfl!(f, "err-enc-mixed-recipient-passphrase")
}
EncryptError::MixedRecipientsFileAndPassphrase => {
wfl!(f, "err-enc-mixed-recipients-file-passphrase")
}
EncryptError::MissingSigningKey => {
writeln!(f, "Error: Signing key is required for encryption.")?;
write!(f, "Provide a signing key with --signing-key <path>")
}
EncryptError::PassphraseDisabled => wfl!(f, "err-enc-passphrase-disabled"),
EncryptError::PassphraseTimedOut => wfl!(f, "err-passphrase-timed-out"),
#[cfg(not(unix))]
EncryptError::PassphraseWithoutFileArgument => {
wfl!(f, "err-enc-passphrase-without-file")
}
EncryptError::PluginNameFlag => {
wfl!(f, "err-enc-plugin-name-flag")
}
EncryptError::SigningError(e) => {
write!(f, "Signing error: {}", e)
}
}
}
}
#[derive(Debug)]
pub(crate) struct DetectedPowerShellCorruptionError;
impl fmt::Display for DetectedPowerShellCorruptionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
wlnfl!(f, "err-detected-powershell-corruption")?;
wfl!(f, "rec-detected-powershell-corruption")
}
}
impl std::error::Error for DetectedPowerShellCorruptionError {}
pub(crate) enum DecryptError {
Age(anubis_age::DecryptError),
ArmorFlag,
IdentityRead(anubis_age::cli_common::ReadError),
Io(io::Error),
MissingIdentities {
stdin_identity: bool,
},
MissingVerifyKey,
MixedIdentityAndPassphrase,
MixedIdentityAndPluginName,
PassphraseFlag,
PassphraseTimedOut,
#[cfg(not(unix))]
PassphraseWithoutFileArgument,
PluginNameFlag,
RecipientFlag,
RecipientsFileFlag,
VerificationError(String),
}
impl From<anubis_age::DecryptError> for DecryptError {
fn from(e: anubis_age::DecryptError) -> Self {
DecryptError::Age(e)
}
}
impl From<anubis_age::cli_common::ReadError> for DecryptError {
fn from(e: anubis_age::cli_common::ReadError) -> Self {
DecryptError::IdentityRead(e)
}
}
impl From<io::Error> for DecryptError {
fn from(e: io::Error) -> Self {
DecryptError::Io(e)
}
}
impl fmt::Display for DecryptError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DecryptError::Age(e) => match e {
anubis_age::DecryptError::ExcessiveWork { required, .. } => {
writeln!(f, "{}", e)?;
wfl!(f, "rec-dec-excessive-work", wf = required)
}
_ => write!(f, "{}", e),
},
DecryptError::ArmorFlag => {
wlnfl!(f, "err-dec-armor-flag")?;
wfl!(f, "rec-dec-armor-flag")
}
DecryptError::IdentityRead(e) => write!(f, "{}", e),
DecryptError::Io(e) => write!(f, "{}", e),
DecryptError::MissingIdentities { stdin_identity } => {
wlnfl!(f, "err-dec-missing-identities")?;
if *stdin_identity {
wfl!(f, "rec-dec-missing-identities-stdin")
} else {
wfl!(f, "rec-dec-missing-identities")
}
}
DecryptError::MissingVerifyKey => {
writeln!(f, "Error: Verification key is required for decryption.")?;
write!(
f,
"Provide a verification key with --verify-key <key-or-file>"
)
}
DecryptError::MixedIdentityAndPassphrase => {
wfl!(f, "err-dec-mixed-identity-passphrase")
}
DecryptError::MixedIdentityAndPluginName => {
wfl!(f, "err-mixed-identity-and-plugin-name")
}
DecryptError::PassphraseFlag => {
wlnfl!(f, "err-dec-passphrase-flag")?;
wfl!(f, "rec-dec-passphrase-flag")
}
DecryptError::PassphraseTimedOut => wfl!(f, "err-passphrase-timed-out"),
#[cfg(not(unix))]
DecryptError::PassphraseWithoutFileArgument => {
wfl!(f, "err-dec-passphrase-without-file-win")
}
DecryptError::PluginNameFlag => {
wfl!(f, "err-enc-plugin-name-flag")
}
DecryptError::RecipientFlag => {
wlnfl!(f, "err-dec-recipient-flag")?;
wfl!(f, "rec-dec-recipient-flag")
}
DecryptError::RecipientsFileFlag => {
wlnfl!(f, "err-dec-recipients-file-flag")?;
wfl!(f, "rec-dec-recipient-flag")
}
DecryptError::VerificationError(e) => {
write!(f, "Signature verification failed: {}", e)
}
}
}
}
pub(crate) enum Error {
Decryption(DecryptError),
Encryption(EncryptError),
IdentityFlagAmbiguous,
MixedEncryptAndDecrypt,
SameInputAndOutput(String),
}
impl From<DecryptError> for Error {
fn from(e: DecryptError) -> Self {
Error::Decryption(e)
}
}
impl From<EncryptError> for Error {
fn from(e: EncryptError) -> Self {
Error::Encryption(e)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Decryption(e) => writeln!(f, "{}", e)?,
Error::Encryption(e) => writeln!(f, "{}", e)?,
Error::IdentityFlagAmbiguous => wlnfl!(f, "err-identity-ambiguous")?,
Error::MixedEncryptAndDecrypt => wlnfl!(f, "err-mixed-encrypt-decrypt")?,
Error::SameInputAndOutput(filename) => {
wlnfl!(f, "err-same-input-and-output", filename = filename.as_str())?
}
}
writeln!(f)?;
writeln!(f, "[ {} ]", crate::fl!("err-ux-A"))?;
write!(
f,
"[ {}: https://github.com/anubis-rage/anubis-rage/issues {} ]",
crate::fl!("err-ux-B"),
crate::fl!("err-ux-C")
)
}
}