diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/pws.rs | 189 | ||||
| -rw-r--r-- | src/tests/pws.rs | 44 | 
2 files changed, 75 insertions, 158 deletions
| @@ -12,55 +12,41 @@ pub 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. -/// -/// The password safe struct wraps a device.  To get back to the original device, use the -/// [`device`][] method.  To retrieve a password safe from a Nitrokey device, use the -/// [`get_password_safe`][] method from the [`GetPasswordSafe`][] trait. +/// 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.  ///  /// # Examples  ///  /// Open a password safe and access a password:  ///  /// ```no_run -/// use nitrokey::{Device, GetPasswordSafe}; +/// use nitrokey::GetPasswordSafe;  /// # use nitrokey::CommandError;  /// -/// fn use_device<T: Device>(device: &T) {} -///  /// # fn try_main() -> Result<(), CommandError> {  /// let device = nitrokey::connect()?; -/// let device = match device.get_password_safe("123456") { -///     Ok(pws) => { -///         let name = pws.get_slot_name(0)?; -///         let login = pws.get_slot_login(0)?; -///         let password = pws.get_slot_login(0)?; -///         println!("Credentials for {}: login {}, password {}", name, login, password); -///         pws.device() -///     }, -///     Err((device, err)) => { -///         println!("Could not open the password safe: {:?}", err); -///         device -///     }, -/// }; -/// use_device(&device); +/// let pws = device.get_password_safe("123456")?; +/// let name = pws.get_slot_name(0)?; +/// let login = pws.get_slot_login(0)?; +/// let password = pws.get_slot_login(0)?; +/// println!("Credentials for {}: login {}, password {}", name, login, password);  /// #     Ok(())  /// # }  /// ```  ///  /// [`SLOT_COUNT`]: constant.SLOT_COUNT.html -/// [`device`]: #method.device  /// [`get_password_safe`]: trait.GetPasswordSafe.html#method.get_password_safe  /// [`GetPasswordSafe`]: trait.GetPasswordSafe.html -pub struct PasswordSafe<T: Device> { -    device: T, +pub struct PasswordSafe<'a> { +    _device: &'a Device,  }  /// Provides access to a [`PasswordSafe`][].  /// -/// When retrieving a password safe, the underlying device is consumed.  On success, the returned -/// password safe also containes the device.  On error, the device is returned as part of the -/// error. +/// The device that implements this trait must always live at least as long as a password safe +/// retrieved from it.  ///  /// [`PasswordSafe`]: struct.PasswordSafe.html  pub trait GetPasswordSafe { @@ -76,25 +62,17 @@ pub trait GetPasswordSafe {      /// # Example      ///      /// ```no_run -    /// use nitrokey::{Device, GetPasswordSafe, PasswordSafe}; +    /// use nitrokey::{GetPasswordSafe, PasswordSafe};      /// # use nitrokey::CommandError;      /// -    /// fn use_password_safe<T: Device>(pws: &PasswordSafe<T>) {} -    /// fn use_device<T: Device>(device: &T) {} +    /// fn use_password_safe(pws: &PasswordSafe) {}      ///      /// # fn try_main() -> Result<(), CommandError> {      /// let device = nitrokey::connect()?; -    /// let device = match device.get_password_safe("123456") { -    ///     Ok(pws) => { -    ///         use_password_safe(&pws); -    ///         pws.device() -    ///     }, -    ///     Err((device, err)) => { -    ///         println!("Could not open the password safe: {:?}", err); -    ///         device -    ///     }, +    /// match device.get_password_safe("123456") { +    ///     Ok(pws) => use_password_safe(&pws), +    ///     Err(err) => println!("Could not open the password safe: {:?}", err),      /// }; -    /// use_device(&device);      /// #     Ok(())      /// # }      /// ``` @@ -102,18 +80,16 @@ pub trait GetPasswordSafe {      /// [`device`]: struct.PasswordSafe.html#method.device      /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword -    fn get_password_safe(self, user_pin: &str) -> Result<PasswordSafe<Self>, (Self, CommandError)> -    where -        Self: Device + Sized; +    fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe, CommandError>;  } -fn get_password_safe<T: Device>( -    device: T, +fn get_password_safe<'a>( +    device: &'a Device,      user_pin: &str, -) -> Result<PasswordSafe<T>, (T, CommandError)> { +) -> Result<PasswordSafe<'a>, CommandError> {      let user_pin_string = CString::new(user_pin);      if user_pin_string.is_err() { -        return Err((device, CommandError::InvalidString)); +        return Err(CommandError::InvalidString);      }      let user_pin_string = user_pin_string.unwrap();      let status = unsafe { @@ -122,36 +98,12 @@ fn get_password_safe<T: Device>(          ))      };      match status { -        CommandStatus::Success => Ok(PasswordSafe { device }), -        CommandStatus::Error(err) => Err((device, err)), +        CommandStatus::Success => Ok(PasswordSafe { _device: device }), +        CommandStatus::Error(err) => Err(err),      }  } -fn get_password_safe_wrapper<T, C>( -    device: T, -    constructor: C, -    user_pin: &str, -) -> Result<PasswordSafe<DeviceWrapper>, (DeviceWrapper, CommandError)> -where -    T: Device, -    C: Fn(T) -> DeviceWrapper, -{ -    let result = device.get_password_safe(user_pin); -    match result { -        Ok(pws) => Ok(PasswordSafe { -            device: constructor(pws.device), -        }), -        Err((device, err)) => Err((constructor(device), err)), -    } -} - -impl<T: Device> PasswordSafe<T> { -    /// Forgets the password safe access and returns an unauthenticated device.  This method -    /// consumes the password safe.  It does not perform any actual commands on the Nitrokey. -    pub fn device(self) -> T { -        self.device -    } - +impl<'a> PasswordSafe<'a> {      /// Returns the status of all password slots.      ///      /// The status indicates whether a slot is programmed or not. @@ -164,18 +116,14 @@ impl<T: Device> PasswordSafe<T> {      ///      /// # fn try_main() -> Result<(), CommandError> {      /// let device = nitrokey::connect()?; -    /// match device.get_password_safe("123456") { -    ///     Ok(pws) => { -    ///         pws.get_slot_status()?.iter().enumerate().for_each(|(slot, programmed)| { -    ///             let status = match *programmed { -    ///                 true => "programmed", -    ///                 false => "not programmed", -    ///             }; -    ///             println!("Slot {}: {}", slot, status); -    ///         }); -    ///     }, -    ///     Err((_, err)) => println!("Could not open the password safe: {:?}", err), -    /// }; +    /// let pws = device.get_password_safe("123456")?; +    /// pws.get_slot_status()?.iter().enumerate().for_each(|(slot, programmed)| { +    ///     let status = match *programmed { +    ///         true => "programmed", +    ///         false => "not programmed", +    ///     }; +    ///     println!("Slot {}: {}", slot, status); +    /// });      /// #     Ok(())      /// # }      /// ``` @@ -218,7 +166,7 @@ impl<T: Device> PasswordSafe<T> {      ///         let password = pws.get_slot_login(0)?;      ///         println!("Credentials for {}: login {}, password {}", name, login, password);      ///     }, -    ///     Err((_, err)) => println!("Could not open the password safe: {:?}", err), +    ///     Err(err) => println!("Could not open the password safe: {:?}", err),      /// };      /// #     Ok(())      /// # } @@ -245,15 +193,11 @@ impl<T: Device> PasswordSafe<T> {      ///      /// # fn try_main() -> Result<(), CommandError> {      /// let device = nitrokey::connect()?; -    /// match device.get_password_safe("123456") { -    ///     Ok(pws) => { -    ///         let name = pws.get_slot_name(0)?; -    ///         let login = pws.get_slot_login(0)?; -    ///         let password = pws.get_slot_login(0)?; -    ///         println!("Credentials for {}: login {}, password {}", name, login, password); -    ///     }, -    ///     Err((_, err)) => println!("Could not open the password safe: {:?}", err), -    /// }; +    /// let pws = device.get_password_safe("123456")?; +    /// let name = pws.get_slot_name(0)?; +    /// let login = pws.get_slot_login(0)?; +    /// let password = pws.get_slot_login(0)?; +    /// println!("Credentials for {}: login {}, password {}", name, login, password);      /// #     Ok(())      /// # }      /// ``` @@ -279,15 +223,11 @@ impl<T: Device> PasswordSafe<T> {      ///      /// # fn try_main() -> Result<(), CommandError> {      /// let device = nitrokey::connect()?; -    /// match device.get_password_safe("123456") { -    ///     Ok(pws) => { -    ///         let name = pws.get_slot_name(0)?; -    ///         let login = pws.get_slot_login(0)?; -    ///         let password = pws.get_slot_login(0)?; -    ///         println!("Credentials for {}: login {}, password {}", name, login, password); -    ///     }, -    ///     Err((_, err)) => println!("Could not open the password safe: {:?}", err), -    /// }; +    /// let pws = device.get_password_safe("123456")?; +    /// let name = pws.get_slot_name(0)?; +    /// let login = pws.get_slot_login(0)?; +    /// let password = pws.get_slot_login(0)?; +    /// println!("Credentials for {}: login {}, password {}", name, login, password);      /// #     Ok(())      /// # }      /// ``` @@ -308,18 +248,16 @@ impl<T: Device> PasswordSafe<T> {      /// # Example      ///      /// ```no_run -    /// use nitrokey::{CommandStatus, GetPasswordSafe}; +    /// use nitrokey::GetPasswordSafe;      /// # use nitrokey::CommandError;      ///      /// # fn try_main() -> Result<(), CommandError> {      /// let device = nitrokey::connect()?; -    /// match device.get_password_safe("123456") { -    ///     Ok(pws) => match pws.write_slot(0, "GitHub", "johndoe", "passw0rd") { -    ///         CommandStatus::Success => println!("Successfully wrote slot 0."), -    ///         CommandStatus::Error(err) => println!("Could not write slot 0: {:?}", err), -    ///     }, -    ///     Err((_, err)) => println!("Could not open the password safe: {:?}", err), -    /// }; +    /// let pws = device.get_password_safe("123456")?; +    /// let name = pws.get_slot_name(0)?; +    /// let login = pws.get_slot_login(0)?; +    /// let password = pws.get_slot_login(0)?; +    /// println!("Credentials for {}: login {}, password {}", name, login, password);      /// #     Ok(())      /// # }      /// ``` @@ -362,12 +300,10 @@ impl<T: Device> PasswordSafe<T> {      ///      /// # fn try_main() -> Result<(), CommandError> {      /// let device = nitrokey::connect()?; -    /// match device.get_password_safe("123456") { -    ///     Ok(pws) => match pws.erase_slot(0) { -    ///         CommandStatus::Success => println!("Successfully erased slot 0."), -    ///         CommandStatus::Error(err) => println!("Could not erase slot 0: {:?}", err), -    ///     }, -    ///     Err((_, err)) => println!("Could not open the password safe: {:?}", err), +    /// let pws = device.get_password_safe("123456")?; +    /// match pws.erase_slot(0) { +    ///     CommandStatus::Success => println!("Erased slot 0."), +    ///     CommandStatus::Error(err) => println!("Could not erase slot 0: {:?}", err),      /// };      /// #     Ok(())      /// # } @@ -380,24 +316,19 @@ impl<T: Device> PasswordSafe<T> {  }  impl GetPasswordSafe for Pro { -    fn get_password_safe(self, user_pin: &str) -> Result<PasswordSafe<Self>, (Self, CommandError)> { +    fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe, CommandError> {          get_password_safe(self, user_pin)      }  }  impl GetPasswordSafe for Storage { -    fn get_password_safe(self, user_pin: &str) -> Result<PasswordSafe<Self>, (Self, CommandError)> { +    fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe, CommandError> {          get_password_safe(self, user_pin)      }  }  impl GetPasswordSafe for DeviceWrapper { -    fn get_password_safe(self, user_pin: &str) -> Result<PasswordSafe<Self>, (Self, CommandError)> { -        match self { -            DeviceWrapper::Storage(storage) => { -                get_password_safe_wrapper(storage, DeviceWrapper::Storage, user_pin) -            } -            DeviceWrapper::Pro(pro) => get_password_safe_wrapper(pro, DeviceWrapper::Pro, user_pin), -        } +    fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe, CommandError> { +        get_password_safe(self, user_pin)      }  } diff --git a/src/tests/pws.rs b/src/tests/pws.rs index f45a81a..30d6853 100644 --- a/src/tests/pws.rs +++ b/src/tests/pws.rs @@ -2,46 +2,29 @@ use pws::{GetPasswordSafe, PasswordSafe, SLOT_COUNT};  use tests::util::{Target, ADMIN_PASSWORD, USER_PASSWORD};  use util::{CommandError, CommandStatus}; -fn get_pws() -> PasswordSafe<Target> { -    Target::connect() -        .unwrap() -        .get_password_safe(USER_PASSWORD) -        .unwrap() +fn get_pws(device: &Target) -> PasswordSafe { +    device.get_password_safe(USER_PASSWORD).unwrap()  }  #[test]  #[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)]  fn enable() { +    let device = Target::connect().unwrap();      assert!( -        Target::connect() -            .unwrap() +        device              .get_password_safe(&(USER_PASSWORD.to_owned() + "123"))              .is_err()      ); -    assert!( -        Target::connect() -            .unwrap() -            .get_password_safe(USER_PASSWORD) -            .is_ok() -    ); -    assert!( -        Target::connect() -            .unwrap() -            .get_password_safe(ADMIN_PASSWORD) -            .is_err() -    ); -    assert!( -        Target::connect() -            .unwrap() -            .get_password_safe(USER_PASSWORD) -            .is_ok() -    ); +    assert!(device.get_password_safe(USER_PASSWORD).is_ok()); +    assert!(device.get_password_safe(ADMIN_PASSWORD).is_err()); +    assert!(device.get_password_safe(USER_PASSWORD).is_ok());  }  #[test]  #[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)]  fn get_status() { -    let pws = get_pws(); +    let device = Target::connect().unwrap(); +    let pws = get_pws(&device);      for i in 0..SLOT_COUNT {          assert_eq!(              CommandStatus::Success, @@ -75,7 +58,8 @@ fn get_status() {  #[test]  #[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)]  fn get_data() { -    let pws = get_pws(); +    let device = Target::connect().unwrap(); +    let pws = get_pws(&device);      assert_eq!(          CommandStatus::Success,          pws.write_slot(1, "name", "login", "password") @@ -118,7 +102,8 @@ fn get_data() {  #[test]  #[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)]  fn write() { -    let pws = get_pws(); +    let device = Target::connect().unwrap(); +    let pws = get_pws(&device);      assert_eq!(          CommandStatus::Error(CommandError::InvalidSlot), @@ -153,7 +138,8 @@ fn write() {  #[test]  #[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)]  fn erase() { -    let pws = get_pws(); +    let device = Target::connect().unwrap(); +    let pws = get_pws(&device);      assert_eq!(          CommandStatus::Error(CommandError::InvalidSlot),          pws.erase_slot(SLOT_COUNT) | 
