revault_lockbox_api 0.0.4

reVault lockbox API to create and manage lockboxes
Documentation
use revault_lockbox_api::{
    Lockbox, LockboxPath, LockboxProtection, OwnerSigningKeyPair, RecoveryReportOptions,
    RecoveryScanner, SecretVec,
};

fn main() -> revault_lockbox_api::Result<()> {
    let root = example_root("recovery")?;
    let lockbox_file = root.join("recovery.lbox");
    let signing_key = OwnerSigningKeyPair::generate()?;
    let content_key = random_content_key()?;

    let mut lockbox = Lockbox::create_file(
        &lockbox_file,
        LockboxProtection::ContentKey(content_key.try_clone()?),
        &signing_key,
    )?;
    lockbox.create_dir(&path("/docs")?, false)?;
    lockbox.add_file(&path("/docs/a.txt")?, b"alpha", false)?;
    lockbox.add_file(&path("/docs/b.txt")?, b"bravo", false)?;
    lockbox.commit()?;

    let mut damaged = std::fs::read(&lockbox_file)
        .map_err(|err| revault_lockbox_api::Error::Io(err.to_string()))?;
    damaged[0] ^= 0xff;

    let report = content_key.with_bytes(|key| RecoveryScanner::scan_bytes(damaged.clone(), key))?;
    println!("{}", report.render(&RecoveryReportOptions::default()));

    let salvaged =
        RecoveryScanner::salvage_bytes_with_secret_key(damaged, &content_key, &signing_key)?;
    println!(
        "recovered /docs/a.txt: {}",
        String::from_utf8_lossy(&salvaged.get_file(&path("/docs/a.txt")?)?)
    );
    Ok(())
}

fn random_content_key() -> revault_lockbox_api::Result<SecretVec> {
    let mut key = SecretVec::new();
    key.resize_zeroed(32)?;
    key.with_mut_bytes(|bytes| {
        getrandom::fill(bytes).map_err(|err| revault_lockbox_api::Error::Io(err.to_string()))
    })??;
    Ok(key)
}

fn path(value: &str) -> revault_lockbox_api::Result<LockboxPath> {
    LockboxPath::new(value)
}

fn example_root(name: &str) -> revault_lockbox_api::Result<std::path::PathBuf> {
    let root = std::env::temp_dir()
        .join("lockbox-core-examples")
        .join(name);
    match std::fs::remove_dir_all(&root) {
        Ok(()) => {}
        Err(err) if err.kind() == std::io::ErrorKind::NotFound => {}
        Err(err) => return Err(revault_lockbox_api::Error::Io(err.to_string())),
    }
    std::fs::create_dir_all(&root)
        .map_err(|err| revault_lockbox_api::Error::Io(err.to_string()))?;
    Ok(root)
}