src/backup/manifest.rs: use serde_json::from_value() to deserialize data
Also modified from_data compute signature ditectly from json.
This commit is contained in:
parent
512d50a455
commit
3dacedce71
@ -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<BackupManifest, Error> {
|
||||
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<super::DataBlob> for BackupManifest {
|
||||
type Error = Error;
|
||||
|
||||
@ -223,54 +229,11 @@ impl TryFrom<super::DataBlob> 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<Value> for BackupManifest {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(data: Value) -> Result<Self, Error> {
|
||||
|
||||
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);
|
||||
|
@ -453,8 +453,6 @@ impl BackupWriter {
|
||||
/// Download backup manifest (index.json) of last backup
|
||||
pub async fn download_previous_manifest(&self) -> Result<BackupManifest, Error> {
|
||||
|
||||
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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user