/** * Anonymous Mode Service * Handles anonymous mode functionality */ import { emitAnonymousModeEnabled } from "./AuthEventService"; import type { IStorageProvider } from "../types/Storage.types"; export class AnonymousModeService { private isAnonymousMode: boolean = false; private storageKey: string; constructor(storageKey: string = "@auth_anonymous_mode") { this.storageKey = storageKey; } async load(storageProvider: IStorageProvider): Promise { try { const value = await storageProvider.get(this.storageKey); this.isAnonymousMode = value === "true"; return this.isAnonymousMode; } catch (error) { if (__DEV__) { console.error('[AnonymousModeService] Failed to load state:', error instanceof Error ? error.message : String(error)); } this.isAnonymousMode = false; return false; } } private async save(storageProvider: IStorageProvider, value: boolean): Promise { try { await storageProvider.set(this.storageKey, value.toString()); return true; } catch (error) { if (__DEV__) { console.error('[AnonymousModeService] Failed to save state:', error instanceof Error ? error.message : String(error)); } return false; } } async clear(storageProvider: IStorageProvider): Promise { try { await storageProvider.remove(this.storageKey); this.isAnonymousMode = false; return true; } catch (error) { if (__DEV__) { console.error('[AnonymousModeService] Failed to clear state:', error instanceof Error ? error.message : String(error)); } return false; } } async enable(storageProvider: IStorageProvider): Promise { const previousState = this.isAnonymousMode; try { // Save to storage first, then update memory to maintain consistency. // This prevents TOCTOU: memory is never set to true unless storage confirms the write. const saveSuccess = await this.save(storageProvider, true); if (!saveSuccess) { // Rollback to previous state on failure this.isAnonymousMode = previousState; throw new Error('Failed to save anonymous mode state'); } this.isAnonymousMode = true; emitAnonymousModeEnabled(); } catch (error) { // Ensure state is rolled back on any error this.isAnonymousMode = previousState; throw error; } } getIsAnonymousMode(): boolean { return this.isAnonymousMode; } setAnonymousMode(enabled: boolean): void { this.isAnonymousMode = enabled; } }