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
|
/// By generating a HMAC SHA256 over the canonical json
|
||||||
/// representation, The 'unpreotected' property is excluded.
|
/// representation, The 'unpreotected' property is excluded.
|
||||||
pub fn signature(&self, crypt_config: &CryptConfig) -> Result<[u8; 32], Error> {
|
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
|
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> {
|
pub fn from_data(data: &[u8], crypt_config: Option<&CryptConfig>) -> Result<BackupManifest, Error> {
|
||||||
let json: Value = serde_json::from_slice(data)?;
|
let json: Value = serde_json::from_slice(data)?;
|
||||||
let signature = json["signature"].as_str().map(String::from);
|
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(ref crypt_config) = crypt_config {
|
||||||
if let Some(signature) = signature {
|
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 {
|
if signature != expected_signature {
|
||||||
bail!("wrong signature in manifest");
|
bail!("wrong signature in manifest");
|
||||||
}
|
}
|
||||||
@ -211,10 +214,13 @@ impl BackupManifest {
|
|||||||
// not signed: warn/fail?
|
// not signed: warn/fail?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let manifest: BackupManifest = serde_json::from_value(json)?;
|
||||||
Ok(manifest)
|
Ok(manifest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl TryFrom<super::DataBlob> for BackupManifest {
|
impl TryFrom<super::DataBlob> for BackupManifest {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
@ -223,54 +229,11 @@ impl TryFrom<super::DataBlob> for BackupManifest {
|
|||||||
.map_err(|err| format_err!("decode backup manifest blob failed - {}", err))?;
|
.map_err(|err| format_err!("decode backup manifest blob failed - {}", err))?;
|
||||||
let json: Value = serde_json::from_slice(&data[..])
|
let json: Value = serde_json::from_slice(&data[..])
|
||||||
.map_err(|err| format_err!("unable to parse backup manifest json - {}", err))?;
|
.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]
|
#[test]
|
||||||
fn test_manifest_signature() -> Result<(), Error> {
|
fn test_manifest_signature() -> Result<(), Error> {
|
||||||
@ -306,7 +269,7 @@ fn test_manifest_signature() -> Result<(), Error> {
|
|||||||
|
|
||||||
assert_eq!(signature, "d7b446fb7db081662081d4b40fedd858a1d6307a5aff4ecff7d5bf4fd35679e9");
|
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)?);
|
let expected_signature = proxmox::tools::digest_to_hex(&manifest.signature(&crypt_config)?);
|
||||||
|
|
||||||
assert_eq!(signature, expected_signature);
|
assert_eq!(signature, expected_signature);
|
||||||
|
@ -453,8 +453,6 @@ impl BackupWriter {
|
|||||||
/// Download backup manifest (index.json) of last backup
|
/// Download backup manifest (index.json) of last backup
|
||||||
pub async fn download_previous_manifest(&self) -> Result<BackupManifest, Error> {
|
pub async fn download_previous_manifest(&self) -> Result<BackupManifest, Error> {
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
|
|
||||||
let mut raw_data = Vec::with_capacity(64 * 1024);
|
let mut raw_data = Vec::with_capacity(64 * 1024);
|
||||||
|
|
||||||
let param = json!({ "archive-name": MANIFEST_BLOB_NAME });
|
let param = json!({ "archive-name": MANIFEST_BLOB_NAME });
|
||||||
@ -463,8 +461,8 @@ impl BackupWriter {
|
|||||||
let blob = DataBlob::from_raw(raw_data)?;
|
let blob = DataBlob::from_raw(raw_data)?;
|
||||||
blob.verify_crc()?;
|
blob.verify_crc()?;
|
||||||
let data = blob.decode(self.crypt_config.as_ref().map(Arc::as_ref))?;
|
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)
|
Ok(manifest)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user