diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-30 15:06:14 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-30 15:06:14 +0200 |
| commit | 91297944791a36f30302ef8c86dd69ebeb177671 (patch) | |
| tree | 568188114baf438059458f1bc87903f4894cec90 /packages/meshbay-hub/src/meshbay_hub/static/group-page.js | |
| parent | a55d40b74bda77dff6ec565abdd551607fc665d6 (diff) | |
| download | meshbay-91297944791a36f30302ef8c86dd69ebeb177671.tar.gz | |
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 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/group-page.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/group-page.js | 16 |
1 files changed, 9 insertions, 7 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/group-page.js b/packages/meshbay-hub/src/meshbay_hub/static/group-page.js index b6f3d37..b18c811 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/group-page.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/group-page.js @@ -245,12 +245,12 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs, setError(''); try { // Same derivation as sign-in — the token is already ours, only the key - // that opens node bundles is missing here. Persisted so this browser is - // set up from now on. - session.bundleKey = { - ...(await window.MeshBayKeys.bundleKeyPairFields(pass, username)), - v1: await window.MeshBayKeys.deriveEncryptionKeyV1(pass, username), - }; + // that opens node bundles is missing here, and the pepper that goes into + // it is asked for with that token. Persisted so this browser is set up + // from now on. + const { pepper, version } = await window.MeshBayKeys.fetchBundlePepper(token); + session.bundleKey = await window.MeshBayKeys.deriveBundleSessionKey( + pass, username, userId, pepper, version); await _storeBundleKey(session.bundleKey); setPassInput(''); setNeedsPass(false); @@ -260,7 +260,7 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs, } finally { setPassBusy(false); } - }, [passInput, username]); + }, [passInput, username, userId, token]); // Everything one handshake ack tells this page, applied in one place. // @@ -650,6 +650,8 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs, // The node has no bundle for us and this browser derived no key to make // one — the passphrase form below is the way in, not a support request. if (err.reason === 'no_keys') setNeedsPass(true); + // An identity sealed before the pepper: only the operator can clear it. + if (err.reason === 'bundle_format_retired') err.message = t('group.bundle_format_retired'); // A key this node has never pinned, for an account it knows. The way in // is a device already trusted here, not an operator — which is the // whole point of device linking: a second browser or a native client |