fixed stale state after logout and replayed or lost share intents
This commit is contained in:
@@ -55,6 +55,15 @@ class AccountData {
|
||||
unawaited(_loadWithRetry());
|
||||
}
|
||||
|
||||
int _sessionEpoch = 0;
|
||||
|
||||
/// Bumped on every sign-out. Async work captures it when it starts and
|
||||
/// drops its result when it changed meanwhile, so a request of the previous
|
||||
/// account cannot land in the next account's state or cache.
|
||||
int get sessionEpoch => _sessionEpoch;
|
||||
|
||||
bool isCurrentSession(int epoch) => epoch == _sessionEpoch;
|
||||
|
||||
String? _username;
|
||||
String? _password;
|
||||
String? _appPassword;
|
||||
@@ -109,6 +118,7 @@ class AccountData {
|
||||
}
|
||||
|
||||
Future<void> removeData() async {
|
||||
_sessionEpoch++;
|
||||
_populated = Completer();
|
||||
_username = null;
|
||||
_password = null;
|
||||
@@ -263,6 +273,52 @@ class AccountData {
|
||||
}
|
||||
}
|
||||
|
||||
bool _isUiEngine = false;
|
||||
|
||||
/// Called from `main()`; background entry points never run it.
|
||||
void markUiEngine() => _isUiEngine = true;
|
||||
|
||||
/// Username currently in the keystore. Other engines (widget task, push
|
||||
/// isolates) sign out or in without this instance noticing.
|
||||
Future<String?> readStoredUsername() =>
|
||||
_secureStorage.read(key: _usernameField);
|
||||
|
||||
/// Re-reads the session for long-lived background engines: they load once
|
||||
/// and would otherwise keep acting with an account that signed out in the
|
||||
/// app meanwhile. Keeps the known state when the keystore is unreadable.
|
||||
Future<void> reloadFromStorage() async {
|
||||
// The UI engine performs sign-in and sign-out itself, so its state is
|
||||
// current; re-reading mid sign-out could resurrect the removed account.
|
||||
if (_isUiEngine) return;
|
||||
try {
|
||||
final username = await _secureStorage.read(key: _usernameField);
|
||||
final password = await _secureStorage.read(key: _passwordField);
|
||||
final isDemo = (await _secureStorage.read(key: _demoField)) == 'true';
|
||||
final usesLoginFlow =
|
||||
(await _secureStorage.read(key: _loginFlowField)) == 'true';
|
||||
String? appPassword;
|
||||
String? appPasswordTalk;
|
||||
try {
|
||||
appPassword = await pushSecureStorage.read(key: _appPasswordField);
|
||||
appPasswordTalk = await pushSecureStorage.read(
|
||||
key: _appPasswordTalkField,
|
||||
);
|
||||
} on Object {
|
||||
// Group keystore unavailable: fall back to the real password.
|
||||
}
|
||||
if (username != _username) _sessionEpoch++;
|
||||
_username = username;
|
||||
_password = password;
|
||||
_isDemo = isDemo;
|
||||
_usesLoginFlow = usesLoginFlow;
|
||||
_appPassword = appPassword;
|
||||
_appPasswordTalk = appPasswordTalk;
|
||||
if (!_populated.isCompleted) _populated.complete();
|
||||
} on Object catch (e) {
|
||||
log('AccountData reload failed, keeping loaded state: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> waitForPopulation() async {
|
||||
await _populated.future;
|
||||
return isPopulated();
|
||||
|
||||
Reference in New Issue
Block a user