From 681cc8882f7995407c33eb48730daaa901074460 Mon Sep 17 00:00:00 2001 From: Daniel Mueller Date: Sat, 4 Apr 2020 15:32:14 -0700 Subject: Move nitrocli source code into repository root Now that all vendored dependencies have been removed, this change moves the program's source code from the nitrocli/ directory into the root of the repository. --- nitrocli/src/args.rs | 984 --------------------------------------------------- 1 file changed, 984 deletions(-) delete mode 100644 nitrocli/src/args.rs (limited to 'nitrocli/src/args.rs') diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs deleted file mode 100644 index 9f4cae2..0000000 --- a/nitrocli/src/args.rs +++ /dev/null @@ -1,984 +0,0 @@ -// args.rs - -// ************************************************************************* -// * Copyright (C) 2018-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 . * -// ************************************************************************* - -use std::ffi; -use std::io; -use std::result; -use std::str; - -use crate::commands; -use crate::error::Error; -use crate::pinentry; -use crate::RunCtx; - -type Result = result::Result; - -/// Wraps a writer and buffers its output. -/// -/// This implementation is similar to `io::BufWriter`, but: -/// - The inner writer is only written to if `flush` is called. -/// - The buffer may grow infinitely large. -struct BufWriter<'w, W: io::Write + ?Sized> { - buf: Vec, - inner: &'w mut W, -} - -impl<'w, W: io::Write + ?Sized> BufWriter<'w, W> { - pub fn new(inner: &'w mut W) -> Self { - BufWriter { - buf: Vec::with_capacity(128), - inner, - } - } -} - -impl<'w, W: io::Write + ?Sized> io::Write for BufWriter<'w, W> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.buf.extend_from_slice(buf); - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.write_all(&self.buf)?; - self.buf.clear(); - self.inner.flush() - } -} - -trait Stdio { - fn stdio(&mut self) -> (&mut dyn io::Write, &mut dyn io::Write); -} - -impl<'io> Stdio for RunCtx<'io> { - fn stdio(&mut self) -> (&mut dyn io::Write, &mut dyn io::Write) { - (self.stdout, self.stderr) - } -} - -impl Stdio for (&mut W, &mut W) -where - W: io::Write, -{ - fn stdio(&mut self) -> (&mut dyn io::Write, &mut dyn io::Write) { - (self.0, self.1) - } -} - -/// A command execution context that captures additional data pertaining -/// the command execution. -pub struct ExecCtx<'io> { - pub model: Option, - pub stdout: &'io mut dyn io::Write, - pub stderr: &'io mut dyn io::Write, - pub admin_pin: Option, - pub user_pin: Option, - pub new_admin_pin: Option, - pub new_user_pin: Option, - pub password: Option, - pub no_cache: bool, - pub verbosity: u64, -} - -impl<'io> Stdio for ExecCtx<'io> { - fn stdio(&mut self) -> (&mut dyn io::Write, &mut dyn io::Write) { - (self.stdout, self.stderr) - } -} - -/// The available Nitrokey models. -#[allow(unused_doc_comments)] -Enum! {DeviceModel, [ - Pro => "pro", - Storage => "storage", -]} - -impl DeviceModel { - pub fn as_user_facing_str(&self) -> &str { - match self { - DeviceModel::Pro => "Pro", - DeviceModel::Storage => "Storage", - } - } -} - -impl From for nitrokey::Model { - fn from(model: DeviceModel) -> nitrokey::Model { - match model { - DeviceModel::Pro => nitrokey::Model::Pro, - DeviceModel::Storage => nitrokey::Model::Storage, - } - } -} - -/// A top-level command for nitrocli. -#[allow(unused_doc_comments)] -Enum! {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), -]} - -Enum! {ConfigCommand, [ - Get => ("get", config_get), - Set => ("set", config_set), -]} - -#[derive(Clone, Copy, Debug)] -pub enum ConfigOption { - Enable(T), - Disable, - Ignore, -} - -impl ConfigOption { - fn try_from(disable: bool, value: Option, name: &'static str) -> Result { - if disable { - if value.is_some() { - Err(Error::Error(format!( - "--{name} and --no-{name} are mutually exclusive", - name = name - ))) - } else { - Ok(ConfigOption::Disable) - } - } else { - match value { - Some(value) => Ok(ConfigOption::Enable(value)), - None => Ok(ConfigOption::Ignore), - } - } - } - - pub fn or(self, default: Option) -> Option { - match self { - ConfigOption::Enable(value) => Some(value), - ConfigOption::Disable => None, - ConfigOption::Ignore => default, - } - } -} - -Enum! {OtpCommand, [ - Clear => ("clear", otp_clear), - Get => ("get", otp_get), - Set => ("set", otp_set), - Status => ("status", otp_status), -]} - -Enum! {OtpAlgorithm, [ - Hotp => "hotp", - Totp => "totp", -]} - -Enum! {OtpMode, [ - SixDigits => "6", - EightDigits => "8", -]} - -impl From for nitrokey::OtpMode { - fn from(mode: OtpMode) -> Self { - match mode { - OtpMode::SixDigits => nitrokey::OtpMode::SixDigits, - OtpMode::EightDigits => nitrokey::OtpMode::EightDigits, - } - } -} - -Enum! {OtpSecretFormat, [ - Ascii => "ascii", - Base32 => "base32", - Hex => "hex", -]} - -Enum! {PinCommand, [ - Clear => ("clear", pin_clear), - Set => ("set", pin_set), - Unblock => ("unblock", pin_unblock), -]} - -Enum! {PwsCommand, [ - Clear => ("clear", pws_clear), - Get => ("get", pws_get), - Set => ("set", pws_set), - Status => ("status", pws_status), -]} - -fn parse( - ctx: &mut impl Stdio, - parser: argparse::ArgumentParser<'_>, - args: Vec, -) -> Result<()> { - let (stdout, stderr) = ctx.stdio(); - let result = parser - .parse(args, stdout, stderr) - .map_err(Error::ArgparseError); - drop(parser); - result -} - -/// Inquire the status of the Nitrokey. -fn status(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Prints the status of the connected Nitrokey device"); - parse(ctx, parser, args)?; - - commands::status(ctx) -} - -/// Perform a factory reset. -fn reset(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Performs a factory reset"); - parse(ctx, parser, args)?; - - commands::reset(ctx) -} - -Enum! {UnencryptedCommand, [ - Set => ("set", unencrypted_set), -]} - -Enum! {UnencryptedVolumeMode, [ - ReadWrite => "read-write", - ReadOnly => "read-only", -]} - -/// Execute an unencrypted subcommand. -fn unencrypted(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = UnencryptedCommand::Set; - let help = cmd_help!(subcommand); - let mut subargs = vec![]; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Interacts with the device's unencrypted volume"); - let _ = - parser - .refer(&mut subcommand) - .required() - .add_argument("subcommand", argparse::Store, &help); - let _ = parser.refer(&mut subargs).add_argument( - "arguments", - argparse::List, - "The arguments for the subcommand", - ); - parser.stop_on_first_argument(true); - parse(ctx, parser, args)?; - - subargs.insert( - 0, - format!( - "{} {} {}", - crate::NITROCLI, - Command::Unencrypted, - subcommand, - ), - ); - subcommand.execute(ctx, subargs) -} - -/// Change the configuration of the unencrypted volume. -fn unencrypted_set(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut mode = UnencryptedVolumeMode::ReadWrite; - let help = format!("The mode to change to ({})", fmt_enum!(mode)); - let mut parser = argparse::ArgumentParser::new(); - parser - .set_description("Changes the configuration of the unencrypted volume on a Nitrokey Storage"); - let _ = parser - .refer(&mut mode) - .required() - .add_argument("type", argparse::Store, &help); - parse(ctx, parser, args)?; - - commands::unencrypted_set(ctx, mode) -} - -Enum! {EncryptedCommand, [ - Close => ("close", encrypted_close), - Open => ("open", encrypted_open), -]} - -/// Execute an encrypted subcommand. -fn encrypted(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = EncryptedCommand::Open; - let help = cmd_help!(subcommand); - let mut subargs = vec![]; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Interacts with the device's encrypted volume"); - let _ = - parser - .refer(&mut subcommand) - .required() - .add_argument("subcommand", argparse::Store, &help); - let _ = parser.refer(&mut subargs).add_argument( - "arguments", - argparse::List, - "The arguments for the subcommand", - ); - parser.stop_on_first_argument(true); - parse(ctx, parser, args)?; - - subargs.insert( - 0, - format!("{} {} {}", crate::NITROCLI, Command::Encrypted, subcommand), - ); - subcommand.execute(ctx, subargs) -} - -/// Open the encrypted volume on the Nitrokey. -fn encrypted_open(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Opens the encrypted volume on a Nitrokey Storage"); - parse(ctx, parser, args)?; - - commands::encrypted_open(ctx) -} - -/// Close the previously opened encrypted volume. -fn encrypted_close(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Closes the encrypted volume on a Nitrokey Storage"); - parse(ctx, parser, args)?; - - commands::encrypted_close(ctx) -} - -Enum! {HiddenCommand, [ - Close => ("close", hidden_close), - Create => ("create", hidden_create), - Open => ("open", hidden_open), -]} - -/// Execute a hidden subcommand. -fn hidden(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = HiddenCommand::Open; - let help = cmd_help!(subcommand); - let mut subargs = vec![]; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Interacts with the device's hidden volume"); - let _ = - parser - .refer(&mut subcommand) - .required() - .add_argument("subcommand", argparse::Store, &help); - let _ = parser.refer(&mut subargs).add_argument( - "arguments", - argparse::List, - "The arguments for the subcommand", - ); - parser.stop_on_first_argument(true); - parse(ctx, parser, args)?; - - subargs.insert( - 0, - format!("{} {} {}", crate::NITROCLI, Command::Hidden, subcommand), - ); - subcommand.execute(ctx, subargs) -} - -fn hidden_create(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut slot: u8 = 0; - let mut start: u8 = 0; - let mut end: u8 = 0; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Creates a hidden volume on a Nitrokey Storage"); - let _ = parser.refer(&mut slot).required().add_argument( - "slot", - argparse::Store, - "The hidden volume slot to use", - ); - let _ = parser.refer(&mut start).required().add_argument( - "start", - argparse::Store, - "The start location of the hidden volume as percentage of the \ - encrypted volume's size (0-99)", - ); - let _ = parser.refer(&mut end).required().add_argument( - "end", - argparse::Store, - "The end location of the hidden volume as percentage of the \ - encrypted volume's size (1-100)", - ); - parse(ctx, parser, args)?; - - commands::hidden_create(ctx, slot, start, end) -} - -fn hidden_open(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Opens a hidden volume on a Nitrokey Storage"); - parse(ctx, parser, args)?; - - commands::hidden_open(ctx) -} - -fn hidden_close(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Closes the hidden volume on a Nitrokey Storage"); - parse(ctx, parser, args)?; - - commands::hidden_close(ctx) -} - -/// Execute a config subcommand. -fn config(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = ConfigCommand::Get; - let help = cmd_help!(subcommand); - let mut subargs = vec![]; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Reads or writes the device configuration"); - let _ = - parser - .refer(&mut subcommand) - .required() - .add_argument("subcommand", argparse::Store, &help); - let _ = parser.refer(&mut subargs).add_argument( - "arguments", - argparse::List, - "The arguments for the subcommand", - ); - parser.stop_on_first_argument(true); - parse(ctx, parser, args)?; - - subargs.insert( - 0, - format!("{} {} {}", crate::NITROCLI, Command::Config, subcommand), - ); - subcommand.execute(ctx, subargs) -} - -/// Read the Nitrokey configuration. -fn config_get(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Prints the Nitrokey configuration"); - parse(ctx, parser, args)?; - - commands::config_get(ctx) -} - -/// Write the Nitrokey configuration. -fn config_set(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut numlock = None; - let mut no_numlock = false; - let mut capslock = None; - let mut no_capslock = false; - let mut scrollock = None; - let mut no_scrollock = false; - let mut otp_pin = false; - let mut no_otp_pin = false; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Changes the Nitrokey configuration"); - let _ = parser.refer(&mut numlock).add_option( - &["-n", "--numlock"], - argparse::StoreOption, - "Set the numlock option to the given HOTP slot", - ); - let _ = parser.refer(&mut no_numlock).add_option( - &["-N", "--no-numlock"], - argparse::StoreTrue, - "Unset the numlock option", - ); - let _ = parser.refer(&mut capslock).add_option( - &["-c", "--capslock"], - argparse::StoreOption, - "Set the capslock option to the given HOTP slot", - ); - let _ = parser.refer(&mut no_capslock).add_option( - &["-C", "--no-capslock"], - argparse::StoreTrue, - "Unset the capslock option", - ); - let _ = parser.refer(&mut scrollock).add_option( - &["-s", "--scrollock"], - argparse::StoreOption, - "Set the scrollock option to the given HOTP slot", - ); - let _ = parser.refer(&mut no_scrollock).add_option( - &["-S", "--no-scrollock"], - argparse::StoreTrue, - "Unset the scrollock option", - ); - let _ = parser.refer(&mut otp_pin).add_option( - &["-o", "--otp-pin"], - argparse::StoreTrue, - "Require the user PIN to generate one-time passwords", - ); - let _ = parser.refer(&mut no_otp_pin).add_option( - &["-O", "--no-otp-pin"], - argparse::StoreTrue, - "Allow one-time password generation without PIN", - ); - parse(ctx, parser, args)?; - - let numlock = ConfigOption::try_from(no_numlock, numlock, "numlock")?; - let capslock = ConfigOption::try_from(no_capslock, capslock, "capslock")?; - let scrollock = ConfigOption::try_from(no_scrollock, scrollock, "scrollock")?; - let otp_pin = if otp_pin { - Some(true) - } else if no_otp_pin { - Some(false) - } else { - None - }; - commands::config_set(ctx, numlock, capslock, scrollock, otp_pin) -} - -/// Lock the Nitrokey. -fn lock(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Locks the connected Nitrokey device"); - parse(ctx, parser, args)?; - - commands::lock(ctx) -} - -/// Execute an OTP subcommand. -fn otp(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = OtpCommand::Get; - let help = cmd_help!(subcommand); - let mut subargs = vec![]; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Accesses one-time passwords"); - let _ = - parser - .refer(&mut subcommand) - .required() - .add_argument("subcommand", argparse::Store, &help); - let _ = parser.refer(&mut subargs).add_argument( - "arguments", - argparse::List, - "The arguments for the subcommand", - ); - parser.stop_on_first_argument(true); - parse(ctx, parser, args)?; - - subargs.insert( - 0, - format!("{} {} {}", crate::NITROCLI, Command::Otp, subcommand), - ); - subcommand.execute(ctx, subargs) -} - -/// Generate a one-time password on the Nitrokey device. -fn otp_get(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut slot: u8 = 0; - let mut algorithm = OtpAlgorithm::Totp; - let help = format!( - "The OTP algorithm to use ({}, default: {})", - fmt_enum!(algorithm), - algorithm - ); - let mut time: Option = None; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Generates a one-time password"); - 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, &help); - let _ = parser.refer(&mut time).add_option( - &["-t", "--time"], - argparse::StoreOption, - "The time to use for TOTP generation (Unix timestamp, default: system time)", - ); - parse(ctx, parser, args)?; - - commands::otp_get(ctx, slot, algorithm, time) -} - -/// Configure a one-time password slot on the Nitrokey device. -pub fn otp_set(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut slot: u8 = 0; - let mut algorithm = OtpAlgorithm::Totp; - let algo_help = format!( - "The OTP algorithm to use ({}, default: {})", - fmt_enum!(algorithm), - algorithm - ); - 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 secret_format = OtpSecretFormat::Hex; - let fmt_help = format!( - "The format of the secret ({}, default: {})", - fmt_enum!(OtpSecretFormat::all_variants()), - secret_format, - ); - 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, &algo_help); - 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 overwritten by --format)", - ); - 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 secret_format) - .add_option(&["-f", "--format"], argparse::Store, &fmt_help); - parse(ctx, parser, args)?; - - let data = nitrokey::OtpSlotData { - number: slot, - name, - secret, - mode: nitrokey::OtpMode::from(digits), - use_enter: false, - token_id: None, - }; - commands::otp_set(ctx, data, algorithm, counter, time_window, secret_format) -} - -/// Clear an OTP slot. -fn otp_clear(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut slot: u8 = 0; - let mut algorithm = OtpAlgorithm::Totp; - let help = format!( - "The OTP algorithm to use ({}, default: {})", - fmt_enum!(algorithm), - algorithm - ); - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Clears a one-time password slot"); - let _ = parser.refer(&mut slot).required().add_argument( - "slot", - argparse::Store, - "The OTP slot to clear", - ); - let _ = parser - .refer(&mut algorithm) - .add_option(&["-a", "--algorithm"], argparse::Store, &help); - parse(ctx, parser, args)?; - - commands::otp_clear(ctx, slot, algorithm) -} - -/// Print the status of the OTP slots. -fn otp_status(ctx: &mut ExecCtx<'_>, args: Vec) -> 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(ctx, parser, args)?; - - commands::otp_status(ctx, all) -} - -/// Execute a PIN subcommand. -fn pin(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = PinCommand::Clear; - let help = cmd_help!(subcommand); - let mut subargs = vec![]; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Manages the Nitrokey PINs"); - let _ = - parser - .refer(&mut subcommand) - .required() - .add_argument("subcommand", argparse::Store, &help); - let _ = parser.refer(&mut subargs).add_argument( - "arguments", - argparse::List, - "The arguments for the subcommand", - ); - parser.stop_on_first_argument(true); - parse(ctx, parser, args)?; - - subargs.insert( - 0, - format!("{} {} {}", crate::NITROCLI, Command::Pin, subcommand), - ); - subcommand.execute(ctx, subargs) -} - -/// Clear the PIN as cached by various other commands. -fn pin_clear(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Clears the cached PINs"); - parse(ctx, parser, args)?; - - commands::pin_clear(ctx) -} - -/// Change a PIN. -fn pin_set(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut pintype = pinentry::PinType::User; - let help = format!("The PIN type to change ({})", fmt_enum!(pintype)); - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Changes a PIN"); - let _ = parser - .refer(&mut pintype) - .required() - .add_argument("type", argparse::Store, &help); - parse(ctx, parser, args)?; - - commands::pin_set(ctx, pintype) -} - -/// Unblock and reset the user PIN. -fn pin_unblock(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Unblocks and resets the user PIN"); - parse(ctx, parser, args)?; - - commands::pin_unblock(ctx) -} - -/// Execute a PWS subcommand. -fn pws(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut subcommand = PwsCommand::Get; - let mut subargs = vec![]; - let help = cmd_help!(subcommand); - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Accesses the password safe"); - let _ = - parser - .refer(&mut subcommand) - .required() - .add_argument("subcommand", argparse::Store, &help); - let _ = parser.refer(&mut subargs).add_argument( - "arguments", - argparse::List, - "The arguments for the subcommand", - ); - parser.stop_on_first_argument(true); - parse(ctx, parser, args)?; - - subargs.insert( - 0, - format!("{} {} {}", crate::NITROCLI, Command::Pws, subcommand), - ); - subcommand.execute(ctx, subargs) -} - -/// Access a slot of the password safe on the Nitrokey. -fn pws_get(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut slot: u8 = 0; - let mut name = false; - let mut login = false; - let mut password = false; - let mut quiet = false; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Reads a password safe slot"); - let _ = parser.refer(&mut slot).required().add_argument( - "slot", - argparse::Store, - "The PWS slot to read", - ); - let _ = parser.refer(&mut name).add_option( - &["-n", "--name"], - argparse::StoreTrue, - "Show the name stored on the slot", - ); - let _ = parser.refer(&mut login).add_option( - &["-l", "--login"], - argparse::StoreTrue, - "Show the login stored on the slot", - ); - let _ = parser.refer(&mut password).add_option( - &["-p", "--password"], - argparse::StoreTrue, - "Show the password stored on the slot", - ); - let _ = parser.refer(&mut quiet).add_option( - &["-q", "--quiet"], - argparse::StoreTrue, - "Print the stored data without description", - ); - parse(ctx, parser, args)?; - - commands::pws_get(ctx, slot, name, login, password, quiet) -} - -/// Set a slot of the password safe on the Nitrokey. -fn pws_set(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut slot: u8 = 0; - let mut name = String::new(); - let mut login = String::new(); - let mut password = String::new(); - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Writes a password safe slot"); - let _ = parser.refer(&mut slot).required().add_argument( - "slot", - argparse::Store, - "The PWS slot to write", - ); - let _ = parser.refer(&mut name).required().add_argument( - "name", - argparse::Store, - "The name to store on the slot", - ); - let _ = parser.refer(&mut login).required().add_argument( - "login", - argparse::Store, - "The login to store on the slot", - ); - let _ = parser.refer(&mut password).required().add_argument( - "password", - argparse::Store, - "The password to store on the slot", - ); - parse(ctx, parser, args)?; - - commands::pws_set(ctx, slot, &name, &login, &password) -} - -/// Clear a PWS slot. -fn pws_clear(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut slot: u8 = 0; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Clears a password safe slot"); - let _ = parser.refer(&mut slot).required().add_argument( - "slot", - argparse::Store, - "The PWS slot to clear", - ); - parse(ctx, parser, args)?; - - commands::pws_clear(ctx, slot) -} - -/// Print the status of the PWS slots. -fn pws_status(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - let mut all = false; - let mut parser = argparse::ArgumentParser::new(); - parser.set_description("Prints the status of the PWS slots"); - let _ = parser.refer(&mut all).add_option( - &["-a", "--all"], - argparse::StoreTrue, - "Show slots that are not programmed", - ); - parse(ctx, parser, args)?; - - commands::pws_status(ctx, all) -} - -/// Parse the command-line arguments and execute the selected command. -pub(crate) fn handle_arguments(ctx: &mut RunCtx<'_>, args: Vec) -> Result<()> { - use std::io::Write; - - let mut version = false; - let mut model: Option = None; - let model_help = format!( - "Select the device model to connect to ({})", - fmt_enum!(DeviceModel::all_variants()) - ); - let mut verbosity = 0; - let mut command = Command::Status; - let cmd_help = cmd_help!(command); - let mut subargs = vec![]; - let mut parser = argparse::ArgumentParser::new(); - let _ = parser.refer(&mut version).add_option( - &["-V", "--version"], - argparse::StoreTrue, - "Print version information and exit", - ); - let _ = parser.refer(&mut verbosity).add_option( - &["-v", "--verbose"], - argparse::IncrBy::(1), - "Increase the log level (can be supplied multiple times)", - ); - let _ = - parser - .refer(&mut model) - .add_option(&["-m", "--model"], argparse::StoreOption, &model_help); - parser.set_description("Provides access to a Nitrokey device"); - let _ = parser - .refer(&mut command) - .required() - .add_argument("command", argparse::Store, &cmd_help); - let _ = parser.refer(&mut subargs).add_argument( - "arguments", - argparse::List, - "The arguments for the command", - ); - parser.stop_on_first_argument(true); - - let mut stdout_buf = BufWriter::new(ctx.stdout); - let mut stderr_buf = BufWriter::new(ctx.stderr); - let mut stdio_buf = (&mut stdout_buf, &mut stderr_buf); - let result = parse(&mut stdio_buf, parser, args); - - if version { - println!(ctx, "{} {}", crate::NITROCLI, env!("CARGO_PKG_VERSION"))?; - Ok(()) - } else { - stdout_buf.flush()?; - stderr_buf.flush()?; - - result?; - subargs.insert(0, format!("{} {}", crate::NITROCLI, command)); - - let mut ctx = ExecCtx { - model, - stdout: ctx.stdout, - stderr: ctx.stderr, - admin_pin: ctx.admin_pin.take(), - user_pin: ctx.user_pin.take(), - new_admin_pin: ctx.new_admin_pin.take(), - new_user_pin: ctx.new_user_pin.take(), - password: ctx.password.take(), - no_cache: ctx.no_cache, - verbosity, - }; - command.execute(&mut ctx, subargs) - } -} -- cgit v1.2.1