turn FormattableErrorResponse into an actual Error type

By removing the NoError variant as it is useless.
This commit is contained in:
Bilal Elmoussaoui 2025-02-13 12:45:19 +01:00
parent dfdc63d424
commit 1110537735
2 changed files with 27 additions and 62 deletions

View file

@ -133,11 +133,10 @@ impl<'a> RefreshableOathCredential<'a> {
} }
impl<'a> OathSession<'a> { impl<'a> OathSession<'a> {
pub fn new(name: &str) -> Result<Self, FormattableErrorResponse> { pub fn new(name: &str) -> Result<Self, Error> {
let transaction_context = TransactionContext::from_name(name)?; let transaction_context = TransactionContext::from_name(name)?;
let info_buffer = transaction_context let info_buffer =
.apdu_read_all(0, INS_SELECT, 0x04, 0, Some(&OATH_AID)) transaction_context.apdu_read_all(0, INS_SELECT, 0x04, 0, Some(&OATH_AID))?;
.unwrap();
let info_map = tlv_to_map(info_buffer); let info_map = tlv_to_map(info_buffer);
for (tag, data) in &info_map { for (tag, data) in &info_map {
@ -167,10 +166,7 @@ impl<'a> OathSession<'a> {
self.version self.version
} }
pub fn delete_code( pub fn delete_code(&self, cred: OathCredential) -> Result<ApduResponse, Error> {
&self,
cred: OathCredential,
) -> Result<ApduResponse, FormattableErrorResponse> {
self.transaction_context.apdu( self.transaction_context.apdu(
0, 0,
Instruction::Delete as u8, Instruction::Delete as u8,
@ -184,9 +180,9 @@ impl<'a> OathSession<'a> {
&self, &self,
cred: OathCredential, cred: OathCredential,
timestamp_sys: Option<SystemTime>, timestamp_sys: Option<SystemTime>,
) -> Result<OathCodeDisplay, FormattableErrorResponse> { ) -> Result<OathCodeDisplay, Error> {
if self.name != cred.device_id { if self.name != cred.device_id {
return Err(FormattableErrorResponse::DeviceMismatchError); return Err(Error::DeviceMismatchError);
} }
let timestamp = time_to_u64(timestamp_sys.unwrap_or_else(SystemTime::now)); let timestamp = time_to_u64(timestamp_sys.unwrap_or_else(SystemTime::now));
@ -207,23 +203,18 @@ impl<'a> OathSession<'a> {
Some(&data), Some(&data),
); );
let meta = let meta = TlvIter::from_vec(resp?).next().ok_or(Error::ParsingError(
TlvIter::from_vec(resp?) "No credentials to unpack found in response".to_string(),
.next() ))?;
.ok_or(FormattableErrorResponse::ParsingError(
"No credentials to unpack found in response".to_string(),
))?;
OathCodeDisplay::from_tlv(meta).ok_or(FormattableErrorResponse::ParsingError( OathCodeDisplay::from_tlv(meta).ok_or(Error::ParsingError(
"error parsing calculation response".to_string(), "error parsing calculation response".to_string(),
)) ))
} }
/// Read the OATH codes from the device, calculate TOTP codes that don't /// Read the OATH codes from the device, calculate TOTP codes that don't
/// need touch /// need touch
pub fn calculate_oath_codes( pub fn calculate_oath_codes(&self) -> Result<Vec<RefreshableOathCredential>, Error> {
&self,
) -> Result<Vec<RefreshableOathCredential>, FormattableErrorResponse> {
let timestamp = SystemTime::now(); let timestamp = SystemTime::now();
// Request OATH codes from device // Request OATH codes from device
let response = self.transaction_context.apdu_read_all( let response = self.transaction_context.apdu_read_all(
@ -258,7 +249,7 @@ impl<'a> OathSession<'a> {
return Ok(key_buffer); return Ok(key_buffer);
} }
pub fn list_oath_codes(&self) -> Result<Vec<CredentialIDData>, FormattableErrorResponse> { pub fn list_oath_codes(&self) -> Result<Vec<CredentialIDData>, Error> {
// Request OATH codes from device // Request OATH codes from device
let response = let response =
self.transaction_context self.transaction_context

View file

@ -8,8 +8,7 @@ use pcsc::{Card, Transaction};
use crate::{ErrorResponse, Instruction, SuccessResponse, Tag}; use crate::{ErrorResponse, Instruction, SuccessResponse, Tag};
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
pub enum FormattableErrorResponse { pub enum Error {
NoError,
Unknown(String), Unknown(String),
Protocol(ErrorResponse), Protocol(ErrorResponse),
PcscError(pcsc::Error), PcscError(pcsc::Error),
@ -17,46 +16,31 @@ pub enum FormattableErrorResponse {
DeviceMismatchError, DeviceMismatchError,
} }
impl FormattableErrorResponse { impl Error {
pub fn from_apdu_response(sw1: u8, sw2: u8) -> Self { fn from_apdu_response(sw1: u8, sw2: u8) -> Result<(), Self> {
let code: u16 = (sw1 as u16 | sw2 as u16) << 8; let code: u16 = (sw1 as u16 | sw2 as u16) << 8;
if let Some(e) = ErrorResponse::any_match(code) { if let Some(e) = ErrorResponse::any_match(code) {
return Self::Protocol(e); return Err(Self::Protocol(e));
} }
if SuccessResponse::any_match(code) if SuccessResponse::any_match(code)
.or(SuccessResponse::any_match(sw1.into())) .or(SuccessResponse::any_match(sw1.into()))
.is_some() .is_some()
{ {
return Self::NoError; return Ok(());
} }
Self::Unknown(String::from("Unknown error")) Err(Self::Unknown(String::from("Unknown error")))
}
pub fn is_ok(&self) -> bool {
*self == Self::NoError
}
pub fn as_opt(self) -> Option<Self> {
if self.is_ok() {
None
} else {
Some(self)
}
}
fn from_transmit(err: pcsc::Error) -> Self {
Self::PcscError(err)
} }
} }
impl From<pcsc::Error> for FormattableErrorResponse { impl From<pcsc::Error> for Error {
fn from(value: pcsc::Error) -> Self { fn from(value: pcsc::Error) -> Self {
Self::PcscError(value) Self::PcscError(value)
} }
} }
impl Display for FormattableErrorResponse { impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::NoError => f.write_str("ok"),
Self::Unknown(msg) => f.write_str(msg), Self::Unknown(msg) => f.write_str(msg),
Self::Protocol(error_response) => f.write_fmt(format_args!("{}", error_response)), Self::Protocol(error_response) => f.write_fmt(format_args!("{}", error_response)),
Self::PcscError(error) => f.write_fmt(format_args!("{}", error)), Self::PcscError(error) => f.write_fmt(format_args!("{}", error)),
@ -80,7 +64,7 @@ fn apdu(
parameter1: u8, parameter1: u8,
parameter2: u8, parameter2: u8,
data: Option<&[u8]>, data: Option<&[u8]>,
) -> Result<ApduResponse, FormattableErrorResponse> { ) -> Result<ApduResponse, Error> {
let command = if let Some(data) = data { let command = if let Some(data) = data {
Command::new_with_payload(class, instruction, parameter1, parameter2, data) Command::new_with_payload(class, instruction, parameter1, parameter2, data)
} else { } else {
@ -93,19 +77,9 @@ fn apdu(
let mut rx_buf = [0; pcsc::MAX_BUFFER_SIZE]; let mut rx_buf = [0; pcsc::MAX_BUFFER_SIZE];
// Write the payload to the device and error if there is a problem // Write the payload to the device and error if there is a problem
let rx_buf = match tx.transmit(&tx_buf, &mut rx_buf) { let rx_buf = tx.transmit(&tx_buf, &mut rx_buf)?;
Ok(slice) => slice,
// Err(err) => return Err(format!("{}", err)),
Err(err) => return Err(FormattableErrorResponse::from_transmit(err)),
};
let resp = Response::from(rx_buf); let resp = Response::from(rx_buf);
let error_context = Error::from_apdu_response(resp.trailer.0, resp.trailer.1)?;
FormattableErrorResponse::from_apdu_response(resp.trailer.0, resp.trailer.1);
if !error_context.is_ok() {
return Err(error_context);
}
Ok(ApduResponse { Ok(ApduResponse {
buf: resp.payload.to_vec(), buf: resp.payload.to_vec(),
@ -121,7 +95,7 @@ fn apdu_read_all(
parameter1: u8, parameter1: u8,
parameter2: u8, parameter2: u8,
data: Option<&[u8]>, data: Option<&[u8]>,
) -> Result<Vec<u8>, FormattableErrorResponse> { ) -> Result<Vec<u8>, Error> {
let mut response_buf = Vec::new(); let mut response_buf = Vec::new();
let mut resp = apdu(tx, class, instruction, parameter1, parameter2, data)?; let mut resp = apdu(tx, class, instruction, parameter1, parameter2, data)?;
response_buf.extend(resp.buf); response_buf.extend(resp.buf);
@ -141,7 +115,7 @@ pub struct TransactionContext {
} }
impl TransactionContext { impl TransactionContext {
pub fn from_name(name: &str) -> Result<Self, FormattableErrorResponse> { pub fn from_name(name: &str) -> Result<Self, Error> {
// Establish a PC/SC context // Establish a PC/SC context
let ctx = pcsc::Context::establish(pcsc::Scope::User)?; let ctx = pcsc::Context::establish(pcsc::Scope::User)?;
@ -166,7 +140,7 @@ impl TransactionContext {
parameter1: u8, parameter1: u8,
parameter2: u8, parameter2: u8,
data: Option<&[u8]>, data: Option<&[u8]>,
) -> Result<ApduResponse, FormattableErrorResponse> { ) -> Result<ApduResponse, Error> {
apdu( apdu(
self.borrow_transaction(), self.borrow_transaction(),
class, class,
@ -184,7 +158,7 @@ impl TransactionContext {
parameter1: u8, parameter1: u8,
parameter2: u8, parameter2: u8,
data: Option<&[u8]>, data: Option<&[u8]>,
) -> Result<Vec<u8>, FormattableErrorResponse> { ) -> Result<Vec<u8>, Error> {
apdu_read_all( apdu_read_all(
self.borrow_transaction(), self.borrow_transaction(),
class, class,