@@ -15,6 +15,7 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
15
15
import io.element.android.libraries.core.extensions.mapFailure
16
16
import io.element.android.libraries.core.extensions.runCatchingExceptions
17
17
import io.element.android.libraries.matrix.api.MatrixClient
18
+ import io.element.android.libraries.matrix.api.auth.AuthenticationException
18
19
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
19
20
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
20
21
import io.element.android.libraries.matrix.api.auth.OidcDetails
@@ -149,6 +150,8 @@ class RustMatrixAuthenticationService(
149
150
val client = currentClient ? : error(" You need to call `setHomeserver()` first" )
150
151
val currentSessionPaths = sessionPaths ? : error(" You need to call `setHomeserver()` first" )
151
152
client.login(username, password, " Element X Android" , null )
153
+ // Ensure that the user is not already logged in with the same account
154
+ ensureNotAlreadyLoggedIn(client)
152
155
val sessionData = client.session()
153
156
.toSessionData(
154
157
isTokenValid = true ,
@@ -237,17 +240,19 @@ class RustMatrixAuthenticationService(
237
240
val client = currentClient ? : error(" You need to call `setHomeserver()` first" )
238
241
val currentSessionPaths = sessionPaths ? : error(" You need to call `setHomeserver()` first" )
239
242
client.loginWithOidcCallback(callbackUrl)
243
+
244
+ // Free the pending data since we won't use it to abort the flow anymore
245
+ pendingOAuthAuthorizationData?.close()
246
+ pendingOAuthAuthorizationData = null
247
+
248
+ // Ensure that the user is not already logged in with the same account
249
+ ensureNotAlreadyLoggedIn(client)
240
250
val sessionData = client.session().toSessionData(
241
251
isTokenValid = true ,
242
252
loginType = LoginType .OIDC ,
243
253
passphrase = pendingPassphrase,
244
254
sessionPaths = currentSessionPaths,
245
255
)
246
-
247
- // Free the pending data since we won't use it to abort the flow anymore
248
- pendingOAuthAuthorizationData?.close()
249
- pendingOAuthAuthorizationData = null
250
-
251
256
val matrixClient = rustMatrixClientFactory.create(client)
252
257
newMatrixClientObservers.forEach { it.invoke(matrixClient) }
253
258
sessionStore.storeData(sessionData)
@@ -263,6 +268,21 @@ class RustMatrixAuthenticationService(
263
268
}
264
269
}
265
270
271
+ @Throws(AuthenticationException .AccountAlreadyLoggedIn ::class )
272
+ private suspend fun ensureNotAlreadyLoggedIn (client : Client ) {
273
+ val newUserId = client.userId()
274
+ val accountAlreadyLoggedIn = sessionStore.getAllSessions().any {
275
+ it.userId == newUserId
276
+ }
277
+ if (accountAlreadyLoggedIn) {
278
+ // Sign out the client, ignoring any error
279
+ runCatchingExceptions {
280
+ client.logout()
281
+ }
282
+ throw AuthenticationException .AccountAlreadyLoggedIn (newUserId)
283
+ }
284
+ }
285
+
266
286
override suspend fun loginWithQrCode (qrCodeData : MatrixQrCodeLoginData , progress : (QrCodeLoginStep ) -> Unit ) =
267
287
withContext(coroutineDispatchers.io) {
268
288
val sdkQrCodeLoginData = (qrCodeData as SdkQrCodeLoginData ).rustQrCodeData
@@ -285,7 +305,8 @@ class RustMatrixAuthenticationService(
285
305
oidcConfiguration = oidcConfiguration,
286
306
progressListener = progressListener,
287
307
)
288
-
308
+ // Ensure that the user is not already logged in with the same account
309
+ ensureNotAlreadyLoggedIn(client)
289
310
val sessionData = client.session()
290
311
.toSessionData(
291
312
isTokenValid = true ,
0 commit comments