diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 446edfbae000ca7c4037273be3c0643250b40142..836b49b3f2dd13315263bad5854ef72cec77e8cb 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' -apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-parcelize' apply plugin: 'realm-android' buildscript { @@ -13,19 +13,15 @@ buildscript { } } -androidExtensions { - experimental = true -} - android { - compileSdkVersion 29 + compileSdkVersion 30 testOptions.unitTests.includeAndroidResources = true defaultConfig { minSdkVersion 21 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 1 - versionName "1.0.13" + versionName "0.0.1" // Multidex is useful for tests multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -116,7 +112,7 @@ dependencies { def lifecycle_version = '2.2.0' def arch_version = '2.1.0' def markwon_version = '3.1.0' - def daggerVersion = '2.29.1' + def daggerVersion = '2.31' def work_version = '2.4.0' def retrofit_version = '2.6.2' @@ -164,16 +160,11 @@ dependencies { // DI implementation "com.google.dagger:dagger:$daggerVersion" kapt "com.google.dagger:dagger-compiler:$daggerVersion" - compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.5.0' - kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.0' // Logging implementation 'com.jakewharton.timber:timber:4.7.1' implementation 'com.facebook.stetho:stetho-okhttp3:1.5.1' - // Bus - implementation 'org.greenrobot:eventbus:3.1.1' - // Phone number https://github.com/google/libphonenumber implementation 'com.googlecode.libphonenumber:libphonenumber:8.10.23' diff --git a/matrix-sdk-android/proguard-rules.pro b/matrix-sdk-android/proguard-rules.pro index fa860d8049e259f7494b4a2b0621eecadee2f365..182f9473e84b53602ecd5d24e3b20bca048653a6 100644 --- a/matrix-sdk-android/proguard-rules.pro +++ b/matrix-sdk-android/proguard-rules.pro @@ -20,14 +20,8 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile - -### EVENT BUS ### - +# BMA: Not sure I can delete this one without side effect -keepattributes *Annotation* --keepclassmembers class * { - @org.greenrobot.eventbus.Subscribe <methods>; -} --keep enum org.greenrobot.eventbus.ThreadMode { *; } ### MOSHI ### diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt index 9996eef0a87eac74106c3544483af0008521206b..b0df6fcb44ba66b82ca490721e01584d667a0539 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt @@ -16,8 +16,18 @@ package org.matrix.android.sdk.account +import org.junit.Assert.assertTrue +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.auth.UIABaseAuth +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.api.auth.UserPasswordAuth import org.matrix.android.sdk.api.auth.data.LoginFlowResult +import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.auth.registration.RegistrationResult import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.MatrixError @@ -25,12 +35,8 @@ import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestMatrixCallback -import org.junit.Assert.assertTrue -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 -import org.junit.runners.MethodSorters +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume @RunWith(JUnit4::class) @FixMethodOrder(MethodSorters.JVM) @@ -44,7 +50,18 @@ class DeactivateAccountTest : InstrumentedTest { // Deactivate the account commonTestHelper.runBlockingTest { - session.deactivateAccount(TestConstants.PASSWORD, false) + session.deactivateAccount( + object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume( + UserPasswordAuth( + user = session.myUserId, + password = TestConstants.PASSWORD, + session = flowResponse.session + ) + ) + } + }, false) } // Try to login on the previous account, it will fail (M_USER_DEACTIVATED) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt index 0e7088a6a5a6dec08b83147f063adc5d73e8a0e8..a4dbd70b116bbf97e14ff3ed58e31a7e6445d613 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt @@ -86,7 +86,7 @@ class CommonTestHelper(context: Context) { * * @param session the session to sync */ - fun syncSession(session: Session) { + fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis) { val lock = CountDownLatch(1) val job = GlobalScope.launch(Dispatchers.Main) { @@ -109,7 +109,7 @@ class CommonTestHelper(context: Context) { } GlobalScope.launch(Dispatchers.Main) { syncLiveData.observeForever(syncObserver) } - await(lock) + await(lock, timeout) } /** @@ -119,7 +119,7 @@ class CommonTestHelper(context: Context) { * @param message the message to send * @param nbOfMessages the number of time the message will be sent */ - fun sendTextMessage(room: Room, message: String, nbOfMessages: Int): List<TimelineEvent> { + fun sendTextMessage(room: Room, message: String, nbOfMessages: Int, timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> { val timeline = room.createTimeline(null, TimelineSettings(10)) val sentEvents = ArrayList<TimelineEvent>(nbOfMessages) val latch = CountDownLatch(1) @@ -151,7 +151,7 @@ class CommonTestHelper(context: Context) { room.sendTextMessage(message + " #" + (i + 1)) } // Wait 3 second more per message - await(latch, timeout = TestConstants.timeOutMillis + 3_000L * nbOfMessages) + await(latch, timeout = timeout + 3_000L * nbOfMessages) timeline.dispose() // Check that all events has been created @@ -215,14 +215,14 @@ class CommonTestHelper(context: Context) { .getLoginFlow(hs, it) } - doSync<RegistrationResult> { + doSync<RegistrationResult>(timeout = 60_000) { matrix.authenticationService .getRegistrationWizard() .createAccount(userName, password, null, it) } // Perform dummy step - val registrationResult = doSync<RegistrationResult> { + val registrationResult = doSync<RegistrationResult>(timeout = 60_000) { matrix.authenticationService .getRegistrationWizard() .dummy(it) @@ -231,7 +231,7 @@ class CommonTestHelper(context: Context) { assertTrue(registrationResult is RegistrationResult.Success) val session = (registrationResult as RegistrationResult.Success).session if (sessionTestParams.withInitialSync) { - syncSession(session) + syncSession(session, 60_000) } return session @@ -378,7 +378,9 @@ class CommonTestHelper(context: Context) { fun Iterable<Session>.signOutAndClose() = forEach { signOutAndClose(it) } fun signOutAndClose(session: Session) { - doSync<Unit>(60_000) { session.signOut(true, it) } + runBlockingTest(timeout = 60_000) { + session.signOut(true) + } // no need signout will close // session.close() } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt index 76e59d9a902658035a2463f3386d1a884f47c71f..b6bedbd7197eff6d73c3d54a063600b81f463791 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt @@ -18,14 +18,21 @@ package org.matrix.android.sdk.common import org.matrix.android.sdk.api.session.Session -data class CryptoTestData(val firstSession: Session, - val roomId: String, - val secondSession: Session? = null, - val thirdSession: Session? = null) { +data class CryptoTestData(val roomId: String, + val sessions: List<Session>) { + + val firstSession: Session + get() = sessions.first() + + val secondSession: Session? + get() = sessions.getOrNull(1) + + val thirdSession: Session? + get() = sessions.getOrNull(2) fun cleanUp(testHelper: CommonTestHelper) { - testHelper.signOutAndClose(firstSession) - secondSession?.let { testHelper.signOutAndClose(it) } - thirdSession?.let { testHelper.signOutAndClose(it) } + sessions.forEach { + testHelper.signOutAndClose(it) + } } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt index cbb22daf0f14ab7d4eaa089836408aaf5d929ecf..eb7e4a9fbec2c3a0f68b242b6f98f2a7cb01f71f 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt @@ -19,6 +19,18 @@ package org.matrix.android.sdk.common import android.os.SystemClock import android.util.Log import androidx.lifecycle.Observer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.matrix.android.sdk.api.auth.UIABaseAuth +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.api.auth.UserPasswordAuth +import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.OutgoingSasVerificationTransaction @@ -36,17 +48,10 @@ import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertNull -import org.junit.Assert.assertTrue import java.util.UUID import java.util.concurrent.CountDownLatch +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume class CryptoTestHelper(private val mTestHelper: CommonTestHelper) { @@ -73,7 +78,7 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) { } } - return CryptoTestData(aliceSession, roomId) + return CryptoTestData(roomId, listOf(aliceSession)) } /** @@ -139,7 +144,7 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) { // assertNotNull(roomFromBobPOV.powerLevels) // assertTrue(roomFromBobPOV.powerLevels.maySendMessage(bobSession.myUserId)) - return CryptoTestData(aliceSession, aliceRoomId, bobSession) + return CryptoTestData(aliceRoomId, listOf(aliceSession, bobSession)) } /** @@ -157,7 +162,7 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) { // wait the initial sync SystemClock.sleep(1000) - return CryptoTestData(aliceSession, aliceRoomId, cryptoTestData.secondSession, samSession) + return CryptoTestData(aliceRoomId, listOf(aliceSession, cryptoTestData.secondSession!!, samSession)) } /** @@ -304,10 +309,18 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) { fun initializeCrossSigning(session: Session) { mTestHelper.doSync<Unit> { session.cryptoService().crossSigningService() - .initializeCrossSigning(UserPasswordAuth( - user = session.myUserId, - password = TestConstants.PASSWORD - ), it) + .initializeCrossSigning( + object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume( + UserPasswordAuth( + user = session.myUserId, + password = TestConstants.PASSWORD, + session = flowResponse.session + ) + ) + } + }, it) } } @@ -381,4 +394,30 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) { } } } + + fun doE2ETestWithManyMembers(numberOfMembers: Int): CryptoTestData { + val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams) + aliceSession.cryptoService().setWarnOnUnknownDevices(false) + + val roomId = mTestHelper.doSync<String> { + aliceSession.createRoom(CreateRoomParams().apply { name = "MyRoom" }, it) + } + val room = aliceSession.getRoom(roomId)!! + + mTestHelper.runBlockingTest { + room.enableEncryption() + } + + val sessions = mutableListOf(aliceSession) + for (index in 1 until numberOfMembers) { + val session = mTestHelper.createAccount("User_$index", defaultSessionParams) + mTestHelper.doSync<Unit>(timeout = 600_000) { room.invite(session.myUserId, null, it) } + println("TEST -> " + session.myUserId + " invited") + mTestHelper.doSync<Unit> { session.joinRoom(room.roomId, null, emptyList(), it) } + println("TEST -> " + session.myUserId + " joined") + sessions.add(session) + } + + return CryptoTestData(roomId, sessions) + } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt index 0e3b29118c5a149c305b2a865a3f8ec896239753..cf31294e2f9150d816bd0347474fa7ff3c85398f 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt @@ -17,7 +17,18 @@ package org.matrix.android.sdk.internal.crypto import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.amshove.kluent.shouldBe +import org.junit.Assert +import org.junit.Before +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.auth.UIABaseAuth +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.api.auth.UserPasswordAuth +import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.EventType @@ -30,19 +41,13 @@ import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm -import org.amshove.kluent.shouldBe -import org.junit.Assert -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters import org.matrix.olm.OlmSession import timber.log.Timber import java.util.concurrent.CountDownLatch +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume /** * Ref: @@ -202,10 +207,18 @@ class UnwedgingTest : InstrumentedTest { // It's a trick to force key request on fail to decrypt mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService() - .initializeCrossSigning(UserPasswordAuth( - user = bobSession.myUserId, - password = TestConstants.PASSWORD - ), it) + .initializeCrossSigning( + object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume( + UserPasswordAuth( + user = bobSession.myUserId, + password = TestConstants.PASSWORD, + session = flowResponse.session + ) + ) + } + }, it) } // Wait until we received back the key diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt index 38c57bd22a6288c8b7e2031ee165c7e901de9623..44af87bcbe482d23dce25012e4939c58d36b1f5a 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt @@ -17,14 +17,6 @@ package org.matrix.android.sdk.internal.crypto.crosssigning import androidx.test.ext.junit.runners.AndroidJUnit4 -import org.matrix.android.sdk.InstrumentedTest -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper -import org.matrix.android.sdk.common.SessionTestParams -import org.matrix.android.sdk.common.TestConstants -import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo -import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -35,6 +27,19 @@ import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters +import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.auth.UIABaseAuth +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.api.auth.UserPasswordAuth +import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse +import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.SessionTestParams +import org.matrix.android.sdk.common.TestConstants +import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo +import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @@ -49,10 +54,17 @@ class XSigningTest : InstrumentedTest { mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService() - .initializeCrossSigning(UserPasswordAuth( - user = aliceSession.myUserId, - password = TestConstants.PASSWORD - ), it) + .initializeCrossSigning(object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume( + UserPasswordAuth( + user = aliceSession.myUserId, + password = TestConstants.PASSWORD, + session = flowResponse.session + ) + ) + } + }, it) } val myCrossSigningKeys = aliceSession.cryptoService().crossSigningService().getMyCrossSigningKeys() @@ -86,8 +98,18 @@ class XSigningTest : InstrumentedTest { password = TestConstants.PASSWORD ) - mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(aliceAuthParams, it) } - mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(bobAuthParams, it) } + mTestHelper.doSync<Unit> { + aliceSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume(aliceAuthParams) + } + }, it) + } + mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume(bobAuthParams) + } + }, it) } // Check that alice can see bob keys mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobSession.myUserId), true, it) } @@ -122,8 +144,16 @@ class XSigningTest : InstrumentedTest { password = TestConstants.PASSWORD ) - mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(aliceAuthParams, it) } - mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(bobAuthParams, it) } + mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume(aliceAuthParams) + } + }, it) } + mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume(bobAuthParams) + } + }, it) } // Check that alice can see bob keys val bobUserId = bobSession.myUserId diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt index 197e36df0686cf4ba87bf6376cf49a8ed1b66784..8c3917adc131e32027c75be629c3790de2c9582f 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt @@ -18,7 +18,21 @@ package org.matrix.android.sdk.internal.crypto.gossiping import android.util.Log import androidx.test.ext.junit.runners.AndroidJUnit4 +import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertNotNull +import junit.framework.TestCase.assertTrue +import junit.framework.TestCase.fail +import org.junit.Assert +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.auth.UIABaseAuth +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.api.auth.UserPasswordAuth +import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod @@ -28,6 +42,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxStat import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams +import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.SessionTestParams @@ -40,17 +55,9 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull -import junit.framework.TestCase.assertTrue -import junit.framework.TestCase.fail -import org.junit.Assert -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters import java.util.concurrent.CountDownLatch +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.JVM) @@ -198,10 +205,17 @@ class KeyShareTests : InstrumentedTest { mTestHelper.doSync<Unit> { aliceSession1.cryptoService().crossSigningService() - .initializeCrossSigning(UserPasswordAuth( - user = aliceSession1.myUserId, - password = TestConstants.PASSWORD - ), it) + .initializeCrossSigning( + object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume( + UserPasswordAuth( + user = aliceSession1.myUserId, + password = TestConstants.PASSWORD + ) + ) + } + }, it) } // Also bootstrap keybackup on first session @@ -296,4 +310,93 @@ class KeyShareTests : InstrumentedTest { mTestHelper.signOutAndClose(aliceSession1) mTestHelper.signOutAndClose(aliceSession2) } + + @Test + fun test_ImproperKeyShareBug() { + val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) + + mTestHelper.doSync<Unit> { + aliceSession.cryptoService().crossSigningService() + .initializeCrossSigning( + object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume( + UserPasswordAuth( + user = aliceSession.myUserId, + password = TestConstants.PASSWORD, + session = flowResponse.session + ) + ) + } + }, it) + } + + // Create an encrypted room and send a couple of messages + val roomId = mTestHelper.doSync<String> { + aliceSession.createRoom( + CreateRoomParams().apply { + visibility = RoomDirectoryVisibility.PRIVATE + enableEncryption() + }, + it + ) + } + val roomAlicePov = aliceSession.getRoom(roomId) + assertNotNull(roomAlicePov) + Thread.sleep(1_000) + assertTrue(roomAlicePov?.isEncrypted() == true) + val secondEventId = mTestHelper.sendTextMessage(roomAlicePov!!, "Message", 3)[1].eventId + + // Create bob session + + val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, SessionTestParams(true)) + mTestHelper.doSync<Unit> { + bobSession.cryptoService().crossSigningService() + .initializeCrossSigning( + object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume( + UserPasswordAuth( + user = bobSession.myUserId, + password = TestConstants.PASSWORD, + session = flowResponse.session + ) + ) + } + }, it) + } + + // Let alice invite bob + mTestHelper.doSync<Unit> { + roomAlicePov.invite(bobSession.myUserId, null, it) + } + + mTestHelper.doSync<Unit> { + bobSession.joinRoom(roomAlicePov.roomId, null, emptyList(), it) + } + + // we want to discard alice outbound session + aliceSession.cryptoService().discardOutboundSession(roomAlicePov.roomId) + + // and now resend a new message to reset index to 0 + mTestHelper.sendTextMessage(roomAlicePov, "After", 1) + + val roomRoomBobPov = aliceSession.getRoom(roomId) + val beforeJoin = roomRoomBobPov!!.getTimeLineEvent(secondEventId) + + var dRes = tryOrNull { bobSession.cryptoService().decryptEvent(beforeJoin!!.root, "") } + + assert(dRes == null) + + // Try to re-ask the keys + + bobSession.cryptoService().reRequestRoomKeyForEvent(beforeJoin!!.root) + + Thread.sleep(3_000) + + // With the bug the first session would have improperly reshare that key :/ + dRes = tryOrNull { bobSession.cryptoService().decryptEvent(beforeJoin.root, "") } + Log.d("#TEST", "KS: sgould not decrypt that ${beforeJoin.root.getClearContent().toModel<MessageContent>()?.body}") + assert(dRes?.clearEvent == null) + } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt index 1385dac1ec6a344fb0833330410cec571fbae213..397f7f9441bf467d3711a06d665bed4d9639d492 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt @@ -17,20 +17,25 @@ package org.matrix.android.sdk.internal.crypto.verification.qrcode import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.amshove.kluent.shouldBe +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.auth.UIABaseAuth +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.api.auth.UserPasswordAuth +import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse +import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.session.crypto.verification.VerificationService import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.TestConstants -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth -import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest -import org.amshove.kluent.shouldBe -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters import java.util.concurrent.CountDownLatch +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.JVM) @@ -157,18 +162,34 @@ class VerificationTest : InstrumentedTest { mTestHelper.doSync<Unit> { callback -> aliceSession.cryptoService().crossSigningService() - .initializeCrossSigning(UserPasswordAuth( - user = aliceSession.myUserId, - password = TestConstants.PASSWORD - ), callback) + .initializeCrossSigning( + object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume( + UserPasswordAuth( + user = aliceSession.myUserId, + password = TestConstants.PASSWORD, + session = flowResponse.session + ) + ) + } + }, callback) } mTestHelper.doSync<Unit> { callback -> bobSession.cryptoService().crossSigningService() - .initializeCrossSigning(UserPasswordAuth( - user = bobSession.myUserId, - password = TestConstants.PASSWORD - ), callback) + .initializeCrossSigning( + object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) { + promise.resume( + UserPasswordAuth( + user = bobSession.myUserId, + password = TestConstants.PASSWORD, + session = flowResponse.session + ) + ) + } + }, callback) } val aliceVerificationService = aliceSession.cryptoService().verificationService() diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/media/UrlsExtractorTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/media/UrlsExtractorTest.kt index 9ee84fdfc684a9c50299e0854fd065194c6d23cb..473b18b31b62b9f05fd34e1e1ed12b811d88b62c 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/media/UrlsExtractorTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/media/UrlsExtractorTest.kt @@ -26,6 +26,8 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent import org.matrix.android.sdk.api.session.room.model.message.MessageType +import org.matrix.android.sdk.api.session.room.sender.SenderInfo +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent @RunWith(AndroidJUnit4::class) internal class UrlsExtractorTest : InstrumentedTest { @@ -36,6 +38,7 @@ internal class UrlsExtractorTest : InstrumentedTest { fun wrongEventTypeTest() { createEvent(body = "https://matrix.org") .copy(type = EventType.STATE_ROOM_GUEST_ACCESS) + .toFakeTimelineEvent() .let { urlsExtractor.extract(it) } .size shouldBeEqualTo 0 } @@ -43,6 +46,7 @@ internal class UrlsExtractorTest : InstrumentedTest { @Test fun oneUrlTest() { createEvent(body = "https://matrix.org") + .toFakeTimelineEvent() .let { urlsExtractor.extract(it) } .let { result -> result.size shouldBeEqualTo 1 @@ -53,6 +57,7 @@ internal class UrlsExtractorTest : InstrumentedTest { @Test fun withoutProtocolTest() { createEvent(body = "www.matrix.org") + .toFakeTimelineEvent() .let { urlsExtractor.extract(it) } .size shouldBeEqualTo 0 } @@ -60,6 +65,7 @@ internal class UrlsExtractorTest : InstrumentedTest { @Test fun oneUrlWithParamTest() { createEvent(body = "https://matrix.org?foo=bar") + .toFakeTimelineEvent() .let { urlsExtractor.extract(it) } .let { result -> result.size shouldBeEqualTo 1 @@ -70,6 +76,7 @@ internal class UrlsExtractorTest : InstrumentedTest { @Test fun oneUrlWithParamsTest() { createEvent(body = "https://matrix.org?foo=bar&bar=foo") + .toFakeTimelineEvent() .let { urlsExtractor.extract(it) } .let { result -> result.size shouldBeEqualTo 1 @@ -80,16 +87,18 @@ internal class UrlsExtractorTest : InstrumentedTest { @Test fun oneUrlInlinedTest() { createEvent(body = "Hello https://matrix.org, how are you?") + .toFakeTimelineEvent() .let { urlsExtractor.extract(it) } .let { result -> result.size shouldBeEqualTo 1 - result[0] shouldBeEqualTo "https://matrix.org" + result[0] shouldBeEqualTo "https://matrix.org" } } @Test fun twoUrlsTest() { createEvent(body = "https://matrix.org https://example.org") + .toFakeTimelineEvent() .let { urlsExtractor.extract(it) } .let { result -> result.size shouldBeEqualTo 2 @@ -99,10 +108,26 @@ internal class UrlsExtractorTest : InstrumentedTest { } private fun createEvent(body: String): Event = Event( + eventId = "!fake", type = EventType.MESSAGE, content = MessageTextContent( msgType = MessageType.MSGTYPE_TEXT, body = body ).toContent() ) + + private fun Event.toFakeTimelineEvent(): TimelineEvent { + return TimelineEvent( + root = this, + localId = 0L, + eventId = eventId!!, + displayIndex = 0, + senderInfo = SenderInfo( + userId = "", + displayName = null, + isUniqueDisplayName = true, + avatarUrl = null + ) + ) + } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt index 34edf37733614146b295c74fab9fcbf5cd4b3617..f156a5eb647c3cb6450ec6df11a03d41439993a4 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt @@ -66,8 +66,8 @@ class TimelineForwardPaginationTest : InstrumentedTest { numberOfMessagesToSend) // Alice clear the cache - commonTestHelper.doSync<Unit> { - aliceSession.clearCache(it) + commonTestHelper.runBlockingTest { + aliceSession.clearCache() } // And restarts the sync diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..ff07cf1d1d4ab473b389cc8e6d2509f818b5dae9 --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.session.room.timeline + +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.runners.MethodSorters +import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.message.MessageContent +import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings +import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CryptoTestHelper +import java.util.concurrent.CountDownLatch +import kotlin.test.fail + +@RunWith(JUnit4::class) +@FixMethodOrder(MethodSorters.JVM) +class TimelineWithManyMembersTest : InstrumentedTest { + + companion object { + private const val NUMBER_OF_MEMBERS = 6 + } + + private val commonTestHelper = CommonTestHelper(context()) + private val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + + /** + * Ensures when someone sends a message to a crowded room, everyone can decrypt the message. + */ + @Test + fun everyone_should_decrypt_message_in_a_crowded_room() { + val cryptoTestData = cryptoTestHelper.doE2ETestWithManyMembers(NUMBER_OF_MEMBERS) + + val sessionForFirstMember = cryptoTestData.firstSession + val roomForFirstMember = sessionForFirstMember.getRoom(cryptoTestData.roomId)!! + + val firstMessage = "First messages from Alice" + commonTestHelper.sendTextMessage( + roomForFirstMember, + firstMessage, + 1, + 600_000 + ) + + for (index in 1 until cryptoTestData.sessions.size) { + val session = cryptoTestData.sessions[index] + val roomForCurrentMember = session.getRoom(cryptoTestData.roomId)!! + val timelineForCurrentMember = roomForCurrentMember.createTimeline(null, TimelineSettings(30)) + timelineForCurrentMember.start() + + session.startSync(true) + + run { + val lock = CountDownLatch(1) + val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> + snapshot + .find { it.isEncrypted() } + ?.let { + val body = it.root.getClearContent()?.toModel<MessageContent>()?.body + if (body?.startsWith(firstMessage).orFalse()) { + println("User " + session.myUserId + " decrypted as " + body) + return@createEventListener true + } else { + fail("User " + session.myUserId + " decrypted as " + body + " CryptoError: " + it.root.mCryptoError) + } + } ?: return@createEventListener false + } + timelineForCurrentMember.addListener(eventsListener) + commonTestHelper.await(lock, 600_000) + } + session.stopSync() + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt index 360b9558694839bd67bb32f5f73e2fc023a68331..bf21941e0c99c5ee5715bcc26b3212420a57ff00 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt @@ -41,6 +41,16 @@ interface AuthenticationService { */ fun getLoginFlowOfSession(sessionId: String, callback: MatrixCallback<LoginFlowResult>): Cancelable + /** + * Get a SSO url + */ + fun getSsoUrl(redirectUrl: String, deviceId: String?, providerId: String?): String? + + /** + * Get the sign in or sign up fallback URL + */ + fun getFallbackUrl(forSignIn: Boolean, deviceId: String?): String? + /** * Return a LoginWizard, to login to the homeserver. The login flow has to be retrieved first. */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/TokenBasedAuth.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/TokenBasedAuth.kt new file mode 100644 index 0000000000000000000000000000000000000000..e522352c3870735644f295556c5815651664c765 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/TokenBasedAuth.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.matrix.android.sdk.api.auth + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.auth.data.LoginFlowTypes + +/** + * This class provides the authentication data by using user and password + */ +@JsonClass(generateAdapter = true) +data class TokenBasedAuth( + + /** + * This is a session identifier that the client must pass back to the homeserver, + * if one is provided, in subsequent attempts to authenticate in the same API call. + */ + @Json(name = "session") + override val session: String? = null, + + /** + * A client may receive a login token via some external service, such as email or SMS. + * Note that a login token is separate from an access token, the latter providing general authentication to various API endpoints. + */ + @Json(name = "token") + val token: String? = null, + + /** + * The txn_id should be a random string generated by the client for the request. + * The same txn_id should be used if retrying the request. + * The txn_id may be used by the server to disallow other devices from using the token, + * thus providing "single use" tokens while still allowing the device to retry the request. + * This would be done by tying the token to the txn_id server side, as well as potentially invalidating + * the token completely once the device has successfully logged in + * (e.g. when we receive a request from the newly provisioned access_token). + */ + @Json(name = "txn_id") + val transactionId: String? = null, + + // registration information + @Json(name = "type") + val type: String? = LoginFlowTypes.TOKEN + +) : UIABaseAuth { + override fun hasAuthInfo() = token != null + + override fun copyWithSession(session: String) = this.copy(session = session) + + override fun asMap(): Map<String, *> = mapOf( + "session" to session, + "token" to token, + "transactionId" to transactionId, + "type" to type + ) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UIABaseAuth.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UIABaseAuth.kt new file mode 100644 index 0000000000000000000000000000000000000000..d5e323e457fe3d7b6beba22e1ebfda5b1fb2989a --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UIABaseAuth.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.auth + +interface UIABaseAuth { + /** + * This is a session identifier that the client must pass back to the homeserver, + * if one is provided, in subsequent attempts to authenticate in the same API call. + */ + val session: String? + + fun hasAuthInfo(): Boolean + + fun copyWithSession(session: String): UIABaseAuth + + fun asMap() : Map<String, *> +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UserInteractiveAuthInterceptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UserInteractiveAuthInterceptor.kt new file mode 100644 index 0000000000000000000000000000000000000000..16a5c8073df734ff5671b0a13ebccff306320e5c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UserInteractiveAuthInterceptor.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.auth + +import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse +import kotlin.coroutines.Continuation + +/** + * Some API endpoints require authentication that interacts with the user. + * The homeserver may provide many different ways of authenticating, such as user/password auth, login via a social network (OAuth2), + * login by confirming a token sent to their email address, etc. + * + * The process takes the form of one or more 'stages'. + * At each stage the client submits a set of data for a given authentication type and awaits a response from the server, + * which will either be a final success or a request to perform an additional stage. + * This exchange continues until the final success. + * + * For each endpoint, a server offers one or more 'flows' that the client can use to authenticate itself. + * Each flow comprises a series of stages, as described above. + * The client is free to choose which flow it follows, however the flow's stages must be completed in order. + * Failing to follow the flows in order must result in an HTTP 401 response. + * When all stages in a flow are complete, authentication is complete and the API call succeeds. + */ +interface UserInteractiveAuthInterceptor { + + /** + * When the API needs additional auth, this will be called. + * Implementation should check the flows from flow response and act accordingly. + * Updated auth should be provided using promise.resume, this allow implementation to perform + * an async operation (prompt for user password, open sso fallback) and then resume initial API call when done. + */ + fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UserPasswordAuth.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UserPasswordAuth.kt similarity index 74% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UserPasswordAuth.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UserPasswordAuth.kt index ba8b34096cb1fc112d3ca56fa8d53739e718234b..e985c5f08abfdeee95c5dcc214f4af169024f9a2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UserPasswordAuth.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UserPasswordAuth.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.internal.crypto.model.rest +package org.matrix.android.sdk.api.auth import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @@ -27,7 +27,7 @@ data class UserPasswordAuth( // device device session id @Json(name = "session") - val session: String? = null, + override val session: String? = null, // registration information @Json(name = "type") @@ -38,4 +38,16 @@ data class UserPasswordAuth( @Json(name = "password") val password: String? = null -) +) : UIABaseAuth { + + override fun hasAuthInfo() = password != null + + override fun copyWithSession(session: String) = this.copy(session = session) + + override fun asMap(): Map<String, *> = mapOf( + "session" to session, + "user" to user, + "password" to password, + "type" to type + ) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt index d89607843f1d745e3ce67de8c213ab598c032bce..cfaf74ce240f4ee8c9bf4650b9302815a92a641c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.auth.data import android.os.Parcelable import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize @JsonClass(generateAdapter = true) @Parcelize @@ -38,15 +38,24 @@ data class SsoIdentityProvider( * If present then it must be an HTTPS URL to an image resource. * This should be hosted by the homeserver service provider to not leak the client's IP address unnecessarily. */ - @Json(name = "icon") val iconUrl: String? + @Json(name = "icon") val iconUrl: String?, + + /** + * The `brand` field is **optional**. It allows the client to style the login + * button to suit a particular brand. It should be a string matching the + * "Common namespaced identifier grammar" as defined in + * [MSC2758](https://github.com/matrix-org/matrix-doc/pull/2758). + */ + @Json(name = "brand") val brand: String? + ) : Parcelable { companion object { - // Not really defined by the spec, but we may define some ids here - const val ID_GOOGLE = "google" - const val ID_GITHUB = "github" - const val ID_APPLE = "apple" - const val ID_FACEBOOK = "facebook" - const val ID_TWITTER = "twitter" + const val BRAND_GOOGLE = "org.matrix.google" + const val BRAND_GITHUB = "org.matrix.github" + const val BRAND_APPLE = "org.matrix.apple" + const val BRAND_FACEBOOK = "org.matrix.facebook" + const val BRAND_TWITTER = "org.matrix.twitter" + const val BRAND_GITLAB = "org.matrix.gitlab" } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegistrationFlowResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt similarity index 93% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegistrationFlowResponse.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt index 3461a4d738c7447472e2381fd41ab77dff1e4912..2b1c1c09b3d7b466d752ff3f7c89fbe4e1131a41 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegistrationFlowResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.auth.registration +package org.matrix.android.sdk.api.auth.registration import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.auth.data.LoginFlowTypes -import org.matrix.android.sdk.api.auth.registration.FlowResult -import org.matrix.android.sdk.api.auth.registration.Stage -import org.matrix.android.sdk.api.auth.registration.TermPolicies import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.auth.data.InteractiveAuthenticationFlow @@ -109,3 +106,8 @@ fun RegistrationFlowResponse.toFlowResult(): FlowResult { return FlowResult(missingStage, completedStage) } + +fun RegistrationFlowResponse.nextUncompletedStage(flowIndex: Int = 0): String? { + val completed = completedStages ?: emptyList() + return flows?.getOrNull(flowIndex)?.stages?.firstOrNull { completed.contains(it).not() } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt index 4711f7957d2f88c2fddc62bd0e8dacb7958ad9a6..c06cdd9e23a4efdf8e399259419b3101d1052bcd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt @@ -16,8 +16,8 @@ package org.matrix.android.sdk.api.failure +import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.extensions.tryOrNull -import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.internal.di.MoshiProvider import java.io.IOException import javax.net.ssl.HttpsURLConnection @@ -43,6 +43,12 @@ fun Throwable.isInvalidPassword(): Boolean { && error.message == "Invalid password" } +fun Throwable.isInvalidUIAAuth(): Boolean { + return this is Failure.ServerError + && error.code == MatrixError.M_FORBIDDEN + && error.flows != null +} + /** * Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible */ @@ -53,6 +59,16 @@ fun Throwable.toRegistrationFlowResponse(): RegistrationFlowResponse? { .adapter(RegistrationFlowResponse::class.java) .fromJson(this.errorBody) } + } else if (this is Failure.ServerError && this.httpCode == 401 && this.error.code == MatrixError.M_FORBIDDEN) { + // This happens when the submission for this stage was bad (like bad password) + if (this.error.session != null && this.error.flows != null) { + RegistrationFlowResponse( + flows = this.error.flows, + session = this.error.session, + completedStages = this.error.completedStages, + params = this.error.params + ) + } else null } else { null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt index de881b9e02656c1787894f931589c79d05bac0af..b2419033649c36684ff79cd54bff16dcd71a08f3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt @@ -16,8 +16,8 @@ package org.matrix.android.sdk.api.failure +import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.session.crypto.MXCryptoError -import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.internal.network.ssl.Fingerprint import java.io.IOException diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt index 895be0031a38a8b1c5e15a7e224c8bdd9c6713f9..3820a442aaa7ef42416a7c7301539e39eebf6f50 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt @@ -18,6 +18,8 @@ package org.matrix.android.sdk.api.failure import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.internal.auth.data.InteractiveAuthenticationFlow /** * This data class holds the error defined by the matrix specifications. @@ -42,7 +44,17 @@ data class MatrixError( @Json(name = "soft_logout") val isSoftLogout: Boolean = false, // For M_INVALID_PEPPER // {"error": "pepper does not match 'erZvr'", "lookup_pepper": "pQgMS", "algorithm": "sha256", "errcode": "M_INVALID_PEPPER"} - @Json(name = "lookup_pepper") val newLookupPepper: String? = null + @Json(name = "lookup_pepper") val newLookupPepper: String? = null, + + // For M_FORBIDDEN UIA + @Json(name = "session") + val session: String? = null, + @Json(name = "completed") + val completedStages: List<String>? = null, + @Json(name = "flows") + val flows: List<InteractiveAuthenticationFlow>? = null, + @Json(name = "params") + val params: JsonDict? = null ) { companion object { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt index 4f9c84a47c2b1171b2f08255205eb8da07bb3db2..6675fb0ff5082b6b0d9169ecaf45937a3026ef73 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt @@ -37,6 +37,6 @@ class SenderNotificationPermissionCondition( fun isSatisfied(event: Event, powerLevels: PowerLevelsContent): Boolean { val powerLevelsHelper = PowerLevelsHelper(powerLevels) - return event.senderId != null && powerLevelsHelper.getUserPowerLevelValue(event.senderId) >= powerLevelsHelper.notificationLevel(key) + return event.senderId != null && powerLevelsHelper.getUserPowerLevelValue(event.senderId) >= powerLevels.notificationLevel(key) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt index 8a95baf3cb82e991a12c38539d732395ecea58fa..ff7c9f0521c6d698c59e202f98b105e7207755b4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt @@ -245,6 +245,8 @@ interface Session : val sharedSecretStorageService: SharedSecretStorageService + fun getUiaSsoFallbackUrl(authenticationSessionId: String): String + /** * Maintenance API, allows to print outs info on DB size to logcat */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt index 8915202f355d6d38cb2a6fee3684f721f9c4c282..eb327dfd56c18b6df0e75db011a8f6eabce9561f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.api.session.account +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor + /** * This interface defines methods to manage the account. It's implemented at the session level. */ @@ -43,5 +45,5 @@ interface AccountService { * @param eraseAllData set to true to forget all messages that have been sent. Warning: this will cause future users to see * an incomplete view of conversations */ - suspend fun deactivateAccount(password: String, eraseAllData: Boolean) + suspend fun deactivateAccount(userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, eraseAllData: Boolean) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/cache/CacheService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/cache/CacheService.kt index c1c56632277df7db8f56fcbd1f89744d70ed1956..2945cc45d6444d1e083948274dc3a85143956bbb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/cache/CacheService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/cache/CacheService.kt @@ -16,8 +16,6 @@ package org.matrix.android.sdk.api.session.cache -import org.matrix.android.sdk.api.MatrixCallback - /** * This interface defines a method to clear the cache. It's implemented at the session level. */ @@ -26,5 +24,5 @@ interface CacheService { /** * Clear the whole cached data, except credentials. Once done, the sync has to be restarted by the sdk user. */ - fun clearCache(callback: MatrixCallback<Unit>) + suspend fun clearCache() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt index 4164b84ecdc38fdf47dab0436907999983fdff6a..98a84b8b662176a71685f37e52fd8cfe83e18d37 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt @@ -20,7 +20,7 @@ import android.net.Uri import android.os.Parcelable import androidx.exifinterface.media.ExifInterface import com.squareup.moshi.JsonClass -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.util.MimeTypes.normalizeMimeType @Parcelize diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index 0eefca1b4ce23c622c3b46cf9a1ba0f59c89bf1e..fa5ea359e8ff9ff7849bb91f5015fbdca97c10f1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -20,6 +20,7 @@ import android.content.Context import androidx.lifecycle.LiveData import androidx.paging.PagedList import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService @@ -53,7 +54,7 @@ interface CryptoService { fun setDeviceName(deviceId: String, deviceName: String, callback: MatrixCallback<Unit>) - fun deleteDevice(deviceId: String, callback: MatrixCallback<Unit>) + fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, callback: MatrixCallback<Unit>) fun deleteDeviceWithUserPassword(deviceId: String, authSession: String?, password: String, callback: MatrixCallback<Unit>) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt index 6a646cd4c717ce0a0ef1a2997e55b537a0e80434..359e33cc2c6bcad8a8be51faa74ae5b2eb0a66c9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt @@ -18,10 +18,10 @@ package org.matrix.android.sdk.api.session.crypto.crosssigning import androidx.lifecycle.LiveData import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustResult import org.matrix.android.sdk.internal.crypto.crosssigning.UserTrustResult -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo interface CrossSigningService { @@ -40,7 +40,7 @@ interface CrossSigningService { * Initialize cross signing for this user. * Users needs to enter credentials */ - fun initializeCrossSigning(authParams: UserPasswordAuth?, + fun initializeCrossSigning(uiaInterceptor: UserInteractiveAuthInterceptor?, callback: MatrixCallback<Unit>) fun isCrossSigningInitialized(): Boolean = getMyCrossSigningKeys() != null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/MediaService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/MediaService.kt index 9040ec7d5c53aab4027d7b5aba114c4dbe997a3d..3b3ef57d738da17fe793709884f74e825181886a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/MediaService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/MediaService.kt @@ -17,15 +17,16 @@ package org.matrix.android.sdk.api.session.media import org.matrix.android.sdk.api.cache.CacheStrategy -import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.util.JsonDict interface MediaService { /** - * Extract URLs from an Event. - * @return the list of URLs contains in the body of the Event. It does not mean that URLs in this list have UrlPreview data + * Extract URLs from a TimelineEvent. + * @param event TimelineEvent to extract the URL from. + * @return the list of URLs contains in the body of the TimelineEvent. It does not mean that URLs in this list have UrlPreview data */ - fun extractUrls(event: Event): List<String> + fun extractUrls(event: TimelineEvent): List<String> /** * Get Raw Url Preview data from the homeserver. There is no cache management for this request diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt index aefc086b4307d09c9e9f2d782185286935fb772d..ac1d726d0324eaafc7ba3f014e5f787c3bc51fab 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt @@ -25,7 +25,6 @@ interface PermalinkService { companion object { const val MATRIX_TO_URL_BASE = "https://matrix.to/#/" - const val MATRIX_TO_CUSTOM_SCHEME_URL_BASE = "element://" } /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt index 1fd83602531de42168737e119a3c8e1609a97fb5..a4d5b665c648f453056e68623db2408e817a1050 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt @@ -20,6 +20,7 @@ package org.matrix.android.sdk.api.session.profile import android.net.Uri import androidx.lifecycle.LiveData import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.JsonDict @@ -107,8 +108,7 @@ interface ProfileService { * Finalize adding a 3Pids. Call this method once the user has validated that he owns the ThreePid */ fun finalizeAddingThreePid(threePid: ThreePid, - uiaSession: String?, - accountPassword: String?, + userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, matrixCallback: MatrixCallback<Unit>): Cancelable /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt index 696b612389ea37eb5f8ca8cfe925e6042878a575..e778f5740ddff6e2ab5eae1b546715f75fa8fa22 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt @@ -25,28 +25,85 @@ import org.matrix.android.sdk.api.session.room.powerlevels.Role */ @JsonClass(generateAdapter = true) data class PowerLevelsContent( + /** + * The level required to ban a user. Defaults to 50 if unspecified. + */ @Json(name = "ban") val ban: Int = Role.Moderator.value, + /** + * The level required to kick a user. Defaults to 50 if unspecified. + */ @Json(name = "kick") val kick: Int = Role.Moderator.value, + /** + * The level required to invite a user. Defaults to 50 if unspecified. + */ @Json(name = "invite") val invite: Int = Role.Moderator.value, + /** + * The level required to redact an event. Defaults to 50 if unspecified. + */ @Json(name = "redact") val redact: Int = Role.Moderator.value, + /** + * The default level required to send message events. Can be overridden by the events key. Defaults to 0 if unspecified. + */ @Json(name = "events_default") val eventsDefault: Int = Role.Default.value, - @Json(name = "events") val events: MutableMap<String, Int> = HashMap(), + /** + * The level required to send specific event types. This is a mapping from event type to power level required. + */ + @Json(name = "events") val events: Map<String, Int> = emptyMap(), + /** + * The default power level for every user in the room, unless their user_id is mentioned in the users key. Defaults to 0 if unspecified. + */ @Json(name = "users_default") val usersDefault: Int = Role.Default.value, - @Json(name = "users") val users: MutableMap<String, Int> = HashMap(), + /** + * The power levels for specific users. This is a mapping from user_id to power level for that user. + */ + @Json(name = "users") val users: Map<String, Int> = emptyMap(), + /** + * The default level required to send state events. Can be overridden by the events key. Defaults to 50 if unspecified. + */ @Json(name = "state_default") val stateDefault: Int = Role.Moderator.value, - @Json(name = "notifications") val notifications: Map<String, Any> = HashMap() + /** + * The power level requirements for specific notification types. This is a mapping from key to power level for that notifications key. + */ + @Json(name = "notifications") val notifications: Map<String, Any> = emptyMap() ) { /** - * Alter this content with a new power level for the specified user + * Return a copy of this content with a new power level for the specified user * * @param userId the userId to alter the power level of * @param powerLevel the new power level, or null to set the default value. */ - fun setUserPowerLevel(userId: String, powerLevel: Int?) { - if (powerLevel == null || powerLevel == usersDefault) { - users.remove(userId) - } else { - users[userId] = powerLevel + fun setUserPowerLevel(userId: String, powerLevel: Int?): PowerLevelsContent { + return copy( + users = users.toMutableMap().apply { + if (powerLevel == null || powerLevel == usersDefault) { + remove(userId) + } else { + put(userId, powerLevel) + } + } + ) + } + + /** + * Get the notification level for a dedicated key. + * + * @param key the notification key + * @return the level, default to Moderator if the key is not found + */ + fun notificationLevel(key: String): Int { + return when (val value = notifications[key]) { + // the first implementation was a string value + is String -> value.toInt() + is Double -> value.toInt() + is Int -> value + else -> Role.Moderator.value } } + + companion object { + /** + * Key to use for content.notifications and get the level required to trigger an @room notification. Defaults to 50 if unspecified. + */ + const val NOTIFICATIONS_ROOM_KEY = "room" + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt index 00fa68c0ac444cd709d266d1f641380fc42d6787..280316d4b5208ee1280cbb5740d9826460b80b93 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt @@ -27,6 +27,7 @@ data class MessageStickerContent( /** * Set in local, not from server */ + @Transient override val msgType: String = MessageType.MSGTYPE_STICKER_LOCAL, /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt index 47922f6968414b10576c08c4b1d203dfaec7c887..4f1253c6df9d33936267145fef863bb0a36ea9de 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt @@ -108,19 +108,4 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) { val powerLevel = getUserPowerLevelValue(userId) return powerLevel >= powerLevelsContent.redact } - - /** - * Get the notification level for a dedicated key. - * - * @param key the notification key - * @return the level - */ - fun notificationLevel(key: String): Int { - return when (val value = powerLevelsContent.notifications[key]) { - // the first implementation was a string value - is String -> value.toInt() - is Int -> value - else -> Role.Moderator.value - } - } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt new file mode 100644 index 0000000000000000000000000000000000000000..c625a7f0885196a70085fab71ab14a2cceb61a35 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.room.state + +import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.RoomJoinRules +import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent + +/** + * Return true if a room can be joined by anyone (RoomJoinRules.PUBLIC) + */ +fun StateService.isPublic(): Boolean { + return getStateEvent(EventType.STATE_ROOM_JOIN_RULES, QueryStringValue.NoCondition) + ?.content + ?.toModel<RoomJoinRulesContent>() + ?.joinRules == RoomJoinRules.PUBLIC +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt index 73cb94b4175c3acf8c085bfc62f4dbe49b4b9995..b10fb540e112e44c8fb5917251661cb10d9e2dcd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt @@ -89,6 +89,17 @@ data class TimelineEvent( */ fun TimelineEvent.hasBeenEdited() = annotations?.editSummary != null +/** + * Get the latest known eventId for an edited event, or the eventId for an Event which has not been edited + */ +fun TimelineEvent.getLatestEventId(): String { + return annotations + ?.editSummary + ?.sourceEvents + ?.lastOrNull() + ?: eventId +} + /** * Get the relation content if any */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt index ebbbac527a9804e4a2ecebcb14a1950fb38f2000..4e4eba274e242cf076907dbe1c3db8d8385578fd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt @@ -16,9 +16,7 @@ package org.matrix.android.sdk.api.session.signout -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.auth.data.Credentials -import org.matrix.android.sdk.api.util.Cancelable /** * This interface defines a method to sign out, or to renew the token. It's implemented at the session level. @@ -29,19 +27,16 @@ interface SignOutService { * Ask the homeserver for a new access token. * The same deviceId will be used */ - fun signInAgain(password: String, - callback: MatrixCallback<Unit>): Cancelable + suspend fun signInAgain(password: String) /** * Update the session with credentials received after SSO */ - fun updateCredentials(credentials: Credentials, - callback: MatrixCallback<Unit>): Cancelable + suspend fun updateCredentials(credentials: Credentials) /** * Sign out, and release the session, clear all the session data, including crypto data * @param signOutFromHomeserver true if the sign out request has to be done */ - fun signOut(signOutFromHomeserver: Boolean, - callback: MatrixCallback<Unit>): Cancelable + suspend fun signOut(signOutFromHomeserver: Boolean) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/UrlExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/UrlExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..17f27b251491c227c80df9d2f398fc09a384f9ac --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/UrlExtensions.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.util + +import java.net.URLEncoder + +/** + * Append param and value to a Url, using "?" or "&". Value parameter will be encoded + * Return this for chaining purpose + */ +fun StringBuilder.appendParamToUrl(param: String, value: String): StringBuilder { + if (contains("?")) { + append("&") + } else { + append("?") + } + + append(param) + append("=") + append(URLEncoder.encode(value, "utf-8")) + + return this +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/Constants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt similarity index 62% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/Constants.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt index 7d18aba627c8e63922b26df72295c81360a4f996..e0c52cf9ca95a451b35c9703837846135e9fb435 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/Constants.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt @@ -14,25 +14,28 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.auth +package org.matrix.android.sdk.internal.auth /** * Path to use when the client does not supported any or all login flows * Ref: https://matrix.org/docs/spec/client_server/latest#login-fallback */ -const val LOGIN_FALLBACK_PATH = "/_matrix/static/client/login/" +internal const val LOGIN_FALLBACK_PATH = "/_matrix/static/client/login/" /** * Path to use when the client does not supported any or all registration flows * Not documented */ -const val REGISTER_FALLBACK_PATH = "/_matrix/static/client/register/" +internal const val REGISTER_FALLBACK_PATH = "/_matrix/static/client/register/" /** * Path to use when the client want to connect using SSO * Ref: https://matrix.org/docs/spec/client_server/latest#sso-client-login */ -const val SSO_REDIRECT_PATH = "/_matrix/client/r0/login/sso/redirect" -const val MSC2858_SSO_REDIRECT_PATH = "/_matrix/client/unstable/org.matrix.msc2858/login/sso/redirect" +internal const val SSO_REDIRECT_PATH = "/_matrix/client/r0/login/sso/redirect" +internal const val MSC2858_SSO_REDIRECT_PATH = "/_matrix/client/unstable/org.matrix.msc2858/login/sso/redirect" -const val SSO_REDIRECT_URL_PARAM = "redirectUrl" +internal const val SSO_REDIRECT_URL_PARAM = "redirectUrl" + +// Ref: https://matrix.org/docs/spec/client_server/r0.6.1#single-sign-on +internal const val SSO_UIA_FALLBACK_PATH = "/_matrix/client/r0/auth/m.login.sso/fallback/web" diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 55f053de8debcf084f74e0b325ed31e25dcce0de..c99e9bd81c88b1c314a1c5fa3abeae4b7cf233c0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.NoOpCancellable +import org.matrix.android.sdk.api.util.appendParamToUrl import org.matrix.android.sdk.internal.SessionManager import org.matrix.android.sdk.internal.auth.data.LoginFlowResponse import org.matrix.android.sdk.internal.auth.data.RiotConfig @@ -99,6 +100,52 @@ internal class DefaultAuthenticationService @Inject constructor( } } + override fun getSsoUrl(redirectUrl: String, deviceId: String?, providerId: String?): String? { + val homeServerUrlBase = getHomeServerUrlBase() ?: return null + + return buildString { + append(homeServerUrlBase) + if (providerId != null) { + append(MSC2858_SSO_REDIRECT_PATH) + append("/$providerId") + } else { + append(SSO_REDIRECT_PATH) + } + // Set the redirect url + appendParamToUrl(SSO_REDIRECT_URL_PARAM, redirectUrl) + deviceId?.takeIf { it.isNotBlank() }?.let { + // But https://github.com/matrix-org/synapse/issues/5755 + appendParamToUrl("device_id", it) + } + } + } + + override fun getFallbackUrl(forSignIn: Boolean, deviceId: String?): String? { + val homeServerUrlBase = getHomeServerUrlBase() ?: return null + + return buildString { + append(homeServerUrlBase) + if (forSignIn) { + append(LOGIN_FALLBACK_PATH) + deviceId?.takeIf { it.isNotBlank() }?.let { + // But https://github.com/matrix-org/synapse/issues/5755 + appendParamToUrl("device_id", it) + } + } else { + // For sign up + append(REGISTER_FALLBACK_PATH) + } + } + } + + private fun getHomeServerUrlBase(): String? { + return pendingSessionData + ?.homeServerConnectionConfig + ?.homeServerUri + ?.toString() + ?.trim { it == '/' } + } + override fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback<LoginFlowResult>): Cancelable { pendingSessionData = null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt index 2b26115f30da3f9f4a4ee9a53e4e2304b4e859c8..d0d17e2cd5378874e93335cfb0cf1392bbd59214 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt @@ -43,5 +43,6 @@ internal data class LoginFlow( * See MSC #2858 */ @Json(name = "org.matrix.msc2858.identity_providers") - val ssoIdentityProvider: List<SsoIdentityProvider>? + val ssoIdentityProvider: List<SsoIdentityProvider>? = null + ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt index 9c6b942a4fc6faed2c81a0de88319e9ad6cedea3..163009d9184866f1046a81c3275417a999588cb7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt @@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.registration.RegisterThreePid import org.matrix.android.sdk.api.auth.registration.RegistrationResult import org.matrix.android.sdk.api.auth.registration.RegistrationWizard +import org.matrix.android.sdk.api.auth.registration.toFlowResult import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.Failure.RegistrationFlowError import org.matrix.android.sdk.api.util.Cancelable diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt index 1e18887008b411fd000519b90a02193505534b54..5d119bb6177678fe6883903ba10411070b5f4739 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt @@ -17,7 +17,7 @@ package org.matrix.android.sdk.internal.auth.registration import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize /** * This class represent a localized privacy policy for registration Flow. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt new file mode 100644 index 0000000000000000000000000000000000000000..1a0383cb220a8d031d80aca9a54a4ce9eff9148b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.auth.registration + +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.api.failure.Failure +import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse +import org.matrix.android.sdk.api.auth.UIABaseAuth +import timber.log.Timber +import kotlin.coroutines.suspendCoroutine + +internal suspend fun handleUIA(failure: Throwable, interceptor: UserInteractiveAuthInterceptor, retryBlock: suspend (UIABaseAuth) -> Unit): Boolean { + Timber.d("## UIA: check error ${failure.message}") + val flowResponse = failure.toRegistrationFlowResponse() + ?: return false.also { + Timber.d("## UIA: not a UIA error") + } + + Timber.d("## UIA: error can be passed to interceptor") + Timber.d("## UIA: type = ${flowResponse.flows}") + + Timber.d("## UIA: delegate to interceptor...") + val authUpdate = try { + suspendCoroutine<UIABaseAuth> { continuation -> + interceptor.performStage(flowResponse, (failure as? Failure.ServerError)?.error?.code, continuation) + } + } catch (failure: Throwable) { + Timber.w(failure, "## UIA: failed to participate") + return false + } + + Timber.d("## UIA: updated auth $authUpdate") + return try { + retryBlock(authUpdate) + true + } catch (failure: Throwable) { + handleUIA(failure, interceptor, retryBlock) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CancelGossipRequestWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CancelGossipRequestWorker.kt index c2c81894fb3d53f75f82b5105b493918a77318f8..7e92ff3e88be724e182cee9b7cc5df99cc2e04ed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CancelGossipRequestWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CancelGossipRequestWorker.kt @@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.crypto import android.content.Context import androidx.work.WorkerParameters import com.squareup.moshi.JsonClass -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.failure.shouldBeRetried import org.matrix.android.sdk.api.session.events.model.Event @@ -60,7 +59,6 @@ internal class CancelGossipRequestWorker(context: Context, @Inject lateinit var sendToDeviceTask: SendToDeviceTask @Inject lateinit var cryptoStore: IMXCryptoStore - @Inject lateinit var eventBus: EventBus @Inject lateinit var credentials: Credentials override fun injectWith(injector: SessionComponent) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index ebd809f7774ee2375a61e4677a73a662cbf6f92d..678bc9819f12dc8bc2ba4d7be820b1d8e6481fb0 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -30,6 +30,7 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.NoOpMatrixCallback +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.crypto.MXCryptoConfig import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.failure.Failure @@ -207,9 +208,9 @@ internal class DefaultCryptoService @Inject constructor( .executeBy(taskExecutor) } - override fun deleteDevice(deviceId: String, callback: MatrixCallback<Unit>) { + override fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, callback: MatrixCallback<Unit>) { deleteDeviceTask - .configureWith(DeleteDeviceTask.Params(deviceId)) { + .configureWith(DeleteDeviceTask.Params(deviceId, userInteractiveAuthInterceptor, null)) { this.executionThread = TaskThread.CRYPTO this.callback = callback } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt index 4f94a27bbd9ed7814309bbcba711e94cdbe96c58..c075c90eb9f09718941be100bab94b54e4673015 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt @@ -32,6 +32,7 @@ import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import org.matrix.android.sdk.internal.crypto.model.rest.GossipingDefaultContent import org.matrix.android.sdk.internal.crypto.model.rest.GossipingToDeviceObject +import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.session.SessionScope @@ -206,34 +207,7 @@ internal class IncomingGossipingRequestManager @Inject constructor( Timber.v("## CRYPTO | GOSSIP processIncomingRoomKeyRequest from $userId:$deviceId for $roomId / ${body.sessionId} id ${request.requestId}") if (credentials.userId != userId) { - Timber.w("## CRYPTO | GOSSIP processReceivedGossipingRequests() : room key request from other user") - val senderKey = body.senderKey ?: return Unit - .also { Timber.w("missing senderKey") } - .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } - val sessionId = body.sessionId ?: return Unit - .also { Timber.w("missing sessionId") } - .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } - - if (alg != MXCRYPTO_ALGORITHM_MEGOLM) { - return Unit - .also { Timber.w("Only megolm is accepted here") } - .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } - } - - val roomEncryptor = roomEncryptorsStore.get(roomId) ?: return Unit - .also { Timber.w("no room Encryptor") } - .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } - - cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { - val isSuccess = roomEncryptor.reshareKey(sessionId, userId, deviceId, senderKey) - - if (isSuccess) { - cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTED) - } else { - cryptoStore.updateGossipingRequestState(request, GossipingRequestState.UNABLE_TO_PROCESS) - } - } - cryptoStore.updateGossipingRequestState(request, GossipingRequestState.RE_REQUESTED) + handleKeyRequestFromOtherUser(body, request, alg, roomId, userId, deviceId) return } // TODO: should we queue up requests we don't yet have keys for, in case they turn up later? @@ -291,6 +265,42 @@ internal class IncomingGossipingRequestManager @Inject constructor( onRoomKeyRequest(request) } + private fun handleKeyRequestFromOtherUser(body: RoomKeyRequestBody, + request: IncomingRoomKeyRequest, + alg: String, + roomId: String, + userId: String, + deviceId: String) { + Timber.w("## CRYPTO | GOSSIP processReceivedGossipingRequests() : room key request from other user") + val senderKey = body.senderKey ?: return Unit + .also { Timber.w("missing senderKey") } + .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } + val sessionId = body.sessionId ?: return Unit + .also { Timber.w("missing sessionId") } + .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } + + if (alg != MXCRYPTO_ALGORITHM_MEGOLM) { + return Unit + .also { Timber.w("Only megolm is accepted here") } + .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } + } + + val roomEncryptor = roomEncryptorsStore.get(roomId) ?: return Unit + .also { Timber.w("no room Encryptor") } + .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } + + cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { + val isSuccess = roomEncryptor.reshareKey(sessionId, userId, deviceId, senderKey) + + if (isSuccess) { + cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTED) + } else { + cryptoStore.updateGossipingRequestState(request, GossipingRequestState.UNABLE_TO_PROCESS) + } + } + cryptoStore.updateGossipingRequestState(request, GossipingRequestState.RE_REQUESTED) + } + private fun processIncomingSecretShareRequest(request: IncomingSecretShareRequest) { val secretName = request.secretName ?: return Unit.also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt index c952602d93f40517e352abbcda76bb1129579b51..b1e91e8d50760b84915b63237ed1773051035291 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt @@ -19,6 +19,8 @@ package org.matrix.android.sdk.internal.crypto import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.util.JSON_DICT_PARAMETERIZED_TYPE import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXOutboundSessionInfo +import org.matrix.android.sdk.internal.crypto.algorithms.megolm.SharedWithHelper import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2 import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper @@ -46,7 +48,7 @@ internal class MXOlmDevice @Inject constructor( */ private val store: IMXCryptoStore, private val inboundGroupSessionStore: InboundGroupSessionStore - ) { +) { /** * @return the Curve25519 key for the account. @@ -63,11 +65,15 @@ internal class MXOlmDevice @Inject constructor( // The OLM lib utility instance. private var olmUtility: OlmUtility? = null + private data class GroupSessionCacheItem( + val groupId: String, + val groupSession: OlmOutboundGroupSession + ) + // The outbound group session. - // They are not stored in 'store' to avoid to remember to which devices we sent the session key. - // Plus, in cryptography, it is good to refresh sessions from time to time. - // The key is the session id, the value the outbound group session. - private val outboundGroupSessionStore: MutableMap<String, OlmOutboundGroupSession> = HashMap() + // Caches active outbound session to avoid to sync with DB before read + // The key is the session id, the value the <roomID,outbound group session>. + private val outboundGroupSessionCache: MutableMap<String, GroupSessionCacheItem> = HashMap() // Store a set of decrypted message indexes for each group session. // This partially mitigates a replay attack where a MITM resends a group @@ -135,6 +141,10 @@ internal class MXOlmDevice @Inject constructor( */ fun release() { olmUtility?.releaseUtility() + outboundGroupSessionCache.values.forEach { + it.groupSession.releaseSession() + } + outboundGroupSessionCache.clear() } /** @@ -406,11 +416,12 @@ internal class MXOlmDevice @Inject constructor( * * @return the session id for the outbound session. */ - fun createOutboundGroupSession(): String? { + fun createOutboundGroupSessionForRoom(roomId: String): String? { var session: OlmOutboundGroupSession? = null try { session = OlmOutboundGroupSession() - outboundGroupSessionStore[session.sessionIdentifier()] = session + outboundGroupSessionCache[session.sessionIdentifier()] = GroupSessionCacheItem(roomId, session) + store.storeCurrentOutboundGroupSessionForRoom(roomId, session) return session.sessionIdentifier() } catch (e: Exception) { Timber.e(e, "createOutboundGroupSession") @@ -421,6 +432,39 @@ internal class MXOlmDevice @Inject constructor( return null } + fun storeOutboundGroupSessionForRoom(roomId: String, sessionId: String) { + outboundGroupSessionCache[sessionId]?.let { + store.storeCurrentOutboundGroupSessionForRoom(roomId, it.groupSession) + } + } + + fun restoreOutboundGroupSessionForRoom(roomId: String): MXOutboundSessionInfo? { + val restoredOutboundGroupSession = store.getCurrentOutboundGroupSessionForRoom(roomId) + if (restoredOutboundGroupSession != null) { + val sessionId = restoredOutboundGroupSession.outboundGroupSession.sessionIdentifier() + // cache it + outboundGroupSessionCache[sessionId] = GroupSessionCacheItem(roomId, restoredOutboundGroupSession.outboundGroupSession) + + return MXOutboundSessionInfo( + sessionId = sessionId, + sharedWithHelper = SharedWithHelper(roomId, sessionId, store), + restoredOutboundGroupSession.creationTime + ) + } + return null + } + + fun discardOutboundGroupSessionForRoom(roomId: String) { + val toDiscard = outboundGroupSessionCache.filter { + it.value.groupId == roomId + } + toDiscard.forEach { (sessionId, cacheItem) -> + cacheItem.groupSession.releaseSession() + outboundGroupSessionCache.remove(sessionId) + } + store.storeCurrentOutboundGroupSessionForRoom(roomId, null) + } + /** * Get the current session key of an outbound group session. * @@ -430,7 +474,7 @@ internal class MXOlmDevice @Inject constructor( fun getSessionKey(sessionId: String): String? { if (sessionId.isNotEmpty()) { try { - return outboundGroupSessionStore[sessionId]!!.sessionKey() + return outboundGroupSessionCache[sessionId]!!.groupSession.sessionKey() } catch (e: Exception) { Timber.e(e, "## getSessionKey() : failed") } @@ -446,7 +490,7 @@ internal class MXOlmDevice @Inject constructor( */ fun getMessageIndex(sessionId: String): Int { return if (sessionId.isNotEmpty()) { - outboundGroupSessionStore[sessionId]!!.messageIndex() + outboundGroupSessionCache[sessionId]!!.groupSession.messageIndex() } else 0 } @@ -460,7 +504,7 @@ internal class MXOlmDevice @Inject constructor( fun encryptGroupMessage(sessionId: String, payloadString: String): String? { if (sessionId.isNotEmpty() && payloadString.isNotEmpty()) { try { - return outboundGroupSessionStore[sessionId]!!.encryptMessage(payloadString) + return outboundGroupSessionCache[sessionId]!!.groupSession.encryptMessage(payloadString) } catch (e: Exception) { Timber.e(e, "## encryptGroupMessage() : failed") } @@ -747,7 +791,7 @@ internal class MXOlmDevice @Inject constructor( throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_SENDER_KEY, MXCryptoError.ERROR_MISSING_PROPERTY_REASON) } - val session = inboundGroupSessionStore.getInboundGroupSession(sessionId, senderKey) + val session = inboundGroupSessionStore.getInboundGroupSession(sessionId, senderKey) if (session != null) { // Check that the room id matches the original one for the session. This stops diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipRequestWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipRequestWorker.kt index 085469e9d99572ddf3d9a5ac975bdf32fcab9f63..e8d567b9441d7facade4f9dc09595a1a50162613 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipRequestWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipRequestWorker.kt @@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.crypto import android.content.Context import androidx.work.WorkerParameters import com.squareup.moshi.JsonClass -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.failure.shouldBeRetried import org.matrix.android.sdk.api.session.events.model.Event @@ -52,7 +51,6 @@ internal class SendGossipRequestWorker(context: Context, @Inject lateinit var sendToDeviceTask: SendToDeviceTask @Inject lateinit var cryptoStore: IMXCryptoStore - @Inject lateinit var eventBus: EventBus @Inject lateinit var credentials: Credentials override fun injectWith(injector: SessionComponent) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt index bcaa16f35637b524da116d45ab5052e2504200f6..8c680570562b5ac41a34c19100d92b646433a4cf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt @@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.crypto import android.content.Context import androidx.work.WorkerParameters import com.squareup.moshi.JsonClass -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.failure.shouldBeRetried import org.matrix.android.sdk.api.session.events.model.Event @@ -54,7 +53,6 @@ internal class SendGossipWorker(context: Context, @Inject lateinit var sendToDeviceTask: SendToDeviceTask @Inject lateinit var cryptoStore: IMXCryptoStore - @Inject lateinit var eventBus: EventBus @Inject lateinit var credentials: Credentials @Inject lateinit var messageEncrypter: MessageEncrypter @Inject lateinit var ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt index fd431ce735655ce1f79a9277b0aab09bf80e02bb..fa8acafb83fabd4dcaffb55b8018bc79a4da536d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt @@ -68,6 +68,10 @@ internal class MXMegolmEncryption( // case outboundSession.shareOperation will be non-null.) private var outboundSession: MXOutboundSessionInfo? = null + init { + // restore existing outbound session if any + outboundSession = olmDevice.restoreOutboundGroupSessionForRoom(roomId) + } // Default rotation periods // TODO: Make it configurable via parameters // Session rotation periods @@ -86,6 +90,9 @@ internal class MXMegolmEncryption( return encryptContent(outboundSession, eventType, eventContent) .also { notifyWithheldForSession(devices.withHeldDevices, outboundSession) + // annoyingly we have to serialize again the saved outbound session to store message index :/ + // if not we would see duplicate message index errors + olmDevice.storeOutboundGroupSessionForRoom(roomId, outboundSession.sessionId) } } @@ -107,6 +114,7 @@ internal class MXMegolmEncryption( override fun discardSessionKey() { outboundSession = null + olmDevice.discardOutboundGroupSessionForRoom(roomId) } /** @@ -116,7 +124,7 @@ internal class MXMegolmEncryption( */ private fun prepareNewSessionInRoom(): MXOutboundSessionInfo { Timber.v("## CRYPTO | prepareNewSessionInRoom() ") - val sessionId = olmDevice.createOutboundGroupSession() + val sessionId = olmDevice.createOutboundGroupSessionForRoom(roomId) val keysClaimedMap = HashMap<String, String>() keysClaimedMap["ed25519"] = olmDevice.deviceEd25519Key!! @@ -152,7 +160,7 @@ internal class MXMegolmEncryption( val deviceIds = devicesInRoom.getUserDeviceIds(userId) for (deviceId in deviceIds!!) { val deviceInfo = devicesInRoom.getObject(userId, deviceId) - if (deviceInfo != null && !cryptoStore.wasSessionSharedWithUser(roomId, safeSession.sessionId, userId, deviceId).found) { + if (deviceInfo != null && !cryptoStore.getSharedSessionInfo(roomId, safeSession.sessionId, userId, deviceId).found) { val devices = shareMap.getOrPut(userId) { ArrayList() } devices.add(deviceInfo) } @@ -401,11 +409,18 @@ internal class MXMegolmEncryption( .also { Timber.w("## Crypto reshareKey: Device not found") } // Get the chain index of the key we previously sent this device - val chainIndex = outboundSession?.sharedWithHelper?.wasSharedWith(userId, deviceId) ?: return false + val wasSessionSharedWithUser = cryptoStore.getSharedSessionInfo(roomId, sessionId, userId, deviceId) + if (!wasSessionSharedWithUser.found) { + // This session was never shared with this user + // Send a room key with held + notifyKeyWithHeld(listOf(UserDevice(userId, deviceId)), sessionId, senderKey, WithHeldCode.UNAUTHORISED) + Timber.w("## Crypto reshareKey: ERROR : Never shared megolm with this device") + return false + } + // if found chain index should not be null + val chainIndex = wasSessionSharedWithUser.chainIndex ?: return false .also { - // Send a room key with held - notifyKeyWithHeld(listOf(UserDevice(userId, deviceId)), sessionId, senderKey, WithHeldCode.UNAUTHORISED) - Timber.w("## Crypto reshareKey: ERROR : Never share megolm with this device") + Timber.w("## Crypto reshareKey: Null chain index") } val devicesByUser = mapOf(userId to listOf(deviceInfo)) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt index 9244b4d5e73069ad4c4ee60ebccefa21d88bce63..5a689378683b141bcd304e9b0cfee2eef70a8a8b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt @@ -23,9 +23,9 @@ import timber.log.Timber internal class MXOutboundSessionInfo( // The id of the session val sessionId: String, - val sharedWithHelper: SharedWithHelper) { - // When the session was created - private val creationTime = System.currentTimeMillis() + val sharedWithHelper: SharedWithHelper, + // When the session was created + private val creationTime: Long = System.currentTimeMillis()) { // Number of times this session has been used var useCount: Int = 0 diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt index 921f9b2cdc3831425e5852924d4af738e8e2ef87..f17168a6d22adb708647202484d55c6f50d396aa 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt @@ -28,10 +28,6 @@ internal class SharedWithHelper( return cryptoStore.getSharedWithInfo(roomId, sessionId) } - fun wasSharedWith(userId: String, deviceId: String): Int? { - return cryptoStore.wasSessionSharedWithUser(roomId, sessionId, userId, deviceId).chainIndex - } - fun markedSessionAsShared(userId: String, deviceId: String, chainIndex: Int) { cryptoStore.markedSessionAsShared(roomId, sessionId, userId, deviceId, chainIndex) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt index b77006aa3a9b9a1a1299aa0aa3fc8cd1ca251a96..c071384df4603cb08bdc5ed333591dbf89782bc9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.crypto.attachments import android.os.Parcelable import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize fun EncryptedFileInfo.toElementToDecrypt(): ElementToDecrypt? { // Check the validity of some fields diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt index bcad448eb6497928fd3b23e732a2444c19d9d7ba..9b282f0a84bd2235b15bc9415a3d5503891dd533 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt @@ -19,30 +19,30 @@ package org.matrix.android.sdk.internal.crypto.crosssigning import androidx.lifecycle.LiveData import androidx.work.BackoffPolicy import androidx.work.ExistingWorkPolicy +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.crypto.DeviceListManager +import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.UploadSignatureQueryBuilder -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo import org.matrix.android.sdk.internal.crypto.tasks.InitializeCrossSigningTask import org.matrix.android.sdk.internal.crypto.tasks.UploadSignaturesTask +import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.di.WorkManagerProvider import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.TaskThread import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.util.JsonCanonicalizer import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch -import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo -import org.matrix.android.sdk.internal.di.SessionId -import org.matrix.android.sdk.internal.di.WorkManagerProvider import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import org.matrix.olm.OlmPkSigning import org.matrix.olm.OlmUtility @@ -61,7 +61,10 @@ internal class DefaultCrossSigningService @Inject constructor( private val taskExecutor: TaskExecutor, private val coroutineDispatchers: MatrixCoroutineDispatchers, private val cryptoCoroutineScope: CoroutineScope, - private val workManagerProvider: WorkManagerProvider) : CrossSigningService, DeviceListManager.UserDevicesUpdateListener { + private val workManagerProvider: WorkManagerProvider, + private val updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository +) : CrossSigningService, + DeviceListManager.UserDevicesUpdateListener { private var olmUtility: OlmUtility? = null @@ -147,11 +150,11 @@ internal class DefaultCrossSigningService @Inject constructor( * - Sign the keys and upload them * - Sign the current device with SSK and sign MSK with device key (migration) and upload signatures */ - override fun initializeCrossSigning(authParams: UserPasswordAuth?, callback: MatrixCallback<Unit>) { + override fun initializeCrossSigning(uiaInterceptor: UserInteractiveAuthInterceptor?, callback: MatrixCallback<Unit>) { Timber.d("## CrossSigning initializeCrossSigning") val params = InitializeCrossSigningTask.Params( - authParams = authParams + interactiveAuthInterceptor = uiaInterceptor ) initializeCrossSigningTask.configureWith(params) { this.callbackThread = TaskThread.CRYPTO @@ -689,7 +692,7 @@ internal class DefaultCrossSigningService @Inject constructor( return DeviceTrustResult.Success(DeviceTrustLevel(crossSigningVerified = true, locallyVerified = locallyTrusted)) } - fun checkDeviceTrust(myKeys: MXCrossSigningInfo?, otherKeys: MXCrossSigningInfo?, otherDevice: CryptoDeviceInfo) : DeviceTrustResult { + fun checkDeviceTrust(myKeys: MXCrossSigningInfo?, otherKeys: MXCrossSigningInfo?, otherDevice: CryptoDeviceInfo): DeviceTrustResult { val locallyTrusted = otherDevice.trustLevel?.isLocallyVerified() myKeys ?: return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.CrossSigningNotConfigured(userId)) @@ -747,8 +750,11 @@ internal class DefaultCrossSigningService @Inject constructor( } override fun onUsersDeviceUpdate(userIds: List<String>) { - Timber.d("## CrossSigning - onUsersDeviceUpdate for $userIds") - val workerParams = UpdateTrustWorker.Params(sessionId = sessionId, updatedUserIds = userIds) + Timber.d("## CrossSigning - onUsersDeviceUpdate for ${userIds.size} users: $userIds") + val workerParams = UpdateTrustWorker.Params( + sessionId = sessionId, + filename = updateTrustWorkerDataRepository.createParam(userIds) + ) val workerData = WorkerParamsFactory.toData(workerParams) val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<UpdateTrustWorker>() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt index 665d770e7f69780469d55661c7538162878af49f..1660bae0b7f1bd5635943bf5705c2240713c1ed0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt @@ -55,7 +55,11 @@ internal class UpdateTrustWorker(context: Context, internal data class Params( override val sessionId: String, override val lastFailureMessage: String? = null, - val updatedUserIds: List<String> + // Kept for compatibility, but not used anymore (can be used for pending Worker) + val updatedUserIds: List<String>? = null, + // Passing a long list of userId can break the Work Manager due to data size limitation. + // so now we use a temporary file to store the data + val filename: String? = null ) : SessionWorkerParams @Inject lateinit var crossSigningService: DefaultCrossSigningService @@ -64,6 +68,7 @@ internal class UpdateTrustWorker(context: Context, @CryptoDatabase @Inject lateinit var realmConfiguration: RealmConfiguration @UserId @Inject lateinit var myUserId: String @Inject lateinit var crossSigningKeysMapper: CrossSigningKeysMapper + @Inject lateinit var updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository @SessionDatabase @Inject lateinit var sessionRealmConfiguration: RealmConfiguration // @Inject lateinit var roomSummaryUpdater: RoomSummaryUpdater @@ -74,7 +79,17 @@ internal class UpdateTrustWorker(context: Context, } override suspend fun doSafeWork(params: Params): Result { - var userList = params.updatedUserIds + var userList = params.filename + ?.let { updateTrustWorkerDataRepository.getParam(it) } + ?.userIds + ?: params.updatedUserIds.orEmpty() + + if (userList.isEmpty()) { + // This should not happen, but let's avoid go further in case of empty list + cleanup(params) + return Result.success() + } + // Unfortunately we don't have much info on what did exactly changed (is it the cross signing keys of that user, // or a new device?) So we check all again :/ @@ -213,9 +228,15 @@ internal class UpdateTrustWorker(context: Context, } } + cleanup(params) return Result.success() } + private fun cleanup(params: Params) { + params.filename + ?.let { updateTrustWorkerDataRepository.delete(it) } + } + private fun updateCrossSigningKeysTrust(realm: Realm, userId: String, verified: Boolean) { val xInfoEntity = realm.where(CrossSigningInfoEntity::class.java) .equalTo(CrossSigningInfoEntityFields.USER_ID, userId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorkerDataRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorkerDataRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..0878a9f7654d0d19b302d5f18bfb4e39db1f1a9e --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorkerDataRepository.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.crypto.crosssigning + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.internal.di.MoshiProvider +import org.matrix.android.sdk.internal.di.SessionFilesDirectory +import java.io.File +import java.util.UUID +import javax.inject.Inject + +@JsonClass(generateAdapter = true) +internal data class UpdateTrustWorkerData( + @Json(name = "userIds") + val userIds: List<String> +) + +internal class UpdateTrustWorkerDataRepository @Inject constructor( + @SessionFilesDirectory parentDir: File +) { + private val workingDirectory = File(parentDir, "tw") + private val jsonAdapter = MoshiProvider.providesMoshi().adapter(UpdateTrustWorkerData::class.java) + + // Return the path of the created file + fun createParam(userIds: List<String>): String { + val filename = "${UUID.randomUUID()}.json" + workingDirectory.mkdirs() + val file = File(workingDirectory, filename) + + UpdateTrustWorkerData(userIds = userIds) + .let { jsonAdapter.toJson(it) } + .let { file.writeText(it) } + + return filename + } + + fun getParam(filename: String): UpdateTrustWorkerData? { + return File(workingDirectory, filename) + .takeIf { it.exists() } + ?.readText() + ?.let { jsonAdapter.fromJson(it) } + } + + fun delete(filename: String) { + tryOrNull("Unable to delete $filename") { + File(workingDirectory, filename).delete() + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/CreateKeysBackupVersionTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/CreateKeysBackupVersionTask.kt index 36b667911d42492f8b0a40768f6ae60b51762a62..5c59cfd80e3215ae47e104f15e03548bc02bd6c5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/CreateKeysBackupVersionTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/CreateKeysBackupVersionTask.kt @@ -19,20 +19,20 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.CreateKeysBackupVersionBody import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface CreateKeysBackupVersionTask : Task<CreateKeysBackupVersionBody, KeysVersion> internal class DefaultCreateKeysBackupVersionTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : CreateKeysBackupVersionTask { override suspend fun execute(params: CreateKeysBackupVersionBody): KeysVersion { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.createKeysBackupVersion(params) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteBackupTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteBackupTask.kt index d174be20a2a99ee4adb56bd1945d69e4a01e1058..ec09da7240cc48a97116fa0cb71ea191613253c8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteBackupTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteBackupTask.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface DeleteBackupTask : Task<DeleteBackupTask.Params, Unit> { @@ -30,11 +30,11 @@ internal interface DeleteBackupTask : Task<DeleteBackupTask.Params, Unit> { internal class DefaultDeleteBackupTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : DeleteBackupTask { override suspend fun execute(params: DeleteBackupTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.deleteBackup(params.version) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionDataTask.kt index 6826596ba44788f04fe697a9f1e200a81e2eb48a..9c477efb7821e6af51e2bca87fec6621b545d267 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionDataTask.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface DeleteRoomSessionDataTask : Task<DeleteRoomSessionDataTask.Params, Unit> { @@ -32,11 +32,11 @@ internal interface DeleteRoomSessionDataTask : Task<DeleteRoomSessionDataTask.Pa internal class DefaultDeleteRoomSessionDataTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : DeleteRoomSessionDataTask { override suspend fun execute(params: DeleteRoomSessionDataTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.deleteRoomSessionData( params.roomId, params.sessionId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionsDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionsDataTask.kt index 5c9aacc1ac3f2f37d1c679a2a52bd6a3fb7cdb59..82d022f3abdb90478cfa620567bc5643721eb9d8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionsDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionsDataTask.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface DeleteRoomSessionsDataTask : Task<DeleteRoomSessionsDataTask.Params, Unit> { @@ -31,11 +31,11 @@ internal interface DeleteRoomSessionsDataTask : Task<DeleteRoomSessionsDataTask. internal class DefaultDeleteRoomSessionsDataTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : DeleteRoomSessionsDataTask { override suspend fun execute(params: DeleteRoomSessionsDataTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.deleteRoomSessionsData( params.roomId, params.version) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteSessionsDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteSessionsDataTask.kt index 3c9cab3fa07c92112bb4f3f238a5a6df06a87385..e4df379963db0a2864d13efba815acc3c6c4e303 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteSessionsDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteSessionsDataTask.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface DeleteSessionsDataTask : Task<DeleteSessionsDataTask.Params, Unit> { @@ -30,11 +30,11 @@ internal interface DeleteSessionsDataTask : Task<DeleteSessionsDataTask.Params, internal class DefaultDeleteSessionsDataTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : DeleteSessionsDataTask { override suspend fun execute(params: DeleteSessionsDataTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.deleteSessionsData(params.version) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetKeysBackupLastVersionTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetKeysBackupLastVersionTask.kt index 25f8f854483623a1e0e7d6acb1d75b9aafc683c1..3566ff0e6856832ac3346b81946e7016a512744a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetKeysBackupLastVersionTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetKeysBackupLastVersionTask.kt @@ -18,20 +18,20 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetKeysBackupLastVersionTask : Task<Unit, KeysVersionResult> internal class DefaultGetKeysBackupLastVersionTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetKeysBackupLastVersionTask { override suspend fun execute(params: Unit): KeysVersionResult { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.getKeysBackupLastVersion() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetKeysBackupVersionTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetKeysBackupVersionTask.kt index dd2dd70e4d2ae01bbc198a508f0a08c4fcbba87f..13c99fb0f4235a1278fdb23129e778e428b78858 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetKeysBackupVersionTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetKeysBackupVersionTask.kt @@ -18,20 +18,20 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetKeysBackupVersionTask : Task<String, KeysVersionResult> internal class DefaultGetKeysBackupVersionTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetKeysBackupVersionTask { override suspend fun execute(params: String): KeysVersionResult { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.getKeysBackupVersion(params) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionDataTask.kt index 8ca03491a1f2fe1c20d48b066269e5df1585ba90..168020d9cd233459645b4860a1a7887bd3fc682e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionDataTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeyBackupData +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetRoomSessionDataTask : Task<GetRoomSessionDataTask.Params, KeyBackupData> { @@ -33,11 +33,11 @@ internal interface GetRoomSessionDataTask : Task<GetRoomSessionDataTask.Params, internal class DefaultGetRoomSessionDataTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetRoomSessionDataTask { override suspend fun execute(params: GetRoomSessionDataTask.Params): KeyBackupData { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.getRoomSessionData( params.roomId, params.sessionId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt index d4c28418b55aab8057b107532b2bb2d15c6bc184..95d5ef2e53ffdee71a311236ba69ba81baa398d4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.RoomKeysBackupData +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetRoomSessionsDataTask : Task<GetRoomSessionsDataTask.Params, RoomKeysBackupData> { @@ -32,11 +32,11 @@ internal interface GetRoomSessionsDataTask : Task<GetRoomSessionsDataTask.Params internal class DefaultGetRoomSessionsDataTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetRoomSessionsDataTask { override suspend fun execute(params: GetRoomSessionsDataTask.Params): RoomKeysBackupData { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.getRoomSessionsData( params.roomId, params.version) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetSessionsDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetSessionsDataTask.kt index c5df82b5aedb53e6e3a10d7a160308b1eed12e6c..e41a13e3eb258df56fe922c83794642020ab1c98 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetSessionsDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetSessionsDataTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetSessionsDataTask : Task<GetSessionsDataTask.Params, KeysBackupData> { @@ -31,11 +31,11 @@ internal interface GetSessionsDataTask : Task<GetSessionsDataTask.Params, KeysBa internal class DefaultGetSessionsDataTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetSessionsDataTask { override suspend fun execute(params: GetSessionsDataTask.Params): KeysBackupData { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.getSessionsData(params.version) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionDataTask.kt index 588a861a8af54bb26a1fe24d629e885ce9597dd2..3954277e3925d75c88d90b31697aa2c5c4d50080 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionDataTask.kt @@ -19,9 +19,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeyBackupData +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface StoreRoomSessionDataTask : Task<StoreRoomSessionDataTask.Params, BackupKeysResult> { @@ -35,11 +35,11 @@ internal interface StoreRoomSessionDataTask : Task<StoreRoomSessionDataTask.Para internal class DefaultStoreRoomSessionDataTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : StoreRoomSessionDataTask { override suspend fun execute(params: StoreRoomSessionDataTask.Params): BackupKeysResult { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.storeRoomSessionData( params.roomId, params.sessionId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionsDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionsDataTask.kt index b77e31e3878479730cdb33745d98d3c402add73e..4e209b4abc4f6eb0d9aca677cd9803be1c8c5112 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionsDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionsDataTask.kt @@ -19,9 +19,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.RoomKeysBackupData +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface StoreRoomSessionsDataTask : Task<StoreRoomSessionsDataTask.Params, BackupKeysResult> { @@ -34,11 +34,11 @@ internal interface StoreRoomSessionsDataTask : Task<StoreRoomSessionsDataTask.Pa internal class DefaultStoreRoomSessionsDataTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : StoreRoomSessionsDataTask { override suspend fun execute(params: StoreRoomSessionsDataTask.Params): BackupKeysResult { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.storeRoomSessionsData( params.roomId, params.version, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreSessionsDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreSessionsDataTask.kt index 3a8198073ee66236f7b2ff4a1dd4704adab9e544..a607477d21712a6369428d2927cf236b4cc342d0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreSessionsDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreSessionsDataTask.kt @@ -19,9 +19,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface StoreSessionsDataTask : Task<StoreSessionsDataTask.Params, BackupKeysResult> { @@ -33,11 +33,11 @@ internal interface StoreSessionsDataTask : Task<StoreSessionsDataTask.Params, Ba internal class DefaultStoreSessionsDataTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : StoreSessionsDataTask { override suspend fun execute(params: StoreSessionsDataTask.Params): BackupKeysResult { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.storeSessionsData( params.version, params.keysBackupData) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/UpdateKeysBackupVersionTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/UpdateKeysBackupVersionTask.kt index 50726c66ac0a83308861ca65e0fbf029bf1552ae..f012cd13ebd48ce1e1dda4d19b6988a93ddf905a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/UpdateKeysBackupVersionTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/UpdateKeysBackupVersionTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.tasks import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.UpdateKeysBackupVersionBody +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface UpdateKeysBackupVersionTask : Task<UpdateKeysBackupVersionTask.Params, Unit> { @@ -32,11 +32,11 @@ internal interface UpdateKeysBackupVersionTask : Task<UpdateKeysBackupVersionTas internal class DefaultUpdateKeysBackupVersionTask @Inject constructor( private val roomKeysApi: RoomKeysApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : UpdateKeysBackupVersionTask { override suspend fun execute(params: UpdateKeysBackupVersionTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomKeysApi.updateKeysBackupVersion(params.version, params.keysBackupVersionBody) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/SessionAssistedInjectModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OutboundGroupSessionWrapper.kt similarity index 65% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/SessionAssistedInjectModule.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OutboundGroupSessionWrapper.kt index da3ecfb907818821050770754057424fd2fdff38..b616284e14a93c2bac4e08ae9effea6f0fca8886 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/SessionAssistedInjectModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OutboundGroupSessionWrapper.kt @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.di +package org.matrix.android.sdk.internal.crypto.model -import com.squareup.inject.assisted.dagger2.AssistedModule -import dagger.Module +import org.matrix.olm.OlmOutboundGroupSession -@AssistedModule -@Module(includes = [AssistedInject_SessionAssistedInjectModule::class]) -interface SessionAssistedInjectModule +data class OutboundGroupSessionWrapper( + val outboundGroupSession: OlmOutboundGroupSession, + val creationTime: Long +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DefaultBaseAuth.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DefaultBaseAuth.kt new file mode 100644 index 0000000000000000000000000000000000000000..bbb4a3a654844487b330858c8cf7054d15b76388 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DefaultBaseAuth.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.crypto.model.rest + +import org.matrix.android.sdk.api.auth.UIABaseAuth + +data class DefaultBaseAuth( + /** + * This is a session identifier that the client must pass back to the homeserver, + * if one is provided, in subsequent attempts to authenticate in the same API call. + */ + override val session: String? = null + +) : UIABaseAuth { + override fun hasAuthInfo() = true + + override fun copyWithSession(session: String) = this.copy(session = session) + + override fun asMap(): Map<String, *> = mapOf("session" to session) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeleteDeviceParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeleteDeviceParams.kt index 0ce6f1f41cf515d5bc7efd35d08f31e84e6784b3..f636ab890d92224cfa236e658cf281fe3401d5a8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeleteDeviceParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeleteDeviceParams.kt @@ -24,5 +24,5 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class DeleteDeviceParams( @Json(name = "auth") - val userPasswordAuth: UserPasswordAuth? = null + val auth: Map<String, *>? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UploadSigningKeysBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UploadSigningKeysBody.kt index 3418bb327de22da4cedad79417a36e860b0a068b..d24b7ae5f0d26761ec4092cf8f95f15676ee28e0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UploadSigningKeysBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UploadSigningKeysBody.kt @@ -30,5 +30,5 @@ internal data class UploadSigningKeysBody( val userSigningKey: RestKeyInfo? = null, @Json(name = "auth") - val auth: UserPasswordAuth? = null + val auth: Map<String, *>? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt index 9a9f645b49be7025bd4435beed01abb01c23cef5..6f1487f80a46da8694bff3ea046b2dab37fe6709 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt @@ -33,11 +33,13 @@ import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2 import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper +import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyWithHeldContent import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity import org.matrix.olm.OlmAccount +import org.matrix.olm.OlmOutboundGroupSession /** * the crypto data store @@ -293,6 +295,16 @@ internal interface IMXCryptoStore { */ fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper2? + /** + * Get the current outbound group session for this encrypted room + */ + fun getCurrentOutboundGroupSessionForRoom(roomId: String): OutboundGroupSessionWrapper? + + /** + * Get the current outbound group session for this encrypted room + */ + fun storeCurrentOutboundGroupSessionForRoom(roomId: String, outboundGroupSession: OlmOutboundGroupSession?) + /** * Remove an inbound group session * @@ -439,7 +451,15 @@ internal interface IMXCryptoStore { fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent? fun markedSessionAsShared(roomId: String?, sessionId: String, userId: String, deviceId: String, chainIndex: Int) - fun wasSessionSharedWithUser(roomId: String?, sessionId: String, userId: String, deviceId: String): SharedSessionResult + + /** + * Query for information on this session sharing history. + * @return SharedSessionResult + * if found is true then this session was initialy shared with that user|device, + * in this case chainIndex is not nullindicates the ratchet position. + * In found is false, chainIndex is null + */ + fun getSharedSessionInfo(roomId: String?, sessionId: String, userId: String, deviceId: String): SharedSessionResult data class SharedSessionResult(val found: Boolean, val chainIndex: Int?) fun getSharedWithInfo(roomId: String?, sessionId: String): MXUsersDevicesMap<Int> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index 6b83c4f7d1ba801a84881c7a5dae4b12cbe18318..369a4976c9683a7799f8809e44584a8896bfe97c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -47,6 +47,7 @@ import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2 import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper +import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyWithHeldContent import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody @@ -73,6 +74,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSess import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields +import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntity import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntity import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity @@ -95,6 +97,7 @@ import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.olm.OlmAccount import org.matrix.olm.OlmException +import org.matrix.olm.OlmOutboundGroupSession import timber.log.Timber import javax.inject.Inject import kotlin.collections.set @@ -756,6 +759,42 @@ internal class RealmCryptoStore @Inject constructor( return inboundGroupSessionToRelease[key] } + override fun getCurrentOutboundGroupSessionForRoom(roomId: String): OutboundGroupSessionWrapper? { + return doWithRealm(realmConfiguration) { realm -> + realm.where<CryptoRoomEntity>() + .equalTo(CryptoRoomEntityFields.ROOM_ID, roomId) + .findFirst()?.outboundSessionInfo?.let { entity -> + entity.getOutboundGroupSession()?.let { + OutboundGroupSessionWrapper( + it, + entity.creationTime ?: 0 + ) + } + } + } + } + + override fun storeCurrentOutboundGroupSessionForRoom(roomId: String, outboundGroupSession: OlmOutboundGroupSession?) { + // we can do this async, as it's just for restoring on next launch + // the olmdevice is caching the active instance + // this is called for each sent message (so not high frequency), thus we can use basic realm async without + // risk of reaching max async operation limit? + doRealmTransactionAsync(realmConfiguration) { realm -> + CryptoRoomEntity.getById(realm, roomId)?.let { entity -> + // we should delete existing outbound session info if any + entity.outboundSessionInfo?.deleteFromRealm() + + if (outboundGroupSession != null) { + val info = realm.createObject(OutboundGroupSessionInfoEntity::class.java).apply { + creationTime = System.currentTimeMillis() + putOutboundGroupSession(outboundGroupSession) + } + entity.outboundSessionInfo = info + } + } + } + } + /** * Note: the result will be only use to export all the keys and not to use the OlmInboundGroupSessionWrapper2, * so there is no need to use or update `inboundGroupSessionToRelease` for native memory management @@ -1645,7 +1684,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun wasSessionSharedWithUser(roomId: String?, sessionId: String, userId: String, deviceId: String): IMXCryptoStore.SharedSessionResult { + override fun getSharedSessionInfo(roomId: String?, sessionId: String, userId: String, deviceId: String): IMXCryptoStore.SharedSessionResult { return doWithRealm(realmConfiguration) { realm -> SharedSessionEntity.get(realm, roomId, sessionId, userId, deviceId)?.let { IMXCryptoStore.SharedSessionResult(true, it.chainIndex) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt index 08806b0627de75a22b120b10b2ce60302d969b0c..bca79143885373c71a286b2b5cd5c276551a1b39 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -44,6 +44,7 @@ import org.matrix.android.sdk.internal.di.SerializeNulls import io.realm.DynamicRealm import io.realm.RealmMigration import io.realm.RealmObjectSchema +import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields import org.matrix.androidsdk.crypto.data.MXOlmInboundGroupSession2 import timber.log.Timber import javax.inject.Inject @@ -55,7 +56,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi // 0, 1, 2: legacy Riot-Android // 3: migrate to RiotX schema // 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6) - const val CRYPTO_STORE_SCHEMA_VERSION = 11L + const val CRYPTO_STORE_SCHEMA_VERSION = 12L } private fun RealmObjectSchema.addFieldIfNotExists(fieldName: String, fieldType: Class<*>): RealmObjectSchema { @@ -93,6 +94,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi if (oldVersion <= 8) migrateTo9(realm) if (oldVersion <= 9) migrateTo10(realm) if (oldVersion <= 10) migrateTo11(realm) + if (oldVersion <= 11) migrateTo12(realm) } private fun migrateTo1Legacy(realm: DynamicRealm) { @@ -483,4 +485,16 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi realm.schema.get("CryptoMetadataEntity") ?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java) } + + // Version 12L added outbound group session persistence + private fun migrateTo12(realm: DynamicRealm) { + Timber.d("Step 11 -> 12") + val outboundEntitySchema = realm.schema.create("OutboundGroupSessionInfoEntity") + .addField(OutboundGroupSessionInfoEntityFields.SERIALIZED_OUTBOUND_SESSION_DATA, String::class.java) + .addField(OutboundGroupSessionInfoEntityFields.CREATION_TIME, Long::class.java) + .setNullable(OutboundGroupSessionInfoEntityFields.CREATION_TIME, true) + + realm.schema.get("CryptoRoomEntity") + ?.addRealmObjectField(CryptoRoomEntityFields.OUTBOUND_SESSION_INFO.`$`, outboundEntitySchema) + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreModule.kt index a453fc3ed00db028e546491b4752f999f0f3654f..6aae68c83eeb3a533daded01446f3a0518228a90 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreModule.kt @@ -33,6 +33,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntity import io.realm.annotations.RealmModule +import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntity /** * Realm module for Crypto store classes @@ -54,6 +55,7 @@ import io.realm.annotations.RealmModule OutgoingGossipingRequestEntity::class, MyDeviceLastSeenInfoEntity::class, WithHeldSessionEntity::class, - SharedSessionEntity::class + SharedSessionEntity::class, + OutboundGroupSessionInfoEntity::class ]) internal class RealmCryptoStoreModule diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt index 4c19b5eb0ea610c7c208fda7d1519e4a5caa9d02..e226f3eaa8f8838c1c78cd46a82d9448cc90663a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt @@ -23,7 +23,12 @@ internal open class CryptoRoomEntity( @PrimaryKey var roomId: String? = null, var algorithm: String? = null, var shouldEncryptForInvitedMembers: Boolean? = null, - var blacklistUnverifiedDevices: Boolean = false) + var blacklistUnverifiedDevices: Boolean = false, + // Store the current outbound session for this room, + // to avoid re-create and re-share at each startup (if rotation not needed..) + // This is specific to megolm but not sure how to model it better + var outboundSessionInfo: OutboundGroupSessionInfoEntity? = null + ) : RealmObject() { companion object diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutboundGroupSessionInfoEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutboundGroupSessionInfoEntity.kt new file mode 100644 index 0000000000000000000000000000000000000000..d50db78415dad5128b9d85b1f0d4cd92915e91d0 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutboundGroupSessionInfoEntity.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.crypto.store.db.model + +import io.realm.RealmObject +import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm +import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm +import org.matrix.olm.OlmOutboundGroupSession +import timber.log.Timber + +internal open class OutboundGroupSessionInfoEntity( + var serializedOutboundSessionData: String? = null, + var creationTime: Long? = null +) : RealmObject() { + + fun getOutboundGroupSession(): OlmOutboundGroupSession? { + return try { + deserializeFromRealm(serializedOutboundSessionData) + } catch (failure: Throwable) { + Timber.e(failure, "## getOutboundGroupSession() Deserialization failure") + return null + } + } + + fun putOutboundGroupSession(olmOutboundGroupSession: OlmOutboundGroupSession?) { + serializedOutboundSessionData = serializeForRealm(olmOutboundGroupSession) + } + + companion object +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/ClaimOneTimeKeysForUsersDeviceTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/ClaimOneTimeKeysForUsersDeviceTask.kt index ae72c7198a48d24ff98c43321be5cd9e3413770e..3df6312adb63663c9f12e12f5579d9aed0d71812 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/ClaimOneTimeKeysForUsersDeviceTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/ClaimOneTimeKeysForUsersDeviceTask.kt @@ -21,9 +21,9 @@ import org.matrix.android.sdk.internal.crypto.model.MXKey import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimBody import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimResponse +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import timber.log.Timber import javax.inject.Inject @@ -36,13 +36,13 @@ internal interface ClaimOneTimeKeysForUsersDeviceTask : Task<ClaimOneTimeKeysFor internal class DefaultClaimOneTimeKeysForUsersDevice @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : ClaimOneTimeKeysForUsersDeviceTask { override suspend fun execute(params: ClaimOneTimeKeysForUsersDeviceTask.Params): MXUsersDevicesMap<MXKey> { val body = KeysClaimBody(oneTimeKeys = params.usersDevicesKeyTypesMap.map) - val keysClaimResponse = executeRequest<KeysClaimResponse>(eventBus) { + val keysClaimResponse = executeRequest<KeysClaimResponse>(globalErrorReceiver) { apiCall = cryptoApi.claimOneTimeKeysForUsersDevices(body) } val map = MXUsersDevicesMap<MXKey>() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt index e5078d5b4e3d223f54aeb6edd033589d8ebeda3b..ff25ac0f66d16e5d0021ba92a766f82833bbe234 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt @@ -16,35 +16,44 @@ package org.matrix.android.sdk.internal.crypto.tasks -import org.matrix.android.sdk.api.failure.Failure -import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.internal.auth.registration.handleUIA import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.rest.DeleteDeviceParams +import org.matrix.android.sdk.api.auth.UIABaseAuth +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus +import timber.log.Timber import javax.inject.Inject internal interface DeleteDeviceTask : Task<DeleteDeviceTask.Params, Unit> { data class Params( - val deviceId: String + val deviceId: String, + val userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor?, + val userAuthParam: UIABaseAuth? ) } internal class DefaultDeleteDeviceTask @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : DeleteDeviceTask { override suspend fun execute(params: DeleteDeviceTask.Params) { try { - executeRequest<Unit>(eventBus) { - apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams()) + executeRequest<Unit>(globalErrorReceiver) { + apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams(params.userAuthParam?.asMap())) } } catch (throwable: Throwable) { - throw throwable.toRegistrationFlowResponse() - ?.let { Failure.RegistrationFlowError(it) } - ?: throwable + if (params.userInteractiveAuthInterceptor == null + || !handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth -> + execute(params.copy(userAuthParam = auth)) + } + ) { + Timber.d("## UIA: propagate failure") + throw throwable + } } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt index 38eee7f932076cfade423958ea7e0d4d4ccecf46..dc0077425ed58b6cf89650fc54ca13677cce5e3d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt @@ -19,11 +19,11 @@ package org.matrix.android.sdk.internal.crypto.tasks import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.rest.DeleteDeviceParams -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth +import org.matrix.android.sdk.api.auth.UserPasswordAuth import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface DeleteDeviceWithUserPasswordTask : Task<DeleteDeviceWithUserPasswordTask.Params, Unit> { @@ -37,19 +37,19 @@ internal interface DeleteDeviceWithUserPasswordTask : Task<DeleteDeviceWithUserP internal class DefaultDeleteDeviceWithUserPasswordTask @Inject constructor( private val cryptoApi: CryptoApi, @UserId private val userId: String, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : DeleteDeviceWithUserPasswordTask { override suspend fun execute(params: DeleteDeviceWithUserPasswordTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams( - userPasswordAuth = UserPasswordAuth( + auth = UserPasswordAuth( type = LoginFlowTypes.PASSWORD, session = params.authSession, user = userId, password = params.password - ) + ).asMap() ) ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DownloadKeysForUsersTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DownloadKeysForUsersTask.kt index 7268c48113a082e28d7e482780402d43415616ef..5eb24b116ad00b2073ff065d046ef92c915b34df 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DownloadKeysForUsersTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DownloadKeysForUsersTask.kt @@ -19,9 +19,9 @@ package org.matrix.android.sdk.internal.crypto.tasks import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryBody import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface DownloadKeysForUsersTask : Task<DownloadKeysForUsersTask.Params, KeysQueryResponse> { @@ -35,7 +35,7 @@ internal interface DownloadKeysForUsersTask : Task<DownloadKeysForUsersTask.Para internal class DefaultDownloadKeysForUsers @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : DownloadKeysForUsersTask { override suspend fun execute(params: DownloadKeysForUsersTask.Params): KeysQueryResponse { @@ -46,7 +46,7 @@ internal class DefaultDownloadKeysForUsers @Inject constructor( token = params.token?.takeIf { it.isNotEmpty() } ) - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = cryptoApi.downloadKeysForUsers(body) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetDeviceInfoTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetDeviceInfoTask.kt index 6bd69c6a0743815b99d5f2900b8cd6cdb0e70298..5f6d2e344fc30871cc4f89ec61b863e51d10509f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetDeviceInfoTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetDeviceInfoTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.crypto.tasks import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetDeviceInfoTask : Task<GetDeviceInfoTask.Params, DeviceInfo> { @@ -29,11 +29,11 @@ internal interface GetDeviceInfoTask : Task<GetDeviceInfoTask.Params, DeviceInfo internal class DefaultGetDeviceInfoTask @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetDeviceInfoTask { override suspend fun execute(params: GetDeviceInfoTask.Params): DeviceInfo { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = cryptoApi.getDeviceInfo(params.deviceId) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetDevicesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetDevicesTask.kt index 731e1ca0312263dff938d88fd48559849a13e3f4..ea33a918bcf9ec91916a0335bdd6234ba0611b5f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetDevicesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetDevicesTask.kt @@ -18,20 +18,20 @@ package org.matrix.android.sdk.internal.crypto.tasks import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetDevicesTask : Task<Unit, DevicesListResponse> internal class DefaultGetDevicesTask @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetDevicesTask { override suspend fun execute(params: Unit): DevicesListResponse { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = cryptoApi.getDevices() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetKeyChangesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetKeyChangesTask.kt index 289a5226f58218d463b8a2202bf115dcc8b3a433..4cc9ab2fcb3cec2b27f38297f33463654a86611d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetKeyChangesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/GetKeyChangesTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.crypto.tasks import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.rest.KeyChangesResponse +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetKeyChangesTask : Task<GetKeyChangesTask.Params, KeyChangesResponse> { @@ -34,11 +34,11 @@ internal interface GetKeyChangesTask : Task<GetKeyChangesTask.Params, KeyChanges internal class DefaultGetKeyChangesTask @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetKeyChangesTask { override suspend fun execute(params: GetKeyChangesTask.Params): KeyChangesResponse { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = cryptoApi.getKeyChanges(params.from, params.to) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt index 6c0a76fa7d3bebc9a9f2434bf12b027d530229d5..ef31130f55c48f862f2502b1baeb26735ed1e683 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt @@ -17,6 +17,8 @@ package org.matrix.android.sdk.internal.crypto.tasks import dagger.Lazy +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.internal.auth.registration.handleUIA import org.matrix.android.sdk.internal.crypto.MXOlmDevice import org.matrix.android.sdk.internal.crypto.MyDeviceInfoHolder import org.matrix.android.sdk.internal.crypto.crosssigning.canonicalSignable @@ -24,7 +26,6 @@ import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding import org.matrix.android.sdk.internal.crypto.model.CryptoCrossSigningKey import org.matrix.android.sdk.internal.crypto.model.KeyUsage import org.matrix.android.sdk.internal.crypto.model.rest.UploadSignatureQueryBuilder -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.JsonCanonicalizer @@ -34,7 +35,7 @@ import javax.inject.Inject internal interface InitializeCrossSigningTask : Task<InitializeCrossSigningTask.Params, InitializeCrossSigningTask.Result> { data class Params( - val authParams: UserPasswordAuth? + val interactiveAuthInterceptor: UserInteractiveAuthInterceptor? ) data class Result( @@ -117,10 +118,21 @@ internal class DefaultInitializeCrossSigningTask @Inject constructor( .key(sskPublicKey) .signature(userId, masterPublicKey, signedSSK) .build(), - userPasswordAuth = params.authParams + userAuthParam = null +// userAuthParam = params.authParams ) - uploadSigningKeysTask.execute(uploadSigningKeysParams) + try { + uploadSigningKeysTask.execute(uploadSigningKeysParams) + } catch (failure: Throwable) { + if (params.interactiveAuthInterceptor == null + || !handleUIA(failure, params.interactiveAuthInterceptor) { authUpdate -> + uploadSigningKeysTask.execute(uploadSigningKeysParams.copy(userAuthParam = authUpdate)) + }) { + Timber.d("## UIA: propagate failure") + throw failure + } + } // Sign the current device with SSK val uploadSignatureQueryBuilder = UploadSignatureQueryBuilder() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt index f35d1b63e8fb772be348ec4e09d932c964b56872..5226e52b33f2daaf7fe6b0bce5e8e0b2927e43d1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt @@ -15,7 +15,7 @@ */ package org.matrix.android.sdk.internal.crypto.tasks -import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.session.room.send.SendResponse @@ -33,10 +33,10 @@ internal interface RedactEventTask : Task<RedactEventTask.Params, String> { internal class DefaultRedactEventTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus) : RedactEventTask { + private val globalErrorReceiver: GlobalErrorReceiver) : RedactEventTask { override suspend fun execute(params: RedactEventTask.Params): String { - val executeRequest = executeRequest<SendResponse>(eventBus) { + val executeRequest = executeRequest<SendResponse>(globalErrorReceiver) { apiCall = roomAPI.redactEvent( txId = params.txID, roomId = params.roomId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt index 8b739c4b64ba2f12cb9fe9025c19277b5009d254..b772bfbce227e365833162ee89f097d88613f6f9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt @@ -15,11 +15,12 @@ */ package org.matrix.android.sdk.internal.crypto.tasks -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.send.SendState +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI +import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository import org.matrix.android.sdk.internal.session.room.send.SendResponse import org.matrix.android.sdk.internal.task.Task @@ -35,16 +36,24 @@ internal interface SendEventTask : Task<SendEventTask.Params, String> { internal class DefaultSendEventTask @Inject constructor( private val localEchoRepository: LocalEchoRepository, private val encryptEventTask: DefaultEncryptEventTask, + private val loadRoomMembersTask: LoadRoomMembersTask, private val roomAPI: RoomAPI, - private val eventBus: EventBus) : SendEventTask { + private val globalErrorReceiver: GlobalErrorReceiver) : SendEventTask { override suspend fun execute(params: SendEventTask.Params): String { try { + // Make sure to load all members in the room before sending the event. + params.event.roomId + ?.takeIf { params.encrypt } + ?.let { roomId -> + loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId)) + } + val event = handleEncryption(params) val localId = event.eventId!! localEchoRepository.updateSendState(localId, params.event.roomId, SendState.SENDING) - val executeRequest = executeRequest<SendResponse>(eventBus) { + val executeRequest = executeRequest<SendResponse>(globalErrorReceiver) { apiCall = roomAPI.send( localId, roomId = event.roomId ?: "", diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendToDeviceTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendToDeviceTask.kt index 37e0bbc887c92468b54a2497cafaa7515627b8a5..d2af91601b49a994ae4de8ed37a9e7480465ee18 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendToDeviceTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendToDeviceTask.kt @@ -19,9 +19,9 @@ package org.matrix.android.sdk.internal.crypto.tasks import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.crypto.model.rest.SendToDeviceBody +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject import kotlin.random.Random @@ -38,7 +38,7 @@ internal interface SendToDeviceTask : Task<SendToDeviceTask.Params, Unit> { internal class DefaultSendToDeviceTask @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SendToDeviceTask { override suspend fun execute(params: SendToDeviceTask.Params) { @@ -46,7 +46,7 @@ internal class DefaultSendToDeviceTask @Inject constructor( messages = params.contentMap.map ) - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = cryptoApi.sendToDevice( params.eventType, params.transactionId ?: Random.nextInt(Integer.MAX_VALUE).toString(), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt index cedb7a6618aecb8313a86f16d1bb0715e4443905..c39dfb101668ed56ad6ace386a61395ac36de769 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt @@ -15,10 +15,10 @@ */ package org.matrix.android.sdk.internal.crypto.tasks -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository @@ -37,7 +37,7 @@ internal class DefaultSendVerificationMessageTask @Inject constructor( private val encryptEventTask: DefaultEncryptEventTask, private val roomAPI: RoomAPI, private val cryptoSessionInfoProvider: CryptoSessionInfoProvider, - private val eventBus: EventBus) : SendVerificationMessageTask { + private val globalErrorReceiver: GlobalErrorReceiver) : SendVerificationMessageTask { override suspend fun execute(params: SendVerificationMessageTask.Params): String { val event = handleEncryption(params) @@ -45,7 +45,7 @@ internal class DefaultSendVerificationMessageTask @Inject constructor( try { localEchoRepository.updateSendState(localId, event.roomId, SendState.SENDING) - val executeRequest = executeRequest<SendResponse>(eventBus) { + val executeRequest = executeRequest<SendResponse>(globalErrorReceiver) { apiCall = roomAPI.send( localId, roomId = event.roomId ?: "", diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SetDeviceNameTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SetDeviceNameTask.kt index 51b9624554b9e11e840ef0c52302f7a950ba2ef6..b835d46236f2a2000e99375f3702c17808255e9f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SetDeviceNameTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SetDeviceNameTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.crypto.tasks import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.rest.UpdateDeviceInfoBody +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface SetDeviceNameTask : Task<SetDeviceNameTask.Params, Unit> { @@ -34,14 +34,14 @@ internal interface SetDeviceNameTask : Task<SetDeviceNameTask.Params, Unit> { internal class DefaultSetDeviceNameTask @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SetDeviceNameTask { override suspend fun execute(params: SetDeviceNameTask.Params) { val body = UpdateDeviceInfoBody( displayName = params.deviceName ) - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = cryptoApi.updateDeviceInfo(params.deviceId, body) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadKeysTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadKeysTask.kt index 6216a3a305944bdb28258c99e2efec005c345490..eb53bbbf8d289375e782c51c77d86e5cefc9013e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadKeysTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadKeysTask.kt @@ -21,9 +21,9 @@ import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.rest.DeviceKeys import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadBody import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import timber.log.Timber import javax.inject.Inject @@ -38,7 +38,7 @@ internal interface UploadKeysTask : Task<UploadKeysTask.Params, KeysUploadRespon internal class DefaultUploadKeysTask @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : UploadKeysTask { override suspend fun execute(params: UploadKeysTask.Params): KeysUploadResponse { @@ -49,7 +49,7 @@ internal class DefaultUploadKeysTask @Inject constructor( Timber.i("## Uploading device keys -> $body") - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = cryptoApi.uploadKeys(body) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSignaturesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSignaturesTask.kt index a4e10ddbfcfcb1ccd46eea7af35bb5ceb61f11e5..c50faf37b1fa7e084ce7a51bfea4d55625c1fec5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSignaturesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSignaturesTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.crypto.tasks import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.rest.SignatureUploadResponse +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface UploadSignaturesTask : Task<UploadSignaturesTask.Params, Unit> { @@ -31,12 +31,12 @@ internal interface UploadSignaturesTask : Task<UploadSignaturesTask.Params, Unit internal class DefaultUploadSignaturesTask @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : UploadSignaturesTask { override suspend fun execute(params: UploadSignaturesTask.Params) { try { - val response = executeRequest<SignatureUploadResponse>(eventBus) { + val response = executeRequest<SignatureUploadResponse>(globalErrorReceiver) { this.isRetryable = true this.maxRetryCount = 10 this.apiCall = cryptoApi.uploadSignatures(params.signatures) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSigningKeysTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSigningKeysTask.kt index 038ef9dbd3e84a27ba53bedd4d1013d5ac177b51..14fad2ea3899466d36e27507cf288eccdd50d0f0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSigningKeysTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSigningKeysTask.kt @@ -16,18 +16,16 @@ package org.matrix.android.sdk.internal.crypto.tasks -import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.failure.Failure -import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse import org.matrix.android.sdk.internal.crypto.api.CryptoApi import org.matrix.android.sdk.internal.crypto.model.CryptoCrossSigningKey import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse +import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.UploadSigningKeysBody -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth import org.matrix.android.sdk.internal.crypto.model.toRest +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface UploadSigningKeysTask : Task<UploadSigningKeysTask.Params, Unit> { @@ -39,15 +37,9 @@ internal interface UploadSigningKeysTask : Task<UploadSigningKeysTask.Params, Un // the SSK val selfSignedKey: CryptoCrossSigningKey, /** - * - If null: - * - no retry will be performed - * - If not null, it may or may not contain a sessionId: - * - If sessionId is null: - * - password should not be null: the task will perform a first request to get a sessionId, and then a second one - * - If sessionId is not null: - * - password should not be null as well, and no retry will be performed + * Authorisation info (User Interactive flow) */ - val userPasswordAuth: UserPasswordAuth? + val userAuthParam: UIABaseAuth? ) } @@ -55,39 +47,21 @@ data class UploadSigningKeys(val failures: Map<String, Any>?) : Failure.FeatureF internal class DefaultUploadSigningKeysTask @Inject constructor( private val cryptoApi: CryptoApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : UploadSigningKeysTask { override suspend fun execute(params: UploadSigningKeysTask.Params) { - val paramsHaveSessionId = params.userPasswordAuth?.session != null - val uploadQuery = UploadSigningKeysBody( masterKey = params.masterKey.toRest(), userSigningKey = params.userKey.toRest(), selfSigningKey = params.selfSignedKey.toRest(), - // If sessionId is provided, use the userPasswordAuth - auth = params.userPasswordAuth.takeIf { paramsHaveSessionId } + auth = params.userAuthParam?.asMap() ) - try { - doRequest(uploadQuery) - } catch (throwable: Throwable) { - val registrationFlowResponse = throwable.toRegistrationFlowResponse() - if (registrationFlowResponse != null - && registrationFlowResponse.flows.orEmpty().any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } - && params.userPasswordAuth?.password != null - && !paramsHaveSessionId - ) { - // Retry with authentication - doRequest(uploadQuery.copy(auth = params.userPasswordAuth.copy(session = registrationFlowResponse.session))) - } else { - // Other error - throw throwable - } - } + doRequest(uploadQuery) } private suspend fun doRequest(uploadQuery: UploadSigningKeysBody) { - val keysQueryResponse = executeRequest<KeysQueryResponse>(eventBus) { + val keysQueryResponse = executeRequest<KeysQueryResponse>(globalErrorReceiver) { apiCall = cryptoApi.uploadSigningKeys(uploadQuery) } if (keysQueryResponse.failures?.isNotEmpty() == true) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index b970ec60e2ba7d5b853ae59b7f615c2edac50be8..57002b5a600b622eed6a8af4c67567c0f45746f4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -21,6 +21,8 @@ import io.realm.RealmMigration import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityFields +import org.matrix.android.sdk.internal.database.model.RoomEntityFields +import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields import timber.log.Timber import javax.inject.Inject @@ -28,7 +30,7 @@ import javax.inject.Inject class RealmSessionStoreMigration @Inject constructor() : RealmMigration { companion object { - const val SESSION_STORE_SCHEMA_VERSION = 6L + const val SESSION_STORE_SCHEMA_VERSION = 7L } override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { @@ -40,6 +42,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { if (oldVersion <= 3) migrateTo4(realm) if (oldVersion <= 4) migrateTo5(realm) if (oldVersion <= 5) migrateTo6(realm) + if (oldVersion <= 6) migrateTo7(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -105,4 +108,18 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { .addField(PreviewUrlCacheEntityFields.MXC_URL, String::class.java) .addField(PreviewUrlCacheEntityFields.LAST_UPDATED_TIMESTAMP, Long::class.java) } + + private fun migrateTo7(realm: DynamicRealm) { + Timber.d("Step 6 -> 7") + realm.schema.get("RoomEntity") + ?.addField(RoomEntityFields.MEMBERS_LOAD_STATUS_STR, String::class.java) + ?.transform { obj -> + if (obj.getBoolean("areAllMembersLoaded")) { + obj.setString("membersLoadStatusStr", RoomMembersLoadStatusType.LOADED.name) + } else { + obj.setString("membersLoadStatusStr", RoomMembersLoadStatusType.NONE.name) + } + } + ?.removeField("areAllMembersLoaded") + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt index 9af1646a4cd1d1e2e3b4d968ca3776529c9ee17a..3ff2532604803b7d9c0080ec0174e038f55c9be0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt @@ -23,8 +23,7 @@ import io.realm.annotations.PrimaryKey internal open class RoomEntity(@PrimaryKey var roomId: String = "", var chunks: RealmList<ChunkEntity> = RealmList(), - var sendingTimelineEvents: RealmList<TimelineEventEntity> = RealmList(), - var areAllMembersLoaded: Boolean = false + var sendingTimelineEvents: RealmList<TimelineEventEntity> = RealmList() ) : RealmObject() { private var membershipStr: String = Membership.NONE.name @@ -36,5 +35,14 @@ internal open class RoomEntity(@PrimaryKey var roomId: String = "", membershipStr = value.name } + private var membersLoadStatusStr: String = RoomMembersLoadStatusType.NONE.name + var membersLoadStatus: RoomMembersLoadStatusType + get() { + return RoomMembersLoadStatusType.valueOf(membersLoadStatusStr) + } + set(value) { + membersLoadStatusStr = value.name + } + companion object } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/eventbus/EventBusTimberLogger.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMembersLoadStatusType.kt similarity index 63% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/eventbus/EventBusTimberLogger.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMembersLoadStatusType.kt index 2cbd7ba7f0ff1fd14e981c6b6df4494f050a23a4..79fe17253b2f7623535dce246c5a44b3ab686b88 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/eventbus/EventBusTimberLogger.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMembersLoadStatusType.kt @@ -14,18 +14,10 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.eventbus +package org.matrix.android.sdk.internal.database.model -import org.greenrobot.eventbus.Logger -import timber.log.Timber -import java.util.logging.Level - -class EventBusTimberLogger : Logger { - override fun log(level: Level, msg: String) { - Timber.d(msg) - } - - override fun log(level: Level, msg: String, th: Throwable) { - Timber.e(th, msg) - } +internal enum class RoomMembersLoadStatusType { + NONE, + LOADING, + LOADED } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorHandler.kt new file mode 100644 index 0000000000000000000000000000000000000000..9afdb40ed1559cd1aad9d46c2f7afc37ce23f1de --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorHandler.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.network + +import org.matrix.android.sdk.api.failure.GlobalError +import org.matrix.android.sdk.internal.auth.SessionParamsStore +import org.matrix.android.sdk.internal.di.SessionId +import org.matrix.android.sdk.internal.session.SessionScope +import org.matrix.android.sdk.internal.task.TaskExecutor +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import timber.log.Timber +import javax.inject.Inject + +@SessionScope +internal class GlobalErrorHandler @Inject constructor( + private val taskExecutor: TaskExecutor, + private val sessionParamsStore: SessionParamsStore, + @SessionId private val sessionId: String +) : GlobalErrorReceiver { + + var listener: Listener? = null + + override fun handleGlobalError(globalError: GlobalError) { + Timber.e("Global error received: $globalError") + + if (globalError is GlobalError.InvalidToken && globalError.softLogout) { + // Mark the token has invalid + taskExecutor.executorScope.launch(Dispatchers.IO) { + sessionParamsStore.setTokenInvalid(sessionId) + } + } + + listener?.onGlobalError(globalError) + } + + internal interface Listener { + fun onGlobalError(globalError: GlobalError) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorReceiver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorReceiver.kt new file mode 100644 index 0000000000000000000000000000000000000000..47607ba8939cd41cdf1749d62be17b9f5d0ba265 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/GlobalErrorReceiver.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.network + +import org.matrix.android.sdk.api.failure.GlobalError + +internal interface GlobalErrorReceiver { + fun handleGlobalError(globalError: GlobalError) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt index 2535a5347ae3e25ab7badba075b70896d4e4039e..442029127d3202fcc5e35761ba1e234b00668f3b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.network import kotlinx.coroutines.CancellationException import kotlinx.coroutines.delay -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.shouldBeRetried import org.matrix.android.sdk.internal.network.ssl.CertUtil @@ -27,10 +26,10 @@ import retrofit2.awaitResponse import timber.log.Timber import java.io.IOException -internal suspend inline fun <DATA : Any> executeRequest(eventBus: EventBus?, - block: Request<DATA>.() -> Unit) = Request<DATA>(eventBus).apply(block).execute() +internal suspend inline fun <DATA : Any> executeRequest(globalErrorReceiver: GlobalErrorReceiver?, + block: Request<DATA>.() -> Unit) = Request<DATA>(globalErrorReceiver).apply(block).execute() -internal class Request<DATA : Any>(private val eventBus: EventBus?) { +internal class Request<DATA : Any>(private val globalErrorReceiver: GlobalErrorReceiver?) { var isRetryable = false var initialDelay: Long = 100L @@ -47,7 +46,7 @@ internal class Request<DATA : Any>(private val eventBus: EventBus?) { response.body() ?: throw IllegalStateException("The request returned a null body") } else { - throw response.toFailure(eventBus) + throw response.toFailure(globalErrorReceiver) } } catch (exception: Throwable) { // Log some details about the request which has failed diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt index c54af571d879a92412e7720b928960734182d3b4..dd5a69dd3c99aa7232ff256fd6ca470204639be9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt @@ -25,7 +25,6 @@ import org.matrix.android.sdk.api.failure.MatrixError import org.matrix.android.sdk.internal.di.MoshiProvider import kotlinx.coroutines.suspendCancellableCoroutine import okhttp3.ResponseBody -import org.greenrobot.eventbus.EventBus import retrofit2.Response import timber.log.Timber import java.io.IOException @@ -54,18 +53,18 @@ internal suspend fun okhttp3.Call.awaitResponse(): okhttp3.Response { /** * Convert a retrofit Response to a Failure, and eventually parse errorBody to convert it to a MatrixError */ -internal fun <T> Response<T>.toFailure(eventBus: EventBus?): Failure { - return toFailure(errorBody(), code(), eventBus) +internal fun <T> Response<T>.toFailure(globalErrorReceiver: GlobalErrorReceiver?): Failure { + return toFailure(errorBody(), code(), globalErrorReceiver) } /** * Convert a okhttp3 Response to a Failure, and eventually parse errorBody to convert it to a MatrixError */ -internal fun okhttp3.Response.toFailure(eventBus: EventBus?): Failure { - return toFailure(body, code, eventBus) +internal fun okhttp3.Response.toFailure(globalErrorReceiver: GlobalErrorReceiver?): Failure { + return toFailure(body, code, globalErrorReceiver) } -private fun toFailure(errorBody: ResponseBody?, httpCode: Int, eventBus: EventBus?): Failure { +private fun toFailure(errorBody: ResponseBody?, httpCode: Int, globalErrorReceiver: GlobalErrorReceiver?): Failure { if (errorBody == null) { return Failure.Unknown(RuntimeException("errorBody should not be null")) } @@ -79,12 +78,12 @@ private fun toFailure(errorBody: ResponseBody?, httpCode: Int, eventBus: EventBu if (matrixError != null) { if (matrixError.code == MatrixError.M_CONSENT_NOT_GIVEN && !matrixError.consentUri.isNullOrBlank()) { - // Also send this error to the bus, for a global management - eventBus?.post(GlobalError.ConsentNotGivenError(matrixError.consentUri)) + // Also send this error to the globalErrorReceiver, for a global management + globalErrorReceiver?.handleGlobalError(GlobalError.ConsentNotGivenError(matrixError.consentUri)) } else if (httpCode == HttpURLConnection.HTTP_UNAUTHORIZED /* 401 */ && matrixError.code == MatrixError.M_UNKNOWN_TOKEN) { - // Also send this error to the bus, for a global management - eventBus?.post(GlobalError.InvalidToken(matrixError.isSoftLogout)) + // Also send this error to the globalErrorReceiver, for a global management + globalErrorReceiver?.handleGlobalError(GlobalError.InvalidToken(matrixError.isSoftLogout)) } return Failure.ServerError(matrixError, httpCode) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index c5f3f65a34c5d791caa7eec252c051f00c13beb9..e09c051c81a25d3c1cf2be408ac3662a3daa7305 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -19,13 +19,7 @@ package org.matrix.android.sdk.internal.session import androidx.annotation.MainThread import dagger.Lazy import io.realm.RealmConfiguration -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import okhttp3.OkHttpClient -import org.greenrobot.eventbus.EventBus -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.pushrules.PushRuleService @@ -58,6 +52,8 @@ import org.matrix.android.sdk.api.session.terms.TermsService import org.matrix.android.sdk.api.session.typing.TypingUsersTracker import org.matrix.android.sdk.api.session.user.UserService import org.matrix.android.sdk.api.session.widgets.WidgetService +import org.matrix.android.sdk.api.util.appendParamToUrl +import org.matrix.android.sdk.internal.auth.SSO_UIA_FALLBACK_PATH import org.matrix.android.sdk.internal.auth.SessionParamsStore import org.matrix.android.sdk.internal.crypto.DefaultCryptoService import org.matrix.android.sdk.internal.database.tools.RealmDebugTools @@ -65,13 +61,12 @@ import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate import org.matrix.android.sdk.internal.di.WorkManagerProvider +import org.matrix.android.sdk.internal.network.GlobalErrorHandler import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor import org.matrix.android.sdk.internal.session.sync.SyncTokenStore import org.matrix.android.sdk.internal.session.sync.job.SyncThread import org.matrix.android.sdk.internal.session.sync.job.SyncWorker -import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.createUIHandler import timber.log.Timber import javax.inject.Inject @@ -81,7 +76,7 @@ import javax.inject.Provider internal class DefaultSession @Inject constructor( override val sessionParams: SessionParams, private val workManagerProvider: WorkManagerProvider, - private val eventBus: EventBus, + private val globalErrorHandler: GlobalErrorHandler, @SessionId override val sessionId: String, @SessionDatabase private val realmConfiguration: RealmConfiguration, @@ -117,10 +112,8 @@ internal class DefaultSession @Inject constructor( private val accountDataService: Lazy<AccountDataService>, private val _sharedSecretStorageService: Lazy<SharedSecretStorageService>, private val accountService: Lazy<AccountService>, - private val coroutineDispatchers: MatrixCoroutineDispatchers, private val defaultIdentityService: DefaultIdentityService, private val integrationManagerService: IntegrationManagerService, - private val taskExecutor: TaskExecutor, private val callSignalingService: Lazy<CallSignalingService>, @UnauthenticatedWithCertificate private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient>, @@ -140,7 +133,8 @@ internal class DefaultSession @Inject constructor( HomeServerCapabilitiesService by homeServerCapabilitiesService.get(), ProfileService by profileService.get(), AccountDataService by accountDataService.get(), - AccountService by accountService.get() { + AccountService by accountService.get(), + GlobalErrorHandler.Listener { override val sharedSecretStorageService: SharedSecretStorageService get() = _sharedSecretStorageService.get() @@ -162,7 +156,7 @@ internal class DefaultSession @Inject constructor( uiHandler.post { lifecycleObservers.forEach { it.onStart() } } - eventBus.register(this) + globalErrorHandler.listener = this eventSenderProcessor.start() } @@ -206,7 +200,7 @@ internal class DefaultSession @Inject constructor( } cryptoService.get().close() isOpen = false - eventBus.unregister(this) + globalErrorHandler.listener = null eventSenderProcessor.interrupt() } @@ -224,26 +218,17 @@ internal class DefaultSession @Inject constructor( } } - override fun clearCache(callback: MatrixCallback<Unit>) { + override suspend fun clearCache() { stopSync() stopAnyBackgroundSync() uiHandler.post { lifecycleObservers.forEach { it.onClearCache() } } - cacheService.get().clearCache(callback) + cacheService.get().clearCache() workManagerProvider.cancelAllWorks() } - @Subscribe(threadMode = ThreadMode.MAIN) - fun onGlobalError(globalError: GlobalError) { - if (globalError is GlobalError.InvalidToken - && globalError.softLogout) { - // Mark the token has invalid - taskExecutor.executorScope.launch(Dispatchers.IO) { - sessionParamsStore.setTokenInvalid(sessionId) - } - } - + override fun onGlobalError(globalError: GlobalError) { sessionListeners.dispatchGlobalError(globalError) } @@ -290,6 +275,18 @@ internal class DefaultSession @Inject constructor( return "$myUserId - ${sessionParams.deviceId}" } + override fun getUiaSsoFallbackUrl(authenticationSessionId: String): String { + val hsBas = sessionParams.homeServerConnectionConfig + .homeServerUri + .toString() + .trim { it == '/' } + return buildString { + append(hsBas) + append(SSO_UIA_FALLBACK_PATH) + appendParamToUrl("session", authenticationSessionId) + } + } + override fun logDbUsageInfo() { RealmDebugTools(realmConfiguration).logInfo("Session") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt index 659fcc8f5cc0397be59b4f2c05b37bc66a5a5d30..f5eade1704e06669b5b3fb76181052f56d3a5946 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt @@ -27,7 +27,6 @@ import org.matrix.android.sdk.internal.crypto.SendGossipWorker import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker import org.matrix.android.sdk.internal.crypto.verification.SendVerificationMessageWorker import org.matrix.android.sdk.internal.di.MatrixComponent -import org.matrix.android.sdk.internal.di.SessionAssistedInjectModule import org.matrix.android.sdk.internal.network.NetworkConnectivityChecker import org.matrix.android.sdk.internal.session.account.AccountModule import org.matrix.android.sdk.internal.session.cache.CacheModule @@ -86,7 +85,6 @@ import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers TermsModule::class, AccountDataModule::class, ProfileModule::class, - SessionAssistedInjectModule::class, AccountModule::class, CallModule::class, SearchModule::class diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index 96b44917bd787620d11293605e8fd27bd84be64f..468c193ad3c55649fe0df57a7e0599f987a9d43e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -26,7 +26,6 @@ import dagger.Provides import dagger.multibindings.IntoSet import io.realm.RealmConfiguration import okhttp3.OkHttpClient -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig @@ -61,9 +60,10 @@ import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificateWithProgress import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.di.UserMd5 -import org.matrix.android.sdk.internal.eventbus.EventBusTimberLogger import org.matrix.android.sdk.internal.network.DefaultNetworkConnectivityChecker import org.matrix.android.sdk.internal.network.FallbackNetworkCallbackStrategy +import org.matrix.android.sdk.internal.network.GlobalErrorHandler +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.NetworkCallbackStrategy import org.matrix.android.sdk.internal.network.NetworkConnectivityChecker import org.matrix.android.sdk.internal.network.PreferredNetworkCallbackStrategy @@ -256,16 +256,6 @@ internal abstract class SessionModule { .create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUri.toString()) } - @JvmStatic - @Provides - @SessionScope - fun providesEventBus(): EventBus { - return EventBus - .builder() - .logger(EventBusTimberLogger()) - .build() - } - @JvmStatic @Provides @SessionScope @@ -294,6 +284,9 @@ internal abstract class SessionModule { @Binds abstract fun bindSession(session: DefaultSession): Session + @Binds + abstract fun bindGlobalErrorReceiver(handler: GlobalErrorHandler): GlobalErrorReceiver + @Binds abstract fun bindNetworkConnectivityChecker(checker: DefaultNetworkConnectivityChecker): NetworkConnectivityChecker diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt index 70cdbda399621e6fc4b6b0e6da1d16526322683d..1b95820918e3d830e4b14e5b96d3b079004e2137 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordParams.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.session.account import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth +import org.matrix.android.sdk.api.auth.UserPasswordAuth /** * Class to pass request parameters to update the password. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordTask.kt index 869d3f516c1bf834627c43443b054a3ba95a206e..1f043b0a9de61e1c9505a05c6f7804428fbb8116 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/ChangePasswordTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.session.account import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface ChangePasswordTask : Task<ChangePasswordTask.Params, Unit> { @@ -32,14 +32,14 @@ internal interface ChangePasswordTask : Task<ChangePasswordTask.Params, Unit> { internal class DefaultChangePasswordTask @Inject constructor( private val accountAPI: AccountAPI, - private val eventBus: EventBus, + private val globalErrorReceiver: GlobalErrorReceiver, @UserId private val userId: String ) : ChangePasswordTask { override suspend fun execute(params: ChangePasswordTask.Params) { val changePasswordParams = ChangePasswordParams.create(userId, params.password, params.newPassword) try { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = accountAPI.changePassword(changePasswordParams) } } catch (throwable: Throwable) { @@ -49,7 +49,7 @@ internal class DefaultChangePasswordTask @Inject constructor( /* Avoid infinite loop */ && changePasswordParams.auth?.session == null) { // Retry with authentication - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = accountAPI.changePassword( changePasswordParams.copy(auth = changePasswordParams.auth?.copy(session = registrationFlowResponse.session)) ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountParams.kt index 6c2e8b4a4e2808d511b00721c234cbdc5eca20f9..d9b4c748b9d2569fd1d5d90331747f0db5bdc836 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountParams.kt @@ -18,21 +18,21 @@ package org.matrix.android.sdk.internal.session.account import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth +import org.matrix.android.sdk.api.auth.UIABaseAuth @JsonClass(generateAdapter = true) internal data class DeactivateAccountParams( - @Json(name = "auth") - val auth: UserPasswordAuth? = null, - // Set to true to erase all data of the account @Json(name = "erase") - val erase: Boolean + val erase: Boolean, + + @Json(name = "auth") + val auth: Map<String, *>? = null ) { companion object { - fun create(userId: String, password: String, erase: Boolean): DeactivateAccountParams { + fun create(auth: UIABaseAuth?, erase: Boolean): DeactivateAccountParams { return DeactivateAccountParams( - auth = UserPasswordAuth(user = userId, password = password), + auth = auth?.asMap(), erase = erase ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt index ac5febcdaee782a102442f9c8fa9080df4d13096..d67b21567e8a752bab63d2e96723b409a7d91b21 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt @@ -16,37 +16,50 @@ package org.matrix.android.sdk.internal.session.account +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor +import org.matrix.android.sdk.internal.auth.registration.handleUIA +import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.cleanup.CleanupSession import org.matrix.android.sdk.internal.session.identity.IdentityDisconnectTask import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import timber.log.Timber import javax.inject.Inject internal interface DeactivateAccountTask : Task<DeactivateAccountTask.Params, Unit> { data class Params( - val password: String, - val eraseAllData: Boolean + val userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, + val eraseAllData: Boolean, + val userAuthParam: UIABaseAuth? = null ) } internal class DefaultDeactivateAccountTask @Inject constructor( private val accountAPI: AccountAPI, - private val eventBus: EventBus, + private val globalErrorReceiver: GlobalErrorReceiver, @UserId private val userId: String, private val identityDisconnectTask: IdentityDisconnectTask, private val cleanupSession: CleanupSession ) : DeactivateAccountTask { override suspend fun execute(params: DeactivateAccountTask.Params) { - val deactivateAccountParams = DeactivateAccountParams.create(userId, params.password, params.eraseAllData) + val deactivateAccountParams = DeactivateAccountParams.create(params.userAuthParam, params.eraseAllData) - executeRequest<Unit>(eventBus) { - apiCall = accountAPI.deactivate(deactivateAccountParams) + try { + executeRequest<Unit>(globalErrorReceiver) { + apiCall = accountAPI.deactivate(deactivateAccountParams) + } + } catch (throwable: Throwable) { + if (!handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth -> + execute(params.copy(userAuthParam = auth)) + } + ) { + Timber.d("## UIA: propagate failure") + throw throwable + } } - // Logout from identity server if any, ignoring errors runCatching { identityDisconnectTask.execute(Unit) } .onFailure { Timber.w(it, "Unable to disconnect identity server") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt index 1165d2116bb5925ec43b967ab8a36b4df268db8f..25b67159a9fa1cf4f61dda94139f61501bacab03 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.session.account +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.session.account.AccountService import javax.inject.Inject @@ -26,7 +27,7 @@ internal class DefaultAccountService @Inject constructor(private val changePassw changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword)) } - override suspend fun deactivateAccount(password: String, eraseAllData: Boolean) { - deactivateAccountTask.execute(DeactivateAccountTask.Params(password, eraseAllData)) + override suspend fun deactivateAccount(userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, eraseAllData: Boolean) { + deactivateAccountTask.execute(DeactivateAccountTask.Params(userInteractiveAuthInterceptor, eraseAllData)) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/cache/DefaultCacheService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/cache/DefaultCacheService.kt index 19365fce0aeb7a03c8cfa07a9270312f4b156c9d..6d0cd37e1fa9c2d60b25edba7ff900967d7a4498 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/cache/DefaultCacheService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/cache/DefaultCacheService.kt @@ -16,23 +16,18 @@ package org.matrix.android.sdk.internal.session.cache -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.cache.CacheService import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.task.configureWith import javax.inject.Inject internal class DefaultCacheService @Inject constructor(@SessionDatabase private val clearCacheTask: ClearCacheTask, - private val taskExecutor: TaskExecutor) : CacheService { + private val taskExecutor: TaskExecutor +) : CacheService { - override fun clearCache(callback: MatrixCallback<Unit>) { + override suspend fun clearCache() { taskExecutor.cancelAll() - clearCacheTask - .configureWith { - this.callback = callback - } - .executeBy(taskExecutor) + clearCacheTask.execute(Unit) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/GetTurnServerTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/GetTurnServerTask.kt index 1cedee3374cb29de489d988de92cac71ca2d6a2e..b21ec1113aafd71299806b60983629b4a2f0437f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/GetTurnServerTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/GetTurnServerTask.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.session.call import org.matrix.android.sdk.api.session.call.TurnServerResponse +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal abstract class GetTurnServerTask : Task<GetTurnServerTask.Params, TurnServerResponse> { @@ -27,10 +27,10 @@ internal abstract class GetTurnServerTask : Task<GetTurnServerTask.Params, TurnS } internal class DefaultGetTurnServerTask @Inject constructor(private val voipAPI: VoipApi, - private val eventBus: EventBus) : GetTurnServerTask() { + private val globalErrorReceiver: GlobalErrorReceiver) : GetTurnServerTask() { override suspend fun execute(params: Params): TurnServerResponse { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = voipAPI.getTurnServer() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt index 4fc1d67c050e97a221c6c4c5caba56c535feab73..8fa595db3044188d23787eb055db1ab4a514f5d0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt @@ -30,10 +30,10 @@ import okhttp3.RequestBody import okhttp3.RequestBody.Companion.toRequestBody import okio.BufferedSink import okio.source -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.content.ContentUrlResolver import org.matrix.android.sdk.internal.di.Authenticated +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.ProgressRequestBody import org.matrix.android.sdk.internal.network.awaitResponse import org.matrix.android.sdk.internal.network.toFailure @@ -45,7 +45,7 @@ import javax.inject.Inject internal class FileUploader @Inject constructor(@Authenticated private val okHttpClient: OkHttpClient, - private val eventBus: EventBus, + private val globalErrorReceiver: GlobalErrorReceiver, private val context: Context, contentUrlResolver: ContentUrlResolver, moshi: Moshi) { @@ -115,7 +115,7 @@ internal class FileUploader @Inject constructor(@Authenticated return okHttpClient.newCall(request).awaitResponse().use { response -> if (!response.isSuccessful) { - throw response.toFailure(eventBus) + throw response.toFailure(globalErrorReceiver) } else { response.body?.source()?.let { responseAdapter.fromJson(it) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt index 6cf65b867c0800c8535bbb5c2db799b137f7932d..1d6cd61060ff6dd7c91d2ab723b3066351f7b4fd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt @@ -28,9 +28,8 @@ import java.io.File import java.util.UUID import javax.inject.Inject -internal class ImageCompressor @Inject constructor() { +internal class ImageCompressor @Inject constructor(private val context: Context) { suspend fun compress( - context: Context, imageFile: File, desiredWidth: Int, desiredHeight: Int, @@ -46,7 +45,7 @@ internal class ImageCompressor @Inject constructor() { } } ?: return@withContext imageFile - val destinationFile = createDestinationFile(context) + val destinationFile = createDestinationFile() runCatching { destinationFile.outputStream().use { @@ -118,7 +117,7 @@ internal class ImageCompressor @Inject constructor() { } } - private fun createDestinationFile(context: Context): File { + private fun createDestinationFile(): File { return File.createTempFile(UUID.randomUUID().toString(), null, context.cacheDir) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt index 4b31db59b1a1e15f1125f9f0db0858e7013b9305..c28668a53eb77074f077c62a87d8e826fd4a8ac7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt @@ -47,22 +47,24 @@ internal object ThumbnailExtractor { val mediaMetadataRetriever = MediaMetadataRetriever() try { mediaMetadataRetriever.setDataSource(context, attachment.queryUri) - val thumbnail = mediaMetadataRetriever.frameAtTime - - val outputStream = ByteArrayOutputStream() - thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) - val thumbnailWidth = thumbnail.width - val thumbnailHeight = thumbnail.height - val thumbnailSize = outputStream.size() - thumbnailData = ThumbnailData( - width = thumbnailWidth, - height = thumbnailHeight, - size = thumbnailSize.toLong(), - bytes = outputStream.toByteArray(), - mimeType = MimeTypes.Jpeg - ) - thumbnail.recycle() - outputStream.reset() + mediaMetadataRetriever.frameAtTime?.let { thumbnail -> + val outputStream = ByteArrayOutputStream() + thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) + val thumbnailWidth = thumbnail.width + val thumbnailHeight = thumbnail.height + val thumbnailSize = outputStream.size() + thumbnailData = ThumbnailData( + width = thumbnailWidth, + height = thumbnailHeight, + size = thumbnailSize.toLong(), + bytes = outputStream.toByteArray(), + mimeType = MimeTypes.Jpeg + ) + thumbnail.recycle() + outputStream.reset() + } ?: run { + Timber.e("Cannot extract video thumbnail at %s", attachment.queryUri.toString()) + } } catch (e: Exception) { Timber.e(e, "Cannot extract video thumbnail") } finally { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt index 672d407d251577a8aa6e0b0247b769afd52fb110..3b727690bfddccb54b07fc90c50740c1b90a54b9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt @@ -156,7 +156,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter // Do not compress gif && attachment.mimeType != MimeTypes.Gif && params.compressBeforeSending) { - fileToUpload = imageCompressor.compress(context, workingFile, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE) + fileToUpload = imageCompressor.compress(workingFile, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE) .also { compressedFile -> // Get new Bitmap size compressedFile.inputStream().use { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt index 69ced92fe57f1a3045574e7d225e8dce9a83fb19..da747934e2676173cc23d067b41e75d58dbc1853 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.session.filter import org.matrix.android.sdk.api.session.sync.FilterService import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject /** @@ -37,7 +37,7 @@ internal class DefaultSaveFilterTask @Inject constructor( @UserId private val userId: String, private val filterAPI: FilterApi, private val filterRepository: FilterRepository, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SaveFilterTask { override suspend fun execute(params: SaveFilterTask.Params) { @@ -59,7 +59,7 @@ internal class DefaultSaveFilterTask @Inject constructor( } val updated = filterRepository.storeFilter(filterBody, roomFilter) if (updated) { - val filterResponse = executeRequest<FilterResponse>(eventBus) { + val filterResponse = executeRequest<FilterResponse>(globalErrorReceiver) { // TODO auto retry apiCall = filterAPI.uploadFilter(userId, filterBody) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt index dd703a5e93ee30b220a0dd0d540f913c1f22424a..9836164aecaefd84d9e5bba9c18e883846abaa25 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt @@ -23,13 +23,13 @@ import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.group.model.GroupRooms import org.matrix.android.sdk.internal.session.group.model.GroupSummaryResponse import org.matrix.android.sdk.internal.session.group.model.GroupUsers import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction -import org.greenrobot.eventbus.EventBus import timber.log.Timber import javax.inject.Inject @@ -43,7 +43,7 @@ internal interface GetGroupDataTask : Task<GetGroupDataTask.Params, Unit> { internal class DefaultGetGroupDataTask @Inject constructor( private val groupAPI: GroupAPI, @SessionDatabase private val monarchy: Monarchy, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetGroupDataTask { private data class GroupData( @@ -64,13 +64,13 @@ internal class DefaultGetGroupDataTask @Inject constructor( } Timber.v("Fetch data for group with ids: ${groupIds.joinToString(";")}") val data = groupIds.map { groupId -> - val groupSummary = executeRequest<GroupSummaryResponse>(eventBus) { + val groupSummary = executeRequest<GroupSummaryResponse>(globalErrorReceiver) { apiCall = groupAPI.getSummary(groupId) } - val groupRooms = executeRequest<GroupRooms>(eventBus) { + val groupRooms = executeRequest<GroupRooms>(globalErrorReceiver) { apiCall = groupAPI.getRooms(groupId) } - val groupUsers = executeRequest<GroupUsers>(eventBus) { + val groupUsers = executeRequest<GroupUsers>(globalErrorReceiver) { apiCall = groupAPI.getUsers(groupId) } GroupData(groupId, groupSummary, groupRooms, groupUsers) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt index f3686b02d3df0f9994f678aabfec50da2d3e2140..845cfb392e5730b1af63e50e85b30df97cc804a5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt @@ -17,7 +17,6 @@ package org.matrix.android.sdk.internal.session.homeserver import com.zhuinden.monarchy.Monarchy -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.wellknown.WellknownResult import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities @@ -27,6 +26,7 @@ import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEnti import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManagerConfigExtractor import org.matrix.android.sdk.internal.session.media.GetMediaConfigResult @@ -44,7 +44,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( private val capabilitiesAPI: CapabilitiesAPI, private val mediaAPI: MediaAPI, @SessionDatabase private val monarchy: Monarchy, - private val eventBus: EventBus, + private val globalErrorReceiver: GlobalErrorReceiver, private val getWellknownTask: GetWellknownTask, private val configExtractor: IntegrationManagerConfigExtractor, private val homeServerConnectionConfig: HomeServerConnectionConfig, @@ -65,13 +65,13 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( } val capabilities = runCatching { - executeRequest<GetCapabilitiesResult>(eventBus) { + executeRequest<GetCapabilitiesResult>(globalErrorReceiver) { apiCall = capabilitiesAPI.getCapabilities() } }.getOrNull() val mediaConfig = runCatching { - executeRequest<GetMediaConfigResult>(eventBus) { + executeRequest<GetMediaConfigResult>(globalErrorReceiver) { apiCall = mediaAPI.getMediaConfig() } }.getOrNull() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt index a03bef95010e1697eac2c69e2bcd13273c470f80..67f3b2aa56952c02e80e9d5d17556a0653fa4fad 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt @@ -52,65 +52,60 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor( val pepper = identityData.hashLookupPepper val hashDetailResponse = if (pepper == null) { // We need to fetch the hash details first - fetchAndStoreHashDetails(identityAPI) + fetchHashDetails(identityAPI) + .also { identityStore.setHashDetails(it) } } else { IdentityHashDetailResponse(pepper, identityData.hashLookupAlgorithm) } - if (hashDetailResponse.algorithms.contains("sha256").not()) { + if (hashDetailResponse.algorithms.contains(IdentityHashDetailResponse.ALGORITHM_SHA256).not()) { // TODO We should ask the user if he is ok to send their 3Pid in clear, but for the moment we do not do it // Also, what we have in cache could be outdated, the identity server maybe now supports sha256 throw IdentityServiceError.BulkLookupSha256NotSupported } - val hashedAddresses = withOlmUtility { olmUtility -> - params.threePids.map { threePid -> - base64ToBase64Url( - olmUtility.sha256(threePid.value.toLowerCase(Locale.ROOT) - + " " + threePid.toMedium() + " " + hashDetailResponse.pepper) - ) - } - } - - val identityLookUpV2Response = lookUpInternal(identityAPI, hashedAddresses, hashDetailResponse, true) + val lookUpData = lookUpInternal(identityAPI, params.threePids, hashDetailResponse, true) // Convert back to List<FoundThreePid> - return handleSuccess(params.threePids, hashedAddresses, identityLookUpV2Response) + return handleSuccess(params.threePids, lookUpData) } + data class LookUpData( + val hashedAddresses: List<String>, + val identityLookUpResponse: IdentityLookUpResponse + ) + private suspend fun lookUpInternal(identityAPI: IdentityAPI, - hashedAddresses: List<String>, + threePids: List<ThreePid>, hashDetailResponse: IdentityHashDetailResponse, - canRetry: Boolean): IdentityLookUpResponse { + canRetry: Boolean): LookUpData { + val hashedAddresses = getHashedAddresses(threePids, hashDetailResponse.pepper) return try { - executeRequest(null) { - apiCall = identityAPI.lookup(IdentityLookUpParams( - hashedAddresses, - IdentityHashDetailResponse.ALGORITHM_SHA256, - hashDetailResponse.pepper - )) - } + LookUpData(hashedAddresses, + executeRequest(null) { + apiCall = identityAPI.lookup(IdentityLookUpParams( + hashedAddresses, + IdentityHashDetailResponse.ALGORITHM_SHA256, + hashDetailResponse.pepper + )) + }) } catch (failure: Throwable) { // Catch invalid hash pepper and retry if (canRetry && failure is Failure.ServerError && failure.error.code == MatrixError.M_INVALID_PEPPER) { // This is not documented, but the error can contain the new pepper! - if (!failure.error.newLookupPepper.isNullOrEmpty()) { + val newHashDetailResponse = if (!failure.error.newLookupPepper.isNullOrEmpty()) { // Store it and use it right now hashDetailResponse.copy(pepper = failure.error.newLookupPepper) - .also { identityStore.setHashDetails(it) } - .let { lookUpInternal(identityAPI, hashedAddresses, it, false /* Avoid infinite loop */) } } else { // Retrieve the new hash details - val newHashDetailResponse = fetchAndStoreHashDetails(identityAPI) - - if (hashDetailResponse.algorithms.contains(IdentityHashDetailResponse.ALGORITHM_SHA256).not()) { - // TODO We should ask the user if he is ok to send their 3Pid in clear, but for the moment we do not do it - // Also, what we have in cache is maybe outdated, the identity server maybe now support sha256 - throw IdentityServiceError.BulkLookupSha256NotSupported - } - - lookUpInternal(identityAPI, hashedAddresses, newHashDetailResponse, false /* Avoid infinite loop */) + fetchHashDetails(identityAPI) + } + .also { identityStore.setHashDetails(it) } + if (newHashDetailResponse.algorithms.contains(IdentityHashDetailResponse.ALGORITHM_SHA256).not()) { + // TODO We should ask the user if he is ok to send their 3Pid in clear, but for the moment we do not do it + throw IdentityServiceError.BulkLookupSha256NotSupported } + lookUpInternal(identityAPI, threePids, newHashDetailResponse, false /* Avoid infinite loop */) } else { // Other error throw failure @@ -118,16 +113,29 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor( } } - private suspend fun fetchAndStoreHashDetails(identityAPI: IdentityAPI): IdentityHashDetailResponse { - return executeRequest<IdentityHashDetailResponse>(null) { + private fun getHashedAddresses(threePids: List<ThreePid>, pepper: String): List<String> { + return withOlmUtility { olmUtility -> + threePids.map { threePid -> + base64ToBase64Url( + olmUtility.sha256(threePid.value.toLowerCase(Locale.ROOT) + + " " + threePid.toMedium() + " " + pepper) + ) + } + } + } + + private suspend fun fetchHashDetails(identityAPI: IdentityAPI): IdentityHashDetailResponse { + return executeRequest(null) { apiCall = identityAPI.hashDetails() } - .also { identityStore.setHashDetails(it) } } - private fun handleSuccess(threePids: List<ThreePid>, hashedAddresses: List<String>, identityLookUpResponse: IdentityLookUpResponse): List<FoundThreePid> { - return identityLookUpResponse.mappings.keys.map { hashedAddress -> - FoundThreePid(threePids[hashedAddresses.indexOf(hashedAddress)], identityLookUpResponse.mappings[hashedAddress] ?: error("")) + private fun handleSuccess(threePids: List<ThreePid>, lookupData: LookUpData): List<FoundThreePid> { + return lookupData.identityLookUpResponse.mappings.keys.map { hashedAddress -> + FoundThreePid( + threePids[lookupData.hashedAddresses.indexOf(hashedAddress)], + lookupData.identityLookUpResponse.mappings[hashedAddress] ?: error("") + ) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/DefaultMediaService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/DefaultMediaService.kt index 1a400ccfcfaea8a593df3bbfab3099a4173cc4a6..9b807d03de52da671b3e961b08305d0376b320a3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/DefaultMediaService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/DefaultMediaService.kt @@ -18,9 +18,10 @@ package org.matrix.android.sdk.internal.session.media import androidx.collection.LruCache import org.matrix.android.sdk.api.cache.CacheStrategy -import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.media.MediaService import org.matrix.android.sdk.api.session.media.PreviewUrlData +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.session.room.timeline.getLatestEventId import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.util.getOrPut import javax.inject.Inject @@ -34,11 +35,12 @@ internal class DefaultMediaService @Inject constructor( // Cache of extracted URLs private val extractedUrlsCache = LruCache<String, List<String>>(1_000) - override fun extractUrls(event: Event): List<String> { + override fun extractUrls(event: TimelineEvent): List<String> { return extractedUrlsCache.getOrPut(event.cacheKey()) { urlsExtractor.extract(event) } } - private fun Event.cacheKey() = "${eventId ?: ""}-${roomId ?: ""}" + // Use the id of the latest Event edition + private fun TimelineEvent.cacheKey() = "${getLatestEventId()}-${root.roomId ?: ""}" override suspend fun getRawPreviewUrl(url: String, timestamp: Long?): JsonDict { return getRawPreviewUrlTask.execute(GetRawPreviewUrlTask.Params(url, timestamp)) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt index 69cdfa8faad3551e8a3b127014b043e5821d22cf..a218f3f93cd6862061179a9d329ccec90095f5d4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt @@ -17,7 +17,6 @@ package org.matrix.android.sdk.internal.session.media import com.zhuinden.monarchy.Monarchy -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.cache.CacheStrategy import org.matrix.android.sdk.api.session.media.PreviewUrlData import org.matrix.android.sdk.api.util.JsonDict @@ -25,6 +24,7 @@ import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntity import org.matrix.android.sdk.internal.database.query.get import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction @@ -41,7 +41,7 @@ internal interface GetPreviewUrlTask : Task<GetPreviewUrlTask.Params, PreviewUrl internal class DefaultGetPreviewUrlTask @Inject constructor( private val mediaAPI: MediaAPI, - private val eventBus: EventBus, + private val globalErrorReceiver: GlobalErrorReceiver, @SessionDatabase private val monarchy: Monarchy ) : GetPreviewUrlTask { @@ -64,7 +64,7 @@ internal class DefaultGetPreviewUrlTask @Inject constructor( } private suspend fun doRequest(url: String, timestamp: Long?): PreviewUrlData { - return executeRequest<JsonDict>(eventBus) { + return executeRequest<JsonDict>(globalErrorReceiver) { apiCall = mediaAPI.getPreviewUrlData(url, timestamp) } .toPreviewUrlData(url) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetRawPreviewUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetRawPreviewUrlTask.kt index 6c5dad2422bffaaefc43065e53c78bd0954d1202..32305cd4e405419470c8e1a4d9a392c849d008e9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetRawPreviewUrlTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetRawPreviewUrlTask.kt @@ -16,8 +16,8 @@ package org.matrix.android.sdk.internal.session.media -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task import javax.inject.Inject @@ -31,11 +31,11 @@ internal interface GetRawPreviewUrlTask : Task<GetRawPreviewUrlTask.Params, Json internal class DefaultGetRawPreviewUrlTask @Inject constructor( private val mediaAPI: MediaAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetRawPreviewUrlTask { override suspend fun execute(params: GetRawPreviewUrlTask.Params): JsonDict { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = mediaAPI.getPreviewUrlData(params.url, params.timestamp) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/UrlsExtractor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/UrlsExtractor.kt index 9d374c342893a04e7c5a9d4e6ad53102d80fe660..6137b4152cb48582d06ae80eac6fdb6aca3b8fdb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/UrlsExtractor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/UrlsExtractor.kt @@ -17,22 +17,24 @@ package org.matrix.android.sdk.internal.session.media import android.util.Patterns -import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType -import org.matrix.android.sdk.api.session.events.model.toModel -import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageType +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import javax.inject.Inject internal class UrlsExtractor @Inject constructor() { // Sadly Patterns.WEB_URL_WITH_PROTOCOL is not public so filter the protocol later private val urlRegex = Patterns.WEB_URL.toRegex() - fun extract(event: Event): List<String> { - return event.takeIf { it.getClearType() == EventType.MESSAGE } - ?.getClearContent() - ?.toModel<MessageContent>() - ?.takeIf { it.msgType == MessageType.MSGTYPE_TEXT || it.msgType == MessageType.MSGTYPE_EMOTE } + fun extract(event: TimelineEvent): List<String> { + return event.takeIf { it.root.getClearType() == EventType.MESSAGE } + ?.getLastMessageContent() + ?.takeIf { + it.msgType == MessageType.MSGTYPE_TEXT + || it.msgType == MessageType.MSGTYPE_NOTICE + || it.msgType == MessageType.MSGTYPE_EMOTE + } ?.body ?.let { urlRegex.findAll(it) } ?.map { it.value } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt index 5d7cfd1719500a388552c96c619d02777644ee8f..f83c6b770af5fa3883d84f73c6163bfebf8e6cb9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.session.openid import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetOpenIdTokenTask : Task<Unit, RequestOpenIdTokenResponse> @@ -27,10 +27,10 @@ internal interface GetOpenIdTokenTask : Task<Unit, RequestOpenIdTokenResponse> internal class DefaultGetOpenIdTokenTask @Inject constructor( @UserId private val userId: String, private val openIdAPI: OpenIdAPI, - private val eventBus: EventBus) : GetOpenIdTokenTask { + private val globalErrorReceiver: GlobalErrorReceiver) : GetOpenIdTokenTask { override suspend fun execute(params: Unit): RequestOpenIdTokenResponse { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = openIdAPI.openIdToken(userId) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt index 2e8a0b3884beab6bab672002e3e381492135fd28..6d6d70bb0d5d51a84200bfee1d6f78bb99cdc57f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.session.profile import com.google.i18n.phonenumbers.PhoneNumberUtil import com.zhuinden.monarchy.Monarchy -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction @@ -37,7 +37,7 @@ internal class DefaultAddThreePidTask @Inject constructor( private val profileAPI: ProfileAPI, @SessionDatabase private val monarchy: Monarchy, private val pendingThreePidMapper: PendingThreePidMapper, - private val eventBus: EventBus) : AddThreePidTask() { + private val globalErrorReceiver: GlobalErrorReceiver) : AddThreePidTask() { override suspend fun execute(params: Params) { when (params.threePid) { @@ -50,7 +50,7 @@ internal class DefaultAddThreePidTask @Inject constructor( val clientSecret = UUID.randomUUID().toString() val sendAttempt = 1 - val result = executeRequest<AddEmailResponse>(eventBus) { + val result = executeRequest<AddEmailResponse>(globalErrorReceiver) { val body = AddEmailBody( clientSecret = clientSecret, email = threePid.email, @@ -84,7 +84,7 @@ internal class DefaultAddThreePidTask @Inject constructor( val countryCode = parsedNumber.countryCode val country = phoneNumberUtil.getRegionCodeForCountryCode(countryCode) - val result = executeRequest<AddMsisdnResponse>(eventBus) { + val result = executeRequest<AddMsisdnResponse>(globalErrorReceiver) { val body = AddMsisdnBody( clientSecret = clientSecret, country = country, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt index dbe6bff508e9ca2c1afc8aceeee9f01d6d38aa52..a37e5380bcc9a0cdeb6b8d5159dafd98f18b3401 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt @@ -19,12 +19,12 @@ package org.matrix.android.sdk.internal.session.profile import org.matrix.android.sdk.api.session.identity.IdentityServiceError import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.internal.di.AuthenticatedIdentity +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.network.token.AccessTokenProvider import org.matrix.android.sdk.internal.session.identity.data.IdentityStore import org.matrix.android.sdk.internal.session.identity.data.getIdentityServerUrlWithoutProtocol import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal abstract class BindThreePidsTask : Task<BindThreePidsTask.Params, Unit> { @@ -37,13 +37,13 @@ internal class DefaultBindThreePidsTask @Inject constructor(private val profileA private val identityStore: IdentityStore, @AuthenticatedIdentity private val accessTokenProvider: AccessTokenProvider, - private val eventBus: EventBus) : BindThreePidsTask() { + private val globalErrorReceiver: GlobalErrorReceiver) : BindThreePidsTask() { override suspend fun execute(params: Params) { val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() ?: throw IdentityServiceError.NoIdentityServerConfigured val identityServerAccessToken = accessTokenProvider.getToken() ?: throw IdentityServiceError.NoIdentityServerConfigured val identityPendingBinding = identityStore.getPendingBinding(params.threePid) ?: throw IdentityServiceError.NoCurrentBindingError - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = profileAPI.bindThreePid( BindThreePidBody( clientSecret = identityPendingBinding.clientSecret, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt index 500d43408e25cbf70fc75786b04645ce818a3822..b3216d744d4bbf006cbbd1dc2a4905f9713715b5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt @@ -22,6 +22,7 @@ import androidx.lifecycle.LiveData import com.zhuinden.monarchy.Monarchy import io.realm.kotlin.where import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.util.Cancelable @@ -170,14 +171,12 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto } override fun finalizeAddingThreePid(threePid: ThreePid, - uiaSession: String?, - accountPassword: String?, + userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, matrixCallback: MatrixCallback<Unit>): Cancelable { return finalizeAddingThreePidTask .configureWith(FinalizeAddingThreePidTask.Params( threePid = threePid, - session = uiaSession, - accountPassword = accountPassword, + userInteractiveAuthInterceptor = userInteractiveAuthInterceptor, userWantsToCancel = false )) { callback = alsoRefresh(matrixCallback) @@ -189,8 +188,7 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto return finalizeAddingThreePidTask .configureWith(FinalizeAddingThreePidTask.Params( threePid = threePid, - session = null, - accountPassword = null, + userInteractiveAuthInterceptor = null, userWantsToCancel = true )) { callback = alsoRefresh(matrixCallback) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt index 3f43cbe5998ff93c4ebcea6fc2a55640be769f7c..3549f3613f62f35372304162e4d6a25b0714cb23 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt @@ -16,9 +16,9 @@ package org.matrix.android.sdk.internal.session.profile -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.toMedium +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task import javax.inject.Inject @@ -31,10 +31,10 @@ internal abstract class DeleteThreePidTask : Task<DeleteThreePidTask.Params, Uni internal class DefaultDeleteThreePidTask @Inject constructor( private val profileAPI: ProfileAPI, - private val eventBus: EventBus) : DeleteThreePidTask() { + private val globalErrorReceiver: GlobalErrorReceiver) : DeleteThreePidTask() { override suspend fun execute(params: Params) { - executeRequest<DeleteThreePidResponse>(eventBus) { + executeRequest<DeleteThreePidResponse>(globalErrorReceiver) { val body = DeleteThreePidBody( medium = params.threePid.toMedium(), address = params.threePid.value diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddThreePidBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddThreePidBody.kt index 4e46dd096d77b88f904deba9b4d258affe87963f..630192954540c71d24761a5b8c7bbf0e91689953 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddThreePidBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddThreePidBody.kt @@ -17,7 +17,6 @@ package org.matrix.android.sdk.internal.session.profile import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth @JsonClass(generateAdapter = true) internal data class FinalizeAddThreePidBody( @@ -37,5 +36,5 @@ internal data class FinalizeAddThreePidBody( * Additional authentication information for the user-interactive authentication API. */ @Json(name = "auth") - val auth: UserPasswordAuth? + val auth: Map<String, *>? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt index 0b1bf8828032085091d561adf6b37168a69277e5..916a6029360f7e7503aa15e2e15d08f2842bc747 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt @@ -17,25 +17,28 @@ package org.matrix.android.sdk.internal.session.profile import com.zhuinden.monarchy.Monarchy -import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse import org.matrix.android.sdk.api.session.identity.ThreePid -import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth +import org.matrix.android.sdk.internal.auth.registration.handleUIA +import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction +import timber.log.Timber import javax.inject.Inject internal abstract class FinalizeAddingThreePidTask : Task<FinalizeAddingThreePidTask.Params, Unit> { data class Params( val threePid: ThreePid, - val session: String?, - val accountPassword: String?, + val userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor?, + val userAuthParam: UIABaseAuth? = null, val userWantsToCancel: Boolean ) } @@ -45,7 +48,7 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor( @SessionDatabase private val monarchy: Monarchy, private val pendingThreePidMapper: PendingThreePidMapper, @UserId private val userId: String, - private val eventBus: EventBus) : FinalizeAddingThreePidTask() { + private val globalErrorReceiver: GlobalErrorReceiver) : FinalizeAddingThreePidTask() { override suspend fun execute(params: Params) { if (params.userWantsToCancel.not()) { @@ -58,24 +61,25 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor( ?: throw IllegalArgumentException("unknown threepid") try { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { val body = FinalizeAddThreePidBody( clientSecret = pendingThreePids.clientSecret, sid = pendingThreePids.sid, - auth = if (params.session != null && params.accountPassword != null) { - UserPasswordAuth( - session = params.session, - user = userId, - password = params.accountPassword - ) - } else null + auth = params.userAuthParam?.asMap() ) apiCall = profileAPI.finalizeAddThreePid(body) } } catch (throwable: Throwable) { - throw throwable.toRegistrationFlowResponse() - ?.let { Failure.RegistrationFlowError(it) } - ?: throwable + if (params.userInteractiveAuthInterceptor == null + || !handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth -> + execute(params.copy(userAuthParam = auth)) + } + ) { + Timber.d("## UIA: propagate failure") + throw throwable.toRegistrationFlowResponse() + ?.let { Failure.RegistrationFlowError(it) } + ?: throwable + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt index 5f1f621ddbaf7ab60743d43aee7428a9ab96bcfd..ed60c4a368d5f8acd7668b35adca3e54caf05e49 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.session.profile import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal abstract class GetProfileInfoTask : Task<GetProfileInfoTask.Params, JsonDict> { @@ -30,10 +30,10 @@ internal abstract class GetProfileInfoTask : Task<GetProfileInfoTask.Params, Jso } internal class DefaultGetProfileInfoTask @Inject constructor(private val profileAPI: ProfileAPI, - private val eventBus: EventBus) : GetProfileInfoTask() { + private val globalErrorReceiver: GlobalErrorReceiver) : GetProfileInfoTask() { override suspend fun execute(params: Params): JsonDict { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = profileAPI.getProfile(params.userId) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt index 5dd092cceba50ad801793fddfe5c6babe43c382f..552ad874eeeba0bea3e88e06589b3fecdb7ddc09 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt @@ -19,9 +19,9 @@ package org.matrix.android.sdk.internal.session.profile import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.internal.database.model.UserThreePidEntity import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.internal.util.awaitTransaction import timber.log.Timber import javax.inject.Inject @@ -30,10 +30,10 @@ internal abstract class RefreshUserThreePidsTask : Task<Unit, Unit> internal class DefaultRefreshUserThreePidsTask @Inject constructor(private val profileAPI: ProfileAPI, @SessionDatabase private val monarchy: Monarchy, - private val eventBus: EventBus) : RefreshUserThreePidsTask() { + private val globalErrorReceiver: GlobalErrorReceiver) : RefreshUserThreePidsTask() { override suspend fun execute(params: Unit) { - val accountThreePidsResponse = executeRequest<AccountThreePidsResponse>(eventBus) { + val accountThreePidsResponse = executeRequest<AccountThreePidsResponse>(globalErrorReceiver) { apiCall = profileAPI.getThreePIDs() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt index 4b863c20983bbdde9ef7f40aaacb0d4310531c26..b29153d665f634d7c529885622022dbd423989f9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt @@ -16,9 +16,9 @@ package org.matrix.android.sdk.internal.session.profile +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal abstract class SetAvatarUrlTask : Task<SetAvatarUrlTask.Params, Unit> { @@ -30,10 +30,10 @@ internal abstract class SetAvatarUrlTask : Task<SetAvatarUrlTask.Params, Unit> { internal class DefaultSetAvatarUrlTask @Inject constructor( private val profileAPI: ProfileAPI, - private val eventBus: EventBus) : SetAvatarUrlTask() { + private val globalErrorReceiver: GlobalErrorReceiver) : SetAvatarUrlTask() { override suspend fun execute(params: Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { val body = SetAvatarUrlBody( avatarUrl = params.newAvatarUrl ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt index 1fa84f98c12288bc6e04e65868fdb208fd9fa5ea..3f236bc589ba22750b31a41d55d59acec236fc2e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt @@ -16,9 +16,9 @@ package org.matrix.android.sdk.internal.session.profile +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal abstract class SetDisplayNameTask : Task<SetDisplayNameTask.Params, Unit> { @@ -30,10 +30,10 @@ internal abstract class SetDisplayNameTask : Task<SetDisplayNameTask.Params, Uni internal class DefaultSetDisplayNameTask @Inject constructor( private val profileAPI: ProfileAPI, - private val eventBus: EventBus) : SetDisplayNameTask() { + private val globalErrorReceiver: GlobalErrorReceiver) : SetDisplayNameTask() { override suspend fun execute(params: Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { val body = SetDisplayNameBody( displayName = params.newDisplayName ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt index 96b0717edbb5763634a017eb1d41f87dabd73bdf..3439f6f840a980af59d0324327a5dc3e2bc50362 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt @@ -19,11 +19,11 @@ package org.matrix.android.sdk.internal.session.profile import org.matrix.android.sdk.api.session.identity.IdentityServiceError import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.toMedium +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.identity.data.IdentityStore import org.matrix.android.sdk.internal.session.identity.data.getIdentityServerUrlWithoutProtocol import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal abstract class UnbindThreePidsTask : Task<UnbindThreePidsTask.Params, Boolean> { @@ -34,12 +34,12 @@ internal abstract class UnbindThreePidsTask : Task<UnbindThreePidsTask.Params, B internal class DefaultUnbindThreePidsTask @Inject constructor(private val profileAPI: ProfileAPI, private val identityStore: IdentityStore, - private val eventBus: EventBus) : UnbindThreePidsTask() { + private val globalErrorReceiver: GlobalErrorReceiver) : UnbindThreePidsTask() { override suspend fun execute(params: Params): Boolean { val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() ?: throw IdentityServiceError.NoIdentityServerConfigured - return executeRequest<UnbindThreePidResponse>(eventBus) { + return executeRequest<UnbindThreePidResponse>(globalErrorReceiver) { apiCall = profileAPI.unbindThreePid( UnbindThreePidBody( identityServerUrlWithoutProtocol, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ValidateSmsCodeTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ValidateSmsCodeTask.kt index 36804e06fef989755f866d584ffa993ea1af7f40..efb6c6e836ca4dabbb7b255e664c4483281d4c67 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ValidateSmsCodeTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ValidateSmsCodeTask.kt @@ -17,13 +17,13 @@ package org.matrix.android.sdk.internal.session.profile import com.zhuinden.monarchy.Monarchy -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.internal.auth.registration.SuccessResult import org.matrix.android.sdk.internal.auth.registration.ValidationCodeBody import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task import javax.inject.Inject @@ -40,7 +40,7 @@ internal class DefaultValidateSmsCodeTask @Inject constructor( @SessionDatabase private val monarchy: Monarchy, private val pendingThreePidMapper: PendingThreePidMapper, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : ValidateSmsCodeTask { override suspend fun execute(params: ValidateSmsCodeTask.Params) { @@ -58,7 +58,7 @@ internal class DefaultValidateSmsCodeTask @Inject constructor( sid = pendingThreePids.sid, code = params.code ) - val result = executeRequest<SuccessResult>(eventBus) { + val result = executeRequest<SuccessResult>(globalErrorReceiver) { apiCall = profileAPI.validateMsisdn(url, body) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddHttpPusherWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddHttpPusherWorker.kt index 31c5cda5ecd57aff28ccd039ace6e7135b0f1325..d0f7cbfca3d0d5b0ec03bead41e847c95932fb54 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddHttpPusherWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddHttpPusherWorker.kt @@ -19,13 +19,13 @@ import android.content.Context import androidx.work.WorkerParameters import com.squareup.moshi.JsonClass import com.zhuinden.monarchy.Monarchy -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.pushers.PusherState import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.model.PusherEntity import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.SessionComponent import org.matrix.android.sdk.internal.util.awaitTransaction @@ -45,7 +45,7 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters) @Inject lateinit var pushersAPI: PushersAPI @Inject @SessionDatabase lateinit var monarchy: Monarchy - @Inject lateinit var eventBus: EventBus + @Inject lateinit var globalErrorReceiver: GlobalErrorReceiver override fun injectWith(injector: SessionComponent) { injector.inject(this) @@ -81,7 +81,7 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters) } private suspend fun setPusher(pusher: JsonPusher) { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = pushersAPI.setPusher(pusher) } monarchy.awaitTransaction { realm -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPushRuleTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPushRuleTask.kt index 28ac5db52e339854dcb53996013fd38913409580..03748b15283517d9ee03f653a659ed3d73d62cc2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPushRuleTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPushRuleTask.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.session.pushers import org.matrix.android.sdk.api.pushrules.RuleKind import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface AddPushRuleTask : Task<AddPushRuleTask.Params, Unit> { @@ -31,11 +31,11 @@ internal interface AddPushRuleTask : Task<AddPushRuleTask.Params, Unit> { internal class DefaultAddPushRuleTask @Inject constructor( private val pushRulesApi: PushRulesApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : AddPushRuleTask { override suspend fun execute(params: AddPushRuleTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = pushRulesApi.addRule(params.kind.value, params.pushRule.ruleId, params.pushRule) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesTask.kt index 0c532cedbc5d4d71f99f2f4dbb09b90dc314f3df..9fb2d51664290bb3fbba12c385efc63990b216cb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesTask.kt @@ -16,9 +16,9 @@ package org.matrix.android.sdk.internal.session.pushers import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetPushRulesTask : Task<GetPushRulesTask.Params, Unit> { @@ -31,11 +31,11 @@ internal interface GetPushRulesTask : Task<GetPushRulesTask.Params, Unit> { internal class DefaultGetPushRulesTask @Inject constructor( private val pushRulesApi: PushRulesApi, private val savePushRulesTask: SavePushRulesTask, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetPushRulesTask { override suspend fun execute(params: GetPushRulesTask.Params) { - val response = executeRequest<GetPushRulesResponse>(eventBus) { + val response = executeRequest<GetPushRulesResponse>(globalErrorReceiver) { apiCall = pushRulesApi.getAllRules() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushersTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushersTask.kt index 39e970f4a89c2e8e51d86be702de77b9ada38089..4c7d370446ec41ed82efdf4dcefa52b45022993b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushersTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushersTask.kt @@ -20,10 +20,10 @@ import org.matrix.android.sdk.api.session.pushers.PusherState import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.model.PusherEntity import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetPushersTask : Task<Unit, Unit> @@ -31,11 +31,11 @@ internal interface GetPushersTask : Task<Unit, Unit> internal class DefaultGetPushersTask @Inject constructor( private val pushersAPI: PushersAPI, @SessionDatabase private val monarchy: Monarchy, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetPushersTask { override suspend fun execute(params: Unit) { - val response = executeRequest<GetPushersResponse>(eventBus) { + val response = executeRequest<GetPushersResponse>(globalErrorReceiver) { apiCall = pushersAPI.getPushers() } monarchy.awaitTransaction { realm -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePushRuleTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePushRuleTask.kt index 2fc97cf02303a8d2d7334e328e55ec734a725c07..ff3122f5665de05f80865c81284751cd44e21a95 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePushRuleTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePushRuleTask.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.session.pushers import org.matrix.android.sdk.api.pushrules.RuleKind import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface RemovePushRuleTask : Task<RemovePushRuleTask.Params, Unit> { @@ -31,11 +31,11 @@ internal interface RemovePushRuleTask : Task<RemovePushRuleTask.Params, Unit> { internal class DefaultRemovePushRuleTask @Inject constructor( private val pushRulesApi: PushRulesApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : RemovePushRuleTask { override suspend fun execute(params: RemovePushRuleTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = pushRulesApi.deleteRule(params.kind.value, params.pushRule.ruleId) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt index 1f108637992e8394a9dcd6018b28e7e5cf50587b..e3f4fdb789671ff7aed078be2c4cacf0c4a3056f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt @@ -26,7 +26,7 @@ import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction import io.realm.Realm -import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import javax.inject.Inject internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> { @@ -37,7 +37,7 @@ internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> { internal class DefaultRemovePusherTask @Inject constructor( private val pushersAPI: PushersAPI, @SessionDatabase private val monarchy: Monarchy, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : RemovePusherTask { override suspend fun execute(params: RemovePusherTask.Params) { @@ -62,7 +62,7 @@ internal class DefaultRemovePusherTask @Inject constructor( data = JsonPusherData(existing.data.url, existing.data.format), append = false ) - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = pushersAPI.setPusher(deleteBody) } monarchy.awaitTransaction { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleActionsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleActionsTask.kt index c2dca8a9a58f4e2f3b35bf1c38d6e914d94d4b57..a5c220e662583512910b307d1d3b8cb37ece7bd9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleActionsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleActionsTask.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.session.pushers import org.matrix.android.sdk.api.pushrules.RuleKind import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface UpdatePushRuleActionsTask : Task<UpdatePushRuleActionsTask.Params, Unit> { @@ -32,13 +32,13 @@ internal interface UpdatePushRuleActionsTask : Task<UpdatePushRuleActionsTask.Pa internal class DefaultUpdatePushRuleActionsTask @Inject constructor( private val pushRulesApi: PushRulesApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : UpdatePushRuleActionsTask { override suspend fun execute(params: UpdatePushRuleActionsTask.Params) { if (params.oldPushRule.enabled != params.newPushRule.enabled) { // First change enabled state - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = pushRulesApi.updateEnableRuleStatus(params.kind.value, params.newPushRule.ruleId, params.newPushRule.enabled) } } @@ -47,7 +47,7 @@ internal class DefaultUpdatePushRuleActionsTask @Inject constructor( // Also ensure the actions are up to date val body = mapOf("actions" to params.newPushRule.actions) - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = pushRulesApi.updateRuleActions(params.kind.value, params.newPushRule.ruleId, body) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt index 4100071c902431b36a6dbbef91165a0bf6f42054..f36b5c55fb1933a4cc4a400a4aadd822ce78d2a9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt @@ -17,9 +17,9 @@ package org.matrix.android.sdk.internal.session.pushers import org.matrix.android.sdk.api.pushrules.RuleKind import org.matrix.android.sdk.api.pushrules.rest.PushRule +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface UpdatePushRuleEnableStatusTask : Task<UpdatePushRuleEnableStatusTask.Params, Unit> { @@ -30,11 +30,11 @@ internal interface UpdatePushRuleEnableStatusTask : Task<UpdatePushRuleEnableSta internal class DefaultUpdatePushRuleEnableStatusTask @Inject constructor( private val pushRulesApi: PushRulesApi, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : UpdatePushRuleEnableStatusTask { override suspend fun execute(params: UpdatePushRuleEnableStatusTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = pushRulesApi.updateEnableRuleStatus(params.kind.value, params.pushRule.ruleId, params.enabled) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/AddRoomAliasTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/AddRoomAliasTask.kt index 9793750fa096d343dd232b535583bc6d182d5e15..9e4ec6f77779258ba3c550ce2f3795af69f68c24 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/AddRoomAliasTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/AddRoomAliasTask.kt @@ -16,8 +16,8 @@ package org.matrix.android.sdk.internal.session.room.alias -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.directory.DirectoryAPI import org.matrix.android.sdk.internal.session.room.alias.RoomAliasAvailabilityChecker.Companion.toFullLocalAlias @@ -39,13 +39,13 @@ internal class DefaultAddRoomAliasTask @Inject constructor( @UserId private val userId: String, private val directoryAPI: DirectoryAPI, private val aliasAvailabilityChecker: RoomAliasAvailabilityChecker, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : AddRoomAliasTask { override suspend fun execute(params: AddRoomAliasTask.Params) { aliasAvailabilityChecker.check(params.aliasLocalPart) - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = directoryAPI.addRoomAlias( roomAlias = params.aliasLocalPart.toFullLocalAlias(userId), body = AddRoomAliasBody( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DefaultAliasService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DefaultAliasService.kt index b6c69224e65dc8e16e988d5c2eed67953cc95ea9..8f58094a2af675c7a5a19c7365de194810db5d57 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DefaultAliasService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DefaultAliasService.kt @@ -16,8 +16,9 @@ package org.matrix.android.sdk.internal.session.room.alias -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import org.matrix.android.sdk.api.session.room.alias.AliasService internal class DefaultAliasService @AssistedInject constructor( @@ -26,9 +27,9 @@ internal class DefaultAliasService @AssistedInject constructor( private val addRoomAliasTask: AddRoomAliasTask ) : AliasService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): AliasService + fun create(roomId: String): DefaultAliasService } override suspend fun getRoomAliases(): List<String> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DeleteRoomAliasTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DeleteRoomAliasTask.kt index 3400fd994ca79bc981726c72794b6ffd7db3aa65..6ad3db90a92f42be824ee8c53235a022545bb93f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DeleteRoomAliasTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/DeleteRoomAliasTask.kt @@ -16,7 +16,7 @@ package org.matrix.android.sdk.internal.session.room.alias -import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.directory.DirectoryAPI import org.matrix.android.sdk.internal.task.Task @@ -30,11 +30,11 @@ internal interface DeleteRoomAliasTask : Task<DeleteRoomAliasTask.Params, Unit> internal class DefaultDeleteRoomAliasTask @Inject constructor( private val directoryAPI: DirectoryAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : DeleteRoomAliasTask { override suspend fun execute(params: DeleteRoomAliasTask.Params) { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = directoryAPI.deleteRoomAlias( roomAlias = params.roomAlias ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomIdByAliasTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomIdByAliasTask.kt index 543d60570730009cbe5f23a95faef0494024de3d..a53ffc4fcdaba71d05cf0ec0bfb0519bacbd63e0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomIdByAliasTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomIdByAliasTask.kt @@ -18,12 +18,12 @@ package org.matrix.android.sdk.internal.session.room.alias import com.zhuinden.monarchy.Monarchy import io.realm.Realm -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.query.findByAlias import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.directory.DirectoryAPI import org.matrix.android.sdk.internal.task.Task @@ -39,7 +39,7 @@ internal interface GetRoomIdByAliasTask : Task<GetRoomIdByAliasTask.Params, Opti internal class DefaultGetRoomIdByAliasTask @Inject constructor( @SessionDatabase private val monarchy: Monarchy, private val directoryAPI: DirectoryAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetRoomIdByAliasTask { override suspend fun execute(params: GetRoomIdByAliasTask.Params): Optional<RoomAliasDescription> { @@ -52,7 +52,7 @@ internal class DefaultGetRoomIdByAliasTask @Inject constructor( Optional.from(null) } else { val description = tryOrNull("## Failed to get roomId from alias") { - executeRequest<RoomAliasDescription>(eventBus) { + executeRequest<RoomAliasDescription>(globalErrorReceiver) { apiCall = directoryAPI.getRoomIdByAlias(params.roomAlias) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomLocalAliasesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomLocalAliasesTask.kt index 7cfce4ecdcd421d42fc7c68cfeda1734c4cb0ffc..202cb1f6de9ea47249e56d0b557d9441ba44dc91 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomLocalAliasesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomLocalAliasesTask.kt @@ -16,7 +16,7 @@ package org.matrix.android.sdk.internal.session.room.alias -import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task @@ -30,12 +30,12 @@ internal interface GetRoomLocalAliasesTask : Task<GetRoomLocalAliasesTask.Params internal class DefaultGetRoomLocalAliasesTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetRoomLocalAliasesTask { override suspend fun execute(params: GetRoomLocalAliasesTask.Params): List<String> { // We do not check for "org.matrix.msc2432", so the API may be missing - val response = executeRequest<GetAliasesResponse>(eventBus) { + val response = executeRequest<GetAliasesResponse>(globalErrorReceiver) { apiCall = roomAPI.getAliases(roomId = params.roomId) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt index 25ba493891418f86f82b772ce6847ec244ef008f..51a849a35e9f9a190284e09a264cca16ac64da70 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt @@ -16,10 +16,10 @@ package org.matrix.android.sdk.internal.session.room.alias -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.room.alias.RoomAliasError import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.directory.DirectoryAPI import javax.inject.Inject @@ -27,7 +27,7 @@ import javax.inject.Inject internal class RoomAliasAvailabilityChecker @Inject constructor( @UserId private val userId: String, private val directoryAPI: DirectoryAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) { /** * @param aliasLocalPart the local part of the alias. @@ -41,7 +41,7 @@ internal class RoomAliasAvailabilityChecker @Inject constructor( // Check alias availability val fullAlias = aliasLocalPart.toFullLocalAlias(userId) try { - executeRequest<RoomAliasDescription>(eventBus) { + executeRequest<RoomAliasDescription>(globalErrorReceiver) { apiCall = directoryAPI.getRoomIdByAlias(fullAlias) } } catch (throwable: Throwable) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/call/DefaultRoomCallService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/call/DefaultRoomCallService.kt index 205a085df6c27ea4593d2a4c2e879157138bbfde..9bde5054f6c24f65fb21b823322ed42e1df1d5a6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/call/DefaultRoomCallService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/call/DefaultRoomCallService.kt @@ -16,8 +16,9 @@ package org.matrix.android.sdk.internal.session.room.call -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.room.call.RoomCallService import org.matrix.android.sdk.internal.session.room.RoomGetter @@ -27,9 +28,9 @@ internal class DefaultRoomCallService @AssistedInject constructor( private val roomGetter: RoomGetter ) : RoomCallService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): RoomCallService + fun create(roomId: String): DefaultRoomCallService } override fun canStartCall(): Boolean { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt index fb840b4eb3f23793db212150e034f8e9f4626748..5e823fc87fe015d89c0eadb0f980c64c77a042c5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt @@ -143,9 +143,11 @@ internal class CreateRoomBodyBuilder @Inject constructor( } private suspend fun canEnableEncryption(params: CreateRoomParams): Boolean { - return (params.enableEncryptionIfInvitedUsersSupportIt - && crossSigningService.isCrossSigningVerified() - && params.invite3pids.isEmpty()) + return params.enableEncryptionIfInvitedUsersSupportIt + // Parity with web, enable if users have encryption ready devices + // for now remove checks on cross signing and 3pid invites + // && crossSigningService.isCrossSigningVerified() + && params.invite3pids.isEmpty() && params.invitedUserIds.isNotEmpty() && params.invitedUserIds.let { userIds -> val keys = deviceListManager.downloadKeys(userIds, forceDownload = false) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt index ef792ab98e5e57f721d449f9e382245003b51824..9c16bd1b0f2214ec1d56a9f3eb448145fa6f3b78 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt @@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.session.room.create import com.zhuinden.monarchy.Monarchy import io.realm.RealmConfiguration import kotlinx.coroutines.TimeoutCancellationException -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.MatrixError import org.matrix.android.sdk.api.session.room.alias.RoomAliasError @@ -32,6 +31,7 @@ import org.matrix.android.sdk.internal.database.model.RoomEntityFields import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.session.room.alias.RoomAliasAvailabilityChecker @@ -55,7 +55,7 @@ internal class DefaultCreateRoomTask @Inject constructor( @SessionDatabase private val realmConfiguration: RealmConfiguration, private val createRoomBodyBuilder: CreateRoomBodyBuilder, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : CreateRoomTask { override suspend fun execute(params: CreateRoomParams): String { @@ -75,7 +75,7 @@ internal class DefaultCreateRoomTask @Inject constructor( val createRoomBody = createRoomBodyBuilder.build(params) val createRoomResponse = try { - executeRequest<CreateRoomResponse>(eventBus) { + executeRequest<CreateRoomResponse>(globalErrorReceiver) { apiCall = roomAPI.createRoom(createRoomBody) } } catch (throwable: Throwable) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetPublicRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetPublicRoomTask.kt index f2bd0c5f69c562aaba34a496bad0d027bd83a45e..edd8ae9b0dfe9a0531f5ee8179604502ffb0f1e0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetPublicRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetPublicRoomTask.kt @@ -18,10 +18,10 @@ package org.matrix.android.sdk.internal.session.room.directory import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetPublicRoomTask : Task<GetPublicRoomTask.Params, PublicRoomsResponse> { @@ -33,11 +33,11 @@ internal interface GetPublicRoomTask : Task<GetPublicRoomTask.Params, PublicRoom internal class DefaultGetPublicRoomTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetPublicRoomTask { override suspend fun execute(params: GetPublicRoomTask.Params): PublicRoomsResponse { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomAPI.publicRooms(params.server, params.publicRoomsParams) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetRoomDirectoryVisibilityTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetRoomDirectoryVisibilityTask.kt index fbdd6a03ebad946b967304bd9b50af71393e8a67..8d71001ef958345e5e8fe97703a8536111a61bbc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetRoomDirectoryVisibilityTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetRoomDirectoryVisibilityTask.kt @@ -16,8 +16,8 @@ package org.matrix.android.sdk.internal.session.room.directory -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.directory.DirectoryAPI import org.matrix.android.sdk.internal.session.directory.RoomDirectoryVisibilityJson @@ -32,11 +32,11 @@ internal interface GetRoomDirectoryVisibilityTask : Task<GetRoomDirectoryVisibil internal class DefaultGetRoomDirectoryVisibilityTask @Inject constructor( private val directoryAPI: DirectoryAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetRoomDirectoryVisibilityTask { override suspend fun execute(params: GetRoomDirectoryVisibilityTask.Params): RoomDirectoryVisibility { - return executeRequest<RoomDirectoryVisibilityJson>(eventBus) { + return executeRequest<RoomDirectoryVisibilityJson>(globalErrorReceiver) { apiCall = directoryAPI.getRoomDirectoryVisibility(params.roomId) } .visibility diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetThirdPartyProtocolsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetThirdPartyProtocolsTask.kt index 5e08284706b4acd596a8ecae061cde7e24b99916..3477aa671ea6ba1283a598e31685e6ca2070a72c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetThirdPartyProtocolsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/GetThirdPartyProtocolsTask.kt @@ -17,21 +17,21 @@ package org.matrix.android.sdk.internal.session.room.directory import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetThirdPartyProtocolsTask : Task<Unit, Map<String, ThirdPartyProtocol>> internal class DefaultGetThirdPartyProtocolsTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetThirdPartyProtocolsTask { override suspend fun execute(params: Unit): Map<String, ThirdPartyProtocol> { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomAPI.thirdPartyProtocols() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/SetRoomDirectoryVisibilityTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/SetRoomDirectoryVisibilityTask.kt index 33b12aa1ca025d6ef8c10566988902e675a6fdcf..cbb0b6d5d1b85259fe308ad6652823fa51933316 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/SetRoomDirectoryVisibilityTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/directory/SetRoomDirectoryVisibilityTask.kt @@ -16,8 +16,8 @@ package org.matrix.android.sdk.internal.session.room.directory -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.directory.DirectoryAPI import org.matrix.android.sdk.internal.session.directory.RoomDirectoryVisibilityJson @@ -33,11 +33,11 @@ internal interface SetRoomDirectoryVisibilityTask : Task<SetRoomDirectoryVisibil internal class DefaultSetRoomDirectoryVisibilityTask @Inject constructor( private val directoryAPI: DirectoryAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SetRoomDirectoryVisibilityTask { override suspend fun execute(params: SetRoomDirectoryVisibilityTask.Params) { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = directoryAPI.setRoomDirectoryVisibility( params.roomId, RoomDirectoryVisibilityJson(visibility = params.roomDirectoryVisibility) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt index 93fbfb4df0c4fc967d8ba1a46dae51f7271ea295..1d4ab6d516c3d7345c27a480c2f5b4345444679d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt @@ -17,8 +17,9 @@ package org.matrix.android.sdk.internal.session.room.draft import androidx.lifecycle.LiveData -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.session.room.send.DraftService import org.matrix.android.sdk.api.session.room.send.UserDraft @@ -30,9 +31,9 @@ internal class DefaultDraftService @AssistedInject constructor(@Assisted private private val coroutineDispatchers: MatrixCoroutineDispatchers ) : DraftService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): DraftService + fun create(roomId: String): DefaultDraftService } /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/DefaultMembershipService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/DefaultMembershipService.kt index 4fc865304b27a2c0c4fd6583b24b33780e0eaa6e..cd1c9bbbdd8e56a7f32ec0eb26cc24956320bc5a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/DefaultMembershipService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/DefaultMembershipService.kt @@ -17,8 +17,9 @@ package org.matrix.android.sdk.internal.session.room.membership import androidx.lifecycle.LiveData -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.identity.ThreePid @@ -58,9 +59,9 @@ internal class DefaultMembershipService @AssistedInject constructor( private val userId: String ) : MembershipService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): MembershipService + fun create(roomId: String): DefaultMembershipService } override fun loadRoomMembersIfNeeded(matrixCallback: MatrixCallback<Unit>): Cancelable { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt index 627f927ad88e1965f783ab3d4e98146736075ad1..2be90bf8e3aa21618acc985d9e031c9787182343 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt @@ -17,25 +17,30 @@ package org.matrix.android.sdk.internal.session.room.membership import com.zhuinden.monarchy.Monarchy +import io.realm.Realm +import io.realm.kotlin.createObject +import kotlinx.coroutines.TimeoutCancellationException import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.send.SendState +import org.matrix.android.sdk.internal.database.awaitNotEmptyResult import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity import org.matrix.android.sdk.internal.database.model.EventInsertType import org.matrix.android.sdk.internal.database.model.RoomEntity +import org.matrix.android.sdk.internal.database.model.RoomEntityFields +import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater import org.matrix.android.sdk.internal.session.sync.SyncTokenStore import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction -import io.realm.Realm -import io.realm.kotlin.createObject -import org.greenrobot.eventbus.EventBus +import java.util.concurrent.TimeUnit import javax.inject.Inject internal interface LoadRoomMembersTask : Task<LoadRoomMembersTask.Params, Unit> { @@ -52,17 +57,44 @@ internal class DefaultLoadRoomMembersTask @Inject constructor( private val syncTokenStore: SyncTokenStore, private val roomSummaryUpdater: RoomSummaryUpdater, private val roomMemberEventHandler: RoomMemberEventHandler, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : LoadRoomMembersTask { override suspend fun execute(params: LoadRoomMembersTask.Params) { - if (areAllMembersAlreadyLoaded(params.roomId)) { - return + when (getRoomMembersLoadStatus(params.roomId)) { + RoomMembersLoadStatusType.NONE -> doRequest(params) + RoomMembersLoadStatusType.LOADING -> waitPreviousRequestToFinish(params) + RoomMembersLoadStatusType.LOADED -> Unit + } + } + + private suspend fun waitPreviousRequestToFinish(params: LoadRoomMembersTask.Params) { + try { + awaitNotEmptyResult(monarchy.realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm -> + realm.where(RoomEntity::class.java) + .equalTo(RoomEntityFields.ROOM_ID, params.roomId) + .equalTo(RoomEntityFields.MEMBERS_LOAD_STATUS_STR, RoomMembersLoadStatusType.LOADED.name) + } + } catch (exception: TimeoutCancellationException) { + // Timeout, do the request anyway (?) + doRequest(params) } + } + + private suspend fun doRequest(params: LoadRoomMembersTask.Params) { + setRoomMembersLoadStatus(params.roomId, RoomMembersLoadStatusType.LOADING) + val lastToken = syncTokenStore.getLastToken() - val response = executeRequest<RoomMembersResponse>(eventBus) { - apiCall = roomAPI.getMembers(params.roomId, lastToken, null, params.excludeMembership?.value) + val response = try { + executeRequest<RoomMembersResponse>(globalErrorReceiver) { + apiCall = roomAPI.getMembers(params.roomId, lastToken, null, params.excludeMembership?.value) + } + } catch (throwable: Throwable) { + // Revert status to NONE + setRoomMembersLoadStatus(params.roomId, RoomMembersLoadStatusType.NONE) + throw throwable } + // This will also set the status to LOADED insertInDb(response, params.roomId) } @@ -84,14 +116,23 @@ internal class DefaultLoadRoomMembersTask @Inject constructor( } roomMemberEventHandler.handle(realm, roomId, roomMemberEvent) } - roomEntity.areAllMembersLoaded = true + roomEntity.membersLoadStatus = RoomMembersLoadStatusType.LOADED roomSummaryUpdater.update(realm, roomId, updateMembers = true) } } - private fun areAllMembersAlreadyLoaded(roomId: String): Boolean { - return Realm.getInstance(monarchy.realmConfiguration).use { - RoomEntity.where(it, roomId).findFirst()?.areAllMembersLoaded ?: false + private fun getRoomMembersLoadStatus(roomId: String): RoomMembersLoadStatusType { + var result: RoomMembersLoadStatusType? + Realm.getInstance(monarchy.realmConfiguration).use { + result = RoomEntity.where(it, roomId).findFirst()?.membersLoadStatus + } + return result ?: RoomMembersLoadStatusType.NONE + } + + private suspend fun setRoomMembersLoadStatus(roomId: String, status: RoomMembersLoadStatusType) { + monarchy.awaitTransaction { realm -> + val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId) + roomEntity.membersLoadStatus = status } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/InviteTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/InviteTask.kt index 854a332679306a273615402b9be92c0e8edc6d0d..05503bd6436742c551a6991463b1fd0b98fc51d5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/InviteTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/InviteTask.kt @@ -16,10 +16,10 @@ package org.matrix.android.sdk.internal.session.room.membership.joining +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface InviteTask : Task<InviteTask.Params, Unit> { @@ -32,11 +32,11 @@ internal interface InviteTask : Task<InviteTask.Params, Unit> { internal class DefaultInviteTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : InviteTask { override suspend fun execute(params: InviteTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { val body = InviteBody(params.userId, params.reason) apiCall = roomAPI.invite(params.roomId, body) isRetryable = true diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt index dd1dc5fa8a6bc5bc60673631d2eb470ca5a0a212..3b7639d42fa28b0fd4f9693451a8e23144c598f8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt @@ -30,7 +30,7 @@ import org.matrix.android.sdk.internal.session.room.read.SetReadMarkersTask import org.matrix.android.sdk.internal.task.Task import io.realm.RealmConfiguration import kotlinx.coroutines.TimeoutCancellationException -import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -48,14 +48,18 @@ internal class DefaultJoinRoomTask @Inject constructor( @SessionDatabase private val realmConfiguration: RealmConfiguration, private val roomChangeMembershipStateDataSource: RoomChangeMembershipStateDataSource, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : JoinRoomTask { override suspend fun execute(params: JoinRoomTask.Params) { roomChangeMembershipStateDataSource.updateState(params.roomIdOrAlias, ChangeMembershipState.Joining) val joinRoomResponse = try { - executeRequest<JoinRoomResponse>(eventBus) { - apiCall = roomAPI.join(params.roomIdOrAlias, params.viaServers, mapOf("reason" to params.reason)) + executeRequest<JoinRoomResponse>(globalErrorReceiver) { + apiCall = roomAPI.join( + roomIdOrAlias = params.roomIdOrAlias, + viaServers = params.viaServers.take(3), + params = mapOf("reason" to params.reason) + ) } } catch (failure: Throwable) { roomChangeMembershipStateDataSource.updateState(params.roomIdOrAlias, ChangeMembershipState.FailedJoining(failure)) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/leaving/LeaveRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/leaving/LeaveRoomTask.kt index 58e34a15ecb12009052ed735398f72377faab4ae..37bb7570d17d599ab2e984ed4da88b343a1647c4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/leaving/LeaveRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/leaving/LeaveRoomTask.kt @@ -21,13 +21,13 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import timber.log.Timber import javax.inject.Inject @@ -40,7 +40,7 @@ internal interface LeaveRoomTask : Task<LeaveRoomTask.Params, Unit> { internal class DefaultLeaveRoomTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus, + private val globalErrorReceiver: GlobalErrorReceiver, private val stateEventDataSource: StateEventDataSource, private val roomSummaryDataSource: RoomSummaryDataSource, private val roomChangeMembershipStateDataSource: RoomChangeMembershipStateDataSource @@ -68,7 +68,7 @@ internal class DefaultLeaveRoomTask @Inject constructor( leaveRoom(predecessorRoomId, reason) } try { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = roomAPI.leave(roomId, mapOf("reason" to reason)) } } catch (failure: Throwable) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/InviteThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/InviteThreePidTask.kt index 80af00fc7863f6b56447b4cb4fa9e8166b0d4e7f..d237ec795e2334b2ad92c8c75e2dbe35ba57bbb6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/InviteThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/InviteThreePidTask.kt @@ -16,11 +16,11 @@ package org.matrix.android.sdk.internal.session.room.membership.threepid -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.identity.IdentityServiceError import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.toMedium import org.matrix.android.sdk.internal.di.AuthenticatedIdentity +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.network.token.AccessTokenProvider import org.matrix.android.sdk.internal.session.identity.EnsureIdentityTokenTask @@ -39,7 +39,7 @@ internal interface InviteThreePidTask : Task<InviteThreePidTask.Params, Unit> { internal class DefaultInviteThreePidTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus, + private val globalErrorReceiver: GlobalErrorReceiver, private val identityStore: IdentityStore, private val ensureIdentityTokenTask: EnsureIdentityTokenTask, @AuthenticatedIdentity @@ -52,7 +52,7 @@ internal class DefaultInviteThreePidTask @Inject constructor( val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() ?: throw IdentityServiceError.NoIdentityServerConfigured val identityServerAccessToken = accessTokenProvider.getToken() ?: throw IdentityServiceError.NoIdentityServerConfigured - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { val body = ThreePidInviteBody( idServer = identityServerUrlWithoutProtocol, idAccessToken = identityServerAccessToken, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt index 67ae55c066e28b59d4fff26d8691928f20a0b94f..5486d96e2898f8fe216c9bb5c89d91e4ec4153cc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt @@ -18,8 +18,9 @@ package org.matrix.android.sdk.internal.session.room.notification import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.api.pushrules.RuleScope import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState @@ -33,9 +34,9 @@ internal class DefaultRoomPushRuleService @AssistedInject constructor(@Assisted @SessionDatabase private val monarchy: Monarchy) : RoomPushRuleService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): RoomPushRuleService + fun create(roomId: String): DefaultRoomPushRuleService } override fun getLiveRoomNotificationState(): LiveData<RoomNotificationState> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/ResolveRoomStateTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/ResolveRoomStateTask.kt index 03ea2408f0956782f66d7fb10a76cf18db23482f..dbec6b555c6fa791b43c5c9fbe2417298c9f9f6e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/ResolveRoomStateTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/ResolveRoomStateTask.kt @@ -16,8 +16,8 @@ package org.matrix.android.sdk.internal.session.room.peeking -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task @@ -31,11 +31,11 @@ internal interface ResolveRoomStateTask : Task<ResolveRoomStateTask.Params, List internal class DefaultResolveRoomStateTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : ResolveRoomStateTask { override suspend fun execute(params: ResolveRoomStateTask.Params): List<Event> { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomAPI.getRoomState(params.roomId) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/read/DefaultReadService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/read/DefaultReadService.kt index 025bea09f4c69617c6a767b50ecd5979aa40d386..3cf8cfe5eef3d8f181004a51b666cb07347c3448 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/read/DefaultReadService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/read/DefaultReadService.kt @@ -18,8 +18,9 @@ package org.matrix.android.sdk.internal.session.room.read import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.room.model.ReadReceipt @@ -46,9 +47,9 @@ internal class DefaultReadService @AssistedInject constructor( @UserId private val userId: String ) : ReadService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): ReadService + fun create(roomId: String): DefaultReadService } override fun markAsRead(params: ReadService.MarkAsReadParams, callback: MatrixCallback<Unit>) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/read/SetReadMarkersTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/read/SetReadMarkersTask.kt index a98bb02c83a0f18be56bb426aa873c2efb38f78b..c7f962a699349900f6fba87f8d8f0d85470c1914 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/read/SetReadMarkersTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/read/SetReadMarkersTask.kt @@ -33,7 +33,7 @@ import org.matrix.android.sdk.internal.session.sync.RoomFullyReadHandler import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction import io.realm.Realm -import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import timber.log.Timber import javax.inject.Inject import kotlin.collections.set @@ -58,7 +58,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor( private val roomFullyReadHandler: RoomFullyReadHandler, private val readReceiptHandler: ReadReceiptHandler, @UserId private val userId: String, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SetReadMarkersTask { override suspend fun execute(params: SetReadMarkersTask.Params) { @@ -96,7 +96,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor( updateDatabase(params.roomId, markers, shouldUpdateRoomSummary) } if (markers.isNotEmpty()) { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { isRetryable = true apiCall = roomAPI.sendReadMarker(params.roomId, markers) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt index a7f3f839807d13ab924cf64a3803ea7c77dfa354..b7caf62865ab6c26216f9486ae91282766b8a282 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt @@ -17,8 +17,9 @@ package org.matrix.android.sdk.internal.session.room.relation import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.events.model.Event @@ -56,9 +57,9 @@ internal class DefaultRelationService @AssistedInject constructor( private val taskExecutor: TaskExecutor) : RelationService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): RelationService + fun create(roomId: String): DefaultRelationService } override fun sendReaction(targetEventId: String, reaction: String): Cancelable { @@ -140,7 +141,7 @@ internal class DefaultRelationService @AssistedInject constructor( } override fun fetchEditHistory(eventId: String, callback: MatrixCallback<List<Event>>) { - val params = FetchEditHistoryTask.Params(roomId, cryptoSessionInfoProvider.isRoomEncrypted(roomId), eventId) + val params = FetchEditHistoryTask.Params(roomId, eventId) fetchEditHistoryTask .configureWith(params) { this.callback = callback diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt index 51eecb8c2a8d604235d2149dc179161c2bcf03ee..854585ca2935654197edb19b83363f75df2b6d56 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt @@ -18,32 +18,35 @@ package org.matrix.android.sdk.internal.session.room.relation import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.RelationType +import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface FetchEditHistoryTask : Task<FetchEditHistoryTask.Params, List<Event>> { - data class Params( val roomId: String, - val isRoomEncrypted: Boolean, val eventId: String ) } internal class DefaultFetchEditHistoryTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver, + private val cryptoSessionInfoProvider: CryptoSessionInfoProvider ) : FetchEditHistoryTask { override suspend fun execute(params: FetchEditHistoryTask.Params): List<Event> { - val response = executeRequest<RelationsResponse>(eventBus) { - apiCall = roomAPI.getRelations(params.roomId, - params.eventId, - RelationType.REPLACE, - if (params.isRoomEncrypted) EventType.ENCRYPTED else EventType.MESSAGE) + val isRoomEncrypted = cryptoSessionInfoProvider.isRoomEncrypted(params.roomId) + val response = executeRequest<RelationsResponse>(globalErrorReceiver) { + apiCall = roomAPI.getRelations( + roomId = params.roomId, + eventId = params.eventId, + relationType = RelationType.REPLACE, + eventType = if (isRoomEncrypted) EventType.ENCRYPTED else EventType.MESSAGE + ) } val events = response.chunks.toMutableList() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/SendRelationWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/SendRelationWorker.kt index 25dfe32cbb04753a7955e78dd0867a1a9a272105..c12597bea0a44d7efeac40ea7039a787727c8578 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/SendRelationWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/SendRelationWorker.kt @@ -18,12 +18,12 @@ package org.matrix.android.sdk.internal.session.room.relation import android.content.Context import androidx.work.WorkerParameters import com.squareup.moshi.JsonClass -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent import org.matrix.android.sdk.api.session.room.model.relation.ReactionInfo +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.SessionComponent import org.matrix.android.sdk.internal.session.room.RoomAPI @@ -47,7 +47,7 @@ internal class SendRelationWorker(context: Context, params: WorkerParameters) ) : SessionWorkerParams @Inject lateinit var roomAPI: RoomAPI - @Inject lateinit var eventBus: EventBus + @Inject lateinit var globalErrorReceiver: GlobalErrorReceiver @Inject lateinit var localEchoRepository: LocalEchoRepository override fun injectWith(injector: SessionComponent) { @@ -84,7 +84,7 @@ internal class SendRelationWorker(context: Context, params: WorkerParameters) } private suspend fun sendRelation(roomId: String, relationType: String, relatedEventId: String, localEvent: Event) { - executeRequest<SendResponse>(eventBus) { + executeRequest<SendResponse>(globalErrorReceiver) { apiCall = roomAPI.sendRelation( roomId = roomId, parentId = relatedEventId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt index cac87a9d30cf3ff2b6b5727582192ff5b45a0ad3..add17a9fa581bfc3b8e33641ff003c9eae421fcc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt @@ -16,17 +16,18 @@ package org.matrix.android.sdk.internal.session.room.reporting -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import org.matrix.android.sdk.api.session.room.reporting.ReportingService internal class DefaultReportingService @AssistedInject constructor(@Assisted private val roomId: String, private val reportContentTask: ReportContentTask ) : ReportingService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): ReportingService + fun create(roomId: String): DefaultReportingService } override suspend fun reportContent(eventId: String, score: Int, reason: String) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/ReportContentTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/ReportContentTask.kt index bd1193767688e942f7ddeddc154924eac6a6074b..9c6e9907a4119e88435779f6d850fab12e61a540 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/ReportContentTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/ReportContentTask.kt @@ -16,10 +16,10 @@ package org.matrix.android.sdk.internal.session.room.reporting +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface ReportContentTask : Task<ReportContentTask.Params, Unit> { @@ -33,11 +33,11 @@ internal interface ReportContentTask : Task<ReportContentTask.Params, Unit> { internal class DefaultReportContentTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : ReportContentTask { override suspend fun execute(params: ReportContentTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomAPI.reportContent(params.roomId, params.eventId, ReportContentBody(params.score, params.reason)) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt index 8828f3dfedd466adc7ab9c977f6583581c45b476..a12962b51ffeda75b2fe8006cd4451ced1b0a03a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt @@ -21,8 +21,9 @@ import androidx.work.BackoffPolicy import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequest import androidx.work.Operation -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.events.model.Event @@ -71,9 +72,9 @@ internal class DefaultSendService @AssistedInject constructor( private val cancelSendTracker: CancelSendTracker ) : SendService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): SendService + fun create(roomId: String): DefaultSendService } private val workerFutureListenerExecutor = Executors.newSingleThreadExecutor() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt index f4871ab35dffa93bac399093b2d51b04281f065e..f742271fa703a20f42f60f7451daf93bdf139691 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.session.room.send import com.zhuinden.monarchy.Monarchy import io.realm.Realm -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel @@ -42,7 +41,7 @@ import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater -import org.matrix.android.sdk.internal.session.room.timeline.DefaultTimeline +import org.matrix.android.sdk.internal.session.room.timeline.TimelineInput import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.util.awaitTransaction import timber.log.Timber @@ -52,7 +51,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private private val taskExecutor: TaskExecutor, private val realmSessionProvider: RealmSessionProvider, private val roomSummaryUpdater: RoomSummaryUpdater, - private val eventBus: EventBus, + private val timelineInput: TimelineInput, private val timelineEventMapper: TimelineEventMapper) { fun createLocalEcho(event: Event) { @@ -76,7 +75,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private } } val timelineEvent = timelineEventMapper.map(timelineEventEntity) - eventBus.post(DefaultTimeline.OnLocalEchoCreated(roomId = roomId, timelineEvent = timelineEvent)) + timelineInput.onLocalEchoCreated(roomId = roomId, timelineEvent = timelineEvent) taskExecutor.executorScope.asyncTransaction(monarchy) { realm -> val eventInsertEntity = EventInsertEntity(event.eventId, event.type).apply { this.insertType = EventInsertType.LOCAL_ECHO @@ -90,7 +89,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private fun updateSendState(eventId: String, roomId: String?, sendState: SendState) { Timber.v("## SendEvent: [${System.currentTimeMillis()}] Update local state of $eventId to ${sendState.name}") - eventBus.post(DefaultTimeline.OnLocalEchoUpdated(roomId ?: "", eventId, sendState)) + timelineInput.onLocalEchoUpdated(roomId = roomId ?: "", eventId = eventId, sendState = sendState) updateEchoAsync(eventId) { realm, sendingEventEntity -> if (sendState == SendState.SENT && sendingEventEntity.sendState == SendState.SYNCED) { // If already synced, do not put as sent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt index 682865eaee17b3e834f335dd9db7e07379721c5b..c901c7e18eb0d72c1c95ce56cdcf1f4b29e68d49 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt @@ -18,8 +18,8 @@ package org.matrix.android.sdk.internal.session.room.send import android.content.Context import androidx.work.WorkerParameters import com.squareup.moshi.JsonClass -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.failure.Failure +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.SessionComponent import org.matrix.android.sdk.internal.session.room.RoomAPI @@ -46,7 +46,7 @@ internal class RedactEventWorker(context: Context, params: WorkerParameters) ) : SessionWorkerParams @Inject lateinit var roomAPI: RoomAPI - @Inject lateinit var eventBus: EventBus + @Inject lateinit var globalErrorReceiver: GlobalErrorReceiver override fun injectWith(injector: SessionComponent) { injector.inject(this) @@ -55,7 +55,7 @@ internal class RedactEventWorker(context: Context, params: WorkerParameters) override suspend fun doSafeWork(params: Params): Result { val eventId = params.eventId return runCatching { - executeRequest<SendResponse>(eventBus) { + executeRequest<SendResponse>(globalErrorReceiver) { apiCall = roomAPI.redactEvent( params.txID, params.roomId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt index 37a429d2429f0db91778fc904da111eaded95fb7..c1fc2fd9fee405d1f0936a8b44bb8477b8f377a4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt @@ -20,7 +20,6 @@ import android.content.Context import androidx.work.WorkerParameters import com.squareup.moshi.JsonClass import io.realm.RealmConfiguration -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.failure.shouldBeRetried import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.room.send.SendState @@ -54,7 +53,6 @@ internal class SendEventWorker(context: Context, @Inject lateinit var localEchoRepository: LocalEchoRepository @Inject lateinit var sendEventTask: SendEventTask @Inject lateinit var cryptoService: CryptoService - @Inject lateinit var eventBus: EventBus @Inject lateinit var cancelSendTracker: CancelSendTracker @SessionDatabase @Inject lateinit var realmConfiguration: RealmConfiguration diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt index b546584450796b14def12b0be59ed122481a50eb..f2640fd1e733d21629f505d8a3b3a4434403273a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt @@ -18,8 +18,9 @@ package org.matrix.android.sdk.internal.session.room.state import android.net.Uri import androidx.lifecycle.LiveData -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType @@ -35,18 +36,16 @@ import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.MimeTypes import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.session.content.FileUploader -import org.matrix.android.sdk.internal.session.room.alias.AddRoomAliasTask internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String, private val stateEventDataSource: StateEventDataSource, private val sendStateTask: SendStateTask, - private val fileUploader: FileUploader, - private val addRoomAliasTask: AddRoomAliasTask + private val fileUploader: FileUploader ) : StateService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): StateService + fun create(roomId: String): DefaultStateService } override fun getStateEvent(eventType: String, stateKey: QueryStringValue): Event? { @@ -74,11 +73,19 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private roomId = roomId, stateKey = stateKey, eventType = eventType, - body = body + body = body.toSafeJson(eventType) ) sendStateTask.execute(params) } + private fun JsonDict.toSafeJson(eventType: String): JsonDict { + // Safe treatment for PowerLevelContent + return when (eventType) { + EventType.STATE_ROOM_POWER_LEVELS -> toSafePowerLevelsContentDict() + else -> this + } + } + override suspend fun updateTopic(topic: String) { sendStateEvent( eventType = EventType.STATE_ROOM_TOPIC, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt new file mode 100644 index 0000000000000000000000000000000000000000..a97709e38ba2d1d3e0b83a99503ab93c0e99cb4b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.state + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent +import org.matrix.android.sdk.api.session.room.powerlevels.Role +import org.matrix.android.sdk.api.util.JsonDict + +@JsonClass(generateAdapter = true) +internal data class SerializablePowerLevelsContent( + @Json(name = "ban") val ban: Int = Role.Moderator.value, + @Json(name = "kick") val kick: Int = Role.Moderator.value, + @Json(name = "invite") val invite: Int = Role.Moderator.value, + @Json(name = "redact") val redact: Int = Role.Moderator.value, + @Json(name = "events_default") val eventsDefault: Int = Role.Default.value, + @Json(name = "events") val events: Map<String, Int> = emptyMap(), + @Json(name = "users_default") val usersDefault: Int = Role.Default.value, + @Json(name = "users") val users: Map<String, Int> = emptyMap(), + @Json(name = "state_default") val stateDefault: Int = Role.Moderator.value, + // `Int` is the diff here (instead of `Any`) + @Json(name = "notifications") val notifications: Map<String, Int> = emptyMap() +) + +internal fun JsonDict.toSafePowerLevelsContentDict(): JsonDict { + return toModel<PowerLevelsContent>() + ?.let { content -> + SerializablePowerLevelsContent( + ban = content.ban, + kick = content.kick, + invite = content.invite, + redact = content.redact, + eventsDefault = content.eventsDefault, + events = content.events, + usersDefault = content.usersDefault, + users = content.users, + stateDefault = content.stateDefault, + notifications = content.notifications.mapValues { content.notificationLevel(it.key) } + ) + } + ?.toContent() + ?: emptyMap() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt index 642f68c15b61a6ff41670a86e09c7306ce3b3639..63691d9207e816109f0f3a8fdc24dd8a0f91d77c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SendStateTask.kt @@ -17,10 +17,10 @@ package org.matrix.android.sdk.internal.session.room.state import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface SendStateTask : Task<SendStateTask.Params, Unit> { @@ -34,11 +34,11 @@ internal interface SendStateTask : Task<SendStateTask.Params, Unit> { internal class DefaultSendStateTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SendStateTask { override suspend fun execute(params: SendStateTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = if (params.stateKey == null) { roomAPI.sendStateEvent( roomId = params.roomId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index 8c71604183f234f79497ab8be66a8c96299ac96f..fff780fb0c65ce5d063d502c087797424c700394 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -140,14 +140,13 @@ internal class RoomSummaryUpdater @Inject constructor( .queryActiveRoomMembersEvent() .notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId) .findAll() - .asSequence() .map { it.userId } roomSummaryEntity.otherMemberIds.clear() roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers) if (roomSummaryEntity.isEncrypted) { // mmm maybe we could only refresh shield instead of checking trust also? - crossSigningService.onUsersDeviceUpdate(roomSummaryEntity.otherMemberIds.toList()) + crossSigningService.onUsersDeviceUpdate(otherRoomMembers) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/AddTagToRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/AddTagToRoomTask.kt index 013fc86d5c9409d2ba09e9d825c0c3bceecfd91b..c3b5c3f78fa2448e6099b7167efb77562ad89323 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/AddTagToRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/AddTagToRoomTask.kt @@ -17,10 +17,10 @@ package org.matrix.android.sdk.internal.session.room.tags import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface AddTagToRoomTask : Task<AddTagToRoomTask.Params, Unit> { @@ -35,11 +35,11 @@ internal interface AddTagToRoomTask : Task<AddTagToRoomTask.Params, Unit> { internal class DefaultAddTagToRoomTask @Inject constructor( private val roomAPI: RoomAPI, @UserId private val userId: String, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : AddTagToRoomTask { override suspend fun execute(params: AddTagToRoomTask.Params) { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = roomAPI.putTag( userId = userId, roomId = params.roomId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DefaultTagsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DefaultTagsService.kt index d6c02f0a49b4d3297b4dcc95fac9412e2030800f..02acaa057044908dce1df587f0c30f5d5bb42c8a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DefaultTagsService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DefaultTagsService.kt @@ -16,8 +16,9 @@ package org.matrix.android.sdk.internal.session.room.tags -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import org.matrix.android.sdk.api.session.room.tags.TagsService internal class DefaultTagsService @AssistedInject constructor( @@ -26,9 +27,9 @@ internal class DefaultTagsService @AssistedInject constructor( private val deleteTagFromRoomTask: DeleteTagFromRoomTask ) : TagsService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): TagsService + fun create(roomId: String): DefaultTagsService } override suspend fun addTag(tag: String, order: Double?) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DeleteTagFromRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DeleteTagFromRoomTask.kt index b22355d4319471faad78de681afce587ca6c2a22..d578d21fde13c558aa488a3cd5b89232f28d2b86 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DeleteTagFromRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DeleteTagFromRoomTask.kt @@ -17,10 +17,10 @@ package org.matrix.android.sdk.internal.session.room.tags import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface DeleteTagFromRoomTask : Task<DeleteTagFromRoomTask.Params, Unit> { @@ -34,11 +34,11 @@ internal interface DeleteTagFromRoomTask : Task<DeleteTagFromRoomTask.Params, Un internal class DefaultDeleteTagFromRoomTask @Inject constructor( private val roomAPI: RoomAPI, @UserId private val userId: String, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : DeleteTagFromRoomTask { override suspend fun execute(params: DeleteTagFromRoomTask.Params) { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = roomAPI.deleteTag( userId = userId, roomId = params.roomId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index 86b0497bd0e78c867a865e18ae921a4aa38cc83b..ae90282d52d2e49dad52cf82021c3b9c6bac8ea8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -23,10 +23,8 @@ import io.realm.RealmConfiguration import io.realm.RealmQuery import io.realm.RealmResults import io.realm.Sort -import org.greenrobot.eventbus.EventBus -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.events.model.EventType @@ -53,6 +51,7 @@ import org.matrix.android.sdk.internal.database.query.filterEvents import org.matrix.android.sdk.internal.database.query.findAllInRoomWithSendStates import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.database.query.whereRoomId +import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.util.Debouncer @@ -79,14 +78,13 @@ internal class DefaultTimeline( private val timelineEventMapper: TimelineEventMapper, private val settings: TimelineSettings, private val hiddenReadReceipts: TimelineHiddenReadReceipts, - private val eventBus: EventBus, + private val timelineInput: TimelineInput, private val eventDecryptor: TimelineEventDecryptor, - private val realmSessionProvider: RealmSessionProvider -) : Timeline, TimelineHiddenReadReceipts.Delegate { - - data class OnNewTimelineEvents(val roomId: String, val eventIds: List<String>) - data class OnLocalEchoCreated(val roomId: String, val timelineEvent: TimelineEvent) - data class OnLocalEchoUpdated(val roomId: String, val eventId: String, val sendState: SendState) + private val realmSessionProvider: RealmSessionProvider, + private val loadRoomMembersTask: LoadRoomMembersTask +) : Timeline, + TimelineHiddenReadReceipts.Delegate, + TimelineInput.Listener { companion object { val BACKGROUND_HANDLER = createBackgroundHandler("TIMELINE_DB_THREAD") @@ -158,7 +156,7 @@ internal class DefaultTimeline( override fun start() { if (isStarted.compareAndSet(false, true)) { Timber.v("Start timeline for roomId: $roomId and eventId: $initialEventId") - eventBus.register(this) + timelineInput.listeners.add(this) BACKGROUND_HANDLER.post { eventDecryptor.start() val realm = Realm.getInstance(realmConfiguration) @@ -184,6 +182,13 @@ internal class DefaultTimeline( if (settings.shouldHandleHiddenReadReceipts()) { hiddenReadReceipts.start(realm, filteredEvents, nonFilteredEvents, this) } + + loadRoomMembersTask + .configureWith(LoadRoomMembersTask.Params(roomId)) { + this.callback = NoOpMatrixCallback() + } + .executeBy(taskExecutor) + isReady.set(true) } } @@ -196,7 +201,7 @@ internal class DefaultTimeline( override fun dispose() { if (isStarted.compareAndSet(true, false)) { isReady.set(false) - eventBus.unregister(this) + timelineInput.listeners.remove(this) Timber.v("Dispose timeline for roomId: $roomId and eventId: $initialEventId") cancelableBag.cancel() BACKGROUND_HANDLER.removeCallbacksAndMessages(null) @@ -313,25 +318,22 @@ internal class DefaultTimeline( postSnapshot() } - @Subscribe(threadMode = ThreadMode.MAIN) - fun onNewTimelineEvents(onNewTimelineEvents: OnNewTimelineEvents) { - if (isLive && onNewTimelineEvents.roomId == roomId) { + override fun onNewTimelineEvents(roomId: String, eventIds: List<String>) { + if (isLive && this.roomId == roomId) { listeners.forEach { - it.onNewTimelineEvents(onNewTimelineEvents.eventIds) + it.onNewTimelineEvents(eventIds) } } } - @Subscribe(threadMode = ThreadMode.MAIN) - fun onLocalEchoCreated(onLocalEchoCreated: OnLocalEchoCreated) { - if (uiEchoManager.onLocalEchoCreated(onLocalEchoCreated)) { + override fun onLocalEchoCreated(roomId: String, timelineEvent: TimelineEvent) { + if (uiEchoManager.onLocalEchoCreated(roomId, timelineEvent)) { postSnapshot() } } - @Subscribe(threadMode = ThreadMode.MAIN) - fun onLocalEchoUpdated(onLocalEchoUpdated: OnLocalEchoUpdated) { - if (uiEchoManager.onLocalEchoUpdated(onLocalEchoUpdated)) { + override fun onLocalEchoUpdated(roomId: String, eventId: String, sendState: SendState) { + if (uiEchoManager.onLocalEchoUpdated(roomId, eventId, sendState)) { postSnapshot() } } @@ -848,11 +850,11 @@ internal class DefaultTimeline( } } - fun onLocalEchoUpdated(onLocalEchoUpdated: OnLocalEchoUpdated): Boolean { - if (isLive && onLocalEchoUpdated.roomId == roomId) { - val existingState = inMemorySendingStates[onLocalEchoUpdated.eventId] - inMemorySendingStates[onLocalEchoUpdated.eventId] = onLocalEchoUpdated.sendState - if (existingState != onLocalEchoUpdated.sendState) { + fun onLocalEchoUpdated(roomId: String, eventId: String, sendState: SendState): Boolean { + if (isLive && roomId == this@DefaultTimeline.roomId) { + val existingState = inMemorySendingStates[eventId] + inMemorySendingStates[eventId] = sendState + if (existingState != sendState) { return true } } @@ -860,22 +862,22 @@ internal class DefaultTimeline( } // return true if should update - fun onLocalEchoCreated(onLocalEchoCreated: OnLocalEchoCreated): Boolean { + fun onLocalEchoCreated(roomId: String, timelineEvent: TimelineEvent): Boolean { var postSnapshot = false - if (isLive && onLocalEchoCreated.roomId == roomId) { + if (isLive && roomId == this@DefaultTimeline.roomId) { // Manage some ui echos (do it before filter because actual event could be filtered out) - when (onLocalEchoCreated.timelineEvent.root.getClearType()) { + when (timelineEvent.root.getClearType()) { EventType.REDACTION -> { } EventType.REACTION -> { - val content = onLocalEchoCreated.timelineEvent.root.content?.toModel<ReactionContent>() + val content = timelineEvent.root.content?.toModel<ReactionContent>() if (RelationType.ANNOTATION == content?.relatesTo?.type) { val reaction = content.relatesTo.key val relatedEventID = content.relatesTo.eventId inMemoryReactions.getOrPut(relatedEventID) { mutableListOf() } .add( ReactionUiEchoData( - localEchoId = onLocalEchoCreated.timelineEvent.eventId, + localEchoId = timelineEvent.eventId, reactedOnEventId = relatedEventID, reaction = reaction ) @@ -888,12 +890,12 @@ internal class DefaultTimeline( } // do not add events that would have been filtered - if (listOf(onLocalEchoCreated.timelineEvent).filterEventsWithSettings().isNotEmpty()) { + if (listOf(timelineEvent).filterEventsWithSettings().isNotEmpty()) { listeners.forEach { - it.onNewTimelineEvents(listOf(onLocalEchoCreated.timelineEvent.eventId)) + it.onNewTimelineEvents(listOf(timelineEvent.eventId)) } - Timber.v("On local echo created: ${onLocalEchoCreated.timelineEvent.eventId}") - inMemorySendingEvents.add(0, onLocalEchoCreated.timelineEvent) + Timber.v("On local echo created: ${timelineEvent.eventId}") + inMemorySendingEvents.add(0, timelineEvent) postSnapshot = true } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt index 783aa53ddf725469e62e2bbf2f0c451b3f6dc50b..ef890db79e75947032a4208da4096ff0a7d24ed0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt @@ -18,12 +18,12 @@ package org.matrix.android.sdk.internal.session.room.timeline import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import com.zhuinden.monarchy.Monarchy import io.realm.Sort import io.realm.kotlin.where -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.events.model.isImageMessage import org.matrix.android.sdk.api.session.events.model.isVideoMessage import org.matrix.android.sdk.api.session.room.timeline.Timeline @@ -39,24 +39,26 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask import org.matrix.android.sdk.internal.task.TaskExecutor internal class DefaultTimelineService @AssistedInject constructor(@Assisted private val roomId: String, @SessionDatabase private val monarchy: Monarchy, private val realmSessionProvider: RealmSessionProvider, - private val eventBus: EventBus, + private val timelineInput: TimelineInput, private val taskExecutor: TaskExecutor, private val contextOfEventTask: GetContextOfEventTask, private val eventDecryptor: TimelineEventDecryptor, private val paginationTask: PaginationTask, private val fetchTokenAndPaginateTask: FetchTokenAndPaginateTask, private val timelineEventMapper: TimelineEventMapper, - private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper + private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper, + private val loadRoomMembersTask: LoadRoomMembersTask ) : TimelineService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): TimelineService + fun create(roomId: String): DefaultTimelineService } override fun createTimeline(eventId: String?, settings: TimelineSettings): Timeline { @@ -70,10 +72,11 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv timelineEventMapper = timelineEventMapper, settings = settings, hiddenReadReceipts = TimelineHiddenReadReceipts(readReceiptsSummaryMapper, roomId, settings), - eventBus = eventBus, + timelineInput = timelineInput, eventDecryptor = eventDecryptor, fetchTokenAndPaginateTask = fetchTokenAndPaginateTask, - realmSessionProvider = realmSessionProvider + realmSessionProvider = realmSessionProvider, + loadRoomMembersTask = loadRoomMembersTask ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/EventContextResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/EventContextResponse.kt index bce03354d75105a83243515d8b5d8891c713dedc..654cf0fb7416c9eb67d97310d723859c16455b5f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/EventContextResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/EventContextResponse.kt @@ -21,16 +21,34 @@ import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.session.events.model.Event @JsonClass(generateAdapter = true) -data class EventContextResponse( +internal data class EventContextResponse( + /** + * Details of the requested event. + */ @Json(name = "event") val event: Event, + /** + * A token that can be used to paginate backwards with. + */ @Json(name = "start") override val start: String? = null, - @Json(name = "events_before") val eventsBefore: List<Event> = emptyList(), - @Json(name = "events_after") val eventsAfter: List<Event> = emptyList(), + /** + * A list of room events that happened just before the requested event, in reverse-chronological order. + */ + @Json(name = "events_before") val eventsBefore: List<Event>? = null, + /** + * A list of room events that happened just after the requested event, in chronological order. + */ + @Json(name = "events_after") val eventsAfter: List<Event>? = null, + /** + * A token that can be used to paginate forwards with. + */ @Json(name = "end") override val end: String? = null, - @Json(name = "state") override val stateEvents: List<Event> = emptyList() + /** + * The state of the room at the last event returned. + */ + @Json(name = "state") override val stateEvents: List<Event>? = null ) : TokenChunkEvent { override val events: List<Event> by lazy { - eventsAfter.reversed() + listOf(event) + eventsBefore + eventsAfter.orEmpty().reversed() + event + eventsBefore.orEmpty() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/FetchTokenAndPaginateTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/FetchTokenAndPaginateTask.kt index d1bfa1adcb5dc137437f1ac4dbf8ed73cdbfb06c..76c4b3812c59f8b281090a72423d28b8820d743b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/FetchTokenAndPaginateTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/FetchTokenAndPaginateTask.kt @@ -20,12 +20,12 @@ import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.query.findIncludingEvent import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.filter.FilterRepository import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface FetchTokenAndPaginateTask : Task<FetchTokenAndPaginateTask.Params, TokenChunkEventPersistor.Result> { @@ -43,12 +43,12 @@ internal class DefaultFetchTokenAndPaginateTask @Inject constructor( @SessionDatabase private val monarchy: Monarchy, private val filterRepository: FilterRepository, private val paginationTask: PaginationTask, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : FetchTokenAndPaginateTask { override suspend fun execute(params: FetchTokenAndPaginateTask.Params): TokenChunkEventPersistor.Result { val filter = filterRepository.getRoomFilter() - val response = executeRequest<EventContextResponse>(eventBus) { + val response = executeRequest<EventContextResponse>(globalErrorReceiver) { apiCall = roomAPI.getContextOfEvent(params.roomId, params.lastKnownEventId, 0, filter) } val fromToken = if (params.direction == PaginationDirection.FORWARDS) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetContextOfEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetContextOfEventTask.kt index 7a611dd350f77f6bde74ef40fc33f0651bbbb0a5..d02a7bafe9a99dcf893ce56e623015479ef5b2e0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetContextOfEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetContextOfEventTask.kt @@ -16,11 +16,11 @@ package org.matrix.android.sdk.internal.session.room.timeline +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.filter.FilterRepository import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetContextOfEventTask : Task<GetContextOfEventTask.Params, TokenChunkEventPersistor.Result> { @@ -35,12 +35,12 @@ internal class DefaultGetContextOfEventTask @Inject constructor( private val roomAPI: RoomAPI, private val filterRepository: FilterRepository, private val tokenChunkEventPersistor: TokenChunkEventPersistor, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : GetContextOfEventTask { override suspend fun execute(params: GetContextOfEventTask.Params): TokenChunkEventPersistor.Result { val filter = filterRepository.getRoomFilter() - val response = executeRequest<EventContextResponse>(eventBus) { + val response = executeRequest<EventContextResponse>(globalErrorReceiver) { // We are limiting the response to the event with eventId to be sure we don't have any issue with potential merging process. apiCall = roomAPI.getContextOfEvent(params.roomId, params.eventId, 0, filter) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt index acac3929ae7ddea543630f1511e1e58cd44983bc..b8585b1e747979135b7be0a7aef059b324e7c4d0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt @@ -17,17 +17,17 @@ package org.matrix.android.sdk.internal.session.room.timeline import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject // TODO Add parent task internal class GetEventTask @Inject constructor( private val roomAPI: RoomAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : Task<GetEventTask.Params, Event> { internal data class Params( @@ -36,7 +36,7 @@ internal class GetEventTask @Inject constructor( ) override suspend fun execute(params: Params): Event { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = roomAPI.getEvent(params.roomId, params.eventId) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationResponse.kt index ed384d3b3c7edd1c7b0b40bf878620a8e3d11736..2f61b1cce8ad7718d9fb20b518775a9785bac349 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationResponse.kt @@ -22,8 +22,28 @@ import org.matrix.android.sdk.api.session.events.model.Event @JsonClass(generateAdapter = true) internal data class PaginationResponse( + /** + * The token the pagination starts from. If dir=b this will be the token supplied in from. + */ @Json(name = "start") override val start: String? = null, + /** + * The token the pagination ends at. If dir=b this token should be used again to request even earlier events. + */ @Json(name = "end") override val end: String? = null, - @Json(name = "chunk") override val events: List<Event> = emptyList(), - @Json(name = "state") override val stateEvents: List<Event> = emptyList() -) : TokenChunkEvent + /** + * A list of room events. The order depends on the dir parameter. For dir=b events will be in + * reverse-chronological order, for dir=f in chronological order, so that events start at the from point. + */ + @Json(name = "chunk") val chunk: List<Event>? = null, + /** + * A list of state events relevant to showing the chunk. For example, if lazy_load_members is enabled + * in the filter then this may contain the membership events for the senders of events in the chunk. + * + * Unless include_redundant_members is true, the server may remove membership events which would have + * already been sent to the client in prior calls to this endpoint, assuming the membership of those members has not changed. + */ + @Json(name = "state") override val stateEvents: List<Event>? = null +) : TokenChunkEvent { + override val events: List<Event> + get() = chunk.orEmpty() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationTask.kt index b663d03bd7b504d983af0b12ed3e6829f517dae4..1f99893e17142c0373343a569c2bcca8c64d259e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationTask.kt @@ -16,11 +16,11 @@ package org.matrix.android.sdk.internal.session.room.timeline +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.filter.FilterRepository import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface PaginationTask : Task<PaginationTask.Params, TokenChunkEventPersistor.Result> { @@ -37,12 +37,12 @@ internal class DefaultPaginationTask @Inject constructor( private val roomAPI: RoomAPI, private val filterRepository: FilterRepository, private val tokenChunkEventPersistor: TokenChunkEventPersistor, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : PaginationTask { override suspend fun execute(params: PaginationTask.Params): TokenChunkEventPersistor.Result { val filter = filterRepository.getRoomFilter() - val chunk = executeRequest<PaginationResponse>(eventBus) { + val chunk = executeRequest<PaginationResponse>(globalErrorReceiver) { isRetryable = true apiCall = roomAPI.getRoomMessagesFrom(params.roomId, params.from, params.direction.value, params.limit, filter) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineInput.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineInput.kt new file mode 100644 index 0000000000000000000000000000000000000000..002ab1dd8a17fe41aec312fcf90c3a8f88725bea --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineInput.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.timeline + +import org.matrix.android.sdk.api.session.room.send.SendState +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.internal.session.SessionScope +import javax.inject.Inject + +@SessionScope +internal class TimelineInput @Inject constructor() { + fun onLocalEchoCreated(roomId: String, timelineEvent: TimelineEvent) { + listeners.toSet().forEach { it.onLocalEchoCreated(roomId, timelineEvent) } + } + + fun onLocalEchoUpdated(roomId: String, eventId: String, sendState: SendState) { + listeners.toSet().forEach { it.onLocalEchoUpdated(roomId, eventId, sendState) } + } + + fun onNewTimelineEvents(roomId: String, eventIds: List<String>) { + listeners.toSet().forEach { it.onNewTimelineEvents(roomId, eventIds) } + } + + val listeners = mutableSetOf<Listener>() + + internal interface Listener { + fun onLocalEchoCreated(roomId: String, timelineEvent: TimelineEvent) + fun onLocalEchoUpdated(roomId: String, eventId: String, sendState: SendState) + fun onNewTimelineEvents(roomId: String, eventIds: List<String>) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt index 08b20f1701b5228cdf4049114a0ebac89ed1795c..465b0faac8058f2c72b023192cdb07c69e1ece37 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt @@ -22,7 +22,7 @@ internal interface TokenChunkEvent { val start: String? val end: String? val events: List<Event> - val stateEvents: List<Event> + val stateEvents: List<Event>? fun hasMore() = start != end } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt index 2a532c6bf55a7a1f25eae4e6d4b57b364df15690..1a497b883555a75d24759a9a6a037d8753b3cf5c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -156,7 +156,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri } } return if (receivedChunk.events.isEmpty()) { - if (receivedChunk.start != receivedChunk.end) { + if (receivedChunk.hasMore()) { Result.SHOULD_FETCH_MORE } else { Result.REACHED_END @@ -196,7 +196,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri val now = System.currentTimeMillis() - for (stateEvent in stateEvents) { + stateEvents?.forEach { stateEvent -> val ageLocalTs = stateEvent.unsignedData?.age?.let { now - it } val stateEventEntity = stateEvent.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, EventInsertType.PAGINATION) currentChunk.addStateEvent(roomId, stateEventEntity, direction) @@ -205,9 +205,9 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri } } val eventIds = ArrayList<String>(eventList.size) - for (event in eventList) { + eventList.forEach { event -> if (event.eventId == null || event.senderId == null) { - continue + return@forEach } val ageLocalTs = event.unsignedData?.age?.let { now - it } eventIds.add(event.eventId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/DefaultTypingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/DefaultTypingService.kt index 5dcf3fcdd664bce700306a5fbc780d66b04e08f1..39b7967bc1de69314497a86d90e8d0cbeaa03e55 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/DefaultTypingService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/DefaultTypingService.kt @@ -17,8 +17,9 @@ package org.matrix.android.sdk.internal.session.room.typing import android.os.SystemClock -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.room.typing.TypingService import org.matrix.android.sdk.api.util.Cancelable @@ -38,9 +39,9 @@ internal class DefaultTypingService @AssistedInject constructor( private val sendTypingTask: SendTypingTask ) : TypingService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): TypingService + fun create(roomId: String): DefaultTypingService } private var currentTask: Cancelable? = null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/SendTypingTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/SendTypingTask.kt index c8cbb08e2cc03ef68fe6873e7fb33153b9166079..3b56d04872820b454fa234c56e030069dcc26727 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/SendTypingTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/SendTypingTask.kt @@ -21,7 +21,7 @@ import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task import kotlinx.coroutines.delay -import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import javax.inject.Inject internal interface SendTypingTask : Task<SendTypingTask.Params, Unit> { @@ -38,13 +38,13 @@ internal interface SendTypingTask : Task<SendTypingTask.Params, Unit> { internal class DefaultSendTypingTask @Inject constructor( private val roomAPI: RoomAPI, @UserId private val userId: String, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SendTypingTask { override suspend fun execute(params: SendTypingTask.Params) { delay(params.delay ?: -1) - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = roomAPI.sendTypingState( params.roomId, userId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/uploads/DefaultUploadsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/uploads/DefaultUploadsService.kt index 895f1cf50d73982962c462077e115d4a0c4776f1..6d841644dc85bea423edfbea762954aa9c68aafa 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/uploads/DefaultUploadsService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/uploads/DefaultUploadsService.kt @@ -16,8 +16,9 @@ package org.matrix.android.sdk.internal.session.room.uploads -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import dagger.assisted.AssistedFactory import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.room.uploads.GetUploadsResult import org.matrix.android.sdk.api.session.room.uploads.UploadsService @@ -28,9 +29,9 @@ internal class DefaultUploadsService @AssistedInject constructor( private val cryptoService: CryptoService ) : UploadsService { - @AssistedInject.Factory + @AssistedFactory interface Factory { - fun create(roomId: String): UploadsService + fun create(roomId: String): DefaultUploadsService } override suspend fun getUploads(numberOfEvents: Int, since: String?): GetUploadsResult { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/uploads/GetUploadsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/uploads/GetUploadsTask.kt index d0439ce7f9ab08153a15cd842720d1f4386dfffa..b3e4a5aa0597cdcc6353a19b9429ef64530cc392 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/uploads/GetUploadsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/uploads/GetUploadsTask.kt @@ -31,6 +31,7 @@ import org.matrix.android.sdk.internal.database.model.EventEntityFields import org.matrix.android.sdk.internal.database.query.TimelineEventFilter import org.matrix.android.sdk.internal.database.query.whereType import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.filter.FilterFactory import org.matrix.android.sdk.internal.session.room.RoomAPI @@ -39,7 +40,6 @@ import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection import org.matrix.android.sdk.internal.session.room.timeline.PaginationResponse import org.matrix.android.sdk.internal.session.sync.SyncTokenStore import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface GetUploadsTask : Task<GetUploadsTask.Params, GetUploadsResult> { @@ -56,8 +56,8 @@ internal class DefaultGetUploadsTask @Inject constructor( private val roomAPI: RoomAPI, private val tokenStore: SyncTokenStore, @SessionDatabase private val monarchy: Monarchy, - private val eventBus: EventBus) - : GetUploadsTask { + private val globalErrorReceiver: GlobalErrorReceiver +) : GetUploadsTask { override suspend fun execute(params: GetUploadsTask.Params): GetUploadsResult { val result: GetUploadsResult @@ -86,7 +86,7 @@ internal class DefaultGetUploadsTask @Inject constructor( val since = params.since ?: tokenStore.getLastToken() ?: throw IllegalStateException("No token available") val filter = FilterFactory.createUploadsFilter(params.numberOfEvents).toJSONString() - val chunk = executeRequest<PaginationResponse>(eventBus) { + val chunk = executeRequest<PaginationResponse>(globalErrorReceiver) { apiCall = roomAPI.getRoomMessagesFrom(params.roomId, since, PaginationDirection.BACKWARDS.value, params.numberOfEvents, filter) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt index 4f574e5ead078f3749d0787b5ec3ece389579e45..402602e4d5488382a8c29f375b2ae76b2ea1543b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt @@ -16,10 +16,10 @@ package org.matrix.android.sdk.internal.session.search -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.search.EventAndSender import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.api.util.MatrixItem +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.search.request.SearchRequestBody import org.matrix.android.sdk.internal.session.search.request.SearchRequestCategories @@ -47,11 +47,11 @@ internal interface SearchTask : Task<SearchTask.Params, SearchResult> { internal class DefaultSearchTask @Inject constructor( private val searchAPI: SearchAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SearchTask { override suspend fun execute(params: SearchTask.Params): SearchResult { - return executeRequest<SearchResponse>(eventBus) { + return executeRequest<SearchResponse>(globalErrorReceiver) { val searchRequestBody = SearchRequestBody( searchCategories = SearchRequestCategories( roomEvents = SearchRequestRoomEvents( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt index ea3730b195351dc9308880e31f0d30d0c6106628..e7b20f905bb9b6e5efa3a54ee6f5c6724eb2425d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt @@ -16,45 +16,25 @@ package org.matrix.android.sdk.internal.session.signout -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.session.signout.SignOutService -import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.internal.auth.SessionParamsStore -import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.task.configureWith -import org.matrix.android.sdk.internal.task.launchToCallback -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import javax.inject.Inject internal class DefaultSignOutService @Inject constructor(private val signOutTask: SignOutTask, private val signInAgainTask: SignInAgainTask, - private val sessionParamsStore: SessionParamsStore, - private val coroutineDispatchers: MatrixCoroutineDispatchers, - private val taskExecutor: TaskExecutor) : SignOutService { + private val sessionParamsStore: SessionParamsStore +) : SignOutService { - override fun signInAgain(password: String, - callback: MatrixCallback<Unit>): Cancelable { - return signInAgainTask - .configureWith(SignInAgainTask.Params(password)) { - this.callback = callback - } - .executeBy(taskExecutor) + override suspend fun signInAgain(password: String) { + signInAgainTask.execute(SignInAgainTask.Params(password)) } - override fun updateCredentials(credentials: Credentials, - callback: MatrixCallback<Unit>): Cancelable { - return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) { - sessionParamsStore.updateCredentials(credentials) - } + override suspend fun updateCredentials(credentials: Credentials) { + sessionParamsStore.updateCredentials(credentials) } - override fun signOut(signOutFromHomeserver: Boolean, - callback: MatrixCallback<Unit>): Cancelable { - return signOutTask - .configureWith(SignOutTask.Params(signOutFromHomeserver)) { - this.callback = callback - } - .executeBy(taskExecutor) + override suspend fun signOut(signOutFromHomeserver: Boolean) { + return signOutTask.execute(SignOutTask.Params(signOutFromHomeserver)) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignInAgainTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignInAgainTask.kt index 3bed0bdbff1192b4d26e3d3512f46b06d0228930..2c3cd5d2703fc9423c6073bf08a1604f57b51475 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignInAgainTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignInAgainTask.kt @@ -20,9 +20,9 @@ import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.internal.auth.SessionParamsStore import org.matrix.android.sdk.internal.auth.data.PasswordLoginParams +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface SignInAgainTask : Task<SignInAgainTask.Params, Unit> { @@ -35,11 +35,11 @@ internal class DefaultSignInAgainTask @Inject constructor( private val signOutAPI: SignOutAPI, private val sessionParams: SessionParams, private val sessionParamsStore: SessionParamsStore, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SignInAgainTask { override suspend fun execute(params: SignInAgainTask.Params) { - val newCredentials = executeRequest<Credentials>(eventBus) { + val newCredentials = executeRequest<Credentials>(globalErrorReceiver) { apiCall = signOutAPI.loginAgain( PasswordLoginParams.userIdentifier( // Reuse the same userId diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt index 153ea5a6fde57e7aa0f14e8f4ea66194935d3711..0cb8704782fa329d354de51da3952bd93553196e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt @@ -18,11 +18,11 @@ package org.matrix.android.sdk.internal.session.signout import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.MatrixError +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.cleanup.CleanupSession import org.matrix.android.sdk.internal.session.identity.IdentityDisconnectTask import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import timber.log.Timber import java.net.HttpURLConnection import javax.inject.Inject @@ -35,7 +35,7 @@ internal interface SignOutTask : Task<SignOutTask.Params, Unit> { internal class DefaultSignOutTask @Inject constructor( private val signOutAPI: SignOutAPI, - private val eventBus: EventBus, + private val globalErrorReceiver: GlobalErrorReceiver, private val identityDisconnectTask: IdentityDisconnectTask, private val cleanupSession: CleanupSession ) : SignOutTask { @@ -45,7 +45,7 @@ internal class DefaultSignOutTask @Inject constructor( if (params.signOutFromHomeserver) { Timber.d("SignOut: send request...") try { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = signOutAPI.signOut() } } catch (throwable: Throwable) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt index b1b2f65dc2fdde7ee6fff658d95a4bdb1fa383ac..456b0f9c2625224be559f61e3675967889e99347 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.session.sync import io.realm.Realm import io.realm.kotlin.createObject -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.R import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.Event @@ -55,8 +54,8 @@ import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembers import org.matrix.android.sdk.internal.session.room.membership.RoomMemberEventHandler import org.matrix.android.sdk.internal.session.room.read.FullyReadContent import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater -import org.matrix.android.sdk.internal.session.room.timeline.DefaultTimeline import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection +import org.matrix.android.sdk.internal.session.room.timeline.TimelineInput import org.matrix.android.sdk.internal.session.room.typing.TypingEventContent import org.matrix.android.sdk.internal.session.sync.model.InvitedRoomSync import org.matrix.android.sdk.internal.session.sync.model.RoomSync @@ -75,7 +74,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle private val roomTypingUsersHandler: RoomTypingUsersHandler, private val roomChangeMembershipStateDataSource: RoomChangeMembershipStateDataSource, @UserId private val userId: String, - private val eventBus: EventBus) { + private val timelineInput: TimelineInput) { sealed class HandlingStrategy { data class JOINED(val data: Map<String, RoomSync>) : HandlingStrategy() @@ -348,7 +347,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle } } // posting new events to timeline if any is registered - eventBus.post(DefaultTimeline.OnNewTimelineEvents(roomId = roomId, eventIds = eventIds)) + timelineInput.onNewTimelineEvents(roomId = roomId, eventIds = eventIds) return chunkEntity } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt index b4fd6e7386ac6c0d0a803e0678ed7509513f20b9..7c38230065ff8bb5c6ff3e5001bb0e95b0a5a64e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt @@ -16,9 +16,9 @@ package org.matrix.android.sdk.internal.session.sync -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.R import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.TimeOutInterceptor import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.DefaultInitialSyncProgressService @@ -48,7 +48,7 @@ internal class DefaultSyncTask @Inject constructor( private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask, private val userStore: UserStore, private val syncTaskSequencer: SyncTaskSequencer, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SyncTask { override suspend fun execute(params: SyncTask.Params) = syncTaskSequencer.post { @@ -81,7 +81,7 @@ internal class DefaultSyncTask @Inject constructor( val readTimeOut = (params.timeout + TIMEOUT_MARGIN).coerceAtLeast(TimeOutInterceptor.DEFAULT_LONG_TIMEOUT) - val syncResponse = executeRequest<SyncResponse>(eventBus) { + val syncResponse = executeRequest<SyncResponse>(globalErrorReceiver) { apiCall = syncAPI.sync( params = requestParams, readTimeOut = readTimeOut diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index 6d100a71f90210e4253de08e7af88e7d1833c01a..cce169c2464af123907e3c25f942b08692313746 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -36,6 +36,7 @@ import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import timber.log.Timber +import java.net.SocketTimeoutException import java.util.concurrent.atomic.AtomicBoolean /** @@ -49,8 +50,9 @@ abstract class SyncService : Service() { private var sessionId: String? = null private var mIsSelfDestroyed: Boolean = false - private var syncTimeoutSeconds: Int = 6 - private var syncDelaySeconds: Int = 60 + private var syncTimeoutSeconds: Int = getDefaultSyncTimeoutSeconds() + private var syncDelaySeconds: Int = getDefaultSyncDelaySeconds() + private var periodic: Boolean = false private var preventReschedule: Boolean = false @@ -68,14 +70,12 @@ abstract class SyncService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Timber.i("## Sync: onStartCommand [$this] $intent with action: ${intent?.action}") - - // We should start we have to ensure we fulfill contract to show notification - // for foreground service (as per design for this service) - // TODO can we check if it's really in foreground - onStart(isInitialSync) when (intent?.action) { ACTION_STOP -> { Timber.i("## Sync: stop command received") + // We should start we have to ensure we fulfill contract to show notification + // for foreground service (as per design for this service) + onStart(isInitialSync) // If it was periodic we ensure that it will not reschedule itself preventReschedule = true // we don't want to cancel initial syncs, let it finish @@ -85,11 +85,12 @@ abstract class SyncService : Service() { } else -> { val isInit = initialize(intent) + onStart(isInitialSync) if (isInit) { periodic = intent?.getBooleanExtra(EXTRA_PERIODIC, false) ?: false val onNetworkBack = intent?.getBooleanExtra(EXTRA_NETWORK_BACK_RESTART, false) ?: false Timber.d("## Sync: command received, periodic: $periodic networkBack: $onNetworkBack") - if (onNetworkBack && !backgroundDetectionObserver.isInBackground) { + if (!isInitialSync && onNetworkBack && !backgroundDetectionObserver.isInBackground) { // the restart after network occurs while the app is in foreground // so just stop. It will be restarted when entering background preventReschedule = true @@ -119,7 +120,11 @@ abstract class SyncService : Service() { serviceScope.coroutineContext.cancelChildren() if (!preventReschedule && periodic && sessionId != null && backgroundDetectionObserver.isInBackground) { Timber.d("## Sync: Reschedule service in $syncDelaySeconds sec") - onRescheduleAsked(sessionId ?: "", false, syncTimeoutSeconds, syncDelaySeconds) + onRescheduleAsked( + sessionId = sessionId ?: "", + syncTimeoutSeconds = syncTimeoutSeconds, + syncDelaySeconds = syncDelaySeconds + ) } super.onDestroy() } @@ -165,10 +170,23 @@ abstract class SyncService : Service() { preventReschedule = true } if (throwable is Failure.NetworkConnection) { - // Network is off, no need to reschedule endless alarms :/ + // Timeout is not critical, so retry as soon as possible. + if (throwable.cause is SocketTimeoutException) { + // For big accounts, computing sync response can take time, but Synapse will cache the + // result for the next request. So keep retrying in loop + Timber.w("Timeout during sync, retry in loop") + doSync() + return + } + // Network might be off, no need to reschedule endless alarms :/ preventReschedule = true - // Instead start a work to restart background sync when network is back - onNetworkError(sessionId ?: "", isInitialSync, syncTimeoutSeconds, syncDelaySeconds) + // Instead start a work to restart background sync when network is on + onNetworkError( + sessionId = sessionId ?: "", + syncTimeoutSeconds = syncTimeoutSeconds, + syncDelaySeconds = syncDelaySeconds, + isPeriodic = periodic + ) } // JobCancellation could be caught here when onDestroy cancels the coroutine context if (isRunning.get()) stopMe() @@ -182,8 +200,8 @@ abstract class SyncService : Service() { } val matrix = Matrix.getInstance(applicationContext) val safeSessionId = intent.getStringExtra(EXTRA_SESSION_ID) ?: return false - syncTimeoutSeconds = intent.getIntExtra(EXTRA_TIMEOUT_SECONDS, 6) - syncDelaySeconds = intent.getIntExtra(EXTRA_DELAY_SECONDS, 60) + syncTimeoutSeconds = intent.getIntExtra(EXTRA_TIMEOUT_SECONDS, getDefaultSyncTimeoutSeconds()) + syncDelaySeconds = intent.getIntExtra(EXTRA_DELAY_SECONDS, getDefaultSyncDelaySeconds()) try { val sessionComponent = matrix.sessionManager.getSessionComponent(safeSessionId) ?: throw IllegalStateException("## Sync: You should have a session to make it work") @@ -202,11 +220,15 @@ abstract class SyncService : Service() { } } + abstract fun getDefaultSyncTimeoutSeconds(): Int + + abstract fun getDefaultSyncDelaySeconds(): Int + abstract fun onStart(isInitialSync: Boolean) - abstract fun onRescheduleAsked(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) + abstract fun onRescheduleAsked(sessionId: String, syncTimeoutSeconds: Int, syncDelaySeconds: Int) - abstract fun onNetworkError(sessionId: String, isInitialSync: Boolean, timeout: Int, delay: Int) + abstract fun onNetworkError(sessionId: String, syncTimeoutSeconds: Int, syncDelaySeconds: Int, isPeriodic: Boolean) override fun onBind(intent: Intent?): IBinder? { return null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt index d1393c8b3706d673bf3085baa62480172865b570..26e8d3380a04cf8f2dff84e73cf6ffbcd9f633c2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt @@ -17,11 +17,11 @@ package org.matrix.android.sdk.internal.session.user.accountdata import com.zhuinden.monarchy.Monarchy -import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes import org.matrix.android.sdk.internal.database.model.IgnoredUserEntity import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.sync.model.accountdata.IgnoredUsersContent import org.matrix.android.sdk.internal.task.Task @@ -40,7 +40,7 @@ internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor( @SessionDatabase private val monarchy: Monarchy, private val saveIgnoredUsersTask: SaveIgnoredUsersTask, @UserId private val userId: String, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : UpdateIgnoredUserIdsTask { override suspend fun execute(params: UpdateIgnoredUserIdsTask.Params) { @@ -63,7 +63,7 @@ internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor( val list = ignoredUserIds.toList() val body = IgnoredUsersContent.createWithUserIds(list) - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = accountDataApi.setAccountData(userId, UserAccountDataTypes.TYPE_IGNORED_USER_LIST, body) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt index 80ab79b22800115f46a94e065bffc8c08236df00..dba28253a7440fc1358c6605a86792634068d39a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt @@ -24,8 +24,8 @@ import org.matrix.android.sdk.internal.session.sync.model.accountdata.AcceptedTe import org.matrix.android.sdk.internal.session.sync.model.accountdata.BreadcrumbsContent import org.matrix.android.sdk.internal.session.sync.model.accountdata.IdentityServerContent import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Params, Unit> { @@ -100,11 +100,11 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa internal class DefaultUpdateUserAccountDataTask @Inject constructor( private val accountDataApi: AccountDataAPI, @UserId private val userId: String, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : UpdateUserAccountDataTask { override suspend fun execute(params: UpdateUserAccountDataTask.Params) { - return executeRequest(eventBus) { + return executeRequest(globalErrorReceiver) { apiCall = accountDataApi.setAccountData(userId, params.type, params.getData()) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUserTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUserTask.kt index cd9be0e7ddee1c819f63e0d2404e6174ed94d915..380fa6e209cdb47293c1ee9df2c63bc79356036d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUserTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUserTask.kt @@ -17,10 +17,10 @@ package org.matrix.android.sdk.internal.session.user.model import org.matrix.android.sdk.api.session.user.model.User +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.user.SearchUserAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface SearchUserTask : Task<SearchUserTask.Params, List<User>> { @@ -34,11 +34,11 @@ internal interface SearchUserTask : Task<SearchUserTask.Params, List<User>> { internal class DefaultSearchUserTask @Inject constructor( private val searchUserAPI: SearchUserAPI, - private val eventBus: EventBus + private val globalErrorReceiver: GlobalErrorReceiver ) : SearchUserTask { override suspend fun execute(params: SearchUserTask.Params): List<User> { - val response = executeRequest<SearchUsersResponse>(eventBus) { + val response = executeRequest<SearchUsersResponse>(globalErrorReceiver) { apiCall = searchUserAPI.searchUsers(SearchUsersParams(params.search, params.limit)) } return response.users.map { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt index 422615af2d35c4dc362a31930fa6deb1afdb6d90..ae807ce30fefed2f472b4101b386c611d7105699 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt @@ -25,10 +25,10 @@ import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFie import org.matrix.android.sdk.internal.database.query.whereStateKey import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface CreateWidgetTask : Task<CreateWidgetTask.Params, Unit> { @@ -43,10 +43,10 @@ internal interface CreateWidgetTask : Task<CreateWidgetTask.Params, Unit> { internal class DefaultCreateWidgetTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy, private val roomAPI: RoomAPI, @UserId private val userId: String, - private val eventBus: EventBus) : CreateWidgetTask { + private val globalErrorReceiver: GlobalErrorReceiver) : CreateWidgetTask { override suspend fun execute(params: CreateWidgetTask.Params) { - executeRequest<Unit>(eventBus) { + executeRequest<Unit>(globalErrorReceiver) { apiCall = roomAPI.sendStateEvent( roomId = params.roomId, stateEventType = EventType.STATE_ROOM_WIDGET_LEGACY, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt index c41f1df0de82b6ec20d3ea2dceb35264d41c6bf3..000b9e38b9e8027774fb33329f48cffd4eafe5c5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt @@ -53,7 +53,7 @@ internal class WidgetFactory @Inject constructor(private val userDataSource: Use } } val isAddedByMe = widgetEvent.senderId == userId - val computedUrl = widgetContent.computeURL(widgetEvent.roomId) + val computedUrl = widgetContent.computeURL(widgetEvent.roomId, widgetId) return Widget( widgetContent = widgetContent, event = widgetEvent, @@ -65,13 +65,14 @@ internal class WidgetFactory @Inject constructor(private val userDataSource: Use ) } - private fun WidgetContent.computeURL(roomId: String?): String? { + private fun WidgetContent.computeURL(roomId: String?, widgetId: String): String? { var computedUrl = url ?: return null val myUser = userDataSource.getUser(userId) computedUrl = computedUrl .replace("\$matrix_user_id", userId) .replace("\$matrix_display_name", myUser?.displayName ?: userId) .replace("\$matrix_avatar_url", myUser?.avatarUrl ?: "") + .replace("\$matrix_widget_id", widgetId) if (roomId != null) { computedUrl = computedUrl.replace("\$matrix_room_id", roomId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt index c6647f757238a3335d23e3c17e02aa374ef6cf68..b58cab99b5d4fbcf6ab5f524965483880d8e175e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt @@ -20,6 +20,7 @@ import android.content.Context import androidx.work.ListenableWorker import androidx.work.WorkerFactory import androidx.work.WorkerParameters +import timber.log.Timber import javax.inject.Inject import javax.inject.Provider @@ -32,6 +33,8 @@ class MatrixWorkerFactory @Inject constructor( workerClassName: String, workerParameters: WorkerParameters ): ListenableWorker? { + Timber.d("MatrixWorkerFactory.createWorker for $workerClassName") + val foundEntry = workerFactories.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) } val factoryProvider = foundEntry?.value diff --git a/matrix-sdk-android/src/main/res/values-cs/strings.xml b/matrix-sdk-android/src/main/res/values-cs/strings.xml index 50dea12b09c799d1eaf76f81d3a08e399eb8eac3..adb35179279190c52c2b3c74d90b5591b0b414d5 100644 --- a/matrix-sdk-android/src/main/res/values-cs/strings.xml +++ b/matrix-sdk-android/src/main/res/values-cs/strings.xml @@ -242,4 +242,30 @@ <string name="notice_room_server_acl_set_banned">• Server shodujÃcà se s %s je zakázán.</string> <string name="notice_room_server_acl_set_title_by_you">Nastavili jste ACL serveru pro tuto mÃstnost.</string> <string name="notice_room_server_acl_set_title">%s nastavili ACL serveru pro tuto mÃstnost.</string> + <string name="notice_room_canonical_alias_no_change_by_you">ZmÄ›nili jste adresy pro tuto mÃstnost.</string> + <string name="notice_room_canonical_alias_no_change">%1$s zmÄ›nili adresy pro tuto mÃstnost.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">ZmÄ›nili jste hlavnà a alternativnà adresu pro tuto mÃstnost.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s zmÄ›nili hlavnà a alternativnà adresu pro tuto mÃstnost.</string> + <string name="notice_room_canonical_alias_alternative_changed_by_you">ZmÄ›nili jste alternativnà adresu pro tuto mÃstnost.</string> + <string name="notice_room_canonical_alias_alternative_changed">%1$s zmÄ›nili alternativnà adresu pro tuto mÃstnost.</string> + <plurals name="notice_room_canonical_alias_alternative_removed_by_you"> + <item quantity="one">Odstranili jste alternativnà adresu %1$s pro tuto mÃstnost.</item> + <item quantity="few">Odstranili jste alternativnà adresy %1$s pro tuto mÃstnost.</item> + <item quantity="other">Odstranili jste alternativnà adresy %1$s pro tuto mÃstnost.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_removed"> + <item quantity="one">%1$s odstranili alternativnà adresu %2$s pro tuto mÃstnost.</item> + <item quantity="few">%1$s odstranili alternativnà adresy %2$s pro tuto mÃstnost.</item> + <item quantity="other">%1$s odstranili alternativnà adresy %2$s pro tuto mÃstnost.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added_by_you"> + <item quantity="one">PÅ™idali jste alternativnà adresu %1$s pro tuto mÃstnost.</item> + <item quantity="few">PÅ™idali jste alternativnà adresy %1$s pro tuto mÃstnost.</item> + <item quantity="other">PÅ™idali jste alternativnà adresy %1$s pro tuto mÃstnost.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added"> + <item quantity="one">%1$s pÅ™idali alternativnà adresu %2$s pro tuto mÃstnost.</item> + <item quantity="few">%1$s pÅ™idali alternativnà adresy %2$s pro tuto mÃstnost.</item> + <item quantity="other">%1$s pÅ™idali alternativnà adresy %2$s pro tuto mÃstnost.</item> + </plurals> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-et/strings.xml b/matrix-sdk-android/src/main/res/values-et/strings.xml index 957c0b9955310acee50291aec2ac1e1048f71b4a..af2cc33b99c9e41952f1d92a6e5ae821413717f8 100644 --- a/matrix-sdk-android/src/main/res/values-et/strings.xml +++ b/matrix-sdk-android/src/main/res/values-et/strings.xml @@ -47,7 +47,7 @@ <string name="notice_crypto_error_unkwown_inbound_session_id">Sõnumi saatja seade ei ole selle sõnumi jaoks saatnud dekrüptimisvõtmeid.</string> <string name="could_not_redact">Ei saanud muuta sõnumit</string> <string name="unable_to_send_message">Sõnumi saatmine ei õnnestunud</string> - <string name="message_failed_to_upload">Faili üles laadimine ei õnnestunud</string> + <string name="message_failed_to_upload">Pildi üleslaadimine ei õnnestunud</string> <string name="network_error">Võrguühenduse viga</string> <string name="matrix_error">Matrix\'i viga</string> <string name="room_error_join_failed_empty_room">Hetkel ei ole võimalik uuesti liituda tühja jututoaga.</string> @@ -236,4 +236,26 @@ <string name="notice_room_server_acl_set_ip_literals_allowed">• Lubatud on serverid, mille ip-aadress vastab mustrile.</string> <string name="notice_room_server_acl_set_allowed">• Lubatud on serverid, mille nimes leidub %s.</string> <string name="notice_room_server_acl_set_banned">• Keelatud on serverid, mille nimes leidub %s.</string> + <string name="notice_room_canonical_alias_no_change">%1$s muutis selle jututoa aadresse.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">Sa muutsid selle jututoa põhiaadressi ja täiendavaid aadresse.</string> + <string name="notice_room_canonical_alias_alternative_changed">%1$s muutis selle jututoa täiendavaid aadresse.</string> + <string name="notice_room_canonical_alias_alternative_changed_by_you">Sa muutsid selle jututoa täiendavaid aadresse.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s muutis selle jututoa põhiaadressi ja täiendavaid aadresse.</string> + <plurals name="notice_room_canonical_alias_alternative_removed_by_you"> + <item quantity="one">Sa eemaldasid selle jututoa täiendava aadressi %1$s.</item> + <item quantity="other">Sa eemaldasid selle jututoa täiendavad aadressid %1$s.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_removed"> + <item quantity="one">%1$s eemaldas selle jututoa täiendava aadressi %2$s.</item> + <item quantity="other">%1$s eemaldas selle jututoa täiendavad aadressid %2$s.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added_by_you"> + <item quantity="one">Sa lisasid sellele jututoale täiendava aadressi %1$s.</item> + <item quantity="other">Sa lisasid sellele jututoale täiendavad aadressid %1$s.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added"> + <item quantity="one">%1$s lisas sellele jututoale täiendava aadressi %2$s.</item> + <item quantity="other">%1$s lisas sellele jututoale täiendavad aadressid %2$s.</item> + </plurals> + <string name="notice_room_canonical_alias_no_change_by_you">Sa muutsid selle jututoa aadresse.</string> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-fa/strings.xml b/matrix-sdk-android/src/main/res/values-fa/strings.xml index 8f8059067e554707e2a2d4467b4d86607422da6b..50446b9708c5d79de412300207fa5c720ba25dc0 100644 --- a/matrix-sdk-android/src/main/res/values-fa/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fa/strings.xml @@ -218,4 +218,5 @@ <item quantity="other">%1$sØŒ %2$sØŒ %3$s Ùˆ %4$d Ù†Ùر دیگر</item> </plurals> <string name="room_displayname_3_members">%1$sØŒ %2$s Ùˆ %3$s</string> + <string name="room_displayname_4_members">%1$sØŒ %2$sØŒ %3$s Ùˆ %4$s</string> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-it/strings.xml b/matrix-sdk-android/src/main/res/values-it/strings.xml index c1a5cf85cbcc0557261feb87743ffe00ad20c622..ec19cd5c17e072ae7c7add030363b3135bd92210 100644 --- a/matrix-sdk-android/src/main/res/values-it/strings.xml +++ b/matrix-sdk-android/src/main/res/values-it/strings.xml @@ -102,7 +102,7 @@ </plurals> <plurals name="notice_room_aliases_removed"> <item quantity="one">%1$s ha rimosso %2$s come indirizzo per questa stanza.</item> - <item quantity="other">%1$s ha rimosso %3$s come indirizzi per questa stanza.</item> + <item quantity="other">%1$s ha rimosso %2$s come indirizzi per questa stanza.</item> </plurals> <string name="notice_room_aliases_added_and_removed">%1$s ha aggiunto %2$s e rimosso %3$s come indirizzi per questa stanza.</string> <string name="notice_room_canonical_alias_set">%1$s ha impostato l\'indirizzo principale per questa stanza a %2$s.</string> @@ -237,4 +237,26 @@ <string name="notice_room_server_acl_set_banned">• I server che corrispondono a %s sono banditi.</string> <string name="notice_room_server_acl_set_title_by_you">Hai impostato le ACL del server per questa stanza.</string> <string name="notice_room_server_acl_set_title">%s ha impostato le ACL del server per questa stanza.</string> + <string name="notice_room_canonical_alias_no_change_by_you">Hai cambiato gli indirizzi per questa stanza.</string> + <string name="notice_room_canonical_alias_no_change">%1$s ha cambiato gli indirizzi per questa stanza.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">Hai cambiato gli indirizzi principali ed alternativi per questa stanza.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s ha cambiato gli indirizzi principali ed alternativi per questa stanza.</string> + <string name="notice_room_canonical_alias_alternative_changed_by_you">Hai cambiato gli indirizzi alternativi per questa stanza.</string> + <string name="notice_room_canonical_alias_alternative_changed">%1$s ha cambiato gli indirizzi alternativi per questa stanza.</string> + <plurals name="notice_room_canonical_alias_alternative_removed_by_you"> + <item quantity="one">Hai rimosso l\'indirizzo alternativo %1$s per questa stanza.</item> + <item quantity="other">Hai rimosso gli indirizzi alternativi %1$s per questa stanza.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_removed"> + <item quantity="one">%1$s ha rimosso l\'indirizzo alternativo %2$s per questa stanza.</item> + <item quantity="other">%1$s ha rimosso gli indirizzi alternativi %2$s per questa stanza.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added_by_you"> + <item quantity="one">Hai aggiunto l\'indirizzo alternativo %1$s per questa stanza.</item> + <item quantity="other">Hai aggiunto gli indirizzi alternativi %1$s per questa stanza.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added"> + <item quantity="one">%1$s ha aggiunto l\'indirizzo alternativo %2$s per questa stanza.</item> + <item quantity="other">%1$s ha aggiunto gli indirizzi alternativi %2$s per questa stanza.</item> + </plurals> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-lv/strings.xml b/matrix-sdk-android/src/main/res/values-lv/strings.xml index b14cbb4b000a9a44a952e6400a3efe1a9c897e14..ec107b47d6bd385cd63704e78d060e8e3f302f8c 100644 --- a/matrix-sdk-android/src/main/res/values-lv/strings.xml +++ b/matrix-sdk-android/src/main/res/values-lv/strings.xml @@ -1,8 +1,7 @@ -<?xml version='1.0' encoding='UTF-8'?> +<?xml version="1.0" encoding="utf-8"?> <resources> <string name="summary_message">%1$s: %2$s</string> <string name="summary_user_sent_image">%1$s nosÅ«tÄ«ja attÄ“lu.</string> - <string name="notice_room_invite_no_invitee">%s\'s uzaicinÄjums</string> <string name="notice_room_invite">%1$s uzaicinÄja %2$s</string> <string name="notice_room_invite_you">%1$s uzaicinÄja tevi</string> @@ -30,46 +29,56 @@ <string name="notice_room_visibility_world_readable">ikviens.</string> <string name="notice_room_visibility_unknown">nezinÄms (%s).</string> <string name="notice_end_to_end">%1$s ieslÄ“dza ierÄ«ce-ierÄ«ce Å¡ifrÄ“Å¡anu (%2$s)</string> - <string name="notice_requested_voip_conference">%1$s vÄ“las VoIP konferenci</string> <string name="notice_voip_started">VoIP konference sÄkusies</string> <string name="notice_voip_finished">VoIP konference ir beigusies</string> - <string name="notice_avatar_changed_too">(arÄ« profila attÄ“ls mainÄ«jÄs)</string> <string name="notice_room_name_removed">%1$s dzÄ“sa istabas nosaukumu</string> <string name="notice_room_topic_removed">%1$s dzÄ“sa istabas tÄ“mas nosaukumu</string> <string name="notice_profile_change_redacted">%1$s atjaunoja profila informÄciju %2$s</string> <string name="notice_room_third_party_invite">%1$s nosÅ«tÄ«ja uzaicinÄjumu %2$s pievienoties istabai</string> <string name="notice_room_third_party_registered_invite">%1$s apstiprinÄja uzaicinÄjumu priekÅ¡ %2$s</string> - <string name="notice_crypto_unable_to_decrypt">** Nav iespÄ“jams atkodÄ“t: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">SÅ«tÄ«tÄja ierÄ«ce mums nenosÅ«tÄ«ja atslÄ“gas priekÅ¡ Å¡Ä«s ziņas.</string> - <string name="could_not_redact">NevarÄ“ja rediģēt</string> <string name="unable_to_send_message">Nav iespÄ“jams nosÅ«tÄ«t ziņu</string> - <string name="message_failed_to_upload">NeizdevÄs augÅ¡uplÄdÄ“t attÄ“lu</string> - <string name="network_error">TÄ«kla kļūda</string> <string name="matrix_error">Matrix kļūda</string> - <string name="room_error_join_failed_empty_room">Å obrÄ«d nav iespÄ“jams atkÄrtoti pievienoties tukÅ¡ai istabai.</string> - <string name="encrypted_message">Å ifrÄ“ta ziņa</string> - <string name="medium_email">Epasta adrese</string> <string name="medium_phone_number">Telefona numurs</string> - <string name="room_displayname_invite_from">UzaicinÄjums no %s</string> <string name="room_displayname_room_invite">UzaicinÄjums uz istabu</string> <string name="room_displayname_two_members">%1$s un %2$s</string> <string name="room_displayname_empty_room">TukÅ¡a istaba</string> - <plurals name="room_displayname_three_and_more_members"> <item quantity="zero">%1$s un 1 cits</item> <item quantity="one">%1$s un %2$d citi</item> <item quantity="other">%1$s un %2$d citu</item> </plurals> - - -</resources> + <string name="notice_display_name_changed_from_by_you">Tu nomainÄ«ji savu attÄ“lojamo vÄrdu no %1$s uz %2$s</string> + <string name="notice_display_name_set_by_you">Tu nomainÄ«jis savu attÄ“lojamo vÄrdu uz %1$s</string> + <string name="notice_avatar_url_changed_by_you">Tu nomainÄ«ji savu avataru</string> + <string name="notice_room_withdraw_by_you">Tu atsauci %1$s uzaicinÄjumu</string> + <string name="notice_room_ban_by_you">Tu nobanoji %1$s</string> + <string name="notice_room_unban_by_you">Tu atbanoji %1$s</string> + <string name="notice_room_kick_by_you">Tu izspÄ“ri %1$s</string> + <string name="notice_room_reject_by_you">Tu noraidÄ«ji uzaicinÄjumu</string> + <string name="notice_direct_room_leave_by_you">Tu pameti telpu</string> + <string name="notice_direct_room_leave">%1$s atstÄja telpu</string> + <string name="notice_room_leave_by_you">Tu atstÄji telpu</string> + <string name="notice_direct_room_join_by_you">Tu pievienojies</string> + <string name="notice_direct_room_join">%1$s pievienojÄs telpai</string> + <string name="notice_room_join_by_you">Tu pievienojies telpai</string> + <string name="notice_room_invite_by_you">Tu uzaicinÄji %1$s</string> + <string name="notice_direct_room_created_by_you">Tu izveidoji apspriedi (diskusiju)</string> + <string name="notice_direct_room_created">%1$s izveidoja apspriedi (diskusiju)</string> + <string name="notice_room_created_by_you">Tu izveidoji istabu</string> + <string name="notice_room_created">%1$s izveidoja telpu</string> + <string name="notice_room_invite_no_invitee_by_you">Tavs uzaicinÄjums</string> + <string name="summary_you_sent_sticker">Tu nosÅ«tÄ«ji uzlÄ«mi/lipekli.</string> + <string name="summary_user_sent_sticker">%1$s nosÅ«tÄ«ja uzlÄ«mi/lipekli.</string> + <string name="summary_you_sent_image">Tu nosÅ«tÄ«ji attÄ“lu.</string> +</resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-nb/strings.xml b/matrix-sdk-android/src/main/res/values-nb/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..07cf4226e02eb7338bca42a647227c62c0fc1d4d --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-nb/strings.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="notice_direct_room_created_by_you">Du opprettet diskusjonen</string> + <string name="notice_room_created_by_you">Du opprettet rommet</string> + <string name="notice_room_invite_no_invitee_by_you">Invitasjonen din</string> + <string name="summary_you_sent_sticker">Du sendte et klistremerke.</string> + <string name="summary_user_sent_sticker">%1$s sendte et klistremerke.</string> + <string name="summary_you_sent_image">Du sendte et bilde.</string> + <string name="summary_user_sent_image">%1$s sendte et bilde.</string> + <string name="summary_message">%1$s: %2$s</string> +</resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-nn/strings.xml b/matrix-sdk-android/src/main/res/values-nn/strings.xml index d986e697ad6c981e3c345b369f95dba593f52ce1..441d568fc3c92a39c9486007e79bddd81b675c0e 100644 --- a/matrix-sdk-android/src/main/res/values-nn/strings.xml +++ b/matrix-sdk-android/src/main/res/values-nn/strings.xml @@ -1,12 +1,9 @@ -<?xml version='1.0' encoding='UTF-8'?> +<?xml version="1.0" encoding="utf-8"?> <resources> <string name="encrypted_message">Kryptert melding</string> - - <string name="summary_message">%1$s: %2$s</string> <string name="summary_user_sent_image">%1$s sende eit bilæte.</string> <string name="summary_user_sent_sticker">%1$s sende eit klistremerke.</string> - <string name="notice_room_invite_no_invitee">%s si innbjoding</string> <string name="notice_room_invite">%1$s inviterte %2$s</string> <string name="notice_room_invite_you">%1$s inviterte deg</string> @@ -34,53 +31,38 @@ <string name="notice_room_visibility_world_readable">kven som heldst.</string> <string name="notice_room_visibility_unknown">uvisst (%s).</string> <string name="notice_end_to_end">%1$s skrudde ende-til-ende-kryptering pÃ¥ (%2$s)</string> - <string name="notice_requested_voip_conference">%1$s bad um ei VoIP-gruppasamtala</string> <string name="notice_voip_started">VoIP-gruppasamtala er starta</string> <string name="notice_voip_finished">VoIP-gruppasamtala er ferdug</string> - <string name="notice_avatar_changed_too">(avataren vart au byta)</string> <string name="notice_room_name_removed">%1$s tok burt romnamnet</string> <string name="notice_room_topic_removed">%1$s tok burt romemnet</string> <string name="notice_profile_change_redacted">%1$s gjorde um pÃ¥ skildringi si %2$s</string> <string name="notice_room_third_party_invite">%1$s inviterte %2$s til rommet</string> <string name="notice_room_third_party_registered_invite">%1$s sa ja til innbjodingi til %2$s</string> - <string name="notice_crypto_unable_to_decrypt">** Fekk ikkje til Ã¥ dekryptera: %s **</string> <string name="notice_crypto_error_unkwown_inbound_session_id">Avsendareiningi hev ikkje sendt oss nyklane fyr denna meldingi.</string> - <string name="could_not_redact">Kunde ikkje gjera um</string> - <string name="unable_to_send_message">Fekk ikkje Ã¥ senda meldingi</string> - + <string name="unable_to_send_message">Fekk ikkje til Ã¥ senda meldingi</string> <string name="message_failed_to_upload">Fekk ikkje til Ã¥ lasta biletet upp</string> - <string name="network_error">Noko gjekk gale med netverket</string> <string name="matrix_error">Noko gjekk gale med Matrix</string> - <string name="room_error_join_failed_empty_room">Det lèt seg fyrebils ikkje gjera Ã¥ fara inn att i eit tomt rom.</string> - <string name="medium_email">Epostadresse</string> <string name="medium_phone_number">Telefonnummer</string> - <string name="room_displayname_invite_from">Innbjoding frÃ¥ %s</string> <string name="room_displayname_room_invite">Rominnbjoding</string> <string name="room_displayname_two_members">%1$s og %2$s</string> - <plurals name="room_displayname_three_and_more_members"> <item quantity="one">%1$s og 1 til</item> <item quantity="other">%1$s og %2$d til</item> </plurals> - <string name="room_displayname_empty_room">Tomt rom</string> - <string name="notice_event_redacted">Ei melding vart stroki</string> <string name="notice_event_redacted_by">%1$s strauk meldingi</string> <string name="notice_event_redacted_with_reason">Meldingi vart stroki [av di: %1$s]</string> <string name="notice_event_redacted_by_with_reason">%1$s strauk meldingi [av di: %2$s]</string> - <string name="notice_room_update">%s oppgraderte rommet.</string> - <string name="clear_timeline_send_queue">Nullstill sendingskø</string> - <string name="notice_room_leave_with_reason">%1$s forlot rommet. Grunn: %2$s</string> -</resources> +</resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml b/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml index e6c93cb55ce78bf97ed28f3425c65eb3297d3280..5e3282a3052560a48085f1b9cb126fc4415abb02 100644 --- a/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml +++ b/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml @@ -178,7 +178,7 @@ </plurals> <plurals name="notice_room_aliases_removed"> <item quantity="one">%1$s removeu %2$s como um endereço desta sala.</item> - <item quantity="other">%1$s removeu %3$s como endereços desta sala.</item> + <item quantity="other">%1$s removeu %2$s como endereços desta sala.</item> </plurals> <plurals name="notice_room_aliases_removed_by_you"> <item quantity="one">Você removeu %1$s como um endereço desta sala.</item> @@ -244,4 +244,26 @@ <string name="notice_room_server_acl_set_banned">• Servidores correspondentes à %s estão banidos.</string> <string name="notice_room_server_acl_set_title_by_you">Você definiu a lista de controle de acesso (ACL) do servidor para esta sala.</string> <string name="notice_room_server_acl_set_title">%s definiu a lista de controle de acesso (ACL) do servidor para esta sala.</string> + <string name="notice_room_canonical_alias_alternative_changed_by_you">Você alterou os endereços alternativos desta sala.</string> + <string name="notice_room_canonical_alias_alternative_changed">%1$s alterou os endereços alternativos desta sala.</string> + <plurals name="notice_room_canonical_alias_alternative_removed_by_you"> + <item quantity="one">Você removeu o endereço alternativo %1$s para esta sala.</item> + <item quantity="other">Você removeu os endereços alternativos %1$s para esta sala.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_removed"> + <item quantity="one">%1$s removeu o endereço alternativo %2$s para esta sala.</item> + <item quantity="other">%1$s removeu os endereços alternativos %2$s para esta sala.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added_by_you"> + <item quantity="one">Você adicionou o endereço alternativo %1$s para esta sala.</item> + <item quantity="other">Você adicionou os endereços alternativos %1$s para esta sala.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added"> + <item quantity="one">%1$s adicionou o endereço alternativo %2$s para esta sala.</item> + <item quantity="other">%1$s adicionou os endereços alternativos %2$s para esta sala.</item> + </plurals> + <string name="notice_room_canonical_alias_no_change_by_you">Você alterou os endereços desta sala.</string> + <string name="notice_room_canonical_alias_no_change">%1$s alterou os endereços desta sala.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">Você alterou os endereços principal e alternativos desta sala.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s alterou os endereços principal e alternativos desta sala.</string> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-ru/strings.xml b/matrix-sdk-android/src/main/res/values-ru/strings.xml index 5ef5a4f447d64e58a1b78027bc739c95df7d2ad2..f2e0bd668f6b5c85c33099ace140ff8e21896dff 100644 --- a/matrix-sdk-android/src/main/res/values-ru/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ru/strings.xml @@ -252,4 +252,34 @@ <string name="notice_room_server_acl_updated_title">%s изменил права доÑтупа Ñервера (ACL) Ð´Ð»Ñ Ñтой комнаты.</string> <string name="notice_room_server_acl_set_title_by_you">Ð’Ñ‹ наÑтроили права доÑтупа Ñервера (ACL) Ð´Ð»Ñ Ñтой комнаты.</string> <string name="notice_room_server_acl_set_title">%s уÑтанавливает права доÑтупа Ñервера (ACL) Ð´Ð»Ñ Ñтой комнаты.</string> + <string name="notice_room_canonical_alias_no_change_by_you">Ð’Ñ‹ изменили адреÑа Ñтой комнаты.</string> + <string name="notice_room_canonical_alias_no_change">%1$s изменил(а) адреÑа Ñтой комнаты.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">Ð’Ñ‹ изменили оÑновной и альтернативный адреÑа Ñтой комнаты.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s изменил(а) оÑновной и альтернативный адреÑа Ñтой комнаты.</string> + <string name="notice_room_canonical_alias_alternative_changed_by_you">Ð’Ñ‹ изменили альтернативные адреÑа Ð´Ð»Ñ Ñтой комнаты.</string> + <string name="notice_room_canonical_alias_alternative_changed">%1$s изменил(а) альтернативные адреÑа Ð´Ð»Ñ Ñтой комнаты.</string> + <plurals name="notice_room_canonical_alias_alternative_removed_by_you"> + <item quantity="one">Ð’Ñ‹ удалили альтернативный Ð°Ð´Ñ€ÐµÑ %1$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="few">Ð’Ñ‹ удалили альтернативные адреÑа %1$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="many">Ð’Ñ‹ удалили альтернативные адреÑа %1$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="other">Ð’Ñ‹ удалили альтернативные адреÑа %1$s Ð´Ð»Ñ Ñтой комнаты.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_removed"> + <item quantity="one">%1$s удалил(а) альтернативный Ð°Ð´Ñ€ÐµÑ %2$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="few">%1$s удалил(а) альтернативные адреÑа %2$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="many">%1$s удалил(а) альтернативные адреÑа %2$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="other">%1$s удалил(а) альтернативные адреÑа %2$s Ð´Ð»Ñ Ñтой комнаты.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added_by_you"> + <item quantity="one">Ð’Ñ‹ добавили альтернативный Ð°Ð´Ñ€ÐµÑ %1$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="few">Ð’Ñ‹ добавили альтернативные адреÑа %1$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="many">Ð’Ñ‹ добавили альтернативные адреÑа %1$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="other">Ð’Ñ‹ добавили альтернативные адреÑа %1$s Ð´Ð»Ñ Ñтой комнаты.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added"> + <item quantity="one">%1$s добавил(а) альтернативный Ð°Ð´Ñ€ÐµÑ %2$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="few">%1$s добавил(а) альтернативные адреÑа %2$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="many">%1$s добавил(а) альтернативные адреÑа %2$s Ð´Ð»Ñ Ñтой комнаты.</item> + <item quantity="other">%1$s добавил(а) альтернативные адреÑа %2$s Ð´Ð»Ñ Ñтой комнаты.</item> + </plurals> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-sk/strings.xml b/matrix-sdk-android/src/main/res/values-sk/strings.xml index 15924d02e1063c3430f39f26458e7492188f4748..a40654f7bf39cd922af9a677645eb42509bb3536 100644 --- a/matrix-sdk-android/src/main/res/values-sk/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sk/strings.xml @@ -197,4 +197,16 @@ <string name="notice_end_to_end_unknown_algorithm">%1$s povolil/a E2E Å¡ifrovanie (Nerozpoznaný algorytmus %2$s).</string> <string name="notice_end_to_end_unknown_algorithm_by_you">Povolili ste E2E Å¡ifrovanie (Nerozpoznaný algorytmus %1$s).</string> <string name="key_verification_request_fallback_message">%s požaduje overenie vaÅ¡ich Å¡ifrovacÃch kľúÄov, ale váš klient nepodporuje overenie kľúÄov v konverzácii. Budete musieÅ¥ použiÅ¥ zastaralú metódu overenia.</string> + <string name="notice_room_server_acl_set_title_by_you">nastavili ste na servery pravidlá ACL tejto miestnosti.</string> + <string name="notice_room_server_acl_set_title">%s nastavil(a) na servery pravidlá ACL tejto miestnosti.</string> + <string name="notice_direct_room_update_by_you">Aktualizovali ste sem.</string> + <string name="notice_direct_room_update">%s aktualizoval(a) sem.</string> + <string name="notice_made_future_direct_room_visibility">%1$s sprÃstupnil(a) budúce správy %2$s</string> + <string name="notice_made_future_direct_room_visibility_by_you">SprÃstupnili ste budúce správy %1$s</string> + <string name="notice_direct_room_leave_by_you">Opustili ste miestnosÅ¥</string> + <string name="notice_direct_room_leave">%1$s opustil(a) miestnosÅ¥</string> + <string name="notice_direct_room_join_by_you">Vstúpili ste</string> + <string name="notice_direct_room_join">%1$s vstúpil(a)</string> + <string name="notice_direct_room_created_by_you">Vytvorili ste konverzáciu</string> + <string name="notice_direct_room_created">%1$s vytvoril(a) konverzáciu</string> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-sq/strings.xml b/matrix-sdk-android/src/main/res/values-sq/strings.xml index 58ba8877bb719cbaeee5e6b75ea65ca367180681..0d4b2888ba016cbdd6628621c05b346308699320 100644 --- a/matrix-sdk-android/src/main/res/values-sq/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sq/strings.xml @@ -101,7 +101,7 @@ </plurals> <plurals name="notice_room_aliases_removed"> <item quantity="one">%1$s hoqi %2$s si adresë për këtë dhomë.</item> - <item quantity="other">%1$s hoqi %3$s si adresa për këtë dhomë.</item> + <item quantity="other">%1$s hoqi %2$s si adresa për këtë dhomë.</item> </plurals> <string name="notice_room_aliases_added_and_removed">%1$s shtoi %2$s dhe hoqi %3$s si adresa për këtë dhomë.</string> <string name="notice_room_canonical_alias_set">%1$s caktoi %2$s si adresë kryesore për këtë dhomë.</string> @@ -232,4 +232,26 @@ <string name="notice_room_server_acl_updated_banned">• Shërbyesit që kanë përputhje me %s tani janë të ndaluar.</string> <string name="notice_room_server_acl_set_allowed">• Shërbyesit që kanë përputhje me %s janë të ndaluar.</string> <string name="notice_room_server_acl_set_banned">• Shërbyesit që kanë përputhje me %s janë të ndaluar.</string> + <string name="notice_room_canonical_alias_no_change_by_you">Ndryshuat adresat për këtë dhomë.</string> + <string name="notice_room_canonical_alias_no_change">%1$s ndryshoi adresat për këtë dhomë.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">Ndryshuat adresat kryesore dhe alternative për këtë dhomë.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s ndryshoi adresat kryesore dhe alternative për këtë dhomë.</string> + <string name="notice_room_canonical_alias_alternative_changed_by_you">Ndryshuat adresat alternative për këtë dhomë.</string> + <string name="notice_room_canonical_alias_alternative_changed">%1$s ndryshoi adresat alternative për këtë dhomë.</string> + <plurals name="notice_room_canonical_alias_alternative_removed_by_you"> + <item quantity="one">Hoqët adresën alternative %1$s për këtë dhomë.</item> + <item quantity="other">Hoqët adresat alternative %1$s për këtë dhomë.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_removed"> + <item quantity="one">%1$s hoqët adresën alternative %2$s për këtë dhomë.</item> + <item quantity="other">%1$s hoqët adresat alternative %2$s për këtë dhomë.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added_by_you"> + <item quantity="one">Shtuat adresën alternative %1$s për këtë dhomë.</item> + <item quantity="other">Shtuat adresat alternative %1$s për këtë dhomë.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added"> + <item quantity="one">%1$s shtoi adresën alternative %2$s për këtë dhomë.</item> + <item quantity="other">%1$s shtoi adresat alternative %2$s për këtë dhomë.</item> + </plurals> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-sv/strings.xml b/matrix-sdk-android/src/main/res/values-sv/strings.xml index d42c6ba2cae6e9960dbb7fbf2bcd7ed07458b8ff..91d874591f5e033d41c115c3799798ccd0f48e97 100644 --- a/matrix-sdk-android/src/main/res/values-sv/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sv/strings.xml @@ -213,4 +213,49 @@ <string name="notice_direct_room_join">%1$s gick med</string> <string name="notice_direct_room_created_by_you">Du skapade diskussionen</string> <string name="notice_direct_room_created">%1$s skapade diskussionen</string> + <string name="notice_room_canonical_alias_no_change_by_you">Du ändrade adresserna för det här rummet.</string> + <string name="notice_room_canonical_alias_no_change">%1$s ändrade adresserna för det här rummet.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">Du ändrade huvudadressen och de alternativa adresserna för det här rummet.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s ändrade huvudadressen och de alternativa adresserna för det här rummet.</string> + <string name="notice_room_canonical_alias_alternative_changed_by_you">Du ändrade de alternativa adresserna för det här rummet.</string> + <string name="notice_room_canonical_alias_alternative_changed">%1$s ändrade de alternativa adresserna för det här rummet.</string> + <plurals name="notice_room_canonical_alias_alternative_removed_by_you"> + <item quantity="one">Du tog bort den alternativa adressen %1$s för det här rummet.</item> + <item quantity="other">Du tog bort de alternativa adresserna %1$s för det här rummet.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_removed"> + <item quantity="one">%1$s tog bort den alternativa adressen %2$s för det här rummet.</item> + <item quantity="other">%1$s tog bort de alternativa adresserna %2$s för det här rummet.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added_by_you"> + <item quantity="one">Du lade till den alternativa adressen %1$s för det här rummet.</item> + <item quantity="other">Du lade till de alternativa adresserna %1$s för det här rummet.</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added"> + <item quantity="one">%1$s lade till den alternativa adressen %2$s för det här rummet.</item> + <item quantity="other">%1$s lade till de alternativa adresserna %2$s för det här rummet.</item> + </plurals> + <string name="room_displayname_empty_room_was">Tomt rum (var %s)</string> + <plurals name="room_displayname_four_and_more_members"> + <item quantity="one">%1$s, %2$s, %3$s och %4$d till</item> + <item quantity="other">%1$s, %2$s, %3$s och %4$d till</item> + </plurals> + <string name="room_displayname_4_members">%1$s, %2$s, %3$s och %4$s</string> + <string name="room_displayname_3_members">%1$s, %2$s och %3$s</string> + <string name="notice_room_server_acl_allow_is_empty">🎉 Alla servrar har bannats frÃ¥n att delta! Det här rummet kan inte användas längre.</string> + <string name="notice_room_server_acl_updated_no_change">Ingen ändring.</string> + <string name="notice_room_server_acl_updated_ip_literals_not_allowed">• Servrar som matchar IP-adresser är nu bannade.</string> + <string name="notice_room_server_acl_updated_ip_literals_allowed">• Servrar som matchar IP-adresser är nu tillÃ¥tna.</string> + <string name="notice_room_server_acl_updated_was_allowed">• Servrar som matchar %s togs bort frÃ¥n tillÃ¥telselistan.</string> + <string name="notice_room_server_acl_updated_allowed">• Servrar som matchar %s är nu tillÃ¥tna.</string> + <string name="notice_room_server_acl_updated_was_banned">• Servrar som matchar %s togs bort frÃ¥n bannlistan.</string> + <string name="notice_room_server_acl_updated_banned">• Servrar som matchar %s är nu bannade.</string> + <string name="notice_room_server_acl_updated_title_by_you">Du ändrade server-ACLer för det här rummet.</string> + <string name="notice_room_server_acl_updated_title">%s ändrade server-ACLer för det här rummet.</string> + <string name="notice_room_server_acl_set_ip_literals_allowed">• Servrar som matchar IP-adresser är tillÃ¥tna.</string> + <string name="notice_room_server_acl_set_ip_literals_not_allowed">• Servrar som matchar IP-adresser är bannade.</string> + <string name="notice_room_server_acl_set_allowed">• Servrar som matchar %s är tillÃ¥tna.</string> + <string name="notice_room_server_acl_set_banned">• Servrar som matchar %s är bannade.</string> + <string name="notice_room_server_acl_set_title_by_you">Du satte server-ACLer för det här rummet.</string> + <string name="notice_room_server_acl_set_title">%s satte server-ACLer för det här rummet.</string> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-szl/strings.xml b/matrix-sdk-android/src/main/res/values-szl/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6b3daec9354f9ae75cdf8d94a67446c6227dd96 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-szl/strings.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources></resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-uk/strings.xml b/matrix-sdk-android/src/main/res/values-uk/strings.xml index 24774873796d4decea113943e39569ba49c5bdb1..0f45a7182ca6d16111ad3e07db35fa1197d6857e 100644 --- a/matrix-sdk-android/src/main/res/values-uk/strings.xml +++ b/matrix-sdk-android/src/main/res/values-uk/strings.xml @@ -13,7 +13,7 @@ <string name="summary_user_sent_sticker">%1$s надіÑлав(ла) наліпку.</string> <string name="notice_room_invite_you">%1$s запроÑив(ла) ВаÑ</string> <string name="notice_room_join">%1$s приєднуєтьÑÑ</string> - <string name="notice_room_leave">%1$s покинув(ла)</string> + <string name="notice_room_leave">%1$s покидає кімнату</string> <string name="notice_room_reject">%1$s відхилив(ла) запрошеннÑ</string> <string name="notice_room_kick">%1$s копнув(ла) %2$s</string> <string name="notice_room_unban">%1$s розблокував(ла) %2$s</string> @@ -65,4 +65,23 @@ <string name="notice_event_redacted">ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð¾</string> <string name="notice_event_redacted_by">%1$s видалили повідомленнÑ</string> <string name="notice_event_redacted_with_reason">ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð¾ [причина: %1$s]</string> + <string name="initial_sync_start_importing_account_data">Початкове налаштуваннÑ: +\nÐ†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… облікового запиÑу</string> + <string name="notice_direct_room_leave_with_reason_by_you">Ви покинули. Причина: %1$s</string> + <string name="notice_direct_room_leave_with_reason">%1$s покидає. Причина: %2$s</string> + <string name="notice_room_leave_with_reason_by_you">Ви покинули кімнату. Причина: %1$s</string> + <string name="notice_room_leave_with_reason">%1$s покидає кімнату. Причина: %2$s</string> + <string name="notice_direct_room_leave">%1$s покидає кімнату</string> + <string name="notice_direct_room_leave_by_you">Ви покинули кімнату</string> + <string name="notice_room_leave_by_you">Ви покинули кімнату</string> + <string name="notice_room_canonical_alias_no_change_by_you">Ви змінили адреÑи цієї кімнати.</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">Ви змінили оÑновну та альтернативну адреÑи цієї кімнати.</string> + <string name="notice_room_canonical_alias_alternative_changed_by_you">Ви змінили альтернативні адреÑи Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— кімнати.</string> + <string name="notice_power_level_changed_by_you">Ви змінили рівень доÑтупу на %1$s.</string> + <string name="notice_room_server_acl_updated_title_by_you">Ви змінили Ñерверні ÑпиÑки контролю доÑтупу Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— кімнати.</string> + <string name="notice_room_name_changed_by_you">Ви змінили назву кімнати на: %1$s</string> + <string name="notice_room_avatar_changed_by_you">Ви змінили Ñвітлину кімнати</string> + <string name="notice_room_topic_changed_by_you">Ви змінили тему на: %1$s</string> + <string name="notice_display_name_changed_from_by_you">Ви змінили показуване ім\'Ñ Ð· %1$s на %2$s</string> + <string name="notice_avatar_url_changed_by_you">Ви змінили Ñвітлину профілю</string> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml index 08050b400d3f2a0095826cd3a03e976bab24fc4d..5038e8aab2a12395019c11c03c7130c709450108 100644 --- a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml +++ b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml @@ -98,7 +98,7 @@ <item quantity="other">%1$s 新增了 %2$s 為æ¤èŠå¤©å®¤çš„地å€ã€‚</item> </plurals> <plurals name="notice_room_aliases_removed"> - <item quantity="other">%1$s 移除了æ¤èŠå¤©å®¤çš„ %3$s 地å€ã€‚</item> + <item quantity="other">%1$s 移除了æ¤èŠå¤©å®¤çš„ %2$s 地å€ã€‚</item> </plurals> <string name="notice_room_aliases_added_and_removed">%1$s 為æ¤èŠå¤©å®¤æ–°å¢ž %2$s 並移除 %3$s 地å€ã€‚</string> <string name="notice_room_canonical_alias_set">%1$s 為æ¤èŠå¤©å®¤è¨å®šäº† %2$s 為主地å€ã€‚</string> @@ -230,4 +230,22 @@ <string name="notice_room_server_acl_set_banned">• å·²ç¦æ¢ä¼ºæœå™¨ç¬¦åˆ %s。</string> <string name="notice_room_server_acl_set_title_by_you">您為æ¤èŠå¤©æ˜¯è¨å®šäº†ä¼ºæœå™¨ ACL。</string> <string name="notice_room_server_acl_set_title">%s 為æ¤èŠå¤©æ˜¯è¨å®šäº†ä¼ºæœå™¨ ACL。</string> + <string name="notice_room_canonical_alias_no_change_by_you">您變更了æ¤èŠå¤©å®¤çš„地å€ã€‚</string> + <string name="notice_room_canonical_alias_no_change">%1$s 變更了æ¤èŠå¤©å®¤çš„地å€ã€‚</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">您為æ¤èŠå¤©å®¤è®Šæ›´äº†ä¸»è¦åŠå‚™ç”¨åœ°å€ã€‚</string> + <string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s 為æ¤èŠå¤©å®¤è®Šæ›´äº†ä¸»è¦åŠå‚™ç”¨åœ°å€ã€‚</string> + <string name="notice_room_canonical_alias_alternative_changed_by_you">您為æ¤èŠå¤©å®¤è®Šæ›´äº†å‚™ç”¨åœ°å€ã€‚</string> + <string name="notice_room_canonical_alias_alternative_changed">%1$s 變更了æ¤èŠå¤©å®¤çš„備用地å€ã€‚</string> + <plurals name="notice_room_canonical_alias_alternative_removed_by_you"> + <item quantity="other">您為æ¤èŠå¤©å®¤ç§»é™¤äº†å‚™ç”¨åœ°å€ %1$s。</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_removed"> + <item quantity="other">%1$s 已為æ¤èŠå¤©å®¤ç§»é™¤å‚™ç”¨åœ°å€ %2$s。</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added_by_you"> + <item quantity="other">您為æ¤èŠå¤©å®¤æ–°å¢žäº†å‚™ç”¨åœ°å€ %1$s。</item> + </plurals> + <plurals name="notice_room_canonical_alias_alternative_added"> + <item quantity="other">%1$s 已為æ¤èŠå¤©å®¤æ–°å¢žäº†å‚™ç”¨åœ°å€ %2$s。</item> + </plurals> </resources> \ No newline at end of file diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt index 667e0b2471f08a735fbc91fa8f874cebeeee9e81..74b6c03d93b15844e19b5d430b34a0baa987ae36 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt @@ -38,19 +38,16 @@ class CoroutineSequencersTest: MatrixTest { val jobs = listOf( GlobalScope.launch(dispatcher) { - sequencer.post { suspendingMethod("#1") }.also { - results.add(it) - } + sequencer.post { suspendingMethod("#1") } + .also { results.add(it) } }, GlobalScope.launch(dispatcher) { - sequencer.post { suspendingMethod("#2") }.also { - results.add(it) - } + sequencer.post { suspendingMethod("#2") } + .also { results.add(it) } }, GlobalScope.launch(dispatcher) { - sequencer.post { suspendingMethod("#3") }.also { - results.add(it) - } + sequencer.post { suspendingMethod("#3") } + .also { results.add(it) } } ) runBlocking { @@ -70,19 +67,16 @@ class CoroutineSequencersTest: MatrixTest { val results = ArrayList<String>() val jobs = listOf( GlobalScope.launch(dispatcher) { - sequencer1.post { suspendingMethod("#1") }.also { - results.add(it) - } + sequencer1.post { suspendingMethod("#1") } + .also { results.add(it) } }, GlobalScope.launch(dispatcher) { - sequencer2.post { suspendingMethod("#2") }.also { - results.add(it) - } + sequencer2.post { suspendingMethod("#2") } + .also { results.add(it) } }, GlobalScope.launch(dispatcher) { - sequencer3.post { suspendingMethod("#3") }.also { - results.add(it) - } + sequencer3.post { suspendingMethod("#3") } + .also { results.add(it) } } ) runBlocking { @@ -97,20 +91,17 @@ class CoroutineSequencersTest: MatrixTest { val results = ArrayList<String>() val jobs = listOf( GlobalScope.launch(dispatcher) { - sequencer.post { suspendingMethod("#1") }.also { - results.add(it) - } + sequencer.post { suspendingMethod("#1") } + .also { results.add(it) } }, GlobalScope.launch(dispatcher) { - val result = sequencer.post { suspendingMethod("#2") }.also { - results.add(it) - } - println("Result: $result") + sequencer.post { suspendingMethod("#2") } + .also { results.add(it) } + .also { println("Result: $it") } }, GlobalScope.launch(dispatcher) { - sequencer.post { suspendingMethod("#3") }.also { - results.add(it) - } + sequencer.post { suspendingMethod("#3") } + .also { results.add(it) } } ) // We are canceling the second job