diff options
author | Robin Krahl <robin.krahl@ireas.org> | 2019-12-29 12:51:28 +0100 |
---|---|---|
committer | Robin Krahl <robin.krahl@ireas.org> | 2020-01-07 11:33:27 +0100 |
commit | c74b8b3ea8dc4fe7c6891ae120540f8da5623227 (patch) | |
tree | 7c66308f30a2a6137339289a55e7ce52f73ae100 /src | |
parent | bcad061ed3e7777547c1b6fc9223dd65f752d94e (diff) | |
download | nitrokey-rs-c74b8b3ea8dc4fe7c6891ae120540f8da5623227.tar.gz nitrokey-rs-c74b8b3ea8dc4fe7c6891ae120540f8da5623227.tar.bz2 |
Add list_devices function
This patch adds support for libnitrokey’s NK_list_devices function by
introducing the top-level list_devices function. It returns a vector of
DeviceInfo structs with information about all connected Nitrokey
devices.
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 68 |
1 files changed, 68 insertions, 0 deletions
@@ -109,8 +109,10 @@ mod otp; mod pws; mod util; +use std::convert::TryInto as _; use std::fmt; use std::marker; +use std::ptr::NonNull; use std::sync; use nitrokey_sys; @@ -126,6 +128,8 @@ pub use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData}; pub use crate::pws::{GetPasswordSafe, PasswordSafe, SLOT_COUNT}; pub use crate::util::LogLevel; +use crate::util::get_last_result; + /// The default admin PIN for all Nitrokey devices. pub const DEFAULT_ADMIN_PIN: &str = "12345678"; /// The default user PIN for all Nitrokey devices. @@ -416,6 +420,70 @@ pub fn force_take() -> Result<sync::MutexGuard<'static, Manager>, Error> { } } +/// List all connected Nitrokey devices. +/// +/// This functions returns a vector with [`DeviceInfo`][] structs that contain information about +/// all connected Nitrokey devices. It will even list unsupported models, although you cannot +/// connect to them. +/// +/// # Errors +/// +/// - [`NotConnected`][] if a Nitrokey device has been disconnected during enumeration +/// - [`Utf8Error`][] if the USB path or the serial number returned by libnitrokey are invalid +/// UTF-8 strings +/// +/// # Example +/// +/// ``` +/// let devices = nitrokey::list_devices()?; +/// if devices.is_empty() { +/// println!("No connected Nitrokey devices found."); +/// } else { +/// println!("model\tpath\tserial number"); +/// for device in devices { +/// match device.model { +/// Some(model) => print!("{}", model), +/// None => print!("unsupported"), +/// } +/// print!("\t{}\t", device.path); +/// match device.serial_number { +/// Some(serial_number) => println!("{}", serial_number), +/// None => println!("unknown"), +/// } +/// } +/// } +/// # Ok::<(), nitrokey::Error>(()) +/// ``` +/// +/// [`DeviceInfo`]: struct.DeviceInfo.html +/// [`NotConnected`]: enum.CommunicationError.html#variant.NotConnected +/// [`Utf8Error`]: enum.Error.html#variant.Utf8Error +pub fn list_devices() -> Result<Vec<DeviceInfo>, Error> { + let ptr = NonNull::new(unsafe { nitrokey_sys::NK_list_devices() }); + match ptr { + Some(mut ptr) => { + let mut vec: Vec<DeviceInfo> = Vec::new(); + push_device_info(&mut vec, unsafe { ptr.as_ref() })?; + unsafe { + nitrokey_sys::NK_free_device_info(ptr.as_mut()); + } + Ok(vec) + } + None => get_last_result().map(|_| Vec::new()), + } +} + +fn push_device_info( + vec: &mut Vec<DeviceInfo>, + info: &nitrokey_sys::NK_device_info, +) -> Result<(), Error> { + vec.push(info.try_into()?); + if let Some(ptr) = NonNull::new(info.next) { + push_device_info(vec, unsafe { ptr.as_ref() })?; + } + Ok(()) +} + /// Enables or disables debug output. Calling this method with `true` is equivalent to setting the /// log level to `Debug`; calling it with `false` is equivalent to the log level `Error` (see /// [`set_log_level`][]). |