diff options
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/app.js | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js index 6fefe0f..0aa74b4 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js @@ -122,6 +122,45 @@ function _restoreSessionKeys() { } catch {} } +/** Public X25519 key from our own secret — never read back from the hub. */ +async function _pkXFromSk(skPkcs8B64) { + const raw = Uint8Array.from(atob(skPkcs8B64), c => c.charCodeAt(0)); + const sk = await crypto.subtle.importKey('pkcs8', raw, { name: 'X25519' }, true, ['deriveBits']); + const jwk = await crypto.subtle.exportKey('jwk', sk); + const b64 = jwk.x.replace(/-/g, '+').replace(/_/g, '/'); + const pad = b64.length % 4; + return pad ? b64 + '='.repeat(4 - pad) : b64; +} + +/** + * Recover our identity keys from what this browser already holds. + * + * sessionStorage dies with the tab, but the encrypted keypair bundle sits in + * localStorage from registration and the key that opens it is in IndexedDB from + * login. Without this, closing the tab looked exactly like never having + * registered here — "this browser does not hold your keys", while both halves + * were on disk a few bytes apart. + */ +async function _recoverLocalKeys(username) { + if (_sessionKeys || !username) return; + try { + if (!_bundleKey) _bundleKey = await _loadBundleKey(); + if (!_bundleKey || !window.MeshBayKeys) return; + const enc = localStorage.getItem(`meshbay_kp_${username}`); + if (!enc) return; + const keys = await window.MeshBayKeys.decryptBundleWithKey(enc, _bundleKey); + _sessionKeys = { + skXB64: keys.skX, + skEdB64: keys.skEd, + pkXB64: await _pkXFromSk(keys.skX), + }; + _pendingBundlePush = enc; // still to be backed up to a node + _saveSessionKeys(); + } catch (e) { + console.warn('[MeshBay] could not recover local keys:', e); + } +} + function loadAuth() { try { return JSON.parse(localStorage.getItem(AUTH_KEY)); @@ -824,6 +863,7 @@ function GroupPage({ groupId, group, token, username, userId, onRefreshAuth }) { gekRef.current = null; if (!_bundleKey) _bundleKey = await _loadBundleKey(); _restoreSessionKeys(); + await _recoverLocalKeys(username); try { const nodesData = await hubFetch(`/v1/groups/${groupId}/nodes`, { token }); if (cancelled) return; |