mod keyring;
use anyhow::{Context, Result};
use keyring::{Error, get_entry};
use readpassphrase_3::{Flags, PASSWORD_LEN, getpass, readpassphrase_into};
use secrecy::{ExposeSecret, SecretString};
pub(crate) fn read(use_keyring: bool, confirm: bool, flags: Flags) -> Result<SecretString> {
let password = use_keyring.then(load_keyring).transpose()?.flatten();
if let Some(password) = password {
if confirm && !check_confirm(password.expose_secret())? {
anyhow::bail!("passwords don’t match");
}
return Ok(password);
}
let password: SecretString =
readpassphrase_into(c"Seed password: ", Vec::with_capacity(PASSWORD_LEN), flags)
.context("failed reading password")?
.into();
if (use_keyring || confirm) && !check_confirm(password.expose_secret())? {
anyhow::bail!("passwords don’t match");
}
if use_keyring {
save_keyring(password.expose_secret())?;
}
Ok(password)
}
pub(crate) fn delete() -> Result<()> {
match get_entry()?.delete_credential() {
Err(Error::NoEntry) => (),
r => r.context("failed deleting password")?,
}
Ok(())
}
pub(crate) fn check_confirm(password: &str) -> Result<bool> {
let confirmed: SecretString = getpass(c"Confirmation: ")
.context("failed reading confirmation")?
.into();
Ok(confirmed.expose_secret() == password)
}
fn load_keyring() -> Result<Option<SecretString>> {
match get_entry()?.get_password() {
Err(Error::NoEntry) => Ok(None),
r => Ok(Some(r?.into())),
}
}
fn save_keyring(password: &str) -> Result<()> {
get_entry()?
.set_password(password)
.context("failed setting password")
}