76 lines
2.4 KiB
Rust
Raw Normal View History

feat(fips): integrate jmcorgan/fips as preferred non-Tor transport + v1.4.0 Bakes the FIPS (Free Internetworking Peering System) mesh daemon into the node stack, supervised by archipelago alongside Tor. Runs as a system service, identity derives from the same BIP-39 master seed, and user-triggered updates track upstream main. Identity seed.rs: new HKDF label archipelago/fips/secp256k1/v1 → dedicated secp256k1 key, distinct from the Nostr-node key for crypto isolation but still seed-recoverable identity.rs: writes fips_key[.pub] to /data/identity on onboarding, chmod 0600; fips_key_exists / load_fips_keys / fips_npub accessors Transport TransportKind::Fips=3 inserted between LAN and Tor (Tor bumps to 4) → router prefers FIPS over Tor for all peer traffic PeerRecord gains fips_npub + last_fips fields (serde(default) for backward-compat with older nodes) transport/fips.rs: NodeTransport stub, reports unavailable until the daemon is live so router falls through to Tor cleanly Federation invites FederatedNode and FederationInvite carry optional fips_npub create_invite / accept_invite / peer-joined callback thread it end to end; signature domain deliberately unchanged — FIPS Noise does its own session auth, so the unsigned hint only affects path selection crate::fips config.rs: renders /etc/fips/fips.yaml and sudo-installs key material service.rs: systemctl status/activate/restart/mask wrappers update.rs: GitHub API check against upstream main; apply stubbed until per-commit .deb artefact source is decided RPC + dashboard fips.status / fips.check-update / fips.apply-update / fips.install / fips.restart registered in dispatcher HomeNetworkCard.vue shipped standalone (unmounted — place in Home.vue when ready); shows state pill, version, FIPS npub, update button, activate button when key is present but service is down ISO + systemd archipelago-fips.service: conditional on key presence, masked by default — backend unmasks after onboarding writes the key build-auto-installer-iso.sh: multi-stage Dockerfile builds the FIPS .deb from jmcorgan/fips main (fail-loud), COPYs it into rootfs, apt installs it so trixie resolves deps; unit copied + masked Version bump: 1.3.5 → 1.4.0 Tests: 33 new/updated passing (seed, identity, transport, federation, fips module, transport::fips). Known gaps: fips.apply-update returns a clear stub error until upstream publishes per-commit .deb artefacts; HomeNetworkCard is not mounted in Home.vue by default. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 22:57:51 -04:00
//! FIPS mesh transport (Free Internetworking Peering System).
//!
//! Delegates the actual wire protocol to the `fips` system daemon
//! (github.com/jmcorgan/fips), which archipelago supervises via the
//! `archipelago-fips.service` unit. This module is the in-process
//! `NodeTransport` adapter: it checks daemon liveness, maps a peer's
//! FIPS npub to a `fd00::/8` IPv6 TUN address, and POSTs the
//! `TransportMessage` payload over it.
//!
//! Sits at priority 3 between LAN and Tor — preferred over Tor for
//! federation and peer traffic but yielding to direct LAN.
//!
//! Currently a stub: `is_available()` returns false until the FIPS
//! daemon integration in `crate::fips` lands and the key at
//! `/data/identity/fips_key` is materialised via onboarding.
use super::{NodeTransport, TransportKind, TransportMessage};
use anyhow::Result;
use std::path::{Path, PathBuf};
pub struct FipsTransport {
identity_dir: PathBuf,
}
impl FipsTransport {
pub fn new(identity_dir: &Path) -> Self {
Self {
identity_dir: identity_dir.to_path_buf(),
}
}
}
impl NodeTransport for FipsTransport {
fn kind(&self) -> TransportKind {
TransportKind::Fips
}
fn is_available(&self) -> bool {
// Readiness gate: key must be on disk AND daemon wiring must exist.
// The daemon-liveness check is added alongside `crate::fips` — until
// then we deliberately report unavailable so the router falls through
// to Tor and no traffic is misrouted onto a missing TUN.
let _key_present = crate::identity::fips_key_exists(&self.identity_dir);
false
}
fn send<'a>(
&'a self,
_address: &'a str,
_message: &'a TransportMessage,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<()>> + Send + 'a>> {
Box::pin(async move {
anyhow::bail!("FIPS transport not yet wired; daemon integration pending")
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_kind_is_fips() {
let t = FipsTransport::new(std::path::Path::new("/tmp"));
assert_eq!(t.kind(), TransportKind::Fips);
}
#[test]
fn test_reports_unavailable_pre_wiring() {
let dir = tempfile::tempdir().unwrap();
let t = FipsTransport::new(dir.path());
// Stub: always unavailable until daemon integration lands.
assert!(!t.is_available());
}
}