From 2ec913fdcadef73281ec30f96c0fc7cd00a4ed26 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 22 May 2018 21:41:30 +0000 Subject: Move the authenticate methods to a new Authenticate trait --- src/device.rs | 121 ++++++++++++++++++++++++++++++++----------------------- src/lib.rs | 8 ++-- src/otp.rs | 8 ++-- src/tests/pro.rs | 2 +- 4 files changed, 80 insertions(+), 59 deletions(-) diff --git a/src/device.rs b/src/device.rs index ce45a50..ab90d3d 100644 --- a/src/device.rs +++ b/src/device.rs @@ -28,7 +28,7 @@ pub enum Model { /// Authentication with error handling: /// /// ```no_run -/// use nitrokey::{UnauthenticatedDevice, UserAuthenticatedDevice}; +/// use nitrokey::{Authenticate, UnauthenticatedDevice, UserAuthenticatedDevice}; /// # use nitrokey::CommandError; /// /// fn perform_user_task(device: &UserAuthenticatedDevice) {} @@ -51,8 +51,8 @@ pub enum Model { /// # } /// ``` /// -/// [`authenticate_admin`]: #method.authenticate_admin -/// [`authenticate_user`]: #method.authenticate_user +/// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin +/// [`authenticate_user`]: trait.Authenticate.html#method.authenticate_user /// [`connect`]: fn.connect.html /// [`connect_model`]: fn.connect_model.html #[derive(Debug)] @@ -64,7 +64,7 @@ pub struct UnauthenticatedDevice {} /// method on an [`UnauthenticatedDevice`][]. To get back to an /// unauthenticated device, use the [`device`][] method. /// -/// [`authenticate_admin`]: struct.UnauthenticatedDevice#method.authenticate_admin +/// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin /// [`device`]: #method.device /// [`UnauthenticatedDevice`]: struct.UnauthenticatedDevice.html #[derive(Debug)] @@ -79,7 +79,7 @@ pub struct UserAuthenticatedDevice { /// method on an [`UnauthenticatedDevice`][]. To get back to an /// unauthenticated device, use the [`device`][] method. /// -/// [`authenticate_admin`]: struct.UnauthenticatedDevice#method.authenticate_admin +/// [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin /// [`device`]: #method.device /// [`UnauthenticatedDevice`]: struct.UnauthenticatedDevice.html #[derive(Debug)] @@ -350,38 +350,10 @@ pub trait Device { } } -trait AuthenticatedDevice { - fn new(device: UnauthenticatedDevice, temp_password: Vec) -> Self; -} - -impl UnauthenticatedDevice { - fn authenticate( - self, - password: &str, - callback: T, - ) -> Result - where - D: AuthenticatedDevice, - T: Fn(*const i8, *const i8) -> c_int, - { - let temp_password = match generate_password(TEMPORARY_PASSWORD_LENGTH) { - Ok(pw) => pw, - Err(_) => return Err((self, CommandError::RngError)), - }; - let password = CString::new(password); - if password.is_err() { - return Err((self, CommandError::InvalidString)); - } - - let pw = password.unwrap(); - let password_ptr = pw.as_ptr(); - let temp_password_ptr = temp_password.as_ptr() as *const i8; - return match callback(password_ptr, temp_password_ptr) { - 0 => Ok(D::new(self, temp_password)), - rv => Err((self, CommandError::from(rv))), - }; - } - +/// Provides methods to authenticate as a user or as an admin using a PIN. The authenticated +/// methods will consume the current device instance. On success, they return the authenticated +/// device. Otherwise, they return the current unauthenticated device and the error code. +pub trait Authenticate { /// Performs user authentication. This method consumes the device. If /// successful, an authenticated device is returned. Otherwise, the /// current unauthenticated device and the error are returned. @@ -398,7 +370,7 @@ impl UnauthenticatedDevice { /// # Example /// /// ```no_run - /// use nitrokey::{UnauthenticatedDevice, UserAuthenticatedDevice}; + /// use nitrokey::{Authenticate, UnauthenticatedDevice, UserAuthenticatedDevice}; /// # use nitrokey::CommandError; /// /// fn perform_user_task(device: &UserAuthenticatedDevice) {} @@ -424,14 +396,12 @@ impl UnauthenticatedDevice { /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString /// [`RngError`]: enum.CommandError.html#variant.RngError /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword - pub fn authenticate_user( + fn authenticate_user( self, password: &str, - ) -> Result { - return self.authenticate(password, |password_ptr, temp_password_ptr| unsafe { - nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr) - }); - } + ) -> Result + where + Self: Sized; /// Performs admin authentication. This method consumes the device. If /// successful, an authenticated device is returned. Otherwise, the @@ -449,7 +419,7 @@ impl UnauthenticatedDevice { /// # Example /// /// ```no_run - /// use nitrokey::{AdminAuthenticatedDevice, UnauthenticatedDevice}; + /// use nitrokey::{Authenticate, AdminAuthenticatedDevice, UnauthenticatedDevice}; /// # use nitrokey::CommandError; /// /// fn perform_admin_task(device: &AdminAuthenticatedDevice) {} @@ -475,10 +445,61 @@ impl UnauthenticatedDevice { /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString /// [`RngError`]: enum.CommandError.html#variant.RngError /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword - pub fn authenticate_admin( + fn authenticate_admin( + self, + password: &str, + ) -> Result + where + Self: Sized; +} + +trait AuthenticatedDevice { + fn new(device: UnauthenticatedDevice, temp_password: Vec) -> Self; +} + +impl UnauthenticatedDevice { + fn authenticate( + self, + password: &str, + callback: T, + ) -> Result + where + D: AuthenticatedDevice, + T: Fn(*const i8, *const i8) -> c_int, + { + let temp_password = match generate_password(TEMPORARY_PASSWORD_LENGTH) { + Ok(pw) => pw, + Err(_) => return Err((self, CommandError::RngError)), + }; + let password = CString::new(password); + if password.is_err() { + return Err((self, CommandError::InvalidString)); + } + + let pw = password.unwrap(); + let password_ptr = pw.as_ptr(); + let temp_password_ptr = temp_password.as_ptr() as *const i8; + return match callback(password_ptr, temp_password_ptr) { + 0 => Ok(D::new(self, temp_password)), + rv => Err((self, CommandError::from(rv))), + }; + } +} + +impl Authenticate for UnauthenticatedDevice { + fn authenticate_user( + self, + password: &str, + ) -> Result { + return self.authenticate(password, |password_ptr, temp_password_ptr| unsafe { + nitrokey_sys::NK_user_authenticate(password_ptr, temp_password_ptr) + }); + } + + fn authenticate_admin( self, password: &str, - ) -> Result { + ) -> Result { return self.authenticate(password, |password_ptr, temp_password_ptr| unsafe { nitrokey_sys::NK_first_authenticate(password_ptr, temp_password_ptr) }); @@ -521,7 +542,7 @@ impl GenerateOtp for UserAuthenticatedDevice { /// # Example /// /// ```no_run - /// use nitrokey::{Device, GenerateOtp}; + /// use nitrokey::{Authenticate, GenerateOtp}; /// # use nitrokey::CommandError; /// /// # fn try_main() -> Result<(), CommandError> { @@ -562,7 +583,7 @@ impl GenerateOtp for UserAuthenticatedDevice { /// # Example /// /// ```no_run - /// use nitrokey::{Device, GenerateOtp}; + /// use nitrokey::{Authenticate, GenerateOtp}; /// # use nitrokey::CommandError; /// /// # fn try_main() -> Result<(), CommandError> { @@ -623,7 +644,7 @@ impl AdminAuthenticatedDevice { /// # Example /// /// ```no_run - /// use nitrokey::Config; + /// use nitrokey::{Authenticate, Config}; /// # use nitrokey::CommandError; /// /// # fn try_main() -> Result<(), CommandError> { diff --git a/src/lib.rs b/src/lib.rs index 1cfb7fd..cb44ee2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,7 +38,7 @@ //! Configure an HOTP slot: //! //! ```no_run -//! use nitrokey::{CommandStatus, ConfigureOtp, Device, OtpMode, OtpSlotData}; +//! use nitrokey::{Authenticate, CommandStatus, ConfigureOtp, OtpMode, OtpSlotData}; //! # use nitrokey::CommandError; //! //! # fn try_main() -> Result<(), (CommandError)> { @@ -73,8 +73,8 @@ //! # } //! ``` //! -//! [`authenticate_admin`]: struct.UnauthenticatedDevice.html#method.authenticate_admin -//! [`authenticate_user`]: struct.UnauthenticatedDevice.html#method.authenticate_user +//! [`authenticate_admin`]: trait.Authenticate.html#method.authenticate_admin +//! [`authenticate_user`]: trait.Authenticate.html#method.authenticate_user //! [`connect`]: fn.connect.html //! [`connect_model`]: fn.connect_model.html //! [`device`]: struct.AuthenticatedDevice.html#method.device @@ -96,7 +96,7 @@ mod util; mod tests; pub use config::Config; -pub use device::{AdminAuthenticatedDevice, Device, Model, UnauthenticatedDevice, +pub use device::{AdminAuthenticatedDevice, Authenticate, Device, Model, UnauthenticatedDevice, UserAuthenticatedDevice}; pub use otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData}; pub use util::{CommandError, CommandStatus, LogLevel}; diff --git a/src/otp.rs b/src/otp.rs index 0451c5f..7145b6c 100644 --- a/src/otp.rs +++ b/src/otp.rs @@ -25,7 +25,7 @@ pub trait ConfigureOtp { /// # Example /// /// ```no_run - /// use nitrokey::{CommandStatus, ConfigureOtp, OtpMode, OtpSlotData}; + /// use nitrokey::{Authenticate, CommandStatus, ConfigureOtp, OtpMode, OtpSlotData}; /// # use nitrokey::CommandError; /// /// # fn try_main() -> Result<(), (CommandError)> { @@ -61,7 +61,7 @@ pub trait ConfigureOtp { /// # Example /// /// ```no_run - /// use nitrokey::{CommandStatus, ConfigureOtp, OtpMode, OtpSlotData}; + /// use nitrokey::{Authenticate, CommandStatus, ConfigureOtp, OtpMode, OtpSlotData}; /// # use nitrokey::CommandError; /// /// # fn try_main() -> Result<(), (CommandError)> { @@ -94,7 +94,7 @@ pub trait ConfigureOtp { /// # Example /// /// ```no_run - /// use nitrokey::{CommandStatus, ConfigureOtp}; + /// use nitrokey::{Authenticate, CommandStatus, ConfigureOtp}; /// # use nitrokey::CommandError; /// /// # fn try_main() -> Result<(), (CommandError)> { @@ -124,7 +124,7 @@ pub trait ConfigureOtp { /// # Example /// /// ```no_run - /// use nitrokey::{CommandStatus, ConfigureOtp}; + /// use nitrokey::{Authenticate, CommandStatus, ConfigureOtp}; /// # use nitrokey::CommandError; /// /// # fn try_main() -> Result<(), (CommandError)> { diff --git a/src/tests/pro.rs b/src/tests/pro.rs index 71daa78..8476451 100644 --- a/src/tests/pro.rs +++ b/src/tests/pro.rs @@ -1,5 +1,5 @@ use std::ffi::CStr; -use {AdminAuthenticatedDevice, CommandError, CommandStatus, Config, ConfigureOtp, +use {AdminAuthenticatedDevice, Authenticate, CommandError, CommandStatus, Config, ConfigureOtp, Device, GenerateOtp, Model, OtpMode, OtpSlotData, UnauthenticatedDevice}; static ADMIN_PASSWORD: &str = "12345678"; -- cgit v1.2.1