diff options
author | Robin Krahl <robin.krahl@ireas.org> | 2018-12-23 02:08:47 +0100 |
---|---|---|
committer | Daniel Mueller <deso@posteo.net> | 2018-12-24 18:15:28 -0800 |
commit | 1630c7872631f5f7e5bab599121df1fed26e47da (patch) | |
tree | d831a9029f970731534cfdef9c05bb9196fe096a /nitrocli/src/args.rs | |
parent | 86b3170b1dd4c1955e540f5c914a317302754be1 (diff) | |
download | nitrocli-1630c7872631f5f7e5bab599121df1fed26e47da.tar.gz nitrocli-1630c7872631f5f7e5bab599121df1fed26e47da.tar.bz2 |
Implement the otp set subcommand
This patch implements the `otp set` subcommand that configures an OTP
slot. There are two ways to specify an OTP secret: as a hexadecimal
string (that means that every two characters are interpreted as a
hexadecimal representation of one byte of the secret) or as an ASCII
string (that means that the ASCII code of every character is interpreted
as one byte of the secret). As the HOTP RFC mentions both
representations, this implementation supports both.
Diffstat (limited to 'nitrocli/src/args.rs')
-rw-r--r-- | nitrocli/src/args.rs | 112 |
1 files changed, 111 insertions, 1 deletions
diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index f4035e6..c27fbc2 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -84,12 +84,14 @@ impl str::FromStr for Command { #[derive(Debug)] enum OtpCommand { Get, + Set, } impl OtpCommand { fn execute(&self, args: Vec<String>) -> Result<()> { match *self { OtpCommand::Get => otp_get(args), + OtpCommand::Set => otp_set(args), } } } @@ -101,6 +103,7 @@ impl fmt::Display for OtpCommand { "{}", match *self { OtpCommand::Get => "get", + OtpCommand::Set => "set", } ) } @@ -112,6 +115,7 @@ impl str::FromStr for OtpCommand { fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { match s { "get" => Ok(OtpCommand::Get), + "set" => Ok(OtpCommand::Set), _ => Err(()), } } @@ -148,6 +152,46 @@ impl str::FromStr for OtpAlgorithm { } } +#[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 = (); + + fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { + match s { + "6" => Ok(OtpMode::SixDigits), + "8" => Ok(OtpMode::EightDigits), + _ => Err(()), + } + } +} + +impl From<OtpMode> for nitrokey::OtpMode { + fn from(mode: OtpMode) -> Self { + match mode { + OtpMode::SixDigits => nitrokey::OtpMode::SixDigits, + OtpMode::EightDigits => nitrokey::OtpMode::EightDigits, + } + } +} + fn parse(parser: &argparse::ArgumentParser<'_>, args: Vec<String>) -> Result<()> { if let Err(err) = parser.parse(args, &mut io::stdout(), &mut io::stderr()) { Err(Error::ArgparseError(err)) @@ -201,7 +245,7 @@ fn otp(args: Vec<String>) -> Result<()> { let _ = parser.refer(&mut subcommand).required().add_argument( "subcommand", argparse::Store, - "The subcommand to execute (get)", + "The subcommand to execute (get|set)", ); let _ = parser.refer(&mut subargs).add_argument( "arguments", @@ -238,6 +282,72 @@ fn otp_get(args: Vec<String>) -> Result<()> { commands::otp_get(slot, algorithm) } +/// Configure a one-time password slot on the Nitrokey device. +pub fn otp_set(args: Vec<String>) -> Result<()> { + let mut slot: u8 = 0; + let mut algorithm = OtpAlgorithm::Totp; + let mut name = "".to_owned(); + let mut secret = "".to_owned(); + let mut digits = OtpMode::SixDigits; + let mut counter: u64 = 0; + let mut time_window: u16 = 30; + let mut ascii = false; + let mut parser = argparse::ArgumentParser::new(); + parser.set_description("Configures a one-time password slot"); + let _ = + parser + .refer(&mut slot) + .required() + .add_argument("slot", argparse::Store, "The OTP slot to use"); + let _ = parser.refer(&mut algorithm).add_option( + &["-a", "--algorithm"], + argparse::Store, + "The OTP algorithm to use (hotp or totp, default: totp", + ); + let _ = parser.refer(&mut name).required().add_argument( + "name", + argparse::Store, + "The name of the slot", + ); + let _ = parser.refer(&mut secret).required().add_argument( + "secret", + argparse::Store, + "The secret to store on the slot as a hexadecimal string (unless --ascii is set)", + ); + let _ = parser.refer(&mut digits).add_option( + &["-d", "--digits"], + argparse::Store, + "The number of digits to use for the one-time password (6 or 8, default: 6)", + ); + let _ = parser.refer(&mut counter).add_option( + &["-c", "--counter"], + argparse::Store, + "The counter value for HOTP (default: 0)", + ); + let _ = parser.refer(&mut time_window).add_option( + &["-t", "--time-window"], + argparse::Store, + "The time window for TOTP (default: 30)", + ); + let _ = parser.refer(&mut ascii).add_option( + &["--ascii"], + argparse::StoreTrue, + "Interpret the given secret as an ASCII string of the secret", + ); + parse(&parser, args)?; + drop(parser); + + let data = nitrokey::OtpSlotData { + number: slot, + name, + secret, + mode: nitrokey::OtpMode::from(digits), + use_enter: false, + token_id: None, + }; + commands::otp_set(data, algorithm, counter, time_window, ascii) +} + /// 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>)> { |