From 28c88908b88c58cba4de08710f6bb268ede02d57 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 14 Oct 2026 22:20:15 +0200 Subject: feat(node): accept a device link request before the proof (MNP 6.3) A new device of a known account holds no identity the node pinned, so it cannot complete a handshake until a pinned device approves it: it now files device_add_request in the pre-proof window, as the desktop app's case already required. The request stays inert until countersigned; at most 10 are pending per account, the oldest dropped. A 6.2 node answers it "Handshake required", which a client reads as "cannot link here". Co-Authored-By: Claude Opus 5.5 --- packages/meshbay-node/src/meshbay_node/roster.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'packages/meshbay-node/src/meshbay_node/roster.py') diff --git a/packages/meshbay-node/src/meshbay_node/roster.py b/packages/meshbay-node/src/meshbay_node/roster.py index 9336e38..9123763 100644 --- a/packages/meshbay-node/src/meshbay_node/roster.py +++ b/packages/meshbay-node/src/meshbay_node/roster.py @@ -327,6 +327,7 @@ class Roster: # keypair bundle can add one — so the answer to "how many" is visibility and # a ceiling, not cryptography. MAX_DEVICES_PER_USER = 5 + MAX_PENDING_DEVICE_REQUESTS = 10 async def pin_identity( self, @@ -522,6 +523,18 @@ class Roster: """ assert self._db expires = _iso_in(ttl) + # Filing needs only an authorized token (it is served before the proof), + # so the table is bounded per account: expired requests go, and past the + # cap the oldest makes room. A person files one per new device, five at + # most, and a retry or two each; a request pushed out costs a new code. + await self._db.execute( + "DELETE FROM device_requests WHERE user_id = ? AND expires_at <= ?", + (user_id, _now())) + await self._db.execute( + "DELETE FROM device_requests WHERE code_hash IN (" + " SELECT code_hash FROM device_requests WHERE user_id = ?" + " ORDER BY created_at DESC, rowid DESC LIMIT -1 OFFSET ?)", + (user_id, self.MAX_PENDING_DEVICE_REQUESTS - 1)) await self._db.execute( "INSERT OR REPLACE INTO device_requests " "(code_hash, user_id, username, pk_ed25519, pk_x25519, created_at, " -- cgit v1.2.3