diff options
| -rw-r--r-- | nitrocli/CHANGELOG.md | 2 | ||||
| -rw-r--r-- | nitrocli/README.md | 9 | ||||
| -rw-r--r-- | nitrocli/doc/nitrocli.1 | 19 | ||||
| -rw-r--r-- | nitrocli/src/args.rs | 88 | ||||
| -rw-r--r-- | nitrocli/src/commands.rs | 4 | ||||
| -rw-r--r-- | nitrocli/src/main.rs | 2 | 
6 files changed, 95 insertions, 29 deletions
| diff --git a/nitrocli/CHANGELOG.md b/nitrocli/CHANGELOG.md index 682995a..813f853 100644 --- a/nitrocli/CHANGELOG.md +++ b/nitrocli/CHANGELOG.md @@ -8,6 +8,8 @@ Unreleased    - Removed the `hid`, `hidapi-sys` and `pkg-config` dependencies  - Added the `otp` command for working with one-time passwords  - Added the `config` command for reading and writing the device configuration +- Moved `open` and `close` commands as subcommands into newly introduced +  `storage` command  - Made `status` command work with Nitrokey Pro devices  - Enabled CI pipeline comprising code style conformance checks, linting,    and building of the project diff --git a/nitrocli/README.md b/nitrocli/README.md index 3e0b518..b28f09e 100644 --- a/nitrocli/README.md +++ b/nitrocli/README.md @@ -11,10 +11,11 @@ nitrocli  certain commands on the [Nitrokey Storage][nitrokey-storage] device.  The following commands are currently supported: -- open: Open the encrypted volume. The user PIN needs to be entered. -- close: Close the encrypted volume.  - status: Report status information about the Nitrokey.  - clear: Remove the user and admin PIN from gpg-agent's cache. +- storage: Work with the Nitrokey's storage. +  - open: Open the encrypted volume. The user PIN needs to be entered. +  - close: Close the encrypted volume.  - otp: Access one-time passwords (OTP).    - get: Generate a one-time password.    - set: Set an OTP slot. @@ -38,7 +39,7 @@ parameter (note that some commands are organized through subcommands,  which are required as well), e.g.:  ```bash  # Open the nitrokey's encrypted volume. -$ nitrocli open +$ nitrocli storage open  $ nitrocli status  Status: @@ -57,7 +58,7 @@ Status:      hidden:          inactive  # Close it again. -$ nitrocli close +$ nitrocli storage close  ``` diff --git a/nitrocli/doc/nitrocli.1 b/nitrocli/doc/nitrocli.1 index e345cdb..44d41fd 100644 --- a/nitrocli/doc/nitrocli.1 +++ b/nitrocli/doc/nitrocli.1 @@ -12,14 +12,6 @@ It can be used to access the encrypted volume and the one-time password generato  .SH COMMANDS  .SS General  .TP -.B nitrocli open -Open the encrypted volume on the Nitrokey Storage. -The user PIN that is required to open the volume is queried using  -\fBpinentry\fR(1) and cached by \fBgpg-agent\fR(1). -.TP -.B nitrocli close -Close the encrypted volume on the Nitrokey Storage. -.TP  .B nitrocli status  Print the status of the connected Nitrokey device, including the stick serial  number, SD card serial number, the firmware version and the PIN retry count. @@ -28,6 +20,17 @@ of the volumes.  .TP  .B nitrocli clear  Clear the passphrases cached by the other commands. + +.SS Storage +.TP +\fBnitrocli storage open +Open the encrypted volume on the Nitrokey Storage. +The user PIN that is required to open the volume is queried using +\fBpinentry\fR(1) and cached by \fBgpg-agent\fR(1). +.TP +\fBnitrocli storage close +Close the encrypted volume on the Nitrokey Storage. +  .SS One-time passwords  .TP  \fBnitrocli otp get \fIslot \fR[\fB-a\fR|\fB--algorithm \fIalgorithm\fR] diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index 36da560..d7a6d25 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -31,11 +31,10 @@ type Result<T> = result::Result<T, Error>;  #[derive(Debug)]  pub enum Command {    Clear, -  Close,    Config, -  Open,    Otp,    Status, +  Storage,  }  impl Command { @@ -43,11 +42,10 @@ impl Command {    pub fn execute(&self, args: Vec<String>) -> Result<()> {      match *self {        Command::Clear => clear(args), -      Command::Close => close(args),        Command::Config => config(args), -      Command::Open => open(args),        Command::Otp => otp(args),        Command::Status => status(args), +      Command::Storage => storage(args),      }    }  } @@ -59,11 +57,10 @@ impl fmt::Display for Command {        "{}",        match *self {          Command::Clear => "clear", -        Command::Close => "close",          Command::Config => "config", -        Command::Open => "open",          Command::Otp => "otp",          Command::Status => "status", +        Command::Storage => "storage",        }      )    } @@ -75,11 +72,10 @@ impl str::FromStr for Command {    fn from_str(s: &str) -> result::Result<Self, Self::Err> {      match s {        "clear" => Ok(Command::Clear), -      "close" => Ok(Command::Close),        "config" => Ok(Command::Config), -      "open" => Ok(Command::Open),        "otp" => Ok(Command::Otp),        "status" => Ok(Command::Status), +      "storage" => Ok(Command::Storage),        _ => Err(()),      }    } @@ -297,24 +293,88 @@ fn status(args: Vec<String>) -> Result<()> {  }  /// Open the encrypted volume on the nitrokey. -fn open(args: Vec<String>) -> Result<()> { +fn storage_open(args: Vec<String>) -> Result<()> {    let mut parser = argparse::ArgumentParser::new();    parser.set_description("Opens the encrypted volume on a Nitrokey Storage");    parse(&parser, args)?; -  commands::open() +  commands::storage_open()  }  /// Close the previously opened encrypted volume. -fn close(args: Vec<String>) -> Result<()> { +fn storage_close(args: Vec<String>) -> Result<()> {    let mut parser = argparse::ArgumentParser::new();    parser.set_description("Closes the encrypted volume on a Nitrokey Storage");    parse(&parser, args)?; -  commands::close() +  commands::storage_close() +} + +#[derive(Debug)] +enum StorageCommand { +  Close, +  Open, +} + +impl StorageCommand { +  fn execute(&self, args: Vec<String>) -> Result<()> { +    match *self { +      StorageCommand::Close => storage_close(args), +      StorageCommand::Open => storage_open(args), +    } +  } +} + +impl fmt::Display for StorageCommand { +  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +    write!( +      f, +      "{}", +      match *self { +        StorageCommand::Close => "close", +        StorageCommand::Open => "open", +      } +    ) +  } +} + +impl str::FromStr for StorageCommand { +  type Err = (); + +  fn from_str(s: &str) -> result::Result<Self, Self::Err> { +    match s { +      "close" => Ok(StorageCommand::Close), +      "open" => Ok(StorageCommand::Open), +      _ => Err(()), +    } +  } +} + +/// Execute a storage subcommand. +fn storage(args: Vec<String>) -> Result<()> { +  let mut subcommand = StorageCommand::Open; +  let mut subargs = vec![]; +  let mut parser = argparse::ArgumentParser::new(); +  parser.set_description("Interacts with the device's storage"); +  let _ = parser.refer(&mut subcommand).required().add_argument( +    "subcommand", +    argparse::Store, +    "The subcommand to execute (open|close)", +  ); +  let _ = parser.refer(&mut subargs).add_argument( +    "arguments", +    argparse::List, +    "The arguments for the subcommand", +  ); +  parser.stop_on_first_argument(true); +  parse(&parser, args)?; +  drop(parser); + +  subargs.insert(0, format!("nitrocli storage {}", subcommand)); +  subcommand.execute(subargs)  } -/// Clear the PIN stored when opening the nitrokey's encrypted volume. +/// Clear the PIN as cached by various other commands.  fn clear(args: Vec<String>) -> Result<()> {    let mut parser = argparse::ArgumentParser::new();    parser.set_description("Clears the cached passphrases"); @@ -584,7 +644,7 @@ fn parse_arguments(args: Vec<String>) -> Result<(Command, Vec<String>)> {    let _ = parser.refer(&mut command).required().add_argument(      "command",      argparse::Store, -    "The command to execute (clear|close|config|open|otp|status)", +    "The command to execute (clear|config|otp|status|storage)",    );    let _ = parser.refer(&mut subargs).add_argument(      "arguments", diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs index 9aef2de..fdfe049 100644 --- a/nitrocli/src/commands.rs +++ b/nitrocli/src/commands.rs @@ -243,7 +243,7 @@ pub fn status() -> Result<()> {  }  /// Open the encrypted volume on the nitrokey. -pub fn open() -> Result<()> { +pub fn storage_open() -> Result<()> {    let device = get_storage_device()?;    try_with_passphrase(      pinentry::PinType::User, @@ -258,7 +258,7 @@ extern "C" {  }  /// Close the previously opened encrypted volume. -pub fn close() -> Result<()> { +pub fn storage_close() -> Result<()> {    // Flush all filesystem caches to disk. We are mostly interested in    // making sure that the encrypted volume on the nitrokey we are    // about to close is not closed while not all data was written to diff --git a/nitrocli/src/main.rs b/nitrocli/src/main.rs index 8a20494..4f39fdb 100644 --- a/nitrocli/src/main.rs +++ b/nitrocli/src/main.rs @@ -66,7 +66,7 @@  )]  //! Nitrocli is a program providing a command line interface to certain -//! commands of the Nitrokey Storage device. +//! commands of Nitrokey Pro and Storage devices.  mod args;  mod commands; | 
