diff options
| -rw-r--r-- | nitrocli/src/args.rs | 22 | ||||
| -rw-r--r-- | nitrocli/src/commands.rs | 44 | 
2 files changed, 65 insertions, 1 deletions
| diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index 5c2cbb8..ab80f3d 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -86,6 +86,7 @@ enum OtpCommand {    Clear,    Get,    Set, +  Status,  }  impl OtpCommand { @@ -94,6 +95,7 @@ impl OtpCommand {        OtpCommand::Clear => otp_clear(args),        OtpCommand::Get => otp_get(args),        OtpCommand::Set => otp_set(args), +      OtpCommand::Status => otp_status(args),      }    }  } @@ -107,6 +109,7 @@ impl fmt::Display for OtpCommand {          OtpCommand::Clear => "clear",          OtpCommand::Get => "get",          OtpCommand::Set => "set", +        OtpCommand::Status => "status",        }      )    } @@ -120,6 +123,7 @@ impl str::FromStr for OtpCommand {        "clear" => Ok(OtpCommand::Clear),        "get" => Ok(OtpCommand::Get),        "set" => Ok(OtpCommand::Set), +      "status" => Ok(OtpCommand::Status),        _ => Err(()),      }    } @@ -249,7 +253,7 @@ fn otp(args: Vec<String>) -> Result<()> {    let _ = parser.refer(&mut subcommand).required().add_argument(      "subcommand",      argparse::Store, -    "The subcommand to execute (clear|get|set)", +    "The subcommand to execute (clear|get|set|status)",    );    let _ = parser.refer(&mut subargs).add_argument(      "arguments", @@ -374,6 +378,22 @@ fn otp_clear(args: Vec<String>) -> Result<()> {    commands::otp_clear(slot, algorithm)  } +/// Print the status of the OTP slots. +fn otp_status(args: Vec<String>) -> Result<()> { +  let mut all = false; +  let mut parser = argparse::ArgumentParser::new(); +  parser.set_description("Prints the status of the OTP slots"); +  let _ = parser.refer(&mut all).add_option( +    &["-a", "--all"], +    argparse::StoreTrue, +    "Show slots that are not programmed", +  ); +  parse(&parser, args)?; +  drop(parser); + +  commands::otp_status(all) +} +  /// Parse the command-line arguments and return the selected command and  /// the remaining arguments for the command.  fn parse_arguments(args: Vec<String>) -> Result<(Command, Vec<String>)> { diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs index 93e9bd3..3546e2e 100644 --- a/nitrocli/src/commands.rs +++ b/nitrocli/src/commands.rs @@ -333,6 +333,50 @@ pub fn otp_clear(slot: u8, algorithm: args::OtpAlgorithm) -> Result<()> {    Ok(())  } +fn print_otp_status( +  algorithm: args::OtpAlgorithm, +  device: &nitrokey::DeviceWrapper, +  all: bool, +) -> Result<()> { +  let mut slot: u8 = 0; +  loop { +    let result = match algorithm { +      args::OtpAlgorithm::Hotp => device.get_hotp_slot_name(slot), +      args::OtpAlgorithm::Totp => device.get_totp_slot_name(slot), +    }; +    slot = match slot.checked_add(1) { +      Some(slot) => slot, +      None => { +        return Err(Error::Error( +          "Integer overflow when iterating OTP slots".to_string(), +        )) +      } +    }; +    let name = match result { +      Ok(name) => name, +      Err(nitrokey::CommandError::InvalidSlot) => return Ok(()), +      Err(nitrokey::CommandError::SlotNotProgrammed) => { +        if all { +          "[not programmed]".to_string() +        } else { +          continue; +        } +      } +      Err(err) => return Err(get_error("Could not check OTP slot", &err)), +    }; +    println!("{}\t{}\t{}", algorithm, slot - 1, name); +  } +} + +/// Print the status of the OTP slots. +pub fn otp_status(all: bool) -> Result<()> { +  let device = get_device()?; +  println!("alg\tslot\tname"); +  print_otp_status(args::OtpAlgorithm::Hotp, &device, all)?; +  print_otp_status(args::OtpAlgorithm::Totp, &device, all)?; +  Ok(()) +} +  #[cfg(test)]  mod tests {    use super::*; | 
