print better errors when deserializing json (#218)
- print stripped json whenever there is a type mismatch when deserializing - Revert "print stripped json whenever there is a type mismatch when deserializing" - print better errors when deserializing json
This commit is contained in:
parent
f080e35971
commit
2dc6376533
5 changed files with 71 additions and 26 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -1840,6 +1840,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_path_to_error"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
@ -2089,6 +2098,7 @@ dependencies = [
|
|||
"secrecy",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"standback",
|
||||
"stderrlog",
|
||||
"steamguard",
|
||||
|
|
|
@ -60,6 +60,7 @@ qrcode = { version = "0.12.0", optional = true }
|
|||
gethostname = "0.4.3"
|
||||
secrecy = { version = "0.8", features = ["serde"] }
|
||||
zeroize = "^1.4.3"
|
||||
serde_path_to_error = "0.1.11"
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
|
|
|
@ -53,7 +53,8 @@ impl AccountManager {
|
|||
let mut reader = BufReader::new(file);
|
||||
let mut buffer = String::new();
|
||||
reader.read_to_string(&mut buffer)?;
|
||||
let manifest: Manifest = match serde_json::from_str(&buffer) {
|
||||
let mut deser = serde_json::Deserializer::from_str(&buffer);
|
||||
let manifest: Manifest = match serde_path_to_error::deserialize(&mut deser) {
|
||||
Ok(m) => m,
|
||||
Err(orig_err) => match serde_json::from_str::<SdaManifest>(&buffer) {
|
||||
Ok(_) => return Err(ManifestLoadError::MigrationNeeded)?,
|
||||
|
@ -159,7 +160,8 @@ impl AccountManager {
|
|||
|
||||
let file = File::open(path)?;
|
||||
let reader = BufReader::new(file);
|
||||
let account: SteamGuardAccount = serde_json::from_reader(reader)?;
|
||||
let mut deser = serde_json::Deserializer::from_reader(reader);
|
||||
let account: SteamGuardAccount = serde_path_to_error::deserialize(&mut deser)?;
|
||||
ensure!(
|
||||
!self.account_exists(&account.account_name),
|
||||
"Account already exists in manifest, please remove it first."
|
||||
|
@ -361,12 +363,16 @@ impl EntryLoader<SteamGuardAccount> for ManifestEntry {
|
|||
return Err(ManifestAccountLoadError::IncorrectPasskey);
|
||||
}
|
||||
let s = std::str::from_utf8(&plaintext).unwrap();
|
||||
serde_json::from_str(s)?
|
||||
let mut deser = serde_json::Deserializer::from_str(s);
|
||||
serde_path_to_error::deserialize(&mut deser)?
|
||||
}
|
||||
(None, Some(_)) => {
|
||||
return Err(ManifestAccountLoadError::MissingPasskey);
|
||||
}
|
||||
(_, None) => serde_json::from_reader(reader)?,
|
||||
(_, None) => {
|
||||
let mut deser = serde_json::Deserializer::from_reader(reader);
|
||||
serde_path_to_error::deserialize(&mut deser)?
|
||||
}
|
||||
};
|
||||
Ok(account)
|
||||
}
|
||||
|
@ -378,8 +384,8 @@ pub enum ManifestLoadError {
|
|||
Missing(#[from] std::io::Error),
|
||||
#[error("Manifest needs to be migrated to the latest format.")]
|
||||
MigrationNeeded,
|
||||
#[error("Failed to deserialize the manifest.")]
|
||||
DeserializationFailed(#[from] serde_json::Error),
|
||||
#[error("Failed to deserialize the manifest. {self:?}")]
|
||||
DeserializationFailed(#[from] serde_path_to_error::Error<serde_json::Error>),
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
@ -394,8 +400,8 @@ pub enum ManifestAccountLoadError {
|
|||
IncorrectPasskey,
|
||||
#[error("Failed to decrypt account. {self:?}")]
|
||||
DecryptionFailed(#[from] crate::encryption::EntryEncryptionError),
|
||||
#[error("Failed to deserialize the account.")]
|
||||
DeserializationFailed(#[from] serde_json::Error),
|
||||
#[error("Failed to deserialize the account. {self:?}")]
|
||||
DeserializationFailed(#[from] serde_path_to_error::Error<serde_json::Error>),
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
|
|
@ -88,12 +88,16 @@ impl EntryLoader<SdaAccount> for SdaManifestEntry {
|
|||
return Err(ManifestAccountLoadError::IncorrectPasskey);
|
||||
}
|
||||
let s = std::str::from_utf8(&plaintext).unwrap();
|
||||
serde_json::from_str(s)?
|
||||
let mut deser = serde_json::Deserializer::from_str(s);
|
||||
serde_path_to_error::deserialize(&mut deser)?
|
||||
}
|
||||
(None, Some(_)) => {
|
||||
return Err(ManifestAccountLoadError::MissingPasskey);
|
||||
}
|
||||
(_, None) => serde_json::from_reader(reader)?,
|
||||
(_, None) => {
|
||||
let mut deser = serde_json::Deserializer::from_reader(reader);
|
||||
serde_path_to_error::deserialize(&mut deser)?
|
||||
}
|
||||
};
|
||||
Ok(account)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{fs::File, io::Read, path::Path};
|
||||
|
||||
use log::debug;
|
||||
use serde::de::Error;
|
||||
use serde::{de::Error, Deserialize};
|
||||
use steamguard::SteamGuardAccount;
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -82,7 +82,7 @@ pub(crate) enum MigrationError {
|
|||
#[error("Passkey is required to decrypt manifest")]
|
||||
MissingPasskey,
|
||||
#[error("Failed to deserialize manifest: {0}")]
|
||||
ManifestDeserializeFailed(serde_json::Error),
|
||||
ManifestDeserializeFailed(serde_path_to_error::Error<serde_json::Error>),
|
||||
#[error("IO error when upgrading manifest: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
#[error("An unexpected error occurred during manifest migration: {0}")]
|
||||
|
@ -180,20 +180,44 @@ impl From<MigratingManifest> for Manifest {
|
|||
}
|
||||
}
|
||||
|
||||
fn deserialize_manifest(text: String) -> Result<MigratingManifest, serde_json::Error> {
|
||||
let json: serde_json::Value = serde_json::from_str(&text)?;
|
||||
debug!("deserializing manifest: version {}", json["version"]);
|
||||
if json["version"] == 1 {
|
||||
let manifest: ManifestV1 = serde_json::from_str(&text)?;
|
||||
Ok(MigratingManifest::ManifestV1(manifest))
|
||||
} else if json["version"] == serde_json::Value::Null {
|
||||
let manifest: SdaManifest = serde_json::from_str(&text)?;
|
||||
Ok(MigratingManifest::Sda(manifest))
|
||||
} else {
|
||||
Err(serde_json::Error::custom(format!(
|
||||
"Unknown manifest version: {}",
|
||||
json["version"]
|
||||
)))
|
||||
#[derive(Deserialize)]
|
||||
struct JustVersion {
|
||||
version: Option<u32>,
|
||||
}
|
||||
|
||||
fn deserialize_manifest(
|
||||
text: String,
|
||||
) -> Result<MigratingManifest, serde_path_to_error::Error<serde_json::Error>> {
|
||||
let mut deser = serde_json::Deserializer::from_str(&text);
|
||||
let version: JustVersion = serde_path_to_error::deserialize(&mut deser)?;
|
||||
|
||||
debug!("deserializing manifest: version {:?}", version.version);
|
||||
let mut deser = serde_json::Deserializer::from_str(&text);
|
||||
|
||||
match version.version {
|
||||
Some(1) => {
|
||||
let manifest: ManifestV1 = serde_path_to_error::deserialize(&mut deser)?;
|
||||
Ok(MigratingManifest::ManifestV1(manifest))
|
||||
}
|
||||
None => {
|
||||
let manifest: SdaManifest = serde_path_to_error::deserialize(&mut deser)?;
|
||||
Ok(MigratingManifest::Sda(manifest))
|
||||
}
|
||||
_ => {
|
||||
// HACK: there's no way to construct the Path type, so we create it by forcing a deserialize error
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Dummy;
|
||||
impl<'de> Deserialize<'de> for Dummy {
|
||||
fn deserialize<D: serde::Deserializer<'de>>(_: D) -> Result<Self, D::Error> {
|
||||
Err(D::Error::custom("Unknown manifest version".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
let mut deser = serde_json::Deserializer::from_str("");
|
||||
let err = serde_path_to_error::deserialize::<_, Dummy>(&mut deser).unwrap_err();
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue