aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/group-page.js
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-30 15:06:14 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-30 15:06:14 +0200
commit91297944791a36f30302ef8c86dd69ebeb177671 (patch)
tree568188114baf438059458f1bc87903f4894cec90 /packages/meshbay-hub/src/meshbay_hub/static/group-page.js
parenta55d40b74bda77dff6ec565abdd551607fc665d6 (diff)
downloadmeshbay-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.js16
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