File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -265,22 +265,22 @@ export function AppSidebar({
265265 useEffect ( ( ) => {
266266 if ( typeof window === "undefined" ) return ;
267267 try {
268- const stored = localStorage . getItem ( CHATS_CACHE_KEY ) ;
268+ const stored = sessionStorage . getItem ( CHATS_CACHE_KEY ) ;
269269 if ( stored && ! cachedChatsRef . current ) {
270270 cachedChatsRef . current = JSON . parse ( stored ) ;
271271 }
272272 } catch ( e ) {
273- console . warn ( "Failed to load chats from localStorage :" , e ) ;
273+ console . warn ( "Failed to load chats from sessionStorage :" , e ) ;
274274 }
275275 } , [ ] ) ;
276276
277277 useEffect ( ( ) => {
278278 if ( chatsResult ?. chats && chatsResult . chats . length > 0 ) {
279279 cachedChatsRef . current = chatsResult . chats ;
280280 try {
281- localStorage . setItem ( CHATS_CACHE_KEY , JSON . stringify ( chatsResult . chats ) ) ;
281+ sessionStorage . setItem ( CHATS_CACHE_KEY , JSON . stringify ( chatsResult . chats ) ) ;
282282 } catch ( e ) {
283- console . warn ( "Failed to save chats to localStorage :" , e ) ;
283+ console . warn ( "Failed to save chats to sessionStorage :" , e ) ;
284284 }
285285 }
286286 } , [ chatsResult ?. chats ] ) ;
Original file line number Diff line number Diff line change @@ -253,10 +253,28 @@ export async function signUpWithEmail(
253253 } ) ;
254254}
255255
256+ /**
257+ * Sensitive sessionStorage keys that store chat content, drafts, and stream data.
258+ * These must be cleared on sign-out to prevent data leakage on shared devices.
259+ */
260+ const SENSITIVE_SESSION_KEYS = [
261+ "openchat-chats-cache" ,
262+ "openchat-prompt-drafts" ,
263+ "openchat-stream" ,
264+ ] ;
265+
256266export async function signOut ( ) {
257267 return authClient . signOut ( {
258268 fetchOptions : {
259269 onSuccess : ( ) => {
270+ // Clear sensitive chat/draft/stream data from sessionStorage
271+ for ( const key of SENSITIVE_SESSION_KEYS ) {
272+ try {
273+ sessionStorage . removeItem ( key ) ;
274+ } catch {
275+ // Ignore storage access errors
276+ }
277+ }
260278 window . location . href = "/auth/sign-in" ;
261279 } ,
262280 } ,
Original file line number Diff line number Diff line change @@ -2,12 +2,16 @@ import { create } from "zustand";
22import { createJSONStorage , devtools , persist } from "zustand/middleware" ;
33
44/**
5- * Store for persisting prompt drafts across page reloads.
5+ * Store for persisting prompt drafts within the current browser session.
6+ *
7+ * Uses sessionStorage instead of localStorage to limit exposure of sensitive
8+ * chat content — data is scoped to the tab/session and not accessible after
9+ * the browser session ends.
610 *
711 * Non-annoying approach:
812 * - Drafts are saved per-chat (or "global" for new chat input)
913 * - Drafts are automatically cleared when a message is sent
10- * - Old drafts are cleaned up after 7 days to prevent localStorage bloat
14+ * - Old drafts are cleaned up after 7 days to prevent storage bloat
1115 */
1216
1317const DRAFT_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000 ; // 7 days
@@ -115,7 +119,7 @@ export const usePromptDraftStore = create<PromptDraftState>()(
115119 } ) ,
116120 {
117121 name : "openchat-prompt-drafts" ,
118- storage : createJSONStorage ( ( ) => localStorage ) ,
122+ storage : createJSONStorage ( ( ) => sessionStorage ) ,
119123 } ,
120124 ) ,
121125 { name : "prompt-draft-store" } ,
Original file line number Diff line number Diff line change @@ -204,7 +204,7 @@ export const useStreamStore = create<StreamState>()(
204204 } ) ,
205205 {
206206 name : "openchat-stream" ,
207- storage : createJSONStorage ( ( ) => localStorage ) ,
207+ storage : createJSONStorage ( ( ) => sessionStorage ) ,
208208 partialize : ( state ) => ( {
209209 activeStream : state . activeStream ,
210210 pendingUserMessage : state . pendingUserMessage ,
You can’t perform that action at this time.
0 commit comments