diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-15 02:16:39 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-15 02:21:01 +0200 |
| commit | 73ad8e4eb566fe682107fa7e50ef624591199e99 (patch) | |
| tree | ff0017d014d46d8835487c080dca55c6def7fd6b /packages/meshbay-hub/src/meshbay_hub/static/profile-page.js | |
| parent | bdefcd025604f2c3009fe5e0cc01213c2ba62a6a (diff) | |
| download | meshbay-73ad8e4eb566fe682107fa7e50ef624591199e99.tar.gz | |
feat(hub): session lifetime is an admin setting, and a browser signs out when idle
Browser idle sign-out (media playback counts as activity; not the desktop app),
refresh idle window and maximum session length, in hours. Sign-out now revokes
on the hub, and the profile has "sign out everywhere".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XuNrwLf5EFWCMHzfoEvnpm
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.js | 26 |
1 files changed, 26 insertions, 0 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 7e355e7..4d452e1 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/profile-page.js @@ -42,6 +42,23 @@ export function ProfilePage({ user, onLogout }) { const [delPass, setDelPass] = useState(''); const [delError, setDelError] = useState(''); const [deleting, setDeleting] = useState(false); + const [revoking, setRevoking] = useState(false); + const [revokeError, setRevokeError] = useState(''); + + // Every session of this account stops renewing, this one included — the + // case it exists for is a browser left signed in somewhere else. + const signOutEverywhere = useCallback(async () => { + if (!confirm(t('settings.sign_out_everywhere_confirm'))) return; + setRevoking(true); + setRevokeError(''); + try { + await hubFetch('/v1/users/me/sessions/revoke', { method: 'POST', token: user.token }); + onLogout(); + } catch (err) { + setRevokeError(err.message); + setRevoking(false); + } + }, [user, onLogout]); const deleteAccount = useCallback(async (e) => { e.preventDefault(); @@ -485,6 +502,15 @@ export function ProfilePage({ user, onLogout }) { </div> <div class="settings-section"> + <h3 class="settings-heading">${t('settings.sessions_heading')}</h3> + <p class="settings-hint">${t('settings.sign_out_everywhere_hint')}</p> + ${revokeError && html`<p class="error-msg">${revokeError}</p>`} + <button class="btn-secondary" disabled=${revoking} onClick=${signOutEverywhere}> + ${revoking ? '…' : t('settings.sign_out_everywhere')} + </button> + </div> + + <div class="settings-section"> <h3 class="settings-heading">${t('settings.danger')}</h3> <p class="settings-hint">${t('settings.delete_hint')}</p> ${delError && html`<p class="error-msg">${delError}</p>`} |