diff options
-rw-r--r-- | nitrocli/src/error.rs | 4 | ||||
-rw-r--r-- | nitrocli/src/main.rs | 68 | ||||
-rw-r--r-- | nitrocli/src/pinentry.rs | 17 |
3 files changed, 41 insertions, 48 deletions
diff --git a/nitrocli/src/error.rs b/nitrocli/src/error.rs index 1b7068d..d755cac 100644 --- a/nitrocli/src/error.rs +++ b/nitrocli/src/error.rs @@ -21,7 +21,6 @@ use std::fmt; use std::io; use std::string; - #[derive(Debug)] pub enum Error { IoError(io::Error), @@ -29,21 +28,18 @@ pub enum Error { Error(String), } - impl From<io::Error> for Error { fn from(e: io::Error) -> Error { Error::IoError(e) } } - impl From<string::FromUtf8Error> for Error { fn from(e: string::FromUtf8Error) -> Error { Error::Utf8Error(e) } } - impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { diff --git a/nitrocli/src/main.rs b/nitrocli/src/main.rs index 8a8405a..c190d1b 100644 --- a/nitrocli/src/main.rs +++ b/nitrocli/src/main.rs @@ -54,7 +54,7 @@ unused_qualifications, unused_results, where_clauses_object_safety, - while_true, + while_true )] #![warn( bad_style, @@ -62,7 +62,7 @@ nonstandard_style, renamed_and_removed_lints, rust_2018_compatibility, - rust_2018_idioms, + rust_2018_idioms )] //! Nitrocli is a program providing a command line interface to certain @@ -82,13 +82,11 @@ type Result<T> = result::Result<T, Error>; const PIN_TYPE: pinentry::PinType = pinentry::PinType::User; - /// Create an `error::Error` with an error message of the format `msg: err`. fn get_error(msg: &str, err: &nitrokey::CommandError) -> Error { Error::Error(format!("{}: {:?}", msg, err)) } - /// Connect to a Nitrokey Storage device and return it. fn get_storage_device() -> Result<nitrokey::Storage> { nitrokey::Storage::connect() @@ -108,37 +106,43 @@ fn get_volume_status(status: &nitrokey::VolumeStatus) -> &'static str { } } - /// Pretty print the response of a status command. fn print_status(status: &nitrokey::StorageStatus) { - println!("Status:"); // We omit displaying information about the smartcard here as this // program really is only about the SD card portion of the device. - println!(" SD card ID: {:#x}", status.serial_number_sd_card); - println!(" firmware version: {}.{}", - status.firmware_version_major, - status.firmware_version_minor); - println!(" firmware: {}", - if status.firmware_locked { - "locked".to_string() - } else { - "unlocked".to_string() - }); - println!(" storage keys: {}", - if status.stick_initialized { - "created".to_string() - } else { - "not created".to_string() - }); - println!(" user retry count: {}", status.user_retry_count); - println!(" admin retry count: {}", status.admin_retry_count); - println!(" volumes:"); - println!(" unencrypted: {}", get_volume_status(&status.unencrypted_volume)); - println!(" encrypted: {}", get_volume_status(&status.encrypted_volume)); - println!(" hidden: {}", get_volume_status(&status.hidden_volume)); + println!( + r#"Status: + SD card ID: {id:#x} + firmware version: {fwv0}.{fwv1} + firmware: {fw} + storage keys: {sk} + user retry count: {urc} + admin retry count: {arc} + volumes: + unencrypted: {vu} + encrypted: {ve} + hidden: {vh}"#, + id = status.serial_number_sd_card, + fwv0 = status.firmware_version_major, + fwv1 = status.firmware_version_minor, + fw = if status.firmware_locked { + "locked" + } else { + "unlocked" + }, + sk = if status.stick_initialized { + "created" + } else { + "not created" + }, + urc = status.user_retry_count, + arc = status.admin_retry_count, + vu = get_volume_status(&status.unencrypted_volume), + ve = get_volume_status(&status.encrypted_volume), + vh = get_volume_status(&status.hidden_volume), + ); } - /// Inquire the status of the nitrokey. fn status() -> Result<()> { let status = get_storage_device()? @@ -149,7 +153,6 @@ fn status() -> Result<()> { Ok(()) } - /// Open the encrypted volume on the nitrokey. fn open() -> Result<()> { let device = get_storage_device()?; @@ -174,14 +177,13 @@ fn open() -> Result<()> { } let error = "Opening encrypted volume failed: Wrong password"; return Err(Error::Error(error.to_string())); - }, + } err => return Err(get_error("Opening encrypted volume failed", &err)), }, }; } } - #[link(name = "c")] extern "C" { fn sync(); @@ -200,13 +202,11 @@ fn close() -> Result<()> { .map_err(|err| get_error("Closing encrypted volume failed", &err)) } - /// Clear the PIN stored when opening the nitrokey's encrypted volume. fn clear() -> Result<()> { pinentry::clear_passphrase(PIN_TYPE) } - // A macro for generating a match of the different supported commands. // Each supplied command is converted into a string and matched against. macro_rules! commands { diff --git a/nitrocli/src/pinentry.rs b/nitrocli/src/pinentry.rs index 66ca6be..fc7af2c 100644 --- a/nitrocli/src/pinentry.rs +++ b/nitrocli/src/pinentry.rs @@ -21,7 +21,6 @@ use std::process; use crate::error::Error; - /// PIN type requested from pinentry. /// /// The available PIN types correspond to the PIN types used by the Nitrokey devices: user and @@ -35,7 +34,6 @@ pub enum PinType { User, } - impl PinType { fn cache_id(self) -> &'static str { match self { @@ -59,7 +57,6 @@ impl PinType { } } - fn parse_pinentry_passphrase(response: Vec<u8>) -> Result<Vec<u8>, Error> { let string = String::from_utf8(response)?; let lines: Vec<&str> = string.lines().collect(); @@ -84,14 +81,15 @@ fn parse_pinentry_passphrase(response: Vec<u8>) -> Result<Vec<u8>, Error> { Err(Error::Error("Unexpected response: ".to_string() + &string)) } - /// Inquire a PIN of the given type from the user. /// /// This function inquires a PIN of the given type from the user or returns the cached passphrase, /// if available. If an error message is set, it is displayed in the passphrase dialog. pub fn inquire_passphrase(pin_type: PinType, error_msg: Option<&str>) -> Result<Vec<u8>, Error> { let cache_id = pin_type.cache_id(); - let error_msg = error_msg.map(|msg| msg.replace(" ", "+")).unwrap_or_else(|| String::from("+")); + let error_msg = error_msg + .map(|msg| msg.replace(" ", "+")) + .unwrap_or_else(|| String::from("+")); let prompt = pin_type.prompt(); let description = pin_type.description().replace(" ", "+"); @@ -103,13 +101,13 @@ pub fn inquire_passphrase(pin_type: PinType, error_msg: Option<&str>) -> Result< // reported for the GET_PASSPHRASE command does not actually cause // gpg-connect-agent to exit with a non-zero error code, we have to // evaluate the output to determine success/failure. - let output = process::Command::new("gpg-connect-agent").arg(command) + let output = process::Command::new("gpg-connect-agent") + .arg(command) .arg("/bye") .output()?; parse_pinentry_passphrase(output.stdout) } - fn parse_pinentry_response(response: Vec<u8>) -> Result<(), Error> { let string = String::from_utf8(response)?; let lines: Vec<&str> = string.lines().collect(); @@ -121,18 +119,17 @@ fn parse_pinentry_response(response: Vec<u8>) -> Result<(), Error> { Err(Error::Error("Unexpected response: ".to_string() + &string)) } - /// Clear the cached passphrase of the given type. pub fn clear_passphrase(pin_type: PinType) -> Result<(), Error> { let command = "CLEAR_PASSPHRASE ".to_string() + pin_type.cache_id(); - let output = process::Command::new("gpg-connect-agent").arg(command) + let output = process::Command::new("gpg-connect-agent") + .arg(command) .arg("/bye") .output()?; parse_pinentry_response(output.stdout) } - #[cfg(test)] mod tests { use super::*; |