From 236f06736e45c2a70f43589c9d447a0a3ef240b5 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sun, 12 Apr 2020 00:08:03 -0400 Subject: improve error handling and reporting --- src/bin/rbw/commands.rs | 164 +++++++++++++++++++++++++++++++----------------- 1 file changed, 108 insertions(+), 56 deletions(-) (limited to 'src/bin/rbw/commands.rs') diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs index b76658c..83c6c81 100644 --- a/src/bin/rbw/commands.rs +++ b/src/bin/rbw/commands.rs @@ -1,76 +1,108 @@ -pub fn config_show() { - let config = rbw::config::Config::load().unwrap(); - serde_json::to_writer_pretty(std::io::stdout(), &config).unwrap(); +use anyhow::Context as _; + +pub fn config_show() -> anyhow::Result<()> { + let config = + rbw::config::Config::load().context("failed to load config")?; + serde_json::to_writer_pretty(std::io::stdout(), &config) + .context("failed to write config to stdout")?; println!(); + + Ok(()) } -pub fn config_set(key: &str, value: &str) { +pub fn config_set(key: &str, value: &str) -> anyhow::Result<()> { let mut config = rbw::config::Config::load() .unwrap_or_else(|_| rbw::config::Config::new()); match key { "email" => config.email = Some(value.to_string()), "base_url" => config.base_url = Some(value.to_string()), "identity_url" => config.identity_url = Some(value.to_string()), - "lock_timeout" => config.lock_timeout = value.parse().unwrap(), - _ => unimplemented!(), + "lock_timeout" => { + config.lock_timeout = value + .parse() + .context("failed to parse value for lock_timeout")? + } + _ => return Err(anyhow::anyhow!("invalid config key: {}", key)), } - config.save().unwrap(); + config.save().context("failed to save config file")?; + + Ok(()) } -pub fn login() { - ensure_agent(); - crate::actions::login(); +pub fn login() -> anyhow::Result<()> { + ensure_agent()?; + crate::actions::login()?; + + Ok(()) } -pub fn unlock() { - ensure_agent(); - crate::actions::login(); - crate::actions::unlock(); +pub fn unlock() -> anyhow::Result<()> { + ensure_agent()?; + crate::actions::login()?; + crate::actions::unlock()?; + + Ok(()) } -pub fn sync() { - ensure_agent(); - crate::actions::login(); - crate::actions::sync(); +pub fn sync() -> anyhow::Result<()> { + ensure_agent()?; + crate::actions::login()?; + crate::actions::sync()?; + + Ok(()) } -pub fn list() { - unlock(); +pub fn list() -> anyhow::Result<()> { + unlock()?; - let email = config_email(); - let db = rbw::db::Db::load(&email).unwrap_or_else(|_| rbw::db::Db::new()); + let email = config_email()?; + let db = rbw::db::Db::load(&email) + .context("failed to load password database")?; for cipher in db.ciphers { - println!("{}", crate::actions::decrypt(&cipher.name)); + println!( + "{}", + crate::actions::decrypt(&cipher.name) + .context("failed to decrypt entry name")? + ); } + + Ok(()) } -pub fn get(name: &str, user: Option<&str>) { - unlock(); +pub fn get(name: &str, user: Option<&str>) -> anyhow::Result<()> { + unlock()?; - let email = config_email(); - let db = rbw::db::Db::load(&email).unwrap_or_else(|_| rbw::db::Db::new()); + let email = config_email()?; + let db = rbw::db::Db::load(&email) + .context("failed to load password database")?; for cipher in db.ciphers { - let cipher_name = crate::actions::decrypt(&cipher.name); + let cipher_name = crate::actions::decrypt(&cipher.name) + .context("failed to decrypt entry name")?; if name == cipher_name { - let cipher_user = crate::actions::decrypt(&cipher.login.username); + let cipher_user = crate::actions::decrypt(&cipher.login.username) + .context("failed to decrypt entry username")?; if let Some(user) = user { if user == cipher_user { let pass = - crate::actions::decrypt(&cipher.login.password); + crate::actions::decrypt(&cipher.login.password) + .context("failed to decrypt entry password")?; println!("{}", pass); - return; + return Ok(()); } } else { - let pass = crate::actions::decrypt(&cipher.login.password); + let pass = crate::actions::decrypt(&cipher.login.password) + .context("failed to decrypt entry password")?; println!("{}", pass); - return; + return Ok(()); } } } + + Ok(()) } -pub fn add() { - unlock(); +pub fn add() -> anyhow::Result<()> { + unlock()?; todo!() } @@ -80,62 +112,82 @@ pub fn generate( user: Option<&str>, len: usize, ty: rbw::pwgen::Type, -) { +) -> anyhow::Result<()> { let pw = rbw::pwgen::pwgen(ty, len); + // unwrap is safe because pwgen is guaranteed to always return valid utf8 println!("{}", std::str::from_utf8(pw.data()).unwrap()); if name.is_some() && user.is_some() { - unlock(); + unlock()?; todo!(); } + + Ok(()) } -pub fn edit() { - unlock(); +pub fn edit() -> anyhow::Result<()> { + unlock()?; todo!() } -pub fn remove() { - unlock(); +pub fn remove() -> anyhow::Result<()> { + unlock()?; todo!() } -pub fn lock() { - ensure_agent(); - crate::actions::lock(); +pub fn lock() -> anyhow::Result<()> { + ensure_agent()?; + crate::actions::lock()?; + + Ok(()) } -pub fn purge() { - stop_agent(); +pub fn purge() -> anyhow::Result<()> { + stop_agent()?; + + let email = config_email()?; + rbw::db::Db::remove(&email).context("failed to remove database")?; - let email = config_email(); - rbw::db::Db::remove(&email).unwrap(); + Ok(()) } -pub fn stop_agent() { - crate::actions::quit(); +pub fn stop_agent() -> anyhow::Result<()> { + crate::actions::quit()?; + + Ok(()) } -fn ensure_agent() { +fn ensure_agent() -> anyhow::Result<()> { let agent_path = std::env::var("RBW_AGENT"); let agent_path = agent_path .as_ref() .map(|s| s.as_str()) .unwrap_or("rbw-agent"); - let status = std::process::Command::new(agent_path).status().unwrap(); + let status = std::process::Command::new(agent_path) + .status() + .context("failed to run rbw-agent")?; if !status.success() { if let Some(code) = status.code() { if code != 23 { - panic!("failed to run agent: {}", status); + return Err(anyhow::anyhow!( + "failed to run rbw-agent: {}", + status + )); } } } + + Ok(()) } -fn config_email() -> String { - let config = rbw::config::Config::load().unwrap(); - config.email.unwrap() +fn config_email() -> anyhow::Result { + let config = rbw::config::Config::load()?; + if let Some(email) = config.email { + Ok(email) + } else { + Err(anyhow::anyhow!("failed to find email address in config")) + } } -- cgit v1.2.3-54-g00ecf