~ireas/nitrokey-rs

1ad530bbf10801fe3da393d88bc940f52e8d8746 — Robin Krahl 2 months ago db48656
Replace SLOT_COUNT with get_slot_count

This patch adds the get_slot_count method to the PasswordSafe struct and
deprecates the SLOT_COUNT constant.  That constant was poorly named, and
hardcoding the number of available slots is not future-proof.
4 files changed, 40 insertions(+), 22 deletions(-)

M CHANGELOG.md
M src/lib.rs
M src/pws.rs
M tests/pws.rs
M CHANGELOG.md => CHANGELOG.md +2 -0
@@ 11,6 11,8 @@ SPDX-License-Identifier: CC0-1.0
    data.
  - Deprecate the `get_status`, `get_slot_name`, `get_slot_login` and
    `get_slot_password` method of the `PasswordSafe` struct.
- Add the `PasswordSafe::get_slot_count` method to access the number of slots
  in the password safe and deprecate the `SLOT_COUNT` constant.

# v0.8.0 (2020-09-29)
- Export the `FirmwareVersion` struct.

M src/lib.rs => src/lib.rs +10 -1
@@ 143,11 143,20 @@ pub use crate::device::{
};
pub use crate::error::{CommandError, CommunicationError, Error, LibraryError};
pub use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData};
pub use crate::pws::{GetPasswordSafe, PasswordSafe, PasswordSlot, SLOT_COUNT};
pub use crate::pws::{GetPasswordSafe, PasswordSafe, PasswordSlot};
pub use crate::util::LogLevel;

use crate::util::{get_cstring, get_last_result};

/// The number of slots in a [`PasswordSafe`][].
///
/// This constant is deprecated.  Use [`PasswordSafe::get_slot_count`][] instead.
///
/// [`PasswordSafe`]: struct.PasswordSafe.html
/// [`PasswordSafe::get_slot_count`]: struct.PasswordSafe.html#method.get_slot_count
#[deprecated(since = "0.9.0", note = "Use PasswordSafe::get_slot_count instead")]
pub const SLOT_COUNT: u8 = 16;

/// The default admin PIN for all Nitrokey devices.
pub const DEFAULT_ADMIN_PIN: &str = "12345678";
/// The default user PIN for all Nitrokey devices.

M src/pws.rs => src/pws.rs +14 -12
@@ 5,18 5,15 @@ use crate::device::{Device, DeviceWrapper, Librem, Pro, Storage};
use crate::error::{CommandError, Error, LibraryError};
use crate::util::{get_command_result, get_cstring, get_last_error, result_from_string};

/// The number of slots in a [`PasswordSafe`][].
///
/// [`PasswordSafe`]: struct.PasswordSafe.html
pub const SLOT_COUNT: u8 = 16;
const SLOT_COUNT: u8 = 16;

/// A password safe on a Nitrokey device.
///
/// The password safe stores a tuple consisting of a name, a login and a password on a slot.  The
/// number of available slots is [`SLOT_COUNT`][].  The slots are addressed starting with zero.  To
/// retrieve a password safe from a Nitrokey device, use the [`get_password_safe`][] method from
/// the [`GetPasswordSafe`][] trait.  Note that the device must live at least as long as the
/// password safe.
/// The password safe stores a tuple consisting of a name, a login and a password on a slot.  Use
/// [`get_slot_count`][] to access the number of available slots.  The slots are addressed starting
/// with zero.  To retrieve a password safe from a Nitrokey device, use the [`get_password_safe`][]
/// method from the [`GetPasswordSafe`][] trait.  Note that the device must live at least as long
/// as the password safe.
///
/// Once the password safe has been unlocked, it can be accessed without a password.  Therefore it
/// is mandatory to call [`lock`][] on the corresponding device after the password store is used.


@@ 50,7 47,7 @@ pub const SLOT_COUNT: u8 = 16;
/// # }
/// ```
///
/// [`SLOT_COUNT`]: constant.SLOT_COUNT.html
/// [`get_slot_count`]: #method.get_slot_count
/// [`get_password_safe`]: trait.GetPasswordSafe.html#method.get_password_safe
/// [`lock`]: trait.Device.html#method.lock
/// [`GetPasswordSafe`]: trait.GetPasswordSafe.html


@@ 146,6 143,11 @@ fn get_pws_result(s: String) -> Result<String, Error> {
}

impl<'a, 'b> PasswordSafe<'a, 'b> {
    /// Returns the number of slots in this password safe.
    pub fn get_slot_count(&self) -> u8 {
        SLOT_COUNT
    }

