Skip to content

Commit 5d3f2ce

Browse files
committed
fix(eid-wallet): clear cached identity data on logout
1 parent e16692d commit 5d3f2ce

4 files changed

Lines changed: 58 additions & 0 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Registry of the module-scope render caches that survive logout.
3+
*
4+
* Pages stash their last-known values at module scope so re-entering paints
5+
* instantly instead of flashing a spinner. That state outlives logout:
6+
* `performLogout` leaves with `goto("/")`, a client-side navigation, and
7+
* SvelteKit never re-evaluates a module on client-side nav. So without an
8+
* explicit reset, the next user to onboard on this device is shown the
9+
* previous user's data. Same hazard `clearAllCachedPhotos` exists for.
10+
*
11+
* A page registers its own reset from `<script module>`, which keeps the cache
12+
* colocated with the code that fills it. A page that was never visited never
13+
* registered — and has nothing cached to leak.
14+
*/
15+
const resets = new Set<() => void>();
16+
17+
/** Register a page's cache reset. Call from `<script module>`. */
18+
export function registerPageCacheReset(reset: () => void): void {
19+
resets.add(reset);
20+
}
21+
22+
/**
23+
* Wipe every registered page cache. Call on logout to prevent cross-user data
24+
* leaks.
25+
*/
26+
export function clearAllPageCaches(): void {
27+
for (const reset of resets) reset();
28+
}

infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ let hasMountedBefore = false;
1111
// instead of flashing the white loading splash. The component still kicks
1212
// off a fresh fetch on mount; the loaders write back into both the
1313
// component state and these slots so the next visit is also instant.
14+
import { registerPageCacheReset } from "../cache";
1415
import type { LegalIdDoc } from "./components/LegalIdAccordion.svelte";
1516
import type { SocialBindingDisplay } from "./components/SocialBindingAccordion.svelte";
1617
@@ -23,6 +24,24 @@ let cachedSelfDocId: string | undefined;
2324
let cachedSocialBindingCount = 0;
2425
let cachedSocialBindingPreview: SocialBindingDisplay[] = [];
2526
let hasEverLoaded = false;
27+
28+
// All of the above is one user's identity, and none of it survives a logout:
29+
// that's a client-side nav, which never re-evaluates this module, so the next
30+
// user to onboard on this device would be shown the previous user's name,
31+
// legal ID and contacts until the first fetch lands. `hasMountedBefore` goes
32+
// with them — a fresh session should play the entrance animation again.
33+
registerPageCacheReset(() => {
34+
cachedUserData = undefined;
35+
cachedEname = undefined;
36+
cachedIsFake = undefined;
37+
cachedLegalId = null;
38+
cachedDisplayName = undefined;
39+
cachedSelfDocId = undefined;
40+
cachedSocialBindingCount = 0;
41+
cachedSocialBindingPreview = [];
42+
hasEverLoaded = false;
43+
hasMountedBefore = false;
44+
});
2645
</script>
2746

2847
<script lang="ts">

infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { isPermissionGranted } from "@choochmeque/tauri-plugin-notifications-api
1515
import { FaceIdIcon, Notification02Icon } from "@hugeicons/core-free-icons";
1616
import { checkStatus } from "@tauri-apps/plugin-biometric";
1717
import { getContext, onMount } from "svelte";
18+
import { clearAllPageCaches } from "../cache";
1819
1920
const getGlobalState = getContext<() => GlobalState>("globalState");
2021
const setGlobalState =
@@ -84,6 +85,7 @@ async function performLogout() {
8485
isLogoutDrawerOpen = false;
8586
clearAllNotifications();
8687
await clearAllCachedPhotos();
88+
clearAllPageCaches();
8789
if (!globalState) {
8890
console.error("Cannot logout: global state not ready");
8991
return;

infrastructure/eid-wallet/src/routes/(app)/social-bindings/+page.svelte

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
<script module lang="ts">
2+
import { registerPageCacheReset } from "../cache";
3+
24
// Survives navigation, like the home screen's caches: returning to this page
35
// paints the last known list immediately instead of showing a full-screen
46
// spinner while every contact is re-resolved from scratch.
57
let cachedContacts: SocialBindingDisplay[] = [];
68
let hasEverLoaded = false;
9+
10+
// It survives logout too — that's a client-side nav — so drop it there, or the
11+
// next user onboarding on this device gets a first paint of these contacts.
12+
registerPageCacheReset(() => {
13+
cachedContacts = [];
14+
hasEverLoaded = false;
15+
});
716
</script>
817

918
<script lang="ts">

0 commit comments

Comments
 (0)