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

View File

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