    /// Returns the status of all password slots.
    ///
    /// The status indicates whether a slot is programmed or not.


@@ 175,7 177,7 @@ impl<'a, 'b> PasswordSafe<'a, 'b> {
    ///
    /// [`get_slots`]: #method.get_slots
    #[deprecated(since = "0.9.0", note = "Use get_slots() instead")]
    pub fn get_slot_status(&self) -> Result<[bool; SLOT_COUNT as usize], Error> {
    pub fn get_slot_status(&self) -> Result<[bool; 16], Error> {
        let status_ptr = unsafe { nitrokey_sys::NK_get_password_safe_slot_status() };
        if status_ptr.is_null() {
            return Err(get_last_error());


@@ 314,7 316,7 @@ impl<'a, 'b> PasswordSafe<'a, 'b> {
    /// [`get_slot`]: #method.get_slot
    /// [`get_slots`]: #method.get_slots
    pub fn get_slot_unchecked(&self, slot: u8) -> Result<PasswordSlot<'_, 'a, 'b>, Error> {
        if slot < SLOT_COUNT {
        if slot < self.get_slot_count() {
            Ok(PasswordSlot { slot, _pws: self })
        } else {
            Err(LibraryError::InvalidSlot.into())

M tests/pws.rs => tests/pws.rs +14 -9
@@ 8,7 8,7 @@ use std::ffi::CStr;
use libc::{c_int, c_void, free};
use nitrokey::{
    CommandError, Device, Error, GetPasswordSafe, LibraryError, PasswordSafe, PasswordSlot,
    DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN, SLOT_COUNT,
    DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN,
};
use nitrokey_sys;
use nitrokey_test::test as test_device;


@@ 84,10 84,11 @@ fn get_status(device: DeviceWrapper) {

    let mut device = device;
    let mut pws = get_pws(&mut device);
    for i in 0..SLOT_COUNT {
    let slot_count = pws.get_slot_count();
    for i in 0..slot_count {
        assert_ok!((), pws.erase_slot(i));
    }
    assert_eq!(vec![None; SLOT_COUNT as usize], get_pws_status(&pws));
    assert_eq!(vec![None; slot_count.into()], get_pws_status(&pws));

    assert_ok!((), pws.write_slot(1, "name", "login", "password"));
    for (i, slot) in get_pws_status(&pws).into_iter().enumerate() {


@@ 98,11 99,11 @@ fn get_status(device: DeviceWrapper) {
        }
    }

    for i in 0..SLOT_COUNT {
    for i in 0..slot_count {
        assert_ok!((), pws.write_slot(i, "name", "login", "password"));
    }
    assert_eq!(
        (0..SLOT_COUNT).map(Some).collect::<Vec<_>>(),
        (0..slot_count).map(Some).collect::<Vec<_>>(),
        get_pws_status(&pws)
    );
}


@@ 139,10 140,11 @@ fn get_data(device: DeviceWrapper) {
    assert_ok!(password.to_string(), slot.get_password());
    drop(slot);

    assert_lib_err!(LibraryError::InvalidSlot, pws.get_slot(SLOT_COUNT));
    let slot_count = pws.get_slot_count();
    assert_lib_err!(LibraryError::InvalidSlot, pws.get_slot(slot_count));
    assert_lib_err!(
        LibraryError::InvalidSlot,
        pws.get_slot_unchecked(SLOT_COUNT)
        pws.get_slot_unchecked(slot_count)
    );
}



@@ 153,7 155,7 @@ fn write(device: DeviceWrapper) {

    assert_lib_err!(
        LibraryError::InvalidSlot,
        pws.write_slot(SLOT_COUNT, "name", "login", "password")
        pws.write_slot(pws.get_slot_count(), "name", "login", "password")
    );

    assert_ok!((), pws.write_slot(0, "", "login", "password"));


@@ 182,7 184,10 @@ fn write(device: DeviceWrapper) {
fn erase(device: DeviceWrapper) {
    let mut device = device;
    let mut pws = get_pws(&mut device);
    assert_lib_err!(LibraryError::InvalidSlot, pws.erase_slot(SLOT_COUNT));
    assert_lib_err!(
        LibraryError::InvalidSlot,
        pws.erase_slot(pws.get_slot_count())
    );

    assert_ok!((), pws.write_slot(0, "name", "login", "password"));
    assert_ok!((), pws.erase_slot(0));