From 048c97adcedab552e8c5b33567a06de4cb5c0f81 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 18 Dec 2018 00:39:24 +0100 Subject: Port argument handling to argparse This patch replaces the macro for argument parsing with `argparse::ArgumentParser` from the argparse crate. It moves the application logic to the `commands` module and the argument parsing to the `options` module. An enum is used to represent the available commands. The code is based on the `subcommands.rs` example shipped with argparse. --- nitrocli/src/args.rs | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 nitrocli/src/args.rs (limited to 'nitrocli/src/args.rs') diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs new file mode 100644 index 0000000..07a3e6a --- /dev/null +++ b/nitrocli/src/args.rs @@ -0,0 +1,153 @@ +// args.rs + +// ************************************************************************* +// * Copyright (C) 2018 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::fmt; +use std::io; +use std::result; +use std::str; + +use crate::commands; +use crate::error::Error; + +type Result = result::Result; + +/// A top-level command for nitrocli. +#[derive(Debug)] +pub enum Command { + Clear, + Close, + Open, + Status, +} + +impl Command { + /// Execute this command with the given arguments. + pub fn execute(&self, args: Vec) -> Result<()> { + match *self { + Command::Clear => clear(args), + Command::Close => close(args), + Command::Open => open(args), + Command::Status => status(args), + } + } +} + +impl fmt::Display for Command { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match *self { + Command::Clear => "clear", + Command::Close => "close", + Command::Open => "open", + Command::Status => "status", + } + ) + } +} + +impl str::FromStr for Command { + type Err = (); + + fn from_str(s: &str) -> result::Result { + match s { + "clear" => Ok(Command::Clear), + "close" => Ok(Command::Close), + "open" => Ok(Command::Open), + "status" => Ok(Command::Status), + _ => Err(()), + } + } +} + +fn parse(parser: &argparse::ArgumentParser<'_>, args: Vec) -> Result<()> { + if let Err(err) = parser.parse(args, &mut io::stdout(), &mut io::stderr()) { + Err(Error::ArgparseError(err)) + } else { + Ok(()) + } +} + +/// Inquire the status of the nitrokey. +fn status(args: Vec) -> Result<()> { + let mut parser = argparse::ArgumentParser::new(); + parser.set_description("Print the status of the connected Nitrokey Storage"); + parse(&parser, args)?; + + commands::status() +} + +/// Open the encrypted volume on the nitrokey. +fn open(args: Vec) -> Result<()> { + let mut parser = argparse::ArgumentParser::new(); + parser.set_description("Opens the encrypted volume on a Nitrokey Storage"); + parse(&parser, args)?; + + commands::open() +} + +/// Close the previously opened encrypted volume. +fn close(args: Vec) -> Result<()> { + let mut parser = argparse::ArgumentParser::new(); + parser.set_description("Closes the encrypted volume on a Nitrokey Storage"); + parse(&parser, args)?; + + commands::close() +} + +/// Clear the PIN stored when opening the nitrokey's encrypted volume. +fn clear(args: Vec) -> Result<()> { + let mut parser = argparse::ArgumentParser::new(); + parser.set_description("Clears the cached passphrase"); + parse(&parser, args)?; + + commands::clear() +} + +/// Parse the command-line arguments and return the selected command and +/// the remaining arguments for the command. +fn parse_arguments(args: Vec) -> Result<(Command, Vec)> { + let mut command = Command::Status; + let mut subargs = vec![]; + let mut parser = argparse::ArgumentParser::new(); + parser.set_description("Provides access to a Nitrokey device"); + let _ = parser.refer(&mut command).required().add_argument( + "command", + argparse::Store, + "The command to execute (clear|close|open|status)", + ); + let _ = parser.refer(&mut subargs).add_argument( + "arguments", + argparse::List, + "The arguments for the command", + ); + parser.stop_on_first_argument(true); + parse(&parser, args)?; + drop(parser); + + subargs.insert(0, format!("nitrocli {}", command)); + Ok((command, subargs)) +} + +/// Parse the command-line arguments and execute the selected command. +pub fn handle_arguments(args: Vec) -> Result<()> { + let (command, args) = parse_arguments(args)?; + command.execute(args) +} -- cgit v1.2.1