openrtc 2.8.2

OpenRTC: a Rust-first P2P runtime for device discovery, signaling, and iroh/QUIC networking.
Documentation
//! Public Rust API proof: independent device processes retain their own keys,
//! exchange signed public files only, and reopen accepted trust without cloud.
#![cfg(unix)]

use openrtc::native::{load_or_create_endpoint_key, FileSigner};
use openrtc::offline::{
    DurableOfflineTrustState, OfflineAssurance, OfflineDeviceCredential, OfflineEnrollmentRequest,
    OfflineSigner, OfflineTrustBundle,
};
use std::{fs, path::PathBuf, process::Command};

const DEVICE_DIRECTORY: &str = "OPENRTC_OFFLINE_PROVISION_FIXTURE";
const ISSUER_PIN: &str = "OPENRTC_OFFLINE_PROVISION_PUBLIC_PIN";

#[test]
fn signed_files_provision_a_restart_safe_device() {
    if let Some(directory) = std::env::var_os(DEVICE_DIRECTORY) {
        let directory = PathBuf::from(directory);
        let signer = FileSigner::load_or_create(directory.join("proof.key")).unwrap();
        let endpoint = load_or_create_endpoint_key(directory.join("iroh.key")).unwrap();
        let request = OfflineEnrollmentRequest::create(
            &signer,
            "field-a",
            "device-a",
            &endpoint.public().to_string(),
            &uuid::Uuid::new_v4().to_string(),
            vec!["sensor".into()],
            OfflineAssurance::Software,
            1_000,
        )
        .unwrap();
        let bundle_file = directory.join("bundle.json");
        if bundle_file.exists() {
            let pin: [u8; 32] = hex::decode(std::env::var(ISSUER_PIN).unwrap())
                .unwrap()
                .try_into()
                .unwrap();
            let issuer = ed25519_dalek::VerifyingKey::from_bytes(&pin).unwrap();
            let bundle: OfflineTrustBundle =
                serde_json::from_slice(&fs::read(bundle_file).unwrap()).unwrap();
            let mut trust = DurableOfflineTrustState::open(
                directory.join("trust.json"),
                "field-a",
                issuer,
                [],
                2_000,
            )
            .unwrap();
            // Restart reopens the accepted journal. Only a distinct update is
            // applied; replaying a generation as a new update is forbidden.
            if trust
                .trust()
                .high_water()
                .unwrap()
                .map(|water| water.digest)
                != Some(bundle.digest().unwrap())
            {
                trust.apply(bundle, 2_000).unwrap();
            }
            let credential = trust.trust().credential("device-a", 2_000).unwrap();
            assert_eq!(credential.body.endpoint_id, endpoint.public().to_string());
            assert_eq!(
                credential.verify(&issuer, 2_000).unwrap(),
                signer.verifying_key().unwrap()
            );
        }
        println!(
            "OPENRTC_ENROLLMENT {}",
            serde_json::to_string(&request).unwrap()
        );
        return;
    }

    struct Fixture(PathBuf);
    impl Drop for Fixture {
        fn drop(&mut self) {
            let _ = fs::remove_dir_all(&self.0);
        }
    }
    let fixture =
        Fixture(std::env::temp_dir().join(format!("openrtc-provision-{}", uuid::Uuid::new_v4())));
    let device = fixture.0.join("device");
    let issuer =
        FileSigner::load_or_create(fixture.0.join("authority").join("issuer.key")).unwrap();
    let spawn_device = || {
        Command::new(std::env::current_exe().unwrap())
            .args([
                "--exact",
                "signed_files_provision_a_restart_safe_device",
                "--nocapture",
            ])
            .env_clear()
            .env(DEVICE_DIRECTORY, &device)
            .env(
                ISSUER_PIN,
                hex::encode(issuer.verifying_key().unwrap().to_bytes()),
            )
            .output()
            .unwrap()
    };
    let request_from = |output: std::process::Output| -> OfflineEnrollmentRequest {
        assert!(
            output.status.success(),
            "device failed: {}",
            String::from_utf8_lossy(&output.stderr)
        );
        let stdout = String::from_utf8(output.stdout).unwrap();
        let json = stdout
            .lines()
            .find_map(|line| line.split_once("OPENRTC_ENROLLMENT ").map(|(_, json)| json))
            .unwrap();
        serde_json::from_str(json).unwrap()
    };
    let first = request_from(spawn_device());
    first.verify().unwrap();
    let credential = OfflineDeviceCredential::issue(
        &issuer,
        &first,
        "serial-a",
        1,
        vec!["sensor".into()],
        OfflineAssurance::Software,
        1_000,
        10_000,
    )
    .unwrap();
    let bundle =
        OfflineTrustBundle::issue(&issuer, "field-a", 1, None, None, vec![credential], vec![])
            .unwrap();
    let bytes = serde_json::to_vec(&bundle).unwrap();
    fs::write(device.join("bundle.json"), &bytes).unwrap();
    for _ in 0..2 {
        let restarted = request_from(spawn_device());
        assert_eq!(restarted.body.endpoint_id, first.body.endpoint_id);
        assert_eq!(restarted.body.proof_public_key, first.body.proof_public_key);
        assert_ne!(restarted.body.enrollment_nonce, first.body.enrollment_nonce);
    }
    let accepted_journal = fs::read(device.join("trust.json")).unwrap();
    let mut forged = bundle;
    forged.body.credentials[0].body.roles = vec!["admin".into()];
    fs::write(
        device.join("bundle.json"),
        serde_json::to_vec(&forged).unwrap(),
    )
    .unwrap();
    assert!(
        !spawn_device().status.success(),
        "unsigned role escalation must fail"
    );
    assert_eq!(
        fs::read(device.join("trust.json")).unwrap(),
        accepted_journal
    );
    fs::write(device.join("bundle.json"), bytes).unwrap();
    assert_eq!(
        request_from(spawn_device()).body.proof_public_key,
        first.body.proof_public_key
    );
}