aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobin Krahl <robin.krahl@ireas.org>2019-01-20 22:16:36 +0100
committerRobin Krahl <robin.krahl@ireas.org>2019-01-20 22:17:37 +0100
commit8c57d3ace0215adb3cd5edd0f18e8cc513f65ff1 (patch)
tree27eb8ac46b130e08d917a7b91da8b48a14b644b6 /src
parent5da2735cfb8ccfaea1ebdee850ddd9fbd0bfb003 (diff)
parentd87859975dc158919ecd5bf11a1111a2da5fcb30 (diff)
downloadnitrokey-rs-8c57d3ace0215adb3cd5edd0f18e8cc513f65ff1.tar.gz
nitrokey-rs-8c57d3ace0215adb3cd5edd0f18e8cc513f65ff1.tar.bz2
Merge branch 'feature/error-refactoring' into next
RFC: https://lists.sr.ht/~ireas/nitrokey-rs-dev/%3C20190117000856.slgb6jwkwd3qu6ey%40localhost%3E
Diffstat (limited to 'src')
-rw-r--r--src/auth.rs63
-rw-r--r--src/config.rs8
-rw-r--r--src/device.rs225
-rw-r--r--src/error.rs233
-rw-r--r--src/lib.rs16
-rw-r--r--src/otp.rs83
-rw-r--r--src/pws.rs80
-rw-r--r--src/util.rs133
8 files changed, 482 insertions, 359 deletions
diff --git a/src/auth.rs b/src/auth.rs
index 2d61d4b..d1eb049 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -6,10 +6,9 @@ use nitrokey_sys;
use crate::config::{Config, RawConfig};
use crate::device::{Device, DeviceWrapper, Pro, Storage};
+use crate::error::Error;
use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData, RawOtpSlotData};
-use crate::util::{
- generate_password, get_command_result, get_cstring, result_from_string, CommandError,
-};
+use crate::util::{generate_password, get_command_result, get_cstring, result_from_string};
static TEMPORARY_PASSWORD_LENGTH: usize = 25;
@@ -34,12 +33,12 @@ pub trait Authenticate {
///
/// ```no_run
/// use nitrokey::{Authenticate, DeviceWrapper, User};
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
/// fn perform_user_task(device: &User<DeviceWrapper>) {}
/// fn perform_other_task(device: &DeviceWrapper) {}
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let device = match device.authenticate_user("123456") {
/// Ok(user) => {
@@ -56,10 +55,10 @@ pub trait Authenticate {
/// # }
/// ```
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`RngError`]: enum.CommandError.html#variant.RngError
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, CommandError)>
+ fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)>
where
Self: Device + Sized;
@@ -80,12 +79,12 @@ pub trait Authenticate {
///
/// ```no_run
/// use nitrokey::{Authenticate, Admin, DeviceWrapper};
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
/// fn perform_admin_task(device: &Admin<DeviceWrapper>) {}
/// fn perform_other_task(device: &DeviceWrapper) {}
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let device = match device.authenticate_admin("123456") {
/// Ok(admin) => {
@@ -102,10 +101,10 @@ pub trait Authenticate {
/// # }
/// ```
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`RngError`]: enum.CommandError.html#variant.RngError
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, CommandError)>
+ fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, Error)>
where
Self: Device + Sized;
}
@@ -144,7 +143,7 @@ pub struct Admin<T: Device> {
temp_password: Vec<u8>,
}
-fn authenticate<D, A, T>(device: D, password: &str, callback: T) -> Result<A, (D, CommandError)>
+fn authenticate<D, A, T>(device: D, password: &str, callback: T) -> Result<A, (D, Error)>
where
D: Device,
A: AuthenticatedDevice<D>,
@@ -162,7 +161,7 @@ where
let temp_password_ptr = temp_password.as_ptr() as *const c_char;
return match callback(password_ptr, temp_password_ptr) {
0 => Ok(A::new(device, temp_password)),
- rv => Err((device, CommandError::from(rv))),
+ rv => Err((device, Error::from(rv))),
};
}
@@ -170,7 +169,7 @@ fn authenticate_user_wrapper<T, C>(
device: T,
constructor: C,
password: &str,
-) -> Result<User<DeviceWrapper>, (DeviceWrapper, CommandError)>
+) -> Result<User<DeviceWrapper>, (DeviceWrapper, Error)>
where
T: Device,
C: Fn(T) -> DeviceWrapper,
@@ -186,7 +185,7 @@ fn authenticate_admin_wrapper<T, C>(
device: T,
constructor: C,
password: &str,
-) -> Result<Admin<DeviceWrapper>, (DeviceWrapper, CommandError)>
+) -> Result<Admin<DeviceWrapper>, (DeviceWrapper, Error)>
where
T: Device,
C: Fn(T) -> DeviceWrapper,
@@ -216,14 +215,14 @@ impl<T: Device> Deref for User<T> {
}
impl<T: Device> GenerateOtp for User<T> {
- fn get_hotp_code(&self, slot: u8) -> Result<String, CommandError> {
+ fn get_hotp_code(&self, slot: u8) -> Result<String, Error> {
unsafe {
let temp_password_ptr = self.temp_password.as_ptr() as *const c_char;
return result_from_string(nitrokey_sys::NK_get_hotp_code_PIN(slot, temp_password_ptr));
}
}
- fn get_totp_code(&self, slot: u8) -> Result<String, CommandError> {
+ fn get_totp_code(&self, slot: u8) -> Result<String, Error> {
unsafe {
let temp_password_ptr = self.temp_password.as_ptr() as *const c_char;
return result_from_string(nitrokey_sys::NK_get_totp_code_PIN(
@@ -272,9 +271,9 @@ impl<T: Device> Admin<T> {
///
/// ```no_run
/// use nitrokey::{Authenticate, Config};
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let config = Config::new(None, None, None, false);
/// match device.authenticate_admin("12345678") {
@@ -288,8 +287,8 @@ impl<T: Device> Admin<T> {
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- pub fn write_config(&self, config: Config) -> Result<(), CommandError> {
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
+ pub fn write_config(&self, config: Config) -> Result<(), Error> {
let raw_config = RawConfig::try_from(config)?;
unsafe {
get_command_result(nitrokey_sys::NK_write_config(
@@ -303,7 +302,7 @@ impl<T: Device> Admin<T> {
}
}
- fn write_otp_slot<C>(&self, data: OtpSlotData, callback: C) -> Result<(), CommandError>
+ fn write_otp_slot<C>(&self, data: OtpSlotData, callback: C) -> Result<(), Error>
where
C: Fn(RawOtpSlotData, *const c_char) -> c_int,
{
@@ -314,7 +313,7 @@ impl<T: Device> Admin<T> {
}
impl<T: Device> ConfigureOtp for Admin<T> {
- fn write_hotp_slot(&self, data: OtpSlotData, counter: u64) -> Result<(), CommandError> {
+ fn write_hotp_slot(&self, data: OtpSlotData, counter: u64) -> Result<(), Error> {
self.write_otp_slot(data, |raw_data: RawOtpSlotData, temp_password_ptr| unsafe {
nitrokey_sys::NK_write_hotp_slot(
raw_data.number,
@@ -330,7 +329,7 @@ impl<T: Device> ConfigureOtp for Admin<T> {
})
}
- fn write_totp_slot(&self, data: OtpSlotData, time_window: u16) -> Result<(), CommandError> {
+ fn write_totp_slot(&self, data: OtpSlotData, time_window: u16) -> Result<(), Error> {
self.write_otp_slot(data, |raw_data: RawOtpSlotData, temp_password_ptr| unsafe {
nitrokey_sys::NK_write_totp_slot(
raw_data.number,
@@ -346,12 +345,12 @@ impl<T: Device> ConfigureOtp for Admin<T> {
})
}
- fn erase_hotp_slot(&self, slot: u8) -> Result<(), CommandError> {
+ fn erase_hotp_slot(&self, slot: u8) -> Result<(), Error> {
let temp_password_ptr = self.temp_password.as_ptr() as *const c_char;
unsafe { get_command_result(nitrokey_sys::NK_erase_hotp_slot(slot, temp_password_ptr)) }
}
- fn erase_totp_slot(&self, slot: u8) -> Result<(), CommandError> {
+ fn erase_totp_slot(&self, slot: u8) -> Result<(), Error> {
let temp_password_ptr = self.temp_password.as_ptr() as *const c_char;
unsafe { get_command_result(nitrokey_sys::NK_erase_totp_slot(slot, temp_password_ptr)) }
}
@@ -367,7 +366,7 @@ impl<T: Device> AuthenticatedDevice<T> for Admin<T> {
}
impl Authenticate for DeviceWrapper {
- fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, CommandError)> {
+ fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)> {
match self {
DeviceWrapper::Storage(storage) => {
authenticate_user_wrapper(storage, DeviceWrapper::Storage, password)
@@ -376,7 +375,7 @@ impl Authenticate for DeviceWrapper {
}
}
- fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, CommandError)> {
+ fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, Error)> {
match self {
DeviceWrapper::Storage(storage) => {
authenticate_admin_wrapper(storage, DeviceWrapper::Storage, password)
@@ -389,13 +388,13 @@ impl Authenticate for DeviceWrapper {
}
impl Authenticate for Pro {
- fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, CommandError)> {
+ fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)> {
authenticate(self, password, |password_ptr, temp_password_ptr| unsafe {
nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr)
})
}
- fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, CommandError)> {
+ fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, Error)> {
authenticate(self, password, |password_ptr, temp_password_ptr| unsafe {
nitrokey_sys::NK_first_authenticate(password_ptr, temp_password_ptr)
})
@@ -403,13 +402,13 @@ impl Authenticate for Pro {
}
impl Authenticate for Storage {
- fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, CommandError)> {
+ fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)> {
authenticate(self, password, |password_ptr, temp_password_ptr| unsafe {
nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr)
})
}
- fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, CommandError)> {
+ fn authenticate_admin(self, password: &str) -> Result<Admin<Self>, (Self, Error)> {
authenticate(self, password, |password_ptr, temp_password_ptr| unsafe {
nitrokey_sys::NK_first_authenticate(password_ptr, temp_password_ptr)
})
diff --git a/src/config.rs b/src/config.rs
index 2ce6f77..6aa6d10 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,4 +1,4 @@
-use crate::util::CommandError;
+use crate::error::{Error, LibraryError};
/// The configuration for a Nitrokey.
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -35,13 +35,13 @@ fn config_otp_slot_to_option(value: u8) -> Option<u8> {
None
}
-fn option_to_config_otp_slot(value: Option<u8>) -> Result<u8, CommandError> {
+fn option_to_config_otp_slot(value: Option<u8>) -> Result<u8, Error> {
match value {
Some(value) => {
if value < 3 {
Ok(value)
} else {
- Err(CommandError::InvalidSlot)
+ Err(LibraryError::InvalidSlot.into())
}
}
None => Ok(255),
@@ -66,7 +66,7 @@ impl Config {
}
impl RawConfig {
- pub fn try_from(config: Config) -> Result<RawConfig, CommandError> {
+ pub fn try_from(config: Config) -> Result<RawConfig, Error> {
Ok(RawConfig {
numlock: option_to_config_otp_slot(config.numlock)?,
capslock: option_to_config_otp_slot(config.capslock)?,
diff --git a/src/device.rs b/src/device.rs
index d794e1b..16064c3 100644
--- a/src/device.rs
+++ b/src/device.rs
@@ -5,11 +5,10 @@ use nitrokey_sys;
use crate::auth::Authenticate;
use crate::config::{Config, RawConfig};
+use crate::error::{CommunicationError, Error};
use crate::otp::GenerateOtp;
use crate::pws::GetPasswordSafe;
-use crate::util::{
- get_command_result, get_cstring, get_last_error, result_from_string, CommandError,
-};
+use crate::util::{get_command_result, get_cstring, get_last_error, result_from_string};
/// Available Nitrokey models.
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -64,12 +63,12 @@ impl fmt::Display for VolumeMode {
///
/// ```no_run
/// use nitrokey::{Authenticate, DeviceWrapper, User};
-/// # use nitrokey::CommandError;
+/// # use nitrokey::Error;
///
/// fn perform_user_task(device: &User<DeviceWrapper>) {}
/// fn perform_other_task(device: &DeviceWrapper) {}
///
-/// # fn try_main() -> Result<(), CommandError> {
+/// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let device = match device.authenticate_user("123456") {
/// Ok(user) => {
@@ -90,12 +89,12 @@ impl fmt::Display for VolumeMode {
///
/// ```no_run
/// use nitrokey::{DeviceWrapper, Storage};
-/// # use nitrokey::CommandError;
+/// # use nitrokey::Error;
///
/// fn perform_common_task(device: &DeviceWrapper) {}
/// fn perform_storage_task(device: &Storage) {}
///
-/// # fn try_main() -> Result<(), CommandError> {
+/// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// perform_common_task(&device);
/// match device {
@@ -128,12 +127,12 @@ pub enum DeviceWrapper {
///
/// ```no_run
/// use nitrokey::{Authenticate, User, Pro};
-/// # use nitrokey::CommandError;
+/// # use nitrokey::Error;
///
/// fn perform_user_task(device: &User<Pro>) {}
/// fn perform_other_task(device: &Pro) {}
///
-/// # fn try_main() -> Result<(), CommandError> {
+/// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Pro::connect()?;
/// let device = match device.authenticate_user("123456") {
/// Ok(user) => {
@@ -170,12 +169,12 @@ pub struct Pro {}
///
/// ```no_run
/// use nitrokey::{Authenticate, User, Storage};
-/// # use nitrokey::CommandError;
+/// # use nitrokey::Error;
///
/// fn perform_user_task(device: &User<Storage>) {}
/// fn perform_other_task(device: &Storage) {}
///
-/// # fn try_main() -> Result<(), CommandError> {
+/// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// let device = match device.authenticate_user("123456") {
/// Ok(user) => {
@@ -287,16 +286,16 @@ pub struct StorageStatus {
///
/// This trait provides the commands that can be executed without authentication and that are
/// present on all supported Nitrokey devices.
-pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
+pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug {
/// Returns the model of the connected Nitrokey device.
///
/// # Example
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// println!("Connected to a Nitrokey {}", device.get_model());
/// # Ok(())
@@ -310,9 +309,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.get_serial_number() {
/// Ok(number) => println!("serial no: {}", number),
@@ -321,7 +320,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
/// # Ok(())
/// # }
/// ```
- fn get_serial_number(&self) -> Result<String, CommandError> {
+ fn get_serial_number(&self) -> Result<String, Error> {
unsafe { result_from_string(nitrokey_sys::NK_device_serial_number()) }
}
@@ -332,9 +331,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let count = device.get_user_retry_count();
/// println!("{} remaining authentication attempts (user)", count);
@@ -352,9 +351,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let count = device.get_admin_retry_count();
/// println!("{} remaining authentication attempts (admin)", count);
@@ -371,9 +370,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// println!(
/// "Firmware version: {}.{}",
@@ -393,9 +392,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// println!(
/// "Firmware version: {}.{}",
@@ -414,9 +413,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let config = device.get_config()?;
/// println!("numlock binding: {:?}", config.numlock);
@@ -426,7 +425,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
/// # Ok(())
/// # }
/// ```
- fn get_config(&self) -> Result<Config, CommandError> {
+ fn get_config(&self) -> Result<Config, Error> {
unsafe {
let config_ptr = nitrokey_sys::NK_read_config();
if config_ptr.is_null() {
@@ -450,9 +449,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.change_admin_pin("12345678", "12345679") {
/// Ok(()) => println!("Updated admin PIN."),
@@ -462,9 +461,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
/// # }
/// ```
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- fn change_admin_pin(&self, current: &str, new: &str) -> Result<(), CommandError> {
+ fn change_admin_pin(&self, current: &str, new: &str) -> Result<(), Error> {
let current_string = get_cstring(current)?;
let new_string = get_cstring(new)?;
unsafe {
@@ -486,9 +485,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.change_user_pin("123456", "123457") {
/// Ok(()) => println!("Updated admin PIN."),
@@ -498,9 +497,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
/// # }
/// ```
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- fn change_user_pin(&self, current: &str, new: &str) -> Result<(), CommandError> {
+ fn change_user_pin(&self, current: &str, new: &str) -> Result<(), Error> {
let current_string = get_cstring(current)?;
let new_string = get_cstring(new)?;
unsafe {
@@ -522,9 +521,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.unlock_user_pin("12345678", "123456") {
/// Ok(()) => println!("Unlocked user PIN."),
@@ -534,9 +533,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
/// # }
/// ```
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- fn unlock_user_pin(&self, admin_pin: &str, user_pin: &str) -> Result<(), CommandError> {
+ fn unlock_user_pin(&self, admin_pin: &str, user_pin: &str) -> Result<(), Error> {
let admin_pin_string = get_cstring(admin_pin)?;
let user_pin_string = get_cstring(user_pin)?;
unsafe {
@@ -556,9 +555,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.lock() {
/// Ok(()) => println!("Locked the Nitrokey device."),
@@ -567,7 +566,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
/// # Ok(())
/// # }
/// ```
- fn lock(&self) -> Result<(), CommandError> {
+ fn lock(&self) -> Result<(), Error> {
unsafe { get_command_result(nitrokey_sys::NK_lock_device()) }
}
@@ -587,9 +586,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.factory_reset("12345678") {
/// Ok(()) => println!("Performed a factory reset."),
@@ -600,7 +599,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
/// ```
///
/// [`build_aes_key`]: #method.build_aes_key
- fn factory_reset(&self, admin_pin: &str) -> Result<(), CommandError> {
+ fn factory_reset(&self, admin_pin: &str) -> Result<(), Error> {
let admin_pin_string = get_cstring(admin_pin)?;
unsafe { get_command_result(nitrokey_sys::NK_factory_reset(admin_pin_string.as_ptr())) }
}
@@ -621,9 +620,9 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// ```no_run
/// use nitrokey::Device;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.build_aes_key("12345678") {
/// Ok(()) => println!("New AES keys have been built."),
@@ -634,7 +633,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
/// ```
///
/// [`factory_reset`]: #method.factory_reset
- fn build_aes_key(&self, admin_pin: &str) -> Result<(), CommandError> {
+ fn build_aes_key(&self, admin_pin: &str) -> Result<(), Error> {
let admin_pin_string = get_cstring(admin_pin)?;
unsafe { get_command_result(nitrokey_sys::NK_build_aes_key(admin_pin_string.as_ptr())) }
}
@@ -645,7 +644,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// # Errors
///
-/// - [`Undefined`][] if no Nitrokey device is connected
+/// - [`NotConnected`][] if no Nitrokey device is connected
///
/// # Example
///
@@ -660,15 +659,15 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
/// }
/// ```
///
-/// [`Undefined`]: enum.CommandError.html#variant.Undefined
-pub fn connect() -> Result<DeviceWrapper, CommandError> {
+/// [`NotConnected`]: enum.CommunicationError.html#variant.NotConnected
+pub fn connect() -> Result<DeviceWrapper, Error> {
unsafe {
match nitrokey_sys::NK_login_auto() {
1 => match get_connected_device() {
Some(wrapper) => Ok(wrapper),
- None => Err(CommandError::Undefined),
+ None => Err(CommunicationError::NotConnected.into()),
},
- _ => Err(CommandError::Undefined),
+ _ => Err(CommunicationError::NotConnected.into()),
}
}
}
@@ -677,7 +676,7 @@ pub fn connect() -> Result<DeviceWrapper, CommandError> {
///
/// # Errors
///
-/// - [`Undefined`][] if no Nitrokey device of the given model is connected
+/// - [`NotConnected`][] if no Nitrokey device of the given model is connected
///
/// # Example
///
@@ -693,12 +692,12 @@ pub fn connect() -> Result<DeviceWrapper, CommandError> {
/// }
/// ```
///
-/// [`Undefined`]: enum.CommandError.html#variant.Undefined
-pub fn connect_model(model: Model) -> Result<DeviceWrapper, CommandError> {
+/// [`NotConnected`]: enum.CommunicationError.html#variant.NotConnected
+pub fn connect_model(model: Model) -> Result<DeviceWrapper, Error> {
if connect_enum(model) {
Ok(create_device_wrapper(model))
} else {
- Err(CommandError::Undefined)
+ Err(CommunicationError::NotConnected.into())
}
}
@@ -741,19 +740,19 @@ impl DeviceWrapper {
}
impl GenerateOtp for DeviceWrapper {
- fn get_hotp_slot_name(&self, slot: u8) -> Result<String, CommandError> {
+ fn get_hotp_slot_name(&self, slot: u8) -> Result<String, Error> {
self.device().get_hotp_slot_name(slot)
}
- fn get_totp_slot_name(&self, slot: u8) -> Result<String, CommandError> {
+ fn get_totp_slot_name(&self, slot: u8) -> Result<String, Error> {
self.device().get_totp_slot_name(slot)
}
- fn get_hotp_code(&self, slot: u8) -> Result<String, CommandError> {
+ fn get_hotp_code(&self, slot: u8) -> Result<String, Error> {
self.device().get_hotp_code(slot)
}
- fn get_totp_code(&self, slot: u8) -> Result<String, CommandError> {
+ fn get_totp_code(&self, slot: u8) -> Result<String, Error> {
self.device().get_totp_code(slot)
}
}
@@ -772,7 +771,7 @@ impl Pro {
///
/// # Errors
///
- /// - [`Undefined`][] if no Nitrokey device of the given model is connected
+ /// - [`NotConnected`][] if no Nitrokey device of the given model is connected
///
/// # Example
///
@@ -787,12 +786,12 @@ impl Pro {
/// }
/// ```
///
- /// [`Undefined`]: enum.CommandError.html#variant.Undefined
- pub fn connect() -> Result<Pro, CommandError> {
+ /// [`NotConnected`]: enum.CommunicationError.html#variant.NotConnected
+ pub fn connect() -> Result<Pro, Error> {
// TODO: maybe Option instead of Result?
match connect_enum(Model::Pro) {
true => Ok(Pro {}),
- false => Err(CommandError::Undefined),
+ false => Err(CommunicationError::NotConnected.into()),
}
}
}
@@ -818,7 +817,7 @@ impl Storage {
///
/// # Errors
///
- /// - [`Undefined`][] if no Nitrokey device of the given model is connected
+ /// - [`NotConnected`][] if no Nitrokey device of the given model is connected
///
/// # Example
///
@@ -833,12 +832,12 @@ impl Storage {
/// }
/// ```
///
- /// [`Undefined`]: enum.CommandError.html#variant.Undefined
- pub fn connect() -> Result<Storage, CommandError> {
+ /// [`NotConnected`]: enum.CommunicationError.html#variant.NotConnected
+ pub fn connect() -> Result<Storage, Error> {
// TODO: maybe Option instead of Result?
match connect_enum(Model::Storage) {
true => Ok(Storage {}),
- false => Err(CommandError::Undefined),
+ false => Err(CommunicationError::NotConnected.into()),
}
}
@@ -856,9 +855,9 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// match device.change_update_pin("12345678", "87654321") {
/// Ok(()) => println!("Updated update PIN."),
@@ -868,9 +867,9 @@ impl Storage {
/// # }
/// ```
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- pub fn change_update_pin(&self, current: &str, new: &str) -> Result<(), CommandError> {
+ pub fn change_update_pin(&self, current: &str, new: &str) -> Result<(), Error> {
let current_string = get_cstring(current)?;
let new_string = get_cstring(new)?;
unsafe {
@@ -896,9 +895,9 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// match device.enable_firmware_update("12345678") {
/// Ok(()) => println!("Nitrokey entered update mode."),
@@ -908,9 +907,9 @@ impl Storage {
/// # }
/// ```
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- pub fn enable_firmware_update(&self, update_pin: &str) -> Result<(), CommandError> {
+ pub fn enable_firmware_update(&self, update_pin: &str) -> Result<(), Error> {
let update_pin_string = get_cstring(update_pin)?;
unsafe {
get_command_result(nitrokey_sys::NK_enable_firmware_update(
@@ -932,9 +931,9 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// match device.enable_encrypted_volume("123456") {
/// Ok(()) => println!("Enabled the encrypted volume."),
@@ -944,9 +943,9 @@ impl Storage {
/// # }
/// ```
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- pub fn enable_encrypted_volume(&self, user_pin: &str) -> Result<(), CommandError> {
+ pub fn enable_encrypted_volume(&self, user_pin: &str) -> Result<(), Error> {
let user_pin = get_cstring(user_pin)?;
unsafe { get_command_result(nitrokey_sys::NK_unlock_encrypted_volume(user_pin.as_ptr())) }
}
@@ -959,11 +958,11 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
/// fn use_volume() {}
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// match device.enable_encrypted_volume("123456") {
/// Ok(()) => {
@@ -981,7 +980,7 @@ impl Storage {
/// # Ok(())
/// # }
/// ```
- pub fn disable_encrypted_volume(&self) -> Result<(), CommandError> {
+ pub fn disable_encrypted_volume(&self) -> Result<(), Error> {
unsafe { get_command_result(nitrokey_sys::NK_lock_encrypted_volume()) }
}
@@ -1007,9 +1006,9 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// device.enable_encrypted_volume("123445")?;
/// match device.enable_hidden_volume("hidden-pw") {
@@ -1022,8 +1021,8 @@ impl Storage {
///
/// [`enable_encrypted_volume`]: #method.enable_encrypted_volume
/// [`AesDecryptionFailed`]: enum.CommandError.html#variant.AesDecryptionFailed
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
- pub fn enable_hidden_volume(&self, volume_password: &str) -> Result<(), CommandError> {
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
+ pub fn enable_hidden_volume(&self, volume_password: &str) -> Result<(), Error> {
let volume_password = get_cstring(volume_password)?;
unsafe {
get_command_result(nitrokey_sys::NK_unlock_hidden_volume(
@@ -1040,11 +1039,11 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
/// fn use_volume() {}
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// device.enable_encrypted_volume("123445")?;
/// match device.enable_hidden_volume("hidden-pw") {
@@ -1063,7 +1062,7 @@ impl Storage {
/// # Ok(())
/// # }
/// ```
- pub fn disable_hidden_volume(&self) -> Result<(), CommandError> {
+ pub fn disable_hidden_volume(&self) -> Result<(), Error> {
unsafe { get_command_result(nitrokey_sys::NK_lock_hidden_volume()) }
}
@@ -1089,9 +1088,9 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// device.enable_encrypted_volume("123445")?;
/// device.create_hidden_volume(0, 0, 100, "hidden-pw")?;
@@ -1100,14 +1099,14 @@ impl Storage {
/// ```
///
/// [`AesDecryptionFailed`]: enum.CommandError.html#variant.AesDecryptionFailed
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
pub fn create_hidden_volume(
&self,
slot: u8,
start: u8,
end: u8,
password: &str,
- ) -> Result<(), CommandError> {
+ ) -> Result<(), Error> {
let password = get_cstring(password)?;
unsafe {
get_command_result(nitrokey_sys::NK_create_hidden_volume(
@@ -1133,10 +1132,10 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
/// use nitrokey::VolumeMode;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// match device.set_unencrypted_volume_mode("123456", VolumeMode::ReadWrite) {
/// Ok(()) => println!("Set the unencrypted volume to read-write mode."),
@@ -1146,13 +1145,13 @@ impl Storage {
/// # }
/// ```
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
pub fn set_unencrypted_volume_mode(
&self,
admin_pin: &str,
mode: VolumeMode,
- ) -> Result<(), CommandError> {
+ ) -> Result<(), Error> {
let admin_pin = get_cstring(admin_pin)?;
let result = match mode {
VolumeMode::ReadOnly => unsafe {
@@ -1170,11 +1169,11 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
/// fn use_volume() {}
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// match device.get_status() {
/// Ok(status) => {
@@ -1185,7 +1184,7 @@ impl Storage {
/// # Ok(())
/// # }
/// ```
- pub fn get_status(&self) -> Result<StorageStatus, CommandError> {
+ pub fn get_status(&self) -> Result<StorageStatus, Error> {
let mut raw_status = nitrokey_sys::NK_storage_status {
unencrypted_volume_read_only: false,
unencrypted_volume_active: false,
@@ -1214,11 +1213,11 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
/// fn use_volume() {}
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// match device.get_production_info() {
/// Ok(data) => {
@@ -1230,7 +1229,7 @@ impl Storage {
/// # Ok(())
/// # }
/// ```
- pub fn get_production_info(&self) -> Result<StorageProductionInfo, CommandError> {
+ pub fn get_production_info(&self) -> Result<StorageProductionInfo, Error> {
let mut raw_data = nitrokey_sys::NK_storage_ProductionTest {
FirmwareVersion_au8: [0, 2],
FirmwareVersionInternal_u8: 0,
@@ -1265,9 +1264,9 @@ impl Storage {
/// # Example
///
/// ```no_run
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// match device.clear_new_sd_card_warning("12345678") {
/// Ok(()) => println!("Cleared the new SD card warning."),
@@ -1277,9 +1276,9 @@ impl Storage {
/// # }
/// ```
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- pub fn clear_new_sd_card_warning(&self, admin_pin: &str) -> Result<(), CommandError> {
+ pub fn clear_new_sd_card_warning(&self, admin_pin: &str) -> Result<(), Error> {
let admin_pin = get_cstring(admin_pin)?;
get_command_result(unsafe {
nitrokey_sys::NK_clear_new_sd_card_warning(admin_pin.as_ptr())
@@ -1287,7 +1286,7 @@ impl Storage {
}
/// Blinks the red and green LED alternatively and infinitely until the device is reconnected.
- pub fn wink(&self) -> Result<(), CommandError> {
+ pub fn wink(&self) -> Result<(), Error> {
get_command_result(unsafe { nitrokey_sys::NK_wink() })
}
@@ -1305,9 +1304,9 @@ impl Storage {
/// - [`InvalidString`][] if one of the provided passwords contains a null byte
/// - [`WrongPassword`][] if the admin password is wrong
///
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- pub fn export_firmware(&self, admin_pin: &str) -> Result<(), CommandError> {
+ pub fn export_firmware(&self, admin_pin: &str) -> Result<(), Error> {
let admin_pin_string = get_cstring(admin_pin)?;
get_command_result(unsafe { nitrokey_sys::NK_export_firmware(admin_pin_string.as_ptr()) })
}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..cde9a34
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,233 @@
+use std::error;
+use std::fmt;
+use std::os::raw;
+use std::result;
+
+/// An error returned by the nitrokey crate.
+#[derive(Debug)]
+pub enum Error {
+ /// An error reported by the Nitrokey device in the response packet.
+ CommandError(CommandError),
+ /// A device communication.
+ CommunicationError(CommunicationError),
+ /// A library usage error.
+ LibraryError(LibraryError),
+ /// An error that occured during random number generation.
+ RandError(rand_core::Error),
+ /// An error that is caused by an unexpected value returned by libnitrokey.
+ UnexpectedError,
+ /// An unknown error returned by libnitrokey.
+ Unknown(i64),
+}
+
+impl From<raw::c_int> for Error {
+ fn from(code: raw::c_int) -> Self {
+ if let Some(err) = CommandError::try_from(code) {
+ Error::CommandError(err)
+ } else if let Some(err) = CommunicationError::try_from(256 - code) {
+ Error::CommunicationError(err)
+ } else if let Some(err) = LibraryError::try_from(code) {
+ Error::LibraryError(err)
+ } else {
+ Error::Unknown(code.into())
+ }
+ }
+}
+
+impl From<CommandError> for Error {
+ fn from(err: CommandError) -> Self {
+ Error::CommandError(err)
+ }
+}
+
+impl From<CommunicationError> for Error {
+ fn from(err: CommunicationError) -> Self {
+ Error::CommunicationError(err)
+ }
+}
+
+impl From<LibraryError> for Error {
+ fn from(err: LibraryError) -> Self {
+ Error::LibraryError(err)
+ }
+}
+
+impl From<rand_core::Error> for Error {
+ fn from(error: rand_core::Error) -> Self {
+ Error::RandError(error)
+ }
+}
+
+impl error::Error for Error {
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ Error::CommandError(ref err) => Some(err),
+ Error::CommunicationError(ref err) => Some(err),
+ Error::LibraryError(ref err) => Some(err),
+ Error::RandError(ref err) => Some(err),
+ Error::UnexpectedError => None,
+ Error::Unknown(_) => None,
+ }
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ Error::CommandError(ref err) => write!(f, "Command error: {}", err),
+ Error::CommunicationError(ref err) => write!(f, "Communication error: {}", err),
+ Error::LibraryError(ref err) => write!(f, "Library error: {}", err),
+ Error::RandError(ref err) => write!(f, "RNG error: {}", err),
+ Error::UnexpectedError => write!(f, "An unexpected error occurred"),
+ Error::Unknown(ref err) => write!(f, "Unknown error: {}", err),
+ }
+ }
+}
+
+/// A result returned by the nitrokey crate.
+pub type Result<T> = result::Result<T, Error>;
+
+/// An error reported by the Nitrokey device in the response packet.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum CommandError {
+ /// A packet with a wrong checksum has been sent or received.
+ WrongCrc,
+ /// A command tried to access an OTP slot that does not exist.
+ WrongSlot,
+ /// A command tried to generate an OTP on a slot that is not configured.
+ SlotNotProgrammed,
+ /// The provided password is wrong.
+ WrongPassword,
+ /// You are not authorized for this command or provided a wrong temporary
+ /// password.
+ NotAuthorized,
+ /// An error occurred when getting or setting the time.
+ Timestamp,
+ /// You did not provide a name for the OTP slot.
+ NoName,
+ /// This command is not supported by this device.
+ NotSupported,
+ /// This command is unknown.
+ UnknownCommand,
+ /// AES decryption failed.
+ AesDecryptionFailed,
+}
+
+impl CommandError {
+ fn try_from(value: raw::c_int) -> Option<Self> {
+ match value {
+ 1 => Some(CommandError::WrongCrc),
+ 2 => Some(CommandError::WrongSlot),
+ 3 => Some(CommandError::SlotNotProgrammed),
+ 4 => Some(CommandError::WrongPassword),
+ 5 => Some(CommandError::NotAuthorized),
+ 6 => Some(CommandError::Timestamp),
+ 7 => Some(CommandError::NoName),
+ 8 => Some(CommandError::NotSupported),
+ 9 => Some(CommandError::UnknownCommand),
+ 10 => Some(CommandError::AesDecryptionFailed),
+ _ => None,
+ }
+ }
+}
+
+impl error::Error for CommandError {}
+
+impl fmt::Display for CommandError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(match *self {
+ CommandError::WrongCrc => "A packet with a wrong checksum has been sent or received",
+ CommandError::WrongSlot => "The given slot does not exist",
+ CommandError::SlotNotProgrammed => "The given slot is not programmed",
+ CommandError::WrongPassword => "The given password is wrong",
+ CommandError::NotAuthorized => {
+ "You are not authorized for this command or provided a wrong temporary \
+ password"
+ }
+ CommandError::Timestamp => "An error occurred when getting or setting the time",
+ CommandError::NoName => "You did not provide a name for the slot",
+ CommandError::NotSupported => "This command is not supported by this device",
+ CommandError::UnknownCommand => "This command is unknown",
+ CommandError::AesDecryptionFailed => "AES decryption failed",
+ })
+ }
+}
+
+/// A device communication error.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum CommunicationError {
+ /// Could not connect to a Nitrokey device.
+ NotConnected,
+ /// Sending a packet failed.
+ SendingFailure,
+ /// Receiving a packet failed.
+ ReceivingFailure,
+ /// A packet with a wrong checksum was received.
+ InvalidCrc,
+}
+
+impl CommunicationError {
+ fn try_from(value: raw::c_int) -> Option<Self> {
+ match value {
+ 2 => Some(CommunicationError::NotConnected),
+ 3 => Some(CommunicationError::SendingFailure),
+ 4 => Some(CommunicationError::ReceivingFailure),
+ 5 => Some(CommunicationError::InvalidCrc),
+ _ => None,
+ }
+ }
+}
+
+impl error::Error for CommunicationError {}
+
+impl fmt::Display for CommunicationError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(match *self {
+ CommunicationError::NotConnected => "Could not connect to a Nitrokey device",
+ CommunicationError::SendingFailure => "Sending a packet failed",
+ CommunicationError::ReceivingFailure => "Receiving a packet failed",
+ CommunicationError::InvalidCrc => "A packet with a wrong checksum was received",
+ })
+ }
+}
+
+/// A library usage error.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum LibraryError {
+ /// A supplied string exceeded a length limit.
+ StringTooLong,
+ /// You passed an invalid slot.
+ InvalidSlot,
+ /// The supplied string was not in hexadecimal format.
+ InvalidHexString,
+ /// The target buffer was smaller than the source.
+ TargetBufferTooSmall,
+ /// You passed a string containing a null byte.
+ InvalidString,
+}
+
+impl LibraryError {
+ fn try_from(value: raw::c_int) -> Option<Self> {
+ match value {
+ 200 => Some(LibraryError::StringTooLong),
+ 201 => Some(LibraryError::InvalidSlot),
+ 202 => Some(LibraryError::InvalidHexString),
+ 203 => Some(LibraryError::TargetBufferTooSmall),
+ _ => None,
+ }
+ }
+}
+
+impl error::Error for LibraryError {}
+
+impl fmt::Display for LibraryError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(match *self {
+ LibraryError::StringTooLong => "The supplied string is too long",
+ LibraryError::InvalidSlot => "The given slot is invalid",
+ LibraryError::InvalidHexString => "The supplied string is not in hexadecimal format",
+ LibraryError::TargetBufferTooSmall => "The target buffer is too small",
+ LibraryError::InvalidString => "You passed a string containing a null byte",
+ })
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 93a9894..993ec92 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -25,9 +25,9 @@
//!
//! ```no_run
//! use nitrokey::Device;
-//! # use nitrokey::CommandError;
+//! # use nitrokey::Error;
//!
-//! # fn try_main() -> Result<(), CommandError> {
+//! # fn try_main() -> Result<(), Error> {
//! let device = nitrokey::connect()?;
//! println!("{}", device.get_serial_number()?);
//! # Ok(())
@@ -38,9 +38,9 @@
//!
//! ```no_run
//! use nitrokey::{Authenticate, ConfigureOtp, OtpMode, OtpSlotData};
-//! # use nitrokey::CommandError;
+//! # use nitrokey::Error;
//!
-//! # fn try_main() -> Result<(), (CommandError)> {
+//! # fn try_main() -> Result<(), Error> {
//! let device = nitrokey::connect()?;
//! let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits);
//! match device.authenticate_admin("12345678") {
@@ -60,9 +60,9 @@
//!
//! ```no_run
//! use nitrokey::{Device, GenerateOtp};
-//! # use nitrokey::CommandError;
+//! # use nitrokey::Error;
//!
-//! # fn try_main() -> Result<(), (CommandError)> {
+//! # fn try_main() -> Result<(), Error> {
//! let device = nitrokey::connect()?;
//! match device.get_hotp_code(1) {
//! Ok(code) => println!("Generated HOTP code: {}", code),
@@ -89,6 +89,7 @@
mod auth;
mod config;
mod device;
+mod error;
mod otp;
mod pws;
mod util;
@@ -103,9 +104,10 @@ pub use crate::device::{
connect, connect_model, Device, DeviceWrapper, Model, Pro, SdCardData, Storage,
StorageProductionInfo, StorageStatus, VolumeMode, VolumeStatus,
};
+pub use crate::error::{CommandError, CommunicationError, Error, LibraryError, Result};
pub use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData};
pub use crate::pws::{GetPasswordSafe, PasswordSafe, SLOT_COUNT};
-pub use crate::util::{CommandError, LogLevel};
+pub use crate::util::LogLevel;
/// The default admin PIN for all Nitrokey devices.
pub const DEFAULT_ADMIN_PIN: &'static str = "12345678";
diff --git a/src/otp.rs b/src/otp.rs
index 901bef9..7535a77 100644
--- a/src/otp.rs
+++ b/src/otp.rs
@@ -2,7 +2,8 @@ use std::ffi::CString;
use nitrokey_sys;
-use crate::util::{get_command_result, get_cstring, result_from_string, CommandError};
+use crate::error::Error;
+use crate::util::{get_command_result, get_cstring, result_from_string};
/// Modes for one-time password generation.
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -28,9 +29,9 @@ pub trait ConfigureOtp {
///
/// ```no_run
/// use nitrokey::{Authenticate, ConfigureOtp, OtpMode, OtpSlotData};
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), (CommandError)> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits);
/// match device.authenticate_admin("12345678") {
@@ -46,10 +47,10 @@ pub trait ConfigureOtp {
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`NoName`]: enum.CommandError.html#variant.NoName
- fn write_hotp_slot(&self, data: OtpSlotData, counter: u64) -> Result<(), CommandError>;
+ fn write_hotp_slot(&self, data: OtpSlotData, counter: u64) -> Result<(), Error>;
/// Configure a TOTP slot with the given data and set the TOTP time window to the given value
/// (default 30).
@@ -64,9 +65,9 @@ pub trait ConfigureOtp {
///
/// ```no_run
/// use nitrokey::{Authenticate, ConfigureOtp, OtpMode, OtpSlotData};
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), (CommandError)> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::EightDigits);
/// match device.authenticate_admin("12345678") {
@@ -82,10 +83,10 @@ pub trait ConfigureOtp {
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`NoName`]: enum.CommandError.html#variant.NoName
- fn write_totp_slot(&self, data: OtpSlotData, time_window: u16) -> Result<(), CommandError>;
+ fn write_totp_slot(&self, data: OtpSlotData, time_window: u16) -> Result<(), Error>;
/// Erases an HOTP slot.
///
@@ -97,9 +98,9 @@ pub trait ConfigureOtp {
///
/// ```no_run
/// use nitrokey::{Authenticate, ConfigureOtp};
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), (CommandError)> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.authenticate_admin("12345678") {
/// Ok(admin) => {
@@ -114,8 +115,8 @@ pub trait ConfigureOtp {
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- fn erase_hotp_slot(&self, slot: u8) -> Result<(), CommandError>;
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
+ fn erase_hotp_slot(&self, slot: u8) -> Result<(), Error>;
/// Erases a TOTP slot.
///
@@ -127,9 +128,9 @@ pub trait ConfigureOtp {
///
/// ```no_run
/// use nitrokey::{Authenticate, ConfigureOtp};
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), (CommandError)> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.authenticate_admin("12345678") {
/// Ok(admin) => {
@@ -144,8 +145,8 @@ pub trait ConfigureOtp {
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- fn erase_totp_slot(&self, slot: u8) -> Result<(), CommandError>;
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
+ fn erase_totp_slot(&self, slot: u8) -> Result<(), Error>;
}
/// Provides methods to generate OTP codes and to query OTP slots on a Nitrokey
@@ -164,9 +165,9 @@ pub trait GenerateOtp {
/// ```no_run
/// use std::time;
/// use nitrokey::GenerateOtp;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH);
/// match time {
@@ -183,7 +184,7 @@ pub trait GenerateOtp {
///
/// [`get_totp_code`]: #method.get_totp_code
/// [`Timestamp`]: enum.CommandError.html#variant.Timestamp
- fn set_time(&self, time: u64, force: bool) -> Result<(), CommandError> {
+ fn set_time(&self, time: u64, force: bool) -> Result<(), Error> {
let result = if force {
unsafe { nitrokey_sys::NK_totp_set_time(time) }
} else {
@@ -202,22 +203,22 @@ pub trait GenerateOtp {
/// # Example
///
/// ```no_run
- /// use nitrokey::{CommandError, GenerateOtp};
+ /// use nitrokey::{CommandError, Error, GenerateOtp};
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.get_hotp_slot_name(1) {
/// Ok(name) => println!("HOTP slot 1: {}", name),
- /// Err(CommandError::SlotNotProgrammed) => println!("HOTP slot 1 not programmed"),
+ /// Err(Error::CommandError(CommandError::SlotNotProgrammed)) => println!("HOTP slot 1 not programmed"),
/// Err(err) => println!("Could not get slot name: {}", err),
/// };
/// # Ok(())
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- fn get_hotp_slot_name(&self, slot: u8) -> Result<String, CommandError> {
+ fn get_hotp_slot_name(&self, slot: u8) -> Result<String, Error> {
unsafe { result_from_string(nitrokey_sys::NK_get_hotp_slot_name(slot)) }
}
@@ -231,22 +232,22 @@ pub trait GenerateOtp {
/// # Example
///
/// ```no_run
- /// use nitrokey::{CommandError, GenerateOtp};
+ /// use nitrokey::{CommandError, Error, GenerateOtp};
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.get_totp_slot_name(1) {
/// Ok(name) => println!("TOTP slot 1: {}", name),
- /// Err(CommandError::SlotNotProgrammed) => println!("TOTP slot 1 not programmed"),
+ /// Err(Error::CommandError(CommandError::SlotNotProgrammed)) => println!("TOTP slot 1 not programmed"),
/// Err(err) => println!("Could not get slot name: {}", err),
/// };
/// # Ok(())
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- fn get_totp_slot_name(&self, slot: u8) -> Result<String, CommandError> {
+ fn get_totp_slot_name(&self, slot: u8) -> Result<String, Error> {
unsafe { result_from_string(nitrokey_sys::NK_get_totp_slot_name(slot)) }
}
@@ -263,9 +264,9 @@ pub trait GenerateOtp {
///
/// ```no_run
/// use nitrokey::GenerateOtp;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let code = device.get_hotp_code(1)?;
/// println!("Generated HOTP code on slot 1: {}", code);
@@ -274,10 +275,10 @@ pub trait GenerateOtp {
/// ```
///
/// [`get_config`]: trait.Device.html#method.get_config
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
/// [`NotAuthorized`]: enum.CommandError.html#variant.NotAuthorized
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- fn get_hotp_code(&self, slot: u8) -> Result<String, CommandError> {
+ fn get_hotp_code(&self, slot: u8) -> Result<String, Error> {
unsafe {
return result_from_string(nitrokey_sys::NK_get_hotp_code(slot));
}
@@ -300,9 +301,9 @@ pub trait GenerateOtp {
/// ```no_run
/// use std::time;
/// use nitrokey::GenerateOtp;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH);
/// match time {
@@ -319,10 +320,10 @@ pub trait GenerateOtp {
///
/// [`set_time`]: #method.set_time
/// [`get_config`]: trait.Device.html#method.get_config
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
/// [`NotAuthorized`]: enum.CommandError.html#variant.NotAuthorized
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- fn get_totp_code(&self, slot: u8) -> Result<String, CommandError> {
+ fn get_totp_code(&self, slot: u8) -> Result<String, Error> {
unsafe {
return result_from_string(nitrokey_sys::NK_get_totp_code(slot, 0, 0, 0));
}
@@ -395,7 +396,7 @@ impl OtpSlotData {
}
impl RawOtpSlotData {
- pub fn new(data: OtpSlotData) -> Result<RawOtpSlotData, CommandError> {
+ pub fn new(data: OtpSlotData) -> Result<RawOtpSlotData, Error> {
let name = get_cstring(data.name)?;
let secret = get_cstring(data.secret)?;
let use_token_id = data.token_id.is_some();
diff --git a/src/pws.rs b/src/pws.rs
index 28f0681..a21527c 100644
--- a/src/pws.rs
+++ b/src/pws.rs
@@ -2,9 +2,8 @@ use libc;
use nitrokey_sys;
use crate::device::{Device, DeviceWrapper, Pro, Storage};
-use crate::util::{
- get_command_result, get_cstring, get_last_error, result_from_string, CommandError,
-};
+use crate::error::{CommandError, Error};
+use crate::util::{get_command_result, get_cstring, get_last_error, result_from_string};
/// The number of slots in a [`PasswordSafe`][].
///
@@ -30,9 +29,9 @@ pub const SLOT_COUNT: u8 = 16;
///
/// ```no_run
/// use nitrokey::{Device, GetPasswordSafe, PasswordSafe};
-/// # use nitrokey::CommandError;
+/// # use nitrokey::Error;
///
-/// fn use_password_safe(pws: &PasswordSafe) -> Result<(), CommandError> {
+/// fn use_password_safe(pws: &PasswordSafe) -> Result<(), Error> {
/// let name = pws.get_slot_name(0)?;
/// let login = pws.get_slot_login(0)?;
/// let password = pws.get_slot_login(0)?;
@@ -40,7 +39,7 @@ pub const SLOT_COUNT: u8 = 16;
/// Ok(())
/// }
///
-/// # fn try_main() -> Result<(), CommandError> {
+/// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let pws = device.get_password_safe("123456")?;
/// use_password_safe(&pws);
@@ -53,6 +52,7 @@ pub const SLOT_COUNT: u8 = 16;
/// [`get_password_safe`]: trait.GetPasswordSafe.html#method.get_password_safe
/// [`lock`]: trait.Device.html#method.lock
/// [`GetPasswordSafe`]: trait.GetPasswordSafe.html
+#[derive(Debug)]
pub struct PasswordSafe<'a> {
_device: &'a dyn Device,
}
@@ -89,11 +89,11 @@ pub trait GetPasswordSafe {
///
/// ```no_run
/// use nitrokey::{Device, GetPasswordSafe, PasswordSafe};
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
/// fn use_password_safe(pws: &PasswordSafe) {}
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.get_password_safe("123456") {
/// Ok(pws) => {
@@ -110,16 +110,16 @@ pub trait GetPasswordSafe {
/// [`lock`]: trait.Device.html#method.lock
/// [`AesDecryptionFailed`]: enum.CommandError.html#variant.AesDecryptionFailed
/// [`Device::build_aes_key`]: trait.Device.html#method.build_aes_key
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
/// [`Unknown`]: enum.CommandError.html#variant.Unknown
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError>;
+ fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, Error>;
}
fn get_password_safe<'a>(
device: &'a dyn Device,
user_pin: &str,
-) -> Result<PasswordSafe<'a>, CommandError> {
+) -> Result<PasswordSafe<'a>, Error> {
let user_pin_string = get_cstring(user_pin)?;
let result = unsafe {
get_command_result(nitrokey_sys::NK_enable_password_safe(
@@ -129,9 +129,9 @@ fn get_password_safe<'a>(
result.map(|()| PasswordSafe { _device: device })
}
-fn get_pws_result(s: String) -> Result<String, CommandError> {
+fn get_pws_result(s: String) -> Result<String, Error> {
if s.is_empty() {
- Err(CommandError::SlotNotProgrammed)
+ Err(CommandError::SlotNotProgrammed.into())
} else {
Ok(s)
}
@@ -146,9 +146,9 @@ impl<'a> PasswordSafe<'a> {
///
/// ```no_run
/// use nitrokey::{GetPasswordSafe, SLOT_COUNT};
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let pws = device.get_password_safe("123456")?;
/// pws.get_slot_status()?.iter().enumerate().for_each(|(slot, programmed)| {
@@ -161,7 +161,7 @@ impl<'a> PasswordSafe<'a> {
/// # Ok(())
/// # }
/// ```
- pub fn get_slot_status(&self) -> Result<[bool; SLOT_COUNT as usize], CommandError> {
+ pub fn get_slot_status(&self) -> Result<[bool; SLOT_COUNT as usize], Error> {
let status_ptr = unsafe { nitrokey_sys::NK_get_password_safe_slot_status() };
if status_ptr.is_null() {
return Err(get_last_error());
@@ -191,9 +191,9 @@ impl<'a> PasswordSafe<'a> {
///
/// ```no_run
/// use nitrokey::GetPasswordSafe;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// match device.get_password_safe("123456") {
/// Ok(pws) => {
@@ -208,9 +208,9 @@ impl<'a> PasswordSafe<'a> {
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- pub fn get_slot_name(&self, slot: u8) -> Result<String, CommandError> {
+ pub fn get_slot_name(&self, slot: u8) -> Result<String, Error> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_name(slot)) }
.and_then(get_pws_result)
}
@@ -228,9 +228,9 @@ impl<'a> PasswordSafe<'a> {
///
/// ```no_run
/// use nitrokey::GetPasswordSafe;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let pws = device.get_password_safe("123456")?;
/// let name = pws.get_slot_name(0)?;
@@ -241,9 +241,9 @@ impl<'a> PasswordSafe<'a> {
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- pub fn get_slot_login(&self, slot: u8) -> Result<String, CommandError> {
+ pub fn get_slot_login(&self, slot: u8) -> Result<String, Error> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_login(slot)) }
.and_then(get_pws_result)
}
@@ -261,9 +261,9 @@ impl<'a> PasswordSafe<'a> {
///
/// ```no_run
/// use nitrokey::GetPasswordSafe;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let pws = device.get_password_safe("123456")?;
/// let name = pws.get_slot_name(0)?;
@@ -274,9 +274,9 @@ impl<'a> PasswordSafe<'a> {
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
/// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
- pub fn get_slot_password(&self, slot: u8) -> Result<String, CommandError> {
+ pub fn get_slot_password(&self, slot: u8) -> Result<String, Error> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_password(slot)) }
.and_then(get_pws_result)
}
@@ -292,9 +292,9 @@ impl<'a> PasswordSafe<'a> {
///
/// ```no_run
/// use nitrokey::GetPasswordSafe;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let pws = device.get_password_safe("123456")?;
/// let name = pws.get_slot_name(0)?;
@@ -305,15 +305,15 @@ impl<'a> PasswordSafe<'a> {
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
+ /// [`InvalidString`]: enum.LibraryError.html#variant.InvalidString
pub fn write_slot(
&self,
slot: u8,
name: &str,
login: &str,
password: &str,
- ) -> Result<(), CommandError> {
+ ) -> Result<(), Error> {
let name_string = get_cstring(name)?;
let login_string = get_cstring(login)?;
let password_string = get_cstring(password)?;
@@ -338,9 +338,9 @@ impl<'a> PasswordSafe<'a> {
///
/// ```no_run
/// use nitrokey::GetPasswordSafe;
- /// # use nitrokey::CommandError;
+ /// # use nitrokey::Error;
///
- /// # fn try_main() -> Result<(), CommandError> {
+ /// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let pws = device.get_password_safe("123456")?;
/// match pws.erase_slot(0) {
@@ -351,8 +351,8 @@ impl<'a> PasswordSafe<'a> {
/// # }
/// ```
///
- /// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- pub fn erase_slot(&self, slot: u8) -> Result<(), CommandError> {
+ /// [`InvalidSlot`]: enum.LibraryError.html#variant.InvalidSlot
+ pub fn erase_slot(&self, slot: u8) -> Result<(), Error> {
unsafe { get_command_result(nitrokey_sys::NK_erase_password_safe_slot(slot)) }
}
}
@@ -365,19 +365,19 @@ impl<'a> Drop for PasswordSafe<'a> {
}
impl GetPasswordSafe for Pro {
- fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError> {
+ fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, Error> {
get_password_safe(self, user_pin)
}
}
impl GetPasswordSafe for Storage {
- fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError> {
+ fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, Error> {
get_password_safe(self, user_pin)
}
}
impl GetPasswordSafe for DeviceWrapper {
- fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError> {
+ fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, Error> {
get_password_safe(self, user_pin)
}
}
diff --git a/src/util.rs b/src/util.rs
index 567c478..79b8c34 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,53 +1,11 @@
-use std::borrow;
use std::ffi::{CStr, CString};
-use std::fmt;
use std::os::raw::{c_char, c_int};
use libc::{c_void, free};
use rand_core::RngCore;
use rand_os::OsRng;
-/// Error types returned by Nitrokey device or by the library.
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum CommandError {
- /// A packet with a wrong checksum has been sent or received.
- WrongCrc,
- /// A command tried to access an OTP slot that does not exist.
- WrongSlot,
- /// A command tried to generate an OTP on a slot that is not configured.
- SlotNotProgrammed,
- /// The provided password is wrong.
- WrongPassword,
- /// You are not authorized for this command or provided a wrong temporary
- /// password.
- NotAuthorized,
- /// An error occurred when getting or setting the time.
- Timestamp,
- /// You did not provide a name for the OTP slot.
- NoName,
- /// This command is not supported by this device.
- NotSupported,
- /// This command is unknown.
- UnknownCommand,
- /// AES decryption failed.
- AesDecryptionFailed,
- /// An unknown error occurred.
- Unknown(i64),
- /// An unspecified error occurred.
- Undefined,
- /// You passed a string containing a null byte.
- InvalidString,
- /// A supplied string exceeded a length limit.
- StringTooLong,
- /// You passed an invalid slot.
- InvalidSlot,
- /// The supplied string was not in hexadecimal format.
- InvalidHexString,
- /// The target buffer was smaller than the source.
- TargetBufferTooSmall,
- /// An error occurred during random number generation.
- RngError,
-}
+use crate::error::{Error, LibraryError};
/// Log level for libnitrokey.
///
@@ -76,9 +34,9 @@ pub fn owned_str_from_ptr(ptr: *const c_char) -> String {
}
}
-pub fn result_from_string(ptr: *const c_char) -> Result<String, CommandError> {
+pub fn result_from_string(ptr: *const c_char) -> Result<String, Error> {
if ptr.is_null() {
- return Err(CommandError::Undefined);
+ return Err(Error::UnexpectedError);
}
unsafe {
let s = owned_str_from_ptr(ptr);
@@ -93,103 +51,34 @@ pub fn result_from_string(ptr: *const c_char) -> Result<String, CommandError> {
}
}
-pub fn get_command_result(value: c_int) -> Result<(), CommandError> {
+pub fn get_command_result(value: c_int) -> Result<(), Error> {
match value {
0 => Ok(()),
- other => Err(CommandError::from(other)),
+ other => Err(Error::from(other)),
}
}
-pub fn get_last_result() -> Result<(), CommandError> {
+pub fn get_last_result() -> Result<(), Error> {
let value = unsafe { nitrokey_sys::NK_get_last_command_status() } as c_int;
get_command_result(value)
}
-pub fn get_last_error() -> CommandError {
+pub fn get_last_error() -> Error {
return match get_last_result() {
- Ok(()) => CommandError::Undefined,
+ Ok(()) => Error::UnexpectedError,
Err(err) => err,
};
}
-pub fn generate_password(length: usize) -> Result<Vec<u8>, CommandError> {
+pub fn generate_password(length: usize) -> Result<Vec<u8>, Error> {
let mut rng = OsRng::new()?;
let mut data = vec![0u8; length];
rng.fill_bytes(&mut data[..]);
Ok(data)
}
-pub fn get_cstring<T: Into<Vec<u8>>>(s: T) -> Result<CString, CommandError> {
- CString::new(s).or(Err(CommandError::InvalidString))
-}
-
-impl CommandError {
- fn as_str(&self) -> borrow::Cow<'static, str> {
- match *self {
- CommandError::WrongCrc => {
- "A packet with a wrong checksum has been sent or received".into()
- }
- CommandError::WrongSlot => "The given OTP slot does not exist".into(),
- CommandError::SlotNotProgrammed => "The given OTP slot is not programmed".into(),
- CommandError::WrongPassword => "The given password is wrong".into(),
- CommandError::NotAuthorized => {
- "You are not authorized for this command or provided a wrong temporary \
- password"
- .into()
- }
- CommandError::Timestamp => "An error occurred when getting or setting the time".into(),
- CommandError::NoName => "You did not provide a name for the OTP slot".into(),
- CommandError::NotSupported => "This command is not supported by this device".into(),
- CommandError::UnknownCommand => "This command is unknown".into(),
- CommandError::AesDecryptionFailed => "AES decryption failed".into(),
- CommandError::Unknown(x) => {
- borrow::Cow::from(format!("An unknown error occurred ({})", x))
- }
- CommandError::Undefined => "An unspecified error occurred".into(),
- CommandError::InvalidString => "You passed a string containing a null byte".into(),
- CommandError::StringTooLong => "The supplied string is too long".into(),
- CommandError::InvalidSlot => "The given slot is invalid".into(),
- CommandError::InvalidHexString => {
- "The supplied string is not in hexadecimal format".into()
- }
- CommandError::TargetBufferTooSmall => "The target buffer is too small".into(),
- CommandError::RngError => "An error occurred during random number generation".into(),
- }
- }
-}
-
-impl fmt::Display for CommandError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.as_str())
- }
-}
-
-impl From<c_int> for CommandError {
- fn from(value: c_int) -> Self {
- match value {
- 1 => CommandError::WrongCrc,
- 2 => CommandError::WrongSlot,
- 3 => CommandError::SlotNotProgrammed,
- 4 => CommandError::WrongPassword,
- 5 => CommandError::NotAuthorized,
- 6 => CommandError::Timestamp,
- 7 => CommandError::NoName,
- 8 => CommandError::NotSupported,
- 9 => CommandError::UnknownCommand,
- 10 => CommandError::AesDecryptionFailed,
- 200 => CommandError::StringTooLong,
- 201 => CommandError::InvalidSlot,
- 202 => CommandError::InvalidHexString,
- 203 => CommandError::TargetBufferTooSmall,
- x => CommandError::Unknown(x.into()),
- }
- }
-}
-
-impl From<rand_core::Error> for CommandError {
- fn from(_error: rand_core::Error) -> Self {
- CommandError::RngError
- }
+pub fn get_cstring<T: Into<Vec<u8>>>(s: T) -> Result<CString, Error> {
+ CString::new(s).or(Err(LibraryError::InvalidString.into()))
}
impl Into<i32> for LogLevel {