From fe2f39826ade5a156945dabb8c8ab725378a15c1 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sun, 27 Jan 2019 18:42:14 +0000 Subject: Store mutable reference to Manager in Device In the last patches, we ensured that devices can only be obtained using the Manager struct. But we did not ensure that there is only one device at a time. This patch adds a mutable reference to the Manager instance to the Device implementations. The borrow checker makes sure that there is only one mutable reference at a time. In this patch, we have to remove the old connect, Pro::connect and Storage::connect functions as they do no longer compile. (They discard the MutexGuard which invalidates the reference to the Manager.) Therefore the tests do no longer compile. --- src/device.rs | 160 +++++++++++++++------------------------------------------- 1 file changed, 40 insertions(+), 120 deletions(-) (limited to 'src/device.rs') diff --git a/src/device.rs b/src/device.rs index 758691d..50ff071 100644 --- a/src/device.rs +++ b/src/device.rs @@ -2,14 +2,13 @@ // SPDX-License-Identifier: MIT use std::fmt; -use std::marker; use libc; use nitrokey_sys; use crate::auth::Authenticate; use crate::config::{Config, RawConfig}; -use crate::error::Error; +use crate::error::{CommunicationError, Error}; use crate::otp::GenerateOtp; use crate::pws::GetPasswordSafe; use crate::util::{ @@ -109,11 +108,11 @@ impl fmt::Display for VolumeMode { /// /// [`connect`]: fn.connect.html #[derive(Debug)] -pub enum DeviceWrapper { +pub enum DeviceWrapper<'a> { /// A Nitrokey Storage device. - Storage(Storage), + Storage(Storage<'a>), /// A Nitrokey Pro device. - Pro(Pro), + Pro(Pro<'a>), } /// A Nitrokey Pro device without user or admin authentication. @@ -156,10 +155,8 @@ pub enum DeviceWrapper { /// [`connect`]: fn.connect.html /// [`Pro::connect`]: #method.connect #[derive(Debug)] -pub struct Pro { - // make sure that users cannot directly instantiate this type - #[doc(hidden)] - marker: marker::PhantomData<()>, +pub struct Pro<'a> { + manager: &'a mut crate::Manager, } /// A Nitrokey Storage device without user or admin authentication. @@ -202,10 +199,8 @@ pub struct Pro { /// [`connect`]: fn.connect.html /// [`Storage::connect`]: #method.connect #[derive(Debug)] -pub struct Storage { - // make sure that users cannot directly instantiate this type - #[doc(hidden)] - marker: marker::PhantomData<()>, +pub struct Storage<'a> { + manager: &'a mut crate::Manager, } /// The status of a volume on a Nitrokey Storage device. @@ -626,32 +621,6 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp + fmt::Debug { } } -/// Connects to a Nitrokey device. This method can be used to connect to any connected device, -/// both a Nitrokey Pro and a Nitrokey Storage. -/// -/// # Errors -/// -/// - [`NotConnected`][] if no Nitrokey device is connected -/// -/// # Example -/// -/// ``` -/// use nitrokey::DeviceWrapper; -/// -/// fn do_something(device: DeviceWrapper) {} -/// -/// match nitrokey::connect() { -/// Ok(device) => do_something(device), -/// Err(err) => eprintln!("Could not connect to a Nitrokey: {}", err), -/// } -/// ``` -/// -/// [`NotConnected`]: enum.CommunicationError.html#variant.NotConnected -#[deprecated(since = "0.4.0", note = "use `nitrokey::Manager::connect` instead")] -pub fn connect() -> Result { - crate::take()?.connect().map_err(Into::into) -} - fn get_connected_model() -> Option { match unsafe { nitrokey_sys::NK_get_device_model() } { nitrokey_sys::NK_device_model_NK_PRO => Some(Model::Pro), @@ -660,15 +629,23 @@ fn get_connected_model() -> Option { } } -pub(crate) fn create_device_wrapper(model: Model) -> DeviceWrapper { +pub(crate) fn create_device_wrapper( + manager: &mut crate::Manager, + model: Model, +) -> DeviceWrapper<'_> { match model { - Model::Pro => Pro::new().into(), - Model::Storage => Storage::new().into(), + Model::Pro => Pro::new(manager).into(), + Model::Storage => Storage::new(manager).into(), } } -pub(crate) fn get_connected_device() -> Option { - get_connected_model().map(create_device_wrapper) +pub(crate) fn get_connected_device( + manager: &mut crate::Manager, +) -> Result, Error> { + match get_connected_model() { + Some(model) => Ok(create_device_wrapper(manager, model)), + None => Err(CommunicationError::NotConnected.into()), + } } pub(crate) fn connect_enum(model: Model) -> bool { @@ -679,7 +656,7 @@ pub(crate) fn connect_enum(model: Model) -> bool { unsafe { nitrokey_sys::NK_login_enum(model) == 1 } } -impl DeviceWrapper { +impl<'a> DeviceWrapper<'a> { fn device(&self) -> &dyn Device { match *self { DeviceWrapper::Storage(ref storage) => storage, @@ -695,19 +672,19 @@ impl DeviceWrapper { } } -impl From for DeviceWrapper { - fn from(device: Pro) -> Self { +impl<'a> From> for DeviceWrapper<'a> { + fn from(device: Pro<'a>) -> Self { DeviceWrapper::Pro(device) } } -impl From for DeviceWrapper { - fn from(device: Storage) -> Self { +impl<'a> From> for DeviceWrapper<'a> { + fn from(device: Storage<'a>) -> Self { DeviceWrapper::Storage(device) } } -impl GenerateOtp for DeviceWrapper { +impl<'a> GenerateOtp for DeviceWrapper<'a> { fn get_hotp_slot_name(&self, slot: u8) -> Result { self.device().get_hotp_slot_name(slot) } @@ -725,7 +702,7 @@ impl GenerateOtp for DeviceWrapper { } } -impl Device for DeviceWrapper { +impl<'a> Device for DeviceWrapper<'a> { fn get_model(&self) -> Model { match *self { DeviceWrapper::Pro(_) => Model::Pro, @@ -734,40 +711,13 @@ impl Device for DeviceWrapper { } } -impl Pro { - /// Connects to a Nitrokey Pro. - /// - /// # Errors - /// - /// - [`NotConnected`][] if no Nitrokey device of the given model is connected - /// - /// # Example - /// - /// ``` - /// use nitrokey::Pro; - /// - /// fn use_pro(device: Pro) {} - /// - /// match nitrokey::Pro::connect() { - /// Ok(device) => use_pro(device), - /// Err(err) => eprintln!("Could not connect to the Nitrokey Pro: {}", err), - /// } - /// ``` - /// - /// [`NotConnected`]: enum.CommunicationError.html#variant.NotConnected - #[deprecated(since = "0.4.0", note = "use `nitrokey::Manager::connect_pro` instead")] - pub fn connect() -> Result { - crate::take()?.connect_pro().map_err(Into::into) - } - - pub(crate) fn new() -> Pro { - Pro { - marker: marker::PhantomData, - } +impl<'a> Pro<'a> { + pub(crate) fn new(manager: &'a mut crate::Manager) -> Pro<'a> { + Pro { manager } } } -impl Drop for Pro { +impl<'a> Drop for Pro<'a> { fn drop(&mut self) { unsafe { nitrokey_sys::NK_logout(); @@ -775,47 +725,17 @@ impl Drop for Pro { } } -impl Device for Pro { +impl<'a> Device for Pro<'a> { fn get_model(&self) -> Model { Model::Pro } } -impl GenerateOtp for Pro {} +impl<'a> GenerateOtp for Pro<'a> {} -impl Storage { - /// Connects to a Nitrokey Storage. - /// - /// # Errors - /// - /// - [`NotConnected`][] if no Nitrokey device of the given model is connected - /// - /// # Example - /// - /// ``` - /// use nitrokey::Storage; - /// - /// fn use_storage(device: Storage) {} - /// - /// match nitrokey::Storage::connect() { - /// Ok(device) => use_storage(device), - /// Err(err) => eprintln!("Could not connect to the Nitrokey Storage: {}", err), - /// } - /// ``` - /// - /// [`NotConnected`]: enum.CommunicationError.html#variant.NotConnected - #[deprecated( - since = "0.4.0", - note = "use `nitrokey::Manager::connect_storage` instead" - )] - pub fn connect() -> Result { - crate::take()?.connect_storage().map_err(Into::into) - } - - pub(crate) fn new() -> Storage { - Storage { - marker: marker::PhantomData, - } +impl<'a> Storage<'a> { + pub(crate) fn new(manager: &'a mut crate::Manager) -> Storage<'a> { + Storage { manager } } /// Changes the update PIN. @@ -1320,7 +1240,7 @@ impl Storage { } } -impl Drop for Storage { +impl<'a> Drop for Storage<'a> { fn drop(&mut self) { unsafe { nitrokey_sys::NK_logout(); @@ -1328,13 +1248,13 @@ impl Drop for Storage { } } -impl Device for Storage { +impl<'a> Device for Storage<'a> { fn get_model(&self) -> Model { Model::Storage } } -impl GenerateOtp for Storage {} +impl<'a> GenerateOtp for Storage<'a> {} impl From for StorageProductionInfo { fn from(data: nitrokey_sys::NK_storage_ProductionTest) -> Self { -- cgit v1.2.1