aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2020-05-23 16:16:25 -0400
committerJesse Luehrs <doy@tozt.net>2020-05-23 16:16:25 -0400
commit80acb66445a612798ddf74bd6df60b51fd674fa0 (patch)
tree9c6b5fe2cb6bf33c79523a2ab2dcd9d0124c3e32
parentc9473e0b61bc9d8264a6ce939ed74c3d9b8f4db5 (diff)
downloadrbw-80acb66445a612798ddf74bd6df60b51fd674fa0.tar.gz
rbw-80acb66445a612798ddf74bd6df60b51fd674fa0.zip
better error messages when parsing a server message
-rw-r--r--Cargo.lock22
-rw-r--r--Cargo.toml2
-rw-r--r--src/api.rs26
-rw-r--r--src/error.rs5
-rw-r--r--src/json.rs38
-rw-r--r--src/lib.rs1
6 files changed, 80 insertions, 14 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f9afe4e..2fdcb51 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -84,6 +84,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]]
+name = "async-trait"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26c4f3195085c36ea8d24d32b2f828d23296a9370a28aa39d111f6f16bef9f3b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1110,6 +1121,7 @@ dependencies = [
"aes",
"anyhow",
"arrayvec",
+ "async-trait",
"base64 0.12.1",
"block-modes",
"chbs",
@@ -1129,6 +1141,7 @@ dependencies = [
"ring",
"serde",
"serde_json",
+ "serde_path_to_error",
"snafu",
"structopt",
"tempfile",
@@ -1333,6 +1346,15 @@ dependencies = [
]
[[package]]
+name = "serde_path_to_error"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "359b895005d818163c78a24d272cc98567cce80c2461cf73f513da1d296c0b62"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "serde_urlencoded"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index f2decf3..e3bb413 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,6 +15,7 @@ license = "MIT"
aes = "0.3"
anyhow = "1.0"
arrayvec = "0.5"
+async-trait = "0.1"
base64 = "0.12"
block-modes = "0.3"
chbs = "0.0.10"
@@ -34,6 +35,7 @@ reqwest = { version = "0.10", features = ["blocking", "json"] }
ring = "0.16"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
+serde_path_to_error = "0.1"
snafu = "0.6"
structopt = { version = "0.3", features = ["paw"] }
tempfile = "3.1"
diff --git a/src/api.rs b/src/api.rs
index 09c90b1..c0125d6 100644
--- a/src/api.rs
+++ b/src/api.rs
@@ -1,5 +1,9 @@
use crate::prelude::*;
+use crate::json::{
+ DeserializeJsonWithPath as _, DeserializeJsonWithPathAsync as _,
+};
+
#[derive(serde::Serialize, Debug)]
struct PreloginReq {
email: String,
@@ -385,8 +389,7 @@ impl Client {
.send()
.await
.context(crate::error::Reqwest)?;
- let prelogin_res: PreloginRes =
- res.json().await.context(crate::error::Reqwest)?;
+ let prelogin_res: PreloginRes = res.json_with_path().await?;
Ok(prelogin_res.kdf_iterations)
}
@@ -417,7 +420,7 @@ impl Client {
.context(crate::error::Reqwest)?;
if let reqwest::StatusCode::OK = res.status() {
let connect_res: ConnectPasswordRes =
- res.json().await.context(crate::error::Reqwest)?;
+ res.json_with_path().await?;
Ok((
connect_res.access_token,
connect_res.refresh_token,
@@ -425,8 +428,7 @@ impl Client {
))
} else {
let code = res.status().as_u16();
- let error_res: ConnectErrorRes =
- res.json().await.context(crate::error::Reqwest)?;
+ let error_res: ConnectErrorRes = res.json_with_path().await?;
if error_res.error_model.message
== "Username or password is incorrect. Try again"
{
@@ -455,8 +457,7 @@ impl Client {
.context(crate::error::Reqwest)?;
match res.status() {
reqwest::StatusCode::OK => {
- let sync_res: SyncRes =
- res.json().await.context(crate::error::Reqwest)?;
+ let sync_res: SyncRes = res.json_with_path().await?;
let folders = sync_res.folders.clone();
let ciphers = sync_res
.ciphers
@@ -760,8 +761,7 @@ impl Client {
.context(crate::error::Reqwest)?;
match res.status() {
reqwest::StatusCode::OK => {
- let folders_res: FoldersRes =
- res.json().context(crate::error::Reqwest)?;
+ let folders_res: FoldersRes = res.json_with_path()?;
Ok(folders_res
.data
.iter()
@@ -794,8 +794,7 @@ impl Client {
.context(crate::error::Reqwest)?;
match res.status() {
reqwest::StatusCode::OK => {
- let folders_res: FoldersResData =
- res.json().context(crate::error::Reqwest)?;
+ let folders_res: FoldersResData = res.json_with_path()?;
Ok(folders_res.id)
}
reqwest::StatusCode::UNAUTHORIZED => {
@@ -822,8 +821,7 @@ impl Client {
.form(&connect_req)
.send()
.context(crate::error::Reqwest)?;
- let connect_res: ConnectRefreshTokenRes =
- res.json().context(crate::error::Reqwest)?;
+ let connect_res: ConnectRefreshTokenRes = res.json_with_path()?;
Ok(connect_res.access_token)
}
@@ -844,7 +842,7 @@ impl Client {
.await
.context(crate::error::Reqwest)?;
let connect_res: ConnectRefreshTokenRes =
- res.json().await.context(crate::error::Reqwest)?;
+ res.json_with_path().await?;
Ok(connect_res.access_token)
}
diff --git a/src/error.rs b/src/error.rs
index a6e6a84..6e8a51e 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -43,6 +43,11 @@ pub enum Error {
#[snafu(display("invalid mac"))]
InvalidMac,
+ #[snafu(display("{}", source))]
+ JSON {
+ source: serde_path_to_error::Error<serde_json::Error>,
+ },
+
#[snafu(display("failed to load config: {}", source))]
LoadConfig { source: std::io::Error },
diff --git a/src/json.rs b/src/json.rs
new file mode 100644
index 0000000..2816a1f
--- /dev/null
+++ b/src/json.rs
@@ -0,0 +1,38 @@
+use crate::prelude::*;
+
+pub trait DeserializeJsonWithPath {
+ fn json_with_path<T: serde::de::DeserializeOwned>(self) -> Result<T>;
+}
+
+impl DeserializeJsonWithPath for String {
+ fn json_with_path<T: serde::de::DeserializeOwned>(self) -> Result<T> {
+ let jd = &mut serde_json::Deserializer::from_str(&self);
+ serde_path_to_error::deserialize(jd).context(crate::error::JSON)
+ }
+}
+
+impl DeserializeJsonWithPath for reqwest::blocking::Response {
+ fn json_with_path<T: serde::de::DeserializeOwned>(self) -> Result<T> {
+ let bytes = self.bytes().context(crate::error::Reqwest)?;
+ let jd = &mut serde_json::Deserializer::from_slice(&bytes);
+ serde_path_to_error::deserialize(jd).context(crate::error::JSON)
+ }
+}
+
+#[async_trait::async_trait]
+pub trait DeserializeJsonWithPathAsync {
+ async fn json_with_path<T: serde::de::DeserializeOwned>(
+ self,
+ ) -> Result<T>;
+}
+
+#[async_trait::async_trait]
+impl DeserializeJsonWithPathAsync for reqwest::Response {
+ async fn json_with_path<T: serde::de::DeserializeOwned>(
+ self,
+ ) -> Result<T> {
+ let bytes = self.bytes().await.context(crate::error::Reqwest)?;
+ let jd = &mut serde_json::Deserializer::from_slice(&bytes);
+ serde_path_to_error::deserialize(jd).context(crate::error::JSON)
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index f010bf0..6605c22 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,6 +19,7 @@ pub mod dirs;
pub mod edit;
pub mod error;
pub mod identity;
+pub mod json;
pub mod locked;
pub mod pinentry;
mod prelude;