diff options
Diffstat (limited to 'nitrokey/src/device.rs')
-rw-r--r-- | nitrokey/src/device.rs | 457 |
1 files changed, 240 insertions, 217 deletions
diff --git a/nitrokey/src/device.rs b/nitrokey/src/device.rs index 9813c50..386ce94 100644 --- a/nitrokey/src/device.rs +++ b/nitrokey/src/device.rs @@ -1,15 +1,18 @@ +// Copyright (C) 2018-2019 Robin Krahl <robin.krahl@ireas.org> +// SPDX-License-Identifier: MIT + use std::fmt; +use std::marker; use libc; 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)] @@ -22,14 +25,10 @@ pub enum Model { impl fmt::Display for Model { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - Model::Pro => "Pro", - Model::Storage => "Storage", - } - ) + f.write_str(match *self { + Model::Pro => "Pro", + Model::Storage => "Storage", + }) } } @@ -44,10 +43,10 @@ pub enum VolumeMode { impl fmt::Display for VolumeMode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - VolumeMode::ReadOnly => f.write_str("read-only"), - VolumeMode::ReadWrite => f.write_str("read-write"), - } + f.write_str(match *self { + VolumeMode::ReadOnly => "read-only", + VolumeMode::ReadWrite => "read-write", + }) } } @@ -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) => { @@ -155,7 +154,11 @@ pub enum DeviceWrapper { /// [`connect`]: fn.connect.html /// [`Pro::connect`]: #method.connect #[derive(Debug)] -pub struct Pro {} +pub struct Pro { + // make sure that users cannot directly instantiate this type + #[doc(hidden)] + marker: marker::PhantomData<()>, +} /// A Nitrokey Storage device without user or admin authentication. /// @@ -170,12 +173,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) => { @@ -197,7 +200,11 @@ pub struct Pro {} /// [`connect`]: fn.connect.html /// [`Storage::connect`]: #method.connect #[derive(Debug)] -pub struct Storage {} +pub struct Storage { + // make sure that users cannot directly instantiate this type + #[doc(hidden)] + marker: marker::PhantomData<()>, +} /// The status of a volume on a Nitrokey Storage device. #[derive(Debug)] @@ -225,13 +232,26 @@ pub struct SdCardData { pub manufacturer: u8, } -#[derive(Debug)] -/// Production information for a Storage device. -pub struct StorageProductionInfo { +/// A firmware version for a Nitrokey device. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct FirmwareVersion { /// The major firmware version, e. g. 0 in v0.40. - pub firmware_version_major: u8, + pub major: u8, /// The minor firmware version, e. g. 40 in v0.40. - pub firmware_version_minor: u8, + pub minor: u8, +} + +impl fmt::Display for FirmwareVersion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "v{}.{}", self.major, self.minor) + } +} + +/// Production information for a Storage device. +#[derive(Debug)] +pub struct StorageProductionInfo { + /// The firmware version. + pub firmware_version: FirmwareVersion, /// The internal firmware version. pub firmware_version_internal: u8, /// The serial number of the CPU. @@ -249,10 +269,8 @@ pub struct StorageStatus { pub encrypted_volume: VolumeStatus, /// The status of the hidden volume. pub hidden_volume: VolumeStatus, - /// The major firmware version, e. g. 0 in v0.40. - pub firmware_version_major: u8, - /// The minor firmware version, e. g. 40 in v0.40. - pub firmware_version_minor: u8, + /// The firmware version. + pub firmware_version: FirmwareVersion, /// Indicates whether the firmware is locked. pub firmware_locked: bool, /// The serial number of the SD card in the Storage stick. @@ -276,16 +294,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(()) @@ -299,9 +317,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), @@ -310,8 +328,8 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp { /// # Ok(()) /// # } /// ``` - fn get_serial_number(&self) -> Result<String, CommandError> { - unsafe { result_from_string(nitrokey_sys::NK_device_serial_number()) } + fn get_serial_number(&self) -> Result<String, Error> { + result_from_string(unsafe { nitrokey_sys::NK_device_serial_number() }) } /// Returns the number of remaining authentication attempts for the user. The total number of @@ -321,9 +339,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); @@ -341,9 +359,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); @@ -360,9 +378,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: {}.{}", @@ -382,9 +400,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: {}.{}", @@ -403,9 +421,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); @@ -415,17 +433,15 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp { /// # Ok(()) /// # } /// ``` - fn get_config(&self) -> Result<Config, CommandError> { - unsafe { - let config_ptr = nitrokey_sys::NK_read_config(); - if config_ptr.is_null() { - return Err(get_last_error()); - } - let config_array_ptr = config_ptr as *const [u8; 5]; - let raw_config = RawConfig::from(*config_array_ptr); - libc::free(config_ptr as *mut libc::c_void); - return Ok(raw_config.into()); + fn get_config(&self) -> Result<Config, Error> { + let config_ptr = unsafe { nitrokey_sys::NK_read_config() }; + if config_ptr.is_null() { + return Err(get_last_error()); } + let config_array_ptr = config_ptr as *const [u8; 5]; + let raw_config = unsafe { RawConfig::from(*config_array_ptr) }; + unsafe { libc::free(config_ptr as *mut libc::c_void) }; + Ok(raw_config.into()) } /// Changes the administrator PIN. @@ -439,9 +455,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."), @@ -451,17 +467,14 @@ 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 { - get_command_result(nitrokey_sys::NK_change_admin_PIN( - current_string.as_ptr(), - new_string.as_ptr(), - )) - } + get_command_result(unsafe { + nitrokey_sys::NK_change_admin_PIN(current_string.as_ptr(), new_string.as_ptr()) + }) } /// Changes the user PIN. @@ -475,9 +488,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."), @@ -487,17 +500,14 @@ 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 { - get_command_result(nitrokey_sys::NK_change_user_PIN( - current_string.as_ptr(), - new_string.as_ptr(), - )) - } + get_command_result(unsafe { + nitrokey_sys::NK_change_user_PIN(current_string.as_ptr(), new_string.as_ptr()) + }) } /// Unlocks the user PIN after three failed login attempts and sets it to the given value. @@ -511,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."), @@ -523,17 +533,17 @@ 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 { - get_command_result(nitrokey_sys::NK_unlock_user_password( + get_command_result(unsafe { + nitrokey_sys::NK_unlock_user_password( admin_pin_string.as_ptr(), user_pin_string.as_ptr(), - )) - } + ) + }) } /// Locks the Nitrokey device. @@ -545,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."), @@ -556,8 +566,8 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp { /// # Ok(()) /// # } /// ``` - fn lock(&self) -> Result<(), CommandError> { - unsafe { get_command_result(nitrokey_sys::NK_lock_device()) } + fn lock(&self) -> Result<(), Error> { + get_command_result(unsafe { nitrokey_sys::NK_lock_device() }) } /// Performs a factory reset on the Nitrokey device. @@ -576,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."), @@ -589,9 +599,9 @@ 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())) } + get_command_result(unsafe { nitrokey_sys::NK_factory_reset(admin_pin_string.as_ptr()) }) } /// Builds a new AES key on the Nitrokey. @@ -610,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."), @@ -623,9 +633,9 @@ 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())) } + get_command_result(unsafe { nitrokey_sys::NK_build_aes_key(admin_pin_string.as_ptr()) }) } } @@ -634,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 /// @@ -649,16 +659,15 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp { /// } /// ``` /// -/// [`Undefined`]: enum.CommandError.html#variant.Undefined -pub fn connect() -> Result<DeviceWrapper, CommandError> { - unsafe { - match nitrokey_sys::NK_login_auto() { - 1 => match get_connected_device() { - Some(wrapper) => Ok(wrapper), - None => Err(CommandError::Undefined), - }, - _ => Err(CommandError::Undefined), +/// [`NotConnected`]: enum.CommunicationError.html#variant.NotConnected +pub fn connect() -> Result<DeviceWrapper, Error> { + if unsafe { nitrokey_sys::NK_login_auto() } == 1 { + match get_connected_device() { + Some(wrapper) => Ok(wrapper), + None => Err(CommunicationError::NotConnected.into()), } + } else { + Err(CommunicationError::NotConnected.into()) } } @@ -666,7 +675,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 /// @@ -682,29 +691,27 @@ 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()) } } fn get_connected_model() -> Option<Model> { - unsafe { - match nitrokey_sys::NK_get_device_model() { - nitrokey_sys::NK_device_model_NK_PRO => Some(Model::Pro), - nitrokey_sys::NK_device_model_NK_STORAGE => Some(Model::Storage), - _ => None, - } + match unsafe { nitrokey_sys::NK_get_device_model() } { + nitrokey_sys::NK_device_model_NK_PRO => Some(Model::Pro), + nitrokey_sys::NK_device_model_NK_STORAGE => Some(Model::Storage), + _ => None, } } fn create_device_wrapper(model: Model) -> DeviceWrapper { match model { - Model::Pro => DeviceWrapper::Pro(Pro {}), - Model::Storage => DeviceWrapper::Storage(Storage {}), + Model::Pro => Pro::new().into(), + Model::Storage => Storage::new().into(), } } @@ -729,20 +736,32 @@ impl DeviceWrapper { } } +impl From<Pro> for DeviceWrapper { + fn from(device: Pro) -> Self { + DeviceWrapper::Pro(device) + } +} + +impl From<Storage> for DeviceWrapper { + fn from(device: Storage) -> Self { + DeviceWrapper::Storage(device) + } +} + 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) } } @@ -761,7 +780,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 /// @@ -776,12 +795,19 @@ 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), + if connect_enum(Model::Pro) { + Ok(Pro::new()) + } else { + Err(CommunicationError::NotConnected.into()) + } + } + + fn new() -> Pro { + Pro { + marker: marker::PhantomData, } } } @@ -807,7 +833,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 /// @@ -822,12 +848,19 @@ 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), + if connect_enum(Model::Storage) { + Ok(Storage::new()) + } else { + Err(CommunicationError::NotConnected.into()) + } + } + + fn new() -> Storage { + Storage { + marker: marker::PhantomData, } } @@ -845,9 +878,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."), @@ -857,17 +890,14 @@ 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 { - get_command_result(nitrokey_sys::NK_change_update_password( - current_string.as_ptr(), - new_string.as_ptr(), - )) - } + get_command_result(unsafe { + nitrokey_sys::NK_change_update_password(current_string.as_ptr(), new_string.as_ptr()) + }) } /// Enables the firmware update mode. @@ -885,9 +915,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."), @@ -897,15 +927,13 @@ 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( - update_pin_string.as_ptr(), - )) - } + get_command_result(unsafe { + nitrokey_sys::NK_enable_firmware_update(update_pin_string.as_ptr()) + }) } /// Enables the encrypted storage volume. @@ -921,9 +949,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."), @@ -933,11 +961,11 @@ 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())) } + get_command_result(unsafe { nitrokey_sys::NK_unlock_encrypted_volume(user_pin.as_ptr()) }) } /// Disables the encrypted storage volume. @@ -948,11 +976,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(()) => { @@ -970,8 +998,8 @@ impl Storage { /// # Ok(()) /// # } /// ``` - pub fn disable_encrypted_volume(&self) -> Result<(), CommandError> { - unsafe { get_command_result(nitrokey_sys::NK_lock_encrypted_volume()) } + pub fn disable_encrypted_volume(&self) -> Result<(), Error> { + get_command_result(unsafe { nitrokey_sys::NK_lock_encrypted_volume() }) } /// Enables a hidden storage volume. @@ -996,9 +1024,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") { @@ -1011,14 +1039,12 @@ 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( - volume_password.as_ptr(), - )) - } + get_command_result(unsafe { + nitrokey_sys::NK_unlock_hidden_volume(volume_password.as_ptr()) + }) } /// Disables a hidden storage volume. @@ -1029,11 +1055,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") { @@ -1052,8 +1078,8 @@ impl Storage { /// # Ok(()) /// # } /// ``` - pub fn disable_hidden_volume(&self) -> Result<(), CommandError> { - unsafe { get_command_result(nitrokey_sys::NK_lock_hidden_volume()) } + pub fn disable_hidden_volume(&self) -> Result<(), Error> { + get_command_result(unsafe { nitrokey_sys::NK_lock_hidden_volume() }) } /// Creates a hidden volume. @@ -1078,9 +1104,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")?; @@ -1089,23 +1115,18 @@ 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( - slot, - start, - end, - password.as_ptr(), - )) - } + get_command_result(unsafe { + nitrokey_sys::NK_create_hidden_volume(slot, start, end, password.as_ptr()) + }) } /// Sets the access mode of the unencrypted volume. @@ -1122,10 +1143,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."), @@ -1135,13 +1156,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 { @@ -1159,11 +1180,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) => { @@ -1174,7 +1195,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, @@ -1194,8 +1215,7 @@ impl Storage { stick_initialized: false, }; let raw_result = unsafe { nitrokey_sys::NK_get_status_storage(&mut raw_status) }; - let result = get_command_result(raw_result); - result.and(Ok(StorageStatus::from(raw_status))) + get_command_result(raw_result).map(|_| StorageStatus::from(raw_status)) } /// Returns the production information for the connected storage device. @@ -1203,11 +1223,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) => { @@ -1219,7 +1239,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, @@ -1236,8 +1256,7 @@ impl Storage { SD_Card_Manufacturer_u8: 0, }; let raw_result = unsafe { nitrokey_sys::NK_get_storage_production_info(&mut raw_data) }; - let result = get_command_result(raw_result); - result.and(Ok(StorageProductionInfo::from(raw_data))) + get_command_result(raw_result).map(|_| StorageProductionInfo::from(raw_data)) } /// Clears the warning for a new SD card. @@ -1254,9 +1273,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."), @@ -1266,9 +1285,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()) @@ -1276,7 +1295,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() }) } @@ -1294,9 +1313,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()) }) } @@ -1321,8 +1340,10 @@ impl GenerateOtp for Storage {} impl From<nitrokey_sys::NK_storage_ProductionTest> for StorageProductionInfo { fn from(data: nitrokey_sys::NK_storage_ProductionTest) -> Self { Self { - firmware_version_major: data.FirmwareVersion_au8[0], - firmware_version_minor: data.FirmwareVersion_au8[1], + firmware_version: FirmwareVersion { + major: data.FirmwareVersion_au8[0], + minor: data.FirmwareVersion_au8[1], + }, firmware_version_internal: data.FirmwareVersionInternal_u8, serial_number_cpu: data.CPU_CardID_u32, sd_card: SdCardData { @@ -1352,8 +1373,10 @@ impl From<nitrokey_sys::NK_storage_status> for StorageStatus { read_only: status.hidden_volume_read_only, active: status.hidden_volume_active, }, - firmware_version_major: status.firmware_version_major, - firmware_version_minor: status.firmware_version_minor, + firmware_version: FirmwareVersion { + major: status.firmware_version_major, + minor: status.firmware_version_minor, + }, firmware_locked: status.firmware_locked, serial_number_sd_card: status.serial_number_sd_card, serial_number_smart_card: status.serial_number_smart_card, |