~ireas/nitrokey-rs

62e8ee8f5d02511d6eb5dc179b087b04e88c1b94 — Robin Krahl 2 years ago 0ac9c40
Update documentation for Manager refactoring

This patch updates the documentation to reflect the latest changes to
connection handling.  It also updates the doc tests to prefer the new
methods over the old ones.
5 files changed, 178 insertions(+), 80 deletions(-)

M src/auth.rs
M src/device.rs
M src/lib.rs
M src/otp.rs
M src/pws.rs
M src/auth.rs => src/auth.rs +8 -5
@@ 39,11 39,12 @@ pub trait Authenticate<'a> {
    /// use nitrokey::{Authenticate, DeviceWrapper, User};
    /// # use nitrokey::Error;
    ///
    /// fn perform_user_task(device: &User<DeviceWrapper>) {}
    /// fn perform_user_task<'a>(device: &User<'a, DeviceWrapper<'a>>) {}
    /// fn perform_other_task(device: &DeviceWrapper) {}
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// let device = match device.authenticate_user("123456") {
    ///     Ok(user) => {
    ///         perform_user_task(&user);


@@ 85,11 86,12 @@ pub trait Authenticate<'a> {
    /// use nitrokey::{Authenticate, Admin, DeviceWrapper};
    /// # use nitrokey::Error;
    ///
    /// fn perform_admin_task(device: &Admin<DeviceWrapper>) {}
    /// fn perform_admin_task<'a>(device: &Admin<'a, DeviceWrapper<'a>>) {}
    /// fn perform_other_task(device: &DeviceWrapper) {}
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// let device = match device.authenticate_admin("123456") {
    ///     Ok(admin) => {
    ///         perform_admin_task(&admin);


@@ 291,7 293,8 @@ impl<'a, T: Device<'a>> Admin<'a, T> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// let config = Config::new(None, None, None, false);
    /// match device.authenticate_admin("12345678") {
    ///     Ok(mut admin) => {

