From 9e77724efff281f0fe6d05440ad65c5ab561f380 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 6 Mar 2021 13:18:29 -0500 Subject: switch to thiserror --- Cargo.lock | 49 ++++++++++++-------------- Cargo.toml | 2 +- src/actions.rs | 4 +-- src/api.rs | 20 +++++------ src/cipherstring.rs | 37 ++++++++++---------- src/config.rs | 52 +++++++++++++++++++--------- src/db.rs | 67 ++++++++++++++++++++++++------------ src/dirs.rs | 30 +++++++++++----- src/error.rs | 99 ++++++++++++++++++++++++++--------------------------- src/identity.rs | 2 +- src/json.rs | 17 ++++++--- src/pinentry.rs | 19 +++++----- src/prelude.rs | 1 - 13 files changed, 227 insertions(+), 172 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5877bb..171687d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,12 +393,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "encoding_rs" version = "0.8.28" @@ -1187,11 +1181,11 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_repr", - "snafu", "structopt", "tempfile", "term_size", "textwrap 0.13.4", + "thiserror", "tokio", "url", "uuid", @@ -1498,27 +1492,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" -[[package]] -name = "snafu" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7" -dependencies = [ - "doc-comment", - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "socket2" version = "0.3.19" @@ -1649,6 +1622,26 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "thiserror" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.3" diff --git a/Cargo.toml b/Cargo.toml index c447cc5..c731b7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,11 +39,11 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_path_to_error = "0.1" serde_repr = "0.1" -snafu = "0.6" structopt = { version = "0.3", features = ["paw", "wrap_help"] } tempfile = "3.2" term_size = "0.3" textwrap = "0.13" +thiserror = "1.0" tokio = { version = "1.2", features = ["full"] } url = "2.2" uuid = { version = "0.8", features = ["v4"] } diff --git a/src/actions.rs b/src/actions.rs index bda8670..0d8c88d 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -259,7 +259,7 @@ where { match f(access_token) { Ok(t) => Ok((None, t)), - Err(crate::error::Error::RequestUnauthorized) => { + Err(Error::RequestUnauthorized) => { let access_token = exchange_refresh_token(refresh_token)?; let t = f(&access_token)?; Ok((Some(access_token), t)) @@ -284,7 +284,7 @@ where { match f(access_token).await { Ok(t) => Ok((None, t)), - Err(crate::error::Error::RequestUnauthorized) => { + Err(Error::RequestUnauthorized) => { let access_token = exchange_refresh_token_async(refresh_token).await?; let t = f(&access_token).await?; diff --git a/src/api.rs b/src/api.rs index 40fe422..99e12fd 100644 --- a/src/api.rs +++ b/src/api.rs @@ -563,7 +563,7 @@ impl Client { .json(&prelogin) .send() .await - .context(crate::error::Reqwest)?; + .map_err(|source| Error::Reqwest { source })?; let prelogin_res: PreloginRes = res.json_with_path().await?; Ok(prelogin_res.kdf_iterations) } @@ -597,7 +597,7 @@ impl Client { .form(&connect_req) .send() .await - .context(crate::error::Reqwest)?; + .map_err(|source| Error::Reqwest { source })?; if let reqwest::StatusCode::OK = res.status() { let connect_res: ConnectPasswordRes = res.json_with_path().await?; @@ -627,7 +627,7 @@ impl Client { .header("Authorization", format!("Bearer {}", access_token)) .send() .await - .context(crate::error::Reqwest)?; + .map_err(|source| Error::Reqwest { source })?; match res.status() { reqwest::StatusCode::OK => { let sync_res: SyncRes = res.json_with_path().await?; @@ -769,7 +769,7 @@ impl Client { .header("Authorization", format!("Bearer {}", access_token)) .json(&req) .send() - .context(crate::error::Reqwest)?; + .map_err(|source| Error::Reqwest { source })?; match res.status() { reqwest::StatusCode::OK => Ok(()), reqwest::StatusCode::UNAUTHORIZED => { @@ -902,7 +902,7 @@ impl Client { .header("Authorization", format!("Bearer {}", access_token)) .json(&req) .send() - .context(crate::error::Reqwest)?; + .map_err(|source| Error::Reqwest { source })?; match res.status() { reqwest::StatusCode::OK => Ok(()), reqwest::StatusCode::UNAUTHORIZED => { @@ -920,7 +920,7 @@ impl Client { .delete(&self.api_url(&format!("/ciphers/{}", id))) .header("Authorization", format!("Bearer {}", access_token)) .send() - .context(crate::error::Reqwest)?; + .map_err(|source| Error::Reqwest { source })?; match res.status() { reqwest::StatusCode::OK => Ok(()), reqwest::StatusCode::UNAUTHORIZED => { @@ -941,7 +941,7 @@ impl Client { .get(&self.api_url("/folders")) .header("Authorization", format!("Bearer {}", access_token)) .send() - .context(crate::error::Reqwest)?; + .map_err(|source| Error::Reqwest { source })?; match res.status() { reqwest::StatusCode::OK => { let folders_res: FoldersRes = res.json_with_path()?; @@ -974,7 +974,7 @@ impl Client { .header("Authorization", format!("Bearer {}", access_token)) .json(&req) .send() - .context(crate::error::Reqwest)?; + .map_err(|source| Error::Reqwest { source })?; match res.status() { reqwest::StatusCode::OK => { let folders_res: FoldersResData = res.json_with_path()?; @@ -1003,7 +1003,7 @@ impl Client { .post(&self.identity_url("/connect/token")) .form(&connect_req) .send() - .context(crate::error::Reqwest)?; + .map_err(|source| Error::Reqwest { source })?; let connect_res: ConnectRefreshTokenRes = res.json_with_path()?; Ok(connect_res.access_token) } @@ -1023,7 +1023,7 @@ impl Client { .form(&connect_req) .send() .await - .context(crate::error::Reqwest)?; + .map_err(|source| Error::Reqwest { source })?; let connect_res: ConnectRefreshTokenRes = res.json_with_path().await?; Ok(connect_res.access_token) diff --git a/src/cipherstring.rs b/src/cipherstring.rs index c1bd80d..f213cf7 100644 --- a/src/cipherstring.rs +++ b/src/cipherstring.rs @@ -48,17 +48,17 @@ impl CipherString { } let iv = base64::decode(parts[0]) - .context(crate::error::InvalidBase64)?; + .map_err(|source| Error::InvalidBase64 { source })?; let ciphertext = base64::decode(parts[1]) - .context(crate::error::InvalidBase64)?; - let mac = if parts.len() > 2 { - Some( - base64::decode(parts[2]) - .context(crate::error::InvalidBase64)?, - ) - } else { - None - }; + .map_err(|source| Error::InvalidBase64 { source })?; + let mac = + if parts.len() > 2 { + Some(base64::decode(parts[2]).map_err(|source| { + Error::InvalidBase64 { source } + })?) + } else { + None + }; Ok(Self::Symmetric { iv, @@ -73,7 +73,7 @@ impl CipherString { // format is: | let contents = contents.split('|').next().unwrap(); let ciphertext = base64::decode(contents) - .context(crate::error::InvalidBase64)?; + .map_err(|source| Error::InvalidBase64 { source })?; Ok(Self::Asymmetric { ciphertext }) } _ => { @@ -100,7 +100,7 @@ impl CipherString { aes::Aes256, block_modes::block_padding::Pkcs7, >::new_var(keys.enc_key(), &iv) - .context(crate::error::CreateBlockMode)?; + .map_err(|source| Error::CreateBlockMode { source })?; let ciphertext = cipher.encrypt_vec(plaintext); let mut digest = ring::hmac::Context::with_key( @@ -135,7 +135,7 @@ impl CipherString { )?; cipher .decrypt_vec(ciphertext) - .context(crate::error::Decrypt) + .map_err(|source| Error::Decrypt { source }) } _ => Err(Error::InvalidCipherString { reason: @@ -165,7 +165,7 @@ impl CipherString { )?; cipher .decrypt(res.data_mut()) - .context(crate::error::Decrypt)?; + .map_err(|source| Error::Decrypt { source })?; Ok(res) } _ => Err(Error::InvalidCipherString { @@ -188,8 +188,9 @@ impl CipherString { let pkey = openssl::pkey::PKey::private_key_from_pkcs8( private_key.private_key(), ) - .context(crate::error::OpenSSL)?; - let rsa = pkey.rsa().context(crate::error::OpenSSL)?; + .map_err(|source| Error::OpenSSL { source })?; + let rsa = + pkey.rsa().map_err(|source| Error::OpenSSL { source })?; let mut res = crate::locked::Vec::new(); res.extend(std::iter::repeat(0).take(rsa.size() as usize)); @@ -200,7 +201,7 @@ impl CipherString { res.data_mut(), openssl::rsa::Padding::PKCS1_OAEP, ) - .context(crate::error::OpenSSL)?; + .map_err(|source| Error::OpenSSL { source })?; res.truncate(bytes); Ok(res) @@ -241,7 +242,7 @@ fn decrypt_common_symmetric( aes::Aes256, block_modes::block_padding::Pkcs7, >::new_var(keys.enc_key(), iv) - .context(crate::error::CreateBlockMode)?) + .map_err(|source| Error::CreateBlockMode { source })?) } impl std::fmt::Display for CipherString { diff --git a/src/config.rs b/src/config.rs index 9bb4696..dbdf759 100644 --- a/src/config.rs +++ b/src/config.rs @@ -41,15 +41,20 @@ impl Config { pub fn load() -> Result { let file = crate::dirs::config_file(); - let mut fh = std::fs::File::open(&file).with_context(|| { - crate::error::LoadConfig { file: file.clone() } + let mut fh = std::fs::File::open(&file).map_err(|source| { + Error::LoadConfig { + source, + file: file.clone(), + } })?; let mut json = String::new(); - fh.read_to_string(&mut json).with_context(|| { - crate::error::LoadConfig { file: file.clone() } - })?; + fh.read_to_string(&mut json) + .map_err(|source| Error::LoadConfig { + source, + file: file.clone(), + })?; let mut slf: Self = serde_json::from_str(&json) - .context(crate::error::LoadConfigJson { file })?; + .map_err(|source| Error::LoadConfigJson { source, file })?; if slf.lock_timeout == 0 { log::warn!("lock_timeout must be greater than 0"); slf.lock_timeout = default_lock_timeout(); @@ -60,15 +65,21 @@ impl Config { pub async fn load_async() -> Result { let file = crate::dirs::config_file(); let mut fh = - tokio::fs::File::open(&file).await.with_context(|| { - crate::error::LoadConfigAsync { file: file.clone() } + tokio::fs::File::open(&file).await.map_err(|source| { + Error::LoadConfigAsync { + source, + file: file.clone(), + } })?; let mut json = String::new(); - fh.read_to_string(&mut json).await.with_context(|| { - crate::error::LoadConfigAsync { file: file.clone() } + fh.read_to_string(&mut json).await.map_err(|source| { + Error::LoadConfigAsync { + source, + file: file.clone(), + } })?; let mut slf: Self = serde_json::from_str(&json) - .context(crate::error::LoadConfigJson { file })?; + .map_err(|source| Error::LoadConfigJson { source, file })?; if slf.lock_timeout == 0 { log::warn!("lock_timeout must be greater than 0"); slf.lock_timeout = default_lock_timeout(); @@ -80,20 +91,27 @@ impl Config { let file = crate::dirs::config_file(); // unwrap is safe here because Self::filename is explicitly // constructed as a filename in a directory - std::fs::create_dir_all(file.parent().unwrap()).with_context( - || crate::error::SaveConfig { file: file.clone() }, + std::fs::create_dir_all(file.parent().unwrap()).map_err( + |source| Error::SaveConfig { + source, + file: file.clone(), + }, )?; - let mut fh = std::fs::File::create(&file).with_context(|| { - crate::error::SaveConfig { file: file.clone() } + let mut fh = std::fs::File::create(&file).map_err(|source| { + Error::SaveConfig { + source, + file: file.clone(), + } })?; fh.write_all( serde_json::to_string(self) - .with_context(|| crate::error::SaveConfigJson { + .map_err(|source| Error::SaveConfigJson { + source, file: file.clone(), })? .as_bytes(), ) - .context(crate::error::SaveConfig { file })?; + .map_err(|source| Error::SaveConfig { source, file })?; Ok(()) } diff --git a/src/db.rs b/src/db.rs index 067f36f..5359321 100644 --- a/src/db.rs +++ b/src/db.rs @@ -179,28 +179,40 @@ impl Db { pub fn load(server: &str, email: &str) -> Result { let file = crate::dirs::db_file(server, email); - let mut fh = std::fs::File::open(&file) - .with_context(|| crate::error::LoadDb { file: file.clone() })?; + let mut fh = + std::fs::File::open(&file).map_err(|source| Error::LoadDb { + source, + file: file.clone(), + })?; let mut json = String::new(); fh.read_to_string(&mut json) - .with_context(|| crate::error::LoadDb { file: file.clone() })?; + .map_err(|source| Error::LoadDb { + source, + file: file.clone(), + })?; let slf: Self = serde_json::from_str(&json) - .context(crate::error::LoadDbJson { file })?; + .map_err(|source| Error::LoadDbJson { source, file })?; Ok(slf) } pub async fn load_async(server: &str, email: &str) -> Result { let file = crate::dirs::db_file(server, email); let mut fh = - tokio::fs::File::open(&file).await.with_context(|| { - crate::error::LoadDbAsync { file: file.clone() } + tokio::fs::File::open(&file).await.map_err(|source| { + Error::LoadDbAsync { + source, + file: file.clone(), + } })?; let mut json = String::new(); - fh.read_to_string(&mut json).await.with_context(|| { - crate::error::LoadDbAsync { file: file.clone() } + fh.read_to_string(&mut json).await.map_err(|source| { + Error::LoadDbAsync { + source, + file: file.clone(), + } })?; let slf: Self = serde_json::from_str(&json) - .context(crate::error::LoadDbJson { file })?; + .map_err(|source| Error::LoadDbJson { source, file })?; Ok(slf) } @@ -209,18 +221,26 @@ impl Db { let file = crate::dirs::db_file(server, email); // unwrap is safe here because Self::filename is explicitly // constructed as a filename in a directory - std::fs::create_dir_all(file.parent().unwrap()) - .with_context(|| crate::error::SaveDb { file: file.clone() })?; - let mut fh = std::fs::File::create(&file) - .with_context(|| crate::error::SaveDb { file: file.clone() })?; + std::fs::create_dir_all(file.parent().unwrap()).map_err( + |source| Error::SaveDb { + source, + file: file.clone(), + }, + )?; + let mut fh = + std::fs::File::create(&file).map_err(|source| Error::SaveDb { + source, + file: file.clone(), + })?; fh.write_all( serde_json::to_string(self) - .with_context(|| crate::error::SaveDbJson { + .map_err(|source| Error::SaveDbJson { + source, file: file.clone(), })? .as_bytes(), ) - .context(crate::error::SaveDb { file })?; + .map_err(|source| Error::SaveDb { source, file })?; Ok(()) } @@ -231,22 +251,27 @@ impl Db { // constructed as a filename in a directory tokio::fs::create_dir_all(file.parent().unwrap()) .await - .with_context(|| crate::error::SaveDbAsync { + .map_err(|source| Error::SaveDbAsync { + source, file: file.clone(), })?; let mut fh = - tokio::fs::File::create(&file).await.with_context(|| { - crate::error::SaveDbAsync { file: file.clone() } + tokio::fs::File::create(&file).await.map_err(|source| { + Error::SaveDbAsync { + source, + file: file.clone(), + } })?; fh.write_all( serde_json::to_string(self) - .with_context(|| crate::error::SaveDbJson { + .map_err(|source| Error::SaveDbJson { + source, file: file.clone(), })? .as_bytes(), ) .await - .context(crate::error::SaveDbAsync { file })?; + .map_err(|source| Error::SaveDbAsync { source, file })?; Ok(()) } @@ -258,7 +283,7 @@ impl Db { return Ok(()); } } - res.context(crate::error::RemoveDb { file })?; + res.map_err(|source| Error::RemoveDb { source, file })?; Ok(()) } diff --git a/src/dirs.rs b/src/dirs.rs index cde00e3..285a0d5 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -3,24 +3,36 @@ use std::os::unix::fs::PermissionsExt as _; pub fn make_all() -> Result<()> { let cache_dir = cache_dir(); - std::fs::create_dir_all(&cache_dir) - .context(crate::error::CreateDirectory { file: cache_dir })?; + std::fs::create_dir_all(&cache_dir).map_err(|source| { + Error::CreateDirectory { + source, + file: cache_dir, + } + })?; let runtime_dir = runtime_dir(); - std::fs::create_dir_all(&runtime_dir).context( - crate::error::CreateDirectory { + std::fs::create_dir_all(&runtime_dir).map_err(|source| { + Error::CreateDirectory { + source, file: runtime_dir.clone(), - }, - )?; + } + })?; std::fs::set_permissions( &runtime_dir, std::fs::Permissions::from_mode(0o700), ) - .context(crate::error::CreateDirectory { file: runtime_dir })?; + .map_err(|source| Error::CreateDirectory { + source, + file: runtime_dir, + })?; let data_dir = data_dir(); - std::fs::create_dir_all(&data_dir) - .context(crate::error::CreateDirectory { file: data_dir })?; + std::fs::create_dir_all(&data_dir).map_err(|source| { + Error::CreateDirectory { + source, + file: data_dir, + } + })?; Ok(()) } diff --git a/src/error.rs b/src/error.rs index cd85c02..3576aa1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,186 +1,183 @@ -#[derive(Debug, snafu::Snafu)] -#[snafu(visibility = "pub")] +#[derive(thiserror::Error, Debug)] pub enum Error { - #[snafu(display("email address not set"))] + #[error("email address not set")] ConfigMissingEmail, - #[snafu(display("failed to create block mode decryptor"))] + #[error("failed to create block mode decryptor")] CreateBlockMode { source: block_modes::InvalidKeyIvLength, }, - #[snafu(display("failed to create directory at {}", file.display()))] + #[error("failed to create directory at {}", .file.display())] CreateDirectory { source: std::io::Error, file: std::path::PathBuf, }, - #[snafu(display("failed to decrypt"))] + #[error("failed to decrypt")] Decrypt { source: block_modes::BlockModeError }, - #[snafu(display("failed to parse pinentry output ({:?})", out))] + #[error("failed to parse pinentry output ({out:?})")] FailedToParsePinentry { out: String }, - #[snafu(display( - "failed to run editor {}: {:?}", - editor.to_string_lossy(), - res - ))] + #[error( + "failed to run editor {}: {res:?}", + .editor.to_string_lossy(), + )] FailedToRunEditor { editor: std::path::PathBuf, res: std::process::ExitStatus, }, - #[snafu(display("failed to expand with hkdf"))] + #[error("failed to expand with hkdf")] HkdfExpand, - #[snafu(display("{}", message))] + #[error("{message}")] IncorrectPassword { message: String }, - #[snafu(display("invalid base64"))] + #[error("invalid base64")] InvalidBase64 { source: base64::DecodeError }, - #[snafu(display("invalid cipherstring: {}", reason))] + #[error("invalid cipherstring: {reason}")] InvalidCipherString { reason: String }, - #[snafu(display( - "invalid value for ${}: {}", - var, - editor.to_string_lossy() - ))] + #[error( + "invalid value for ${var}: {}", + .editor.to_string_lossy() + )] InvalidEditor { var: String, editor: std::ffi::OsString, }, - #[snafu(display("invalid mac"))] + #[error("invalid mac")] InvalidMac, - #[snafu(display("invalid two factor provider type: {}", ty))] + #[error("invalid two factor provider type: {ty}")] InvalidTwoFactorProvider { ty: String }, - #[snafu(display("failed to parse JSON"))] + #[error("failed to parse JSON")] JSON { source: serde_path_to_error::Error, }, - #[snafu(display("failed to load config from {}", file.display()))] + #[error("failed to load config from {}", .file.display())] LoadConfig { source: std::io::Error, file: std::path::PathBuf, }, - #[snafu(display("failed to load config from {}", file.display()))] + #[error("failed to load config from {}", .file.display())] LoadConfigAsync { source: tokio::io::Error, file: std::path::PathBuf, }, - #[snafu(display("failed to load config from {}", file.display()))] + #[error("failed to load config from {}", .file.display())] LoadConfigJson { source: serde_json::Error, file: std::path::PathBuf, }, - #[snafu(display("failed to load db from {}", file.display()))] + #[error("failed to load db from {}", .file.display())] LoadDb { source: std::io::Error, file: std::path::PathBuf, }, - #[snafu(display("failed to load db from {}", file.display()))] + #[error("failed to load db from {}", .file.display())] LoadDbAsync { source: tokio::io::Error, file: std::path::PathBuf, }, - #[snafu(display("failed to load db from {}", file.display()))] + #[error("failed to load db from {}", .file.display())] LoadDbJson { source: serde_json::Error, file: std::path::PathBuf, }, - #[snafu(display("openssl error"))] + #[error("openssl error")] OpenSSL { source: openssl::error::ErrorStack }, - #[snafu(display("failed to parse match type {}", s))] + #[error("failed to parse match type {s}")] ParseMatchType { s: String }, - #[snafu(display("pbkdf2 requires at least 1 iteration (got 0)"))] + #[error("pbkdf2 requires at least 1 iteration (got 0)")] Pbkdf2ZeroIterations, - #[snafu(display("pinentry cancelled"))] + #[error("pinentry cancelled")] PinentryCancelled, - #[snafu(display("pinentry error: {}", error))] + #[error("pinentry error: {error}")] PinentryErrorMessage { error: String }, - #[snafu(display("error reading pinentry output"))] + #[error("error reading pinentry output")] PinentryReadOutput { source: tokio::io::Error }, - #[snafu(display("error waiting for pinentry to exit"))] + #[error("error waiting for pinentry to exit")] PinentryWait { source: tokio::io::Error }, - #[snafu(display("failed to remove db at {}", file.display()))] + #[error("failed to remove db at {}", .file.display())] RemoveDb { source: std::io::Error, file: std::path::PathBuf, }, - #[snafu(display("api request returned error: {}", status))] + #[error("api request returned error: {status}")] RequestFailed { status: u16 }, - #[snafu(display("api request unauthorized"))] + #[error("api request unauthorized")] RequestUnauthorized, - #[snafu(display("error making api request"))] + #[error("error making api request")] Reqwest { source: reqwest::Error }, - #[snafu(display("failed to save config to {}", file.display()))] + #[error("failed to save config to {}", .file.display())] SaveConfig { source: std::io::Error, file: std::path::PathBuf, }, - #[snafu(display("failed to save config to {}", file.display()))] + #[error("failed to save config to {}", .file.display())] SaveConfigJson { source: serde_json::Error, file: std::path::PathBuf, }, - #[snafu(display("failed to save db to {}", file.display()))] + #[error("failed to save db to {}", .file.display())] SaveDb { source: std::io::Error, file: std::path::PathBuf, }, - #[snafu(display("failed to save db to {}", file.display()))] + #[error("failed to save db to {}", .file.display())] SaveDbAsync { source: tokio::io::Error, file: std::path::PathBuf, }, - #[snafu(display("failed to save db to {}", file.display()))] + #[error("failed to save db to {}", .file.display())] SaveDbJson { source: serde_json::Error, file: std::path::PathBuf, }, - #[snafu(display("error spawning pinentry"))] + #[error("error spawning pinentry")] Spawn { source: tokio::io::Error }, - #[snafu(display("cipherstring type {} too old\n\nPlease rotate your account encryption key (https://bitwarden.com/help/article/account-encryption-key/) and try again.", ty))] + #[error("cipherstring type {ty} too old\n\nPlease rotate your account encryption key (https://bitwarden.com/help/article/account-encryption-key/) and try again.")] TooOldCipherStringType { ty: String }, - #[snafu(display("two factor required"))] + #[error("two factor required")] TwoFactorRequired { providers: Vec, }, - #[snafu(display("unimplemented cipherstring type: {}", ty))] + #[error("unimplemented cipherstring type: {ty}")] UnimplementedCipherStringType { ty: String }, - #[snafu(display("error writing to pinentry stdin"))] + #[error("error writing to pinentry stdin")] WriteStdin { source: tokio::io::Error }, } diff --git a/src/identity.rs b/src/identity.rs index 8415765..602940f 100644 --- a/src/identity.rs +++ b/src/identity.rs @@ -13,7 +13,7 @@ impl Identity { iterations: u32, ) -> Result { let iterations = std::num::NonZeroU32::new(iterations) - .context(crate::error::Pbkdf2ZeroIterations)?; + .ok_or(Error::Pbkdf2ZeroIterations)?; let mut keys = crate::locked::Vec::new(); keys.extend(std::iter::repeat(0).take(64)); diff --git a/src/json.rs b/src/json.rs index 2816a1f..d6c5328 100644 --- a/src/json.rs +++ b/src/json.rs @@ -7,15 +7,18 @@ pub trait DeserializeJsonWithPath { impl DeserializeJsonWithPath for String { fn json_with_path(self) -> Result { let jd = &mut serde_json::Deserializer::from_str(&self); - serde_path_to_error::deserialize(jd).context(crate::error::JSON) + serde_path_to_error::deserialize(jd) + .map_err(|source| Error::JSON { source }) } } impl DeserializeJsonWithPath for reqwest::blocking::Response { fn json_with_path(self) -> Result { - let bytes = self.bytes().context(crate::error::Reqwest)?; + let bytes = + self.bytes().map_err(|source| Error::Reqwest { source })?; let jd = &mut serde_json::Deserializer::from_slice(&bytes); - serde_path_to_error::deserialize(jd).context(crate::error::JSON) + serde_path_to_error::deserialize(jd) + .map_err(|source| Error::JSON { source }) } } @@ -31,8 +34,12 @@ impl DeserializeJsonWithPathAsync for reqwest::Response { async fn json_with_path( self, ) -> Result { - let bytes = self.bytes().await.context(crate::error::Reqwest)?; + let bytes = self + .bytes() + .await + .map_err(|source| Error::Reqwest { source })?; let jd = &mut serde_json::Deserializer::from_slice(&bytes); - serde_path_to_error::deserialize(jd).context(crate::error::JSON) + serde_path_to_error::deserialize(jd) + .map_err(|source| Error::JSON { source }) } } diff --git a/src/pinentry.rs b/src/pinentry.rs index 683a880..b055b77 100644 --- a/src/pinentry.rs +++ b/src/pinentry.rs @@ -17,7 +17,7 @@ pub async fn getpin( } else { opts.args(&["-o", "0"]); } - let mut child = opts.spawn().context(crate::error::Spawn)?; + let mut child = opts.spawn().map_err(|source| Error::Spawn { source })?; // unwrap is safe because we specified stdin as piped in the command opts // above let mut stdin = child.stdin.take().unwrap(); @@ -26,29 +26,29 @@ pub async fn getpin( stdin .write_all(b"SETTITLE rbw\n") .await - .context(crate::error::WriteStdin)?; + .map_err(|source| Error::WriteStdin { source })?; ncommands += 1; stdin .write_all(format!("SETPROMPT {}\n", prompt).as_bytes()) .await - .context(crate::error::WriteStdin)?; + .map_err(|source| Error::WriteStdin { source })?; ncommands += 1; stdin .write_all(format!("SETDESC {}\n", desc).as_bytes()) .await - .context(crate::error::WriteStdin)?; + .map_err(|source| Error::WriteStdin { source })?; ncommands += 1; if let Some(err) = err { stdin .write_all(format!("SETERROR {}\n", err).as_bytes()) .await - .context(crate::error::WriteStdin)?; + .map_err(|source| Error::WriteStdin { source })?; ncommands += 1; } stdin .write_all(b"GETPIN\n") .await - .context(crate::error::WriteStdin)?; + .map_err(|source| Error::WriteStdin { source })?; ncommands += 1; drop(stdin); @@ -64,7 +64,10 @@ pub async fn getpin( .await?; buf.truncate(len); - child.wait().await.context(crate::error::PinentryWait)?; + child + .wait() + .await + .map_err(|source| Error::PinentryWait { source })?; Ok(crate::locked::Password::new(buf)) } @@ -130,7 +133,7 @@ where let bytes = r .read(&mut data[len..]) .await - .context(crate::error::PinentryReadOutput)?; + .map_err(|source| Error::PinentryReadOutput { source })?; len += bytes; } } diff --git a/src/prelude.rs b/src/prelude.rs index af8bbd7..af4fb59 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,2 +1 @@ pub use crate::error::{Error, Result}; -pub use snafu::{OptionExt as _, ResultExt as _}; -- cgit v1.2.3