fix(mesh): route ContentRef over federation when >160B

mesh.send-content was failing with "Message too large for LoRa: 624
bytes (max 160)" because a single ContentRef envelope (cid + onion +
cap_token + thumb) dwarfs a LoRa frame. Add a federation Tor fallback:

- New POST /archipelago/mesh-typed endpoint accepts
  {from_pubkey, typed_envelope_b64, signature}, verifies ed25519 over
  the raw wire bytes, and injects the decoded envelope into MeshState
  via a new MeshService::inject_typed_from_federation helper. This
  shares the same dispatch match as LoRa receives via a new pub(crate)
  handle_typed_envelope_direct extracted from handle_typed_message.
- MeshService::send_typed_wire_via_federation POSTs the signed wire to
  a peer's onion over TOR_SOCKS_PROXY and records a local Sent record.
- handle_mesh_send_content looks up the peer's onion in federation
  storage and routes via federation when available, falling back to
  LoRa only when no federation presence is known (still fails on
  oversized — chunking is Phase 4).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-04-13 13:37:48 -04:00
co-authored by Claude Opus 4.6
parent 649433b7fd
commit bc3729d99f
6 changed files with 240 additions and 4 deletions
+9
View File
@@ -267,6 +267,15 @@ impl ApiHandler {
Self::handle_node_message(body_bytes).await
}
// Mesh typed envelope relay over federation — peers POST
// pre-encoded TypedEnvelope wire bytes here when the envelope is
// too large for a single LoRa frame (primarily ContentRef). No
// session auth: the body carries a pubkey + ed25519 signature
// over the wire bytes which we verify before dispatching.
(Method::POST, "/archipelago/mesh-typed") => {
Self::handle_mesh_typed_relay(self.rpc_handler.clone(), body_bytes).await
}
// Blob upload — local/session use only. Session-authenticated so
// only the node owner can push attachments into the blob store.
(Method::POST, "/api/blob") => {