diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/device.rs | 41 | ||||
| -rw-r--r-- | src/tests/device.rs | 39 | 
2 files changed, 80 insertions, 0 deletions
| diff --git a/src/device.rs b/src/device.rs index 73952cc..d6b9780 100644 --- a/src/device.rs +++ b/src/device.rs @@ -367,6 +367,47 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {              ))          }      } + +    /// Unlocks the user PIN after three failed login attempts and sets it to the given value. +    /// +    /// # Errors +    /// +    /// - [`InvalidString`][] if one of the provided passwords contains a null byte +    /// - [`WrongPassword`][] if the admin password is wrong +    /// +    /// # Example +    /// +    /// ```no_run +    /// use nitrokey::{CommandStatus, Device}; +    /// # use nitrokey::CommandError; +    /// +    /// # fn try_main() -> Result<(), CommandError> { +    /// let device = nitrokey::connect()?; +    /// match device.unlock_user_pin("12345678", "123456") { +    ///     CommandStatus::Success => println!("Unlocked user PIN."), +    ///     CommandStatus::Error(err) => println!("Failed to unlock user PIN: {:?}", err), +    /// }; +    /// #     Ok(()) +    /// # } +    /// ``` +    /// +    /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString +    /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword +    fn unlock_user_pin(&self, admin_pin: &str, user_pin: &str) -> CommandStatus { +        let admin_pin_string = CString::new(admin_pin); +        let user_pin_string = CString::new(user_pin); +        if admin_pin_string.is_err() || user_pin_string.is_err() { +            return CommandStatus::Error(CommandError::InvalidString); +        } +        let admin_pin_string = admin_pin_string.unwrap(); +        let user_pin_string = user_pin_string.unwrap(); +        unsafe { +            CommandStatus::from(nitrokey_sys::NK_unlock_user_password( +                admin_pin_string.as_ptr(), +                user_pin_string.as_ptr(), +            )) +        } +    }  }  /// Connects to a Nitrokey device.  This method can be used to connect to any connected device, diff --git a/src/tests/device.rs b/src/tests/device.rs index 6c24025..6f88bf5 100644 --- a/src/tests/device.rs +++ b/src/tests/device.rs @@ -189,3 +189,42 @@ fn change_admin_pin() {      let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device();      device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err();  } + +fn require_failed_user_login(device: Target, password: &str, error: CommandError) -> Target { +    let result = device.authenticate_user(password); +    assert!(result.is_err()); +    let err = result.unwrap_err(); +    assert_eq!(error, err.1); +    err.0 +} + +#[test] +#[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)] +fn unlock_user_pin() { +    let device = Target::connect().unwrap(); +    let device = device.authenticate_user(USER_PASSWORD).unwrap().device(); +    assert_eq!( +        CommandStatus::Success, +        device.unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD) +    ); +    assert_eq!( +        CommandStatus::Error(CommandError::WrongPassword), +        device.unlock_user_pin(USER_PASSWORD, USER_PASSWORD) +    ); + +    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 device = require_failed_user_login(device, USER_PASSWORD, CommandError::WrongPassword); + +    assert_eq!( +        CommandStatus::Error(CommandError::WrongPassword), +        device.unlock_user_pin(USER_PASSWORD, USER_PASSWORD) +    ); +    assert_eq!( +        CommandStatus::Success, +        device.unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD) +    ); +    device.authenticate_user(USER_PASSWORD).unwrap(); +} | 
