aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/roster.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-30 21:04:39 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-30 21:04:39 +0200
commit0378e8e0912a1a7e6cea4424e69d524e7afecbf8 (patch)
tree4ae94e32d6638b4c2cc1ae4f74cbe5d00c940636 /packages/meshbay-node/src/meshbay_node/roster.py
parent0ed56d3a1b4f71cf622d3e27edc87a15ef33c185 (diff)
downloadmeshbay-0378e8e0912a1a7e6cea4424e69d524e7afecbf8.tar.gz
fix: an identity signs a named kind, and a device approval answers a request
The desktop main process builds every transcript itself from fields (transcripts.js) and signs no raw bytes; the page's identity has the same contract (crypto.js transcriptFor). The keyring seals no bundle while browser access is off. On the node, device_add must redeem a pending request filed by the same keys, and device_revoke is signed under its own prefix (meshbay:device_revoke:v1), so a retirement signature admits nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/roster.py')
-rw-r--r--packages/meshbay-node/src/meshbay_node/roster.py13
1 files changed, 8 insertions, 5 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/roster.py b/packages/meshbay-node/src/meshbay_node/roster.py
index 8144373..0116aaa 100644
--- a/packages/meshbay-node/src/meshbay_node/roster.py
+++ b/packages/meshbay-node/src/meshbay_node/roster.py
@@ -512,19 +512,22 @@ class Roster:
await self._db.commit()
return expires
- async def take_device_request(self, code_hash: str,
- user_id: str) -> dict | None:
+ async def take_device_request(self, code_hash: str, user_id: str,
+ pk_ed25519: str, pk_x25519: str) -> dict | None:
"""
- Claim a pending request by its hash, for this account only.
+ Claim a pending request by its hash, for this account and these keys.
Single use and scoped to the account: a request filed for one person
cannot be redeemed by another even with the code, and a code that has
- been spent is gone.
+ been spent is gone. Scoped to the keys too: the request is what the new
+ device filed and signed, so an approval redeeming it admits those keys
+ and no others.
"""
assert self._db
async with self._db.execute(
"SELECT * FROM device_requests WHERE code_hash = ? AND user_id = ? "
- "AND expires_at > ?", (code_hash, user_id, _now())
+ "AND pk_ed25519 = ? AND pk_x25519 = ? AND expires_at > ?",
+ (code_hash, user_id, pk_ed25519, pk_x25519, _now())
) as cur:
row = await cur.fetchone()
if row is None: