use std::borrow; use std::error; use std::fmt; use std::os::raw; use std::result; /// An error returned by the nitrokey crate. #[derive(Debug)] pub enum Error { /// An error reported by the Nitrokey device in the response packet. CommandError(CommandError), /// Placeholder for testing. CommunicationError(CommunicationError), /// An error that occured during random number generation. RandError(rand_core::Error), } impl From for Error { fn from(err: CommandError) -> Self { Error::CommandError(err) } } impl From for Error { fn from(error: rand_core::Error) -> Self { Error::RandError(error) } } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match *self { Error::CommandError(ref err) => Some(err), Error::CommunicationError(_) => None, Error::RandError(ref err) => Some(err), } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Error::CommandError(ref err) => write!(f, "Command error: {}", err), Error::CommunicationError(_) => write!(f, "Placeholder"), Error::RandError(ref err) => write!(f, "RNG error: {}", err), } } } /// A result returned by the nitrokey crate. pub type Result = result::Result; /// An error reported by the Nitrokey device in the response packet. #[derive(Clone, Copy, Debug, PartialEq)] pub enum CommandError { /// A packet with a wrong checksum has been sent or received. WrongCrc, /// A command tried to access an OTP slot that does not exist. WrongSlot, /// A command tried to generate an OTP on a slot that is not configured. SlotNotProgrammed, /// The provided password is wrong. WrongPassword, /// You are not authorized for this command or provided a wrong temporary /// password. NotAuthorized, /// An error occurred when getting or setting the time. Timestamp, /// You did not provide a name for the OTP slot. NoName, /// This command is not supported by this device. NotSupported, /// This command is unknown. UnknownCommand, /// AES decryption failed. AesDecryptionFailed, /// An unknown error occurred. Unknown(i64), /// An unspecified error occurred. Undefined, /// You passed a string containing a null byte. InvalidString, /// A supplied string exceeded a length limit. StringTooLong, /// You passed an invalid slot. InvalidSlot, /// The supplied string was not in hexadecimal format. InvalidHexString, /// The target buffer was smaller than the source. TargetBufferTooSmall, } /// Placeholder for testing. #[derive(Debug)] pub enum CommunicationError { /// Placeholder for testing. NotConnected, } impl CommandError { fn as_str(&self) -> borrow::Cow<'static, str> { match *self { CommandError::WrongCrc => { "A packet with a wrong checksum has been sent or received".into() } CommandError::WrongSlot => "The given OTP slot does not exist".into(), CommandError::SlotNotProgrammed => "The given OTP slot is not programmed".into(), CommandError::WrongPassword => "The given password is wrong".into(), CommandError::NotAuthorized => { "You are not authorized for this command or provided a wrong temporary \ password" .into() } CommandError::Timestamp => "An error occurred when getting or setting the time".into(), CommandError::NoName => "You did not provide a name for the OTP slot".into(), CommandError::NotSupported => "This command is not supported by this device".into(), CommandError::UnknownCommand => "This command is unknown".into(), CommandError::AesDecryptionFailed => "AES decryption failed".into(), CommandError::Unknown(x) => { borrow::Cow::from(format!("An unknown error occurred ({})", x)) } CommandError::Undefined => "An unspecified error occurred".into(), CommandError::InvalidString => "You passed a string containing a null byte".into(), CommandError::StringTooLong => "The supplied string is too long".into(), CommandError::InvalidSlot => "The given slot is invalid".into(), CommandError::InvalidHexString => { "The supplied string is not in hexadecimal format".into() } CommandError::TargetBufferTooSmall => "The target buffer is too small".into(), } } } impl error::Error for CommandError {} impl fmt::Display for CommandError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.as_str()) } } impl From for CommandError { fn from(value: raw::c_int) -> Self { match value { 1 => CommandError::WrongCrc, 2 => CommandError::WrongSlot, 3 => CommandError::SlotNotProgrammed, 4 => CommandError::WrongPassword, 5 => CommandError::NotAuthorized, 6 => CommandError::Timestamp, 7 => CommandError::NoName, 8 => CommandError::NotSupported, 9 => CommandError::UnknownCommand, 10 => CommandError::AesDecryptionFailed, 200 => CommandError::StringTooLong, 201 => CommandError::InvalidSlot, 202 => CommandError::InvalidHexString, 203 => CommandError::TargetBufferTooSmall, x => CommandError::Unknown(x.into()), } } }