diff options
-rw-r--r-- | nitrocli/CHANGELOG.md | 2 | ||||
-rw-r--r-- | nitrocli/doc/nitrocli.1 | 9 | ||||
-rw-r--r-- | nitrocli/doc/nitrocli.1.pdf | bin | 17751 -> 18096 bytes | |||
-rw-r--r-- | nitrocli/src/args.rs | 2 | ||||
-rw-r--r-- | nitrocli/src/commands.rs | 13 | ||||
-rw-r--r-- | nitrocli/src/main.rs | 4 | ||||
-rw-r--r-- | nitrocli/src/pinentry.rs | 19 | ||||
-rw-r--r-- | nitrocli/src/tests/mod.rs | 1 |
8 files changed, 38 insertions, 12 deletions
diff --git a/nitrocli/CHANGELOG.md b/nitrocli/CHANGELOG.md index 0170fb7..fe3ac74 100644 --- a/nitrocli/CHANGELOG.md +++ b/nitrocli/CHANGELOG.md @@ -3,6 +3,8 @@ Unreleased - Added the `reset` command to perform a factory reset - Added the `-V`/`--version` option to print the program's version - Check the status of a PWS slot before accessing it in `pws get` +- Added `NITROCLI_NO_CACHE` environment variable to bypass caching of + secrets - Bumped `libc` dependency to `0.2.55` - Bumped `cc` dependency to `1.0.37` diff --git a/nitrocli/doc/nitrocli.1 b/nitrocli/doc/nitrocli.1 index 66d73f9..9029335 100644 --- a/nitrocli/doc/nitrocli.1 +++ b/nitrocli/doc/nitrocli.1 @@ -1,4 +1,4 @@ -.TH NITROCLI 1 2019-01-21 +.TH NITROCLI 1 2019-05-26 .SH NAME nitrocli \- access Nitrokey devices .SH SYNOPSIS @@ -279,6 +279,13 @@ for the \fBuser\fR type. .TP .B NITROCLI_PASSWORD A password used by commands that require one (e.g., \fBstorage hidden open\fR). +.TP +.B NITROCLI_NO_CACHE +If this variable is present in the environment, do not cache any inquired +secrets using \fBgpg\-agent\fR(1) but ask for them each time they are needed. +Note that this variable does not cause any cached secrets to be cleared. If a +secret is already in the cache it will be ignored, but left otherwise untouched. +Use the \fBpin clear\fR command to clear secrets from the cache. .SH EXAMPLES .SS Storage diff --git a/nitrocli/doc/nitrocli.1.pdf b/nitrocli/doc/nitrocli.1.pdf Binary files differindex ff72f94..fa4e4bc 100644 --- a/nitrocli/doc/nitrocli.1.pdf +++ b/nitrocli/doc/nitrocli.1.pdf diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index 82e9c2a..10a097e 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -91,6 +91,7 @@ pub struct ExecCtx<'io> { 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, } @@ -929,6 +930,7 @@ pub(crate) fn handle_arguments(ctx: &mut RunCtx<'_>, args: Vec<String>) -> Resul 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) diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs index 82d6240..a81859c 100644 --- a/nitrocli/src/commands.rs +++ b/nitrocli/src/commands.rs @@ -166,7 +166,7 @@ fn get_volume_status(status: &nitrokey::VolumeStatus) -> &'static str { /// /// This function will query the pin of the given type from the user /// using pinentry. It will then execute the given function. If this -/// function returns a result, the result will be passed it on. If it +/// function returns a result, the result will be passed on. If it /// returns a `CommandError::WrongPassword`, the user will be asked /// again to enter the pin. Otherwise, this function returns an error /// containing the given error message. The user will have at most @@ -177,6 +177,7 @@ 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>( + ctx: &mut args::ExecCtx<'_>, pin_entry: &pinentry::PinEntry, msg: &'static str, data: D, @@ -189,7 +190,7 @@ where let mut retry = 3; let mut error_msg = None; loop { - let pin = pinentry::inquire(pin_entry, pinentry::Mode::Query, error_msg)?; + let pin = pinentry::inquire(ctx, pin_entry, pinentry::Mode::Query, error_msg)?; match op(data, &pin) { Ok(result) => return Ok(result), Err((new_data, err)) => match err { @@ -235,7 +236,7 @@ where })?; op(data, &pin).map_err(|(_, err)| get_error(msg, err)) } else { - try_with_pin_and_data_with_pinentry(pin_entry, msg, data, op) + try_with_pin_and_data_with_pinentry(ctx, pin_entry, msg, data, op) } } @@ -359,7 +360,7 @@ pub fn storage_hidden_create( .ok_or_else(|| Error::from("Failed to read password: invalid Unicode data found")) .map(ToOwned::to_owned) } else { - pinentry::choose(&pwd_entry) + pinentry::choose(ctx, &pwd_entry) }?; device @@ -377,7 +378,7 @@ pub fn storage_hidden_open(ctx: &mut args::ExecCtx<'_>) -> Result<()> { .ok_or_else(|| Error::from("Failed to read password: invalid Unicode data found")) .map(ToOwned::to_owned) } else { - pinentry::inquire(&pwd_entry, pinentry::Mode::Query, None) + pinentry::inquire(ctx, &pwd_entry, pinentry::Mode::Query, None) }?; // We may forcefully close an encrypted volume, if active, so be sure @@ -706,7 +707,7 @@ fn choose_pin( .ok_or_else(|| Error::from("Failed to read PIN: invalid Unicode data found")) .map(ToOwned::to_owned) } else { - pinentry::choose(pin_entry) + pinentry::choose(ctx, pin_entry) } } diff --git a/nitrocli/src/main.rs b/nitrocli/src/main.rs index 1629167..5cb3faf 100644 --- a/nitrocli/src/main.rs +++ b/nitrocli/src/main.rs @@ -102,6 +102,7 @@ const NITROCLI_USER_PIN: &str = "NITROCLI_USER_PIN"; const NITROCLI_NEW_ADMIN_PIN: &str = "NITROCLI_NEW_ADMIN_PIN"; const NITROCLI_NEW_USER_PIN: &str = "NITROCLI_NEW_USER_PIN"; const NITROCLI_PASSWORD: &str = "NITROCLI_PASSWORD"; +const NITROCLI_NO_CACHE: &str = "NITROCLI_NO_CACHE"; /// The context used when running the program. pub(crate) struct RunCtx<'io> { @@ -123,6 +124,8 @@ pub(crate) struct RunCtx<'io> { pub new_user_pin: Option<ffi::OsString>, /// A password used by some commands, if provided through an environment variable. pub password: Option<ffi::OsString>, + /// Whether to bypass the cache for all secrets or not. + pub no_cache: bool, } fn run<'ctx, 'io: 'ctx>(ctx: &'ctx mut RunCtx<'io>, args: Vec<String>) -> i32 { @@ -157,6 +160,7 @@ fn main() { new_admin_pin: env::var_os(NITROCLI_NEW_ADMIN_PIN), new_user_pin: env::var_os(NITROCLI_NEW_USER_PIN), password: env::var_os(NITROCLI_PASSWORD), + no_cache: env::var_os(NITROCLI_NO_CACHE).is_some(), }; let rc = run(ctx, args); diff --git a/nitrocli/src/pinentry.rs b/nitrocli/src/pinentry.rs index 7bba6b9..d8a77d4 100644 --- a/nitrocli/src/pinentry.rs +++ b/nitrocli/src/pinentry.rs @@ -22,6 +22,7 @@ use std::fmt; use std::process; use std::str; +use crate::args; use crate::error::Error; type CowStr = borrow::Cow<'static, str>; @@ -223,19 +224,27 @@ where /// Inquire a secret from the user. /// /// This function inquires a secret from the user or returns a cached -/// entry, if available. If an error message is set, it is displayed in +/// entry, if available (and if caching is not disabled for the given +/// execution context). If an error message is set, it is displayed in /// the entry dialog. The mode describes the context of the pinentry /// 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>(entry: &E, mode: Mode, error_msg: Option<&str>) -> crate::Result<String> +pub fn inquire<E>( + ctx: &mut args::ExecCtx<'_>, + entry: &E, + mode: Mode, + error_msg: Option<&str>, +) -> crate::Result<String> where E: SecretEntry, { let cache_id = entry .cache_id() + .and_then(|id| if ctx.no_cache { None } else { Some(id) }) // "X" is a sentinel value indicating that no caching is desired. .unwrap_or_else(|| "X".into()) .into(); + let error_msg = error_msg .map(|msg| msg.replace(" ", "+")) .unwrap_or_else(|| String::from("+")); @@ -272,16 +281,16 @@ where } } -pub fn choose<E>(entry: &E) -> crate::Result<String> +pub fn choose<E>(ctx: &mut args::ExecCtx<'_>, entry: &E) -> crate::Result<String> where E: SecretEntry, { clear(entry)?; - let chosen = inquire(entry, Mode::Choose, None)?; + let chosen = inquire(ctx, entry, Mode::Choose, None)?; clear(entry)?; check(entry, &chosen)?; - let confirmed = inquire(entry, Mode::Confirm, None)?; + let confirmed = inquire(ctx, entry, Mode::Confirm, None)?; clear(entry)?; if chosen != confirmed { diff --git a/nitrocli/src/tests/mod.rs b/nitrocli/src/tests/mod.rs index e2e6ce0..b1e1618 100644 --- a/nitrocli/src/tests/mod.rs +++ b/nitrocli/src/tests/mod.rs @@ -157,6 +157,7 @@ impl Nitrocli { new_admin_pin: self.new_admin_pin.clone(), new_user_pin: self.new_user_pin.clone(), password: self.password.clone(), + no_cache: true, }; (f(ctx, args), stdout, stderr) |