M src/device.rs => src/device.rs +72 -45
@@ 53,7 53,7 @@ impl fmt::Display for VolumeMode {

/// A wrapper for a Nitrokey device of unknown type.
///
/// Use the function [`connect`][] to obtain a wrapped instance.  The wrapper implements all traits
/// Use the [`connect`][] method to obtain a wrapped instance.  The wrapper implements all traits
/// that are shared between all Nitrokey devices so that the shared functionality can be used
/// without knowing the type of the underlying device.  If you want to use functionality that is
/// not available for all devices, you have to extract the device.


@@ 66,11 66,12 @@ impl fmt::Display for VolumeMode {
/// use nitrokey::{Authenticate, DeviceWrapper, User};
/// # use nitrokey::Error;
///
/// fn perform_user_task(device: &User<DeviceWrapper>) {}
/// fn perform_user_task<'a>(device: &User<'a, DeviceWrapper<'a>>) {}
/// fn perform_other_task(device: &DeviceWrapper) {}
///
/// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let mut manager = nitrokey::take()?;
/// let device = manager.connect()?;
/// let device = match device.authenticate_user("123456") {
///     Ok(user) => {
///         perform_user_task(&user);


@@ 96,7 97,8 @@ impl fmt::Display for VolumeMode {
/// fn perform_storage_task(device: &Storage) {}
///
/// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::connect()?;
/// let mut manager = nitrokey::take()?;
/// let device = manager.connect()?;
/// perform_common_task(&device);
/// match device {
///     DeviceWrapper::Storage(storage) => perform_storage_task(&storage),


@@ 106,7 108,7 @@ impl fmt::Display for VolumeMode {
/// # }
/// ```
///
/// [`connect`]: fn.connect.html
/// [`connect`]: struct.Manager.html#method.connect
#[derive(Debug)]
pub enum DeviceWrapper<'a> {
    /// A Nitrokey Storage device.


@@ 117,10 119,9 @@ pub enum DeviceWrapper<'a> {

/// A Nitrokey Pro device without user or admin authentication.
///
/// Use the global function [`connect`][] to obtain an instance wrapper or the method
/// [`connect`][`Pro::connect`] to directly obtain an instance.  If you want to execute a command
/// that requires user or admin authentication, use [`authenticate_admin`][] or
/// [`authenticate_user`][].
/// Use the [`connect`][] method to obtain an instance wrapper or the [`connect_pro`] method to
/// directly obtain an instance.  If you want to execute a command that requires user or admin
/// authentication, use [`authenticate_admin`][] or [`authenticate_user`][].
///
/// # Examples
///


@@ 130,11 131,12 @@ pub enum DeviceWrapper<'a> {
/// use nitrokey::{Authenticate, User, Pro};
/// # use nitrokey::Error;
///
/// fn perform_user_task(device: &User<Pro>) {}
/// fn perform_user_task<'a>(device: &User<'a, Pro<'a>>) {}
/// fn perform_other_task(device: &Pro) {}
///
/// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Pro::connect()?;
/// let mut manager = nitrokey::take()?;
/// let device = manager.connect_pro()?;
/// let device = match device.authenticate_user("123456") {
///     Ok(user) => {
///         perform_user_task(&user);


@@ 152,8 154,8 @@ pub enum DeviceWrapper<'a> {
///
/// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin
/// [`authenticate_user`]: trait.Authenticate.html#method.authenticate_user
/// [`connect`]: fn.connect.html
/// [`Pro::connect`]: #method.connect
/// [`connect`]: struct.Manager.html#method.connect
/// [`connect_pro`]: struct.Manager.html#method.connect_pro
#[derive(Debug)]
pub struct Pro<'a> {
    manager: Option<&'a mut crate::Manager>,


@@ 161,10 163,9 @@ pub struct Pro<'a> {

/// A Nitrokey Storage device without user or admin authentication.
///
/// Use the global function [`connect`][] to obtain an instance wrapper or the method
/// [`connect`][`Storage::connect`] to directly obtain an instance.  If you want to execute a
/// command that requires user or admin authentication, use [`authenticate_admin`][] or
/// [`authenticate_user`][].
/// Use the [`connect`][] method to obtain an instance wrapper or the [`connect_storage`] method to
/// directly obtain an instance.  If you want to execute a command that requires user or admin
/// authentication, use [`authenticate_admin`][] or [`authenticate_user`][].
///
/// # Examples
///


@@ 174,11 175,12 @@ pub struct Pro<'a> {
/// use nitrokey::{Authenticate, User, Storage};
/// # use nitrokey::Error;
///
/// fn perform_user_task(device: &User<Storage>) {}
/// fn perform_user_task<'a>(device: &User<'a, Storage<'a>>) {}
/// fn perform_other_task(device: &Storage) {}
///
/// # fn try_main() -> Result<(), Error> {
/// let device = nitrokey::Storage::connect()?;
/// let mut manager = nitrokey::take()?;
/// let device = manager.connect_storage()?;
/// let device = match device.authenticate_user("123456") {
///     Ok(user) => {
///         perform_user_task(&user);


@@ 196,8 198,8 @@ pub struct Pro<'a> {
///
/// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin
/// [`authenticate_user`]: trait.Authenticate.html#method.authenticate_user
/// [`connect`]: fn.connect.html
/// [`Storage::connect`]: #method.connect
/// [`connect`]: struct.Manager.html#method.connect
/// [`connect_storage`]: struct.Manager.html#method.connect_storage
#[derive(Debug)]
pub struct Storage<'a> {
    manager: Option<&'a mut crate::Manager>,


@@ 326,7 328,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// println!("Connected to a Nitrokey {}", device.get_model());
    /// #    Ok(())
    /// # }


@@ 342,7 345,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// match device.get_serial_number() {
    ///     Ok(number) => println!("serial no: {}", number),
    ///     Err(err) => eprintln!("Could not get serial number: {}", err),


@@ 364,7 368,9 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// let count = device.get_user_retry_count();
    /// match device.get_user_retry_count() {
    ///     Ok(count) => println!("{} remaining authentication attempts (user)", count),
    ///     Err(err) => eprintln!("Could not get user retry count: {}", err),


@@ 386,7 392,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// let count = device.get_admin_retry_count();
    /// match device.get_admin_retry_count() {
    ///     Ok(count) => println!("{} remaining authentication attempts (admin)", count),


@@ 408,7 415,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// match device.get_firmware_version() {
    ///     Ok(version) => println!("Firmware version: {}", version),
    ///     Err(err) => eprintln!("Could not access firmware version: {}", err),


@@ 431,7 439,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// let config = device.get_config()?;
    /// println!("numlock binding:          {:?}", config.numlock);
    /// println!("capslock binding:         {:?}", config.capslock);


@@ 465,7 474,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// match device.change_admin_pin("12345678", "12345679") {
    ///     Ok(()) => println!("Updated admin PIN."),
    ///     Err(err) => eprintln!("Failed to update admin PIN: {}", err),


@@ 498,7 508,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// match device.change_user_pin("123456", "123457") {
    ///     Ok(()) => println!("Updated admin PIN."),
    ///     Err(err) => eprintln!("Failed to update admin PIN: {}", err),


@@ 531,7 542,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// match device.unlock_user_pin("12345678", "123456") {
    ///     Ok(()) => println!("Unlocked user PIN."),
    ///     Err(err) => eprintln!("Failed to unlock user PIN: {}", err),


@@ 565,7 577,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// match device.lock() {
    ///     Ok(()) => println!("Locked the Nitrokey device."),
    ///     Err(err) => eprintln!("Could not lock the Nitrokey device: {}", err),


@@ 596,7 609,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// match device.factory_reset("12345678") {
    ///     Ok(()) => println!("Performed a factory reset."),
    ///     Err(err) => eprintln!("Could not perform a factory reset: {}", err),


@@ 630,7 644,8 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// match device.build_aes_key("12345678") {
    ///     Ok(()) => println!("New AES keys have been built."),
    ///     Err(err) => eprintln!("Could not build new AES keys: {}", err),


@@ 795,7 810,8 @@ impl<'a> Storage<'a> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect_storage()?;
    /// match device.change_update_pin("12345678", "87654321") {
    ///     Ok(()) => println!("Updated update PIN."),
    ///     Err(err) => eprintln!("Failed to update update PIN: {}", err),


@@ 832,7 848,8 @@ impl<'a> Storage<'a> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect_storage()?;
    /// match device.enable_firmware_update("12345678") {
    ///     Ok(()) => println!("Nitrokey entered update mode."),
    ///     Err(err) => eprintln!("Could not enter update mode: {}", err),


@@ 866,7 883,8 @@ impl<'a> Storage<'a> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect_storage()?;
    /// match device.enable_encrypted_volume("123456") {
    ///     Ok(()) => println!("Enabled the encrypted volume."),
    ///     Err(err) => eprintln!("Could not enable the encrypted volume: {}", err),


@@ 895,7 913,8 @@ impl<'a> Storage<'a> {
    /// fn use_volume() {}
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect_storage()?;
    /// match device.enable_encrypted_volume("123456") {
    ///     Ok(()) => {
    ///         println!("Enabled the encrypted volume.");


@@ 941,7 960,8 @@ impl<'a> Storage<'a> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect_storage()?;
    /// device.enable_encrypted_volume("123445")?;
    /// match device.enable_hidden_volume("hidden-pw") {
    ///     Ok(()) => println!("Enabled a hidden volume."),


@@ 974,7 994,8 @@ impl<'a> Storage<'a> {
    /// fn use_volume() {}
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect_storage()?;
    /// device.enable_encrypted_volume("123445")?;
    /// match device.enable_hidden_volume("hidden-pw") {
    ///     Ok(()) => {


@@ 1021,7 1042,8 @@ impl<'a> Storage<'a> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect_storage()?;
    /// device.enable_encrypted_volume("123445")?;
    /// device.create_hidden_volume(0, 0, 100, "hidden-pw")?;
    /// #     Ok(())


@@ 1061,7 1083,8 @@ impl<'a> Storage<'a> {
    /// use nitrokey::VolumeMode;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect_storage()?;
    /// match device.set_unencrypted_volume_mode("12345678", VolumeMode::ReadWrite) {
    ///     Ok(()) => println!("Set the unencrypted volume to read-write mode."),
    ///     Err(err) => eprintln!("Could not set the unencrypted volume to read-write mode: {}", err),


@@ 1106,7 1129,8 @@ impl<'a> Storage<'a> {
    /// use nitrokey::VolumeMode;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect_storage()?;
    /// match device.set_encrypted_volume_mode("12345678", VolumeMode::ReadWrite) {
    ///     Ok(()) => println!("Set the encrypted volume to read-write mode."),
    ///     Err(err) => eprintln!("Could not set the encrypted volume to read-write mode: {}", err),


@@ 1144,7 1168,8 @@ impl<'a> Storage<'a> {
    /// fn use_volume() {}
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect_storage()?;
    /// match device.get_status() {
    ///     Ok(status) => {
    ///         println!("SD card ID: {:#x}", status.serial_number_sd_card);


@@ 1187,7 1212,8 @@ impl<'a> Storage<'a> {
    /// fn use_volume() {}
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect_storage()?;
    /// match device.get_production_info() {
    ///     Ok(data) => {
    ///         println!("SD card ID:   {:#x}", data.sd_card.serial_number);


@@ 1235,7 1261,8 @@ impl<'a> Storage<'a> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::Storage::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect_storage()?;
    /// match device.clear_new_sd_card_warning("12345678") {
    ///     Ok(()) => println!("Cleared the new SD card warning."),
    ///     Err(err) => eprintln!("Could not set the clear the new SD card warning: {}", err),

M src/lib.rs => src/lib.rs +64 -13
@@ 9,13 9,16 @@
//! performed without authentication, some require user access, and some require admin access.
//! This is modelled using the types [`User`][] and [`Admin`][].
//!
//! Use [`connect`][] to connect to any Nitrokey device.  The method will return a
//! You can only connect to one Nitrokey at a time.  Use the global [`take`][] function to obtain
//! an reference to the [`Manager`][] singleton that keeps track of the connections.  Then use the
//! [`connect`][] method to connect to any Nitrokey device.  The method will return a
//! [`DeviceWrapper`][] that abstracts over the supported Nitrokey devices.  You can also use
//! [`Pro::connect`][] or [`Storage::connect`][] to connect to a specific device.
//! [`connect_model`][], [`connect_pro`][] or [`connect_storage`][] to connect to a specific
//! device.
//!
//! You can then use [`authenticate_user`][] or [`authenticate_admin`][] to get an authenticated
//! device that can perform operations that require authentication.  You can use [`device`][] to go
//! back to the unauthenticated device.
//! You can call [`authenticate_user`][] or [`authenticate_admin`][] to get an authenticated device
//! that can perform operations that require authentication.  You can use [`device`][] to go back
//! to the unauthenticated device.
//!
//! This makes sure that you can only execute a command if you have the required access rights.
//! Otherwise, your code will not compile.  The only exception are the methods to generate one-time


@@ 31,7 34,8 @@
//! # use nitrokey::Error;
//!
//! # fn try_main() -> Result<(), Error> {
//! let device = nitrokey::connect()?;
//! let mut manager = nitrokey::take()?;
//! let device = manager.connect()?;
//! println!("{}", device.get_serial_number()?);
//! #     Ok(())
//! # }


@@ 44,7 48,8 @@
//! # use nitrokey::Error;
//!
//! # fn try_main() -> Result<(), Error> {
//! let device = nitrokey::connect()?;
//! let mut manager = nitrokey::take()?;
//! let device = manager.connect()?;
//! let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits);
//! match device.authenticate_admin("12345678") {
//!     Ok(mut admin) => {


@@ 66,7 71,8 @@
//! # use nitrokey::Error;
//!
//! # fn try_main() -> Result<(), Error> {
//! let mut device = nitrokey::connect()?;
//! let mut manager = nitrokey::take()?;
//! let mut device = manager.connect()?;
//! match device.get_hotp_code(1) {
//!     Ok(code) => println!("Generated HOTP code: {}", code),
//!     Err(err) => eprintln!("Could not generate HOTP code: {}", err),


@@ 77,9 83,12 @@
//!
//! [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin
//! [`authenticate_user`]: trait.Authenticate.html#method.authenticate_user
//! [`connect`]: fn.connect.html
//! [`Pro::connect`]: struct.Pro.html#fn.connect.html
//! [`Storage::connect`]: struct.Storage.html#fn.connect.html
//! [`take`]: fn.take.html
//! [`connect`]: struct.Manager.html#method.connect
//! [`connect_model`]: struct.Manager.html#method.connect_model
//! [`connect_pro`]: struct.Manager.html#method.connect_pro
//! [`connect_storage`]: struct.Manager.html#method.connect_storage
//! [`manager`]: trait.Device.html#method.manager
//! [`device`]: struct.User.html#method.device
//! [`get_hotp_code`]: trait.GenerateOtp.html#method.get_hotp_code
//! [`get_totp_code`]: trait.GenerateOtp.html#method.get_totp_code


@@ 163,9 172,50 @@ impl fmt::Display for Version {
/// manager struct makes sure that `nitrokey-rs` does not try to connect to two devices at the same
/// time.
///
/// To obtain an instance of this manager, use the [`take`][] function.
/// To obtain a reference to an instance of this manager, use the [`take`][] function.  Use one of
/// the connect methods – [`connect`][], [`connect_model`][], [`connect_pro`][] or
/// [`connect_storage`][] – to retrieve a [`Device`][] instance.
///
/// # Examples
///
/// Connect to a single device:
///
/// ```no_run
/// use nitrokey::Device;
/// # use nitrokey::Error;
///
/// # fn try_main() -> Result<(), Error> {
/// let mut manager = nitrokey::take()?;
/// let device = manager.connect()?;
/// println!("{}", device.get_serial_number()?);
/// #     Ok(())
/// # }
/// ```
///
/// Connect to a Pro and a Storage device:
///
/// ```no_run
/// use nitrokey::{Device, Model};
/// # use nitrokey::Error;
///
/// # fn try_main() -> Result<(), Error> {
/// let mut manager = nitrokey::take()?;
/// let device = manager.connect_model(Model::Pro)?;
/// println!("Pro: {}", device.get_serial_number()?);
/// drop(device);
/// let device = manager.connect_model(Model::Storage)?;
/// println!("Storage: {}", device.get_serial_number()?);
/// #     Ok(())
/// # }
/// ```
///
/// [`connect`]: #method.connect
/// [`connect_model`]: #method.connect_model
/// [`connect_pro`]: #method.connect_pro
/// [`connect_storage`]: #method.connect_storage
/// [`manager`]: trait.Device.html#method.manager
/// [`take`]: fn.take.html
/// [`Device`]: trait.Device.html
#[derive(Debug)]
pub struct Manager {
    marker: marker::PhantomData<()>,


@@ 195,7 245,8 @@ impl Manager {
    /// fn do_something(device: DeviceWrapper) {}
    ///
    /// # fn main() -> Result<(), nitrokey::Error> {
    /// match nitrokey::take()?.connect() {
    /// let mut manager = nitrokey::take()?;
    /// match manager.connect() {
    ///     Ok(device) => do_something(device),
    ///     Err(err) => println!("Could not connect to a Nitrokey: {}", err),
    /// }

M src/otp.rs => src/otp.rs +18 -9
@@ 35,7 35,8 @@ pub trait ConfigureOtp {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits);
    /// match device.authenticate_admin("12345678") {
    ///     Ok(mut admin) => {


@@ 71,7 72,8 @@ pub trait ConfigureOtp {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::EightDigits);
    /// match device.authenticate_admin("12345678") {
    ///     Ok(mut admin) => {


@@ 104,7 106,8 @@ pub trait ConfigureOtp {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// match device.authenticate_admin("12345678") {
    ///     Ok(mut admin) => {
    ///         match admin.erase_hotp_slot(1) {


@@ 134,7 137,8 @@ pub trait ConfigureOtp {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// match device.authenticate_admin("12345678") {
    ///     Ok(mut admin) => {
    ///         match admin.erase_totp_slot(1) {


@@ 171,7 175,8 @@ pub trait GenerateOtp {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH);
    /// match time {
    ///     Ok(time) => device.set_time(time.as_secs(), false)?,


@@ 209,7 214,8 @@ pub trait GenerateOtp {
    /// use nitrokey::{CommandError, Error, GenerateOtp};
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// match device.get_hotp_slot_name(1) {
    ///     Ok(name) => println!("HOTP slot 1: {}", name),
    ///     Err(Error::CommandError(CommandError::SlotNotProgrammed)) => eprintln!("HOTP slot 1 not programmed"),


@@ 238,7 244,8 @@ pub trait GenerateOtp {
    /// use nitrokey::{CommandError, Error, GenerateOtp};
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let device = manager.connect()?;
    /// match device.get_totp_slot_name(1) {
    ///     Ok(name) => println!("TOTP slot 1: {}", name),
    ///     Err(Error::CommandError(CommandError::SlotNotProgrammed)) => eprintln!("TOTP slot 1 not programmed"),


@@ 270,7 277,8 @@ pub trait GenerateOtp {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// let code = device.get_hotp_code(1)?;
    /// println!("Generated HOTP code on slot 1: {}", code);
    /// #     Ok(())


@@ 305,7 313,8 @@ pub trait GenerateOtp {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH);
    /// match time {
    ///     Ok(time) => {

M src/pws.rs => src/pws.rs +16 -8
@@ 43,7 43,8 @@ pub const SLOT_COUNT: u8 = 16;
/// }
///
/// # fn try_main() -> Result<(), Error> {
/// let mut device = nitrokey::connect()?;
/// let mut manager = nitrokey::take()?;
/// let mut device = manager.connect()?;
/// let pws = device.get_password_safe("123456")?;
/// use_password_safe(&pws);
/// drop(pws);


@@ 98,7 99,8 @@ pub trait GetPasswordSafe<'a> {
    /// fn use_password_safe(pws: &PasswordSafe) {}
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// match device.get_password_safe("123456") {
    ///     Ok(pws) => {
    ///         use_password_safe(&pws);


@@ 149,7 151,8 @@ impl<'a, 'b> PasswordSafe<'a, 'b> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// let pws = device.get_password_safe("123456")?;
    /// pws.get_slot_status()?.iter().enumerate().for_each(|(slot, programmed)| {
    ///     let status = match *programmed {


@@ 194,7 197,8 @@ impl<'a, 'b> PasswordSafe<'a, 'b> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// match device.get_password_safe("123456") {
    ///     Ok(pws) => {
    ///         let name = pws.get_slot_name(0)?;


@@ 231,7 235,8 @@ impl<'a, 'b> PasswordSafe<'a, 'b> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// let pws = device.get_password_safe("123456")?;
    /// let name = pws.get_slot_name(0)?;
    /// let login = pws.get_slot_login(0)?;


@@ 264,7 269,8 @@ impl<'a, 'b> PasswordSafe<'a, 'b> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// let pws = device.get_password_safe("123456")?;
    /// let name = pws.get_slot_name(0)?;
    /// let login = pws.get_slot_login(0)?;


@@ 295,7 301,8 @@ impl<'a, 'b> PasswordSafe<'a, 'b> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// let pws = device.get_password_safe("123456")?;
    /// let name = pws.get_slot_name(0)?;
    /// let login = pws.get_slot_login(0)?;


@@ 341,7 348,8 @@ impl<'a, 'b> PasswordSafe<'a, 'b> {
    /// # use nitrokey::Error;
    ///
    /// # fn try_main() -> Result<(), Error> {
    /// let mut device = nitrokey::connect()?;
    /// let mut manager = nitrokey::take()?;
    /// let mut device = manager.connect()?;
    /// let mut pws = device.get_password_safe("123456")?;
    /// match pws.erase_slot(0) {
    ///     Ok(()) => println!("Erased slot 0."),