From 91297944791a36f30302ef8c86dd69ebeb177671 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 30 Sep 2026 15:06:14 +0200 Subject: feat: bundles sealed per node under the passphrase and the hub's pepper The session key is M = HKDF(Argon2(passphrase) || pepper, account id); each node's bundle key and the playlist key derive from it. Bundles are MBK3, bound to account and node; MBK1/MBK2 are refused by name, never replaced silently. Playlists move to key v2 and are re-sealed over unreadable node copies. Co-Authored-By: Claude Opus 5.5 --- packages/meshbay-hub/src/meshbay_hub/static/hub-client.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'packages/meshbay-hub/src/meshbay_hub/static/hub-client.js') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/hub-client.js b/packages/meshbay-hub/src/meshbay_hub/static/hub-client.js index ba91f00..3081ad8 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/hub-client.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/hub-client.js @@ -159,7 +159,12 @@ async function _loadKey(slot) { // only groups joined in the unbroken session that generated it. Cleared with // everything else on sign-out. const _storeBundleKey = (key) => _storeKey('bk', key); -const _loadBundleKey = () => _loadKey('bk'); +// A key stored before the pepper (`{v2, v1, …}`) opens nothing any more: it is +// no key at all, and the group page asks for the passphrase again. +const _loadBundleKey = async () => { + const k = await _loadKey('bk'); + return k && k.v3 ? k : null; +}; const _storeRecoveryKey = (key) => _storeKey('rk', key); const _loadRecoveryKey = () => _loadKey('rk'); async function _clearKeyDB() { -- cgit v1.2.3