From e106613dbd94bf0580b873da0ad3c3751e156f24 Mon Sep 17 00:00:00 2001 From: Daniel Mueller Date: Sun, 20 Jan 2019 08:28:46 -0800 Subject: Make caching of secrets optional Currently, when we enter a secret (i.e., a PIN) through the pinentry module, this PIN will automatically be cached and not asked from the user again on subsequent inquiries. However, caching may not always be desired. For the upcoming support of passwords used in conjunction with hidden volumes, we do not want any caching because different passwords can be entered for different volumes and the user's intention is not clear until a password has actually been entered. To accommodate this use case, this change modifies the signature of the SecretEntry trait's cache_id method to return an optional cache ID. If none is returned, caching of the entered secret is disabled. --- nitrocli/src/pinentry.rs | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/nitrocli/src/pinentry.rs b/nitrocli/src/pinentry.rs index 68cc4aa..1a3982e 100644 --- a/nitrocli/src/pinentry.rs +++ b/nitrocli/src/pinentry.rs @@ -38,7 +38,7 @@ Enum! {PinType, [ /// A trait representing a secret to be entered by the user. pub trait SecretEntry: fmt::Debug { /// The cache ID to use for this secret. - fn cache_id(&self) -> CowStr; + fn cache_id(&self) -> Option; /// The prompt to display when asking for the secret. fn prompt(&self) -> CowStr; /// The description to display when asking for the secret. @@ -72,15 +72,14 @@ impl PinEntry { } impl SecretEntry for PinEntry { - fn cache_id(&self) -> CowStr { + fn cache_id(&self) -> Option { let model = self.model.to_string().to_lowercase(); let suffix = format!("{}:{}", model, self.serial); - - match self.pin_type { + let cache_id = match self.pin_type { PinType::Admin => format!("nitrocli:admin:{}", suffix), PinType::User => format!("nitrocli:user:{}", suffix), - } - .into() + }; + Some(cache_id.into()) } fn prompt(&self) -> CowStr { @@ -173,7 +172,11 @@ pub fn inquire(entry: &E, mode: Mode, error_msg: Option<&str>) -> crate::Resu where E: SecretEntry, { - let cache_id = entry.cache_id().into(); + let cache_id = entry + .cache_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("+")); @@ -246,13 +249,17 @@ pub fn clear(entry: &E) -> crate::Result<()> where E: SecretEntry, { - let command = format!("CLEAR_PASSPHRASE {}", entry.cache_id()); - let output = process::Command::new("gpg-connect-agent") - .arg(command) - .arg("/bye") - .output()?; - - parse_pinentry_response(str::from_utf8(&output.stdout)?) + if let Some(cache_id) = entry.cache_id() { + let command = format!("CLEAR_PASSPHRASE {}", cache_id); + let output = process::Command::new("gpg-connect-agent") + .arg(command) + .arg("/bye") + .output()?; + + parse_pinentry_response(str::from_utf8(&output.stdout)?) + } else { + Ok(()) + } } #[cfg(test)] -- cgit v1.2.1