From 3dacedce7148415fc5680cc696d4d9b3da4d3f45 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 9 Jul 2020 09:48:30 +0200 Subject: [PATCH] src/backup/manifest.rs: use serde_json::from_value() to deserialize data Also modified from_data compute signature ditectly from json. --- src/backup/manifest.rs | 61 ++++++++----------------------------- src/client/backup_writer.rs | 6 ++-- 2 files changed, 14 insertions(+), 53 deletions(-) diff --git a/src/backup/manifest.rs b/src/backup/manifest.rs index 8b0567e3..83e39e9c 100644 --- a/src/backup/manifest.rs +++ b/src/backup/manifest.rs @@ -168,8 +168,12 @@ impl BackupManifest { /// By generating a HMAC SHA256 over the canonical json /// representation, The 'unpreotected' property is excluded. pub fn signature(&self, crypt_config: &CryptConfig) -> Result<[u8; 32], Error> { + Self::json_signature(&serde_json::to_value(&self)?, crypt_config) + } - let mut signed_data = serde_json::to_value(&self)?; + fn json_signature(data: &Value, crypt_config: &CryptConfig) -> Result<[u8; 32], Error> { + + let mut signed_data = data.clone(); signed_data.as_object_mut().unwrap().remove("unprotected"); // exclude @@ -199,11 +203,10 @@ impl BackupManifest { pub fn from_data(data: &[u8], crypt_config: Option<&CryptConfig>) -> Result { let json: Value = serde_json::from_slice(data)?; let signature = json["signature"].as_str().map(String::from); - let manifest = BackupManifest::try_from(json)?; if let Some(ref crypt_config) = crypt_config { if let Some(signature) = signature { - let expected_signature = proxmox::tools::digest_to_hex(&manifest.signature(crypt_config)?); + let expected_signature = proxmox::tools::digest_to_hex(&Self::json_signature(&json, crypt_config)?); if signature != expected_signature { bail!("wrong signature in manifest"); } @@ -211,10 +214,13 @@ impl BackupManifest { // not signed: warn/fail? } } + + let manifest: BackupManifest = serde_json::from_value(json)?; Ok(manifest) } } + impl TryFrom for BackupManifest { type Error = Error; @@ -223,54 +229,11 @@ impl TryFrom for BackupManifest { .map_err(|err| format_err!("decode backup manifest blob failed - {}", err))?; let json: Value = serde_json::from_slice(&data[..]) .map_err(|err| format_err!("unable to parse backup manifest json - {}", err))?; - BackupManifest::try_from(json) + let manifest: BackupManifest = serde_json::from_value(json)?; + Ok(manifest) } } -impl TryFrom for BackupManifest { - type Error = Error; - - fn try_from(data: Value) -> Result { - - use crate::tools::{required_string_property, required_integer_property, required_array_property}; - - proxmox::try_block!({ - let backup_type = required_string_property(&data, "backup-type")?; - let backup_id = required_string_property(&data, "backup-id")?; - let backup_time = required_integer_property(&data, "backup-time")?; - - let snapshot = BackupDir::new(backup_type, backup_id, backup_time); - - let mut manifest = BackupManifest::new(snapshot); - - for item in required_array_property(&data, "files")?.iter() { - let filename = required_string_property(item, "filename")?.to_owned(); - let csum = required_string_property(item, "csum")?; - let csum = proxmox::tools::hex_to_digest(csum)?; - let size = required_integer_property(item, "size")? as u64; - - let mut crypt_mode = CryptMode::None; - - if let Some(true) = item["encrypted"].as_bool() { // compatible to < 0.8.0 - crypt_mode = CryptMode::Encrypt; - } - - if let Some(mode) = item.get("crypt-mode") { - crypt_mode = serde_json::from_value(mode.clone())?; - } - - manifest.add_file(filename, size, csum, crypt_mode)?; - } - - if manifest.files().is_empty() { - bail!("manifest does not list any files."); - } - - Ok(manifest) - }).map_err(|err: Error| format_err!("unable to parse backup manifest - {}", err)) - - } -} #[test] fn test_manifest_signature() -> Result<(), Error> { @@ -306,7 +269,7 @@ fn test_manifest_signature() -> Result<(), Error> { assert_eq!(signature, "d7b446fb7db081662081d4b40fedd858a1d6307a5aff4ecff7d5bf4fd35679e9"); - let manifest = BackupManifest::try_from(manifest)?; + let manifest: BackupManifest = serde_json::from_value(manifest)?; let expected_signature = proxmox::tools::digest_to_hex(&manifest.signature(&crypt_config)?); assert_eq!(signature, expected_signature); diff --git a/src/client/backup_writer.rs b/src/client/backup_writer.rs index 8cad52bb..079213d4 100644 --- a/src/client/backup_writer.rs +++ b/src/client/backup_writer.rs @@ -453,8 +453,6 @@ impl BackupWriter { /// Download backup manifest (index.json) of last backup pub async fn download_previous_manifest(&self) -> Result { - use std::convert::TryFrom; - let mut raw_data = Vec::with_capacity(64 * 1024); let param = json!({ "archive-name": MANIFEST_BLOB_NAME }); @@ -463,8 +461,8 @@ impl BackupWriter { let blob = DataBlob::from_raw(raw_data)?; blob.verify_crc()?; let data = blob.decode(self.crypt_config.as_ref().map(Arc::as_ref))?; - let json: Value = serde_json::from_slice(&data[..])?; - let manifest = BackupManifest::try_from(json)?; + + let manifest = BackupManifest::from_data(&data[..], self.crypt_config.as_ref().map(Arc::as_ref))?; Ok(manifest) }