use core::fmt;
use std::{
error::Error as StdError,
io,
result,
};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CtapStatus {
Ok,
InvalidCommand,
ChannelBusy,
CborUnexpectedType,
InvalidCbor,
MissingParameter,
OperationDenied,
KeepaliveCancel,
NoCredentials,
UserActionTimeout,
PinInvalid,
PinBlocked,
PinAuthInvalid,
PinAuthBlocked,
PinNotSet,
PinRequired,
PinPolicyViolation,
Other(u8),
}
impl CtapStatus {
#[must_use]
pub const fn from_byte(byte: u8) -> Self {
match byte {
0x00 => Self::Ok,
0x01 => Self::InvalidCommand,
0x06 => Self::ChannelBusy,
0x11 => Self::CborUnexpectedType,
0x12 => Self::InvalidCbor,
0x13 => Self::MissingParameter,
0x27 => Self::OperationDenied,
0x2D => Self::KeepaliveCancel,
0x2E => Self::NoCredentials,
0x2F => Self::UserActionTimeout,
0x31 => Self::PinInvalid,
0x32 => Self::PinBlocked,
0x33 => Self::PinAuthInvalid,
0x34 => Self::PinAuthBlocked,
0x35 => Self::PinNotSet,
0x36 => Self::PinRequired,
0x37 => Self::PinPolicyViolation,
other => Self::Other(other),
}
}
#[must_use]
pub const fn as_byte(self) -> u8 {
match self {
Self::Ok => 0x00,
Self::InvalidCommand => 0x01,
Self::ChannelBusy => 0x06,
Self::CborUnexpectedType => 0x11,
Self::InvalidCbor => 0x12,
Self::MissingParameter => 0x13,
Self::OperationDenied => 0x27,
Self::KeepaliveCancel => 0x2D,
Self::NoCredentials => 0x2E,
Self::UserActionTimeout => 0x2F,
Self::PinInvalid => 0x31,
Self::PinBlocked => 0x32,
Self::PinAuthInvalid => 0x33,
Self::PinAuthBlocked => 0x34,
Self::PinNotSet => 0x35,
Self::PinRequired => 0x36,
Self::PinPolicyViolation => 0x37,
Self::Other(byte) => byte,
}
}
}
impl From<u8> for CtapStatus {
fn from(byte: u8) -> Self {
Self::from_byte(byte)
}
}
impl From<CtapStatus> for u8 {
fn from(status: CtapStatus) -> Self {
status.as_byte()
}
}
impl fmt::Display for CtapStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "CTAP status 0x{:02X}", self.as_byte())
}
}
#[derive(Debug)]
pub enum Error {
Ctap(CtapStatus),
MissingExtension(&'static str),
Io(io::Error),
Hid(String),
Cbor(String),
Pin(&'static str),
Parse(&'static str),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Ctap(ref status) => write!(f, "{status}"),
Self::MissingExtension(name) => write!(f, "device omitted required extension: {name}"),
Self::Io(ref err) => write!(f, "hid io: {err}"),
Self::Hid(ref msg) => write!(f, "hidapi: {msg}"),
Self::Cbor(ref msg) => write!(f, "cbor: {msg}"),
Self::Pin(msg) => write!(f, "pin protocol: {msg}"),
Self::Parse(msg) => write!(f, "parse: {msg}"),
}
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match *self {
Self::Io(ref err) => Some(err),
_ => None,
}
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Self::Io(err)
}
}
pub type Result<T> = result::Result<T, Error>;