diff options
-rw-r--r-- | nitrocli/src/arg_util.rs | 79 | ||||
-rw-r--r-- | nitrocli/src/args.rs | 427 | ||||
-rw-r--r-- | nitrocli/src/main.rs | 2 |
3 files changed, 152 insertions, 356 deletions
diff --git a/nitrocli/src/arg_util.rs b/nitrocli/src/arg_util.rs new file mode 100644 index 0000000..6dd14ed --- /dev/null +++ b/nitrocli/src/arg_util.rs @@ -0,0 +1,79 @@ +// arg_util.rs + +// ************************************************************************* +// * Copyright (C) 2019 Daniel Mueller (deso@posteo.net) * +// * * +// * This program is free software: you can redistribute it and/or modify * +// * it under the terms of the GNU General Public License as published by * +// * the Free Software Foundation, either version 3 of the License, or * +// * (at your option) any later version. * +// * * +// * This program is distributed in the hope that it will be useful, * +// * but WITHOUT ANY WARRANTY; without even the implied warranty of * +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +// * GNU General Public License for more details. * +// * * +// * You should have received a copy of the GNU General Public License * +// * along with this program. If not, see <http://www.gnu.org/licenses/>. * +// ************************************************************************* + +/// A macro for generating an enum with a set of simple (i.e., no +/// parameters) variants and their textual representations. +// TODO: Right now we hard code the derives we create. We may want to +// make this set configurable. +macro_rules! Enum { + ( $name:ident, [ $( $var:ident => $str:expr ), *] ) => { + #[derive(Clone, Copy, Debug, PartialEq)] + #[allow(unused)] + pub enum $name { + $( + $var, + )* + } + + impl AsRef<str> for $name { + fn as_ref(&self) -> &'static str { + match *self { + $( + $name::$var => $str, + )* + } + } + } + + impl ::std::fmt::Display for $name { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "{}", self.as_ref()) + } + } + + impl ::std::str::FromStr for $name { + type Err = (); + + fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> { + match s { + $( + $str => Ok($name::$var), + )* + _ => Err(()), + } + } + } + } +} + +#[cfg(test)] +mod tests { + Enum! {Command, [ + Var1 => "var1", + Var2 => "2", + Var3 => "crazy" + ]} + + #[test] + fn text_representations() { + assert_eq!(Command::Var1.as_ref(), "var1"); + assert_eq!(Command::Var2.as_ref(), "2"); + assert_eq!(Command::Var3.as_ref(), "crazy"); + } +} diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index 76b9766..8ce06e2 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -17,7 +17,6 @@ // * along with this program. If not, see <http://www.gnu.org/licenses/>. * // ************************************************************************* -use std::fmt; use std::io; use std::result; use std::str; @@ -29,38 +28,6 @@ use crate::RunCtx; type Result<T> = result::Result<T, Error>; -/// The available Nitrokey models. -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum DeviceModel { - Pro, - Storage, -} - -impl fmt::Display for DeviceModel { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - DeviceModel::Pro => "pro", - DeviceModel::Storage => "storage", - } - ) - } -} - -impl str::FromStr for DeviceModel { - type Err = (); - - fn from_str(s: &str) -> result::Result<Self, Self::Err> { - match s { - "pro" => Ok(DeviceModel::Pro), - "storage" => Ok(DeviceModel::Storage), - _ => Err(()), - } - } -} - trait Stdio { fn stdio(&mut self) -> (&mut dyn io::Write, &mut dyn io::Write); } @@ -86,22 +53,27 @@ impl<'io> Stdio for ExecCtx<'io> { } } +/// The available Nitrokey models. +Enum! {DeviceModel, [ + Pro => "pro", + Storage => "storage" +]} + /// A top-level command for nitrocli. -#[derive(Debug)] -pub enum Command { - Config, - Lock, - Otp, - Pin, - Pws, - Status, - Storage, -} +Enum! {Command, [ + Config => "config", + Lock => "lock", + Otp => "otp", + Pin => "pin", + Pws => "pws", + Status => "status", + Storage => "storage" +]} impl Command { /// Execute this command with the given arguments. - pub fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { - match *self { + pub fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { + match self { Command::Config => config(ctx, args), Command::Lock => lock(ctx, args), Command::Otp => otp(ctx, args), @@ -113,81 +85,20 @@ impl Command { } } -impl fmt::Display for Command { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - Command::Config => "config", - Command::Lock => "lock", - Command::Otp => "otp", - Command::Pin => "pin", - Command::Pws => "pws", - Command::Status => "status", - Command::Storage => "storage", - } - ) - } -} - -impl str::FromStr for Command { - type Err = (); - - fn from_str(s: &str) -> result::Result<Self, Self::Err> { - match s { - "config" => Ok(Command::Config), - "lock" => Ok(Command::Lock), - "otp" => Ok(Command::Otp), - "pin" => Ok(Command::Pin), - "pws" => Ok(Command::Pws), - "status" => Ok(Command::Status), - "storage" => Ok(Command::Storage), - _ => Err(()), - } - } -} - -#[derive(Debug)] -enum ConfigCommand { - Get, - Set, -} +Enum! {ConfigCommand, [ + Get => "get", + Set => "set" +]} impl ConfigCommand { - fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { - match *self { + fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { + match self { ConfigCommand::Get => config_get(ctx, args), ConfigCommand::Set => config_set(ctx, args), } } } -impl fmt::Display for ConfigCommand { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - ConfigCommand::Get => "get", - ConfigCommand::Set => "set", - } - ) - } -} - -impl str::FromStr for ConfigCommand { - type Err = (); - - fn from_str(s: &str) -> result::Result<Self, Self::Err> { - match s { - "get" => Ok(ConfigCommand::Get), - "set" => Ok(ConfigCommand::Set), - _ => Err(()), - } - } -} - #[derive(Clone, Copy, Debug)] pub enum ConfigOption<T> { Enable(T), @@ -223,17 +134,16 @@ impl<T> ConfigOption<T> { } } -#[derive(Debug)] -enum OtpCommand { - Clear, - Get, - Set, - Status, -} +Enum! {OtpCommand, [ + Clear => "clear", + Get => "get", + Set => "set", + Status => "status" +]} impl OtpCommand { - fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { - match *self { + fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { + match self { OtpCommand::Clear => otp_clear(ctx, args), OtpCommand::Get => otp_get(ctx, args), OtpCommand::Set => otp_set(ctx, args), @@ -242,96 +152,15 @@ impl OtpCommand { } } -impl fmt::Display for OtpCommand { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - OtpCommand::Clear => "clear", - OtpCommand::Get => "get", - OtpCommand::Set => "set", - OtpCommand::Status => "status", - } - ) - } -} - -impl str::FromStr for OtpCommand { - type Err = (); - - fn from_str(s: &str) -> result::Result<Self, Self::Err> { - match s { - "clear" => Ok(OtpCommand::Clear), - "get" => Ok(OtpCommand::Get), - "set" => Ok(OtpCommand::Set), - "status" => Ok(OtpCommand::Status), - _ => Err(()), - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum OtpAlgorithm { - Hotp, - Totp, -} - -impl fmt::Display for OtpAlgorithm { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - OtpAlgorithm::Hotp => "hotp", - OtpAlgorithm::Totp => "totp", - } - ) - } -} - -impl str::FromStr for OtpAlgorithm { - type Err = (); - - fn from_str(s: &str) -> result::Result<Self, Self::Err> { - match s { - "hotp" => Ok(OtpAlgorithm::Hotp), - "totp" => Ok(OtpAlgorithm::Totp), - _ => Err(()), - } - } -} - -#[derive(Clone, Copy, Debug)] -enum OtpMode { - SixDigits, - EightDigits, -} - -impl fmt::Display for OtpMode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - OtpMode::SixDigits => "6", - OtpMode::EightDigits => "8", - } - ) - } -} - -impl str::FromStr for OtpMode { - type Err = (); +Enum! {OtpAlgorithm, [ + Hotp => "hotp", + Totp => "totp" +]} - fn from_str(s: &str) -> result::Result<Self, Self::Err> { - match s { - "6" => Ok(OtpMode::SixDigits), - "8" => Ok(OtpMode::EightDigits), - _ => Err(()), - } - } -} +Enum! {OtpMode, [ + SixDigits => "6", + EightDigits => "8" +]} impl From<OtpMode> for nitrokey::OtpMode { fn from(mode: OtpMode) -> Self { @@ -342,50 +171,21 @@ impl From<OtpMode> for nitrokey::OtpMode { } } -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum OtpSecretFormat { - Ascii, - Base32, - Hex, -} - -impl fmt::Display for OtpSecretFormat { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - OtpSecretFormat::Ascii => "ascii", - OtpSecretFormat::Base32 => "base32", - OtpSecretFormat::Hex => "hex", - } - ) - } -} - -impl str::FromStr for OtpSecretFormat { - type Err = (); - - fn from_str(s: &str) -> result::Result<Self, Self::Err> { - match s { - "ascii" => Ok(OtpSecretFormat::Ascii), - "base32" => Ok(OtpSecretFormat::Base32), - "hex" => Ok(OtpSecretFormat::Hex), - _ => Err(()), - } - } -} +Enum! {OtpSecretFormat, [ + Ascii => "ascii", + Base32 => "base32", + Hex => "hex" +]} -#[derive(Debug)] -enum PinCommand { - Clear, - Set, - Unblock, -} +Enum! {PinCommand, [ + Clear => "clear", + Set => "set", + Unblock => "unblock" +]} impl PinCommand { - fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { - match *self { + fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { + match self { PinCommand::Clear => pin_clear(ctx, args), PinCommand::Set => pin_set(ctx, args), PinCommand::Unblock => pin_unblock(ctx, args), @@ -393,44 +193,16 @@ impl PinCommand { } } -impl fmt::Display for PinCommand { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - PinCommand::Clear => "clear", - PinCommand::Set => "set", - PinCommand::Unblock => "unblock", - } - ) - } -} - -impl str::FromStr for PinCommand { - type Err = (); - - fn from_str(s: &str) -> result::Result<Self, Self::Err> { - match s { - "clear" => Ok(PinCommand::Clear), - "set" => Ok(PinCommand::Set), - "unblock" => Ok(PinCommand::Unblock), - _ => Err(()), - } - } -} - -#[derive(Debug)] -enum PwsCommand { - Clear, - Get, - Set, - Status, -} +Enum! {PwsCommand, [ + Clear => "clear", + Get => "get", + Set => "set", + Status => "status" +]} impl PwsCommand { - fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { - match *self { + fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { + match self { PwsCommand::Clear => pws_clear(ctx, args), PwsCommand::Get => pws_get(ctx, args), PwsCommand::Set => pws_set(ctx, args), @@ -439,35 +211,6 @@ impl PwsCommand { } } -impl fmt::Display for PwsCommand { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - PwsCommand::Clear => "clear", - PwsCommand::Get => "get", - PwsCommand::Set => "set", - PwsCommand::Status => "status", - } - ) - } -} - -impl str::FromStr for PwsCommand { - type Err = (); - - fn from_str(s: &str) -> result::Result<Self, Self::Err> { - match s { - "clear" => Ok(PwsCommand::Clear), - "get" => Ok(PwsCommand::Get), - "set" => Ok(PwsCommand::Set), - "status" => Ok(PwsCommand::Status), - _ => Err(()), - } - } -} - fn parse( ctx: &mut impl Stdio, parser: &argparse::ArgumentParser<'_>, @@ -490,16 +233,15 @@ fn status(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { commands::status(ctx) } -#[derive(Debug)] -enum StorageCommand { - Close, - Open, - Status, -} +Enum! {StorageCommand, [ + Close => "close", + Open => "open", + Status => "status" +]} impl StorageCommand { - fn execute(&self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { - match *self { + fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { + match self { StorageCommand::Close => storage_close(ctx, args), StorageCommand::Open => storage_open(ctx, args), StorageCommand::Status => storage_status(ctx, args), @@ -507,33 +249,6 @@ impl StorageCommand { } } -impl fmt::Display for StorageCommand { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - StorageCommand::Close => "close", - StorageCommand::Open => "open", - StorageCommand::Status => "status", - } - ) - } -} - -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), - "status" => Ok(StorageCommand::Status), - _ => Err(()), - } - } -} - /// Execute a storage subcommand. fn storage(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { let mut subcommand = StorageCommand::Open; @@ -554,7 +269,7 @@ fn storage(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { parse(ctx, &parser, args)?; drop(parser); - subargs.insert(0, format!("nitrocli storage {}", subcommand)); + subargs.insert(0, format!("nitrocli {} {}", Command::Storage, subcommand)); subcommand.execute(ctx, subargs) } @@ -605,7 +320,7 @@ fn config(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { parse(ctx, &parser, args)?; drop(parser); - subargs.insert(0, format!("nitrocli config {}", subcommand)); + subargs.insert(0, format!("nitrocli {} {}", Command::Config, subcommand)); subcommand.execute(ctx, subargs) } @@ -715,7 +430,7 @@ fn otp(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { parse(ctx, &parser, args)?; drop(parser); - subargs.insert(0, format!("nitrocli otp {}", subcommand)); + subargs.insert(0, format!("nitrocli {} {}", Command::Otp, subcommand)); subcommand.execute(ctx, subargs) } @@ -892,7 +607,7 @@ fn pin(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { parse(ctx, &parser, args)?; drop(parser); - subargs.insert(0, format!("nitrocli pin {}", subcommand)); + subargs.insert(0, format!("nitrocli {} {}", Command::Pin, subcommand)); subcommand.execute(ctx, subargs) } @@ -950,7 +665,7 @@ fn pws(ctx: &mut ExecCtx<'_>, args: Vec<String>) -> Result<()> { parse(ctx, &parser, args)?; drop(parser); - subargs.insert(0, format!("nitrocli pws {}", subcommand)); + subargs.insert(0, format!("nitrocli {} {}", Command::Pws, subcommand)); subcommand.execute(ctx, subargs) } diff --git a/nitrocli/src/main.rs b/nitrocli/src/main.rs index a9e31f8..9f56f75 100644 --- a/nitrocli/src/main.rs +++ b/nitrocli/src/main.rs @@ -70,6 +70,8 @@ #[macro_use] mod redefine; +#[macro_use] +mod arg_util; mod args; mod commands; |