// Version: 2.1.0 | Created: 2026-04-01 | Updated: 2026-04-27 // Riverpod notifier that owns the auth state machine. // // WEB SECURITY MODEL: Every visit requires a fresh login. No session // persistence. Only the Matrix device ID is saved across sessions so // encryption keys accumulate on one device instead of creating ghosts. import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import '../../features/auth/data/auth_repository.dart'; import '../../features/auth/domain/auth_failure.dart'; import '../network/matrix_client.dart'; import '../push/web_push_service.dart'; import '../storage/sync_persistence_service.dart'; import 'auth_state.dart'; part 'auth_notifier.g.dart'; @Riverpod(keepAlive: true) class AuthNotifier extends _$AuthNotifier { @override AuthState build() { // No session restore on web — always require fresh login. return const AuthState.unauthenticated(); } Future login({ required String username, required String password, }) async { state = const AuthState.loading(); try { final repo = ref.read(authRepositoryProvider); debugPrint('[Auth] Logging in...'); final response = await repo.login( username: username, password: password, ); debugPrint('[Auth] Login OK as ${response.userId} ' 'device=${response.deviceId}'); state = AuthState.authenticated( userId: response.userId, accessToken: response.accessToken, deviceId: response.deviceId, ); // Start background sync-to-database persistence. try { ref.read(syncPersistenceServiceProvider).start(); } catch (_) {} // Register Web Push subscription (fire-and-forget, non-fatal). final client = ref.read(matrixClientProvider); unawaited(setupWebPush(client)); } on AuthFailure catch (failure) { state = AuthState.unauthenticated(failure: failure.userMessage); } } Future logout() async { state = const AuthState.loading(); final repo = ref.read(authRepositoryProvider); await repo.logout(); // Keep the device ID in storage so the next login reuses it. state = const AuthState.unauthenticated(); } }