Repeat prompt for passwords when generating artifacts.
- The function common::password::prompt_for_password is intended for creating artifacts. For example, if a new key or subkey is generated, or a message should be encrypted using a password. The cost of mistyping is high, so we prompt twice. - If the user mistypes, repeating the process allows for graceful recovery, which seems to be in the best interest of the user. - Make the function repeated the prompts if the user mistypes. Rename it to better indicate intent. Adjust documentation. - Fixes #145.
This commit is contained in:
parent
1346e3013c
commit
68bf9e91f2
@ -26,7 +26,7 @@ use crate::cli::types::FileOrStdin;
|
||||
use crate::cli::types::MetadataTime;
|
||||
use crate::Config;
|
||||
use crate::Result;
|
||||
use crate::common::prompt_for_password;
|
||||
use crate::common::password;
|
||||
use crate::load_certs;
|
||||
|
||||
use crate::commands::CompressionMode;
|
||||
@ -101,7 +101,7 @@ pub fn encrypt<'a, 'b: 'a>(
|
||||
let mut passwords: Vec<crypto::Password> = Vec::with_capacity(npasswords);
|
||||
for n in 0..npasswords {
|
||||
let nprompt = format!("Enter password {}", n + 1);
|
||||
if let Some(password) = prompt_for_password(
|
||||
if let Some(password) = password::prompt_for_new(
|
||||
if npasswords > 1 {
|
||||
&nprompt
|
||||
} else {
|
||||
|
@ -12,7 +12,7 @@ use openpgp::Packet;
|
||||
use openpgp::Result;
|
||||
use sequoia_openpgp as openpgp;
|
||||
|
||||
use crate::common::prompt_for_password;
|
||||
use crate::common::password;
|
||||
use crate::Config;
|
||||
use crate::cli::types::FileOrStdout;
|
||||
use crate::cli;
|
||||
@ -103,7 +103,7 @@ pub fn generate(
|
||||
|
||||
if command.with_password {
|
||||
builder = builder.set_password(
|
||||
prompt_for_password(
|
||||
password::prompt_for_new(
|
||||
"Enter password to protect the key",
|
||||
)?);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use openpgp::Packet;
|
||||
use openpgp::Result;
|
||||
use sequoia_openpgp as openpgp;
|
||||
|
||||
use crate::common::prompt_for_password;
|
||||
use crate::common;
|
||||
use crate::Config;
|
||||
use crate::cli;
|
||||
use crate::decrypt_key;
|
||||
@ -48,7 +48,7 @@ pub fn password(
|
||||
} else if let Some(path) = command.new_password_file {
|
||||
Some(std::fs::read(path)?.into())
|
||||
} else {
|
||||
prompt_for_password("New password")?
|
||||
common::password::prompt_for_new("New password")?
|
||||
};
|
||||
|
||||
if let Some(new) = new_password {
|
||||
|
@ -30,10 +30,10 @@ use crate::cli::key::SubkeyCommand;
|
||||
use crate::cli::key::SubkeyRevokeCommand;
|
||||
use crate::cli::types::FileOrStdout;
|
||||
use crate::commands::get_primary_keys;
|
||||
use crate::common;
|
||||
use crate::common::NULL_POLICY;
|
||||
use crate::common::RevocationOutput;
|
||||
use crate::common::get_secret_signer;
|
||||
use crate::common::prompt_for_password;
|
||||
use crate::common::read_cert;
|
||||
use crate::common::read_secret;
|
||||
use crate::parse_notations;
|
||||
@ -266,7 +266,7 @@ fn subkey_add(
|
||||
if command.with_password {
|
||||
(
|
||||
keys.into_iter().next().unwrap().0,
|
||||
prompt_for_password(
|
||||
common::password::prompt_for_new(
|
||||
"Please enter password to encrypt the new subkey",
|
||||
)?
|
||||
)
|
||||
|
@ -16,8 +16,7 @@ mod revoke;
|
||||
pub use revoke::get_secret_signer;
|
||||
pub use revoke::RevocationOutput;
|
||||
|
||||
mod password;
|
||||
pub use password::prompt_for_password;
|
||||
pub mod password;
|
||||
|
||||
pub const NULL_POLICY: &NullPolicy = &NullPolicy::new();
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
//! Common password-related functionality such as prompting.
|
||||
|
||||
use openpgp::crypto::Password;
|
||||
use openpgp::Result;
|
||||
use rpassword::prompt_password;
|
||||
@ -8,25 +10,37 @@ const REPEAT_PROMPT: &str = "Repeat password";
|
||||
|
||||
/// Prompts twice for a new password and returns an optional [`Password`].
|
||||
///
|
||||
/// Prompts twice for comparison and only returns a [`Password`] in a [`Result`]
|
||||
/// if both inputs match and are not empty.
|
||||
/// Returns [`None`](Option::None), if the password is empty.
|
||||
pub fn prompt_for_password(
|
||||
/// This function is intended for creating artifacts. For example, if
|
||||
/// a new key or subkey is generated, or a message should be encrypted
|
||||
/// using a password. The cost of mistyping is high, so we prompt
|
||||
/// twice.
|
||||
///
|
||||
/// If the two entered passwords match, the result is returned. If
|
||||
/// the password was the empty string, `None` is returned.
|
||||
///
|
||||
/// If the passwords differ, an error message is printed and the
|
||||
/// process is repeated.
|
||||
pub fn prompt_for_new(
|
||||
prompt: &str,
|
||||
) -> Result<Option<Password>> {
|
||||
let width = prompt.len().max(REPEAT_PROMPT.len());
|
||||
let p0 = format!("{:>1$}: ", prompt, width);
|
||||
let p1 = format!("{:>1$}: ", REPEAT_PROMPT, width);
|
||||
let password = prompt_password(&p0)?;
|
||||
let password_repeat = prompt_password(&p1)?;
|
||||
|
||||
if password != password_repeat {
|
||||
return Err(anyhow::anyhow!("The passwords do not match!"));
|
||||
}
|
||||
loop {
|
||||
let password = prompt_password(&p0)?;
|
||||
let password_repeat = prompt_password(&p1)?;
|
||||
|
||||
if password.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(password.into()))
|
||||
if password != password_repeat {
|
||||
wprintln!("The passwords do not match. Please try again.");
|
||||
wprintln!();
|
||||
continue;
|
||||
}
|
||||
|
||||
return if password.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(password.into()))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user