diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt index 053b4e19bd..0d71af864b 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt @@ -17,6 +17,8 @@ package org.matrix.android.sdk.api import android.content.Context +import android.os.Handler +import android.os.Looper import androidx.lifecycle.ProcessLifecycleOwner import androidx.work.Configuration import androidx.work.WorkManager @@ -48,13 +50,17 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo @Inject internal lateinit var olmManager: OlmManager @Inject internal lateinit var sessionManager: SessionManager + private val uiHandler = Handler(Looper.getMainLooper()) + init { Monarchy.init(context) DaggerTestMatrixComponent.factory().create(context, matrixConfiguration).inject(this) if (context.applicationContext !is Configuration.Provider) { WorkManager.initialize(context, Configuration.Builder().setExecutor(Executors.newCachedThreadPool()).build()) } - ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver) + uiHandler.post { + ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver) + } } fun getUserAgent() = userAgentHolder.userAgent diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreHelper.kt index 6e6a11d568..75ccce0db9 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreHelper.kt @@ -16,7 +16,6 @@ package org.matrix.android.sdk.internal.crypto -import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule @@ -34,14 +33,8 @@ internal class CryptoStoreHelper { .modules(RealmCryptoStoreModule()) .build(), crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi()), - credentials = createCredential()) + userId = "userId_" + Random.nextInt(), + deviceId = "deviceId_sample" + ) } - - fun createCredential() = Credentials( - userId = "userId_" + Random.nextInt(), - homeServer = "http://matrix.org", - accessToken = "access_token", - refreshToken = null, - deviceId = "deviceId_sample" - ) } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt new file mode 100644 index 0000000000..e42059c639 --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt @@ -0,0 +1,111 @@ +/* + * 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.encryption + +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.NoOpMatrixCallback +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.Room +import org.matrix.android.sdk.api.session.room.send.SendState +import org.matrix.android.sdk.api.session.room.timeline.Timeline +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +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 org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM +import org.matrix.android.sdk.internal.crypto.model.event.EncryptionEventContent +import java.util.concurrent.CountDownLatch + +@RunWith(AndroidJUnit4::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class EncryptionTest : InstrumentedTest { + private val mTestHelper = CommonTestHelper(context()) + private val mCryptoTestHelper = CryptoTestHelper(mTestHelper) + + @Test + fun test_EncryptionEvent() { + performTest(roomShouldBeEncrypted = false) { room -> + // Send an encryption Event as an Event (and not as a state event) + room.sendEvent( + eventType = EventType.STATE_ROOM_ENCRYPTION, + content = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent() + ) + } + } + + @Test + fun test_EncryptionStateEvent() { + performTest(roomShouldBeEncrypted = true) { room -> + // Send an encryption Event as a State Event + room.sendStateEvent( + eventType = EventType.STATE_ROOM_ENCRYPTION, + stateKey = null, + body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent(), + callback = NoOpMatrixCallback() + ) + } + } + + private fun performTest(roomShouldBeEncrypted: Boolean, action: (Room) -> Unit) { + val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceInARoom(encryptedRoom = false) + + val aliceSession = cryptoTestData.firstSession + val room = aliceSession.getRoom(cryptoTestData.roomId)!! + + room.isEncrypted() shouldBe false + + val timeline = room.createTimeline(null, TimelineSettings(10)) + val latch = CountDownLatch(1) + val timelineListener = object : Timeline.Listener { + override fun onTimelineFailure(throwable: Throwable) { + } + + override fun onNewTimelineEvents(eventIds: List) { + // noop + } + + override fun onTimelineUpdated(snapshot: List) { + val newMessages = snapshot + .filter { it.root.sendState == SendState.SYNCED } + .filter { it.root.getClearType() == EventType.STATE_ROOM_ENCRYPTION } + + if (newMessages.isNotEmpty()) { + timeline.removeListener(this) + latch.countDown() + } + } + } + timeline.start() + timeline.addListener(timelineListener) + + action.invoke(room) + + mTestHelper.await(latch) + timeline.dispose() + + room.isEncrypted() shouldBe roomShouldBeEncrypted + + cryptoTestData.cleanUp(mTestHelper) + } +} diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt index 92afd3ee47..ee604fc9ab 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt @@ -17,15 +17,14 @@ package org.matrix.android.sdk.internal.crypto.verification.qrcode import androidx.test.ext.junit.runners.AndroidJUnit4 -import org.matrix.android.sdk.InstrumentedTest +import org.amshove.kluent.shouldBeEqualTo import org.amshove.kluent.shouldBeNull -import org.amshove.kluent.shouldEqual -import org.amshove.kluent.shouldEqualTo import org.amshove.kluent.shouldNotBeNull import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters +import org.matrix.android.sdk.InstrumentedTest @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.JVM) @@ -66,32 +65,32 @@ class QrCodeTest : InstrumentedTest { @Test fun testEncoding1() { - qrCode1.toEncodedString() shouldEqual value1 + qrCode1.toEncodedString() shouldBeEqualTo value1 } @Test fun testEncoding2() { - qrCode2.toEncodedString() shouldEqual value2 + qrCode2.toEncodedString() shouldBeEqualTo value2 } @Test fun testEncoding3() { - qrCode3.toEncodedString() shouldEqual value3 + qrCode3.toEncodedString() shouldBeEqualTo value3 } @Test fun testSymmetry1() { - qrCode1.toEncodedString().toQrCodeData() shouldEqual qrCode1 + qrCode1.toEncodedString().toQrCodeData() shouldBeEqualTo qrCode1 } @Test fun testSymmetry2() { - qrCode2.toEncodedString().toQrCodeData() shouldEqual qrCode2 + qrCode2.toEncodedString().toQrCodeData() shouldBeEqualTo qrCode2 } @Test fun testSymmetry3() { - qrCode3.toEncodedString().toQrCodeData() shouldEqual qrCode3 + qrCode3.toEncodedString().toQrCodeData() shouldBeEqualTo qrCode3 } @Test @@ -102,7 +101,7 @@ class QrCodeTest : InstrumentedTest { checkHeader(byteArray) // Mode - byteArray[7] shouldEqualTo 0 + byteArray[7] shouldBeEqualTo 0 checkSizeAndTransaction(byteArray) @@ -120,7 +119,7 @@ class QrCodeTest : InstrumentedTest { checkHeader(byteArray) // Mode - byteArray[7] shouldEqualTo 1 + byteArray[7] shouldBeEqualTo 1 checkSizeAndTransaction(byteArray) compareArray(byteArray.copyOfRange(23, 23 + 32), kte_byteArray) @@ -137,7 +136,7 @@ class QrCodeTest : InstrumentedTest { checkHeader(byteArray) // Mode - byteArray[7] shouldEqualTo 2 + byteArray[7] shouldBeEqualTo 2 checkSizeAndTransaction(byteArray) compareArray(byteArray.copyOfRange(23, 23 + 32), tlx_byteArray) @@ -156,10 +155,10 @@ class QrCodeTest : InstrumentedTest { val result = qrCode.toEncodedString() val expected = value1.replace("\u0000\u000DMaTransaction", "\u0007\u00D0$longTransactionId") - result shouldEqual expected + result shouldBeEqualTo expected // Reverse operation - expected.toQrCodeData() shouldEqual qrCode + expected.toQrCodeData() shouldBeEqualTo qrCode } @Test @@ -170,7 +169,7 @@ class QrCodeTest : InstrumentedTest { val qrCode = qrCode1.copy(transactionId = longTransactionId) // Symmetric operation - qrCode.toEncodedString().toQrCodeData() shouldEqual qrCode + qrCode.toEncodedString().toQrCodeData() shouldBeEqualTo qrCode } } @@ -218,32 +217,32 @@ class QrCodeTest : InstrumentedTest { } private fun compareArray(actual: ByteArray, expected: ByteArray) { - actual.size shouldEqual expected.size + actual.size shouldBeEqualTo expected.size for (i in actual.indices) { - actual[i] shouldEqualTo expected[i] + actual[i] shouldBeEqualTo expected[i] } } private fun checkHeader(byteArray: ByteArray) { // MATRIX - byteArray[0] shouldEqualTo 'M'.toByte() - byteArray[1] shouldEqualTo 'A'.toByte() - byteArray[2] shouldEqualTo 'T'.toByte() - byteArray[3] shouldEqualTo 'R'.toByte() - byteArray[4] shouldEqualTo 'I'.toByte() - byteArray[5] shouldEqualTo 'X'.toByte() + byteArray[0] shouldBeEqualTo 'M'.toByte() + byteArray[1] shouldBeEqualTo 'A'.toByte() + byteArray[2] shouldBeEqualTo 'T'.toByte() + byteArray[3] shouldBeEqualTo 'R'.toByte() + byteArray[4] shouldBeEqualTo 'I'.toByte() + byteArray[5] shouldBeEqualTo 'X'.toByte() // Version - byteArray[6] shouldEqualTo 2 + byteArray[6] shouldBeEqualTo 2 } private fun checkSizeAndTransaction(byteArray: ByteArray) { // Size - byteArray[8] shouldEqualTo 0 - byteArray[9] shouldEqualTo 13 + byteArray[8] shouldBeEqualTo 0 + byteArray[9] shouldBeEqualTo 13 // Transaction - byteArray.copyOfRange(10, 10 + "MaTransaction".length).toString(Charsets.ISO_8859_1) shouldEqual "MaTransaction" + byteArray.copyOfRange(10, 10 + "MaTransaction".length).toString(Charsets.ISO_8859_1) shouldBeEqualTo "MaTransaction" } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt index 237386832c..69ae57e644 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt @@ -18,6 +18,14 @@ package org.matrix.android.sdk.session.room.timeline import androidx.test.ext.junit.runners.AndroidJUnit4 import com.zhuinden.monarchy.Monarchy +import io.realm.Realm +import io.realm.RealmConfiguration +import io.realm.kotlin.createObject +import org.amshove.kluent.shouldBeEqualTo +import org.amshove.kluent.shouldBeTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.send.SendState @@ -29,14 +37,6 @@ import org.matrix.android.sdk.internal.database.model.SessionRealmModule import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeListOfEvents import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeMessageEvent -import io.realm.Realm -import io.realm.RealmConfiguration -import io.realm.kotlin.createObject -import org.amshove.kluent.shouldBeTrue -import org.amshove.kluent.shouldEqual -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) internal class ChunkEntityTest : InstrumentedTest { @@ -60,10 +60,10 @@ internal class ChunkEntityTest : InstrumentedTest { val chunk: ChunkEntity = realm.createObject() val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED, System.currentTimeMillis()).let { - realm.copyToRealmOrUpdate(it) + realm.copyToRealm(it) } chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap()) - chunk.timelineEvents.size shouldEqual 1 + chunk.timelineEvents.size shouldBeEqualTo 1 } } @@ -72,11 +72,11 @@ internal class ChunkEntityTest : InstrumentedTest { monarchy.runTransactionSync { realm -> val chunk: ChunkEntity = realm.createObject() val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED, System.currentTimeMillis()).let { - realm.copyToRealmOrUpdate(it) + realm.copyToRealm(it) } chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap()) chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap()) - chunk.timelineEvents.size shouldEqual 1 + chunk.timelineEvents.size shouldBeEqualTo 1 } } @@ -88,7 +88,7 @@ internal class ChunkEntityTest : InstrumentedTest { chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS) - chunk1.timelineEvents.size shouldEqual 60 + chunk1.timelineEvents.size shouldBeEqualTo 60 } } @@ -104,7 +104,7 @@ internal class ChunkEntityTest : InstrumentedTest { chunk1.addAll(ROOM_ID, eventsForChunk1, PaginationDirection.FORWARDS) chunk2.addAll(ROOM_ID, eventsForChunk2, PaginationDirection.BACKWARDS) chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS) - chunk1.timelineEvents.size shouldEqual 40 + chunk1.timelineEvents.size shouldBeEqualTo 40 chunk1.isLastForward.shouldBeTrue() } } @@ -119,7 +119,7 @@ internal class ChunkEntityTest : InstrumentedTest { chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk1.merge(ROOM_ID, chunk2, PaginationDirection.FORWARDS) - chunk1.prevToken shouldEqual prevToken + chunk1.prevToken shouldBeEqualTo prevToken } } @@ -133,7 +133,7 @@ internal class ChunkEntityTest : InstrumentedTest { chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS) - chunk1.nextToken shouldEqual nextToken + chunk1.nextToken shouldBeEqualTo nextToken } } @@ -142,7 +142,7 @@ internal class ChunkEntityTest : InstrumentedTest { direction: PaginationDirection) { events.forEach { event -> val fakeEvent = event.toEntity(roomId, SendState.SYNCED, System.currentTimeMillis()).let { - realm.copyToRealmOrUpdate(it) + realm.copyToRealm(it) } addTimelineEvent(roomId, fakeEvent, direction, emptyMap()) } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt index 0dace9bd4c..1adf31be5f 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt @@ -21,7 +21,7 @@ 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.toContent import org.matrix.android.sdk.api.session.room.model.Membership -import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary +import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent import org.matrix.android.sdk.api.session.room.model.message.MessageType import kotlin.random.Random @@ -41,11 +41,11 @@ object RoomDataHelper { } } - fun createFakeEvent(type: String, - content: Content? = null, - prevContent: Content? = null, - sender: String = FAKE_TEST_SENDER, - stateKey: String = FAKE_TEST_SENDER + private fun createFakeEvent(type: String, + content: Content? = null, + prevContent: Content? = null, + sender: String = FAKE_TEST_SENDER, + stateKey: String = FAKE_TEST_SENDER ): Event { return Event( type = type, @@ -62,8 +62,8 @@ object RoomDataHelper { return createFakeEvent(EventType.MESSAGE, message) } - fun createFakeRoomMemberEvent(): Event { - val roomMember = RoomMemberSummary(Membership.JOIN, "Fake name #${Random.nextLong()}").toContent() + private fun createFakeRoomMemberEvent(): Event { + val roomMember = RoomMemberContent(Membership.JOIN, "Fake name #${Random.nextLong()}").toContent() return createFakeEvent(EventType.STATE_ROOM_MEMBER, roomMember) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineTest.kt index 91016f7d01..9be0a5d5af 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineTest.kt @@ -78,7 +78,7 @@ internal class TimelineTest : InstrumentedTest { // } // } // latch.await() -// timelineEvents.size shouldEqual initialLoad + paginationCount +// timelineEvents.size shouldBeEqualTo initialLoad + paginationCount // timeline.dispose() // } } diff --git a/matrix-sdk-android/src/main/AndroidManifest.xml b/matrix-sdk-android/src/main/AndroidManifest.xml index eeb944d955..220a168f60 100644 --- a/matrix-sdk-android/src/main/AndroidManifest.xml +++ b/matrix-sdk-android/src/main/AndroidManifest.xml @@ -2,8 +2,10 @@ xmlns:tools="http://schemas.android.com/tools" package="org.matrix.android.sdk"> + + 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 c77ac70124..b78afe6d41 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 @@ -194,18 +194,18 @@ internal class DefaultCryptoService @Inject constructor( private val lastNewSessionForcedDates = MXUsersDevicesMap() fun onStateEvent(roomId: String, event: Event) { - when { - event.getClearType() == EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) - event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) - event.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) + when (event.getClearType()) { + EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) + EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) + EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) } } fun onLiveEvent(roomId: String, event: Event) { - when { - event.getClearType() == EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) - event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) - event.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) + when (event.getClearType()) { + EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) + EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) + EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) } } @@ -615,6 +615,7 @@ internal class DefaultCryptoService @Inject constructor( val encryptionEvent = monarchy.fetchCopied { realm -> EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION) .contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"") + .isNotNull(EventEntityFields.STATE_KEY) .findFirst() } return encryptionEvent != null @@ -915,6 +916,11 @@ internal class DefaultCryptoService @Inject constructor( * @param event the encryption event. */ private fun onRoomEncryptionEvent(roomId: String, event: Event) { + if (!event.isStateEvent()) { + // Ignore + Timber.w("Invalid encryption event") + return + } cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { val params = LoadRoomMembersTask.Params(roomId) try { 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 9065da47b9..b25349cba9 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 @@ -23,7 +23,6 @@ import io.realm.Realm import io.realm.RealmConfiguration import io.realm.Sort import io.realm.kotlin.where -import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.LocalEcho @@ -86,7 +85,9 @@ import org.matrix.android.sdk.internal.crypto.store.db.query.getById import org.matrix.android.sdk.internal.crypto.store.db.query.getOrCreate import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.di.CryptoDatabase +import org.matrix.android.sdk.internal.di.DeviceId import org.matrix.android.sdk.internal.di.MoshiProvider +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 @@ -98,7 +99,9 @@ import kotlin.collections.set internal class RealmCryptoStore @Inject constructor( @CryptoDatabase private val realmConfiguration: RealmConfiguration, private val crossSigningKeysMapper: CrossSigningKeysMapper, - private val credentials: Credentials) : IMXCryptoStore { + @UserId private val userId: String, + @DeviceId private val deviceId: String? +) : IMXCryptoStore { /* ========================================================================================== * Memory cache, to correctly release JNI objects @@ -141,8 +144,8 @@ internal class RealmCryptoStore @Inject constructor( // Check credentials // The device id may not have been provided in credentials. // Check it only if provided, else trust the stored one. - if (currentMetadata.userId != credentials.userId - || (credentials.deviceId != null && credentials.deviceId != currentMetadata.deviceId)) { + if (currentMetadata.userId != userId + || (deviceId != null && deviceId != currentMetadata.deviceId)) { Timber.w("## open() : Credentials do not match, close this store and delete data") deleteAll = true currentMetadata = null @@ -155,8 +158,8 @@ internal class RealmCryptoStore @Inject constructor( } // Metadata not found, or database cleaned, create it - realm.createObject(CryptoMetadataEntity::class.java, credentials.userId).apply { - deviceId = credentials.deviceId + realm.createObject(CryptoMetadataEntity::class.java, userId).apply { + deviceId = this@RealmCryptoStore.deviceId } } } @@ -312,7 +315,7 @@ internal class RealmCryptoStore @Inject constructor( Timber.d("## CrossSigning MSK change for $userId") val keyEntity = crossSigningKeysMapper.map(masterKey) signingInfo.setMasterKey(keyEntity) - if (userId == credentials.userId) { + if (userId == this.userId) { shouldResetMyDevicesLocalTrust = true // my msk has changed! clear my private key // Could we have some race here? e.g I am the one that did change the keys @@ -331,7 +334,7 @@ internal class RealmCryptoStore @Inject constructor( Timber.d("## CrossSigning SSK change for $userId") val keyEntity = crossSigningKeysMapper.map(selfSigningKey) signingInfo.setSelfSignedKey(keyEntity) - if (userId == credentials.userId) { + if (userId == this.userId) { shouldResetMyDevicesLocalTrust = true // my ssk has changed! clear my private key realm.where().findFirst()?.apply { @@ -349,7 +352,7 @@ internal class RealmCryptoStore @Inject constructor( Timber.d("## CrossSigning USK change for $userId") val keyEntity = crossSigningKeysMapper.map(userSigningKey) signingInfo.setUserSignedKey(keyEntity) - if (userId == credentials.userId) { + if (userId == this.userId) { shouldResetMyDevicesLocalTrust = true // my usk has changed! clear my private key realm.where().findFirst()?.apply { @@ -362,11 +365,11 @@ internal class RealmCryptoStore @Inject constructor( // When my cross signing keys are reset, we consider clearing all existing device trust if (shouldResetMyDevicesLocalTrust) { realm.where() - .equalTo(UserEntityFields.USER_ID, credentials.userId) + .equalTo(UserEntityFields.USER_ID, this.userId) .findFirst() ?.devices?.forEach { it?.trustLevelEntity?.crossSignedVerified = false - it?.trustLevelEntity?.locallyVerified = it.deviceId == credentials.deviceId + it?.trustLevelEntity?.locallyVerified = it.deviceId == deviceId } } userEntity.crossSigningInfoEntity = signingInfo @@ -1355,7 +1358,7 @@ internal class RealmCryptoStore @Inject constructor( .findAll() xInfoEntities?.forEach { info -> // Need to ignore mine - if (info.userId != credentials.userId) { + if (info.userId != userId) { info.crossSigningKeys.forEach { it.trustLevelEntity = null } @@ -1370,7 +1373,7 @@ internal class RealmCryptoStore @Inject constructor( .findAll() xInfoEntities?.forEach { xInfoEntity -> // Need to ignore mine - if (xInfoEntity.userId == credentials.userId) return@forEach + if (xInfoEntity.userId == userId) return@forEach val mapped = mapCrossSigningInfoEntity(xInfoEntity) val currentTrust = mapped.isTrusted() val newTrust = check(mapped.userId) 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 f58059d6f2..f9a27c367c 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 @@ -94,6 +94,7 @@ internal class RoomSummaryUpdater @Inject constructor( // Don't use current state for this one as we are only interested in having MXCRYPTO_ALGORITHM_MEGOLM event in the room val encryptionEvent = EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION) .contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"") + .isNotNull(EventEntityFields.STATE_KEY) .findFirst() val latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/BinaryStringTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/BinaryStringTest.kt index a56426688d..b04834f9f4 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/BinaryStringTest.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/BinaryStringTest.kt @@ -17,13 +17,13 @@ package org.matrix.android.sdk.internal.crypto.verification.qrcode import org.matrix.android.sdk.MatrixTest -import org.amshove.kluent.shouldEqualTo +import org.amshove.kluent.shouldBeEqualTo import org.junit.FixMethodOrder import org.junit.Test import org.junit.runners.MethodSorters @FixMethodOrder(MethodSorters.JVM) -class BinaryStringTest: MatrixTest { +class BinaryStringTest : MatrixTest { /** * I want to put bytes to a String, and vice versa @@ -37,17 +37,17 @@ class BinaryStringTest: MatrixTest { val str = byteArray.toString(Charsets.ISO_8859_1) - str.length shouldEqualTo 256 + str.length shouldBeEqualTo 256 // Ok convert back to bytearray val result = str.toByteArray(Charsets.ISO_8859_1) - result.size shouldEqualTo 256 + result.size shouldBeEqualTo 256 for (i in 0..255) { - result[i] shouldEqualTo i.toByte() - result[i] shouldEqualTo byteArray[i] + result[i] shouldBeEqualTo i.toByte() + result[i] shouldBeEqualTo byteArray[i] } } } diff --git a/tools/check/forbidden_strings_in_resources.txt b/tools/check/forbidden_strings_in_resources.txt index 0bbe90b31f..6fb6b184ba 100644 --- a/tools/check/forbidden_strings_in_resources.txt +++ b/tools/check/forbidden_strings_in_resources.txt @@ -79,9 +79,5 @@ layout_constraintLeft_ ### Use im.vector.app.core.preference.VectorPreference to support multiline of the title ()?.algorithm val informationData = informationDataFactory.create(event, null) val attributes = messageItemAttributesFactory.create(null, informationData, callback) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt index 35db7fe469..e7a911ceb1 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt @@ -148,7 +148,7 @@ class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolde var hasEncryption = false var encryptionAlgorithm: String? = null while (prevEvent != null && prevEvent.isRoomConfiguration(null)) { - if (prevEvent.root.getClearType() == EventType.STATE_ROOM_ENCRYPTION) { + if (prevEvent.root.isStateEvent() && prevEvent.root.getClearType() == EventType.STATE_ROOM_ENCRYPTION) { hasEncryption = true encryptionAlgorithm = prevEvent.root.getClearContent()?.toModel()?.algorithm } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/NoticeEventFormatter.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/NoticeEventFormatter.kt index e26472feb0..1a5f820831 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/NoticeEventFormatter.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/NoticeEventFormatter.kt @@ -428,6 +428,9 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour } private fun formatRoomEncryptionEvent(event: Event, senderName: String?): CharSequence? { + if (!event.isStateEvent()) { + return null + } val content = event.content.toModel() ?: return null return when (content.algorithm) { MXCRYPTO_ALGORITHM_MEGOLM -> diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt index b1b1109580..14b8c12fee 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt @@ -55,7 +55,7 @@ fun TimelineEvent.canBeMerged(): Boolean { } fun TimelineEvent.isRoomConfiguration(roomCreatorUserId: String?): Boolean { - return when (root.getClearType()) { + return root.isStateEvent() && when (root.getClearType()) { EventType.STATE_ROOM_GUEST_ACCESS, EventType.STATE_ROOM_HISTORY_VISIBILITY, EventType.STATE_ROOM_JOIN_RULES, diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt index 77337d7208..66745fef25 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt @@ -58,9 +58,6 @@ class RoomMemberListFragment @Inject constructor( setupSearchView() setupInviteUsersButton() recyclerView.configureWith(roomMemberListController, hasFixedSize = true) - viewModel.selectSubscribe(this, RoomMemberListViewState::actionsPermissions) { - invalidateOptionsMenu() - } } private fun setupInviteUsersButton() { @@ -88,7 +85,6 @@ class RoomMemberListFragment @Inject constructor( } private fun setupSearchView() { - searchViewAppBarLayout.isVisible = true searchView.queryHint = getString(R.string.search_members_hint) searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { @@ -111,6 +107,8 @@ class RoomMemberListFragment @Inject constructor( roomMemberListController.setData(viewState) renderRoomSummary(viewState) inviteUsersButton.isVisible = viewState.actionsPermissions.canInvite + // Display filter only if there are more than 2 members in this room + searchViewAppBarLayout.isVisible = viewState.roomSummary()?.otherMemberIds.orEmpty().size > 1 } override fun onRoomMemberClicked(roomMember: RoomMemberSummary) { diff --git a/vector/src/main/res/layout/item_expandable_textview.xml b/vector/src/main/res/layout/item_expandable_textview.xml index b0c232d77e..9f61a3c4d4 100644 --- a/vector/src/main/res/layout/item_expandable_textview.xml +++ b/vector/src/main/res/layout/item_expandable_textview.xml @@ -10,7 +10,11 @@ android:id="@+id/expandableContent" android:layout_width="match_parent" android:layout_height="wrap_content" + android:autoLink="web" android:ellipsize="end" + android:fontFamily="sans-serif" + android:textSize="14sp" + android:textStyle="normal" app:layout_constraintBottom_toTopOf="@+id/expandableArrow" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -23,12 +27,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="4dp" - android:autoLink="web" - android:fontFamily="sans-serif" - android:gravity="center" android:src="@drawable/ic_expand_more" - android:textSize="14sp" - android:textStyle="normal" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/expandableContent"