aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index dad4a20..5600d24 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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`][]).