aboutsummaryrefslogtreecommitdiffstats
path: root/src/bin/rbw/commands.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/rbw/commands.rs')
-rw-r--r--src/bin/rbw/commands.rs251
1 files changed, 123 insertions, 128 deletions
diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs
index 9efd966..0068efd 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -26,22 +26,28 @@ impl DecryptedCipher {
fn display_short(&self, desc: &str) -> bool {
match &self.data {
DecryptedData::Login { password, .. } => {
- if let Some(password) = password {
- println!("{}", password);
- true
- } else {
- eprintln!("entry for '{}' had no password", desc);
- false
- }
+ password.as_ref().map_or_else(
+ || {
+ eprintln!("entry for '{}' had no password", desc);
+ false
+ },
+ |password| {
+ println!("{}", password);
+ true
+ },
+ )
}
DecryptedData::Card { number, .. } => {
- if let Some(number) = number {
- println!("{}", number);
- true
- } else {
- eprintln!("entry for '{}' had no card number", desc);
- false
- }
+ number.as_ref().map_or_else(
+ || {
+ eprintln!("entry for '{}' had no card number", desc);
+ false
+ },
+ |number| {
+ println!("{}", number);
+ true
+ },
+ )
}
DecryptedData::Identity {
title,
@@ -65,15 +71,16 @@ impl DecryptedCipher {
true
}
}
- DecryptedData::SecureNote {} => {
- if let Some(notes) = &self.notes {
- println!("{}", notes);
- true
- } else {
+ DecryptedData::SecureNote {} => self.notes.as_ref().map_or_else(
+ || {
eprintln!("entry for '{}' had no notes", desc);
false
- }
- }
+ },
+ |notes| {
+ println!("{}", notes);
+ true
+ },
+ ),
}
}
@@ -86,18 +93,15 @@ impl DecryptedCipher {
..
} => {
let mut displayed = self.display_short(desc);
- displayed |=
- self.display_field("Username", username.as_deref());
- displayed |=
- self.display_field("TOTP Secret", totp.as_deref());
+ displayed |= display_field("Username", username.as_deref());
+ displayed |= display_field("TOTP Secret", totp.as_deref());
if let Some(uris) = uris {
for uri in uris {
- displayed |=
- self.display_field("URI", Some(&uri.uri));
+ displayed |= display_field("URI", Some(&uri.uri));
let match_type =
uri.match_type.map(|ty| format!("{}", ty));
- displayed |= self.display_field(
+ displayed |= display_field(
"Match type",
match_type.as_deref(),
);
@@ -105,7 +109,7 @@ impl DecryptedCipher {
}
for field in &self.fields {
- displayed |= self.display_field(
+ displayed |= display_field(
field.name.as_deref().unwrap_or("(null)"),
Some(field.value.as_deref().unwrap_or("")),
);
@@ -134,10 +138,10 @@ impl DecryptedCipher {
println!("Expiration: {}/{}", exp_month, exp_year);
displayed = true;
}
- displayed |= self.display_field("CVV", code.as_deref());
+ displayed |= display_field("CVV", code.as_deref());
displayed |=
- self.display_field("Name", cardholder_name.as_deref());
- displayed |= self.display_field("Brand", brand.as_deref());
+ display_field("Name", cardholder_name.as_deref());
+ displayed |= display_field("Brand", brand.as_deref());
if let Some(notes) = &self.notes {
if displayed {
@@ -164,27 +168,22 @@ impl DecryptedCipher {
} => {
let mut displayed = self.display_short(desc);
+ displayed |= display_field("Address", address1.as_deref());
+ displayed |= display_field("Address", address2.as_deref());
+ displayed |= display_field("Address", address3.as_deref());
+ displayed |= display_field("City", city.as_deref());
+ displayed |= display_field("State", state.as_deref());
displayed |=
- self.display_field("Address", address1.as_deref());
- displayed |=
- self.display_field("Address", address2.as_deref());
- displayed |=
- self.display_field("Address", address3.as_deref());
- displayed |= self.display_field("City", city.as_deref());
- displayed |= self.display_field("State", state.as_deref());
- displayed |=
- self.display_field("Postcode", postal_code.as_deref());
- displayed |=
- self.display_field("Country", country.as_deref());
- displayed |= self.display_field("Phone", phone.as_deref());
- displayed |= self.display_field("Email", email.as_deref());
- displayed |= self.display_field("SSN", ssn.as_deref());
+ display_field("Postcode", postal_code.as_deref());
+ displayed |= display_field("Country", country.as_deref());
+ displayed |= display_field("Phone", phone.as_deref());
+ displayed |= display_field("Email", email.as_deref());
+ displayed |= display_field("SSN", ssn.as_deref());
displayed |=
- self.display_field("License", license_number.as_deref());
- displayed |= self
- .display_field("Passport", passport_number.as_deref());
+ display_field("License", license_number.as_deref());
displayed |=
- self.display_field("Username", username.as_deref());
+ display_field("Passport", passport_number.as_deref());
+ displayed |= display_field("Username", username.as_deref());
if let Some(notes) = &self.notes {
if displayed {
@@ -199,23 +198,13 @@ impl DecryptedCipher {
}
}
- fn display_field(&self, name: &str, field: Option<&str>) -> bool {
- if let Some(field) = field {
- println!("{}: {}", name, field);
- true
- } else {
- false
- }
- }
-
fn display_name(&self) -> String {
match &self.data {
DecryptedData::Login { username, .. } => {
- if let Some(username) = username {
- format!("{}@{}", username, self.name)
- } else {
- self.name.clone()
- }
+ username.as_ref().map_or_else(
+ || self.name.clone(),
+ |username| format!("{}@{}", username, self.name),
+ )
}
_ => self.name.clone(),
}
@@ -314,6 +303,7 @@ impl DecryptedCipher {
#[derive(Debug, Clone)]
#[cfg_attr(test, derive(Eq, PartialEq))]
+#[allow(clippy::large_enum_variant)]
enum DecryptedData {
Login {
username: Option<String>,
@@ -448,7 +438,7 @@ pub fn config_unset(key: &str) -> anyhow::Result<()> {
"base_url" => config.base_url = None,
"identity_url" => config.identity_url = None,
"lock_timeout" => {
- config.lock_timeout = rbw::config::default_lock_timeout()
+ config.lock_timeout = rbw::config::default_lock_timeout();
}
"pinentry" => config.pinentry = rbw::config::default_pinentry(),
_ => return Err(anyhow::anyhow!("invalid config key: {}", key)),
@@ -526,17 +516,18 @@ pub fn list(fields: &[String]) -> anyhow::Result<()> {
ListField::Name => cipher.name.clone(),
ListField::Id => cipher.id.clone(),
ListField::User => match &cipher.data {
- DecryptedData::Login { username, .. } => username
- .as_ref()
- .map(std::string::ToString::to_string)
- .unwrap_or_else(|| "".to_string()),
+ DecryptedData::Login { username, .. } => {
+ username.as_ref().map_or_else(
+ || "".to_string(),
+ std::string::ToString::to_string,
+ )
+ }
_ => "".to_string(),
},
- ListField::Folder => cipher
- .folder
- .as_ref()
- .map(std::string::ToString::to_string)
- .unwrap_or_else(|| "".to_string()),
+ ListField::Folder => cipher.folder.as_ref().map_or_else(
+ || "".to_string(),
+ std::string::ToString::to_string,
+ ),
})
.collect();
println!("{}", values.join("\t"));
@@ -557,8 +548,7 @@ pub fn get(
let desc = format!(
"{}{}",
- user.map(|s| format!("{}@", s))
- .unwrap_or_else(|| "".to_string()),
+ user.map_or_else(|| "".to_string(), |s| format!("{}@", s)),
name
);
@@ -584,8 +574,7 @@ pub fn code(
let desc = format!(
"{}{}",
- user.map(|s| format!("{}@", s))
- .unwrap_or_else(|| "".to_string()),
+ user.map_or_else(|| "".to_string(), |s| format!("{}@", s)),
name
);
@@ -594,7 +583,7 @@ pub fn code(
if let DecryptedData::Login { totp, .. } = decrypted.data {
if let Some(totp) = totp {
- println!("{}", generate_totp(&totp)?)
+ println!("{}", generate_totp(&totp)?);
} else {
return Err(anyhow::anyhow!(
"entry does not contain a totp secret"
@@ -610,7 +599,7 @@ pub fn code(
pub fn add(
name: &str,
username: Option<&str>,
- uris: Vec<(String, Option<rbw::api::UriMatchType>)>,
+ uris: &[(String, Option<rbw::api::UriMatchType>)],
folder: Option<&str>,
) -> anyhow::Result<()> {
unlock()?;
@@ -707,7 +696,7 @@ pub fn add(
pub fn generate(
name: Option<&str>,
username: Option<&str>,
- uris: Vec<(String, Option<rbw::api::UriMatchType>)>,
+ uris: &[(String, Option<rbw::api::UriMatchType>)],
folder: Option<&str>,
len: usize,
ty: rbw::pwgen::Type,
@@ -813,9 +802,7 @@ pub fn edit(
let desc = format!(
"{}{}",
- username
- .map(|s| format!("{}@", s))
- .unwrap_or_else(|| "".to_string()),
+ username.map_or_else(|| "".to_string(), |s| format!("{}@", s)),
name
);
@@ -874,7 +861,7 @@ pub fn edit(
let data = rbw::db::EntryData::Login {
username: entry_username.clone(),
password,
- uris: entry_uris.to_vec(),
+ uris: entry_uris.clone(),
totp: entry_totp.clone(),
};
(data, notes, history)
@@ -918,9 +905,7 @@ pub fn remove(
let desc = format!(
"{}{}",
- username
- .map(|s| format!("{}@", s))
- .unwrap_or_else(|| "".to_string()),
+ username.map_or_else(|| "".to_string(), |s| format!("{}@", s)),
name
);
@@ -950,9 +935,7 @@ pub fn history(
let desc = format!(
"{}{}",
- username
- .map(|s| format!("{}@", s))
- .unwrap_or_else(|| "".to_string()),
+ username.map_or_else(|| "".to_string(), |s| format!("{}@", s)),
name
);
@@ -1017,7 +1000,7 @@ fn ensure_agent_once() -> anyhow::Result<()> {
let agent_path = std::env::var("RBW_AGENT");
let agent_path = agent_path
.as_ref()
- .map(|s| s.as_str())
+ .map(std::string::String::as_str)
.unwrap_or("rbw-agent");
let status = std::process::Command::new(agent_path)
.status()
@@ -1045,6 +1028,8 @@ fn check_config() -> anyhow::Result<()> {
fn version_or_quit() -> anyhow::Result<u32> {
crate::actions::version().map_err(|e| {
+ // https://github.com/rust-lang/rust-clippy/issues/8003
+ #[allow(clippy::let_underscore_drop)]
let _ = crate::actions::quit();
e
})
@@ -1056,26 +1041,23 @@ fn find_entry(
username: Option<&str>,
folder: Option<&str>,
) -> anyhow::Result<(rbw::db::Entry, DecryptedCipher)> {
- match uuid::Uuid::parse_str(name) {
- Ok(_) => {
- for cipher in &db.entries {
- if name == cipher.id {
- return Ok((cipher.clone(), decrypt_cipher(cipher)?));
- }
+ if uuid::Uuid::parse_str(name).is_ok() {
+ for cipher in &db.entries {
+ if name == cipher.id {
+ return Ok((cipher.clone(), decrypt_cipher(cipher)?));
}
- Err(anyhow::anyhow!("no entry found"))
- }
- Err(_) => {
- let ciphers: Vec<(rbw::db::Entry, DecryptedCipher)> = db
- .entries
- .iter()
- .cloned()
- .map(|entry| {
- decrypt_cipher(&entry).map(|decrypted| (entry, decrypted))
- })
- .collect::<anyhow::Result<_>>()?;
- find_entry_raw(&ciphers, name, username, folder)
}
+ Err(anyhow::anyhow!("no entry found"))
+ } else {
+ let ciphers: Vec<(rbw::db::Entry, DecryptedCipher)> = db
+ .entries
+ .iter()
+ .cloned()
+ .map(|entry| {
+ decrypt_cipher(&entry).map(|decrypted| (entry, decrypted))
+ })
+ .collect::<anyhow::Result<_>>()?;
+ find_entry_raw(&ciphers, name, username, folder)
}
}
@@ -1447,32 +1429,35 @@ fn parse_editor(contents: &str) -> (Option<String>, Option<String>) {
fn load_db() -> anyhow::Result<rbw::db::Db> {
let config = rbw::config::Config::load()?;
- if let Some(email) = &config.email {
- rbw::db::Db::load(&config.server_name(), email)
- .map_err(anyhow::Error::new)
- } else {
- Err(anyhow::anyhow!("failed to find email address in config"))
- }
+ config.email.as_ref().map_or_else(
+ || Err(anyhow::anyhow!("failed to find email address in config")),
+ |email| {
+ rbw::db::Db::load(&config.server_name(), email)
+ .map_err(anyhow::Error::new)
+ },
+ )
}
fn save_db(db: &rbw::db::Db) -> anyhow::Result<()> {
let config = rbw::config::Config::load()?;
- if let Some(email) = &config.email {
- db.save(&config.server_name(), email)
- .map_err(anyhow::Error::new)
- } else {
- Err(anyhow::anyhow!("failed to find email address in config"))
- }
+ config.email.as_ref().map_or_else(
+ || Err(anyhow::anyhow!("failed to find email address in config")),
+ |email| {
+ db.save(&config.server_name(), email)
+ .map_err(anyhow::Error::new)
+ },
+ )
}
fn remove_db() -> anyhow::Result<()> {
let config = rbw::config::Config::load()?;
- if let Some(email) = &config.email {
- rbw::db::Db::remove(&config.server_name(), email)
- .map_err(anyhow::Error::new)
- } else {
- Err(anyhow::anyhow!("failed to find email address in config"))
- }
+ config.email.as_ref().map_or_else(
+ || Err(anyhow::anyhow!("failed to find email address in config")),
+ |email| {
+ rbw::db::Db::remove(&config.server_name(), email)
+ .map_err(anyhow::Error::new)
+ },
+ )
}
fn parse_totp_secret(secret: &str) -> anyhow::Result<Vec<u8>> {
@@ -1680,3 +1665,13 @@ mod test {
)
}
}
+
+fn display_field(name: &str, field: Option<&str>) -> bool {
+ field.map_or_else(
+ || false,
+ |field| {
+ println!("{}: {}", name, field);
+ true
+ },
+ )
+}