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::*; | 
