mirror of
https://github.com/LordGrimmauld/yubi-oath-rs.git
synced 2025-03-03 21:34:40 +01:00
slightly better error handling
by implementing the proper traits for error types and propagating error where possible
This commit is contained in:
parent
821229af35
commit
dfdc63d424
4 changed files with 50 additions and 49 deletions
|
@ -24,19 +24,6 @@ pub enum ErrorResponse {
|
|||
}
|
||||
|
||||
impl ErrorResponse {
|
||||
pub fn as_string(self) -> String {
|
||||
match self {
|
||||
ErrorResponse::NoSpace => "No Space left on device",
|
||||
ErrorResponse::CommandAborted => "Command aborted",
|
||||
ErrorResponse::InvalidInstruction => "Invalid instruction",
|
||||
ErrorResponse::AuthRequired => "Authentication required",
|
||||
ErrorResponse::WrongSyntax => "Wrong syntax",
|
||||
ErrorResponse::GenericError => "Generic Error",
|
||||
ErrorResponse::NoSuchObject => "No such Object",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn any_match(code: u16) -> Option<ErrorResponse> {
|
||||
for resp in ErrorResponse::iter() {
|
||||
if code == resp as u16 {
|
||||
|
@ -47,6 +34,22 @@ impl ErrorResponse {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ErrorResponse {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::NoSpace => f.write_str("No Space left on device"),
|
||||
Self::CommandAborted => f.write_str("Command aborted"),
|
||||
Self::InvalidInstruction => f.write_str("Invalid instruction"),
|
||||
Self::AuthRequired => f.write_str("Authentication required"),
|
||||
Self::WrongSyntax => f.write_str("Wrong syntax"),
|
||||
Self::GenericError => f.write_str("Generic Error"),
|
||||
Self::NoSuchObject => f.write_str("No such Object"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ErrorResponse {}
|
||||
|
||||
#[derive(Debug, EnumIter, Clone, Copy)]
|
||||
#[repr(u16)]
|
||||
pub enum SuccessResponse {
|
||||
|
|
|
@ -30,7 +30,7 @@ fn main() {
|
|||
for yubikey in yubikeys {
|
||||
let device_label: &str = yubikey;
|
||||
println!("Found device with label {}", device_label);
|
||||
let session = OathSession::new(yubikey);
|
||||
let session = OathSession::new(yubikey).unwrap();
|
||||
println!("YubiKey version is {:?}", session.get_version());
|
||||
for c in session.list_oath_codes().unwrap() {
|
||||
println!("{}", c);
|
||||
|
|
|
@ -133,8 +133,8 @@ impl<'a> RefreshableOathCredential<'a> {
|
|||
}
|
||||
|
||||
impl<'a> OathSession<'a> {
|
||||
pub fn new(name: &str) -> Self {
|
||||
let transaction_context = TransactionContext::from_name(name);
|
||||
pub fn new(name: &str) -> Result<Self, FormattableErrorResponse> {
|
||||
let transaction_context = TransactionContext::from_name(name)?;
|
||||
let info_buffer = transaction_context
|
||||
.apdu_read_all(0, INS_SELECT, 0x04, 0, Some(&OATH_AID))
|
||||
.unwrap();
|
||||
|
@ -145,7 +145,7 @@ impl<'a> OathSession<'a> {
|
|||
println!("{:?}: {:?}", tag, data);
|
||||
}
|
||||
|
||||
OathSession {
|
||||
Ok(Self {
|
||||
version: clone_with_lifetime(
|
||||
info_map.get(&(Tag::Version as u8)).unwrap_or(&vec![0u8; 0]),
|
||||
)
|
||||
|
@ -160,7 +160,7 @@ impl<'a> OathSession<'a> {
|
|||
.leak(),
|
||||
name: name.to_string(),
|
||||
transaction_context,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_version(&self) -> &[u8] {
|
||||
|
|
|
@ -18,23 +18,23 @@ pub enum FormattableErrorResponse {
|
|||
}
|
||||
|
||||
impl FormattableErrorResponse {
|
||||
pub fn from_apdu_response(sw1: u8, sw2: u8) -> FormattableErrorResponse {
|
||||
pub fn from_apdu_response(sw1: u8, sw2: u8) -> Self {
|
||||
let code: u16 = (sw1 as u16 | sw2 as u16) << 8;
|
||||
if let Some(e) = ErrorResponse::any_match(code) {
|
||||
return FormattableErrorResponse::Protocol(e);
|
||||
return Self::Protocol(e);
|
||||
}
|
||||
if SuccessResponse::any_match(code)
|
||||
.or(SuccessResponse::any_match(sw1.into()))
|
||||
.is_some()
|
||||
{
|
||||
return FormattableErrorResponse::NoError;
|
||||
return Self::NoError;
|
||||
}
|
||||
FormattableErrorResponse::Unknown(String::from("Unknown error"))
|
||||
Self::Unknown(String::from("Unknown error"))
|
||||
}
|
||||
pub fn is_ok(&self) -> bool {
|
||||
*self == FormattableErrorResponse::NoError
|
||||
*self == Self::NoError
|
||||
}
|
||||
pub fn as_opt(self) -> Option<FormattableErrorResponse> {
|
||||
pub fn as_opt(self) -> Option<Self> {
|
||||
if self.is_ok() {
|
||||
None
|
||||
} else {
|
||||
|
@ -42,25 +42,27 @@ impl FormattableErrorResponse {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_transmit(err: pcsc::Error) -> FormattableErrorResponse {
|
||||
FormattableErrorResponse::PcscError(err)
|
||||
fn from_transmit(err: pcsc::Error) -> Self {
|
||||
Self::PcscError(err)
|
||||
}
|
||||
}
|
||||
|
||||
fn as_string(&self) -> String {
|
||||
match self {
|
||||
FormattableErrorResponse::NoError => "ok".to_string(),
|
||||
FormattableErrorResponse::Unknown(msg) => msg.to_owned(),
|
||||
FormattableErrorResponse::Protocol(error_response) => error_response.as_string(),
|
||||
FormattableErrorResponse::PcscError(error) => format!("{}", error),
|
||||
FormattableErrorResponse::ParsingError(msg) => msg.to_owned(),
|
||||
FormattableErrorResponse::DeviceMismatchError => "Devices do not match".to_string(),
|
||||
}
|
||||
impl From<pcsc::Error> for FormattableErrorResponse {
|
||||
fn from(value: pcsc::Error) -> Self {
|
||||
Self::PcscError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FormattableErrorResponse {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&self.as_string())
|
||||
match self {
|
||||
Self::NoError => f.write_str("ok"),
|
||||
Self::Unknown(msg) => f.write_str(msg),
|
||||
Self::Protocol(error_response) => f.write_fmt(format_args!("{}", error_response)),
|
||||
Self::PcscError(error) => f.write_fmt(format_args!("{}", error)),
|
||||
Self::ParsingError(msg) => f.write_str(msg),
|
||||
Self::DeviceMismatchError => f.write_str("Devices do not match"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,26 +141,22 @@ pub struct TransactionContext {
|
|||
}
|
||||
|
||||
impl TransactionContext {
|
||||
pub fn from_name(name: &str) -> Self {
|
||||
// FIXME: error handling here
|
||||
|
||||
pub fn from_name(name: &str) -> Result<Self, FormattableErrorResponse> {
|
||||
// Establish a PC/SC context
|
||||
let ctx = pcsc::Context::establish(pcsc::Scope::User).unwrap();
|
||||
let ctx = pcsc::Context::establish(pcsc::Scope::User)?;
|
||||
|
||||
// Connect to the card
|
||||
let card = ctx
|
||||
.connect(
|
||||
&CString::new(name).unwrap(),
|
||||
pcsc::ShareMode::Shared,
|
||||
pcsc::Protocols::ANY,
|
||||
)
|
||||
.unwrap();
|
||||
let card = ctx.connect(
|
||||
&CString::new(name).unwrap(),
|
||||
pcsc::ShareMode::Shared,
|
||||
pcsc::Protocols::ANY,
|
||||
)?;
|
||||
|
||||
TransactionContextBuilder {
|
||||
Ok(TransactionContextBuilder {
|
||||
card,
|
||||
transaction_builder: |c| c.transaction().unwrap(),
|
||||
}
|
||||
.build()
|
||||
.build())
|
||||
}
|
||||
|
||||
pub fn apdu(
|
||||
|
|
Loading…
Add table
Reference in a new issue