1use core::fmt;
4use std::{
5 error::Error as StdError,
6 io,
7 result,
8};
9
10#[derive(Copy, Clone, Debug, PartialEq, Eq)]
16pub enum CtapStatus {
17 Ok,
19 InvalidCommand,
21 ChannelBusy,
24 CborUnexpectedType,
26 InvalidCbor,
28 MissingParameter,
30 OperationDenied,
32 KeepaliveCancel,
34 NoCredentials,
36 UserActionTimeout,
38 PinInvalid,
40 PinBlocked,
42 PinAuthInvalid,
44 PinAuthBlocked,
46 PinNotSet,
48 PinRequired,
50 PinPolicyViolation,
52 Other(u8),
54}
55
56impl CtapStatus {
57 #[must_use]
59 pub const fn from_byte(byte: u8) -> Self {
60 match byte {
61 0x00 => Self::Ok,
62 0x01 => Self::InvalidCommand,
63 0x06 => Self::ChannelBusy,
64 0x11 => Self::CborUnexpectedType,
65 0x12 => Self::InvalidCbor,
66 0x13 => Self::MissingParameter,
67 0x27 => Self::OperationDenied,
68 0x2D => Self::KeepaliveCancel,
69 0x2E => Self::NoCredentials,
70 0x2F => Self::UserActionTimeout,
71 0x31 => Self::PinInvalid,
72 0x32 => Self::PinBlocked,
73 0x33 => Self::PinAuthInvalid,
74 0x34 => Self::PinAuthBlocked,
75 0x35 => Self::PinNotSet,
76 0x36 => Self::PinRequired,
77 0x37 => Self::PinPolicyViolation,
78 other => Self::Other(other),
79 }
80 }
81
82 #[must_use]
84 pub const fn as_byte(self) -> u8 {
85 match self {
86 Self::Ok => 0x00,
87 Self::InvalidCommand => 0x01,
88 Self::ChannelBusy => 0x06,
89 Self::CborUnexpectedType => 0x11,
90 Self::InvalidCbor => 0x12,
91 Self::MissingParameter => 0x13,
92 Self::OperationDenied => 0x27,
93 Self::KeepaliveCancel => 0x2D,
94 Self::NoCredentials => 0x2E,
95 Self::UserActionTimeout => 0x2F,
96 Self::PinInvalid => 0x31,
97 Self::PinBlocked => 0x32,
98 Self::PinAuthInvalid => 0x33,
99 Self::PinAuthBlocked => 0x34,
100 Self::PinNotSet => 0x35,
101 Self::PinRequired => 0x36,
102 Self::PinPolicyViolation => 0x37,
103 Self::Other(byte) => byte,
104 }
105 }
106}
107
108impl From<u8> for CtapStatus {
109 fn from(byte: u8) -> Self {
110 Self::from_byte(byte)
111 }
112}
113
114impl From<CtapStatus> for u8 {
115 fn from(status: CtapStatus) -> Self {
116 status.as_byte()
117 }
118}
119
120impl fmt::Display for CtapStatus {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 write!(f, "CTAP status 0x{:02X}", self.as_byte())
123 }
124}
125
126#[derive(Debug)]
128pub enum Error {
129 Ctap(CtapStatus),
131 MissingExtension(&'static str),
133 Io(io::Error),
135 Hid(String),
137 Cbor(String),
139 Pin(&'static str),
141 Parse(&'static str),
143}
144
145impl fmt::Display for Error {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 match *self {
148 Self::Ctap(ref status) => write!(f, "{status}"),
149 Self::MissingExtension(name) => write!(f, "device omitted required extension: {name}"),
150 Self::Io(ref err) => write!(f, "hid io: {err}"),
151 Self::Hid(ref msg) => write!(f, "hidapi: {msg}"),
152 Self::Cbor(ref msg) => write!(f, "cbor: {msg}"),
153 Self::Pin(msg) => write!(f, "pin protocol: {msg}"),
154 Self::Parse(msg) => write!(f, "parse: {msg}"),
155 }
156 }
157}
158
159impl StdError for Error {
160 fn source(&self) -> Option<&(dyn StdError + 'static)> {
161 match *self {
162 Self::Io(ref err) => Some(err),
163 _ => None,
164 }
165 }
166}
167
168impl From<io::Error> for Error {
169 fn from(err: io::Error) -> Self {
170 Self::Io(err)
171 }
172}
173
174pub type Result<T> = result::Result<T, Error>;