From 4500fe3854fd3a499d1139bc89ccc488d104cc29 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Sat, 26 Sep 2026 02:44:52 +0200 Subject: fix(hub): the NAT-punch signal needs a shared active group, like the offer relay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit POST /v1/nodes/{id}/incoming checked only the caller's own address, then revealed whether the node was connected (404 vs 504) and, with QUIC on, made it punch โ€” so any authenticated account could poll it for a node's liveness or make a stranger's node emit a UDP probe. The membership gate webrtc_offer did inline is now require_shared_active_group() in api/signaling.py, called by both routes; in notify_incoming it runs before anything depends on the node's connection state, so a non-member gets one uniform 403 whether the node is up or not. test_incoming_membership.py holds it (a non-member is refused with a membership 403 whether the node is connected or not; a member passes the gate); red before, green after. The offer relay is unchanged in behaviour (it now calls the shared helper); signaling/availability suites pass. Design ยง7.2 updated. Co-Authored-By: Claude Opus 4.8 --- packages/meshbay-hub/src/meshbay_hub/api/revocation.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'packages/meshbay-hub/src/meshbay_hub/api/revocation.py') diff --git a/packages/meshbay-hub/src/meshbay_hub/api/revocation.py b/packages/meshbay-hub/src/meshbay_hub/api/revocation.py index f8cae8a..2c0b8db 100644 --- a/packages/meshbay-hub/src/meshbay_hub/api/revocation.py +++ b/packages/meshbay-hub/src/meshbay_hub/api/revocation.py @@ -441,6 +441,7 @@ async def notify_incoming( body: IncomingRequest, request: Request, current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), ): """ Signal a node that a client wants to connect (NAT punch coordination). @@ -450,8 +451,18 @@ async def notify_incoming( arbitrary node emit UDP packets to an address of their choosing โ€” a small reflection primitive using someone else's machine. The probe target must now be the caller's own source address. + + Like the offer relay, the caller must share an active group with the node โ€” + checked **before** anything reveals whether the node is connected, so this is + not a liveness oracle a stranger can poll, and a stranger cannot make a node + punch on their behalf. """ from meshbay_hub.api.netutil import client_ip + from meshbay_hub.api.signaling import require_shared_active_group + + # First, and before anything reveals whether the node is connected: a + # stranger cannot poll this for a node's liveness, nor make it punch. + await require_shared_active_group(db, node_id, current_user.id) caller_ip = client_ip(request) if body.peer_ip != caller_ip: -- cgit v1.2.3