aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/transport-devices.js
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-10-14 23:02:49 +0200
committerChristophe Besson <cbesson@gmail.com>2026-10-14 23:02:49 +0200
commit3131630d900aa4a72bf880bfa9c5232bff64d6d6 (patch)
tree5ef229f9a3f589fad6e7543f14b58ec7f9526758 /packages/meshbay-hub/src/meshbay_hub/static/transport-devices.js
parent422647e7898b8df67cd11f8fb060aec23dec84aa (diff)
downloadmeshbay-3131630d900aa4a72bf880bfa9c5232bff64d6d6.tar.gz
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 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/transport-devices.js')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/transport-devices.js15
1 files changed, 12 insertions, 3 deletions
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);
}