replaced account data singleton with a session model
This commit is contained in:
@@ -1,39 +1,43 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import '../../../model/account_data.dart';
|
||||
import '../../../session/session.dart';
|
||||
import '../../../session/session_lifecycle.dart';
|
||||
import '../../../session/session_manager.dart';
|
||||
import '../../errors/auth_exception.dart';
|
||||
import '../queries/auth_logout/auth_logout.dart';
|
||||
import '../queries/auth_verify/auth_verify.dart';
|
||||
import 'token_storage.dart';
|
||||
|
||||
/// Background 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.
|
||||
/// 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.
|
||||
class SessionValidator {
|
||||
static Future<void> probeStored({
|
||||
required Future<void> Function() onInvalidated,
|
||||
}) async {
|
||||
if (!AccountData().isPopulated()) return;
|
||||
// AuthVerify uses its own dio (bypassing the demo interceptor), so a demo
|
||||
// session must be skipped here or its missing token would 401 into a logout.
|
||||
if (AccountData().isDemo) return;
|
||||
final username = AccountData().getUsername();
|
||||
final password = AccountData().getPassword();
|
||||
final epoch = AccountData().sessionEpoch;
|
||||
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 {
|
||||
await AuthVerify().run(username: username, password: password);
|
||||
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 already signed out; the 401 must not sign out
|
||||
// whoever logged in meanwhile.
|
||||
if (!AccountData().isCurrentSession(epoch)) return;
|
||||
log('MC: stored credentials rejected — forcing re-login');
|
||||
await AuthLogout().run();
|
||||
await const MarianumConnectTokenStorage().clear();
|
||||
await AccountData().removeData();
|
||||
if (!SessionManager().isCurrentSession(epoch)) return;
|
||||
log('MC: stored session rejected — forcing re-login');
|
||||
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();
|
||||
} catch (e) {
|
||||
log('MC: background credential check failed (transient): $e');
|
||||
log('MC: background session check failed (transient): $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user