Pass Tor E2E shared DM flow and harden mesh relay for fleet participants.

MLS export/reset and accept use live HTTP so uvicorn privacy-core state stays consistent; relay persistence and sender_seal fixes enable invite-accept-shared decrypt across onion peers. Adds participant/e2e compose overlays and harness recovery with optional Tor-only replicate mode.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
BigBodyCobain
2026-06-14 11:26:57 -06:00
co-authored by Cursor
parent c266c5ff5e
commit f1cd9eb4b9
18 changed files with 3452 additions and 585 deletions
+8
View File
@@ -65,6 +65,10 @@ def _hydrate_dm_relay_from_chain(events: list) -> int:
@limiter.limit("30/minute")
async def infonet_peer_push(request: Request):
"""Accept pushed Infonet events from relay peers (HMAC-authenticated)."""
from services.mesh.mesh_fleet_defaults import infonet_fleet_join_enabled
if not infonet_fleet_join_enabled():
return {"ok": True, "accepted": 0, "duplicates": 0, "rejected": [], "skipped": "fleet_join_disabled"}
content_length = request.headers.get("content-length")
if content_length:
try:
@@ -154,6 +158,10 @@ async def dm_replicate_envelope(request: Request):
@limiter.limit("30/minute")
async def gate_peer_push(request: Request):
"""Accept pushed gate events from relay peers (private plane)."""
from services.mesh.mesh_fleet_defaults import infonet_fleet_join_enabled
if not infonet_fleet_join_enabled():
return {"ok": True, "accepted": 0, "duplicates": 0, "skipped": "fleet_join_disabled"}
content_length = request.headers.get("content-length")
if content_length:
try:
+40
View File
@@ -308,6 +308,10 @@ class WormholeDmDecryptRequest(BaseModel):
session_welcome: str | None = None
class WormholeDmMlsKeyPackageRequest(BaseModel):
alias: str
class WormholeDmResetRequest(BaseModel):
peer_id: str | None = None
@@ -1228,6 +1232,23 @@ async def api_wormhole_dm_decrypt(request: Request, body: WormholeDmDecryptReque
)
@router.post("/api/wormhole/dm/mls-key-package", dependencies=[Depends(require_admin)])
@limiter.limit("60/minute")
async def api_wormhole_dm_mls_key_package(request: Request, body: WormholeDmMlsKeyPackageRequest):
from services.mesh.mesh_dm_mls import export_dm_key_package_for_alias
return export_dm_key_package_for_alias(str(body.alias or "").strip())
@router.post("/api/wormhole/dm/mls-reset", dependencies=[Depends(require_admin)])
@limiter.limit("30/minute")
async def api_wormhole_dm_mls_reset(request: Request):
from services.mesh.mesh_dm_mls import reset_dm_mls_state
reset_dm_mls_state(clear_privacy_core=True, clear_persistence=True)
return {"ok": True}
@router.post("/api/wormhole/dm/reset", dependencies=[Depends(require_admin)])
@limiter.limit("30/minute")
async def api_wormhole_dm_reset(request: Request, body: WormholeDmResetRequest):
@@ -1326,6 +1347,25 @@ async def api_wormhole_status(request: Request):
return await _m.api_wormhole_status(request)
@router.get(
"/api/wormhole/private-delivery/{item_id}",
dependencies=[Depends(require_local_operator)],
)
@limiter.limit("120/minute")
async def api_wormhole_private_delivery_item(request: Request, item_id: str):
from services.mesh.mesh_metadata_exposure import metadata_exposure_for_request
from services.mesh.mesh_private_outbox import private_delivery_outbox
exposure = metadata_exposure_for_request(
request,
authenticated=True,
)
item = private_delivery_outbox.get_item(item_id, exposure=exposure)
if item is None:
raise HTTPException(status_code=404, detail="private_delivery_item_not_found")
return {"ok": True, "item": item}
@router.post("/api/wormhole/private-delivery/{item_id}/action", dependencies=[Depends(require_local_operator)])
@limiter.limit("30/minute")
async def api_wormhole_private_delivery_action(