diff options
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| -rw-r--r-- | src/auth.rs | 183 | ||||
| -rw-r--r-- | src/device.rs | 42 | ||||
| -rw-r--r-- | src/lib.rs | 4 | ||||
| -rw-r--r-- | src/otp.rs | 16 | ||||
| -rw-r--r-- | tests/device.rs | 137 | ||||
| -rw-r--r-- | tests/otp.rs | 66 | ||||
| -rw-r--r-- | tests/util/mod.rs | 12 | 
8 files changed, 185 insertions, 277 deletions
| diff --git a/CHANGELOG.md b/CHANGELOG.md index e98e857..8e6cb9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ SPDX-License-Identifier: MIT    - Implement `DerefMut` for `User<T>` and `Admin<T>`.    - Add `device_mut` method to `DeviceWrapper`.    - Require a mutable `Device` reference if a method changes the device state. +- Let `Admin` and `User` store a mutable reference to the `Device` instead of +  the `Device` value.  # v0.3.4 (2019-01-20)  - Fix authentication methods that assumed that `char` is signed. diff --git a/src/auth.rs b/src/auth.rs index f9f50fa..573fed3 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -42,16 +42,10 @@ pub trait Authenticate {      /// fn perform_other_task(device: &DeviceWrapper) {}      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; -    /// let device = match device.authenticate_user("123456") { -    ///     Ok(user) => { -    ///         perform_user_task(&user); -    ///         user.device() -    ///     }, -    ///     Err((device, err)) => { -    ///         eprintln!("Could not authenticate as user: {}", err); -    ///         device -    ///     }, +    /// let mut device = nitrokey::connect()?; +    /// match device.authenticate_user("123456") { +    ///     Ok(user) => perform_user_task(&user), +    ///     Err(err) => eprintln!("Could not authenticate as user: {}", err),      /// };      /// perform_other_task(&device);      /// #     Ok(()) @@ -61,9 +55,9 @@ pub trait Authenticate {      /// [`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, Error)> +    fn authenticate_user(&mut self, password: &str) -> Result<User<'_, Self>, Error>      where -        Self: Device + Sized; +        Self: Device + std::marker::Sized;      /// Performs admin authentication.  This method consumes the device.  If successful, an      /// authenticated device is returned.  Otherwise, the current unauthenticated device and the @@ -88,16 +82,10 @@ pub trait Authenticate {      /// fn perform_other_task(device: &DeviceWrapper) {}      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; -    /// let device = match device.authenticate_admin("123456") { -    ///     Ok(admin) => { -    ///         perform_admin_task(&admin); -    ///         admin.device() -    ///     }, -    ///     Err((device, err)) => { -    ///         eprintln!("Could not authenticate as admin: {}", err); -    ///         device -    ///     }, +    /// let mut device = nitrokey::connect()?; +    /// match device.authenticate_admin("123456") { +    ///     Ok(admin) => perform_admin_task(&admin), +    ///     Err(err) => eprintln!("Could not authenticate as admin: {}", err),      /// };      /// perform_other_task(&device);      /// #     Ok(()) @@ -107,13 +95,13 @@ pub trait Authenticate {      /// [`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, Error)> +    fn authenticate_admin(&mut self, password: &str) -> Result<Admin<'_, Self>, Error>      where -        Self: Device + Sized; +        Self: Device + std::marker::Sized;  } -trait AuthenticatedDevice<T> { -    fn new(device: T, temp_password: Vec<u8>) -> Self; +trait AuthenticatedDevice<'a, T> { +    fn new(device: &'a mut T, temp_password: Vec<u8>) -> Self;      fn temp_password_ptr(&self) -> *const c_char;  } @@ -128,8 +116,8 @@ trait AuthenticatedDevice<T> {  /// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin  /// [`device`]: #method.device  #[derive(Debug)] -pub struct User<T: Device> { -    device: T, +pub struct User<'a, T: Device> { +    device: &'a mut T,      temp_password: Vec<u8>,  } @@ -143,89 +131,42 @@ pub struct User<T: Device> {  /// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin  /// [`device`]: #method.device  #[derive(Debug)] -pub struct Admin<T: Device> { -    device: T, +pub struct Admin<'a, T: Device> { +    device: &'a mut T,      temp_password: Vec<u8>,  } -fn authenticate<D, A, T>(device: D, password: &str, callback: T) -> Result<A, (D, Error)> +fn authenticate<'a, D, A, T>(device: &'a mut D, password: &str, callback: T) -> Result<A, Error>  where      D: Device, -    A: AuthenticatedDevice<D>, +    A: AuthenticatedDevice<'a, D>,      T: Fn(*const c_char, *const c_char) -> c_int,  { -    let temp_password = match generate_password(TEMPORARY_PASSWORD_LENGTH) { -        Ok(temp_password) => temp_password, -        Err(err) => return Err((device, err)), -    }; -    let password = match get_cstring(password) { -        Ok(password) => password, -        Err(err) => return Err((device, err)), -    }; +    let temp_password = generate_password(TEMPORARY_PASSWORD_LENGTH)?; +    let password = get_cstring(password)?;      let password_ptr = password.as_ptr();      let temp_password_ptr = temp_password.as_ptr() as *const c_char;      match callback(password_ptr, temp_password_ptr) {          0 => Ok(A::new(device, temp_password)), -        rv => Err((device, Error::from(rv))), +        rv => Err(Error::from(rv)),      }  } -fn authenticate_user_wrapper<T, C>( -    device: T, -    constructor: C, -    password: &str, -) -> Result<User<DeviceWrapper>, (DeviceWrapper, Error)> -where -    T: Device, -    C: Fn(T) -> DeviceWrapper, -{ -    let result = device.authenticate_user(password); -    match result { -        Ok(user) => Ok(User::new(constructor(user.device), user.temp_password)), -        Err((device, err)) => Err((constructor(device), err)), -    } -} - -fn authenticate_admin_wrapper<T, C>( -    device: T, -    constructor: C, -    password: &str, -) -> Result<Admin<DeviceWrapper>, (DeviceWrapper, Error)> -where -    T: Device, -    C: Fn(T) -> DeviceWrapper, -{ -    let result = device.authenticate_admin(password); -    match result { -        Ok(user) => Ok(Admin::new(constructor(user.device), user.temp_password)), -        Err((device, err)) => Err((constructor(device), err)), -    } -} - -impl<T: Device> User<T> { -    /// Forgets the user authentication and returns an unauthenticated device.  This method -    /// consumes the authenticated device.  It does not perform any actual commands on the -    /// Nitrokey. -    pub fn device(self) -> T { -        self.device -    } -} - -impl<T: Device> ops::Deref for User<T> { +impl<'a, T: Device> ops::Deref for User<'a, T> {      type Target = T;      fn deref(&self) -> &Self::Target { -        &self.device +        self.device      }  } -impl<T: Device> ops::DerefMut for User<T> { +impl<'a, T: Device> ops::DerefMut for User<'a, T> {      fn deref_mut(&mut self) -> &mut T { -        &mut self.device +        self.device      }  } -impl<T: Device> GenerateOtp for User<T> { +impl<'a, T: Device> GenerateOtp for User<'a, T> {      fn get_hotp_code(&mut self, slot: u8) -> Result<String, Error> {          result_from_string(unsafe {              nitrokey_sys::NK_get_hotp_code_PIN(slot, self.temp_password_ptr()) @@ -239,8 +180,8 @@ impl<T: Device> GenerateOtp for User<T> {      }  } -impl<T: Device> AuthenticatedDevice<T> for User<T> { -    fn new(device: T, temp_password: Vec<u8>) -> Self { +impl<'a, T: Device> AuthenticatedDevice<'a, T> for User<'a, T> { +    fn new(device: &'a mut T, temp_password: Vec<u8>) -> Self {          User {              device,              temp_password, @@ -252,28 +193,21 @@ impl<T: Device> AuthenticatedDevice<T> for User<T> {      }  } -impl<T: Device> ops::Deref for Admin<T> { +impl<'a, T: Device> ops::Deref for Admin<'a, T> {      type Target = T;      fn deref(&self) -> &Self::Target { -        &self.device +        self.device      }  } -impl<T: Device> ops::DerefMut for Admin<T> { +impl<'a, T: Device> ops::DerefMut for Admin<'a, T> {      fn deref_mut(&mut self) -> &mut T { -        &mut self.device -    } -} - -impl<T: Device> Admin<T> { -    /// Forgets the user authentication and returns an unauthenticated device.  This method -    /// consumes the authenticated device.  It does not perform any actual commands on the -    /// Nitrokey. -    pub fn device(self) -> T {          self.device      } +} +impl<'a, T: Device> Admin<'a, T> {      /// Writes the given configuration to the Nitrokey device.      ///      /// # Errors @@ -287,14 +221,11 @@ impl<T: Device> Admin<T> {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// let config = Config::new(None, None, None, false);      /// match device.authenticate_admin("12345678") { -    ///     Ok(mut admin) => { -    ///         admin.write_config(config); -    ///         () -    ///     }, -    ///     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), +    ///     Ok(mut admin) => admin.write_config(config)?, +    ///     Err(err) => eprintln!("Could not authenticate as admin: {}", err),      /// };      /// #     Ok(())      /// # } @@ -316,7 +247,7 @@ impl<T: Device> Admin<T> {      }  } -impl<T: Device> ConfigureOtp for Admin<T> { +impl<'a, T: Device> ConfigureOtp for Admin<'a, T> {      fn write_hotp_slot(&mut self, data: OtpSlotData, counter: u64) -> Result<(), Error> {          let raw_data = RawOtpSlotData::new(data)?;          get_command_result(unsafe { @@ -364,8 +295,8 @@ impl<T: Device> ConfigureOtp for Admin<T> {      }  } -impl<T: Device> AuthenticatedDevice<T> for Admin<T> { -    fn new(device: T, temp_password: Vec<u8>) -> Self { +impl<'a, T: Device> AuthenticatedDevice<'a, T> for Admin<'a, T> { +    fn new(device: &'a mut T, temp_password: Vec<u8>) -> Self {          Admin {              device,              temp_password, @@ -378,35 +309,27 @@ impl<T: Device> AuthenticatedDevice<T> for Admin<T> {  }  impl Authenticate for DeviceWrapper { -    fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)> { -        match self { -            DeviceWrapper::Storage(storage) => { -                authenticate_user_wrapper(storage, DeviceWrapper::Storage, password) -            } -            DeviceWrapper::Pro(pro) => authenticate_user_wrapper(pro, DeviceWrapper::Pro, password), -        } +    fn authenticate_user(&mut self, password: &str) -> Result<User<'_, 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, Error)> { -        match self { -            DeviceWrapper::Storage(storage) => { -                authenticate_admin_wrapper(storage, DeviceWrapper::Storage, password) -            } -            DeviceWrapper::Pro(pro) => { -                authenticate_admin_wrapper(pro, DeviceWrapper::Pro, password) -            } -        } +    fn authenticate_admin(&mut self, password: &str) -> Result<Admin<'_, Self>, Error> { +        authenticate(self, password, |password_ptr, temp_password_ptr| unsafe { +            nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr) +        })      }  }  impl Authenticate for Pro { -    fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)> { +    fn authenticate_user(&mut self, password: &str) -> Result<User<'_, 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, Error)> { +    fn authenticate_admin(&mut self, password: &str) -> Result<Admin<'_, Self>, Error> {          authenticate(self, password, |password_ptr, temp_password_ptr| unsafe {              nitrokey_sys::NK_first_authenticate(password_ptr, temp_password_ptr)          }) @@ -414,13 +337,13 @@ impl Authenticate for Pro {  }  impl Authenticate for Storage { -    fn authenticate_user(self, password: &str) -> Result<User<Self>, (Self, Error)> { +    fn authenticate_user(&mut self, password: &str) -> Result<User<'_, 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, Error)> { +    fn authenticate_admin(&mut self, password: &str) -> Result<Admin<'_, 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/device.rs b/src/device.rs index f6492cd..a0df30e 100644 --- a/src/device.rs +++ b/src/device.rs @@ -71,16 +71,10 @@ impl fmt::Display for VolumeMode {  /// fn perform_other_task(device: &DeviceWrapper) {}  ///  /// # fn try_main() -> Result<(), Error> { -/// let device = nitrokey::connect()?; -/// let device = match device.authenticate_user("123456") { -///     Ok(user) => { -///         perform_user_task(&user); -///         user.device() -///     }, -///     Err((device, err)) => { -///         eprintln!("Could not authenticate as user: {}", err); -///         device -///     }, +/// let mut device = nitrokey::connect()?; +/// match device.authenticate_user("123456") { +///     Ok(user) => perform_user_task(&user), +///     Err(err) => eprintln!("Could not authenticate as user: {}", err),  /// };  /// perform_other_task(&device);  /// #     Ok(()) @@ -135,16 +129,10 @@ pub enum DeviceWrapper {  /// fn perform_other_task(device: &Pro) {}  ///  /// # fn try_main() -> Result<(), Error> { -/// let device = nitrokey::Pro::connect()?; -/// let device = match device.authenticate_user("123456") { -///     Ok(user) => { -///         perform_user_task(&user); -///         user.device() -///     }, -///     Err((device, err)) => { -///         eprintln!("Could not authenticate as user: {}", err); -///         device -///     }, +/// let mut device = nitrokey::Pro::connect()?; +/// match device.authenticate_user("123456") { +///     Ok(user) => perform_user_task(&user), +///     Err(err) => eprintln!("Could not authenticate as user: {}", err),  /// };  /// perform_other_task(&device);  /// #     Ok(()) @@ -181,16 +169,10 @@ pub struct Pro {  /// fn perform_other_task(device: &Storage) {}  ///  /// # fn try_main() -> Result<(), Error> { -/// let device = nitrokey::Storage::connect()?; -/// let device = match device.authenticate_user("123456") { -///     Ok(user) => { -///         perform_user_task(&user); -///         user.device() -///     }, -///     Err((device, err)) => { -///         eprintln!("Could not authenticate as user: {}", err); -///         device -///     }, +/// let mut device = nitrokey::Storage::connect()?; +/// match device.authenticate_user("123456") { +///     Ok(user) => perform_user_task(&user), +///     Err(err) => eprintln!("Could not authenticate as user: {}", err),  /// };  /// perform_other_task(&device);  /// #     Ok(()) @@ -44,7 +44,7 @@  //! # use nitrokey::Error;  //!  //! # fn try_main() -> Result<(), Error> { -//! let device = nitrokey::connect()?; +//! let mut device = nitrokey::connect()?;  //! let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits);  //! match device.authenticate_admin("12345678") {  //!     Ok(mut admin) => { @@ -53,7 +53,7 @@  //!             Err(err) => eprintln!("Could not write slot: {}", err),  //!         }  //!     }, -//!     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), +//!     Err(err) => eprintln!("Could not authenticate as admin: {}", err),  //! }  //! #     Ok(())  //! # } @@ -35,7 +35,7 @@ pub trait ConfigureOtp {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits);      /// match device.authenticate_admin("12345678") {      ///     Ok(mut admin) => { @@ -44,7 +44,7 @@ pub trait ConfigureOtp {      ///             Err(err) => eprintln!("Could not write slot: {}", err),      ///         }      ///     }, -    ///     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), +    ///     Err(err) => eprintln!("Could not authenticate as admin: {}", err),      /// }      /// #     Ok(())      /// # } @@ -71,7 +71,7 @@ pub trait ConfigureOtp {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::EightDigits);      /// match device.authenticate_admin("12345678") {      ///     Ok(mut admin) => { @@ -80,7 +80,7 @@ pub trait ConfigureOtp {      ///             Err(err) => eprintln!("Could not write slot: {}", err),      ///         }      ///     }, -    ///     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), +    ///     Err(err) => eprintln!("Could not authenticate as admin: {}", err),      /// }      /// #     Ok(())      /// # } @@ -104,7 +104,7 @@ pub trait ConfigureOtp {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// match device.authenticate_admin("12345678") {      ///     Ok(mut admin) => {      ///         match admin.erase_hotp_slot(1) { @@ -112,7 +112,7 @@ pub trait ConfigureOtp {      ///             Err(err) => eprintln!("Could not erase slot: {}", err),      ///         }      ///     }, -    ///     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), +    ///     Err(err) => eprintln!("Could not authenticate as admin: {}", err),      /// }      /// #     Ok(())      /// # } @@ -134,7 +134,7 @@ pub trait ConfigureOtp {      /// # use nitrokey::Error;      ///      /// # fn try_main() -> Result<(), Error> { -    /// let device = nitrokey::connect()?; +    /// let mut device = nitrokey::connect()?;      /// match device.authenticate_admin("12345678") {      ///     Ok(mut admin) => {      ///         match admin.erase_totp_slot(1) { @@ -142,7 +142,7 @@ pub trait ConfigureOtp {      ///             Err(err) => eprintln!("Could not erase slot: {}", err),      ///         }      ///     }, -    ///     Err((_, err)) => eprintln!("Could not authenticate as admin: {}", err), +    ///     Err(err) => eprintln!("Could not authenticate as admin: {}", err),      /// }      /// #     Ok(())      /// # } diff --git a/tests/device.rs b/tests/device.rs index 7a69214..bffd767 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -98,41 +98,34 @@ fn get_firmware_version(device: Pro) {      assert!(version.minor > 0);  } -fn admin_retry<T: Authenticate + Device>(device: T, suffix: &str, count: u8) -> T { -    let result = device.authenticate_admin(&(ADMIN_PASSWORD.to_owned() + suffix)); -    let device = match result { -        Ok(admin) => admin.device(), -        Err((device, _)) => device, -    }; +fn admin_retry<T: Authenticate + Device>(device: &mut T, suffix: &str, count: u8) { +    assert_any_ok!(device.authenticate_admin(&(ADMIN_PASSWORD.to_owned() + suffix)));      assert_ok!(count, device.get_admin_retry_count()); -    return device;  } -fn user_retry<T: Authenticate + Device>(device: T, suffix: &str, count: u8) -> T { -    let result = device.authenticate_user(&(USER_PASSWORD.to_owned() + suffix)); -    let device = match result { -        Ok(admin) => admin.device(), -        Err((device, _)) => device, -    }; +fn user_retry<T: Authenticate + Device>(device: &mut T, suffix: &str, count: u8) { +    assert_any_ok!(device.authenticate_user(&(USER_PASSWORD.to_owned() + suffix)));      assert_ok!(count, device.get_user_retry_count()); -    return device;  }  #[test_device]  fn get_retry_count(device: DeviceWrapper) { -    let device = admin_retry(device, "", 3); -    let device = admin_retry(device, "123", 2); -    let device = admin_retry(device, "456", 1); -    let device = admin_retry(device, "", 3); - -    let device = user_retry(device, "", 3); -    let device = user_retry(device, "123", 2); -    let device = user_retry(device, "456", 1); -    user_retry(device, "", 3); +    let mut device = device; + +    admin_retry(&mut device, "", 3); +    admin_retry(&mut device, "123", 2); +    admin_retry(&mut device, "456", 1); +    admin_retry(&mut device, "", 3); + +    user_retry(&mut device, "", 3); +    user_retry(&mut device, "123", 2); +    user_retry(&mut device, "456", 1); +    user_retry(&mut device, "", 3);  }  #[test_device]  fn config(device: DeviceWrapper) { +    let mut device = device;      let mut admin = unwrap_ok!(device.authenticate_admin(ADMIN_PASSWORD));      let config = Config::new(None, None, None, true); @@ -153,43 +146,52 @@ fn config(device: DeviceWrapper) {  #[test_device]  fn change_user_pin(device: DeviceWrapper) { -    let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); -    let device = device.authenticate_user(USER_NEW_PASSWORD).unwrap_err().0; -      let mut device = device; +    assert_any_ok!(device.authenticate_user(USER_PASSWORD)); +    assert_cmd_err!( +        CommandError::WrongPassword, +        device.authenticate_user(USER_NEW_PASSWORD) +    ); +      assert_ok!((), device.change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD)); -    let device = device.authenticate_user(USER_PASSWORD).unwrap_err().0; -    let device = device -        .authenticate_user(USER_NEW_PASSWORD) -        .unwrap() -        .device(); +    assert_cmd_err!( +        CommandError::WrongPassword, +        device.authenticate_user(USER_PASSWORD) +    ); +    assert_any_ok!(device.authenticate_user(USER_NEW_PASSWORD)); -    let mut device = device;      let result = device.change_user_pin(USER_PASSWORD, USER_PASSWORD);      assert_cmd_err!(CommandError::WrongPassword, result);      assert_ok!((), device.change_user_pin(USER_NEW_PASSWORD, USER_PASSWORD)); -    let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); -    assert!(device.authenticate_user(USER_NEW_PASSWORD).is_err()); +    assert_any_ok!(device.authenticate_user(USER_PASSWORD)); +    assert_cmd_err!( +        CommandError::WrongPassword, +        device.authenticate_user(USER_NEW_PASSWORD) +    );  }  #[test_device]  fn change_admin_pin(device: DeviceWrapper) { -    let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); -    let mut device = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err().0; +    let mut device = device; +    assert_any_ok!(device.authenticate_admin(ADMIN_PASSWORD)); +    assert_cmd_err!( +        CommandError::WrongPassword, +        device.authenticate_admin(ADMIN_NEW_PASSWORD) +    );      assert_ok!(          (),          device.change_admin_pin(ADMIN_PASSWORD, ADMIN_NEW_PASSWORD)      ); -    let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap_err().0; -    let mut device = device -        .authenticate_admin(ADMIN_NEW_PASSWORD) -        .unwrap() -        .device(); +    assert_cmd_err!( +        CommandError::WrongPassword, +        device.authenticate_admin(ADMIN_PASSWORD) +    ); +    assert_any_ok!(device.authenticate_admin(ADMIN_NEW_PASSWORD));      assert_cmd_err!(          CommandError::WrongPassword, @@ -201,28 +203,24 @@ fn change_admin_pin(device: DeviceWrapper) {          device.change_admin_pin(ADMIN_NEW_PASSWORD, ADMIN_PASSWORD)      ); -    let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); -    device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err(); +    assert_any_ok!(device.authenticate_admin(ADMIN_PASSWORD)); +    assert_cmd_err!( +        CommandError::WrongPassword, +        device.authenticate_admin(ADMIN_NEW_PASSWORD) +    );  } -fn require_failed_user_login<D>(device: D, password: &str, error: CommandError) -> D -where -    D: Device + Authenticate, -    nitrokey::User<D>: std::fmt::Debug, -{ -    let result = device.authenticate_user(password); -    assert!(result.is_err()); -    let err = result.unwrap_err(); -    match err.1 { -        Error::CommandError(err) => assert_eq!(error, err), -        _ => assert!(false), -    }; -    err.0 +fn require_failed_user_login<D: Authenticate + Device>(device: &mut D, password: &str) { +    assert_cmd_err!( +        CommandError::WrongPassword, +        device.authenticate_user(password) +    );  }  #[test_device]  fn unlock_user_pin(device: DeviceWrapper) { -    let mut device = device.authenticate_user(USER_PASSWORD).unwrap().device(); +    let mut device = device; +    assert_any_ok!(device.authenticate_user(USER_PASSWORD));      assert_ok!((), device.unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD));      assert_cmd_err!(          CommandError::WrongPassword, @@ -231,10 +229,10 @@ fn unlock_user_pin(device: DeviceWrapper) {      // block user PIN      let wrong_password = USER_PASSWORD.to_owned() + "foo"; -    let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); -    let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); -    let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); -    let mut device = require_failed_user_login(device, USER_PASSWORD, CommandError::WrongPassword); +    require_failed_user_login(&mut device, &wrong_password); +    require_failed_user_login(&mut device, &wrong_password); +    require_failed_user_login(&mut device, &wrong_password); +    require_failed_user_login(&mut device, USER_PASSWORD);      // unblock with current PIN      assert_cmd_err!( @@ -242,13 +240,13 @@ fn unlock_user_pin(device: DeviceWrapper) {          device.unlock_user_pin(USER_PASSWORD, USER_PASSWORD)      );      assert_ok!((), device.unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD)); -    let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); +    assert_any_ok!(device.authenticate_user(USER_PASSWORD));      // block user PIN -    let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); -    let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); -    let device = require_failed_user_login(device, &wrong_password, CommandError::WrongPassword); -    let mut device = require_failed_user_login(device, USER_PASSWORD, CommandError::WrongPassword); +    require_failed_user_login(&mut device, &wrong_password); +    require_failed_user_login(&mut device, &wrong_password); +    require_failed_user_login(&mut device, &wrong_password); +    require_failed_user_login(&mut device, USER_PASSWORD);      // unblock with new PIN      assert_cmd_err!( @@ -274,11 +272,11 @@ fn assert_utf8_err_or_ne(left: &str, right: Result<String, Error>) {  #[test_device]  fn factory_reset(device: DeviceWrapper) { +    let mut device = device;      let mut admin = unwrap_ok!(device.authenticate_admin(ADMIN_PASSWORD));      let otp_data = OtpSlotData::new(1, "test", "0123468790", OtpMode::SixDigits);      assert_ok!((), admin.write_totp_slot(otp_data, 30)); -    let mut device = admin.device();      let mut pws = unwrap_ok!(device.get_password_safe(USER_PASSWORD));      assert_ok!((), pws.write_slot(0, "test", "testlogin", "testpw"));      drop(pws); @@ -299,12 +297,11 @@ fn factory_reset(device: DeviceWrapper) {      );      assert_ok!((), device.factory_reset(ADMIN_NEW_PASSWORD)); -    let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); +    assert_any_ok!(device.authenticate_admin(ADMIN_PASSWORD));      let user = unwrap_ok!(device.authenticate_user(USER_PASSWORD));      assert_cmd_err!(CommandError::SlotNotProgrammed, user.get_totp_slot_name(1)); -    let mut device = user.device();      let pws = unwrap_ok!(device.get_password_safe(USER_PASSWORD));      assert_utf8_err_or_ne("test", pws.get_slot_name(0));      assert_utf8_err_or_ne("testlogin", pws.get_slot_login(0)); @@ -327,7 +324,7 @@ fn build_aes_key(device: DeviceWrapper) {      );      assert_ok!((), device.build_aes_key(ADMIN_PASSWORD)); -    let mut device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); +    assert_any_ok!(device.authenticate_admin(ADMIN_PASSWORD));      let pws = unwrap_ok!(device.get_password_safe(USER_PASSWORD));      assert_utf8_err_or_ne("test", pws.get_slot_name(0)); diff --git a/tests/otp.rs b/tests/otp.rs index 28a8d7c..8ca8311 100644 --- a/tests/otp.rs +++ b/tests/otp.rs @@ -3,7 +3,6 @@  mod util; -use std::fmt::Debug;  use std::ops::DerefMut;  use nitrokey::{ @@ -38,14 +37,11 @@ enum TotpTimestampSize {      U64,  } -fn make_admin_test_device<T>(device: T) -> Admin<T> +fn make_admin_test_device<'a, T>(device: &'a mut T) -> Admin<'a, T>  where      T: Device, -    (T, nitrokey::Error): Debug,  { -    device -        .authenticate_admin(ADMIN_PASSWORD) -        .expect("Could not login as admin.") +    unwrap_ok!(device.authenticate_admin(ADMIN_PASSWORD))  }  fn configure_hotp(admin: &mut ConfigureOtp, counter: u8) { @@ -72,7 +68,8 @@ fn set_time(device: DeviceWrapper) {  #[test_device]  fn hotp_no_pin(device: DeviceWrapper) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let config = Config::new(None, None, None, false);      assert_ok!((), admin.write_config(config)); @@ -83,36 +80,38 @@ fn hotp_no_pin(device: DeviceWrapper) {      check_hotp_codes(admin.deref_mut(), 5);      configure_hotp(&mut admin, 0); -    check_hotp_codes(&mut admin.device(), 0); +    check_hotp_codes(&mut device, 0);  }  #[test_device]  fn hotp_pin(device: DeviceWrapper) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let config = Config::new(None, None, None, true);      assert_ok!((), admin.write_config(config));      configure_hotp(&mut admin, 0); -    let mut user = unwrap_ok!(admin.device().authenticate_user(USER_PASSWORD)); +    let mut user = unwrap_ok!(device.authenticate_user(USER_PASSWORD));      check_hotp_codes(&mut user, 0); -    assert_cmd_err!(CommandError::NotAuthorized, user.device().get_hotp_code(1)); +    assert_cmd_err!(CommandError::NotAuthorized, user.get_hotp_code(1));  }  #[test_device]  fn hotp_slot_name(device: DeviceWrapper) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let slot_data = OtpSlotData::new(1, "test-hotp", HOTP_SECRET, OtpMode::SixDigits);      assert_ok!((), admin.write_hotp_slot(slot_data, 0)); -    let device = admin.device();      assert_ok!("test-hotp".to_string(), device.get_hotp_slot_name(1));      assert_lib_err!(LibraryError::InvalidSlot, device.get_hotp_slot_name(4));  }  #[test_device]  fn hotp_error(device: DeviceWrapper) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let slot_data = OtpSlotData::new(1, "", HOTP_SECRET, OtpMode::SixDigits);      assert_cmd_err!(CommandError::NoName, admin.write_hotp_slot(slot_data, 0));      let slot_data = OtpSlotData::new(4, "test", HOTP_SECRET, OtpMode::SixDigits); @@ -131,7 +130,8 @@ fn hotp_error(device: DeviceWrapper) {  #[test_device]  fn hotp_erase(device: DeviceWrapper) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let config = Config::new(None, None, None, false);      assert_ok!((), admin.write_config(config));      let slot_data = OtpSlotData::new(1, "test1", HOTP_SECRET, OtpMode::SixDigits); @@ -141,7 +141,6 @@ fn hotp_erase(device: DeviceWrapper) {      assert_ok!((), admin.erase_hotp_slot(1)); -    let mut device = admin.device();      let result = device.get_hotp_slot_name(1);      assert_cmd_err!(CommandError::SlotNotProgrammed, result);      let result = device.get_hotp_code(1); @@ -178,7 +177,8 @@ fn check_totp_codes(device: &mut GenerateOtp, factor: u64, timestamp_size: TotpT  #[test_device]  fn totp_no_pin(device: DeviceWrapper) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let config = Config::new(None, None, None, false);      assert_ok!((), admin.write_config(config)); @@ -189,14 +189,15 @@ fn totp_no_pin(device: DeviceWrapper) {      check_totp_codes(admin.deref_mut(), 2, TotpTimestampSize::U32);      configure_totp(&mut admin, 1); -    check_totp_codes(&mut admin.device(), 1, TotpTimestampSize::U32); +    check_totp_codes(&mut device, 1, TotpTimestampSize::U32);  }  #[test_device]  // Nitrokey Storage does only support timestamps that fit in a 32-bit  // unsigned integer, so don't test with it.  fn totp_no_pin_64(device: Pro) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let config = Config::new(None, None, None, false);      assert_ok!((), admin.write_config(config)); @@ -207,43 +208,45 @@ fn totp_no_pin_64(device: Pro) {      check_totp_codes(admin.deref_mut(), 2, TotpTimestampSize::U64);      configure_totp(&mut admin, 1); -    check_totp_codes(&mut admin.device(), 1, TotpTimestampSize::U64); +    check_totp_codes(&mut device, 1, TotpTimestampSize::U64);  }  #[test_device]  fn totp_pin(device: DeviceWrapper) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let config = Config::new(None, None, None, true);      assert_ok!((), admin.write_config(config));      configure_totp(&mut admin, 1); -    let mut user = unwrap_ok!(admin.device().authenticate_user(USER_PASSWORD)); +    let mut user = unwrap_ok!(device.authenticate_user(USER_PASSWORD));      check_totp_codes(&mut user, 1, TotpTimestampSize::U32); -    assert_cmd_err!(CommandError::NotAuthorized, user.device().get_totp_code(1)); +    assert_cmd_err!(CommandError::NotAuthorized, user.get_totp_code(1));  }  #[test_device]  // See comment for totp_no_pin_64.  fn totp_pin_64(device: Pro) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let config = Config::new(None, None, None, true);      assert_ok!((), admin.write_config(config));      configure_totp(&mut admin, 1); -    let mut user = unwrap_ok!(admin.device().authenticate_user(USER_PASSWORD)); +    let mut user = unwrap_ok!(admin.authenticate_user(USER_PASSWORD));      check_totp_codes(&mut user, 1, TotpTimestampSize::U64); -    assert_cmd_err!(CommandError::NotAuthorized, user.device().get_totp_code(1)); +    assert_cmd_err!(CommandError::NotAuthorized, device.get_totp_code(1));  }  #[test_device]  fn totp_slot_name(device: DeviceWrapper) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let slot_data = OtpSlotData::new(1, "test-totp", TOTP_SECRET, OtpMode::EightDigits);      assert_ok!((), admin.write_totp_slot(slot_data, 0)); -    let device = admin.device();      let result = device.get_totp_slot_name(1);      assert_ok!("test-totp", result);      let result = device.get_totp_slot_name(16); @@ -252,7 +255,8 @@ fn totp_slot_name(device: DeviceWrapper) {  #[test_device]  fn totp_error(device: DeviceWrapper) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let slot_data = OtpSlotData::new(1, "", TOTP_SECRET, OtpMode::SixDigits);      assert_cmd_err!(CommandError::NoName, admin.write_totp_slot(slot_data, 0));      let slot_data = OtpSlotData::new(20, "test", TOTP_SECRET, OtpMode::SixDigits); @@ -271,7 +275,8 @@ fn totp_error(device: DeviceWrapper) {  #[test_device]  fn totp_erase(device: DeviceWrapper) { -    let mut admin = make_admin_test_device(device); +    let mut device = device; +    let mut admin = make_admin_test_device(&mut device);      let config = Config::new(None, None, None, false);      assert_ok!((), admin.write_config(config));      let slot_data = OtpSlotData::new(1, "test1", TOTP_SECRET, OtpMode::SixDigits); @@ -281,7 +286,6 @@ fn totp_erase(device: DeviceWrapper) {      assert_ok!((), admin.erase_totp_slot(1)); -    let device = admin.device();      let result = device.get_totp_slot_name(1);      assert_cmd_err!(CommandError::SlotNotProgrammed, result);      let result = device.get_totp_code(1); diff --git a/tests/util/mod.rs b/tests/util/mod.rs index bd207a9..f80372d 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -8,7 +8,7 @@ pub static USER_PASSWORD: &str = "123456";  #[macro_export]  macro_rules! unwrap_ok { -    ($val:expr) => {{ +    ($val:expr) => {          match $val {              Ok(val) => val,              Err(err) => panic!( @@ -18,12 +18,12 @@ macro_rules! unwrap_ok {                  err              ),          } -    }}; +    };  }  #[macro_export]  macro_rules! assert_any_ok { -    ($val:expr) => {{ +    ($val:expr) => {          match &$val {              Ok(_) => {}              Err(err) => panic!( @@ -33,12 +33,12 @@ macro_rules! assert_any_ok {                  err              ),          } -    }}; +    };  }  #[macro_export]  macro_rules! assert_ok { -    ($left:expr, $right:expr) => {{ +    ($left:expr, $right:expr) => {          match &$right {              Ok(right) => match &$left {                  left => { @@ -59,7 +59,7 @@ macro_rules! assert_ok {                  $left, right_err              ),          } -    }}; +    };  }  #[macro_export] | 
