diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index f37ecbb..1c2167f 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -2,7 +2,7 @@ import { onMount } from 'svelte'; import { ready } from './lib/crypto'; import { api, ApiError } from './lib/api'; - import { session } from './lib/session.svelte'; + import { session, setSessionUserOnly } from './lib/session.svelte'; import { logout } from './lib/auth'; import Login from './components/Login.svelte'; import Signup from './components/Signup.svelte'; @@ -112,14 +112,19 @@ .then((s) => { selfRegistryEnabled = s.self_registry_enabled; }) .catch(() => { /* default open if the call fails */ }); - // Probe the server for an existing session, but it doesn't change which - // URL we're rendering — only what content we'd show on /home. + // Probe the server for an existing session and rehydrate client-side + // state. The DEK is intentionally NOT persisted (it lives only in + // memory), so after a reload private rows can't be decrypted until the + // user re-enters their password. We used to log out here to avoid the + // "logged in but can't decrypt" state, but that broke permalink + // navigation: clicking `` causes a full reload, this + // handler ran, and the session was destroyed — kicking the user out + // mid-click. Now: keep the server session (so non-private content, + // hearts, bookmarks, etc. all keep working) and just leave dek=null. try { const me = await api.me(); defaultEmail = me.email; - // Reloaded with a server session but no DEK. Drop the server session; - // we can't decrypt anything without the password anyway. - await api.logout(); + setSessionUserOnly(me); } catch { // No session — fine. } diff --git a/frontend/src/components/ActivityRow.svelte b/frontend/src/components/ActivityRow.svelte index 6ea08f4..f98c88e 100644 --- a/frontend/src/components/ActivityRow.svelte +++ b/frontend/src/components/ActivityRow.svelte @@ -224,6 +224,13 @@ {@render locationLine(decrypted.loc_label, null, null)} {/if} {#if decrypted.scheduled_at}

šŸ•’ {formatDate(decrypted.scheduled_at)}

{/if} + {:else if !session.dek} +

+ Privat +

+

+ Innholdet er kryptert. Logg inn pƄ nytt med passordet ditt for Ƅ vise det. +

{:else}

Dekrypterer …

{/if} diff --git a/frontend/src/lib/session.svelte.ts b/frontend/src/lib/session.svelte.ts index f2814a6..c03bdc9 100644 --- a/frontend/src/lib/session.svelte.ts +++ b/frontend/src/lib/session.svelte.ts @@ -19,6 +19,16 @@ export function setSession(user: MeResponse, dek: Uint8Array): void { session.dek = dek; } +/** + * Rehydrate the user identity from /me on page load. The DEK is intentionally + * left null — it never persists across reloads. Callers needing private + * decryption must run the full login flow to re-derive it. + */ +export function setSessionUserOnly(user: MeResponse): void { + session.user = user; + session.dek = null; +} + export function clearSession(): void { if (session.dek) { // Best-effort zeroisation. The buffer may have been copied internally by