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:
parent
2e1f21393a
commit
d049e667ee
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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) => {},
|
||||
|
|
|
|||
Loading…
Reference in New Issue