diff --git a/src/context/SessionContext.tsx b/src/context/SessionContext.tsx index 0ec5c08a4..225002967 100644 --- a/src/context/SessionContext.tsx +++ b/src/context/SessionContext.tsx @@ -2,7 +2,7 @@ import React, { createContext, useContext } from 'react'; import StatusContext from './StatusContext'; import { BackendApi, useApi } from '../api'; -import { useLocalStorageKeystore } from '../services/LocalStorageKeystore'; +import { KeystoreEvent, useLocalStorageKeystore } from '../services/LocalStorageKeystore'; import type { LocalStorageKeystore } from '../services/LocalStorageKeystore'; @@ -23,7 +23,8 @@ const SessionContext: React.Context = createContext({ export const SessionContextProvider = ({ children }) => { const { isOnline } = useContext(StatusContext); const api = useApi(isOnline); - const keystore = useLocalStorageKeystore(); + const keystoreEvents = new EventTarget(); + const keystore = useLocalStorageKeystore(keystoreEvents); const logout = async () => { // Clear URL parameters @@ -32,6 +33,8 @@ export const SessionContextProvider = ({ children }) => { await keystore.close(); }; + keystoreEvents.addEventListener(KeystoreEvent.Close, logout, { once: true }); + const value: SessionContextValue = { api, isLoggedIn: api.isLoggedIn() && keystore.isOpen(), diff --git a/src/services/LocalStorageKeystore.ts b/src/services/LocalStorageKeystore.ts index 11865682f..46715f83f 100644 --- a/src/services/LocalStorageKeystore.ts +++ b/src/services/LocalStorageKeystore.ts @@ -27,6 +27,13 @@ export type CachedUser = { prfKeys: WebauthnPrfSaltInfo[]; } +export enum KeystoreEvent { + /** The keystore has been closed. This event should be propagated to all tabs. */ + Close = 'keystore.close', + /** The keystore has been closed. This event should not be propagated to other tabs. */ + CloseTabLocal = 'keystore.closeTabLocal', +} + export type CommitCallback = () => Promise; export interface LocalStorageKeystore { isOpen(): boolean, @@ -75,7 +82,7 @@ export interface LocalStorageKeystore { } /** A stateful wrapper around the keystore module, storing state in the browser's localStorage and sessionStorage. */ -export function useLocalStorageKeystore(): LocalStorageKeystore { +export function useLocalStorageKeystore(eventTarget: EventTarget): LocalStorageKeystore { const [cachedUsers, setCachedUsers,] = useLocalStorage("cachedUsers", []); const [privateData, setPrivateData, clearPrivateData] = useLocalStorage("privateData", null); const [globalUserHandleB64u, setGlobalUserHandleB64u, clearGlobalUserHandleB64u] = useLocalStorage("userHandle", null); @@ -97,6 +104,7 @@ export function useLocalStorageKeystore(): LocalStorageKeystore { const closeTabLocal = useCallback( () => { clearSessionStorage(); + eventTarget.dispatchEvent(new CustomEvent(KeystoreEvent.CloseTabLocal)); }, [clearSessionStorage], ); @@ -107,6 +115,7 @@ export function useLocalStorageKeystore(): LocalStorageKeystore { clearPrivateData(); clearGlobalUserHandleB64u(); closeTabLocal(); + eventTarget.dispatchEvent(new CustomEvent(KeystoreEvent.Close)); }, [closeTabLocal, idb, clearGlobalUserHandleB64u, clearPrivateData], );