use std::fmt;
use std::io;
use yubikey::{piv::RetiredSlotId, Serial};
use crate::util::slot_to_ui;
pub enum Error {
CustomManagementKey,
InvalidFlagCommand(String, String),
InvalidFlagTui(String),
InvalidPinLength,
InvalidPinPolicy(String),
InvalidSlot(u8),
InvalidTouchPolicy(String),
Io(io::Error),
MultipleCommands,
MultipleYubiKeys,
NoEmptySlots(Serial),
NoMatchingSerial(Serial),
SlotHasNoIdentity(RetiredSlotId),
SlotIsNotEmpty(RetiredSlotId),
TimedOut,
UseListForSingleSlot,
YubiKey(yubikey::Error),
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::Io(e)
}
}
impl From<yubikey::Error> for Error {
fn from(e: yubikey::Error) -> Self {
Error::YubiKey(e)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::CustomManagementKey => {
writeln!(f, "Custom unprotected management keys are not supported.")?
}
Error::InvalidFlagCommand(flag, command) => {
writeln!(f, "Flag '{}' cannot be used with '{}'.", flag, command)?
}
Error::InvalidFlagTui(flag) => writeln!(
f,
"Flag '{}' cannot be used with the interactive interface.",
flag
)?,
Error::InvalidPinLength => writeln!(f, "The PIN needs to be 1-8 characters.")?,
Error::InvalidPinPolicy(s) => writeln!(
f,
"Invalid PIN policy '{}' (expected [always, once, never]).",
s
)?,
Error::InvalidSlot(slot) => writeln!(
f,
"Invalid slot '{}' (expected number between 1 and 20).",
slot
)?,
Error::InvalidTouchPolicy(s) => writeln!(
f,
"Invalid touch policy '{}' (expected [always, cached, never]).",
s
)?,
Error::Io(e) => writeln!(f, "Failed to set up YubiKey: {}", e)?,
Error::MultipleCommands => writeln!(
f,
"Only one of --generate, --identity, --list, --list-all can be specified."
)?,
Error::MultipleYubiKeys => writeln!(
f,
"Multiple YubiKeys are plugged in. Use --serial to select a single YubiKey."
)?,
Error::NoEmptySlots(serial) => {
writeln!(f, "YubiKey with serial {} has no empty slots.", serial)?
}
Error::NoMatchingSerial(serial) => {
writeln!(f, "Could not find YubiKey with serial {}.", serial)?
}
Error::SlotHasNoIdentity(slot) => writeln!(
f,
"Slot {} does not contain an age identity or compatible key.",
slot_to_ui(slot)
)?,
Error::SlotIsNotEmpty(slot) => writeln!(
f,
"Slot {} is not empty. Use --force to overwrite the slot.",
slot_to_ui(slot)
)?,
Error::TimedOut => {
writeln!(f, "Timed out while waiting for a YubiKey to be inserted.")?
}
Error::UseListForSingleSlot => {
writeln!(f, "Use --list to print the recipient for a single slot.")?
}
Error::YubiKey(e) => match e {
yubikey::Error::NotFound => {
writeln!(f, "Please insert the YubiKey you want to set up")?
}
yubikey::Error::WrongPin { tries } => writeln!(
f,
"Invalid PIN ({} tries remaining before it is blocked)",
tries
)?,
e => {
writeln!(f, "Error while communicating with YubiKey: {}", e)?;
use std::error::Error;
if let Some(inner) = e.source() {
writeln!(f, "Cause: {}", inner)?;
}
}
},
}
writeln!(f)?;
writeln!(
f,
"[ Did this not do what you expected? Could an error be more useful? ]"
)?;
write!(
f,
"[ Tell us: https://str4d.xyz/age-plugin-yubikey/report ]"
)
}
}