//! Provides access to a Nitrokey device using the native libnitrokey API. //! //! # Usage //! //! Operations on the Nitrokey require different authentication levels. Some //! operations can be performed without authentication, some require user //! access, and some require admin access. This is modelled using the types //! [`UnauthenticatedDevice`][], [`UserAuthenticatedDevice`][] and //! [`AdminAuthenticatedDevice`][]. //! //! Use [`connect`][] or [`connect_model`][] to obtain an //! [`UnauthenticatedDevice`][]. You can then use [`authenticate_user`][] or //! [`authenticate_admin`][] to get an authenticated device. You can then use //! [`device`][] to go back to the unauthenticated device. //! //! This makes sure that you can only execute a command if you have the //! required access rights. Otherwise, your code will not compile. The only //! exception are the methods to generate one-time passwords – //! [`get_hotp_code`][] and [`get_totp_code`][]. Depending on the stick //! configuration, these operations are available without authentication or //! with user authentication. //! //! # Examples //! //! Connect to any Nitrokey and print its serial number: //! //! ```no_run //! use nitrokey::Device; //! # use nitrokey::CommandError; //! //! # fn try_main() -> Result<(), CommandError> { //! let device = nitrokey::connect()?; //! println!("{}", device.get_serial_number()?); //! # Ok(()) //! # } //! ``` //! //! Configure an HOTP slot: //! //! ```no_run //! use nitrokey::{CommandStatus, ConfigureOtp, Device, OtpMode, OtpSlotData}; //! # use nitrokey::CommandError; //! //! # fn try_main() -> Result<(), (CommandError)> { //! let device = nitrokey::connect()?; //! let slot_data = OtpSlotData::new(1, "test", "01234567890123456689", OtpMode::SixDigits); //! match device.authenticate_admin("12345678") { //! Ok(admin) => { //! match admin.write_hotp_slot(slot_data, 0) { //! CommandStatus::Success => println!("Successfully wrote slot."), //! CommandStatus::Error(err) => println!("Could not write slot: {:?}", err), //! } //! }, //! Err((_, err)) => println!("Could not authenticate as admin: {:?}", err), //! } //! # Ok(()) //! # } //! ``` //! //! Generate an HOTP one-time password: //! //! ```no_run //! use nitrokey::{Device, GenerateOtp}; //! # use nitrokey::CommandError; //! //! # fn try_main() -> Result<(), (CommandError)> { //! let device = nitrokey::connect()?; //! match device.get_hotp_code(1) { //! Ok(code) => println!("Generated HOTP code: {:?}", code), //! Err(err) => println!("Could not generate HOTP code: {:?}", err), //! } //! # Ok(()) //! # } //! ``` //! //! [`authenticate_admin`]: struct.UnauthenticatedDevice.html#method.authenticate_admin //! [`authenticate_user`]: struct.UnauthenticatedDevice.html#method.authenticate_user //! [`connect`]: fn.connect.html //! [`connect_model`]: fn.connect_model.html //! [`device`]: struct.AuthenticatedDevice.html#method.device //! [`get_hotp_code`]: trait.ProvideOtp.html#method.get_hotp_code //! [`get_totp_code`]: trait.ProvideOtp.html#method.get_totp_code //! [`AdminAuthenticatedDevice`]: struct.AdminAuthenticatedDevice.html //! [`UserAuthenticatedDevice`]: struct.UserAuthenticatedDevice.html //! [`UnauthenticatedDevice`]: struct.UnauthenticatedDevice.html extern crate libc; extern crate nitrokey_sys; extern crate rand; mod config; mod device; mod otp; mod util; #[cfg(test)] mod tests; pub use config::Config; pub use device::{AdminAuthenticatedDevice, Device, Model, UnauthenticatedDevice, UserAuthenticatedDevice}; pub use otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData}; pub use util::{CommandError, CommandStatus, LogLevel}; /// Connects to a Nitrokey device. This method can be used to connect to any /// connected device, both a Nitrokey Pro and a Nitrokey Storage. /// /// # Example /// /// ``` /// use nitrokey::UnauthenticatedDevice; /// /// fn do_something(device: UnauthenticatedDevice) {} /// /// match nitrokey::connect() { /// Ok(device) => do_something(device), /// Err(err) => println!("Could not connect to a Nitrokey: {:?}", err), /// } /// ``` pub fn connect() -> Result { unsafe { match nitrokey_sys::NK_login_auto() { 1 => Ok(UnauthenticatedDevice {}), _ => Err(CommandError::Unknown), } } } /// Connects to a Nitrokey device of the given model. /// /// # Example /// /// ``` /// use nitrokey::{Model, UnauthenticatedDevice}; /// /// fn do_something(device: UnauthenticatedDevice) {} /// /// match nitrokey::connect_model(Model::Pro) { /// Ok(device) => do_something(device), /// Err(err) => println!("Could not connect to a Nitrokey Pro: {:?}", err), /// } /// ``` pub fn connect_model(model: Model) -> Result { let model = match model { Model::Storage => nitrokey_sys::NK_device_model_NK_STORAGE, Model::Pro => nitrokey_sys::NK_device_model_NK_PRO, }; unsafe { return match nitrokey_sys::NK_login_enum(model) { 1 => Ok(UnauthenticatedDevice {}), rv => Err(CommandError::from(rv)), }; } } /// 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`][]). /// /// If debug output is enabled, detailed information about the communication /// with the Nitrokey device is printed to the standard output. /// /// [`set_log_level`]: fn.set_log_level.html pub fn set_debug(state: bool) { unsafe { nitrokey_sys::NK_set_debug(state); } } /// Sets the log level for libnitrokey. All log messages are written to the /// standard output or standard errror. pub fn set_log_level(level: LogLevel) { unsafe { nitrokey_sys::NK_set_debug_level(level.into()); } }