refactor: BREAKING Allow calling init when in soft logout state and fix some bugs

This fixes several problems with current soft logout
handling, as it now stores the refresh token correct and
only refreshs it 1 minute in advance instead of 5
minutes.
This commit is contained in:
Krille 2024-02-27 12:53:01 +01:00
parent 2e1f21393a
commit d049e667ee
No known key found for this signature in database
GPG Key ID: E067ECD60F1A0652
2 changed files with 54 additions and 17 deletions

View File

@ -43,7 +43,7 @@ import 'package:matrix/src/utils/try_get_push_rule.dart';
typedef RoomSorter = int Function(Room a, Room b);
enum LoginState { loggedIn, loggedOut }
enum LoginState { loggedIn, loggedOut, softLoggedOut }
extension TrailingSlash on Uri {
Uri stripTrailingSlash() => path.endsWith('/')
@ -267,10 +267,15 @@ class Client extends MatrixApi {
final tokenResponse = await refresh(refreshToken);
accessToken = tokenResponse.accessToken;
final expiresInMs = tokenResponse.expiresInMs;
final tokenExpiresAt = expiresInMs == null
? null
: DateTime.now().add(Duration(milliseconds: expiresInMs));
accessTokenExpiresAt = tokenExpiresAt;
await database?.updateClient(
homeserverUrl,
tokenResponse.accessToken,
accessTokenExpiresAt,
tokenExpiresAt,
tokenResponse.refreshToken,
userId,
deviceId,
@ -1574,7 +1579,7 @@ class Client extends MatrixApi {
String? userID;
try {
Logs().i('Initialize client $clientName');
if (isLogged()) {
if (onLoginStateChanged.value == LoginState.loggedIn) {
throw ClientInitPreconditionError(
'User is already logged in! Call [logout()] first!',
);
@ -1592,6 +1597,7 @@ class Client extends MatrixApi {
_serverConfigCache.invalidate();
final account = await this.database?.getClient(clientName);
newRefreshToken ??= account?.tryGet<String>('refresh_token');
if (account != null) {
_id = account['client_id'];
homeserver = Uri.parse(account['homeserver_url']);
@ -1626,6 +1632,26 @@ class Client extends MatrixApi {
olmAccount = newOlmAccount ?? olmAccount;
}
// If we are refreshing the session, we are done here:
if (onLoginStateChanged.value == LoginState.softLoggedOut) {
if (newRefreshToken != null && accessToken != null && userID != null) {
// Store the new tokens:
await _database?.updateClient(
homeserver.toString(),
accessToken,
accessTokenExpiresAt,
newRefreshToken,
userID,
_deviceID,
_deviceName,
prevBatch,
encryption?.pickledOlmAccount,
);
}
onLoginStateChanged.add(LoginState.loggedIn);
return;
}
if (accessToken == null || homeserver == null || userID == null) {
if (legacyDatabaseBuilder != null) {
await _migrateFromLegacyDatabase(onMigration: onMigration);
@ -1806,6 +1832,21 @@ class Client extends MatrixApi {
return;
}
Future<void> _handleSoftLogout() async {
final onSoftLogout = this.onSoftLogout;
if (onSoftLogout == null) return;
onLoginStateChanged.add(LoginState.softLoggedOut);
try {
await onSoftLogout(this);
onLoginStateChanged.add(LoginState.loggedIn);
} catch (e, s) {
Logs().w('Unable to refresh session after soft logout', e, s);
await clear();
rethrow;
}
}
/// Pass a timeout to set how long the server waits before sending an empty response.
/// (Corresponds to the timeout param on the /sync request.)
Future<void> _innerSync({Duration? timeout}) async {
@ -1820,20 +1861,20 @@ class Client extends MatrixApi {
Object? syncError;
await _checkSyncFilter();
// The timeout we send to the server for the sync loop. It says to the
// server that we want to receive an empty sync response after this
// amount of time if nothing happens.
timeout ??= const Duration(seconds: 30);
// Call onSoftLogout 5 minutes before access token expires to prevent
// failing network requests.
final tokenExpiresAt = accessTokenExpiresAt;
if (onSoftLogout != null &&
tokenExpiresAt != null &&
tokenExpiresAt.difference(DateTime.now()) <= Duration(minutes: 5)) {
await onSoftLogout?.call(this);
tokenExpiresAt.difference(DateTime.now()) <= timeout * 2) {
await _handleSoftLogout();
}
// The timeout we send to the server for the sync loop. It says to the
// server that we want to receive an empty sync response after this
// amount of time if nothing happens.
timeout ??= const Duration(seconds: 30);
final syncRequest = sync(
filter: syncFilterId,
since: prevBatch,
@ -1910,12 +1951,8 @@ class Client extends MatrixApi {
final onSoftLogout = this.onSoftLogout;
if (e.raw.tryGet<bool>('soft_logout') == true && onSoftLogout != null) {
Logs().w('The user has been soft logged out! Try to login again...');
try {
await onSoftLogout(this);
} catch (e, s) {
Logs().e('Unable to login again', e, s);
await clear();
}
await _handleSoftLogout();
} else {
Logs().w('The user has been logged out!');
await clear();

View File

@ -2034,7 +2034,7 @@ class FakeMatrixApi extends BaseClient {
'POST': {
'/client/v3/refresh': (var req) => {
'access_token': 'a_new_token',
'expires_in_ms': 60000,
'expires_in_ms': 1000 * 60 * 5,
'refresh_token': 'another_new_token'
},
'/client/v3/delete_devices': (var req) => {},