import 'dart:developer'; import '../../../session/session.dart'; import '../../../session/session_lifecycle.dart'; import '../../../session/session_manager.dart'; import '../../errors/auth_exception.dart'; import '../queries/auth_verify/auth_verify.dart'; /// Credential probe. A server-side password rotation forces a re-login on the /// next cold start even when the bearer token would still be accepted. /// Another stored account then takes over. class SessionValidator { static Future probeStored({ required Future Function(String? nextAccountId) onInvalidated, }) async { final session = SessionManager().current; // The probes use their own dio (bypassing the demo interceptor), so a demo // session must be skipped or its missing token would 401 into a logout. if (session == null || session.isDemo) return; final epoch = SessionManager().sessionEpoch; try { switch (session) { case CredentialSession(:final username, :final password): await AuthVerify().run(username: username, password: password); } } on AuthException catch (e) { if (e.statusCode != 401) return; // The probed account is no longer the active one; the 401 must not // sign out whoever took over meanwhile. if (!SessionManager().isCurrentSession(epoch)) return; log('MC: stored session rejected — forcing re-login'); final next = await SessionLifecycle.signOut( notice: switch (session) { CredentialSession() => 'Deine Zugangsdaten wurden vom Server abgelehnt. Vermutlich ' 'wurde dein Passwort geändert. Bitte melde dich erneut an.', }, ); await onInvalidated(next); } catch (e) { log('MC: background session check failed (transient): $e'); } } }