2 Commits

Author SHA1 Message Date
Dorian
274ed008fe feat(fips): peer dialing + dedicated fips0 listener with path whitelist
Wires the FIPS transport end-to-end so peer-to-peer calls can reach
other nodes over the mesh without going through Tor:

- fips::dial — raw RFC 1035 DNS client (zero new deps) that queries the
  FIPS daemon's local resolver at 127.0.0.1:5354 for `<npub>.fips` AAAA
  records. Exposes peer_base_url(npub) → "http://[fd9d:…]:5679" plus a
  reqwest client factory for call-site migrations.
- fips::iface — parses /proc/net/if_inet6 to find the ULA address on
  `fips0`. Runs under the archipelago service user without extra caps.
- FipsTransport::is_available() — live probe of archipelago-fips and
  upstream fips.service via `systemctl is-active`, cached 10s so the
  send hot path doesn't thrash DBus.
- FipsTransport::send() — resolve npub, POST TransportMessage JSON to
  the peer's /transport/inbox. Today /transport/inbox isn't wired on
  the receive side, so call-site migrations use dial::peer_base_url
  directly against the already-signed endpoints (/rpc/v1,
  /archipelago/node-message, /content/*). The inbox handler lands as
  part of the Settings/transport work.
- server::serve_with_shutdown — takes an optional peer_addr and spawns
  a second listener bound specifically to the fips0 ULA on port 5679.
  The peer listener applies is_peer_allowed_path() — a whitelist of
  endpoints that already do per-request signature auth — and returns
  404 for everything else. Shutdown cascades to both listeners via a
  watch channel; 5s drain window preserved.
- main.rs — if fips0 has a ULA at startup, pass the peer SocketAddr to
  serve_with_shutdown; otherwise run the main listener only.

Security: the peer listener is bound to the fips0 ULA directly, not
wildcard, so it's unreachable from WAN IPv6. The path whitelist limits
exposure to endpoints whose handlers verify ed25519 signatures or
federation DID headers server-side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 01:12:39 -04:00
Dorian
30a7f73ead 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