1use crate::{NookError, Result};
2use serde::{Deserialize, Serialize};
3use sha2::{Digest, Sha256};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
7pub enum ObjectType {
8 Manifest,
9 Content,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub enum NodeType {
14 #[serde(rename = "file")]
15 File,
16 #[serde(rename = "directory")]
17 Directory,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct Node {
22 pub node_id: u64,
23 pub parent_id: Option<u64>,
24 pub name: String,
25 pub node_type: NodeType,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub content_object_id: Option<[u8; 32]>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub wrapped_dek: Option<Vec<u8>>,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub logical_size: Option<u64>,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct Manifest {
36 pub manifest_version: u32,
37 pub root_node_id: u64,
38 pub nodes: Vec<Node>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub previous_manifest_hash: Option<String>,
41 pub integrity_checksum: String,
42}
43
44#[derive(Serialize)]
45struct ManifestIntegrityView<'a> {
46 manifest_version: u32,
47 root_node_id: u64,
48 nodes: &'a [Node],
49 #[serde(skip_serializing_if = "Option::is_none")]
50 previous_manifest_hash: &'a Option<String>,
51}
52
53impl Manifest {
54 pub fn compute_integrity(&self) -> Result<String> {
55 let view = ManifestIntegrityView {
56 manifest_version: self.manifest_version,
57 root_node_id: self.root_node_id,
58 nodes: &self.nodes,
59 previous_manifest_hash: &self.previous_manifest_hash,
60 };
61 let bytes =
62 serde_json::to_vec(&view).map_err(|e| NookError::Serialization(e.to_string()))?;
63 Ok(hex::encode(Sha256::digest(bytes)))
64 }
65
66 pub fn validate_integrity(&self) -> Result<()> {
67 let expected = self.compute_integrity()?;
68 if expected != self.integrity_checksum {
69 return Err(NookError::Integrity("manifest checksum mismatch".into()));
70 }
71 Ok(())
72 }
73}