From 3131630d900aa4a72bf880bfa9c5232bff64d6d6 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 14 Oct 2026 23:02:49 +0200 Subject: fix(client): link a device from the application; approve one match only "Get a linking code" called the connection the page had just closed on the node's unknown_device refusal, so it never filed anything. It now retries with the request filed on that connection, before the proof (MNP 6.3), and the page tries the group again after each refusal until a linked device approves the code. Offered only in the desktop application: a browser's minted identity is gone by its next connection. Approving refuses a code that matches more than one pending request: filing needs only the account's token, so somebody holding the passphrase who saw a code could file their own keys under it. Co-Authored-By: Claude Opus 5.5 --- .../src/meshbay_hub/static/transport-devices.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'packages/meshbay-hub/src/meshbay_hub/static/transport-devices.js') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/transport-devices.js b/packages/meshbay-hub/src/meshbay_hub/static/transport-devices.js index 3d56f69b..5c6adef4 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/transport-devices.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/transport-devices.js @@ -227,15 +227,24 @@ extendTransport(class { const listed = await this._sendAndWait({ type: 'device_lookup', v: '0.1' }); if (listed.type === 'error') throw new Error(listed.detail || 'Not found'); - let match = null; + // Every match, not the first: a request is filed with the account's token + // alone, so somebody holding the passphrase who saw the code on screen can + // file a second one with the same code and keys of their own. Neither is + // approved then — the person's device asks again, with a new code. + const matches = []; for (const req of listed.requests || []) { const expect = await C.deviceCodeHash( normalized, req.pk_ed25519, req.pk_x25519); - if (expect === req.code_hash) { match = req; break; } + if (expect === req.code_hash) matches.push(req); } - if (!match) { + if (!matches.length) { throw new Error('No device is waiting with that code'); } + if (matches.length > 1) { + throw new Error('More than one device is waiting with that code, so none was ' + + 'approved. Get a new code on the device you are linking.'); + } + const match = matches[0]; return this._countersign(userId, match.code_hash, match.pk_ed25519, match.pk_x25519); } -- cgit v1.2.3