use openpgp::crypto::Password;
use openpgp::Result;
use sequoia_openpgp as openpgp;
use crate::Sq;
const REPEAT_PROMPT: &str = "Please repeat the password";
fn prompt_password(sq: &Sq, prompt: impl ToString) -> Result<String> {
if sq.batch {
Err(anyhow::anyhow!("cannot prompt for password in batch mode"))
} else {
Ok(rpassword::prompt_password(prompt)?)
}
}
pub fn prompt_for_new(sq: &Sq, reason: &str) -> Result<Password> {
prompt_for_new_internal(sq, reason, false)
.map(|p| p.expect("is not None"))
}
pub fn prompt_for_new_or_none(sq: &Sq, reason: &str)
-> Result<Option<Password>>
{
prompt_for_new_internal(sq, reason, true)
}
fn prompt_for_new_internal(
sq: &Sq,
reason: &str,
allow_none: bool,
) -> Result<Option<Password>> {
let mut prompt = format!("Please enter the password to protect {}", reason);
if allow_none {
prompt.push_str(" (press enter to not use a password)");
}
let width = prompt.len().max(REPEAT_PROMPT.len());
let p0 = format!("{:>1$}: ", prompt, width);
let p1 = format!("{:>1$}: ", REPEAT_PROMPT, width);
loop {
let password = prompt_password(sq, &p0)?;
if password.is_empty() && ! allow_none {
weprintln!("Password required. Please try again.");
weprintln!();
continue;
}
let password_repeat = prompt_password(sq, &p1)?;
if password != password_repeat {
weprintln!("The passwords do not match. Please try again.");
weprintln!();
continue;
}
return if password.is_empty() {
Ok(None)
} else {
Ok(Some(password.into()))
};
}
}
pub fn prompt_to_unlock(sq: &Sq, reason: &str) -> Result<Password> {
let prompt =
format!("Please enter the password to decrypt {}: ", reason);
let password = prompt_password(sq, &prompt)?;
Ok(password.into())
}
pub fn prompt_to_unlock_or_cancel(sq: &Sq, reason: &str)
-> Result<Option<Password>>
{
let password =
prompt_to_unlock(sq, &format!("{} (blank to skip)", reason))?;
Ok(if password.map(|p| p.is_empty()) { None } else { Some(password) })
}