From 527bfee4d4a2e3587daffe24c1e0fb5ac7c4c604 Mon Sep 17 00:00:00 2001 From: Local Dev Date: Wed, 7 Oct 2026 21:45:12 +0200 Subject: [PATCH] Pithos: renames and vault unlocks reach every open view A renamed user kept its old name in the full page and in the other open views until they were reloaded, and the pithos.sia address still named the old user. The server now tells every view, and each one updates its selection, its address and the page on screen. When the vault locked while pithos.sia was open, the page fell through to the console password sign-in, which a Theseus user has no use for. It now shows the vault's PIN unlock, and it opens again on its own once the vault is unlocked anywhere, the sidebar's PIN pad included. The sidebar likewise opens again when the vault is unlocked elsewhere. --- core/server.js | 3 +++ ui/app.js | 68 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/core/server.js b/core/server.js index 634c90e..85436da 100644 --- a/core/server.js +++ b/core/server.js @@ -320,6 +320,9 @@ export async function createPithos(opts = {}) { if (wasRunning) { try { daemon.start(); } catch (e) { daemon.pushLog('sys', `could not start s3d: ${e.message}`); } } } daemon.pushLog('sys', `renamed user ${p.name} to ${name}`); + // every open view (sidebar, full page, browser) follows the new name + siteUsersCache = { at: 0, set: new Set() }; + broadcast('user-renamed', { from: p.name, to: name }); return { name }; }); route('GET', '/api/keys', (req, url) => cli.listKeys(url.searchParams.get('user') || undefined)); diff --git a/ui/app.js b/ui/app.js index 21cd2f9..adb4567 100644 --- a/ui/app.js +++ b/ui/app.js @@ -175,6 +175,7 @@ const eventHandlers = { if (['done', 'already'].includes(d?.state) && d.state !== was) refreshNavAccount(true); }, install(p) { if (p.phase === 'extract') toast('Verified checksum, installing…'); }, + 'user-renamed'(d) { followRename(d); }, move(p) { progressSink?.(p); }, convert(p) { progressSink?.(p); }, }; @@ -274,6 +275,29 @@ function navTo(hash) { route(); } +// A user renamed here or in another Pithos view (sidebar, full page, +// browser): the selection, the address and the page on screen follow. +function followRename({ from, to } = {}) { + if (!from || !to || from === to) return; + if (state.selectedUser === from) { state.selectedUser = to; try { localStorage.setItem('pithos.user', to); } catch {} } + const swap = (parts, i) => { + let cur = ''; + try { cur = decodeURIComponent(parts[i] || ''); } catch {} + if (cur !== from) return false; + parts[i] = encodeURIComponent(to); + return true; + }; + if (PATH_MODE) { + const segs = location.pathname.split('/'); + if (swap(segs, 1)) history.replaceState(null, '', segs.join('/') + location.search); + } else if (location.hash.startsWith('#/u/')) { + const parts = location.hash.split('/'); + if (swap(parts, 2)) history.replaceState(null, '', parts.join('/')); + } + const [page] = currentRoute(); + if (page === 'users' || page === 'buckets') route(); +} + function route() { cleanup.forEach((fn) => fn()); cleanup = []; @@ -1101,10 +1125,8 @@ function users(main) { if (!name || name === current) return; try { await api('POST', `/api/users/${encodeURIComponent(current)}/rename`, { name }); - if (state.selectedUser === current) { state.selectedUser = name; try { localStorage.setItem('pithos.user', name); } catch {} } - expanded.delete(current); toast(`Renamed to ${name}`); - load(); + followRename({ from: current, to: name }); } catch (e) { fail(e); load(); } } @@ -2735,6 +2757,10 @@ function watchVaultLock() { if (st.setup && st.prompt && !st.unlocked && $('#locked').hidden) { $('#app').hidden = true; $('#locked').hidden = false; + } else if (st.unlocked && !$('#locked').hidden) { + // unlocked somewhere else (the full page, Settings): open again + $('#locked').hidden = true; + $('#app').hidden = false; } }); } @@ -2902,14 +2928,48 @@ function addBackToSidebar() { } function showSignin() { + // pithos.sia in Theseus signs out when the vault locks (idle, Lock now): + // that is the vault's PIN prompt, not the console password. + if (PATH_MODE) { + api('GET', '/api/session').then((s) => (s.locked ? showLocked() : showPassword())).catch(showPassword); + return; + } + showPassword(); +} +function showPassword() { $('#app').hidden = true; + $('#locked').hidden = true; $('#signin').hidden = false; } +// Locked with the Theseus vault. Unlocking anywhere (this page's button, the +// sidebar's PIN pad, Settings) reopens the page by itself. +let lockWatch = null; +function showLocked() { + $('#app').hidden = true; + $('#signin').hidden = true; + $('#locked').hidden = false; + if (lockWatch) return; + const check = async () => { + let s; + try { s = await api('GET', '/api/session'); } catch { return; } + if (s.locked || !s.authenticated) return; + clearInterval(lockWatch); + lockWatch = null; + document.removeEventListener('visibilitychange', onShow); + window.removeEventListener('focus', check); + location.reload(); // a fresh start: the event stream ended with the lock + }; + const onShow = () => { if (!document.hidden) check(); }; + lockWatch = setInterval(check, 2000); + document.addEventListener('visibilitychange', onShow); + window.addEventListener('focus', check); +} + async function boot() { const s = await api('GET', '/api/session'); // pithos.sia in Theseus: locked with the vault, like the sidebar panel. - if (s.locked) { $('#locked').hidden = false; return; } + if (s.locked) { showLocked(); return; } if (!s.authenticated) { showSignin(); if (!s.passwordLogin) {