1use std::io::{Read as _, Write as _};23use age::{Identity, Recipient};4use anyhow::{Context as _, Result, anyhow, bail};5use camino::Utf8PathBuf;6use serde::{Deserialize, Serialize};78use crate::MANIFEST_VERSION;910#[derive(Serialize, Deserialize, Debug, Clone)]11#[serde(rename_all = "camelCase")]12pub struct Manifest {13 pub version: u32,14 pub host: String,15 pub toplevel: Utf8PathBuf,16 pub paths: Vec<PathEntry>,17}1819#[derive(Serialize, Deserialize, Debug, Clone)]20#[serde(rename_all = "camelCase")]21pub struct PathEntry {22 pub store_path: Utf8PathBuf,23 pub nar_hash: String,24 pub nar_size: u64,25 pub references: Vec<Utf8PathBuf>,26 pub sigs: Vec<String>,27 pub compression: String,28 pub key: String,29 pub chunks: Vec<String>,30}3132pub fn encrypt_manifest<'r>(33 manifest: &Manifest,34 recipients: impl Iterator<Item = &'r dyn Recipient>,35) -> Result<Vec<u8>> {36 let json = serde_json::to_vec(manifest)?;37 let mut out = Vec::new();38 let mut encryptor = age::Encryptor::with_recipients(recipients)39 .map_err(|e| anyhow!("no recipients: {e}"))?40 .wrap_output(&mut out)41 .context("age encrypt")?;42 encryptor.write_all(&json)?;43 encryptor.finish()?;44 Ok(out)45}4647pub fn decrypt_manifest(data: &[u8], identity: &dyn Identity) -> Result<Manifest> {48 let decryptor = age::Decryptor::new(data).context("age decrypt")?;49 let mut reader = decryptor50 .decrypt(std::iter::once(identity))51 .context("manifest is not encrypted for this identity")?;52 let mut json = Vec::new();53 reader.read_to_end(&mut json)?;54 let manifest: Manifest = serde_json::from_slice(&json).context("manifest json")?;55 if manifest.version != MANIFEST_VERSION {56 bail!(57 "unsupported manifest version {}, this fleet-usbd supports {MANIFEST_VERSION}",58 manifest.version59 );60 }61 Ok(manifest)62}