mirror of
https://github.com/LordGrimmauld/yubi-oath-rs.git
synced 2025-03-04 05:44:40 +01:00
turn FormattableErrorResponse into an actual Error type
By removing the NoError variant as it is useless.
This commit is contained in:
parent
dfdc63d424
commit
1110537735
2 changed files with 27 additions and 62 deletions
33
src/lib.rs
33
src/lib.rs
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Reference in a new issue