From b9fbc489819a111f21eecb2b9a07a931dca1b8ce Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 7 Jan 2020 12:12:39 +0000 Subject: Add data structures for the options and arguments This patch introduces new structs that can be used with structopt to store the options and arguments parsed from the command line. These structs use the existing enums and command structs. --- src/args.rs | 338 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 301 insertions(+), 37 deletions(-) diff --git a/src/args.rs b/src/args.rs index 4ab332e..d25bc15 100644 --- a/src/args.rs +++ b/src/args.rs @@ -101,6 +101,20 @@ impl<'io> Stdio for ExecCtx<'io> { } } +/// Provides access to a Nitrokey device +#[derive(structopt::StructOpt)] +#[structopt(name = "nitrocli")] +pub struct Args { + /// Increases the log level (can be supplied multiple times) + #[structopt(short, long, parse(from_occurrences))] + verbose: u8, + /// Selects the device model to connect to + #[structopt(short, long)] + model: Option, + #[structopt(subcommand)] + cmd: Command, +} + /// The available Nitrokey models. #[allow(unused_doc_comments)] Enum! {DeviceModel, [ @@ -129,21 +143,271 @@ impl From for nitrokey::Model { /// A top-level command for nitrocli. #[allow(unused_doc_comments)] Command! {Command, [ - Config => ("config", config), - Encrypted => ("encrypted", encrypted), - Hidden => ("hidden", hidden), - Lock => ("lock", lock), - Otp => ("otp", otp), - Pin => ("pin", pin), - Pws => ("pws", pws), - Reset => ("reset", reset), - Status => ("status", status), - Unencrypted => ("unencrypted", unencrypted), + Config(ConfigArgs) => ("config", config), + Encrypted(EncryptedArgs) => ("encrypted", encrypted), + Hidden(HiddenArgs) => ("hidden", hidden), + Lock(LockArgs) => ("lock", lock), + Otp(OtpArgs) => ("otp", otp), + Pin(PinArgs) => ("pin", pin), + Pws(PwsArgs) => ("pws", pws), + Reset(ResetArgs) => ("reset", reset), + Status(StatusArgs) => ("status", status), + Unencrypted(UnencryptedArgs) => ("unencrypted", unencrypted), ]} +/// Reads or writes the device configuration +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct ConfigArgs { + #[structopt(subcommand)] + subcmd: ConfigCommand, +} + +/// Prints the Nitrokey configuration +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct ConfigGetArgs {} + +/// Changes the Nitrokey configuration +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct ConfigSetArgs { + /// Sets the numlock option to the given HOTP slot + #[structopt(short = "n", long)] + numlock: Option, + /// Unsets the numlock option + #[structopt(short = "N", long, conflicts_with("numlock"))] + no_numlock: bool, + /// Sets the capslock option to the given HOTP slot + #[structopt(short = "c", long)] + capslock: Option, + /// Unsets the capslock option + #[structopt(short = "C", long, conflicts_with("capslock"))] + no_capslock: bool, + /// Sets the scrollock option to the given HOTP slot + #[structopt(short = "s", long)] + scrollock: Option, + /// Unsets the scrollock option + #[structopt(short = "S", long, conflicts_with("scrollock"))] + no_scrollock: bool, + /// Requires the user PIN to generate one-time passwords + #[structopt(short = "o", long)] + otp_pin: bool, + /// Allows one-time password generation without PIN + #[structopt(short = "O", long, conflicts_with("otp_pin"))] + no_otp_pin: bool, +} + +/// Interacts with the device's encrypted volume +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct EncryptedArgs { + #[structopt(subcommand)] + subcmd: EncryptedCommand, +} + +/// Closes the encrypted volume on a Nitrokey Storage +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct EncryptedCloseArgs {} + +/// Opens the encrypted volume on a Nitrokey Storage +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct EncryptedOpenArgs {} + +/// Interacts with the device's hidden volume +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct HiddenArgs { + #[structopt(subcommand)] + subcmd: HiddenCommand, +} + +/// Closes the hidden volume on a Nitrokey Storage +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct HiddenCloseArgs {} + +/// Creates a hidden volume on a Nitrokey Storage +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct HiddenCreateArgs { + /// The hidden volume slot to use + slot: u8, + /// The start location of the hidden volume as a percentage of the encrypted volume's size (0-99) + start: u8, + /// The end location of the hidden volume as a percentage of the encrypted volume's size (1-100) + end: u8, +} + +/// Opens the hidden volume on a Nitrokey Storage +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct HiddenOpenArgs {} + +/// Locks the connected Nitrokey device +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct LockArgs {} + +/// Accesses one-time passwords +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct OtpArgs { + #[structopt(subcommand)] + subcmd: OtpCommand, +} + +/// Clears a one-time password slot +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct OtpClearArgs { + /// The OTP algorithm to use + #[structopt(short, long, default_value = "totp")] + algorithm: OtpAlgorithm, + /// The OTP slot to clear + slot: u8, +} + +/// Generates a one-time password +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct OtpGetArgs { + /// The OTP algorithm to use + #[structopt(short, long, default_value = "totp")] + algorithm: OtpAlgorithm, + /// The time to use for TOTP generation (Unix timestamp) [default: system time] + #[structopt(short, long)] + time: Option, + /// The OTP slot to use + slot: u8, +} + +/// Configures a one-time password slot +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct OtpSetArgs { + /// The OTP algorithm to use + #[structopt(short, long, default_value = "totp")] + algorithm: OtpAlgorithm, + /// The number of digits to use for the one-time password + #[structopt(short, long, default_value = "6")] + digits: OtpMode, + /// The counter value for HOTP + #[structopt(short, long, default_value = "0")] + counter: u64, + /// The time window for TOTP + #[structopt(short, long, default_value = "30")] + time_window: u16, + /// The format of the secret + #[structopt(short, long, default_value = "hex")] + format: OtpSecretFormat, + /// The OTP slot to use + slot: u8, + /// The name of the slot + name: String, + /// The secret to store on the slot as a hexadecimal string (or in the format set with the + /// --format option) + secret: String, +} + +/// Prints the status of the one-time password slots +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct OtpStatusArgs { + /// Shows slots that are not programmed + #[structopt(short, long)] + all: bool, +} + +/// Manages the Nitrokey PINs +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct PinArgs { + #[structopt(subcommand)] + subcmd: PinCommand, +} + +/// Clears the cached PINs +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct PinClearArgs {} + +/// Changes a PIN +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct PinSetArgs { + /// The PIN type to change + #[structopt(name = "type")] + pintype: pinentry::PinType, +} + +/// Unblocks and resets the user PIN +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct PinUnblockArgs {} + +/// Accesses the password safe +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct PwsArgs { + #[structopt(subcommand)] + subcmd: PwsCommand, +} + +/// Clears a password safe slot +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct PwsClearArgs { + /// The PWS slot to clear + slot: u8, +} + +/// Reads a password safe slot +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct PwsGetArgs { + /// Shows the name stored on the slot + #[structopt(short, long)] + name: bool, + /// Shows the login stored on the slot + #[structopt(short, long)] + login: bool, + /// Shows the password stored on the slot + #[structopt(short, long)] + password: bool, + /// Prints the stored data without description + #[structopt(short, long)] + quiet: bool, + /// The PWS slot to read + slot: u8, +} + +/// Writes a password safe slot +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct PwsSetArgs { + /// The PWS slot to write + slot: u8, + /// The name to store on the slot + name: String, + /// The login to store on the slot + login: String, + /// The password to store on the slot + password: String, +} + +/// Prints the status of the password safe slots +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct PwsStatusArgs { + /// Shows slots that are not programmed + #[structopt(short, long)] + all: bool, +} + +/// Performs a factory reset +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct ResetArgs {} + +/// Prints the status of the connected Nitrokey device +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct StatusArgs {} + +/// Interacts with the device's unencrypted volume +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct UnencryptedArgs { + #[structopt(subcommand)] + subcmd: UnencryptedCommand, +} + +/// Changes the configuration of the unencrypted volume on a Nitrokey Storage +#[derive(Debug, Default, PartialEq, structopt::StructOpt)] +pub struct UnencryptedSetArgs { + /// The mode to change to + #[structopt(name = "type")] + mode: UnencryptedVolumeMode, +} + Command! {ConfigCommand, [ - Get => ("get", config_get), - Set => ("set", config_set), + Get(ConfigGetArgs) => ("get", config_get), + Set(ConfigSetArgs) => ("set", config_set), ]} #[derive(Clone, Copy, Debug)] @@ -182,10 +446,10 @@ impl ConfigOption { } Command! {OtpCommand, [ - Clear => ("clear", otp_clear), - Get => ("get", otp_get), - Set => ("set", otp_set), - Status => ("status", otp_status), + Clear(OtpClearArgs) => ("clear", otp_clear), + Get(OtpGetArgs) => ("get", otp_get), + Set(OtpSetArgs) => ("set", otp_set), + Status(OtpStatusArgs) => ("status", otp_status), ]} Enum! {OtpAlgorithm, [ @@ -214,16 +478,16 @@ Enum! {OtpSecretFormat, [ ]} Command! {PinCommand, [ - Clear => ("clear", pin_clear), - Set => ("set", pin_set), - Unblock => ("unblock", pin_unblock), + Clear(PinClearArgs) => ("clear", pin_clear), + Set(PinSetArgs) => ("set", pin_set), + Unblock(PinUnblockArgs) => ("unblock", pin_unblock), ]} Command! {PwsCommand, [ - Clear => ("clear", pws_clear), - Get => ("get", pws_get), - Set => ("set", pws_set), - Status => ("status", pws_status), + Clear(PwsClearArgs) => ("clear", pws_clear), + Get(PwsGetArgs) => ("get", pws_get), + Set(PwsSetArgs) => ("set", pws_set), + Status(PwsStatusArgs) => ("status", pws_status), ]} fn parse( @@ -258,7 +522,7 @@ fn reset(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { } Command! {UnencryptedCommand, [ - Set => ("set", unencrypted_set), + Set(UnencryptedSetArgs) => ("set", unencrypted_set), ]} Enum! {UnencryptedVolumeMode, [ @@ -268,7 +532,7 @@ Enum! {UnencryptedVolumeMode, [ /// Execute an unencrypted subcommand. fn unencrypted(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = UnencryptedCommand::Set; + let mut subcommand = UnencryptedCommand::Set(Default::default()); let help = "".to_string(); let mut subargs = vec![]; let mut parser = argparse::ArgumentParser::new(); @@ -310,13 +574,13 @@ fn unencrypted_set(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { } Command! {EncryptedCommand, [ - Close => ("close", encrypted_close), - Open => ("open", encrypted_open), + Close(EncryptedCloseArgs) => ("close", encrypted_close), + Open(EncryptedOpenArgs) => ("open", encrypted_open), ]} /// Execute an encrypted subcommand. fn encrypted(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = EncryptedCommand::Open; + let mut subcommand = EncryptedCommand::Open(Default::default()); let help = "".to_string(); let mut subargs = vec![]; let mut parser = argparse::ArgumentParser::new(); @@ -360,14 +624,14 @@ fn encrypted_close(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { } Command! {HiddenCommand, [ - Close => ("close", hidden_close), - Create => ("create", hidden_create), - Open => ("open", hidden_open), + Close(HiddenCloseArgs) => ("close", hidden_close), + Create(HiddenCreateArgs) => ("create", hidden_create), + Open(HiddenOpenArgs) => ("open", hidden_open), ]} /// Execute a hidden subcommand. fn hidden(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = HiddenCommand::Open; + let mut subcommand = HiddenCommand::Open(Default::default()); let help = "".to_string(); let mut subargs = vec![]; let mut parser = argparse::ArgumentParser::new(); @@ -438,7 +702,7 @@ fn hidden_close(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { /// Execute a config subcommand. fn config(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = ConfigCommand::Get; + let mut subcommand = ConfigCommand::Get(Default::default()); let help = "".to_string(); let mut subargs = vec![]; let mut parser = argparse::ArgumentParser::new(); @@ -550,7 +814,7 @@ fn lock(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { /// Execute an OTP subcommand. fn otp(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = OtpCommand::Get; + let mut subcommand = OtpCommand::Get(Default::default()); let help = "".to_string(); let mut subargs = vec![]; let mut parser = argparse::ArgumentParser::new(); @@ -716,7 +980,7 @@ fn otp_status(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { /// Execute a PIN subcommand. fn pin(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = PinCommand::Clear; + let mut subcommand = PinCommand::Clear(Default::default()); let help = "".to_string(); let mut subargs = vec![]; let mut parser = argparse::ArgumentParser::new(); @@ -773,7 +1037,7 @@ fn pin_unblock(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { /// Execute a PWS subcommand. fn pws(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = PwsCommand::Get; + let mut subcommand = PwsCommand::Get(Default::default()); let mut subargs = vec![]; let help = "".to_string(); let mut parser = argparse::ArgumentParser::new(); @@ -908,7 +1172,7 @@ pub(crate) fn handle_arguments(ctx: &mut RunCtx<'_>, args: Vec) -> Resul fmt_enum!(DeviceModel::all_variants()) ); let mut verbosity = 0; - let mut command = Command::Status; + let mut command = Command::Status(Default::default()); let cmd_help = "".to_string(); let mut subargs = vec![]; let mut parser = argparse::ArgumentParser::new(); -- cgit v1.2.3