aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-30 16:58:31 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-30 16:58:31 +0200
commit6d167392f6f8ede37e2794a68a3738f8ba03131d (patch)
tree9caacef15dd034c6425f4bb623e0cd50a28ec52a /packages/meshbay-hub/src/meshbay_hub/static/profile-page.js
parent8926f163dad9d32dc06c3a142658a4e11d9c12c1 (diff)
downloadmeshbay-6d167392f6f8ede37e2794a68a3738f8ba03131d.tar.gz
feat(client): the desktop application keeps M and every node identity in its main process
keyring.js derives, opens, mints, seals, signs and agrees there; the page gets public keys and a handle. Argon2 comes from the page's own WebAssembly build (Electron's crypto has none). Without OS key storage the page keeps its keys as a browser does. A node's bundle is settled after connecting, re-sealed when the key changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/profile-page.js')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/profile-page.js51
1 files changed, 32 insertions, 19 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js b/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js
index 7a309a9..cd00f03 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js
@@ -4,6 +4,7 @@ import {
import { t } from './i18n.js';
import { ask } from './ask.js';
import { Icon } from './icon.js';
+import * as platform from './platform.js';
import {
hubFetch, HUB, session, setAuth,
_storeBundleKey, _loadBundleKey, _storeRecoveryKey,
@@ -143,33 +144,45 @@ export function ProfilePage({ user, onLogout }) {
// run at all the account is left untouched.
// Both keys from the passphrases, with the pepper this open session asks
// for: the old one opens the bundles as they are, the new one seals them.
+ // In the desktop application both are kept by its main process, the new
+ // one set aside until the hub has accepted the change.
const K = window.MeshBayKeys;
const { pepper, version } = await K.fetchBundlePepper(user.token);
- const oldKey = await K.deriveBundleSessionKey(
+ const oldKey = await K.sessionBundleKey(
cpOld, user.username, user.userId, pepper, version);
- const newKey = await K.deriveBundleSessionKey(
- cpNew, user.username, user.userId, pepper, version);
- const result = await window.MeshBayTransport.rewrapAllNodes({
- hubUrl: HUB, token: user.token,
- username: user.username, userId: user.userId,
- bundleKey: oldKey, newBundleKey: newKey,
- onProgress: setCpProgress,
- });
-
- const oldAuthKey = await window.MeshBayKeys.deriveAuthKey(cpOld, user.username);
- const newAuthKey = await window.MeshBayKeys.deriveAuthKey(cpNew, user.username);
- const resp = await hubFetch('/v1/users/password', {
- method: 'POST', token: user.token,
- body: { old_auth_key: oldAuthKey, new_auth_key: newAuthKey },
- });
+ const newKey = await K.sessionBundleKey(
+ cpNew, user.username, user.userId, pepper, version, { pending: true });
+ let resp;
+ try {
+ const result = await window.MeshBayTransport.rewrapAllNodes({
+ hubUrl: HUB, token: user.token,
+ username: user.username, userId: user.userId,
+ bundleKey: oldKey, newBundleKey: newKey,
+ onProgress: setCpProgress,
+ });
+ const oldAuthKey = await window.MeshBayKeys.deriveAuthKey(cpOld, user.username);
+ const newAuthKey = await window.MeshBayKeys.deriveAuthKey(cpNew, user.username);
+ resp = await hubFetch('/v1/users/password', {
+ method: 'POST', token: user.token,
+ body: { old_auth_key: oldAuthKey, new_auth_key: newAuthKey },
+ });
+ setCpResult(result);
+ } catch (err) {
+ if (newKey.native) await platform.keys.dropPending(user.userId);
+ throw err;
+ }
// Keep this tab signed in with the fresh pair, and move the session's
// bundle key forward so the next node connection opens the new bundles.
setAuth({ ...user, token: resp.access_token, refreshToken: resp.refresh_token });
- session.bundleKey = newKey;
- _storeBundleKey(newKey);
+ if (newKey.native) {
+ await platform.keys.commitPending(user.userId);
+ session.bundleKey = { ...newKey, pending: false };
+ } else {
+ session.bundleKey = newKey;
+ _storeBundleKey(newKey);
+ }
- setCpResult(result);
setCpPhase('done');
} catch (err) {
const msg = err.message === 'account_locked'