anubis-wormhole 1.0.0

A post-quantum secure file transfer tool based on the Magic Wormhole protocol.
Documentation
use serde::{Deserialize, Serialize};
use std::fs::{self, OpenOptions};
use std::io::{BufWriter, Write};
use std::path::PathBuf;

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "t", content = "v")]
pub enum JournalEvent {
    PakeStart { code_len: usize },
    PakeDone,
    KemSentPubkey,
    KemGotCiphertext,
    KeysDerived,
    Rekey,
    Close,
    // Mailbox/session events for replay
    MailboxAllocated { nameplate: String },
    MailboxClaimed { nameplate: String },
    MailboxOpened { mailbox: String },
    MailboxReleased { nameplate: String },
    MailboxClosed { mailbox: String, mood: String },
    // Subchannel / framing events
    SubchDuplicate { subchannel: u32, expected: u64, got: u64 },
    SubchOutOfOrder { subchannel: u32, expected: u64, got: u64 },
    SubchFinAfterFin { subchannel: u32 },
    SubchQueueOverflow { subchannel: u32, capacity: usize },
}

pub trait Journal {
    fn record(&mut self, ev: &JournalEvent);
}

pub struct FileJournal {
    path: PathBuf,
}

impl FileJournal {
    pub fn new(path: PathBuf) -> Self { Self { path } }
}

impl Journal for FileJournal {
    fn record(&mut self, ev: &JournalEvent) {
        if let Ok(f) = OpenOptions::new().create(true).append(true).open(&self.path) {
            let mut w = BufWriter::new(f);
            if let Ok(line) = serde_json::to_string(ev) {
                let _ = writeln!(w, "{}", line);
            }
            let _ = w.flush();
        }
    }
}

pub struct NoopJournal;
impl Journal for NoopJournal {
    fn record(&mut self, _ev: &JournalEvent) {}
}

pub fn read_all(path: &PathBuf) -> Vec<JournalEvent> {
    let data = fs::read_to_string(path).unwrap_or_default();
    data.lines()
        .filter_map(|l| serde_json::from_str::<JournalEvent>(l).ok())
        .collect()
}