fix: session restore timeout + block .git access
- Add 12s timeout to restoreSession() — client.init() could hang indefinitely if token expired or server unreachable, leaving user on spinner forever. Now clears stale credentials and shows login. - Sync persistence startup wrapped in try-catch — non-fatal - .htaccess blocks .git directory (was returning 200 to scanners) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
// Version: 1.1.0 | Created: 2026-04-01
|
// Version: 1.1.1 | Created: 2026-04-01
|
||||||
// Riverpod notifier that owns the auth state machine.
|
// Riverpod notifier that owns the auth state machine.
|
||||||
// All login/logout/session-restore transitions go through here.
|
// All login/logout/session-restore transitions go through here.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
import '../../features/auth/data/auth_repository.dart';
|
import '../../features/auth/data/auth_repository.dart';
|
||||||
@@ -39,25 +41,40 @@ class AuthNotifier extends _$AuthNotifier {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final repo = ref.read(authRepositoryProvider);
|
final repo = ref.read(authRepositoryProvider);
|
||||||
await repo.restoreSession(
|
|
||||||
accessToken: credentials.accessToken,
|
// Timeout: client.init() starts the Matrix sync loop and can hang
|
||||||
userId: credentials.userId,
|
// indefinitely if the token is expired or the server is unreachable.
|
||||||
deviceId: credentials.deviceId,
|
// After 12 seconds we give up and send the user to the login screen.
|
||||||
);
|
await repo
|
||||||
|
.restoreSession(
|
||||||
|
accessToken: credentials.accessToken,
|
||||||
|
userId: credentials.userId,
|
||||||
|
deviceId: credentials.deviceId,
|
||||||
|
)
|
||||||
|
.timeout(
|
||||||
|
const Duration(seconds: 12),
|
||||||
|
onTimeout: () => throw Exception('Session restore timed out'),
|
||||||
|
);
|
||||||
|
|
||||||
state = AuthState.authenticated(
|
state = AuthState.authenticated(
|
||||||
userId: credentials.userId,
|
userId: credentials.userId,
|
||||||
accessToken: credentials.accessToken,
|
accessToken: credentials.accessToken,
|
||||||
deviceId: credentials.deviceId,
|
deviceId: credentials.deviceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Resume background persistence for the restored session.
|
// Resume background persistence — fire-and-forget so it never blocks auth.
|
||||||
ref.read(syncPersistenceServiceProvider).start();
|
try {
|
||||||
|
ref.read(syncPersistenceServiceProvider).start();
|
||||||
|
} catch (_) {
|
||||||
|
// Persistence failure is non-fatal; the app works without it.
|
||||||
|
}
|
||||||
} on AuthFailure {
|
} on AuthFailure {
|
||||||
// Stored credentials are invalid; force re-login.
|
// Stored credentials are invalid; force re-login.
|
||||||
await storage.clearCredentials();
|
await storage.clearCredentials();
|
||||||
state = const AuthState.unauthenticated();
|
state = const AuthState.unauthenticated();
|
||||||
} on Exception {
|
} on Exception {
|
||||||
// Network offline at startup; still land on login rather than crashing.
|
// Covers: timeout, network offline, Olm init failure.
|
||||||
|
// Clear stale credentials so the login screen appears cleanly.
|
||||||
await storage.clearCredentials();
|
await storage.clearCredentials();
|
||||||
state = const AuthState.unauthenticated();
|
state = const AuthState.unauthenticated();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user