aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arg_util.rs2
-rw-r--r--src/args.rs99
-rw-r--r--src/commands.rs112
-rw-r--r--src/main.rs85
-rw-r--r--src/pinentry.rs6
-rw-r--r--src/tests/mod.rs2
6 files changed, 134 insertions, 172 deletions
diff --git a/src/arg_util.rs b/src/arg_util.rs
index c16c326..439a594 100644
--- a/src/arg_util.rs
+++ b/src/arg_util.rs
@@ -46,7 +46,7 @@ macro_rules! Command {
impl $name {
pub fn execute(
self,
- ctx: &mut crate::args::ExecCtx<'_>,
+ ctx: &mut crate::ExecCtx<'_>,
) -> crate::Result<()> {
match self {
$(
diff --git a/src/args.rs b/src/args.rs
deleted file mode 100644
index d0b2a88..0000000
--- a/src/args.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-// args.rs
-
-// *************************************************************************
-// * Copyright (C) 2018-2020 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/>. *
-// *************************************************************************
-
-use std::ffi;
-use std::io;
-use std::result;
-
-use crate::arg_defs;
-use crate::error::Error;
-use crate::RunCtx;
-
-type Result<T> = result::Result<T, Error>;
-
-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<W> 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<arg_defs::DeviceModel>,
- pub stdout: &'io mut dyn io::Write,
- pub stderr: &'io mut dyn io::Write,
- pub admin_pin: Option<ffi::OsString>,
- pub user_pin: Option<ffi::OsString>,
- pub new_admin_pin: Option<ffi::OsString>,
- pub new_user_pin: Option<ffi::OsString>,
- pub password: Option<ffi::OsString>,
- 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)
- }
-}
-
-/// Parse the command-line arguments and execute the selected command.
-pub(crate) fn handle_arguments(ctx: &mut RunCtx<'_>, args: Vec<String>) -> Result<()> {
- use structopt::StructOpt;
-
- match arg_defs::Args::from_iter_safe(args.iter()) {
- Ok(args) => {
- let mut ctx = ExecCtx {
- model: args.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: args.verbose.into(),
- };
- args.cmd.execute(&mut ctx)
- }
- Err(err) => {
- if err.use_stderr() {
- Err(err.into())
- } else {
- println!(ctx, "{}", err.message)?;
- Ok(())
- }
- }
- }
-}
diff --git a/src/commands.rs b/src/commands.rs
index b40d552..208c039 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -32,10 +32,10 @@ use nitrokey::GenerateOtp;
use nitrokey::GetPasswordSafe;
use crate::arg_defs;
-use crate::args;
use crate::error;
use crate::error::Error;
use crate::pinentry;
+use crate::ExecCtx;
use crate::Result;
/// Create an `error::Error` with an error message of the format `msg: err`.
@@ -44,7 +44,7 @@ fn get_error(msg: &'static str, err: nitrokey::Error) -> Error {
}
/// Set `libnitrokey`'s log level based on the execution context's verbosity.
-fn set_log_level(ctx: &mut args::ExecCtx<'_>) {
+fn set_log_level(ctx: &mut ExecCtx<'_>) {
let log_lvl = match ctx.verbosity {
// The error log level is what libnitrokey uses by default. As such,
// there is no harm in us setting that as well when the user did not
@@ -60,9 +60,9 @@ fn set_log_level(ctx: &mut args::ExecCtx<'_>) {
}
/// Connect to any Nitrokey device and do something with it.
-fn with_device<F>(ctx: &mut args::ExecCtx<'_>, op: F) -> Result<()>
+fn with_device<F>(ctx: &mut ExecCtx<'_>, op: F) -> Result<()>
where
- F: FnOnce(&mut args::ExecCtx<'_>, nitrokey::DeviceWrapper<'_>) -> Result<()>,
+ F: FnOnce(&mut ExecCtx<'_>, nitrokey::DeviceWrapper<'_>) -> Result<()>,
{
let mut manager = nitrokey::take()?;
set_log_level(ctx);
@@ -81,9 +81,9 @@ where
}
/// Connect to a Nitrokey Storage device and do something with it.
-fn with_storage_device<F>(ctx: &mut args::ExecCtx<'_>, op: F) -> Result<()>
+fn with_storage_device<F>(ctx: &mut ExecCtx<'_>, op: F) -> Result<()>
where
- F: FnOnce(&mut args::ExecCtx<'_>, nitrokey::Storage<'_>) -> Result<()>,
+ F: FnOnce(&mut ExecCtx<'_>, nitrokey::Storage<'_>) -> Result<()>,
{
let mut manager = nitrokey::take()?;
set_log_level(ctx);
@@ -104,9 +104,9 @@ where
/// Connect to any Nitrokey device, retrieve a password safe handle, and
/// do something with it.
-fn with_password_safe<F>(ctx: &mut args::ExecCtx<'_>, mut op: F) -> Result<()>
+fn with_password_safe<F>(ctx: &mut ExecCtx<'_>, mut op: F) -> Result<()>
where
- F: FnMut(&mut args::ExecCtx<'_>, nitrokey::PasswordSafe<'_, '_>) -> Result<()>,
+ F: FnMut(&mut ExecCtx<'_>, nitrokey::PasswordSafe<'_, '_>) -> Result<()>,
{
with_device(ctx, |ctx, mut device| {
let pin_entry = pinentry::PinEntry::from(arg_defs::PinType::User, &device)?;
@@ -131,7 +131,7 @@ where
///
/// If an error occurs, the error message `msg` is used.
fn authenticate<'mgr, D, A, F>(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
device: D,
pin_type: arg_defs::PinType,
msg: &'static str,
@@ -139,7 +139,7 @@ fn authenticate<'mgr, D, A, F>(
) -> Result<A>
where
D: Device<'mgr>,
- F: FnMut(&mut args::ExecCtx<'_>, D, &str) -> result::Result<A, (D, nitrokey::Error)>,
+ F: FnMut(&mut ExecCtx<'_>, D, &str) -> result::Result<A, (D, nitrokey::Error)>,
{
let pin_entry = pinentry::PinEntry::from(pin_type, &device)?;
@@ -147,10 +147,7 @@ where
}
/// Authenticate the given device with the user PIN.
-fn authenticate_user<'mgr, T>(
- ctx: &mut args::ExecCtx<'_>,
- device: T,
-) -> Result<nitrokey::User<'mgr, T>>
+fn authenticate_user<'mgr, T>(ctx: &mut ExecCtx<'_>, device: T) -> Result<nitrokey::User<'mgr, T>>
where
T: Device<'mgr>,
{
@@ -164,10 +161,7 @@ where
}
/// Authenticate the given device with the admin PIN.
-fn authenticate_admin<'mgr, T>(
- ctx: &mut args::ExecCtx<'_>,
- device: T,
-) -> Result<nitrokey::Admin<'mgr, T>>
+fn authenticate_admin<'mgr, T>(ctx: &mut ExecCtx<'_>, device: T) -> Result<nitrokey::Admin<'mgr, T>>
where
T: Device<'mgr>,
{
@@ -208,14 +202,14 @@ fn get_volume_status(status: &nitrokey::VolumeStatus) -> &'static str {
/// second or third try, it will call `op` with the data returned by the
/// previous call to `op`.
fn try_with_pin_and_data_with_pinentry<D, F, R, E>(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
pin_entry: &pinentry::PinEntry,
msg: &'static str,
data: D,
mut op: F,
) -> Result<R>
where
- F: FnMut(&mut args::ExecCtx<'_>, D, &str) -> result::Result<R, (D, E)>,
+ F: FnMut(&mut ExecCtx<'_>, D, &str) -> result::Result<R, (D, E)>,
E: error::TryInto<nitrokey::Error>,
{
let mut data = data;
@@ -248,14 +242,14 @@ where
/// Try to execute the given function with a PIN.
fn try_with_pin_and_data<D, F, R, E>(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
pin_entry: &pinentry::PinEntry,
msg: &'static str,
data: D,
mut op: F,
) -> Result<R>
where
- F: FnMut(&mut args::ExecCtx<'_>, D, &str) -> result::Result<R, (D, E)>,
+ F: FnMut(&mut ExecCtx<'_>, D, &str) -> result::Result<R, (D, E)>,
E: Into<Error> + error::TryInto<nitrokey::Error>,
{
let pin = match pin_entry.pin_type() {
@@ -284,7 +278,7 @@ where
/// This function behaves exactly as `try_with_pin_and_data`, but
/// it refrains from passing any data to it.
fn try_with_pin<F, E>(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
pin_entry: &pinentry::PinEntry,
msg: &'static str,
mut op: F,
@@ -299,10 +293,7 @@ where
}
/// Pretty print the status of a Nitrokey Storage.
-fn print_storage_status(
- ctx: &mut args::ExecCtx<'_>,
- status: &nitrokey::StorageStatus,
-) -> Result<()> {
+fn print_storage_status(ctx: &mut ExecCtx<'_>, status: &nitrokey::StorageStatus) -> Result<()> {
println!(
ctx,
r#" Storage:
@@ -333,7 +324,7 @@ fn print_storage_status(
/// Query and pretty print the status that is common to all Nitrokey devices.
fn print_status(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
model: &'static str,
device: &nitrokey::DeviceWrapper<'_>,
) -> Result<()> {
@@ -368,7 +359,7 @@ fn print_status(
}
/// Inquire the status of the nitrokey.
-pub fn status(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+pub fn status(ctx: &mut ExecCtx<'_>) -> Result<()> {
with_device(ctx, |ctx, device| {
let model = match device {
nitrokey::DeviceWrapper::Pro(_) => "Pro",
@@ -379,7 +370,7 @@ pub fn status(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
}
/// List the attached Nitrokey devices.
-pub fn list(ctx: &mut args::ExecCtx<'_>, no_connect: bool) -> Result<()> {
+pub fn list(ctx: &mut ExecCtx<'_>, no_connect: bool) -> Result<()> {
set_log_level(ctx);
let device_infos = nitrokey::list_devices()?;
@@ -417,7 +408,7 @@ pub fn list(ctx: &mut args::ExecCtx<'_>, no_connect: bool) -> Result<()> {
}
/// Perform a factory reset.
-pub fn reset(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+pub fn reset(ctx: &mut ExecCtx<'_>) -> Result<()> {
with_device(ctx, |ctx, mut device| {
let pin_entry = pinentry::PinEntry::from(arg_defs::PinType::Admin, &device)?;
@@ -441,10 +432,7 @@ pub fn reset(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
}
/// Change the configuration of the unencrypted volume.
-pub fn unencrypted_set(
- ctx: &mut args::ExecCtx<'_>,
- mode: arg_defs::UnencryptedVolumeMode,
-) -> Result<()> {
+pub fn unencrypted_set(ctx: &mut ExecCtx<'_>, mode: arg_defs::UnencryptedVolumeMode) -> Result<()> {
with_storage_device(ctx, |ctx, mut device| {
let pin_entry = pinentry::PinEntry::from(arg_defs::PinType::Admin, &device)?;
let mode = match mode {
@@ -466,7 +454,7 @@ pub fn unencrypted_set(
}
/// Open the encrypted volume on the Nitrokey.
-pub fn encrypted_open(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+pub fn encrypted_open(ctx: &mut ExecCtx<'_>) -> Result<()> {
with_storage_device(ctx, |ctx, mut device| {
let pin_entry = pinentry::PinEntry::from(arg_defs::PinType::User, &device)?;
@@ -481,7 +469,7 @@ pub fn encrypted_open(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
}
/// Close the previously opened encrypted volume.
-pub fn encrypted_close(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+pub fn encrypted_close(ctx: &mut ExecCtx<'_>) -> Result<()> {
with_storage_device(ctx, |_ctx, mut device| {
// Flush all filesystem caches to disk. We are mostly interested in
// making sure that the encrypted volume on the Nitrokey we are
@@ -496,7 +484,7 @@ pub fn encrypted_close(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
}
/// Create a hidden volume.
-pub fn hidden_create(ctx: &mut args::ExecCtx<'_>, slot: u8, start: u8, end: u8) -> Result<()> {
+pub fn hidden_create(ctx: &mut ExecCtx<'_>, slot: u8, start: u8, end: u8) -> Result<()> {
with_storage_device(ctx, |ctx, mut device| {
let pwd_entry = pinentry::PwdEntry::from(&device)?;
let pwd = if let Some(pwd) = &ctx.password {
@@ -515,7 +503,7 @@ pub fn hidden_create(ctx: &mut args::ExecCtx<'_>, slot: u8, start: u8, end: u8)
}
/// Open a hidden volume.
-pub fn hidden_open(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+pub fn hidden_open(ctx: &mut ExecCtx<'_>) -> Result<()> {
with_storage_device(ctx, |ctx, mut device| {
let pwd_entry = pinentry::PwdEntry::from(&device)?;
let pwd = if let Some(pwd) = &ctx.password {
@@ -538,7 +526,7 @@ pub fn hidden_open(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
}
/// Close a previously opened hidden volume.
-pub fn hidden_close(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+pub fn hidden_close(ctx: &mut ExecCtx<'_>) -> Result<()> {
with_storage_device(ctx, |_ctx, mut device| {
unsafe { sync() };
@@ -557,7 +545,7 @@ fn format_option<T: fmt::Display>(option: Option<T>) -> String {
}
/// Read the Nitrokey configuration.
-pub fn config_get(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+pub fn config_get(ctx: &mut ExecCtx<'_>) -> Result<()> {
with_device(ctx, |ctx, device| {
let config = device
.get_config()
@@ -579,7 +567,7 @@ pub fn config_get(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
}
/// Write the Nitrokey configuration.
-pub fn config_set(ctx: &mut args::ExecCtx<'_>, args: arg_defs::ConfigSetArgs) -> Result<()> {
+pub fn config_set(ctx: &mut ExecCtx<'_>, args: arg_defs::ConfigSetArgs) -> Result<()> {
let numlock = arg_defs::ConfigOption::try_from(args.no_numlock, args.numlock, "numlock")?;
let capslock = arg_defs::ConfigOption::try_from(args.no_capslock, args.capslock, "capslock")?;
let scrollock = arg_defs::ConfigOption::try_from(args.no_scrollock, args.scrollock, "scrollock")?;
@@ -609,7 +597,7 @@ pub fn config_set(ctx: &mut args::ExecCtx<'_>, args: arg_defs::ConfigSetArgs) ->
}
/// Lock the Nitrokey device.
-pub fn lock(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+pub fn lock(ctx: &mut ExecCtx<'_>) -> Result<()> {
with_device(ctx, |_ctx, mut device| {
device
.lock()
@@ -637,7 +625,7 @@ fn get_unix_timestamp() -> Result<u64> {
/// Generate a one-time password on the Nitrokey device.
pub fn otp_get(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
slot: u8,
algorithm: arg_defs::OtpAlgorithm,
time: Option<u64>,
@@ -700,7 +688,7 @@ fn prepare_base32_secret(secret: &str) -> Result<String> {
}
/// Configure a one-time password slot on the Nitrokey device.
-pub fn otp_set(ctx: &mut args::ExecCtx<'_>, mut args: arg_defs::OtpSetArgs) -> Result<()> {
+pub fn otp_set(ctx: &mut ExecCtx<'_>, mut args: arg_defs::OtpSetArgs) -> Result<()> {
let mut data = nitrokey::OtpSlotData {
number: args.slot,
name: mem::take(&mut args.name),
@@ -739,11 +727,7 @@ pub fn otp_set(ctx: &mut args::ExecCtx<'_>, mut args: arg_defs::OtpSetArgs) -> R
}
/// Clear an OTP slot.
-pub fn otp_clear(
- ctx: &mut args::ExecCtx<'_>,
- slot: u8,
- algorithm: arg_defs::OtpAlgorithm,
-) -> Result<()> {
+pub fn otp_clear(ctx: &mut ExecCtx<'_>, slot: u8, algorithm: arg_defs::OtpAlgorithm) -> Result<()> {
with_device(ctx, |ctx, device| {
let mut device = authenticate_admin(ctx, device)?;
match algorithm {
@@ -756,7 +740,7 @@ pub fn otp_clear(
}
fn print_otp_status(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
algorithm: arg_defs::OtpAlgorithm,
device: &nitrokey::DeviceWrapper<'_>,
all: bool,
@@ -790,7 +774,7 @@ fn print_otp_status(
}
/// Print the status of the OTP slots.
-pub fn otp_status(ctx: &mut args::ExecCtx<'_>, all: bool) -> Result<()> {
+pub fn otp_status(ctx: &mut ExecCtx<'_>, all: bool) -> Result<()> {
with_device(ctx, |ctx, device| {
println!(ctx, "alg\tslot\tname")?;
print_otp_status(ctx, arg_defs::OtpAlgorithm::Hotp, &device, all)?;
@@ -800,7 +784,7 @@ pub fn otp_status(ctx: &mut args::ExecCtx<'_>, all: bool) -> Result<()> {
}
/// Clear the PIN stored by various operations.
-pub fn pin_clear(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+pub fn pin_clear(ctx: &mut ExecCtx<'_>) -> Result<()> {
with_device(ctx, |_ctx, device| {
pinentry::clear(&pinentry::PinEntry::from(
arg_defs::PinType::Admin,
@@ -815,11 +799,7 @@ pub fn pin_clear(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
///
/// If the user has set the respective environment variable for the
/// given PIN type, it will be used.
-fn choose_pin(
- ctx: &mut args::ExecCtx<'_>,
- pin_entry: &pinentry::PinEntry,
- new: bool,
-) -> Result<String> {
+fn choose_pin(ctx: &mut ExecCtx<'_>, pin_entry: &pinentry::PinEntry, new: bool) -> Result<String> {
let new_pin = match pin_entry.pin_type() {
arg_defs::PinType::Admin => {
if new {
@@ -848,7 +828,7 @@ fn choose_pin(
}
/// Change a PIN.
-pub fn pin_set(ctx: &mut args::ExecCtx<'_>, pin_type: arg_defs::PinType) -> Result<()> {
+pub fn pin_set(ctx: &mut ExecCtx<'_>, pin_type: arg_defs::PinType) -> Result<()> {
with_device(ctx, |ctx, mut device| {
let pin_entry = pinentry::PinEntry::from(pin_type, &device)?;
let new_pin = choose_pin(ctx, &pin_entry, true)?;
@@ -871,7 +851,7 @@ pub fn pin_set(ctx: &mut args::ExecCtx<'_>, pin_type: arg_defs::PinType) -> Resu
}
/// Unblock and reset the user PIN.
-pub fn pin_unblock(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
+pub fn pin_unblock(ctx: &mut ExecCtx<'_>) -> Result<()> {
with_device(ctx, |ctx, mut device| {
let pin_entry = pinentry::PinEntry::from(arg_defs::PinType::User, &device)?;
let user_pin = choose_pin(ctx, &pin_entry, false)?;
@@ -887,7 +867,7 @@ pub fn pin_unblock(ctx: &mut args::ExecCtx<'_>) -> Result<()> {
}
fn print_pws_data(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
description: &'static str,
result: result::Result<String, nitrokey::Error>,
quiet: bool,
@@ -920,7 +900,7 @@ fn check_slot(pws: &nitrokey::PasswordSafe<'_, '_>, slot: u8) -> Result<()> {
/// Read a PWS slot.
pub fn pws_get(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
slot: u8,
show_name: bool,
show_login: bool,
@@ -946,7 +926,7 @@ pub fn pws_get(
/// Write a PWS slot.
pub fn pws_set(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
slot: u8,
name: &str,
login: &str,
@@ -960,7 +940,7 @@ pub fn pws_set(
}
/// Clear a PWS slot.
-pub fn pws_clear(ctx: &mut args::ExecCtx<'_>, slot: u8) -> Result<()> {
+pub fn pws_clear(ctx: &mut ExecCtx<'_>, slot: u8) -> Result<()> {
with_password_safe(ctx, |_ctx, mut pws| {
pws
.erase_slot(slot)
@@ -969,7 +949,7 @@ pub fn pws_clear(ctx: &mut args::ExecCtx<'_>, slot: u8) -> Result<()> {
}
fn print_pws_slot(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
pws: &nitrokey::PasswordSafe<'_, '_>,
slot: usize,
programmed: bool,
@@ -990,7 +970,7 @@ fn print_pws_slot(
}
/// Print the status of all PWS slots.
-pub fn pws_status(ctx: &mut args::ExecCtx<'_>, all: bool) -> Result<()> {
+pub fn pws_status(ctx: &mut ExecCtx<'_>, all: bool) -> Result<()> {
with_password_safe(ctx, |ctx, pws| {
let slots = pws
.get_slot_status()
diff --git a/src/main.rs b/src/main.rs
index 89c9d67..a2c4f48 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -69,7 +69,6 @@ mod redefine;
mod arg_util;
mod arg_defs;
-mod args;
mod commands;
mod error;
mod pinentry;
@@ -93,6 +92,88 @@ const NITROCLI_NEW_USER_PIN: &str = "NITROCLI_NEW_USER_PIN";
const NITROCLI_PASSWORD: &str = "NITROCLI_PASSWORD";
const NITROCLI_NO_CACHE: &str = "NITROCLI_NO_CACHE";
+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<W> 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.
+#[allow(missing_debug_implementations)]
+pub struct ExecCtx<'io> {
+ /// The Nitrokey model to use.
+ pub model: Option<arg_defs::DeviceModel>,
+ /// See `RunCtx::stdout`.
+ pub stdout: &'io mut dyn io::Write,
+ /// See `RunCtx::stderr`.
+ pub stderr: &'io mut dyn io::Write,
+ /// See `RunCtx::admin_pin`.
+ pub admin_pin: Option<ffi::OsString>,
+ /// See `RunCtx::user_pin`.
+ pub user_pin: Option<ffi::OsString>,
+ /// See `RunCtx::new_admin_pin`.
+ pub new_admin_pin: Option<ffi::OsString>,
+ /// See `RunCtx::new_user_pin`.
+ pub new_user_pin: Option<ffi::OsString>,
+ /// See `RunCtx::password`.
+ pub password: Option<ffi::OsString>,
+ /// See `RunCtx::no_cache`.
+ pub no_cache: bool,
+ /// The verbosity level to use for logging.
+ 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)
+ }
+}
+
+/// Parse the command-line arguments and execute the selected command.
+fn handle_arguments(ctx: &mut RunCtx<'_>, args: Vec<String>) -> Result<()> {
+ use structopt::StructOpt;
+
+ match arg_defs::Args::from_iter_safe(args.iter()) {
+ Ok(args) => {
+ let mut ctx = ExecCtx {
+ model: args.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: args.verbose.into(),
+ };
+ args.cmd.execute(&mut ctx)
+ }
+ Err(err) => {
+ if err.use_stderr() {
+ Err(err.into())
+ } else {
+ println!(ctx, "{}", err.message)?;
+ Ok(())
+ }
+ }
+ }
+}
+
/// The context used when running the program.
pub(crate) struct RunCtx<'io> {
/// The `Write` object used as standard output throughout the program.
@@ -118,7 +199,7 @@ pub(crate) struct RunCtx<'io> {
}
fn run<'ctx, 'io: 'ctx>(ctx: &'ctx mut RunCtx<'io>, args: Vec<String>) -> i32 {
- match args::handle_arguments(ctx, args) {
+ match handle_arguments(ctx, args) {
Ok(()) => 0,
Err(err) => {
let _ = eprintln!(ctx, "{}", err);
diff --git a/src/pinentry.rs b/src/pinentry.rs
index 878ed9e..47c8844 100644
--- a/src/pinentry.rs
+++ b/src/pinentry.rs
@@ -24,8 +24,8 @@ use std::process;
use std::str;
use crate::arg_defs;
-use crate::args;
use crate::error::Error;
+use crate::ExecCtx;
type CowStr = borrow::Cow<'static, str>;
@@ -222,7 +222,7 @@ where
/// dialog. It is used to choose an appropriate description and to
/// decide whether a quality bar is shown in the dialog.
pub fn inquire<E>(
- ctx: &mut args::ExecCtx<'_>,
+ ctx: &mut ExecCtx<'_>,
entry: &E,
mode: Mode,
error_msg: Option<&str>,
@@ -279,7 +279,7 @@ where
}
}
-pub fn choose<E>(ctx: &mut args::ExecCtx<'_>, entry: &E) -> crate::Result<String>
+pub fn choose<E>(ctx: &mut ExecCtx<'_>, entry: &E) -> crate::Result<String>
where
E: SecretEntry,
{
diff --git a/src/tests/mod.rs b/src/tests/mod.rs
index 1edf8f2..abf63e3 100644
--- a/src/tests/mod.rs
+++ b/src/tests/mod.rs
@@ -178,7 +178,7 @@ impl Nitrocli {
/// Run `nitrocli`'s `handle_arguments` function.
pub fn handle(&mut self, args: &[&str]) -> crate::Result<String> {
- let (res, out, _) = self.do_run(args, |c, a| crate::args::handle_arguments(c, a));
+ let (res, out, _) = self.do_run(args, |c, a| crate::handle_arguments(c, a));
res.map(|_| String::from_utf8_lossy(&out).into_owned())
}