diff --git a/CHANGES.md b/CHANGES.md index 587f2d61c2..9d2f39a441 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,15 @@ +Changes in Element v1.6.22 (2024-09-23) +======================================= + +Important: this version removes the dependency of the deprecated libolm library. +Application installations that have not been updated to the first version with the migration (1.6.3 release at 2023-06-27) will not be able to migrate the account. +More details in ([#8901](https://github.com/element-hq/element-android/issues/8901)) + +Other changes +------------- + - Remove legacy QR code login. ([#8889](https://github.com/element-hq/element-android/issues/8889)) + + Changes in Element v1.6.20 (2024-07-25) ======================================= @@ -13,7 +25,7 @@ Bugfixes 🐛 ---------- - Fix redacted events not grouped correctly when hidden events are inserted between. ([#8840](https://github.com/element-hq/element-android/issues/8840)) - Element-Android session doesn't encrypt for a dehydrated device ([#8842](https://github.com/element-hq/element-android/issues/8842)) - - Intercept only links from `element.io` well known hosts. The previous behaviour broke OIDC login in Element X. ([#8894](https://github.com/element-hq/element-android/issues/8894)) + - Intercept only links from `element.io` well known hosts. The previous behaviour broke OIDC login in Element X. ([#8849](https://github.com/element-hq/element-android/issues/8849)) Other changes ------------- diff --git a/build.gradle b/build.gradle index 5fd7606f3e..cbb72b9266 100644 --- a/build.gradle +++ b/build.gradle @@ -88,9 +88,9 @@ allprojects { } // Jitsi repo maven { - url "https://github.com/element-hq/jitsi_libre_maven/raw/main/android-sdk-8.1.1" + url "https://github.com/element-hq/jitsi_libre_maven/raw/main/mobile-sdk-10.2.0" // Note: to test Jitsi release you can use a local file like this: - // url "file:///Users/bmarty/workspaces/jitsi_libre_maven/android-sdk-8.1.1" + // url "file:///Users/bmarty/workspaces/jitsi_libre_maven/mobile-sdk-10.2.0" content { groups.jitsi.regex.each { includeGroupByRegex it } groups.jitsi.group.each { includeGroup it } diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index 5c976d8c32..478999d331 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -73,6 +73,7 @@ ext.groups = [ 'com.facebook.flipper', 'com.facebook.fresco', 'com.facebook.infer.annotation', + 'com.facebook.react', 'com.facebook.soloader', 'com.facebook.stetho', 'com.facebook.yoga', diff --git a/docs/jitsi.md b/docs/jitsi.md index b413d93dfc..d962b1e8a3 100644 --- a/docs/jitsi.md +++ b/docs/jitsi.md @@ -28,18 +28,18 @@ The generated maven repository is then host in the project https://github.com/el #### Jitsi version -Update the script `./tools/jitsi/build_jisti_libs.sh` with the tag of the project `https://github.com/jitsi/jitsi-meet`. +Update the script `./tools/jitsi/build_jitsi_libs.sh` with the tag of the project `https://github.com/jitsi/jitsi-meet`. Latest tag can be found from this page: https://github.com/jitsi/jitsi-meet-release-notes/blob/master/CHANGELOG-MOBILE-SDKS.md -Currently we are building the version with the tag `android-sdk-8.1.1`. +Currently we are building the version with the tag `mobile-sdk-10.2.0`. #### Run the build script At the root of the Element Android, run the following script: ```shell script -./tools/jitsi/build_jisti_libs.sh +./tools/jitsi/build_jitsi_libs.sh ``` It will build the Jitsi Meet Android library and put every generated files in the folder `/tmp/jitsi` @@ -49,7 +49,7 @@ It will build the Jitsi Meet Android library and put every generated files in th - Update the file `./build.gradle` to use the previously created local Maven repository. Currently we have this line: ```groovy -url "https://github.com/element-hq/jitsi_libre_maven/raw/main/android-sdk-8.1.1" +url "https://github.com/element-hq/jitsi_libre_maven/raw/main/mobile-sdk-10.2.0" ``` You can uncomment and update the line starting with `// url "file://...` and comment the line starting with `url`, to test the library using the locally generated Maven repository. @@ -57,13 +57,7 @@ You can uncomment and update the line starting with `// url "file://...` and com - Update the dependency of the Jitsi Meet library in the file `./vector/build.gradle`. Currently we have this line: ```groovy -api('org.jitsi.react:jitsi-meet-sdk:8.1.1') -``` - -- Update the dependency of the WebRTC library in the file `./vector/build.gradle`. Currently we have this line: - -```groovy -implementation('com.facebook.react:react-native-webrtc:111.0.0-jitsi-13672566@aar') +api('org.jitsi.react:jitsi-meet-sdk:10.2.0') ``` - Perform a gradle sync and build the project @@ -88,7 +82,7 @@ If all the tests are passed, you can export the generated Jitsi library to our M - Update the file `./build.gradle` to use the previously created Maven repository. Currently we have this line: ```groovy -url "https://github.com/element-hq/jitsi_libre_maven/raw/main/android-sdk-8.1.1" +url "https://github.com/element-hq/jitsi_libre_maven/raw/main/mobile-sdk-10.2.0" ``` - Build the project and perform the sanity tests again. diff --git a/fastlane/metadata/android/en-US/changelogs/40106220.txt b/fastlane/metadata/android/en-US/changelogs/40106220.txt new file mode 100644 index 0000000000..7a30d8a05a --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40106220.txt @@ -0,0 +1,2 @@ +Main changes in this version: crypto sdk upgrade. +Full changelog: https://github.com/element-hq/element-android/releases diff --git a/library/ui-strings/src/main/res/values-fa/strings.xml b/library/ui-strings/src/main/res/values-fa/strings.xml index e28afadaa8..4be2e46ce7 100644 --- a/library/ui-strings/src/main/res/values-fa/strings.xml +++ b/library/ui-strings/src/main/res/values-fa/strings.xml @@ -2966,4 +2966,4 @@ \n%s آغاز گپ به هر حال دعوت به هر حال - + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-zh-rCN/strings.xml b/library/ui-strings/src/main/res/values-zh-rCN/strings.xml index 970bee794c..30fba77195 100644 --- a/library/ui-strings/src/main/res/values-zh-rCN/strings.xml +++ b/library/ui-strings/src/main/res/values-zh-rCN/strings.xml @@ -2865,4 +2865,4 @@ 显示投票 切换引用 切换有序列表 - + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 2a98069c2e..30e6ef673e 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -1175,9 +1175,9 @@ Room addresses - See and managed addresses of this room, and its visibility in the room directory. + See and manage addresses of this room, and its visibility in the room directory. Space addresses - See and managed addresses of this space. + See and manage addresses of this space. Published Addresses Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first. @@ -2228,7 +2228,8 @@ If you don’t know your password, go back to reset it. This is not a valid user identifier. Expected format: \'@user:homeserver.org\' Unable to find a valid homeserver. Please check your identifier - Scan QR code + + Scan QR code Seen by @@ -3475,9 +3476,10 @@ Session name Custom session names can help you recognize your devices more easily. Please be aware that session names are also visible to people you communicate with. - Sign in with QR Code - You can use this device to sign in a mobile or web device with a QR code. There are two ways to do this: - + + Sign in with QR Code + + You can use this device to sign in a mobile or web device with a QR code. There are two ways to do this: Inactive sessions Inactive sessions are sessions you have not used in some time, but they continue to receive encryption keys.\n\nRemoving inactive sessions improves security and performance, and makes it easier for you to identify if a new session is suspicious. Unverified sessions @@ -3515,45 +3517,82 @@ Tap top right to see the option to feedback. Try it out - 1 - 2 - 3 + + 1 + + 2 + + 3 - Scan QR code - Use the camera on this device to scan the QR code shown on your other device: - Sign in with QR code - Use your signed in device to scan the QR code below: - Scan the QR code below with your device that’s signed out. - Secure connection established - Check your signed in device, the code below should be displayed. Confirm that the code below matches with that device: - Unsuccessful connection - Linking with this device is not supported. - The linking wasn’t completed in the required time. - The request was denied on the other device. - The request failed. - A security issue was encountered setting up secure messaging. One of the following may be compromised: Your homeserver; Your internet connection(s); Your device(s); - The other device is already signed in. - The other device must be signed in. - That QR code is invalid. - The sign in was cancelled on the other device. - The homeserver doesn\'t support sign in with QR code. - Open the app on your other device - Go to Settings -> Security & Privacy - Select \'Show QR code\' - Start at the sign in screen - Select \'Sign in with QR code\' - Start at the sign in screen - Select \'Scan QR code\' - Show QR code in this device - Signing in a mobile device? - Scan QR code - Connecting to device - Signing you in - No match? - Try again - Confirm - Please ensure that you know the origin of this code. By linking devices, you will provide someone with full access to your account. + + Scan QR code + + Use the camera on this device to scan the QR code shown on your other device: + + Sign in with QR code + + Use your signed in device to scan the QR code below: + + Scan the QR code below with your device that’s signed out. + + Secure connection established + + Check your signed in device, the code below should be displayed. Confirm that the code below matches with that device: + + Unsuccessful connection + + Linking with this device is not supported. + + The linking wasn’t completed in the required time. + + The request was denied on the other device. + + The request failed. + + A security issue was encountered setting up secure messaging. One of the following may be compromised: Your homeserver; Your internet connection(s); Your device(s); + + The other device is already signed in. + + The other device must be signed in. + + That QR code is invalid. + + The sign in was cancelled on the other device. + + The homeserver doesn\'t support sign in with QR code. + + Open the app on your other device + + Go to Settings -> Security & Privacy + + Select \'Show QR code\' + + Start at the sign in screen + + Select \'Sign in with QR code\' + + Start at the sign in screen + + Select \'Scan QR code\' + + Show QR code in this device + + Signing in a mobile device? + + Scan QR code + + Connecting to device + + Signing you in + + No match? + + Try again + + Confirm + + Please ensure that you know the origin of this code. By linking devices, you will provide someone with full access to your account. Apply bold format diff --git a/library/ui-styles/src/main/res/values/stylable_qr_code_instructions_view.xml b/library/ui-styles/src/main/res/values/stylable_qr_code_instructions_view.xml deleted file mode 100644 index c9a4bb9d05..0000000000 --- a/library/ui-styles/src/main/res/values/stylable_qr_code_instructions_view.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/library/ui-styles/src/main/res/values/stylable_qr_code_login_header_view.xml b/library/ui-styles/src/main/res/values/stylable_qr_code_login_header_view.xml deleted file mode 100644 index 99f56084d9..0000000000 --- a/library/ui-styles/src/main/res/values/stylable_qr_code_login_header_view.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 78f4a6d179..02f1e371fe 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -62,7 +62,7 @@ android { // that the app's state is completely cleared between tests. testInstrumentationRunnerArguments clearPackageData: 'true' - buildConfigField "String", "SDK_VERSION", "\"1.6.20\"" + buildConfigField "String", "SDK_VERSION", "\"1.6.22\"" buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\"" @@ -205,9 +205,6 @@ dependencies { // Work implementation libs.androidx.work - // olm lib is now hosted in MavenCentral - implementation 'org.matrix.android:olm-sdk:3.2.12' - // DI implementation libs.dagger.dagger kapt libs.dagger.daggerCompiler @@ -224,7 +221,7 @@ dependencies { implementation libs.google.phonenumber - implementation("org.matrix.rustcomponents:crypto-android:0.4.1") + implementation("org.matrix.rustcomponents:crypto-android:0.4.3") // api project(":library:rustCrypto") testImplementation libs.tests.junit @@ -236,6 +233,7 @@ dependencies { testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1' // Transitively required for mocking realm as monarchy doesn't expose Rx testImplementation libs.rx.rxKotlin + testImplementation libs.tests.robolectric kaptAndroidTest libs.dagger.daggerCompiler androidTestImplementation libs.androidx.testCore diff --git a/matrix-sdk-android/src/androidTest/assets/crypto_store_20.realm b/matrix-sdk-android/src/androidTest/assets/crypto_store_20.realm deleted file mode 100644 index cfdd2e6da6..0000000000 --- a/matrix-sdk-android/src/androidTest/assets/crypto_store_20.realm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a7acd69f37612bab0a1ab7f456656712d7ba19dbb679f81b97b58ef44e239f42 -size 8523776 diff --git a/matrix-sdk-android/src/androidTest/assets/crypto_store_migration_16.realm b/matrix-sdk-android/src/androidTest/assets/crypto_store_migration_16.realm deleted file mode 100644 index 4995bfc4a1..0000000000 --- a/matrix-sdk-android/src/androidTest/assets/crypto_store_migration_16.realm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:59b4957aa2f9cdc17b14ec8546e144537fac9dee050c6eb173f56fa8602c2736 -size 2097152 diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/rendezvous/RendezvousTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/rendezvous/RendezvousTest.kt deleted file mode 100644 index 5b5aad4c51..0000000000 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/rendezvous/RendezvousTest.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2023 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.rendezvous - -import org.amshove.kluent.invoking -import org.amshove.kluent.shouldBeEqualTo -import org.amshove.kluent.shouldBeInstanceOf -import org.amshove.kluent.shouldThrow -import org.amshove.kluent.with -import org.junit.Test -import org.matrix.android.sdk.InstrumentedTest -import org.matrix.android.sdk.api.rendezvous.channels.ECDHRendezvousChannel -import org.matrix.android.sdk.api.rendezvous.model.RendezvousError -import org.matrix.android.sdk.common.CommonTestHelper - -class RendezvousTest : InstrumentedTest { - - @Test - fun shouldSuccessfullyBuildChannels() = CommonTestHelper.runCryptoTest(context()) { _, _ -> - val cases = listOf( - // v1: - "{\"rendezvous\":{\"algorithm\":\"org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256\"," + - "\"key\":\"aeSGwYTV1IUhikUyCapzC6p2xG5NpJ4Lwj2UgUMlcTk\",\"transport\":" + - "{\"type\":\"org.matrix.msc3886.http.v1\",\"uri\":\"https://rendezvous.lab.element.dev/bcab62cd-3e34-48b4-bc39-90895da8f6fe\"}}," + - "\"intent\":\"login.reciprocate\"}", - // v2: - "{\"rendezvous\":{\"algorithm\":\"org.matrix.msc3903.rendezvous.v2.curve25519-aes-sha256\"," + - "\"key\":\"aeSGwYTV1IUhikUyCapzC6p2xG5NpJ4Lwj2UgUMlcTk\",\"transport\":" + - "{\"type\":\"org.matrix.msc3886.http.v1\",\"uri\":\"https://rendezvous.lab.element.dev/bcab62cd-3e34-48b4-bc39-90895da8f6fe\"}}," + - "\"intent\":\"login.reciprocate\"}", - ) - - cases.forEach { input -> - Rendezvous.buildChannelFromCode(input).channel shouldBeInstanceOf ECDHRendezvousChannel::class - } - } - - @Test - fun shouldFailToBuildChannelAsUnsupportedAlgorithm() { - invoking { - Rendezvous.buildChannelFromCode( - "{\"rendezvous\":{\"algorithm\":\"bad algo\"," + - "\"key\":\"aeSGwYTV1IUhikUyCapzC6p2xG5NpJ4Lwj2UgUMlcTk\",\"transport\":" + - "{\"type\":\"org.matrix.msc3886.http.v1\",\"uri\":\"https://rendezvous.lab.element.dev/bcab62cd-3e34-48b4-bc39-90895da8f6fe\"}}," + - "\"intent\":\"login.reciprocate\"}" - ) - } shouldThrow RendezvousError::class with { - this.reason shouldBeEqualTo RendezvousFailureReason.UnsupportedAlgorithm - } - } - - @Test - fun shouldFailToBuildChannelAsUnsupportedTransport() { - invoking { - Rendezvous.buildChannelFromCode( - "{\"rendezvous\":{\"algorithm\":\"org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256\"," + - "\"key\":\"aeSGwYTV1IUhikUyCapzC6p2xG5NpJ4Lwj2UgUMlcTk\",\"transport\":" + - "{\"type\":\"bad transport\",\"uri\":\"https://rendezvous.lab.element.dev/bcab62cd-3e34-48b4-bc39-90895da8f6fe\"}}," + - "\"intent\":\"login.reciprocate\"}" - ) - } shouldThrow RendezvousError::class with { - this.reason shouldBeEqualTo RendezvousFailureReason.UnsupportedTransport - } - } - - @Test - fun shouldFailToBuildChannelWithInvalidIntent() { - invoking { - Rendezvous.buildChannelFromCode( - "{\"rendezvous\":{\"algorithm\":\"org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256\"," + - "\"key\":\"aeSGwYTV1IUhikUyCapzC6p2xG5NpJ4Lwj2UgUMlcTk\",\"transport\":" + - "{\"type\":\"org.matrix.msc3886.http.v1\",\"uri\":\"https://rendezvous.lab.element.dev/bcab62cd-3e34-48b4-bc39-90895da8f6fe\"}}," + - "\"intent\":\"foo\"}" - ) - } shouldThrow RendezvousError::class with { - this.reason shouldBeEqualTo RendezvousFailureReason.InvalidCode - } - } - - @Test - fun shouldFailToBuildChannelAsInvalidCode() { - val cases = listOf( - "{}", - "rubbish", - "" - ) - - cases.forEach { input -> - invoking { - Rendezvous.buildChannelFromCode(input) - } shouldThrow RendezvousError::class with { - this.reason shouldBeEqualTo RendezvousFailureReason.InvalidCode - } - } - } -} diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt index 60201b34c7..f042e0734f 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt @@ -36,7 +36,6 @@ import org.matrix.android.sdk.internal.network.ApiInterceptor import org.matrix.android.sdk.internal.network.UserAgentHolder import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory -import org.matrix.olm.OlmManager import java.util.concurrent.Executors import javax.inject.Inject @@ -49,7 +48,6 @@ internal class TestMatrix(context: Context, matrixConfiguration: MatrixConfigura @Inject internal lateinit var rawService: RawService @Inject internal lateinit var userAgentHolder: UserAgentHolder @Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver - @Inject internal lateinit var olmManager: OlmManager @Inject internal lateinit var sessionManager: SessionManager @Inject internal lateinit var homeServerHistoryService: HomeServerHistoryService @Inject internal lateinit var apiInterceptor: ApiInterceptor diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPasswordTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPasswordTest.kt index 9bf08f6fc0..8d63f06d3e 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPasswordTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPasswordTest.kt @@ -20,7 +20,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue -import org.junit.Before import org.junit.FixMethodOrder import org.junit.Ignore import org.junit.Test @@ -29,19 +28,12 @@ import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.common.assertByteArrayNotEqual -import org.matrix.olm.OlmManager -import org.matrix.olm.OlmPkDecryption @Ignore("Ignored in order to speed up test run time") @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.JVM) class KeysBackupPasswordTest : InstrumentedTest { - @Before - fun ensureLibLoaded() { - OlmManager() - } - /** * Check KeysBackupPassword utilities */ @@ -51,7 +43,7 @@ class KeysBackupPasswordTest : InstrumentedTest { assertEquals(32, generatePrivateKeyResult.salt.length) assertEquals(500_000, generatePrivateKeyResult.iterations) - assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size) + assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, generatePrivateKeyResult.privateKey.size) // Reverse operation val retrievedPrivateKey = retrievePrivateKeyWithPassword( @@ -60,7 +52,7 @@ class KeysBackupPasswordTest : InstrumentedTest { generatePrivateKeyResult.iterations ) - assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size) + assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, retrievedPrivateKey.size) assertArrayEquals(generatePrivateKeyResult.privateKey, retrievedPrivateKey) } @@ -101,7 +93,7 @@ class KeysBackupPasswordTest : InstrumentedTest { assertEquals(32, generatePrivateKeyResult.salt.length) assertEquals(500_000, generatePrivateKeyResult.iterations) - assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size) + assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, generatePrivateKeyResult.privateKey.size) // Reverse operation, with bad password val retrievedPrivateKey = retrievePrivateKeyWithPassword( @@ -110,7 +102,7 @@ class KeysBackupPasswordTest : InstrumentedTest { generatePrivateKeyResult.iterations ) - assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size) + assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, retrievedPrivateKey.size) assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey) } @@ -123,7 +115,7 @@ class KeysBackupPasswordTest : InstrumentedTest { assertEquals(32, generatePrivateKeyResult.salt.length) assertEquals(500_000, generatePrivateKeyResult.iterations) - assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size) + assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, generatePrivateKeyResult.privateKey.size) // Reverse operation, with bad iteration val retrievedPrivateKey = retrievePrivateKeyWithPassword( @@ -132,7 +124,7 @@ class KeysBackupPasswordTest : InstrumentedTest { 500_001 ) - assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size) + assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, retrievedPrivateKey.size) assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey) } @@ -145,7 +137,7 @@ class KeysBackupPasswordTest : InstrumentedTest { assertEquals(32, generatePrivateKeyResult.salt.length) assertEquals(500_000, generatePrivateKeyResult.iterations) - assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size) + assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, generatePrivateKeyResult.privateKey.size) // Reverse operation, with bad iteration val retrievedPrivateKey = retrievePrivateKeyWithPassword( @@ -154,7 +146,7 @@ class KeysBackupPasswordTest : InstrumentedTest { generatePrivateKeyResult.iterations ) - assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size) + assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, retrievedPrivateKey.size) assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey) } @@ -169,7 +161,7 @@ class KeysBackupPasswordTest : InstrumentedTest { val retrievedPrivateKey = retrievePrivateKeyWithPassword(password, salt, iteration) - assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size) + assertEquals(EXPECTED_PRIVATE_KEY_LENGTH, retrievedPrivateKey.size) // Data from RiotWeb val privateKeyBytes = byteArrayOf( @@ -187,5 +179,7 @@ class KeysBackupPasswordTest : InstrumentedTest { private const val BAD_PASSWORD = "passw0rd" private const val BAD_SALT = "AA0lxhQ9aYgGfMsclVWPIAublg8h9Nlu" + + private const val EXPECTED_PRIVATE_KEY_LENGTH = 32 } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/store/migration/DynamicElementAndroidToElementRMigrationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/store/migration/DynamicElementAndroidToElementRMigrationTest.kt deleted file mode 100644 index 52a75d0653..0000000000 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/store/migration/DynamicElementAndroidToElementRMigrationTest.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2022 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.migration - -import android.content.Context -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import io.mockk.spyk -import io.realm.Realm -import io.realm.kotlin.where -import org.amshove.kluent.internal.assertEquals -import org.junit.After -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertTrue -import org.junit.Before -import org.junit.Ignore -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.matrix.android.sdk.TestBuildVersionSdkIntProvider -import org.matrix.android.sdk.api.securestorage.SecretStoringUtils -import org.matrix.android.sdk.internal.crypto.RustEncryptionConfiguration -import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreMigration -import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule -import org.matrix.android.sdk.internal.crypto.store.db.RustMigrationInfoProvider -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity -import org.matrix.android.sdk.internal.database.RealmKeysUtils -import org.matrix.android.sdk.internal.database.TestRealmConfigurationFactory -import org.matrix.android.sdk.internal.util.time.Clock -import org.matrix.android.sdk.test.shared.createTimberTestRule -import org.matrix.olm.OlmAccount -import org.matrix.olm.OlmManager -import org.matrix.rustcomponents.sdk.crypto.OlmMachine -import java.io.File -import java.security.KeyStore - -@RunWith(AndroidJUnit4::class) -class DynamicElementAndroidToElementRMigrationTest { - - @get:Rule val configurationFactory = TestRealmConfigurationFactory() - - @Rule - fun timberTestRule() = createTimberTestRule() - - var context: Context = InstrumentationRegistry.getInstrumentation().context - var realm: Realm? = null - - @Before - fun setUp() { - // Ensure Olm is initialized - OlmManager() - } - - @After - fun tearDown() { - realm?.close() - } - - private val keyStore = spyk(KeyStore.getInstance("AndroidKeyStore")).also { it.load(null) } - - private val rustEncryptionConfiguration = RustEncryptionConfiguration( - "foo", - RealmKeysUtils( - context, - SecretStoringUtils(context, keyStore, TestBuildVersionSdkIntProvider(), false) - ) - ) - - private val fakeClock = object : Clock { - override fun epochMillis() = 0L - } - - @Test - fun given_a_valid_crypto_store_realm_file_then_migration_should_be_successful() { - testMigrate(false) - } - - @Test - @Ignore("We don't migrate group sessions for now, and it's making this test suite unstable") - fun given_a_valid_crypto_store_realm_file_no_lazy_then_migration_should_be_successful() { - testMigrate(true) - } - - private fun testMigrate(migrateGroupSessions: Boolean) { - val targetFile = File(configurationFactory.root, "rust-sdk") - - val realmName = "crypto_store_migration_16.realm" - val infoProvider = RustMigrationInfoProvider( - targetFile, - rustEncryptionConfiguration - ).apply { - migrateMegolmGroupSessions = migrateGroupSessions - } - val migration = RealmCryptoStoreMigration(fakeClock, infoProvider) - - val realmConfiguration = configurationFactory.createConfiguration( - realmName, - null, - RealmCryptoStoreModule(), - migration.schemaVersion, - migration - ) - configurationFactory.copyRealmFromAssets(context, realmName, realmName) - - realm = Realm.getInstance(realmConfiguration) - val metaData = realm!!.where().findFirst()!! - val userId = metaData.userId!! - val deviceId = metaData.deviceId!! - val olmAccount = metaData.getOlmAccount()!! - - val machine = OlmMachine(userId, deviceId, targetFile.path, rustEncryptionConfiguration.getDatabasePassphrase()) - - assertEquals(olmAccount.identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY], machine.identityKeys()["ed25519"]) - assertNotNull(machine.getBackupKeys()) - val crossSigningStatus = machine.crossSigningStatus() - assertTrue(crossSigningStatus.hasMaster) - assertTrue(crossSigningStatus.hasSelfSigning) - assertTrue(crossSigningStatus.hasUserSigning) - - if (migrateGroupSessions) { - assertTrue("Some outbound sessions should be migrated", machine.roomKeyCounts().total.toInt() > 0) - assertTrue("There are some backed-up sessions", machine.roomKeyCounts().backedUp.toInt() > 0) - } else { - assertTrue(machine.roomKeyCounts().total.toInt() == 0) - assertTrue(machine.roomKeyCounts().backedUp.toInt() == 0) - } - - // legacy olm sessions should have been deleted - val remainingOlmSessions = realm!!.where().findAll().size - assertEquals("legacy olm sessions should have been removed from store", 0, remainingOlmSessions) - } -} diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/database/CryptoSanityMigrationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/database/CryptoSanityMigrationTest.kt deleted file mode 100644 index 828c0f51d4..0000000000 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/database/CryptoSanityMigrationTest.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2023 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.database - -import android.content.Context -import androidx.test.platform.app.InstrumentationRegistry -import io.mockk.spyk -import io.realm.Realm -import org.junit.After -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.matrix.android.sdk.TestBuildVersionSdkIntProvider -import org.matrix.android.sdk.api.securestorage.SecretStoringUtils -import org.matrix.android.sdk.internal.crypto.RustEncryptionConfiguration -import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreMigration -import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule -import org.matrix.android.sdk.internal.crypto.store.db.RustMigrationInfoProvider -import org.matrix.android.sdk.internal.util.time.Clock -import org.matrix.olm.OlmManager -import java.io.File -import java.security.KeyStore - -class CryptoSanityMigrationTest { - @get:Rule val configurationFactory = TestRealmConfigurationFactory() - - lateinit var context: Context - var realm: Realm? = null - - @Before - fun setUp() { - // Ensure Olm is initialized - OlmManager() - context = InstrumentationRegistry.getInstrumentation().context - } - - @After - fun tearDown() { - realm?.close() - } - - private val keyStore = spyk(KeyStore.getInstance("AndroidKeyStore")).also { it.load(null) } - - @Test - fun cryptoDatabaseShouldMigrateGracefully() { - val realmName = "crypto_store_20.realm" - - val rustMigrationInfo = RustMigrationInfoProvider( - File(configurationFactory.root, "test_rust"), - RustEncryptionConfiguration( - "foo", - RealmKeysUtils( - context, - SecretStoringUtils(context, keyStore, TestBuildVersionSdkIntProvider(), false) - ) - ), - ) - val migration = RealmCryptoStoreMigration( - object : Clock { - override fun epochMillis(): Long { - return 0L - } - }, - rustMigrationInfo - ) - - val realmConfiguration = configurationFactory.createConfiguration( - realmName, - "7b9a21a8a311e85d75b069a343c23fc952fc3fec5e0c83ecfa13f24b787479c487c3ed587db3dd1f5805d52041fc0ac246516e94b27ffa699ff928622e621aca", - RealmCryptoStoreModule(), - migration.schemaVersion, - migration - ) - configurationFactory.copyRealmFromAssets(context, realmName, realmName) - - realm = Realm.getInstance(realmConfiguration) - } -} diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/contentscanner/ScanEncryptorUtilsTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/contentscanner/ScanEncryptorUtilsTest.kt new file mode 100644 index 0000000000..ba04e4607e --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/contentscanner/ScanEncryptorUtilsTest.kt @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024 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.contentscanner + +import org.amshove.kluent.shouldBe +import org.amshove.kluent.shouldBeEqualTo +import org.amshove.kluent.shouldNotBe +import org.junit.Test +import org.matrix.android.sdk.api.session.crypto.attachments.ElementToDecrypt +import org.matrix.android.sdk.api.session.crypto.model.EncryptedFileInfo +import org.matrix.android.sdk.api.session.crypto.model.EncryptedFileKey +import org.matrix.android.sdk.internal.session.contentscanner.model.DownloadBody + +class ScanEncryptorUtilsTest { + private val anMxcUrl = "mxc://matrix.org/123456" + private val anElementToDecrypt = ElementToDecrypt( + k = "key", + iv = "iv", + sha256 = "sha256" + ) + private val aPublicKey = "6n3l15JqsNhpM1OwRIoDCL/3c1B5idcwvy07Y5qFRyw=" + private val aPrivateKey = "CLYwNaeA9d0KHE0DniO1bxGgmNsPJ/pyanF4b4tcK1M=" + + @Test + fun whenNoServerKeyIsProvidedTheContentIsNotEncrypted() { + val result = ScanEncryptorUtils.getDownloadBodyAndEncryptIfNeeded( + publicServerKey = null, + mxcUrl = anMxcUrl, + elementToDecrypt = anElementToDecrypt + ) + result shouldBeEqualTo DownloadBody( + file = EncryptedFileInfo( + url = anMxcUrl, + iv = anElementToDecrypt.iv, + hashes = mapOf("sha256" to anElementToDecrypt.sha256), + key = EncryptedFileKey( + k = anElementToDecrypt.k, + alg = "A256CTR", + keyOps = listOf("encrypt", "decrypt"), + kty = "oct", + ext = true + ), + v = "v2" + ), + encryptedBody = null + ) + } + + @Test + fun whenServerKeyIsProvidedTheContentIsEncrypted() { + val result = ScanEncryptorUtils.getDownloadBodyAndEncryptIfNeeded( + publicServerKey = aPublicKey, + mxcUrl = anMxcUrl, + elementToDecrypt = anElementToDecrypt + ) + result.file shouldBe null + // Note: we cannot check the members of EncryptedBody because they change on each call. + result.encryptedBody shouldNotBe null + } + + // Note: PkDecryption is not exposed in the FFI layer, so we cannot use this test. + /* + @Test + fun checkThatTheCodeIsAbleToDecryptContent() { + System.loadLibrary("olm") + val clearInfo = ScanEncryptorUtils.getDownloadBodyAndEncryptIfNeeded( + publicServerKey = null, + mxcUrl = anMxcUrl, + elementToDecrypt = anElementToDecrypt + ) + // Uncomment to get a new encrypted body + // val encryptedBody = ScanEncryptorUtils.getDownloadBodyAndEncryptIfNeeded( + // publicServerKey = aPublicKey, + // mxcUrl = anMxcUrl, + // elementToDecrypt = anElementToDecrypt + // ).encryptedBody!! + // println("libolmEncryptedBody: $encryptedBody") + val libolmEncryptedBody = EncryptedBody( + cipherText = "GTnDhm6xe5fPe/QCr6fyGcZXheFhZlPG" + + "nJZiCK8Xwq6qTg71vSUGWtLdt3uaTmK7" + + "F7fB3PBKchHu2VVv6MMgo8fpUQ7KBbmu" + + "NWTrNmf3QdhXuRwUwz/q4GxsbGR2zjSX" + + "/UoE5S4ymVtOVhvSfXQfssN56wVIzC6S" + + "dy57y6b1IXPihlCUdvb8LMkMvViHYeNf" + + "beFrAfMlsyr1+jdZEXZF5Q7iruhsH2iu" + + "k7+Ayl9rdILCD5tjE9pezwe1V6uc/Agb", + mac = "Wk77HRg50oM", + ephemeral = "rMTK6/CGASinfX4USFS5qmD3r4meffxKc/jCSFIBczw" + ) + // Try to decrypt the body + val result = withOlmDecryption { olmPkDecryption -> + olmPkDecryption.setPrivateKey(aPrivateKey.decodeBase64()!!.toByteArray()) + olmPkDecryption.decrypt( + OlmPkMessage().apply { + mCipherText = libolmEncryptedBody.cipherText + mMac = libolmEncryptedBody.mac + mEphemeralKey = libolmEncryptedBody.ephemeral + } + ) + } + val parseResult = MoshiProvider.providesMoshi() + .adapter(DownloadBody::class.java) + .fromJson(result) + parseResult shouldBeEqualTo clearInfo + } + */ +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt index b9780b8021..5f87425cfc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt @@ -39,7 +39,6 @@ import org.matrix.android.sdk.internal.network.ApiInterceptor import org.matrix.android.sdk.internal.network.UserAgentHolder import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory -import org.matrix.olm.OlmManager import java.util.concurrent.Executors import javax.inject.Inject @@ -59,7 +58,6 @@ class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) { @Inject internal lateinit var debugService: DebugService @Inject internal lateinit var userAgentHolder: UserAgentHolder @Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver - @Inject internal lateinit var olmManager: OlmManager @Inject internal lateinit var sessionManager: SessionManager @Inject internal lateinit var homeServerHistoryService: HomeServerHistoryService @Inject internal lateinit var apiInterceptor: ApiInterceptor diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/CryptoConstants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/CryptoConstants.kt index aced0ca3a2..5b6bd0c3e1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/CryptoConstants.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/CryptoConstants.kt @@ -31,11 +31,6 @@ const val MXCRYPTO_ALGORITHM_MEGOLM = "m.megolm.v1.aes-sha2" */ const val MXCRYPTO_ALGORITHM_MEGOLM_BACKUP = "m.megolm_backup.v1.curve25519-aes-sha2" -/** - * Secured Shared Storage algorithm constant. - */ -const val SSSS_ALGORITHM_CURVE25519_AES_SHA2 = "m.secret_storage.v1.curve25519-aes-sha2" - /* Secrets are encrypted using AES-CTR-256 and MACed using HMAC-SHA-256. **/ const val SSSS_ALGORITHM_AES_HMAC_SHA2 = "m.secret_storage.v1.aes-hmac-sha2" diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt deleted file mode 100644 index 5bceecf643..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/Rendezvous.kt +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright 2022 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.rendezvous - -import android.net.Uri -import org.matrix.android.sdk.api.auth.AuthenticationService -import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig -import org.matrix.android.sdk.api.logger.LoggerTag -import org.matrix.android.sdk.api.rendezvous.channels.ECDHRendezvousChannel -import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode -import org.matrix.android.sdk.api.rendezvous.model.Outcome -import org.matrix.android.sdk.api.rendezvous.model.Payload -import org.matrix.android.sdk.api.rendezvous.model.PayloadType -import org.matrix.android.sdk.api.rendezvous.model.Protocol -import org.matrix.android.sdk.api.rendezvous.model.RendezvousCode -import org.matrix.android.sdk.api.rendezvous.model.RendezvousError -import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent -import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportType -import org.matrix.android.sdk.api.rendezvous.model.SecureRendezvousChannelAlgorithm -import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransport -import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel -import org.matrix.android.sdk.api.util.MatrixJsonParser -import timber.log.Timber - -// n.b MSC3886/MSC3903/MSC3906 that this is based on are now closed. -// However, we want to keep this implementation around for some time. -// TODO define an end-of-life date for this implementation. - -/** - * Implementation of MSC3906 to sign in + E2EE set up using a QR code. - */ -class Rendezvous( - val channel: RendezvousChannel, - val theirIntent: RendezvousIntent, -) { - companion object { - private val TAG = LoggerTag(Rendezvous::class.java.simpleName, LoggerTag.RENDEZVOUS).value - - @Throws(RendezvousError::class) - fun buildChannelFromCode(code: String): Rendezvous { - // we first check that the code is valid JSON and has right high-level structure - val genericParsed = try { - // we rely on moshi validating the code and throwing exception if invalid JSON or algorithm doesn't match - MatrixJsonParser.getMoshi().adapter(RendezvousCode::class.java).fromJson(code) - } catch (a: Throwable) { - throw RendezvousError("Malformed code", RendezvousFailureReason.InvalidCode) - } ?: throw RendezvousError("Code is null", RendezvousFailureReason.InvalidCode) - - // then we check that algorithm is supported - if (!SecureRendezvousChannelAlgorithm.values().map { it.value }.contains(genericParsed.rendezvous.algorithm)) { - throw RendezvousError("Unsupported algorithm", RendezvousFailureReason.UnsupportedAlgorithm) - } - - // and, that the transport is supported - if (!RendezvousTransportType.values().map { it.value }.contains(genericParsed.rendezvous.transport.type)) { - throw RendezvousError("Unsupported transport", RendezvousFailureReason.UnsupportedTransport) - } - - // now that we know the overall structure looks sensible, we rely on moshi validating the code and - // throwing exception if other parts are invalid - val supportedParsed = try { - MatrixJsonParser.getMoshi().adapter(ECDHRendezvousCode::class.java).fromJson(code) - } catch (a: Throwable) { - throw RendezvousError("Malformed ECDH rendezvous code", RendezvousFailureReason.InvalidCode) - } ?: throw RendezvousError("ECDH rendezvous code is null", RendezvousFailureReason.InvalidCode) - - val transport = SimpleHttpRendezvousTransport(supportedParsed.rendezvous.transport.uri) - - return Rendezvous( - ECDHRendezvousChannel(transport, supportedParsed.rendezvous.algorithm, supportedParsed.rendezvous.key), - supportedParsed.intent - ) - } - } - - private val adapter = MatrixJsonParser.getMoshi().adapter(Payload::class.java) - - // not yet implemented: RendezvousIntent.RECIPROCATE_LOGIN_ON_EXISTING_DEVICE - val ourIntent: RendezvousIntent = RendezvousIntent.LOGIN_ON_NEW_DEVICE - - @Throws(RendezvousError::class) - private suspend fun checkCompatibility() { - val incompatible = theirIntent == ourIntent - - Timber.tag(TAG).d("ourIntent: $ourIntent, theirIntent: $theirIntent, incompatible: $incompatible") - - if (incompatible) { - // inform the other side - send(Payload(PayloadType.FINISH, intent = ourIntent)) - if (ourIntent == RendezvousIntent.LOGIN_ON_NEW_DEVICE) { - throw RendezvousError("The other device isn't signed in", RendezvousFailureReason.OtherDeviceNotSignedIn) - } else { - throw RendezvousError("The other device is already signed in", RendezvousFailureReason.OtherDeviceAlreadySignedIn) - } - } - } - - @Throws(RendezvousError::class) - suspend fun startAfterScanningCode(): String { - val checksum = channel.connect() - - Timber.tag(TAG).i("Connected to secure channel with checksum: $checksum") - - checkCompatibility() - - // get protocols - Timber.tag(TAG).i("Waiting for protocols") - val protocolsResponse = receive() - - if (protocolsResponse?.protocols == null || !protocolsResponse.protocols.contains(Protocol.LOGIN_TOKEN)) { - send(Payload(PayloadType.FINISH, outcome = Outcome.UNSUPPORTED)) - throw RendezvousError("Unsupported protocols", RendezvousFailureReason.UnsupportedHomeserver) - } - - send(Payload(PayloadType.PROGRESS, protocol = Protocol.LOGIN_TOKEN)) - - return checksum - } - - @Throws(RendezvousError::class) - suspend fun waitForLoginOnNewDevice(authenticationService: AuthenticationService): Session { - Timber.tag(TAG).i("Waiting for login_token") - - val loginToken = receive() - - if (loginToken?.type == PayloadType.FINISH) { - when (loginToken.outcome) { - Outcome.DECLINED -> { - throw RendezvousError("Login declined by other device", RendezvousFailureReason.UserDeclined) - } - Outcome.UNSUPPORTED -> { - throw RendezvousError("Homeserver lacks support", RendezvousFailureReason.UnsupportedHomeserver) - } - else -> { - throw RendezvousError("Unknown error", RendezvousFailureReason.Unknown) - } - } - } - - val homeserver = loginToken?.homeserver ?: throw RendezvousError("No homeserver returned", RendezvousFailureReason.ProtocolError) - val token = loginToken.loginToken ?: throw RendezvousError("No login token returned", RendezvousFailureReason.ProtocolError) - - Timber.tag(TAG).i("Got login_token now attempting to sign in with $homeserver") - - val hsConfig = HomeServerConnectionConfig(homeServerUri = Uri.parse(homeserver)) - return authenticationService.loginUsingQrLoginToken(hsConfig, token) - } - - @Throws(RendezvousError::class) - suspend fun completeVerificationOnNewDevice(session: Session) { - val userId = session.myUserId - val crypto = session.cryptoService() - val deviceId = crypto.getMyCryptoDevice().deviceId - val deviceKey = crypto.getMyCryptoDevice().fingerprint() - send(Payload(PayloadType.PROGRESS, outcome = Outcome.SUCCESS, deviceId = deviceId, deviceKey = deviceKey)) - - try { - // explicitly download keys for ourself rather than racing with initial sync which might not complete in time - crypto.downloadKeysIfNeeded(listOf(userId), false) - } catch (e: Throwable) { - // log as warning and continue as initial sync might still complete - Timber.tag(TAG).w(e, "Failed to download keys for self") - } - - // await confirmation of verification - val verificationResponse = receive() - if (verificationResponse?.outcome == Outcome.VERIFIED) { - val verifyingDeviceId = verificationResponse.verifyingDeviceId - ?: throw RendezvousError("No verifying device id returned", RendezvousFailureReason.ProtocolError) - val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) - if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifyingDeviceKey) { - Timber.tag(TAG).w( - "Verifying device $verifyingDeviceId key doesn't match: ${ - verifyingDeviceFromServer?.fingerprint() - } vs ${verificationResponse.verifyingDeviceKey})" - ) - // inform the other side - send(Payload(PayloadType.FINISH, outcome = Outcome.E2EE_SECURITY_ERROR)) - throw RendezvousError("Key from verifying device doesn't match", RendezvousFailureReason.E2EESecurityIssue) - } - - verificationResponse.masterKey?.let { masterKeyFromVerifyingDevice -> - // verifying device provided us with a master key, so use it to check integrity - - // see what the homeserver told us - val localMasterKey = crypto.crossSigningService().getMyCrossSigningKeys()?.masterKey() - - // n.b. if no local master key this is a problem, as well as it not matching - if (localMasterKey?.unpaddedBase64PublicKey != masterKeyFromVerifyingDevice) { - Timber.tag(TAG).w("Master key from verifying device doesn't match: $masterKeyFromVerifyingDevice vs $localMasterKey") - // inform the other side - send(Payload(PayloadType.FINISH, outcome = Outcome.E2EE_SECURITY_ERROR)) - throw RendezvousError("Master key from verifying device doesn't match", RendezvousFailureReason.E2EESecurityIssue) - } - - // set other device as verified - Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") - crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) - - Timber.tag(TAG).i("Setting master key as trusted") - crypto.crossSigningService().markMyMasterKeyAsTrusted() - } ?: run { - // set other device as verified anyway - Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") - crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) - - Timber.tag(TAG).i("No master key given by verifying device") - } - - // request secrets from other sessions. - Timber.tag(TAG).i("Requesting secrets from other sessions") - - session.sharedSecretStorageService().requestMissingSecrets() - } else { - Timber.tag(TAG).i("Not doing verification") - } - } - - @Throws(RendezvousError::class) - private suspend fun receive(): Payload? { - val data = channel.receive() ?: return null - val payload = try { - adapter.fromJson(data.toString(Charsets.UTF_8)) - } catch (e: Exception) { - Timber.tag(TAG).w(e, "Failed to parse payload") - throw RendezvousError("Invalid payload received", RendezvousFailureReason.Unknown) - } - - return payload - } - - private suspend fun send(payload: Payload) { - channel.send(adapter.toJson(payload).toByteArray(Charsets.UTF_8)) - } - - suspend fun close() { - channel.close() - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt deleted file mode 100644 index 0956a5b0a0..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousChannel.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2022 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.rendezvous - -import org.matrix.android.sdk.api.rendezvous.model.RendezvousError - -/** - * Representation of a rendezvous channel such as that described by MSC3903. - */ -interface RendezvousChannel { - val transport: RendezvousTransport - - /** - * @returns the checksum/confirmation digits to be shown to the user - */ - @Throws(RendezvousError::class) - suspend fun connect(): String - - /** - * Send a payload via the channel. - * @param data payload to send - */ - @Throws(RendezvousError::class) - suspend fun send(data: ByteArray) - - /** - * Receive a payload from the channel. - * @returns the received payload - */ - @Throws(RendezvousError::class) - suspend fun receive(): ByteArray? - - /** - * Closes the channel and cleans up. - */ - suspend fun close() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousFailureReason.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousFailureReason.kt deleted file mode 100644 index 18e625d825..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousFailureReason.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 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.rendezvous - -enum class RendezvousFailureReason(val canRetry: Boolean = true) { - UserDeclined, - OtherDeviceNotSignedIn, - OtherDeviceAlreadySignedIn, - Unknown, - Expired, - UserCancelled, - InvalidCode, - UnsupportedAlgorithm(false), - UnsupportedTransport(false), - UnsupportedHomeserver(false), - ProtocolError, - E2EESecurityIssue(false) -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt deleted file mode 100644 index 81632e951a..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/RendezvousTransport.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2022 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.rendezvous - -import okhttp3.MediaType -import org.matrix.android.sdk.api.rendezvous.model.RendezvousError -import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails - -interface RendezvousTransport { - var ready: Boolean - - @Throws(RendezvousError::class) - suspend fun details(): RendezvousTransportDetails - - @Throws(RendezvousError::class) - suspend fun send(contentType: MediaType, data: ByteArray) - - @Throws(RendezvousError::class) - suspend fun receive(): ByteArray? - - suspend fun close() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt deleted file mode 100644 index bcde4a2a7f..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/channels/ECDHRendezvousChannel.kt +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.channels - -import android.util.Base64 -import com.squareup.moshi.JsonClass -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import okhttp3.MediaType.Companion.toMediaType -import org.matrix.android.sdk.api.logger.LoggerTag -import org.matrix.android.sdk.api.rendezvous.RendezvousChannel -import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason -import org.matrix.android.sdk.api.rendezvous.RendezvousTransport -import org.matrix.android.sdk.api.rendezvous.model.RendezvousError -import org.matrix.android.sdk.api.rendezvous.model.SecureRendezvousChannelAlgorithm -import org.matrix.android.sdk.api.util.MatrixJsonParser -import org.matrix.android.sdk.internal.crypto.verification.getDecimalCodeRepresentation -import org.matrix.olm.OlmSAS -import timber.log.Timber -import java.security.SecureRandom -import java.util.LinkedList -import javax.crypto.Cipher -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.SecretKeySpec - -/** - * Implements X25519 ECDH key agreement and AES-256-GCM encryption channel as per MSC3903: - * https://github.com/matrix-org/matrix-spec-proposals/pull/3903 - */ -class ECDHRendezvousChannel( - override var transport: RendezvousTransport, - private val algorithm: SecureRendezvousChannelAlgorithm, - theirPublicKeyBase64: String?, -) : RendezvousChannel { - companion object { - private const val ALGORITHM_SPEC = "AES/GCM/NoPadding" - private const val KEY_SPEC = "AES" - private val TAG = LoggerTag(ECDHRendezvousChannel::class.java.simpleName, LoggerTag.RENDEZVOUS).value - } - - @JsonClass(generateAdapter = true) - internal data class ECDHPayload( - val algorithm: SecureRendezvousChannelAlgorithm? = null, - val key: String? = null, - val ciphertext: String? = null, - val iv: String? = null, - ) - - private val olmSASMutex = Mutex() - private var olmSAS: OlmSAS? - private val ourPublicKey: ByteArray - private val ecdhAdapter = MatrixJsonParser.getMoshi().adapter(ECDHPayload::class.java) - private var theirPublicKey: ByteArray? = null - private var aesKey: ByteArray? = null - - init { - theirPublicKeyBase64?.let { - theirPublicKey = decodeBase64(it) - } - olmSAS = OlmSAS() - ourPublicKey = decodeBase64(olmSAS!!.publicKey) - } - - fun encodeBase64(input: ByteArray?): String? { - if (algorithm == SecureRendezvousChannelAlgorithm.ECDH_V2) { - return Base64.encodeToString(input, Base64.NO_WRAP or Base64.NO_PADDING) - } - return Base64.encodeToString(input, Base64.NO_WRAP) - } - - fun decodeBase64(input: String?): ByteArray { - // for decoding we aren't concerned about padding - return Base64.decode(input, Base64.NO_WRAP) - } - - @Throws(RendezvousError::class) - override suspend fun connect(): String { - val sas = olmSAS ?: throw RendezvousError("Channel closed", RendezvousFailureReason.Unknown) - val isInitiator = theirPublicKey == null - - if (isInitiator) { - Timber.tag(TAG).i("Waiting for other device to send their public key") - val res = this.receiveAsPayload() ?: throw RendezvousError("No reply from other device", RendezvousFailureReason.ProtocolError) - - if (res.key == null) { - throw RendezvousError( - "Unsupported algorithm: ${res.algorithm}", - RendezvousFailureReason.UnsupportedAlgorithm, - ) - } - theirPublicKey = decodeBase64(res.key) - } else { - // send our public key unencrypted - Timber.tag(TAG).i("Sending public key") - send( - ECDHPayload( - algorithm = algorithm, - key = encodeBase64(ourPublicKey) - ) - ) - } - - olmSASMutex.withLock { - sas.setTheirPublicKey(encodeBase64(theirPublicKey)) - sas.setTheirPublicKey(encodeBase64(theirPublicKey)) - - val initiatorKey = encodeBase64(if (isInitiator) ourPublicKey else theirPublicKey) - val recipientKey = encodeBase64(if (isInitiator) theirPublicKey else ourPublicKey) - val aesInfo = "${algorithm.value}|$initiatorKey|$recipientKey" - - aesKey = sas.generateShortCode(aesInfo, 32) - - val rawChecksum = sas.generateShortCode(aesInfo, 5) - return rawChecksum.getDecimalCodeRepresentation(separator = "-") - } - } - - private suspend fun send(payload: ECDHPayload) { - transport.send("application/json".toMediaType(), ecdhAdapter.toJson(payload).toByteArray(Charsets.UTF_8)) - } - - override suspend fun send(data: ByteArray) { - if (aesKey == null) { - throw IllegalStateException("Shared secret not established") - } - send(encrypt(data)) - } - - private suspend fun receiveAsPayload(): ECDHPayload? { - transport.receive()?.toString(Charsets.UTF_8)?.let { - return ecdhAdapter.fromJson(it) - } ?: return null - } - - override suspend fun receive(): ByteArray? { - if (aesKey == null) { - throw IllegalStateException("Shared secret not established") - } - val payload = receiveAsPayload() ?: return null - return decrypt(payload) - } - - override suspend fun close() { - val sas = olmSAS ?: throw IllegalStateException("Channel already closed") - olmSASMutex.withLock { - // this does a double release check already so we don't re-check ourselves - sas.releaseSas() - olmSAS = null - } - transport.close() - } - - private fun encrypt(plainText: ByteArray): ECDHPayload { - val iv = ByteArray(16) - SecureRandom().nextBytes(iv) - - val cipherText = LinkedList() - - val encryptCipher = Cipher.getInstance(ALGORITHM_SPEC) - val secretKeySpec = SecretKeySpec(aesKey, KEY_SPEC) - val ivParameterSpec = IvParameterSpec(iv) - encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec) - cipherText.addAll(encryptCipher.update(plainText).toList()) - cipherText.addAll(encryptCipher.doFinal().toList()) - - return ECDHPayload( - ciphertext = encodeBase64(cipherText.toByteArray()), - iv = encodeBase64(iv) - ) - } - - private fun decrypt(payload: ECDHPayload): ByteArray { - val iv = decodeBase64(payload.iv) - val encryptCipher = Cipher.getInstance(ALGORITHM_SPEC) - val secretKeySpec = SecretKeySpec(aesKey, KEY_SPEC) - val ivParameterSpec = IvParameterSpec(iv) - encryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec) - - val plainText = LinkedList() - plainText.addAll(encryptCipher.update(decodeBase64(payload.ciphertext)).toList()) - plainText.addAll(encryptCipher.doFinal().toList()) - - return plainText.toByteArray() - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt deleted file mode 100644 index 55bac6397e..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvous.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -data class ECDHRendezvous( - val transport: SimpleHttpRendezvousTransportDetails, - val algorithm: SecureRendezvousChannelAlgorithm, - val key: String -) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt deleted file mode 100644 index 575b5d4bfd..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/ECDHRendezvousCode.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -data class ECDHRendezvousCode( - val intent: RendezvousIntent, - val rendezvous: ECDHRendezvous -) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt deleted file mode 100644 index 0ebd1f88b3..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Outcome.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = false) -enum class Outcome(val value: String) { - @Json(name = "success") - SUCCESS("success"), - - @Json(name = "declined") - DECLINED("declined"), - - @Json(name = "unsupported") - UNSUPPORTED("unsupported"), - - @Json(name = "verified") - VERIFIED("verified"), - - @Json(name = "e2ee_security_error") - E2EE_SECURITY_ERROR("e2ee_security_error") -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt deleted file mode 100644 index 04631ce959..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Payload.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -internal data class Payload( - val type: PayloadType, - val intent: RendezvousIntent? = null, - val outcome: Outcome? = null, - val protocols: List? = null, - val protocol: Protocol? = null, - val homeserver: String? = null, - @Json(name = "login_token") val loginToken: String? = null, - @Json(name = "device_id") val deviceId: String? = null, - @Json(name = "device_key") val deviceKey: String? = null, - @Json(name = "verifying_device_id") val verifyingDeviceId: String? = null, - @Json(name = "verifying_device_key") val verifyingDeviceKey: String? = null, - @Json(name = "master_key") val masterKey: String? = null -) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt deleted file mode 100644 index 33beb1f525..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/PayloadType.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = false) -internal enum class PayloadType(val value: String) { - @Json(name = "m.login.start") - START("m.login.start"), - - @Json(name = "m.login.finish") - FINISH("m.login.finish"), - - @Json(name = "m.login.progress") - PROGRESS("m.login.progress") -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt deleted file mode 100644 index 6fce2fa11c..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Protocol.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = false) -enum class Protocol(val value: String) { - @Json(name = "org.matrix.msc3906.login_token") - LOGIN_TOKEN("org.matrix.msc3906.login_token") -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Rendezvous.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Rendezvous.kt deleted file mode 100644 index f424f8cab0..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/Rendezvous.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2023 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.rendezvous.model - -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -open class Rendezvous( - val transport: RendezvousTransportDetails, - val algorithm: String, -) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousCode.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousCode.kt deleted file mode 100644 index ffa8bf6661..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousCode.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2023 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.rendezvous.model - -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -open class RendezvousCode( - open val intent: RendezvousIntent, - open val rendezvous: Rendezvous -) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt deleted file mode 100644 index c52b11a322..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousError.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason - -class RendezvousError(val description: String, val reason: RendezvousFailureReason) : Exception(description) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt deleted file mode 100644 index 65037e1252..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousIntent.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = false) -enum class RendezvousIntent { - @Json(name = "login.start") LOGIN_ON_NEW_DEVICE, - @Json(name = "login.reciprocate") RECIPROCATE_LOGIN_ON_EXISTING_DEVICE -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportDetails.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportDetails.kt deleted file mode 100644 index 34d96ac64a..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportDetails.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -open class RendezvousTransportDetails( - val type: String -) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt deleted file mode 100644 index 6fca7efa71..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/RendezvousTransportType.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = false) -enum class RendezvousTransportType(val value: String) { - @Json(name = "org.matrix.msc3886.http.v1") - MSC3886_SIMPLE_HTTP_V1("org.matrix.msc3886.http.v1") -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt deleted file mode 100644 index 123e41a5d7..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SecureRendezvousChannelAlgorithm.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = false) -enum class SecureRendezvousChannelAlgorithm(val value: String) { - @Json(name = "org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256") - ECDH_V1("org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256"), - @Json(name = "org.matrix.msc3903.rendezvous.v2.curve25519-aes-sha256") - ECDH_V2("org.matrix.msc3903.rendezvous.v2.curve25519-aes-sha256") -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt deleted file mode 100644 index d2342bb9d5..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/model/SimpleHttpRendezvousTransportDetails.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.model - -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -data class SimpleHttpRendezvousTransportDetails( - val uri: String -) : RendezvousTransportDetails(type = RendezvousTransportType.MSC3886_SIMPLE_HTTP_V1.name) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt deleted file mode 100644 index 620b599e3d..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/rendezvous/transports/SimpleHttpRendezvousTransport.kt +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2022 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.rendezvous.transports - -import kotlinx.coroutines.delay -import okhttp3.MediaType -import okhttp3.Request -import okhttp3.RequestBody.Companion.toRequestBody -import org.matrix.android.sdk.api.logger.LoggerTag -import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason -import org.matrix.android.sdk.api.rendezvous.RendezvousTransport -import org.matrix.android.sdk.api.rendezvous.model.RendezvousError -import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails -import org.matrix.android.sdk.api.rendezvous.model.SimpleHttpRendezvousTransportDetails -import timber.log.Timber -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale - -/** - * Implementation of the Simple HTTP transport MSC3886: https://github.com/matrix-org/matrix-spec-proposals/pull/3886 - */ -class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTransport { - companion object { - private val TAG = LoggerTag(SimpleHttpRendezvousTransport::class.java.simpleName, LoggerTag.RENDEZVOUS).value - } - - override var ready = false - private var cancelled = false - private var uri: String? - private var etag: String? = null - private var expiresAt: Date? = null - - init { - uri = rendezvousUri - } - - override suspend fun details(): RendezvousTransportDetails { - val uri = uri ?: throw IllegalStateException("Rendezvous not set up") - - return SimpleHttpRendezvousTransportDetails(uri) - } - - @Throws(RendezvousError::class) - override suspend fun send(contentType: MediaType, data: ByteArray) { - if (cancelled) { - throw IllegalStateException("Rendezvous cancelled") - } - - val method = if (uri != null) "PUT" else "POST" - val uri = this.uri ?: throw RuntimeException("No rendezvous URI") - - val httpClient = okhttp3.OkHttpClient.Builder().build() - - val request = Request.Builder() - .url(uri) - .method(method, data.toRequestBody()) - .header("content-type", contentType.toString()) - - etag?.let { - request.header("if-match", it) - } - - val response = httpClient.newCall(request.build()).execute() - - if (response.code == 404) { - throw get404Error() - } - etag = response.header("etag") - - Timber.tag(TAG).i("Sent data to $uri new etag $etag") - - if (method == "POST") { - val location = response.header("location") ?: throw RuntimeException("No rendezvous URI found in response") - - response.header("expires")?.let { - val format = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - expiresAt = format.parse(it) - } - - // resolve location header which could be relative or absolute - this.uri = response.request.url.toUri().resolve(location).toString() - ready = true - } - } - - @Throws(RendezvousError::class) - override suspend fun receive(): ByteArray? { - if (cancelled) { - throw IllegalStateException("Rendezvous cancelled") - } - val uri = uri ?: throw IllegalStateException("Rendezvous not set up") - val httpClient = okhttp3.OkHttpClient.Builder().build() - while (true) { - Timber.tag(TAG).i("Polling: $uri after etag $etag") - val request = Request.Builder() - .url(uri) - .get() - - etag?.let { - request.header("if-none-match", it) - } - - val response = httpClient.newCall(request.build()).execute() - - try { - // expired - if (response.code == 404) { - throw get404Error() - } - - // rely on server expiring the channel rather than checking ourselves - - if (response.header("content-type") != "application/json") { - response.header("etag")?.let { - etag = it - } - } else if (response.code == 200) { - response.header("etag")?.let { - etag = it - } - return response.body?.bytes() - } - - // sleep for a second before polling again - // we rely on the server expiring the channel rather than checking it ourselves - delay(1000) - } finally { - response.close() - } - } - } - - private fun get404Error(): RendezvousError { - if (expiresAt != null && Date() > expiresAt) { - return RendezvousError("Expired", RendezvousFailureReason.Expired) - } - - return RendezvousError("Received unexpected 404", RendezvousFailureReason.Unknown) - } - - override suspend fun close() { - cancelled = true - ready = false - - uri?.let { - try { - val httpClient = okhttp3.OkHttpClient.Builder().build() - val request = Request.Builder() - .url(it) - .delete() - .build() - httpClient.newCall(request).execute() - } catch (e: Throwable) { - Timber.tag(TAG).w(e, "Failed to delete channel") - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt index 94ee7ba403..220a75bd3f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.api.session.crypto import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap -import org.matrix.olm.OlmException /** * Represents a crypto error response. @@ -34,8 +33,6 @@ sealed class MXCryptoError : Throwable() { val detailedErrorDescription: String? = null ) : MXCryptoError() - data class OlmError(val olmException: OlmException) : MXCryptoError() - data class UnknownDevice(val deviceList: MXUsersDevicesMap) : MXCryptoError() enum class ErrorType { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt index b8d9711358..c45f85671e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt @@ -53,7 +53,6 @@ import org.matrix.android.sdk.api.util.toOptional import org.matrix.android.sdk.internal.coroutines.builder.safeInvokeOnClose import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.DefaultKeysAlgorithmAndData import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysAlgorithmAndData -import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.SasVerification import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest @@ -318,22 +317,6 @@ internal class OlmMachine @Inject constructor( inner.receiveVerificationEvent(serializedEvent, roomId) } - /** - * Used for lazy migration of inboundGroupSession from EA to ER. - */ - suspend fun importRoomKey(inbound: MXInboundMegolmSessionWrapper): Result { - Timber.v("Migration:: Tentative lazy migration") - return withContext(coroutineDispatchers.io) { - val export = inbound.exportKeys() - ?: return@withContext Result.failure(Exception("Failed to export key")) - val result = importDecryptedKeys(listOf(export), null).also { - Timber.v("Migration:: Tentative lazy migration result: ${it.totalNumberOfKeys}") - } - if (result.totalNumberOfKeys == 1) return@withContext Result.success(Unit) - return@withContext Result.failure(Exception("Import failed")) - } - } - /** * Mark the given list of users to be tracked, triggering a key query request for them. * diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt index e4c0469c74..72242d876c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt @@ -121,7 +121,8 @@ internal class PrepareToEncryptUseCase @Inject constructor( HistoryVisibility.INVITED } else { HistoryVisibility.JOINED - } + }, + errorOnVerifiedUserProblem = false, ) measureTimeMillis { keyShareLock.withLock { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RustCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RustCryptoService.kt index a6e4efd875..c998f104f4 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RustCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RustCryptoService.kt @@ -504,15 +504,8 @@ internal class RustCryptoService @Inject constructor( val content = event.content?.toModel() ?: throw mxCryptoError val roomId = event.roomId val sessionId = content.sessionId - val senderKey = content.senderKey if (roomId != null && sessionId != null) { - // try to perform a lazy migration from legacy store - val legacy = tryOrNull("Failed to access legacy crypto store") { - cryptoStore.getInboundGroupSession(sessionId, senderKey.orEmpty()) - } - if (legacy == null || olmMachine.importRoomKey(legacy).isFailure) { - perSessionBackupQueryRateLimiter.tryFromBackupIfPossible(sessionId, roomId) - } + perSessionBackupQueryRateLimiter.tryFromBackupIfPossible(sessionId, roomId) } } throw mxCryptoError @@ -851,9 +844,9 @@ internal class RustCryptoService @Inject constructor( override fun removeSessionListener(listener: NewSessionListener) { megolmSessionImportManager.removeListener(listener) } -/* ========================================================================================== - * DEBUG INFO - * ========================================================================================== */ + /* ========================================================================================== + * DEBUG INFO + * ========================================================================================== */ override fun toString(): String { return "DefaultCryptoService of $myUserId ($deviceId)" diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt index 37d1bd4b89..6750808454 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt @@ -65,7 +65,6 @@ import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.util.JsonCanonicalizer -import org.matrix.olm.OlmException import org.matrix.rustcomponents.sdk.crypto.Request import org.matrix.rustcomponents.sdk.crypto.RequestType import org.matrix.rustcomponents.sdk.crypto.SignatureVerification @@ -840,8 +839,8 @@ internal class RustKeyBackupService @Inject constructor( try { olmMachine.enableBackupV1(retrievedMegolmBackupAuthData.publicKey, keysVersionResult.version) keysBackupVersion = keysVersionResult - } catch (e: OlmException) { - Timber.e(e, "OlmException") + } catch (e: Exception) { + Timber.e(e, "Exception") keysBackupStateManager.state = KeysBackupState.Disabled return } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXInboundMegolmSessionWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXInboundMegolmSessionWrapper.kt deleted file mode 100644 index 2c6a0a967a..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXInboundMegolmSessionWrapper.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2022 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 - -import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM -import org.matrix.android.sdk.api.extensions.tryOrNull -import org.matrix.android.sdk.internal.crypto.MegolmSessionData -import org.matrix.olm.OlmInboundGroupSession -import timber.log.Timber - -data class MXInboundMegolmSessionWrapper( - // olm object - val session: OlmInboundGroupSession, - // data about the session - val sessionData: InboundGroupSessionData -) { - // shortcut - val roomId = sessionData.roomId - val senderKey = sessionData.senderKey - val safeSessionId = tryOrNull("Fail to get megolm session Id") { session.sessionIdentifier() } - - /** - * Export the inbound group session keys. - * @param index the index to export. If null, the first known index will be used - * @return the inbound group session as MegolmSessionData if the operation succeeds - */ - internal fun exportKeys(index: Long? = null): MegolmSessionData? { - return try { - val keysClaimed = sessionData.keysClaimed ?: return null - val wantedIndex = index ?: session.firstKnownIndex - - MegolmSessionData( - senderClaimedEd25519Key = sessionData.keysClaimed?.get("ed25519"), - forwardingCurve25519KeyChain = sessionData.forwardingCurve25519KeyChain?.toList().orEmpty(), - sessionKey = session.export(wantedIndex), - senderClaimedKeys = keysClaimed, - roomId = sessionData.roomId, - sessionId = session.sessionIdentifier(), - senderKey = senderKey, - algorithm = MXCRYPTO_ALGORITHM_MEGOLM, - sharedHistory = sessionData.sharedHistory - ) - } catch (e: Exception) { - Timber.e(e, "## Failed to export megolm : sessionID ${tryOrNull { session.sessionIdentifier() }} failed") - null - } - } - - companion object { - - /** - * @exportFormat true if the megolm keys are in export format - * (ie, they lack an ed25519 signature) - */ - @Throws - internal fun newFromMegolmData(megolmSessionData: MegolmSessionData, exportFormat: Boolean): MXInboundMegolmSessionWrapper { - val exportedKey = megolmSessionData.sessionKey ?: throw IllegalArgumentException("key data not found") - val inboundSession = if (exportFormat) { - OlmInboundGroupSession.importSession(exportedKey) - } else { - OlmInboundGroupSession(exportedKey) - } - .also { - if (it.sessionIdentifier() != megolmSessionData.sessionId) { - it.releaseSession() - throw IllegalStateException("Mismatched group session Id") - } - } - val data = InboundGroupSessionData( - roomId = megolmSessionData.roomId, - senderKey = megolmSessionData.senderKey, - keysClaimed = megolmSessionData.senderClaimedKeys, - forwardingCurve25519KeyChain = megolmSessionData.forwardingCurve25519KeyChain, - sharedHistory = megolmSessionData.sharedHistory, - trusted = false - ) - - return MXInboundMegolmSessionWrapper( - inboundSession, - data - ) - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt deleted file mode 100755 index 6b747d19f2..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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 - -import org.matrix.android.sdk.api.util.JsonDict -import timber.log.Timber - -internal data class MXKey( - /** - * The type of the key (in the example: "signed_curve25519"). - */ - val type: String, - - /** - * The id of the key (in the example: "AAAAFw"). - */ - private val keyId: String, - - /** - * The key (in the example: "IjwIcskng7YjYcn0tS8TUOT2OHHtBSfMpcfIczCgXj4"). - */ - val value: String, - - /** - * signature user Id to [deviceid][signature]. - */ - private val signatures: Map>, - - /** - * We have to store the original json because it can contain other fields - * that we don't support yet but they would be needed to check signatures. - */ - private val rawMap: JsonDict -) { - - /** - * @return the signed data map - */ - fun signalableJSONDictionary(): Map { - return rawMap.filter { - it.key != "signatures" && it.key != "unsigned" - } - } - - /** - * Returns a signature for an user Id and a signkey. - * - * @param userId the user id - * @param signkey the sign key - * @return the signature - */ - fun signatureForUserId(userId: String, signkey: String): String? { - // sanity checks - if (userId.isNotBlank() && signkey.isNotBlank()) { - return signatures[userId]?.get(signkey) - } - - return null - } - - companion object { - /** - * Key types. - */ - const val KEY_CURVE_25519_TYPE = "curve25519" - const val KEY_SIGNED_CURVE_25519_TYPE = "signed_curve25519" - // const val KEY_ED_25519_TYPE = "ed25519" - - /** - * Convert a map to a MXKey. - * - * @param map the map to convert - * - * Json Example: - * - *
-         *   "signed_curve25519:AAAAFw": {
-         *     "key": "IjwIcskng7YjYcn0tS8TUOT2OHHtBSfMpcfIczCgXj4",
-         *     "fallback" : true|false
-         *     "signatures": {
-         *       "@userId:matrix.org": {
-         *         "ed25519:GMJRREOASV": "EUjp6pXzK9u3SDFR\/qLbzpOi3bEREeI6qMnKzXu992HsfuDDZftfJfiUXv9b\/Hqq1og4qM\/vCQJGTHAWMmgkCg"
-         *       }
-         *     }
-         *   }
-         * 
- * - * into several val members - */ - fun from(map: Map?): MXKey? { - if (map?.isNotEmpty() == true) { - val firstKey = map.keys.first() - - val components = firstKey.split(":").dropLastWhile { it.isEmpty() } - - if (components.size == 2) { - val params = map[firstKey] - if (params != null) { - if (params["key"] is String) { - @Suppress("UNCHECKED_CAST") - return MXKey( - type = components[0], - keyId = components[1], - value = params["key"] as String, - signatures = params["signatures"] as Map>, - rawMap = params - ) - } - } - } - } - - // Error case - Timber.e("## Unable to parse map") - return null - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXOlmSessionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXOlmSessionResult.kt deleted file mode 100755 index 666ab2d678..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXOlmSessionResult.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 - -import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo -import java.io.Serializable - -internal data class MXOlmSessionResult( - /** - * the device. - */ - val deviceInfo: CryptoDeviceInfo, - /** - * Base64 olm session id. - * null if no session could be established. - */ - var sessionId: String? -) : Serializable diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXUsersDevicesMap.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXUsersDevicesMap.kt deleted file mode 100755 index 58aff14a3d..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXUsersDevicesMap.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 - -import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap - -internal fun MXUsersDevicesMap.toDebugString() = - map.entries.joinToString { "${it.key} [${it.value.keys.joinToString { it }}]" } - -internal fun MXUsersDevicesMap.toDebugCount() = - map.entries.fold(0) { acc, new -> - acc + new.value.keys.size - } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper.kt deleted file mode 100755 index ecb2946680..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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 - -import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM -import org.matrix.android.sdk.internal.crypto.MegolmSessionData -import org.matrix.olm.OlmInboundGroupSession -import timber.log.Timber -import java.io.Serializable - -/** - * This class adds more context to a OlmInboundGroupSession object. - * This allows additional checks. The class implements Serializable so that the context can be stored. - */ -internal class OlmInboundGroupSessionWrapper : Serializable { - - // The associated olm inbound group session. - var olmInboundGroupSession: OlmInboundGroupSession? = null - - // The room in which this session is used. - var roomId: String? = null - - // The base64-encoded curve25519 key of the sender. - var senderKey: String? = null - - // Other keys the sender claims. - var keysClaimed: Map? = null - - // Devices which forwarded this session to us (normally empty). - var forwardingCurve25519KeyChain: List? = ArrayList() - - /** - * @return the first known message index - */ - val firstKnownIndex: Long? - get() { - if (null != olmInboundGroupSession) { - try { - return olmInboundGroupSession!!.firstKnownIndex - } catch (e: Exception) { - Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed") - } - } - - return null - } - - /** - * Constructor. - * - * @param sessionKey the session key - * @param isImported true if it is an imported session key - */ - constructor(sessionKey: String, isImported: Boolean) { - try { - if (!isImported) { - olmInboundGroupSession = OlmInboundGroupSession(sessionKey) - } else { - olmInboundGroupSession = OlmInboundGroupSession.importSession(sessionKey) - } - } catch (e: Exception) { - Timber.e(e, "Cannot create") - } - } - - /** - * Create a new instance from the provided keys map. - * - * @param megolmSessionData the megolm session data - * @throws Exception if the data are invalid - */ - @Throws(Exception::class) - constructor(megolmSessionData: MegolmSessionData) { - try { - olmInboundGroupSession = OlmInboundGroupSession.importSession(megolmSessionData.sessionKey!!) - - if (olmInboundGroupSession!!.sessionIdentifier() != megolmSessionData.sessionId) { - throw Exception("Mismatched group session Id") - } - - senderKey = megolmSessionData.senderKey - keysClaimed = megolmSessionData.senderClaimedKeys - roomId = megolmSessionData.roomId - } catch (e: Exception) { - throw Exception(e.message) - } - } - - /** - * Export the inbound group session keys. - * - * @return the inbound group session as MegolmSessionData if the operation succeeds - */ - fun exportKeys(): MegolmSessionData? { - return try { - if (null == forwardingCurve25519KeyChain) { - forwardingCurve25519KeyChain = ArrayList() - } - - if (keysClaimed == null) { - return null - } - - MegolmSessionData( - senderClaimedEd25519Key = keysClaimed?.get("ed25519"), - forwardingCurve25519KeyChain = ArrayList(forwardingCurve25519KeyChain!!), - senderKey = senderKey, - senderClaimedKeys = keysClaimed, - roomId = roomId, - sessionId = olmInboundGroupSession!!.sessionIdentifier(), - sessionKey = olmInboundGroupSession!!.export(olmInboundGroupSession!!.firstKnownIndex), - algorithm = MXCRYPTO_ALGORITHM_MEGOLM - ) - } catch (e: Exception) { - Timber.e(e, "## export() : senderKey $senderKey failed") - null - } - } - - /** - * Export the session for a message index. - * - * @param messageIndex the message index - * @return the exported data - */ - fun exportSession(messageIndex: Long): String? { - if (null != olmInboundGroupSession) { - try { - return olmInboundGroupSession!!.export(messageIndex) - } catch (e: Exception) { - Timber.e(e, "## exportSession() : export failed") - } - } - - return null - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt deleted file mode 100755 index 600fcb1003..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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 - -import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM -import org.matrix.android.sdk.internal.crypto.MegolmSessionData -import org.matrix.olm.OlmInboundGroupSession -import timber.log.Timber -import java.io.Serializable - -/** - * This class adds more context to a OlmInboundGroupSession object. - * This allows additional checks. The class implements Serializable so that the context can be stored. - */ -// Note used anymore, just for database migration -// Deprecated("Use MXInboundMegolmSessionWrapper") -internal class OlmInboundGroupSessionWrapper2 : Serializable { - - // The associated olm inbound group session. - var olmInboundGroupSession: OlmInboundGroupSession? = null - - // The room in which this session is used. - var roomId: String? = null - - // The base64-encoded curve25519 key of the sender. - var senderKey: String? = null - - // Other keys the sender claims. - var keysClaimed: Map? = null - - // Devices which forwarded this session to us (normally empty). - var forwardingCurve25519KeyChain: List? = ArrayList() - - /** - * @return the first known message index - */ - val firstKnownIndex: Long? - get() { - return try { - olmInboundGroupSession?.firstKnownIndex - } catch (e: Exception) { - Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed") - null - } - } - - /** - * Constructor. - * - * @param sessionKey the session key - * @param isImported true if it is an imported session key - */ - constructor(sessionKey: String, isImported: Boolean) { - try { - if (!isImported) { - olmInboundGroupSession = OlmInboundGroupSession(sessionKey) - } else { - olmInboundGroupSession = OlmInboundGroupSession.importSession(sessionKey) - } - } catch (e: Exception) { - Timber.e(e, "Cannot create") - } - } - - constructor() { - // empty - } - - /** - * Create a new instance from the provided keys map. - * - * @param megolmSessionData the megolm session data - * @throws Exception if the data are invalid - */ - @Throws(Exception::class) - constructor(megolmSessionData: MegolmSessionData) { - try { - val safeSessionKey = megolmSessionData.sessionKey ?: throw Exception("invalid data") - olmInboundGroupSession = OlmInboundGroupSession.importSession(safeSessionKey) - .also { - if (it.sessionIdentifier() != megolmSessionData.sessionId) { - throw Exception("Mismatched group session Id") - } - } - - senderKey = megolmSessionData.senderKey - keysClaimed = megolmSessionData.senderClaimedKeys - roomId = megolmSessionData.roomId - } catch (e: Exception) { - throw Exception(e.message) - } - } - - /** - * Export the inbound group session keys. - * @param index the index to export. If null, the first known index will be used - * - * @return the inbound group session as MegolmSessionData if the operation succeeds - */ - fun exportKeys(index: Long? = null): MegolmSessionData? { - return try { - if (null == forwardingCurve25519KeyChain) { - forwardingCurve25519KeyChain = ArrayList() - } - - if (keysClaimed == null) { - return null - } - - val safeOlmInboundGroupSession = olmInboundGroupSession ?: return null - - val wantedIndex = index ?: safeOlmInboundGroupSession.firstKnownIndex - - MegolmSessionData( - senderClaimedEd25519Key = keysClaimed?.get("ed25519"), - forwardingCurve25519KeyChain = forwardingCurve25519KeyChain?.toList().orEmpty(), - senderKey = senderKey, - senderClaimedKeys = keysClaimed, - roomId = roomId, - sessionId = safeOlmInboundGroupSession.sessionIdentifier(), - sessionKey = safeOlmInboundGroupSession.export(wantedIndex), - algorithm = MXCRYPTO_ALGORITHM_MEGOLM - ) - } catch (e: Exception) { - Timber.e(e, "## export() : senderKey $senderKey failed") - null - } - } - - /** - * Export the session for a message index. - * - * @param messageIndex the message index - * @return the exported data - */ - fun exportSession(messageIndex: Long): String? { - return try { - return olmInboundGroupSession?.export(messageIndex) - } catch (e: Exception) { - Timber.e(e, "## exportSession() : export failed") - null - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmSessionWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmSessionWrapper.kt deleted file mode 100644 index a1e58ead0c..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmSessionWrapper.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 - -import kotlinx.coroutines.sync.Mutex -import org.matrix.olm.OlmSession - -/** - * Encapsulate a OlmSession and a last received message Timestamp. - */ -internal data class OlmSessionWrapper( - // The associated olm session. - val olmSession: OlmSession, - // Timestamp at which the session last received a message. - var lastReceivedMessageTs: Long = 0, - - val mutex: Mutex = Mutex() -) { - - /** - * Notify that a message has been received on this olm session so that it updates `lastReceivedMessageTs`. - */ - fun onMessageReceived(currentTimeMillis: Long) { - lastReceivedMessageTs = currentTimeMillis - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OutboundGroupSessionWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OutboundGroupSessionWrapper.kt deleted file mode 100644 index 5a6d1f4bc1..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OutboundGroupSessionWrapper.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 - -import org.matrix.olm.OlmOutboundGroupSession - -internal data class OutboundGroupSessionWrapper( - val outboundGroupSession: OlmOutboundGroupSession, - val creationTime: Long, - /** - * As per MSC 3061, declares if this key could be shared when inviting a new user to the room. - */ - val sharedHistory: Boolean = false -) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt index 05b9e14b82..f443e5b7f6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt @@ -20,7 +20,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.crypto.SSSS_ALGORITHM_AES_HMAC_SHA2 -import org.matrix.android.sdk.api.crypto.SSSS_ALGORITHM_CURVE25519_AES_SHA2 import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService @@ -44,9 +43,7 @@ import org.matrix.android.sdk.api.util.toBase64NoPadding import org.matrix.android.sdk.internal.crypto.SecretShareManager import org.matrix.android.sdk.internal.crypto.keysbackup.generatePrivateKeyWithPassword import org.matrix.android.sdk.internal.crypto.tools.HkdfSha256 -import org.matrix.android.sdk.internal.crypto.tools.withOlmDecryption import org.matrix.android.sdk.internal.di.UserId -import org.matrix.olm.OlmPkMessage import java.security.SecureRandom import javax.crypto.Cipher import javax.crypto.Mac @@ -321,22 +318,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor( ?: throw SharedSecretStorageError.ParsingError val algorithm = key.keyInfo.content - if (SSSS_ALGORITHM_CURVE25519_AES_SHA2 == algorithm.algorithm) { - val keySpec = secretKey as? RawBytesKeySpec ?: throw SharedSecretStorageError.BadKeyFormat - return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) { - // decrypt from recovery key - withOlmDecryption { olmPkDecryption -> - olmPkDecryption.setPrivateKey(keySpec.privateKey) - olmPkDecryption.decrypt(OlmPkMessage() - .apply { - mCipherText = secretContent.ciphertext - mEphemeralKey = secretContent.ephemeral - mMac = secretContent.mac - } - ) - } - } - } else if (SSSS_ALGORITHM_AES_HMAC_SHA2 == algorithm.algorithm) { + if (SSSS_ALGORITHM_AES_HMAC_SHA2 == algorithm.algorithm) { val keySpec = secretKey as? RawBytesKeySpec ?: throw SharedSecretStorageError.BadKeyFormat return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) { decryptAesHmacSha2(keySpec, name, secretContent) @@ -366,8 +348,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor( val keyInfo = (keyInfoResult as? KeyInfoResult.Success)?.keyInfo ?: return IntegrityResult.Error(SharedSecretStorageError.UnknownKey(keyId ?: "")) - if (keyInfo.content.algorithm != SSSS_ALGORITHM_AES_HMAC_SHA2 && - keyInfo.content.algorithm != SSSS_ALGORITHM_CURVE25519_AES_SHA2) { + if (keyInfo.content.algorithm != SSSS_ALGORITHM_AES_HMAC_SHA2) { // Unsupported algorithm return IntegrityResult.Error( SharedSecretStorageError.UnsupportedAlgorithm(keyInfo.content.algorithm ?: "") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCommonCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCommonCryptoStore.kt index 68b002c087..ca389c9b00 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCommonCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCommonCryptoStore.kt @@ -23,7 +23,6 @@ import org.matrix.android.sdk.api.session.crypto.model.CryptoRoomInfo import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent import org.matrix.android.sdk.api.util.Optional -import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator /** @@ -143,14 +142,4 @@ interface IMXCommonCryptoStore { * @return the device or null if not found */ fun deviceWithIdentityKey(userId: String, identityKey: String): CryptoDeviceInfo? - - /** - * Retrieve an inbound group session. - * Used in rust for lazy migration - * - * @param sessionId the session identifier. - * @param senderKey the base64-encoded curve25519 key of the sender. - * @return an inbound group session. - */ - fun getInboundGroupSession(sessionId: String, senderKey: String): MXInboundMegolmSessionWrapper? } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/RustCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/RustCryptoStore.kt index 6854449861..93d4963c91 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/RustCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/RustCryptoStore.kt @@ -35,32 +35,23 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventCo import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toOptional import org.matrix.android.sdk.internal.crypto.OlmMachine -import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator import org.matrix.android.sdk.internal.crypto.store.db.doRealmTransaction import org.matrix.android.sdk.internal.crypto.store.db.doRealmTransactionAsync import org.matrix.android.sdk.internal.crypto.store.db.doWithRealm import org.matrix.android.sdk.internal.crypto.store.db.mapper.CryptoRoomInfoMapper import org.matrix.android.sdk.internal.crypto.store.db.mapper.MyDeviceLastSeenInfoEntityMapper -import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.createPrimaryKey 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.di.CryptoDatabase import org.matrix.android.sdk.internal.di.DeviceId import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.SessionScope -import org.matrix.android.sdk.internal.util.time.Clock import timber.log.Timber import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -75,7 +66,6 @@ private val loggerTag = LoggerTag("RealmCryptoStore", LoggerTag.CRYPTO) @SessionScope internal class RustCryptoStore @Inject constructor( @CryptoDatabase private val realmConfiguration: RealmConfiguration, - private val clock: Clock, @UserId private val userId: String, @DeviceId private val deviceId: String, private val myDeviceLastSeenInfoEntityMapper: MyDeviceLastSeenInfoEntityMapper, @@ -134,20 +124,6 @@ internal class RustCryptoStore @Inject constructor( } } - /** - * Needed for lazy migration of sessions from the legacy store. - */ - override fun getInboundGroupSession(sessionId: String, senderKey: String): MXInboundMegolmSessionWrapper? { - val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionId, senderKey) - - return doWithRealm(realmConfiguration) { realm -> - realm.where() - .equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key) - .findFirst() - ?.toModel() - } - } - // ================================================ // Things that should be migrated to another store than realm // ================================================ @@ -163,30 +139,7 @@ internal class RustCryptoStore @Inject constructor( // nop } - override fun tidyUpDataBase() { - // These entities are not used in rust actually, but as they are not yet cleaned up, this will do it with time - val prevWeekTs = clock.epochMillis() - 7 * 24 * 60 * 60 * 1_000 - doRealmTransaction("tidyUpDataBase", realmConfiguration) { realm -> - - // Clean the old ones? - realm.where() - .lessThan(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, prevWeekTs) - .findAll() - .also { Timber.i("## Crypto Clean up ${it.size} OutgoingKeyRequestEntity") } - .deleteAllFromRealm() - - // Only keep one month history - - val prevMonthTs = clock.epochMillis() - 4 * 7 * 24 * 60 * 60 * 1_000L - realm.where() - .lessThan(AuditTrailEntityFields.AGE_LOCAL_TS, prevMonthTs) - .findAll() - .also { Timber.i("## Crypto Clean up ${it.size} AuditTrailEntity") } - .deleteAllFromRealm() - - // Can we do something for WithHeldSessionEntity? - } - } + override fun tidyUpDataBase() = Unit override fun close() { val tasks = monarchyWriteAsyncExecutor.shutdownNow() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/UserDataToStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/UserDataToStore.kt deleted file mode 100644 index 914ce4704e..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/UserDataToStore.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2023 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 - -import org.matrix.android.sdk.api.session.crypto.crosssigning.UserIdentity -import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo - -internal data class UserDataToStore( - /** - * Map of userId -> (Map of deviceId -> [CryptoDeviceInfo]). - */ - val userDevices: MutableMap> = mutableMapOf(), - /** - * Map of userId -> [UserIdentity]. - */ - val userIdentities: MutableMap = mutableMapOf(), -) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt index 6412df205f..fb10ecc999 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt @@ -16,15 +16,9 @@ package org.matrix.android.sdk.internal.crypto.store.db -import android.util.Base64 import io.realm.Realm import io.realm.RealmConfiguration -import io.realm.RealmObject import timber.log.Timber -import java.io.ByteArrayOutputStream -import java.io.ObjectOutputStream -import java.util.zip.GZIPInputStream -import java.util.zip.GZIPOutputStream import kotlin.system.measureTimeMillis /** @@ -36,24 +30,6 @@ internal fun doWithRealm(realmConfiguration: RealmConfiguration, action: (Re } } -/** - * Get realm, do the query, copy from realm, close realm, and return the copied result. - */ -internal fun doRealmQueryAndCopy(realmConfiguration: RealmConfiguration, action: (Realm) -> T?): T? { - return Realm.getInstance(realmConfiguration).use { realm -> - action.invoke(realm)?.let { realm.copyFromRealm(it) } - } -} - -/** - * Get realm, do the list query, copy from realm, close realm, and return the copied result. - */ -internal fun doRealmQueryAndCopyList(realmConfiguration: RealmConfiguration, action: (Realm) -> Iterable): Iterable { - return Realm.getInstance(realmConfiguration).use { realm -> - action.invoke(realm).let { realm.copyFromRealm(it) } - } -} - /** * Get realm instance, invoke the action in a transaction and close realm. */ @@ -70,38 +46,3 @@ internal fun doRealmTransactionAsync(realmConfiguration: RealmConfiguration, act realm.executeTransactionAsync { action.invoke(it) } } } - -/** - * Serialize any Serializable object, zip it and convert to Base64 String. - */ -internal fun serializeForRealm(o: Any?): String? { - if (o == null) { - return null - } - - val baos = ByteArrayOutputStream() - val gzis = GZIPOutputStream(baos) - val out = ObjectOutputStream(gzis) - out.use { - it.writeObject(o) - } - return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT) -} - -/** - * Do the opposite of serializeForRealm. - */ -@Suppress("UNCHECKED_CAST") -internal fun deserializeFromRealm(string: String?): T? { - if (string == null) { - return null - } - val decodedB64 = Base64.decode(string.toByteArray(), Base64.DEFAULT) - - val bais = decodedB64.inputStream() - val gzis = GZIPInputStream(bais) - val ois = SafeObjectInputStream(gzis) - return ois.use { - it.readObject() as T - } -} 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 1b0143f4fa..bbb14aaca0 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 @@ -17,31 +17,8 @@ package org.matrix.android.sdk.internal.crypto.store.db import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo001Legacy -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo002Legacy -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo003RiotX -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo004 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo005 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo006 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo007 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo008 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo009 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo010 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo011 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo012 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo013 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo014 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo015 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo016 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo017 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo018 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo019 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo020 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo021 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo022 -import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo023 +import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo024 import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration -import org.matrix.android.sdk.internal.util.time.Clock import javax.inject.Inject /** @@ -49,13 +26,11 @@ import javax.inject.Inject * 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). + * 24: Delete nearly all the crypto DB */ -internal class RealmCryptoStoreMigration @Inject constructor( - private val clock: Clock, - private val rustMigrationInfoProvider: RustMigrationInfoProvider, -) : MatrixRealmMigration( +internal class RealmCryptoStoreMigration @Inject constructor() : MatrixRealmMigration( dbName = "Crypto", - schemaVersion = 23L, + schemaVersion = 24L, ) { /** * Forces all RealmCryptoStoreMigration instances to be equal. @@ -65,33 +40,6 @@ internal class RealmCryptoStoreMigration @Inject constructor( override fun hashCode() = 5000 override fun doMigrate(realm: DynamicRealm, oldVersion: Long) { - if (oldVersion < 1) MigrateCryptoTo001Legacy(realm).perform() - if (oldVersion < 2) MigrateCryptoTo002Legacy(realm).perform() - if (oldVersion < 3) MigrateCryptoTo003RiotX(realm).perform() - if (oldVersion < 4) MigrateCryptoTo004(realm).perform() - if (oldVersion < 5) MigrateCryptoTo005(realm).perform() - if (oldVersion < 6) MigrateCryptoTo006(realm).perform() - if (oldVersion < 7) MigrateCryptoTo007(realm).perform() - if (oldVersion < 8) MigrateCryptoTo008(realm, clock).perform() - if (oldVersion < 9) MigrateCryptoTo009(realm).perform() - if (oldVersion < 10) MigrateCryptoTo010(realm).perform() - if (oldVersion < 11) MigrateCryptoTo011(realm).perform() - if (oldVersion < 12) MigrateCryptoTo012(realm).perform() - if (oldVersion < 13) MigrateCryptoTo013(realm).perform() - if (oldVersion < 14) MigrateCryptoTo014(realm).perform() - if (oldVersion < 15) MigrateCryptoTo015(realm).perform() - if (oldVersion < 16) MigrateCryptoTo016(realm).perform() - if (oldVersion < 17) MigrateCryptoTo017(realm).perform() - if (oldVersion < 18) MigrateCryptoTo018(realm).perform() - if (oldVersion < 19) MigrateCryptoTo019(realm).perform() - if (oldVersion < 20) MigrateCryptoTo020(realm).perform() - if (oldVersion < 21) MigrateCryptoTo021(realm).perform() - if (oldVersion < 22) MigrateCryptoTo022( - realm, - rustMigrationInfoProvider.rustDirectory, - rustMigrationInfoProvider.rustEncryptionConfiguration, - rustMigrationInfoProvider.migrateMegolmGroupSessions - ).perform() - if (oldVersion < 23) MigrateCryptoTo023(realm).perform() + if (oldVersion < 24) MigrateCryptoTo024(realm).perform() } } 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 6696cf8281..8b94baacde 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 @@ -17,23 +17,9 @@ package org.matrix.android.sdk.internal.crypto.store.db import io.realm.annotations.RealmModule -import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.KeyRequestReplyEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity -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 /** * Realm module for Crypto store classes. @@ -43,21 +29,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEnti classes = [ CryptoMetadataEntity::class, CryptoRoomEntity::class, - DeviceInfoEntity::class, - KeysBackupDataEntity::class, - OlmInboundGroupSessionEntity::class, - OlmSessionEntity::class, - UserEntity::class, - KeyInfoEntity::class, - CrossSigningInfoEntity::class, - TrustLevelEntity::class, - AuditTrailEntity::class, - OutgoingKeyRequestEntity::class, - KeyRequestReplyEntity::class, MyDeviceLastSeenInfoEntity::class, - WithHeldSessionEntity::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/RustMigrationInfoProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RustMigrationInfoProvider.kt deleted file mode 100644 index 667990468c..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RustMigrationInfoProvider.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2023 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 - -import org.matrix.android.sdk.internal.crypto.RustEncryptionConfiguration -import org.matrix.android.sdk.internal.di.SessionRustFilesDirectory -import java.io.File -import javax.inject.Inject - -internal class RustMigrationInfoProvider @Inject constructor( - @SessionRustFilesDirectory - val rustDirectory: File, - val rustEncryptionConfiguration: RustEncryptionConfiguration -) { - - var migrateMegolmGroupSessions: Boolean = false -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/SafeObjectInputStream.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/SafeObjectInputStream.kt deleted file mode 100644 index 5897869a97..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/SafeObjectInputStream.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 - -import java.io.IOException -import java.io.InputStream -import java.io.ObjectInputStream -import java.io.ObjectStreamClass - -/** - * Package has been renamed from `im.vector.matrix.android` to `org.matrix.android.sdk` - * so ensure deserialization of previously stored objects still works - * - * Ref: https://stackoverflow.com/questions/3884492/how-can-i-change-package-for-a-bunch-of-java-serializable-classes - */ -internal class SafeObjectInputStream(inputStream: InputStream) : ObjectInputStream(inputStream) { - - init { - enableResolveObject(true) - } - - @Throws(IOException::class, ClassNotFoundException::class) - override fun readClassDescriptor(): ObjectStreamClass { - val read = super.readClassDescriptor() - if (read.name.startsWith("im.vector.matrix.android.")) { - return ObjectStreamClass.lookup(Class.forName(read.name.replace("im.vector.matrix.android.", "org.matrix.android.sdk."))) - } - return read - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/CrossSigningKeysMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/CrossSigningKeysMapper.kt deleted file mode 100644 index 8b7bf9c26b..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/CrossSigningKeysMapper.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.mapper - -import com.squareup.moshi.Moshi -import com.squareup.moshi.Types -import io.realm.RealmList -import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey -import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel -import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntity -import timber.log.Timber -import javax.inject.Inject - -internal class CrossSigningKeysMapper @Inject constructor(moshi: Moshi) { - - private val signaturesAdapter = moshi.adapter>>( - Types.newParameterizedType( - Map::class.java, - String::class.java, - Any::class.java - ) - ) - - fun update(keyInfo: KeyInfoEntity, cryptoCrossSigningKey: CryptoCrossSigningKey) { - // update signatures? - keyInfo.signatures = serializeSignatures(cryptoCrossSigningKey.signatures) - keyInfo.usages = cryptoCrossSigningKey.usages?.toTypedArray()?.let { RealmList(*it) } - ?: RealmList() - } - - fun map(userId: String?, keyInfo: KeyInfoEntity?): CryptoCrossSigningKey? { - val pubKey = keyInfo?.publicKeyBase64 ?: return null - return CryptoCrossSigningKey( - userId = userId ?: "", - keys = mapOf("ed25519:$pubKey" to pubKey), - usages = keyInfo.usages.toList(), - signatures = deserializeSignatures(keyInfo.signatures), - trustLevel = keyInfo.trustLevelEntity?.let { - DeviceTrustLevel( - crossSigningVerified = it.crossSignedVerified ?: false, - locallyVerified = it.locallyVerified ?: false - ) - } - ) - } - - fun map(keyInfo: CryptoCrossSigningKey): KeyInfoEntity { - return KeyInfoEntity().apply { - publicKeyBase64 = keyInfo.unpaddedBase64PublicKey - usages = keyInfo.usages?.let { RealmList(*it.toTypedArray()) } ?: RealmList() - signatures = serializeSignatures(keyInfo.signatures) - // TODO how to handle better, check if same keys? - // reset trust - trustLevelEntity = null - } - } - - fun serializeSignatures(signatures: Map>?): String { - return signaturesAdapter.toJson(signatures) - } - - fun deserializeSignatures(signatures: String?): Map>? { - if (signatures == null) { - return null - } - return try { - signaturesAdapter.fromJson(signatures) - } catch (failure: Throwable) { - Timber.e(failure) - null - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo001Legacy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo001Legacy.kt deleted file mode 100644 index 7dee42e51a..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo001Legacy.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import timber.log.Timber - -internal class MigrateCryptoTo001Legacy(realm: DynamicRealm) : RealmMigrator(realm, 1) { - - override fun doMigrate(realm: DynamicRealm) { - Timber.d("Add field lastReceivedMessageTs (Long) and set the value to 0") - - realm.schema.get("OlmSessionEntity") - ?.addField(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, Long::class.java) - ?.transform { - it.setLong(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS, 0) - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo002Legacy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo002Legacy.kt deleted file mode 100644 index 1b53e1928a..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo002Legacy.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import timber.log.Timber - -internal class MigrateCryptoTo002Legacy(realm: DynamicRealm) : RealmMigrator(realm, 2) { - - override fun doMigrate(realm: DynamicRealm) { - Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields") - realm.schema.get("IncomingRoomKeyRequestEntity") - ?.addFieldIfNotExists("requestBodyAlgorithm", String::class.java) - ?.addFieldIfNotExists("requestBodyRoomId", String::class.java) - ?.addFieldIfNotExists("requestBodySenderKey", String::class.java) - ?.addFieldIfNotExists("requestBodySessionId", String::class.java) - ?.transform { dynamicObject -> - try { - val requestBodyString = dynamicObject.getString("requestBodyString") - // It was a map before - val map: Map? = deserializeFromRealm(requestBodyString) - - map?.let { - dynamicObject.setString("requestBodyAlgorithm", it["algorithm"]) - dynamicObject.setString("requestBodyRoomId", it["room_id"]) - dynamicObject.setString("requestBodySenderKey", it["sender_key"]) - dynamicObject.setString("requestBodySessionId", it["session_id"]) - } - } catch (e: Exception) { - Timber.e(e, "Error") - } - } - ?.removeFieldIfExists("requestBodyString") - - Timber.d("Update IncomingRoomKeyRequestEntity format: requestBodyString field is exploded into several fields") - realm.schema.get("OutgoingRoomKeyRequestEntity") - ?.addFieldIfNotExists("requestBodyAlgorithm", String::class.java) - ?.addFieldIfNotExists("requestBodyRoomId", String::class.java) - ?.addFieldIfNotExists("requestBodySenderKey", String::class.java) - ?.addFieldIfNotExists("requestBodySessionId", String::class.java) - ?.transform { dynamicObject -> - try { - val requestBodyString = dynamicObject.getString("requestBodyString") - // It was a map before - val map: Map? = deserializeFromRealm(requestBodyString) - - map?.let { - dynamicObject.setString("requestBodyAlgorithm", it["algorithm"]) - dynamicObject.setString("requestBodyRoomId", it["room_id"]) - dynamicObject.setString("requestBodySenderKey", it["sender_key"]) - dynamicObject.setString("requestBodySessionId", it["session_id"]) - } - } catch (e: Exception) { - Timber.e(e, "Error") - } - } - ?.removeFieldIfExists("requestBodyString") - - Timber.d("Create KeysBackupDataEntity") - if (!realm.schema.contains("KeysBackupDataEntity")) { - realm.schema.create("KeysBackupDataEntity") - .addField(KeysBackupDataEntityFields.PRIMARY_KEY, Integer::class.java) - .addPrimaryKey(KeysBackupDataEntityFields.PRIMARY_KEY) - .setRequired(KeysBackupDataEntityFields.PRIMARY_KEY, true) - .addField(KeysBackupDataEntityFields.BACKUP_LAST_SERVER_HASH, String::class.java) - .addField(KeysBackupDataEntityFields.BACKUP_LAST_SERVER_NUMBER_OF_KEYS, Integer::class.java) - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo003RiotX.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo003RiotX.kt deleted file mode 100644 index 34d1afa2d8..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo003RiotX.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper -import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import org.matrix.androidsdk.crypto.data.MXDeviceInfo -import org.matrix.androidsdk.crypto.data.MXOlmInboundGroupSession2 -import timber.log.Timber - -internal class MigrateCryptoTo003RiotX(realm: DynamicRealm) : RealmMigrator(realm, 3) { - - override fun doMigrate(realm: DynamicRealm) { - Timber.d("Migrate to RiotX model") - realm.schema.get("CryptoRoomEntity") - ?.addFieldIfNotExists(CryptoRoomEntityFields.SHOULD_ENCRYPT_FOR_INVITED_MEMBERS, Boolean::class.java) - ?.setRequiredIfNotAlready(CryptoRoomEntityFields.SHOULD_ENCRYPT_FOR_INVITED_MEMBERS, false) - - // Convert format of MXDeviceInfo, package has to be the same. - realm.schema.get("DeviceInfoEntity") - ?.transform { obj -> - try { - val oldSerializedData = obj.getString("deviceInfoData") - deserializeFromRealm(oldSerializedData)?.let { legacyMxDeviceInfo -> - val newMxDeviceInfo = org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo( - deviceId = legacyMxDeviceInfo.deviceId, - userId = legacyMxDeviceInfo.userId, - algorithms = legacyMxDeviceInfo.algorithms, - keys = legacyMxDeviceInfo.keys, - signatures = legacyMxDeviceInfo.signatures, - unsigned = legacyMxDeviceInfo.unsigned, - verified = legacyMxDeviceInfo.mVerified - ) - - obj.setString("deviceInfoData", serializeForRealm(newMxDeviceInfo)) - } - } catch (e: Exception) { - Timber.e(e, "Error") - } - } - - // Convert MXOlmInboundGroupSession2 to OlmInboundGroupSessionWrapper - realm.schema.get("OlmInboundGroupSessionEntity") - ?.transform { obj -> - try { - val oldSerializedData = obj.getString("olmInboundGroupSessionData") - deserializeFromRealm(oldSerializedData)?.let { mxOlmInboundGroupSession2 -> - val sessionKey = mxOlmInboundGroupSession2.mSession.sessionIdentifier() - val newOlmInboundGroupSessionWrapper = OlmInboundGroupSessionWrapper(sessionKey, false) - .apply { - olmInboundGroupSession = mxOlmInboundGroupSession2.mSession - roomId = mxOlmInboundGroupSession2.mRoomId - senderKey = mxOlmInboundGroupSession2.mSenderKey - keysClaimed = mxOlmInboundGroupSession2.mKeysClaimed - forwardingCurve25519KeyChain = mxOlmInboundGroupSession2.mForwardingCurve25519KeyChain - } - - obj.setString("olmInboundGroupSessionData", serializeForRealm(newOlmInboundGroupSessionWrapper)) - } - } catch (e: Exception) { - Timber.e(e, "Error") - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt deleted file mode 100644 index 0a986892d9..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import com.squareup.moshi.Moshi -import com.squareup.moshi.Types -import io.realm.DynamicRealm -import org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo -import org.matrix.android.sdk.api.util.JsonDict -import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields -import org.matrix.android.sdk.internal.di.SerializeNulls -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import timber.log.Timber - -// Version 4L added Cross Signing info persistence -internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) { - - override fun doMigrate(realm: DynamicRealm) { - if (realm.schema.contains("TrustLevelEntity")) { - Timber.d("Skipping Step 3 -> 4 because entities already exist") - return - } - - Timber.d("Create KeyInfoEntity") - val trustLevelEntityEntitySchema = realm.schema.create("TrustLevelEntity") - .addField(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, Boolean::class.java) - .setNullable(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, true) - .addField(TrustLevelEntityFields.LOCALLY_VERIFIED, Boolean::class.java) - .setNullable(TrustLevelEntityFields.LOCALLY_VERIFIED, true) - - val keyInfoEntitySchema = realm.schema.create("KeyInfoEntity") - .addField(KeyInfoEntityFields.PUBLIC_KEY_BASE64, String::class.java) - .addField(KeyInfoEntityFields.SIGNATURES, String::class.java) - .addRealmListField(KeyInfoEntityFields.USAGES.`$`, String::class.java) - .addRealmObjectField(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelEntityEntitySchema) - - Timber.d("Create CrossSigningInfoEntity") - - val crossSigningInfoSchema = realm.schema.create("CrossSigningInfoEntity") - .addField(CrossSigningInfoEntityFields.USER_ID, String::class.java) - .addPrimaryKey(CrossSigningInfoEntityFields.USER_ID) - .addRealmListField(CrossSigningInfoEntityFields.CROSS_SIGNING_KEYS.`$`, keyInfoEntitySchema) - - Timber.d("Updating UserEntity table") - realm.schema.get("UserEntity") - ?.addRealmObjectField(UserEntityFields.CROSS_SIGNING_INFO_ENTITY.`$`, crossSigningInfoSchema) - - Timber.d("Updating CryptoMetadataEntity table") - realm.schema.get("CryptoMetadataEntity") - ?.addField(CryptoMetadataEntityFields.X_SIGN_MASTER_PRIVATE_KEY, String::class.java) - ?.addField(CryptoMetadataEntityFields.X_SIGN_USER_PRIVATE_KEY, String::class.java) - ?.addField(CryptoMetadataEntityFields.X_SIGN_SELF_SIGNED_PRIVATE_KEY, String::class.java) - - val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build() - val listMigrationAdapter = moshi.adapter>( - Types.newParameterizedType( - List::class.java, - String::class.java, - Any::class.java - ) - ) - val mapMigrationAdapter = moshi.adapter( - Types.newParameterizedType( - Map::class.java, - String::class.java, - Any::class.java - ) - ) - - realm.schema.get("DeviceInfoEntity") - ?.addField(DeviceInfoEntityFields.USER_ID, String::class.java) - ?.addField(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, String::class.java) - ?.addField(DeviceInfoEntityFields.KEYS_MAP_JSON, String::class.java) - ?.addField(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, String::class.java) - ?.addField(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, String::class.java) - ?.addField(DeviceInfoEntityFields.IS_BLOCKED, Boolean::class.java) - ?.setNullable(DeviceInfoEntityFields.IS_BLOCKED, true) - ?.addRealmObjectField(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelEntityEntitySchema) - ?.transform { obj -> - - try { - val oldSerializedData = obj.getString("deviceInfoData") - deserializeFromRealm(oldSerializedData)?.let { oldDevice -> - - val trustLevel = realm.createObject("TrustLevelEntity") - when (oldDevice.verified) { - MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> { - obj.setNull(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`) - } - MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> { - trustLevel.setNull(TrustLevelEntityFields.LOCALLY_VERIFIED) - trustLevel.setNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED) - obj.setBoolean(DeviceInfoEntityFields.IS_BLOCKED, oldDevice.isBlocked) - obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) - } - MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED -> { - trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, false) - trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false) - obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) - } - MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> { - trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, true) - trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false) - obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) - } - } - - obj.setString(DeviceInfoEntityFields.USER_ID, oldDevice.userId) - obj.setString(DeviceInfoEntityFields.IDENTITY_KEY, oldDevice.identityKey()) - obj.setString(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, listMigrationAdapter.toJson(oldDevice.algorithms)) - obj.setString(DeviceInfoEntityFields.KEYS_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.keys)) - obj.setString(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.signatures)) - obj.setString(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.unsigned)) - } - } catch (failure: Throwable) { - Timber.w(failure, "Crypto Data base migration error") - // an unfortunate refactor did modify that class, making deserialization failing - // so we just skip and ignore.. - } - } - ?.removeField("deviceInfoData") - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt deleted file mode 100644 index 8ec2932a8f..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -internal class MigrateCryptoTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.remove("OutgoingRoomKeyRequestEntity") - realm.schema.remove("IncomingRoomKeyRequestEntity") - - // Not need to migrate existing request, just start fresh? - realm.schema.create("GossipingEventEntity") - .addField("type", String::class.java) - .addIndex("type") - .addField("content", String::class.java) - .addField("sender", String::class.java) - .addIndex("sender") - .addField("decryptionResultJson", String::class.java) - .addField("decryptionErrorCode", String::class.java) - .addField("ageLocalTs", Long::class.java) - .setNullable("ageLocalTs", true) - .addField("sendStateStr", String::class.java) - - realm.schema.create("IncomingGossipingRequestEntity") - .addField("requestId", String::class.java) - .addIndex("requestId") - .addField("typeStr", String::class.java) - .addIndex("typeStr") - .addField("otherUserId", String::class.java) - .addField("requestedInfoStr", String::class.java) - .addField("otherDeviceId", String::class.java) - .addField("requestStateStr", String::class.java) - .addField("localCreationTimestamp", Long::class.java) - .setNullable("localCreationTimestamp", true) - - realm.schema.create("OutgoingGossipingRequestEntity") - .addField("requestId", String::class.java) - .addIndex("requestId") - .addField("recipientsData", String::class.java) - .addField("requestedInfoStr", String::class.java) - .addField("typeStr", String::class.java) - .addIndex("typeStr") - .addField("requestStateStr", String::class.java) - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo006.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo006.kt deleted file mode 100644 index 39b2898514..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo006.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import timber.log.Timber - -internal class MigrateCryptoTo006(realm: DynamicRealm) : RealmMigrator(realm, 6) { - - override fun doMigrate(realm: DynamicRealm) { - Timber.d("Updating CryptoMetadataEntity table") - realm.schema.get("CryptoMetadataEntity") - ?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY, String::class.java) - ?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY_VERSION, String::class.java) - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt deleted file mode 100644 index 0e221e78f3..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper -import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2 -import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm -import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper -import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm -import org.matrix.android.sdk.internal.di.MoshiProvider -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import timber.log.Timber - -internal class MigrateCryptoTo007(realm: DynamicRealm) : RealmMigrator(realm, 7) { - - override fun doMigrate(realm: DynamicRealm) { - Timber.d("Updating KeyInfoEntity table") - val crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi()) - - val keyInfoEntities = realm.where("KeyInfoEntity").findAll() - try { - keyInfoEntities.forEach { - val stringSignatures = it.getString(KeyInfoEntityFields.SIGNATURES) - val objectSignatures: Map>? = deserializeFromRealm(stringSignatures) - val jsonSignatures = crossSigningKeysMapper.serializeSignatures(objectSignatures) - it.setString(KeyInfoEntityFields.SIGNATURES, jsonSignatures) - } - } catch (ignore: Throwable) { - } - - // Migrate frozen classes - val inboundGroupSessions = realm.where("OlmInboundGroupSessionEntity").findAll() - inboundGroupSessions.forEach { dynamicObject -> - dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { serializedObject -> - try { - deserializeFromRealm(serializedObject)?.let { oldFormat -> - val newFormat = oldFormat.exportKeys()?.let { - OlmInboundGroupSessionWrapper2(it) - } - dynamicObject.setString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA, serializeForRealm(newFormat)) - } - } catch (failure: Throwable) { - Timber.e(failure, "## OlmInboundGroupSessionEntity migration failed") - } - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo008.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo008.kt deleted file mode 100644 index ad195e6e55..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo008.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.api.extensions.tryOrNull -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import org.matrix.android.sdk.internal.util.time.Clock - -internal class MigrateCryptoTo008( - realm: DynamicRealm, - private val clock: Clock, -) : RealmMigrator(realm, 8) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.create("MyDeviceLastSeenInfoEntity") - .addField(MyDeviceLastSeenInfoEntityFields.DEVICE_ID, String::class.java) - .addPrimaryKey(MyDeviceLastSeenInfoEntityFields.DEVICE_ID) - .addField(MyDeviceLastSeenInfoEntityFields.DISPLAY_NAME, String::class.java) - .addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_IP, String::class.java) - .addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_TS, Long::class.java) - .setNullable(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_TS, true) - - val now = clock.epochMillis() - realm.schema.get("DeviceInfoEntity") - ?.addField(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, Long::class.java) - ?.setNullable(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, true) - ?.transform { deviceInfoEntity -> - tryOrNull { - deviceInfoEntity.setLong(DeviceInfoEntityFields.FIRST_TIME_SEEN_LOCAL_TS, now) - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo009.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo009.kt deleted file mode 100644 index 8d9d24dfba..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo009.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import timber.log.Timber - -// Fixes duplicate devices in UserEntity#devices -internal class MigrateCryptoTo009(realm: DynamicRealm) : RealmMigrator(realm, 9) { - - override fun doMigrate(realm: DynamicRealm) { - val userEntities = realm.where("UserEntity").findAll() - userEntities.forEach { - try { - val deviceList = it.getList(UserEntityFields.DEVICES.`$`) - ?: return@forEach - val distinct = deviceList.distinctBy { it.getString(DeviceInfoEntityFields.DEVICE_ID) } - if (distinct.size != deviceList.size) { - deviceList.clear() - deviceList.addAll(distinct) - } - } catch (failure: Throwable) { - Timber.w(failure, "Crypto Data base migration error for migrateTo9") - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo010.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo010.kt deleted file mode 100644 index faf0d58832..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo010.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -// Version 10L added WithHeld Keys Info (MSC2399) -internal class MigrateCryptoTo010(realm: DynamicRealm) : RealmMigrator(realm, 10) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.create("WithHeldSessionEntity") - .addField(WithHeldSessionEntityFields.ROOM_ID, String::class.java) - .addField(WithHeldSessionEntityFields.ALGORITHM, String::class.java) - .addField(WithHeldSessionEntityFields.SESSION_ID, String::class.java) - .addIndex(WithHeldSessionEntityFields.SESSION_ID) - .addField(WithHeldSessionEntityFields.SENDER_KEY, String::class.java) - .addIndex(WithHeldSessionEntityFields.SENDER_KEY) - .addField(WithHeldSessionEntityFields.CODE_STRING, String::class.java) - .addField(WithHeldSessionEntityFields.REASON, String::class.java) - - realm.schema.create("SharedSessionEntity") - .addField(SharedSessionEntityFields.ROOM_ID, String::class.java) - .addField(SharedSessionEntityFields.ALGORITHM, String::class.java) - .addField(SharedSessionEntityFields.SESSION_ID, String::class.java) - .addIndex(SharedSessionEntityFields.SESSION_ID) - .addField(SharedSessionEntityFields.USER_ID, String::class.java) - .addIndex(SharedSessionEntityFields.USER_ID) - .addField(SharedSessionEntityFields.DEVICE_ID, String::class.java) - .addIndex(SharedSessionEntityFields.DEVICE_ID) - .addField(SharedSessionEntityFields.CHAIN_INDEX, Long::class.java) - .setNullable(SharedSessionEntityFields.CHAIN_INDEX, true) - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo011.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo011.kt deleted file mode 100644 index feaab4bb19..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo011.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -// Version 11L added deviceKeysSentToServer boolean to CryptoMetadataEntity -internal class MigrateCryptoTo011(realm: DynamicRealm) : RealmMigrator(realm, 11) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.get("CryptoMetadataEntity") - ?.addField(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER, Boolean::class.java) - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo012.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo012.kt deleted file mode 100644 index 4626757a06..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo012.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -// Version 12L added outbound group session persistence -internal class MigrateCryptoTo012(realm: DynamicRealm) : RealmMigrator(realm, 12) { - - override fun doMigrate(realm: DynamicRealm) { - 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/migration/MigrateCryptoTo013.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo013.kt deleted file mode 100644 index dc8984da41..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo013.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import timber.log.Timber - -// Version 13L delete unreferenced TrustLevelEntity -internal class MigrateCryptoTo013(realm: DynamicRealm) : RealmMigrator(realm, 13) { - - override fun doMigrate(realm: DynamicRealm) { - // Use a trick to do that... Ref: https://stackoverflow.com/questions/55221366 - val trustLevelEntitySchema = realm.schema.get("TrustLevelEntity") - - /* - Creating a new temp field called isLinked which is set to true for those which are - references by other objects. Rest of them are set to false. Then removing all - those which are false and hence duplicate and unnecessary. Then removing the temp field - isLinked - */ - var mainCounter = 0 - var deviceInfoCounter = 0 - var keyInfoCounter = 0 - val deleteCounter: Int - - trustLevelEntitySchema - ?.addField("isLinked", Boolean::class.java) - ?.transform { obj -> - // Setting to false for all by default - obj.set("isLinked", false) - mainCounter++ - } - - realm.schema.get("DeviceInfoEntity")?.transform { obj -> - // Setting to true for those which are referenced in DeviceInfoEntity - deviceInfoCounter++ - obj.getObject("trustLevelEntity")?.set("isLinked", true) - } - - realm.schema.get("KeyInfoEntity")?.transform { obj -> - // Setting to true for those which are referenced in KeyInfoEntity - keyInfoCounter++ - obj.getObject("trustLevelEntity")?.set("isLinked", true) - } - - // Removing all those which are set as false - realm.where("TrustLevelEntity") - .equalTo("isLinked", false) - .findAll() - .also { deleteCounter = it.size } - .deleteAllFromRealm() - - trustLevelEntitySchema?.removeField("isLinked") - - Timber.w("TrustLevelEntity cleanup: $mainCounter entities") - Timber.w("TrustLevelEntity cleanup: $deviceInfoCounter entities referenced in DeviceInfoEntities") - Timber.w("TrustLevelEntity cleanup: $keyInfoCounter entities referenced in KeyInfoEntity") - Timber.w("TrustLevelEntity cleanup: $deleteCounter entities deleted!") - if (mainCounter != deviceInfoCounter + keyInfoCounter + deleteCounter) { - Timber.e("TrustLevelEntity cleanup: Something is not correct...") - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo014.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo014.kt deleted file mode 100644 index 548672790a..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo014.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -// Version 14L Update the way we remember key sharing -internal class MigrateCryptoTo014(realm: DynamicRealm) : RealmMigrator(realm, 14) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.get("SharedSessionEntity") - ?.addField(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, String::class.java) - ?.addIndex(SharedSessionEntityFields.DEVICE_IDENTITY_KEY) - ?.transform { - val sharedUserId = it.getString(SharedSessionEntityFields.USER_ID) - val sharedDeviceId = it.getString(SharedSessionEntityFields.DEVICE_ID) - val knownDevice = realm.where("DeviceInfoEntity") - .equalTo(DeviceInfoEntityFields.USER_ID, sharedUserId) - .equalTo(DeviceInfoEntityFields.DEVICE_ID, sharedDeviceId) - .findFirst() - it.setString(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, knownDevice?.getString(DeviceInfoEntityFields.IDENTITY_KEY)) - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo015.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo015.kt deleted file mode 100644 index bca02c2e6e..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo015.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -// Version 15L adds wasEncryptedOnce field to CryptoRoomEntity -internal class MigrateCryptoTo015(realm: DynamicRealm) : RealmMigrator(realm, 15) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.get("CryptoRoomEntity") - ?.addField(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, Boolean::class.java) - ?.setNullable(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, true) - ?.transform { - val currentAlgorithm = it.getString(CryptoRoomEntityFields.ALGORITHM) - it.set(CryptoRoomEntityFields.WAS_ENCRYPTED_ONCE, currentAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM) - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo016.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo016.kt deleted file mode 100644 index 5a14ebf85a..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo016.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.KeyRequestReplyEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -internal class MigrateCryptoTo016(realm: DynamicRealm) : RealmMigrator(realm, 16) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.remove("OutgoingGossipingRequestEntity") - realm.schema.remove("IncomingGossipingRequestEntity") - realm.schema.remove("GossipingEventEntity") - - // No need to migrate existing request, just start fresh - - val replySchema = realm.schema.create("KeyRequestReplyEntity") - .addField(KeyRequestReplyEntityFields.SENDER_ID, String::class.java) - .addField(KeyRequestReplyEntityFields.FROM_DEVICE, String::class.java) - .addField(KeyRequestReplyEntityFields.EVENT_JSON, String::class.java) - - realm.schema.create("OutgoingKeyRequestEntity") - .addField(OutgoingKeyRequestEntityFields.REQUEST_ID, String::class.java) - .addIndex(OutgoingKeyRequestEntityFields.REQUEST_ID) - .addField(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, String::class.java) - .addIndex(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID) - .addRealmListField(OutgoingKeyRequestEntityFields.REPLIES.`$`, replySchema) - .addField(OutgoingKeyRequestEntityFields.RECIPIENTS_DATA, String::class.java) - .addField(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, String::class.java) - .addIndex(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR) - .addField(OutgoingKeyRequestEntityFields.REQUESTED_INFO_STR, String::class.java) - .addField(OutgoingKeyRequestEntityFields.ROOM_ID, String::class.java) - .addIndex(OutgoingKeyRequestEntityFields.ROOM_ID) - .addField(OutgoingKeyRequestEntityFields.REQUESTED_INDEX, Integer::class.java) - .addField(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, Long::class.java) - .setNullable(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, true) - - realm.schema.create("AuditTrailEntity") - .addField(AuditTrailEntityFields.AGE_LOCAL_TS, Long::class.java) - .setNullable(AuditTrailEntityFields.AGE_LOCAL_TS, true) - .addField(AuditTrailEntityFields.CONTENT_JSON, String::class.java) - .addField(AuditTrailEntityFields.TYPE, String::class.java) - .addIndex(AuditTrailEntityFields.TYPE) - - realm.schema.get("CryptoMetadataEntity") - ?.addField(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, Boolean::class.java) - ?.transform { - // set the default value to true - it.setBoolean(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, true) - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt deleted file mode 100644 index 8904c412cd..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.api.extensions.tryOrNull -import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData -import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm -import org.matrix.android.sdk.internal.di.MoshiProvider -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import timber.log.Timber - -/** - * Version 17L enhance OlmInboundGroupSessionEntity to support shared history for MSC3061. - * Also migrates how megolm session are stored to avoid additional serialized frozen class. - */ -internal class MigrateCryptoTo017(realm: DynamicRealm) : RealmMigrator(realm, 17) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.get("CryptoRoomEntity") - ?.addField(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform { - // We don't have access to the session database to check for the state here and set the good value. - // But for now as it's behind a lab flag, will set to false and force initial sync when enabled - it.setBoolean(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, false) - } - - realm.schema.get("OutboundGroupSessionInfoEntity") - ?.addField(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)?.transform { - // We don't have access to the session database to check for the state here and set the good value. - // But for now as it's behind a lab flag, will set to false and force initial sync when enabled - it.setBoolean(OutboundGroupSessionInfoEntityFields.SHOULD_SHARE_HISTORY, false) - } - - realm.schema.get("CryptoMetadataEntity") - ?.addField(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, Boolean::class.java) - ?.transform { obj -> - // default to false - obj.setBoolean(CryptoMetadataEntityFields.ENABLE_KEY_FORWARDING_ON_INVITE, false) - } - - val moshiAdapter = MoshiProvider.providesMoshi().adapter(InboundGroupSessionData::class.java) - - realm.schema.get("OlmInboundGroupSessionEntity") - ?.addField(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, Boolean::class.java) - ?.addField(OlmInboundGroupSessionEntityFields.ROOM_ID, String::class.java) - ?.addField(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, String::class.java) - ?.addField(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, String::class.java) - ?.transform { dynamicObject -> - try { - // we want to convert the old wrapper frozen class into a - // map of sessionData & the pickled session herself - dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { oldData -> - val oldWrapper = tryOrNull("Failed to convert megolm inbound group data") { - @Suppress("DEPRECATION") - deserializeFromRealm(oldData) - } - val groupSession = oldWrapper?.olmInboundGroupSession - ?: return@transform Unit.also { - Timber.w("Failed to migrate megolm session, no olmInboundGroupSession") - } - // now convert to new data - val data = InboundGroupSessionData( - senderKey = oldWrapper.senderKey, - roomId = oldWrapper.roomId, - keysClaimed = oldWrapper.keysClaimed, - forwardingCurve25519KeyChain = oldWrapper.forwardingCurve25519KeyChain, - sharedHistory = false, - ) - - dynamicObject.setString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, moshiAdapter.toJson(data)) - dynamicObject.setString(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION, serializeForRealm(groupSession)) - - // denormalized fields - dynamicObject.setString(OlmInboundGroupSessionEntityFields.ROOM_ID, oldWrapper.roomId) - dynamicObject.setBoolean(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, false) - } - } catch (failure: Throwable) { - Timber.e(failure, "Failed to migrate megolm session") - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo018.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo018.kt deleted file mode 100644 index 3bedf58ca2..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo018.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields -import org.matrix.android.sdk.internal.di.MoshiProvider -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import timber.log.Timber - -/** - * This migration is adding support for trusted flags on megolm sessions. - * We can't really assert the trust of existing keys, so for the sake of simplicity we are going to - * mark existing keys as safe. - * This migration can take long depending on the account - */ -internal class MigrateCryptoTo018(realm: DynamicRealm) : RealmMigrator(realm, 18) { - - private val moshiAdapter = MoshiProvider.providesMoshi().adapter(InboundGroupSessionData::class.java) - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.get("OlmInboundGroupSessionEntity") - ?.transform { dynamicObject -> - try { - dynamicObject.getString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON)?.let { oldData -> - moshiAdapter.fromJson(oldData)?.let { dataToMigrate -> - dataToMigrate.copy(trusted = true).let { - dynamicObject.setString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON, moshiAdapter.toJson(it)) - } - } - } - } catch (failure: Throwable) { - Timber.e(failure, "Failed to migrate megolm session") - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo019.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo019.kt deleted file mode 100644 index 65280300ab..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo019.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import io.realm.DynamicRealmObject -import org.matrix.android.sdk.api.session.crypto.crosssigning.KeyUsage -import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -/** - * This migration is adding support for trusted flags on megolm sessions. - * We can't really assert the trust of existing keys, so for the sake of simplicity we are going to - * mark existing keys as safe. - * This migration can take long depending on the account - */ -internal class MigrateCryptoTo019(realm: DynamicRealm) : RealmMigrator(realm, 19) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.get("CrossSigningInfoEntity") - ?.addField(CrossSigningInfoEntityFields.WAS_USER_VERIFIED_ONCE, Boolean::class.java) - ?.transform { dynamicObject -> - - val knowKeys = dynamicObject.getList(CrossSigningInfoEntityFields.CROSS_SIGNING_KEYS.`$`) - val msk = knowKeys.firstOrNull { - it.getList(KeyInfoEntityFields.USAGES.`$`, String::class.java).orEmpty().contains(KeyUsage.MASTER.value) - } - val ssk = knowKeys.firstOrNull { - it.getList(KeyInfoEntityFields.USAGES.`$`, String::class.java).orEmpty().contains(KeyUsage.SELF_SIGNING.value) - } - val isTrusted = isDynamicKeyInfoTrusted(msk?.get(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`)) && - isDynamicKeyInfoTrusted(ssk?.get(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`)) - - dynamicObject.setBoolean(CrossSigningInfoEntityFields.WAS_USER_VERIFIED_ONCE, isTrusted) - } - } - - private fun isDynamicKeyInfoTrusted(keyInfo: DynamicRealmObject?): Boolean { - if (keyInfo == null) return false - return !keyInfo.isNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED) && keyInfo.getBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED) && - !keyInfo.isNull(TrustLevelEntityFields.LOCALLY_VERIFIED) && keyInfo.getBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED) - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo020.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo020.kt deleted file mode 100644 index 44d07ab538..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo020.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -/** - * This migration adds a new field into MyDeviceLastSeenInfoEntity corresponding to the last seen user agent. - */ -internal class MigrateCryptoTo020(realm: DynamicRealm) : RealmMigrator(realm, 20) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.get("MyDeviceLastSeenInfoEntity") - ?.addField(MyDeviceLastSeenInfoEntityFields.LAST_SEEN_USER_AGENT, String::class.java) - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo021.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo021.kt deleted file mode 100644 index a90614e53f..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo021.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2023 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.api.crypto.MEGOLM_DEFAULT_ROTATION_MSGS -import org.matrix.android.sdk.api.crypto.MEGOLM_DEFAULT_ROTATION_PERIOD_MS -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -/** - * This migration stores the rotation parameters for megolm oubound sessions. - */ -internal class MigrateCryptoTo021(realm: DynamicRealm) : RealmMigrator(realm, 21) { - - override fun doMigrate(realm: DynamicRealm) { - realm.schema.get("CryptoRoomEntity") - ?.addField(CryptoRoomEntityFields.ROTATION_PERIOD_MS, Long::class.java) - ?.setNullable(CryptoRoomEntityFields.ROTATION_PERIOD_MS, true) - ?.addField(CryptoRoomEntityFields.ROTATION_PERIOD_MSGS, Long::class.java) - ?.setNullable(CryptoRoomEntityFields.ROTATION_PERIOD_MSGS, true) - ?.transform { - // As a migration we set the default (will be on par with existing code) - // A clear cache will have the correct values. - it.setLong(CryptoRoomEntityFields.ROTATION_PERIOD_MS, MEGOLM_DEFAULT_ROTATION_PERIOD_MS) - it.setLong(CryptoRoomEntityFields.ROTATION_PERIOD_MSGS, MEGOLM_DEFAULT_ROTATION_MSGS) - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo022.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo022.kt deleted file mode 100644 index 5d1119778d..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo022.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2023 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.RustEncryptionConfiguration -import org.matrix.android.sdk.internal.session.MigrateEAtoEROperation -import org.matrix.android.sdk.internal.util.database.RealmMigrator -import java.io.File - -/** - * This migration creates the rust database and migrates from legacy crypto. - */ -internal class MigrateCryptoTo022( - realm: DynamicRealm, - private val rustDirectory: File, - private val rustEncryptionConfiguration: RustEncryptionConfiguration, - private val migrateMegolmGroupSessions: Boolean = false -) : RealmMigrator( - realm, - 22 -) { - override fun doMigrate(realm: DynamicRealm) { - // Migrate to rust! - val migrateOperation = MigrateEAtoEROperation(migrateMegolmGroupSessions) - migrateOperation.dynamicExecute(realm, rustDirectory, rustEncryptionConfiguration.getDatabasePassphrase()) - - // wa can't delete all for now, but we can do some cleaning - realm.schema.get("OlmSessionEntity")?.transform { - it.deleteFromRealm() - } - - // a future migration will clean the rest - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo023.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo023.kt deleted file mode 100644 index 1302b452bd..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo023.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2024 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.migration - -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator - -// Some fields are now required due to upgrade of Kotlin version. -// See https://github.com/realm/realm-java/issues/7810 for more details. -internal class MigrateCryptoTo023(realm: DynamicRealm) : RealmMigrator(realm, 23) { - override fun doMigrate(realm: DynamicRealm) { - realm.schema.get("OutgoingKeyRequestEntity") - ?.setRequired(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, true) - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo024.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo024.kt new file mode 100644 index 0000000000..9a87eb4741 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo024.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 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.migration + +import io.realm.DynamicRealm +import org.matrix.android.sdk.internal.util.database.RealmMigrator + +internal class MigrateCryptoTo024(realm: DynamicRealm) : RealmMigrator(realm, 24) { + /** + * Delete the whole DB, except tables that are still used to store data. + * Keep: + * - CryptoMetadataEntity + * - MyDeviceLastSeenInfoEntity + * - CryptoRoomEntity (but remove unused member 'outboundSessionInfo: OutboundGroupSessionInfoEntity') + */ + override fun doMigrate(realm: DynamicRealm) { + with(realm.schema) { + get("CryptoRoomEntity")?.removeField("outboundSessionInfo") + + // Warning: order is important, first remove classes that depends on others. + remove("UserEntity") + remove("DeviceInfoEntity") + remove("CrossSigningInfoEntity") + remove("KeyInfoEntity") + remove("TrustLevelEntity") + remove("KeysBackupDataEntity") + remove("OlmInboundGroupSessionEntity") + remove("OlmSessionEntity") + remove("AuditTrailEntity") + remove("OutgoingKeyRequestEntity") + remove("KeyRequestReplyEntity") + remove("WithHeldSessionEntity") + remove("SharedSessionEntity") + remove("OutboundGroupSessionInfoEntity") + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/rust/ExtractMigrationDataFailure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/rust/ExtractMigrationDataFailure.kt deleted file mode 100644 index fb4bd1c8fe..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/rust/ExtractMigrationDataFailure.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 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.migration.rust - -data class ExtractMigrationDataFailure(override val cause: Throwable) : - java.lang.RuntimeException("Can't proceed with migration, crypto store is empty or some necessary data is missing.", cause) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/rust/ExtractMigrationDataUseCase.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/rust/ExtractMigrationDataUseCase.kt deleted file mode 100644 index 3dae9a6b13..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/rust/ExtractMigrationDataUseCase.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2022 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.migration.rust - -import io.realm.Realm -import io.realm.RealmConfiguration -import io.realm.kotlin.where -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity -import org.matrix.olm.OlmUtility -import org.matrix.rustcomponents.sdk.crypto.MigrationData -import timber.log.Timber -import kotlin.system.measureTimeMillis - -internal class ExtractMigrationDataUseCase(private val migrateGroupSessions: Boolean = false) { - - fun extractData(realm: RealmToMigrate, importPartial: ((MigrationData) -> Unit)) { - return try { - extract(realm, importPartial) - } catch (failure: Throwable) { - throw ExtractMigrationDataFailure(failure) - } - } - - fun hasExistingData(realmConfiguration: RealmConfiguration): Boolean { - return Realm.getInstance(realmConfiguration).use { realm -> - !realm.isEmpty && - // Check if there is a MetaData object - realm.where().count() > 0 && - realm.where().findFirst()?.olmAccountData != null - } - } - - private fun extract(realm: RealmToMigrate, importPartial: ((MigrationData) -> Unit)) { - val pickleKey = OlmUtility.getRandomKey() - - val baseExtract = realm.getPickledAccount(pickleKey) - // import the account asap - importPartial(baseExtract) - - val chunkSize = 500 - realm.trackedUsersChunk(500) { - importPartial( - baseExtract.copy(trackedUsers = it) - ) - } - - var migratedOlmSessionCount = 0 - var writeTime = 0L - measureTimeMillis { - realm.pickledOlmSessions(pickleKey, chunkSize) { pickledSessions -> - migratedOlmSessionCount += pickledSessions.size - measureTimeMillis { - importPartial( - baseExtract.copy(sessions = pickledSessions) - ) - }.also { writeTime += it } - } - }.also { - Timber.i("Migration: took $it ms to migrate $migratedOlmSessionCount olm sessions") - Timber.i("Migration: rust import time $writeTime") - } - - // We don't migrate outbound session by default directly after migration - // We are going to do it lazyly when decryption fails - if (migrateGroupSessions) { - var migratedInboundGroupSessionCount = 0 - measureTimeMillis { - realm.pickledOlmGroupSessions(pickleKey, chunkSize) { pickledSessions -> - migratedInboundGroupSessionCount += pickledSessions.size - measureTimeMillis { - importPartial( - baseExtract.copy(inboundGroupSessions = pickledSessions) - ) - }.also { writeTime += it } - } - }.also { - Timber.i("Migration: took $it ms to migrate $migratedInboundGroupSessionCount group sessions") - Timber.i("Migration: rust import time $writeTime") - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/rust/RealmToMigrate.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/rust/RealmToMigrate.kt deleted file mode 100644 index 7f9e7e212a..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/rust/RealmToMigrate.kt +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (c) 2023 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.migration.rust - -import io.realm.kotlin.where -import okhttp3.internal.toImmutableList -import org.matrix.android.sdk.api.extensions.orFalse -import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData -import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity -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.UserEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields -import org.matrix.android.sdk.internal.di.MoshiProvider -import org.matrix.olm.OlmAccount -import org.matrix.olm.OlmInboundGroupSession -import org.matrix.olm.OlmSession -import org.matrix.rustcomponents.sdk.crypto.CrossSigningKeyExport -import org.matrix.rustcomponents.sdk.crypto.MigrationData -import org.matrix.rustcomponents.sdk.crypto.PickledAccount -import org.matrix.rustcomponents.sdk.crypto.PickledInboundGroupSession -import org.matrix.rustcomponents.sdk.crypto.PickledSession -import timber.log.Timber -import java.nio.charset.Charset - -sealed class RealmToMigrate { - data class DynamicRealm(val realm: io.realm.DynamicRealm) : RealmToMigrate() - data class ClassicRealm(val realm: io.realm.Realm) : RealmToMigrate() -} - -fun RealmToMigrate.hasExistingData(): Boolean { - return when (this) { - is RealmToMigrate.ClassicRealm -> { - !this.realm.isEmpty && - // Check if there is a MetaData object - this.realm.where().count() > 0 && - this.realm.where().findFirst()?.olmAccountData != null - } - is RealmToMigrate.DynamicRealm -> { - return true - } - } -} - -@Throws -fun RealmToMigrate.getPickledAccount(pickleKey: ByteArray): MigrationData { - return when (this) { - is RealmToMigrate.ClassicRealm -> { - val metadataEntity = realm.where().findFirst() - ?: throw java.lang.IllegalArgumentException("Rust db migration: No existing metadataEntity") - - val masterKey = metadataEntity.xSignMasterPrivateKey - val userKey = metadataEntity.xSignUserPrivateKey - val selfSignedKey = metadataEntity.xSignSelfSignedPrivateKey - - Timber.i("## Migration: has private MSK ${masterKey.isNullOrBlank().not()}") - Timber.i("## Migration: has private USK ${userKey.isNullOrBlank().not()}") - Timber.i("## Migration: has private SSK ${selfSignedKey.isNullOrBlank().not()}") - - val userId = metadataEntity.userId - ?: throw java.lang.IllegalArgumentException("Rust db migration: userId is null") - val deviceId = metadataEntity.deviceId - ?: throw java.lang.IllegalArgumentException("Rust db migration: deviceID is null") - - val backupVersion = metadataEntity.backupVersion - val backupRecoveryKey = metadataEntity.keyBackupRecoveryKey - - Timber.i("## Migration: has private backup key ${backupRecoveryKey != null} for version $backupVersion") - - val isOlmAccountShared = metadataEntity.deviceKeysSentToServer - - val olmAccount = metadataEntity.getOlmAccount() - ?: throw java.lang.IllegalArgumentException("Rust db migration: No existing account") - val pickledOlmAccount = olmAccount.pickle(pickleKey, StringBuffer()).asString() - - val pickledAccount = PickledAccount( - userId = userId, - deviceId = deviceId, - pickle = pickledOlmAccount, - shared = isOlmAccountShared, - uploadedSignedKeyCount = 50 - ) - MigrationData( - account = pickledAccount, - pickleKey = pickleKey, - crossSigning = CrossSigningKeyExport( - masterKey = masterKey, - selfSigningKey = selfSignedKey, - userSigningKey = userKey - ), - sessions = emptyList(), - backupRecoveryKey = backupRecoveryKey, - trackedUsers = emptyList(), - inboundGroupSessions = emptyList(), - backupVersion = backupVersion, - // TODO import room settings from legacy DB - roomSettings = emptyMap() - ) - } - is RealmToMigrate.DynamicRealm -> { - val cryptoMetadataEntitySchema = realm.schema.get("CryptoMetadataEntity") - ?: throw java.lang.IllegalStateException("Missing Metadata entity") - - var migrationData: MigrationData? = null - cryptoMetadataEntitySchema.transform { dynMetaData -> - - val serializedOlmAccount = dynMetaData.getString(CryptoMetadataEntityFields.OLM_ACCOUNT_DATA) - - val masterKey = dynMetaData.getString(CryptoMetadataEntityFields.X_SIGN_MASTER_PRIVATE_KEY) - val userKey = dynMetaData.getString(CryptoMetadataEntityFields.X_SIGN_USER_PRIVATE_KEY) - val selfSignedKey = dynMetaData.getString(CryptoMetadataEntityFields.X_SIGN_SELF_SIGNED_PRIVATE_KEY) - - val userId = dynMetaData.getString(CryptoMetadataEntityFields.USER_ID) - ?: throw java.lang.IllegalArgumentException("Rust db migration: userId is null") - val deviceId = dynMetaData.getString(CryptoMetadataEntityFields.DEVICE_ID) - ?: throw java.lang.IllegalArgumentException("Rust db migration: deviceID is null") - - val backupVersion = dynMetaData.getString(CryptoMetadataEntityFields.BACKUP_VERSION) - val backupRecoveryKey = dynMetaData.getString(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY) - - val isOlmAccountShared = dynMetaData.getBoolean(CryptoMetadataEntityFields.DEVICE_KEYS_SENT_TO_SERVER) - - val olmAccount = deserializeFromRealm(serializedOlmAccount) - ?: throw java.lang.IllegalArgumentException("Rust db migration: No existing account") - - val pickledOlmAccount = olmAccount.pickle(pickleKey, StringBuffer()).asString() - - val pickledAccount = PickledAccount( - userId = userId, - deviceId = deviceId, - pickle = pickledOlmAccount, - shared = isOlmAccountShared, - uploadedSignedKeyCount = 50 - ) - - migrationData = MigrationData( - account = pickledAccount, - pickleKey = pickleKey, - crossSigning = CrossSigningKeyExport( - masterKey = masterKey, - selfSigningKey = selfSignedKey, - userSigningKey = userKey - ), - sessions = emptyList(), - backupRecoveryKey = backupRecoveryKey, - trackedUsers = emptyList(), - inboundGroupSessions = emptyList(), - backupVersion = backupVersion, - // TODO import room settings from legacy DB - roomSettings = emptyMap() - ) - } - migrationData!! - } - } -} - -fun RealmToMigrate.trackedUsersChunk(chunkSize: Int, onChunk: ((List) -> Unit)) { - when (this) { - is RealmToMigrate.ClassicRealm -> { - realm.where() - .findAll() - .chunked(chunkSize) - .onEach { - onChunk(it.mapNotNull { it.userId }) - } - } - is RealmToMigrate.DynamicRealm -> { - val userList = mutableListOf() - realm.schema.get("UserEntity")?.transform { - val userId = it.getString(UserEntityFields.USER_ID) - // should we check the tracking status? - userList.add(userId) - if (userList.size > chunkSize) { - onChunk(userList.toImmutableList()) - userList.clear() - } - } - if (userList.isNotEmpty()) { - onChunk(userList) - } - } - } -} - -fun RealmToMigrate.pickledOlmSessions(pickleKey: ByteArray, chunkSize: Int, onChunk: ((List) -> Unit)) { - when (this) { - is RealmToMigrate.ClassicRealm -> { - realm.where().findAll() - .chunked(chunkSize) { chunk -> - val export = chunk.map { it.toPickledSession(pickleKey) } - onChunk(export) - } - } - is RealmToMigrate.DynamicRealm -> { - val pickledSessions = mutableListOf() - realm.schema.get("OlmSessionEntity")?.transform { - val sessionData = it.getString(OlmSessionEntityFields.OLM_SESSION_DATA) - val deviceKey = it.getString(OlmSessionEntityFields.DEVICE_KEY) - val lastReceivedMessageTs = it.getLong(OlmSessionEntityFields.LAST_RECEIVED_MESSAGE_TS) - val olmSession = deserializeFromRealm(sessionData)!! - val pickle = olmSession.pickle(pickleKey, StringBuffer()).asString() - val pickledSession = PickledSession( - pickle = pickle, - senderKey = deviceKey, - createdUsingFallbackKey = false, - // / Unix timestamp (in seconds) when the session was created. - creationTime = (lastReceivedMessageTs / 1000).toULong(), - // / Unix timestamp (in seconds) when the session was last used. - lastUseTime = (lastReceivedMessageTs / 1000).toULong(), - ) - // should we check the tracking status? - pickledSessions.add(pickledSession) - if (pickledSessions.size > chunkSize) { - onChunk(pickledSessions.toImmutableList()) - pickledSessions.clear() - } - } - if (pickledSessions.isNotEmpty()) { - onChunk(pickledSessions) - } - } - } -} - -private val sessionDataAdapter = MoshiProvider.providesMoshi() - .adapter(InboundGroupSessionData::class.java) -fun RealmToMigrate.pickledOlmGroupSessions(pickleKey: ByteArray, chunkSize: Int, onChunk: ((List) -> Unit)) { - when (this) { - is RealmToMigrate.ClassicRealm -> { - realm.where() - .findAll() - .chunked(chunkSize) { chunk -> - val export = chunk.mapNotNull { it.toPickledInboundGroupSession(pickleKey) } - onChunk(export) - } - } - is RealmToMigrate.DynamicRealm -> { - val pickledSessions = mutableListOf() - realm.schema.get("OlmInboundGroupSessionEntity")?.transform { - val senderKey = it.getString(OlmInboundGroupSessionEntityFields.SENDER_KEY) - val roomId = it.getString(OlmInboundGroupSessionEntityFields.ROOM_ID) - val backedUp = it.getBoolean(OlmInboundGroupSessionEntityFields.BACKED_UP) - val serializedOlmInboundGroupSession = it.getString(OlmInboundGroupSessionEntityFields.SERIALIZED_OLM_INBOUND_GROUP_SESSION) - val inboundSession = deserializeFromRealm(serializedOlmInboundGroupSession) ?: return@transform Unit.also { - Timber.w("Rust db migration: Failed to migrated group session, no meta data") - } - val sessionData = it.getString(OlmInboundGroupSessionEntityFields.INBOUND_GROUP_SESSION_DATA_JSON).let { json -> - sessionDataAdapter.fromJson(json) - } ?: return@transform Unit.also { - Timber.w("Rust db migration: Failed to migrated group session, no meta data") - } - val pickle = inboundSession.pickle(pickleKey, StringBuffer()).asString() - val pickledSession = PickledInboundGroupSession( - pickle = pickle, - senderKey = senderKey, - signingKey = sessionData.keysClaimed.orEmpty(), - roomId = roomId, - forwardingChains = sessionData.forwardingCurve25519KeyChain.orEmpty(), - imported = sessionData.trusted.orFalse().not(), - backedUp = backedUp - ) - // should we check the tracking status? - pickledSessions.add(pickledSession) - if (pickledSessions.size > chunkSize) { - onChunk(pickledSessions.toImmutableList()) - pickledSessions.clear() - } - } - if (pickledSessions.isNotEmpty()) { - onChunk(pickledSessions) - } - } - } -} - -private fun OlmInboundGroupSessionEntity.toPickledInboundGroupSession(pickleKey: ByteArray): PickledInboundGroupSession? { - val senderKey = this.senderKey ?: return null - val backedUp = this.backedUp - val olmInboundGroupSession = this.getOlmGroupSession() ?: return null.also { - Timber.w("Rust db migration: Failed to migrated group session $sessionId") - } - val data = this.getData() ?: return null.also { - Timber.w("Rust db migration: Failed to migrated group session $sessionId, no meta data") - } - val roomId = data.roomId ?: return null.also { - Timber.w("Rust db migration: Failed to migrated group session $sessionId, no roomId") - } - val pickledInboundGroupSession = olmInboundGroupSession.pickle(pickleKey, StringBuffer()).asString() - return PickledInboundGroupSession( - pickle = pickledInboundGroupSession, - senderKey = senderKey, - signingKey = data.keysClaimed.orEmpty(), - roomId = roomId, - forwardingChains = data.forwardingCurve25519KeyChain.orEmpty(), - imported = data.trusted.orFalse().not(), - backedUp = backedUp - ) -} -private fun OlmSessionEntity.toPickledSession(pickleKey: ByteArray): PickledSession { - val deviceKey = this.deviceKey ?: "" - val lastReceivedMessageTs = this.lastReceivedMessageTs - val olmSessionStr = this.olmSessionData - val olmSession = deserializeFromRealm(olmSessionStr)!! - val pickledOlmSession = olmSession.pickle(pickleKey, StringBuffer()).asString() - return PickledSession( - pickle = pickledOlmSession, - senderKey = deviceKey, - createdUsingFallbackKey = false, - // Rust expect in seconds - creationTime = (lastReceivedMessageTs / 1000).toULong(), - // Rust expect in seconds - lastUseTime = (lastReceivedMessageTs / 1000).toULong(), - ) -} - -private val charset = Charset.forName("UTF-8") -private fun ByteArray.asString() = String(this, charset) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailEntity.kt deleted file mode 100644 index 2e0e9c8c8b..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailEntity.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 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 io.realm.annotations.Index - -internal open class AuditTrailEntity( - var ageLocalTs: Long? = null, - @Index var type: String? = null, - var contentJson: String? = null -) : RealmObject() { - companion object -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt deleted file mode 100644 index fe8e9f1db7..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2022 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 org.matrix.android.sdk.api.extensions.tryOrNull -import org.matrix.android.sdk.api.session.crypto.model.AuditTrail -import org.matrix.android.sdk.api.session.crypto.model.ForwardInfo -import org.matrix.android.sdk.api.session.crypto.model.IncomingKeyRequestInfo -import org.matrix.android.sdk.api.session.crypto.model.TrailType -import org.matrix.android.sdk.api.session.crypto.model.UnknownInfo -import org.matrix.android.sdk.api.session.crypto.model.WithheldInfo -import org.matrix.android.sdk.internal.di.MoshiProvider - -internal object AuditTrailMapper { - - fun map(entity: AuditTrailEntity): AuditTrail? { - val contentJson = entity.contentJson ?: return null - return when (entity.type) { - TrailType.OutgoingKeyForward.name -> { - val info = tryOrNull { - MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson) - } ?: return null - AuditTrail( - ageLocalTs = entity.ageLocalTs ?: 0, - type = TrailType.OutgoingKeyForward, - info = info - ) - } - TrailType.OutgoingKeyWithheld.name -> { - val info = tryOrNull { - MoshiProvider.providesMoshi().adapter(WithheldInfo::class.java).fromJson(contentJson) - } ?: return null - AuditTrail( - ageLocalTs = entity.ageLocalTs ?: 0, - type = TrailType.OutgoingKeyWithheld, - info = info - ) - } - TrailType.IncomingKeyRequest.name -> { - val info = tryOrNull { - MoshiProvider.providesMoshi().adapter(IncomingKeyRequestInfo::class.java).fromJson(contentJson) - } ?: return null - AuditTrail( - ageLocalTs = entity.ageLocalTs ?: 0, - type = TrailType.IncomingKeyRequest, - info = info - ) - } - TrailType.IncomingKeyForward.name -> { - val info = tryOrNull { - MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson) - } ?: return null - AuditTrail( - ageLocalTs = entity.ageLocalTs ?: 0, - type = TrailType.IncomingKeyForward, - info = info - ) - } - else -> { - AuditTrail( - ageLocalTs = entity.ageLocalTs ?: 0, - type = TrailType.Unknown, - info = UnknownInfo - ) - } - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CrossSigningInfoEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CrossSigningInfoEntity.kt deleted file mode 100644 index 033b7662c5..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CrossSigningInfoEntity.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.RealmList -import io.realm.RealmObject -import io.realm.annotations.PrimaryKey -import org.matrix.android.sdk.api.session.crypto.crosssigning.KeyUsage -import org.matrix.android.sdk.internal.extensions.clearWith - -internal open class CrossSigningInfoEntity( - @PrimaryKey - var userId: String? = null, - var wasUserVerifiedOnce: Boolean = false, - var crossSigningKeys: RealmList = RealmList() -) : RealmObject() { - - companion object - - fun getMasterKey() = crossSigningKeys.firstOrNull { it.usages.contains(KeyUsage.MASTER.value) } - - fun setMasterKey(info: KeyInfoEntity?) { - crossSigningKeys - .filter { it.usages.contains(KeyUsage.MASTER.value) } - .forEach { crossSigningKeys.remove(it) } - info?.let { crossSigningKeys.add(it) } - } - - fun getSelfSignedKey() = crossSigningKeys.firstOrNull { it.usages.contains(KeyUsage.SELF_SIGNING.value) } - - fun setSelfSignedKey(info: KeyInfoEntity?) { - crossSigningKeys - .filter { it.usages.contains(KeyUsage.SELF_SIGNING.value) } - .forEach { crossSigningKeys.remove(it) } - info?.let { crossSigningKeys.add(it) } - } - - fun getUserSigningKey() = crossSigningKeys.firstOrNull { it.usages.contains(KeyUsage.USER_SIGNING.value) } - - fun setUserSignedKey(info: KeyInfoEntity?) { - crossSigningKeys - .filter { it.usages.contains(KeyUsage.USER_SIGNING.value) } - .forEach { crossSigningKeys.remove(it) } - info?.let { crossSigningKeys.add(it) } - } -} - -internal fun CrossSigningInfoEntity.deleteOnCascade() { - crossSigningKeys.clearWith { it.deleteOnCascade() } - deleteFromRealm() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMapper.kt deleted file mode 100644 index ca41930f80..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMapper.kt +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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 com.squareup.moshi.Moshi -import com.squareup.moshi.Types -import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel -import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo -import org.matrix.android.sdk.api.session.crypto.model.UnsignedDeviceInfo -import org.matrix.android.sdk.api.util.JsonDict -import org.matrix.android.sdk.internal.di.SerializeNulls -import timber.log.Timber - -internal object CryptoMapper { - - private val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build() - private val listMigrationAdapter = moshi.adapter>( - Types.newParameterizedType( - List::class.java, - String::class.java, - Any::class.java - ) - ) - private val mapMigrationAdapter = moshi.adapter( - Types.newParameterizedType( - Map::class.java, - String::class.java, - Any::class.java - ) - ) - private val mapOfStringMigrationAdapter = moshi.adapter>>( - Types.newParameterizedType( - Map::class.java, - String::class.java, - Any::class.java - ) - ) - - internal fun mapToEntity(deviceInfo: CryptoDeviceInfo): DeviceInfoEntity { - return DeviceInfoEntity(primaryKey = DeviceInfoEntity.createPrimaryKey(deviceInfo.userId, deviceInfo.deviceId)) - .also { updateDeviceInfoEntity(it, deviceInfo) } - } - - internal fun updateDeviceInfoEntity(entity: DeviceInfoEntity, deviceInfo: CryptoDeviceInfo) { - entity.userId = deviceInfo.userId - entity.deviceId = deviceInfo.deviceId - entity.algorithmListJson = listMigrationAdapter.toJson(deviceInfo.algorithms) - entity.keysMapJson = mapMigrationAdapter.toJson(deviceInfo.keys) - entity.signatureMapJson = mapMigrationAdapter.toJson(deviceInfo.signatures) - entity.isBlocked = deviceInfo.isBlocked - val deviceInfoTrustLevel = deviceInfo.trustLevel - if (deviceInfoTrustLevel == null) { - entity.trustLevelEntity?.deleteFromRealm() - entity.trustLevelEntity = null - } else { - if (entity.trustLevelEntity == null) { - // Create a new TrustLevelEntity object - entity.trustLevelEntity = TrustLevelEntity() - } - // Update the existing TrustLevelEntity object - entity.trustLevelEntity?.crossSignedVerified = deviceInfoTrustLevel.crossSigningVerified - entity.trustLevelEntity?.locallyVerified = deviceInfoTrustLevel.locallyVerified - } - // We store the device name if present now - entity.unsignedMapJson = deviceInfo.unsigned?.deviceDisplayName - } - - internal fun mapToModel(deviceInfoEntity: DeviceInfoEntity): CryptoDeviceInfo { - return CryptoDeviceInfo( - userId = deviceInfoEntity.userId ?: "", - deviceId = deviceInfoEntity.deviceId ?: "", - isBlocked = deviceInfoEntity.isBlocked ?: false, - trustLevel = deviceInfoEntity.trustLevelEntity?.let { - DeviceTrustLevel(it.crossSignedVerified ?: false, it.locallyVerified) - }, - unsigned = deviceInfoEntity.unsignedMapJson?.let { UnsignedDeviceInfo(deviceDisplayName = it) }, - signatures = deviceInfoEntity.signatureMapJson?.let { - try { - mapOfStringMigrationAdapter.fromJson(it) - } catch (failure: Throwable) { - Timber.e(failure) - null - } - }, - keys = deviceInfoEntity.keysMapJson?.let { - try { - moshi.adapter>( - Types.newParameterizedType( - Map::class.java, - String::class.java, - Any::class.java - ) - ).fromJson(it) - } catch (failure: Throwable) { - Timber.e(failure) - null - } - }, - algorithms = deviceInfoEntity.algorithmListJson?.let { - try { - listMigrationAdapter.fromJson(it) - } catch (failure: Throwable) { - Timber.e(failure) - null - } - }, - firstTimeSeenLocalTs = deviceInfoEntity.firstTimeSeenLocalTs - ) - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt index 88708f824e..73992485a6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt @@ -18,9 +18,6 @@ package org.matrix.android.sdk.internal.crypto.store.db.model import io.realm.RealmObject import io.realm.annotations.PrimaryKey -import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm -import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm -import org.matrix.olm.OlmAccount internal open class CryptoMetadataEntity( // The current user id. @@ -53,15 +50,4 @@ internal open class CryptoMetadataEntity( var keyBackupRecoveryKeyVersion: String? = null // var crossSigningInfoEntity: CrossSigningInfoEntity? = null -) : RealmObject() { - - // Deserialize data - fun getOlmAccount(): OlmAccount? { - return deserializeFromRealm(olmAccountData) - } - - // Serialize data - fun putOlmAccount(olmAccount: OlmAccount?) { - olmAccountData = serializeForRealm(olmAccount) - } -} +) : RealmObject() 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 dce47860c7..613bcee2f3 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 @@ -26,10 +26,6 @@ internal open class CryptoRoomEntity( var blacklistUnverifiedDevices: Boolean = false, // Determines whether or not room history should be shared on new member invites var shouldShareHistory: 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, // a security to ensure that a room will never revert to not encrypted // even if a new state event with empty encryption, or state is reset somehow var wasEncryptedOnce: Boolean? = false, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/DeviceInfoEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/DeviceInfoEntity.kt deleted file mode 100644 index 61870ec486..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/DeviceInfoEntity.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 io.realm.RealmResults -import io.realm.annotations.LinkingObjects -import io.realm.annotations.PrimaryKey - -internal fun DeviceInfoEntity.Companion.createPrimaryKey(userId: String, deviceId: String) = "$userId|$deviceId" - -internal open class DeviceInfoEntity( - @PrimaryKey var primaryKey: String = "", - var deviceId: String? = null, - var identityKey: String? = null, - var userId: String? = null, - var isBlocked: Boolean? = null, - var algorithmListJson: String? = null, - var keysMapJson: String? = null, - var signatureMapJson: String? = null, - // Will contain the device name from unsigned data if present - var unsignedMapJson: String? = null, - var trustLevelEntity: TrustLevelEntity? = null, - /** - * We use that to make distinction between old devices (there before mine) - * and new ones. Used for example to detect new unverified login - */ - var firstTimeSeenLocalTs: Long? = null -) : RealmObject() { - - @LinkingObjects("devices") - val users: RealmResults? = null - - companion object -} - -internal fun DeviceInfoEntity.deleteOnCascade() { - trustLevelEntity?.deleteFromRealm() - deleteFromRealm() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyInfoEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyInfoEntity.kt deleted file mode 100644 index 9133413589..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyInfoEntity.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.RealmList -import io.realm.RealmObject - -internal open class KeyInfoEntity( - var publicKeyBase64: String? = null, -// var isTrusted: Boolean = false, - var usages: RealmList = RealmList(), - /** - * The signature of this MXDeviceInfo. - * A map from "" to a map from ":" to "" - */ - var signatures: String? = null, - var trustLevelEntity: TrustLevelEntity? = null -) : RealmObject() - -internal fun KeyInfoEntity.deleteOnCascade() { - trustLevelEntity?.deleteFromRealm() - deleteFromRealm() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyRequestReplyEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyRequestReplyEntity.kt deleted file mode 100644 index 0c7cf79e78..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyRequestReplyEntity.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2022 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.api.session.events.model.Event -import org.matrix.android.sdk.internal.di.MoshiProvider - -internal open class KeyRequestReplyEntity( - var senderId: String? = null, - var fromDevice: String? = null, - var eventJson: String? = null -) : RealmObject() { - companion object - - fun getEvent(): Event? { - return eventJson?.let { - MoshiProvider.providesMoshi().adapter(Event::class.java).fromJson(it) - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeysBackupDataEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeysBackupDataEntity.kt deleted file mode 100644 index 99b9e0ccdf..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeysBackupDataEntity.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 io.realm.annotations.PrimaryKey - -internal open class KeysBackupDataEntity( - // Primary key to update this object. There is only one object, so it's a constant, please do not set it - @PrimaryKey - var primaryKey: Int = 0, - // The last known hash of the backed up keys on the server - var backupLastServerHash: String? = null, - // The last known number of backed up keys on the server - var backupLastServerNumberOfKeys: Int? = null -) : RealmObject() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt deleted file mode 100644 index 62ab73e379..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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 io.realm.annotations.PrimaryKey -import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData -import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper -import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm -import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm -import org.matrix.android.sdk.internal.di.MoshiProvider -import org.matrix.olm.OlmInboundGroupSession -import timber.log.Timber - -internal fun OlmInboundGroupSessionEntity.Companion.createPrimaryKey(sessionId: String?, senderKey: String?) = "$sessionId|$senderKey" - -internal open class OlmInboundGroupSessionEntity( - // Combined value to build a primary key - @PrimaryKey var primaryKey: String? = null, - - // denormalization for faster querying (these fields are in the inboundGroupSessionDataJson) - var sessionId: String? = null, - var senderKey: String? = null, - var roomId: String? = null, - - // Deprecated, used for migration / olmInboundGroupSessionData contains Json - // keep it in case of problem to have a chance to recover - var olmInboundGroupSessionData: String? = null, - - // Stores the session data in an extensible format - // to allow to store data not yet supported for later use - var inboundGroupSessionDataJson: String? = null, - - // The pickled session - var serializedOlmInboundGroupSession: String? = null, - - // Flag that indicates whether or not the current inboundSession will be shared to - // invited users to decrypt past messages - var sharedHistory: Boolean = false, - // Indicate if the key has been backed up to the homeserver - var backedUp: Boolean = false -) : - RealmObject() { - - fun store(wrapper: MXInboundMegolmSessionWrapper) { - this.serializedOlmInboundGroupSession = serializeForRealm(wrapper.session) - this.inboundGroupSessionDataJson = adapter.toJson(wrapper.sessionData) - this.roomId = wrapper.sessionData.roomId - this.senderKey = wrapper.sessionData.senderKey - this.sessionId = wrapper.session.sessionIdentifier() - this.sharedHistory = wrapper.sessionData.sharedHistory - } -// fun getInboundGroupSession(): OlmInboundGroupSessionWrapper2? { -// return try { -// deserializeFromRealm(olmInboundGroupSessionData) -// } catch (failure: Throwable) { -// Timber.e(failure, "## Deserialization failure") -// return null -// } -// } -// -// fun putInboundGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2?) { -// olmInboundGroupSessionData = serializeForRealm(olmInboundGroupSessionWrapper) -// } - - fun getOlmGroupSession(): OlmInboundGroupSession? { - return try { - deserializeFromRealm(serializedOlmInboundGroupSession) - } catch (failure: Throwable) { - Timber.e(failure, "## Deserialization failure") - return null - } - } - - fun getData(): InboundGroupSessionData? { - return try { - inboundGroupSessionDataJson?.let { - adapter.fromJson(it) - } - } catch (failure: Throwable) { - Timber.e(failure, "## Deserialization failure") - return null - } - } - - fun toModel(): MXInboundMegolmSessionWrapper? { - val data = getData() ?: return null - val session = getOlmGroupSession() ?: return null - return MXInboundMegolmSessionWrapper( - session = session, - sessionData = data - ) - } - - companion object { - private val adapter = MoshiProvider.providesMoshi() - .adapter(InboundGroupSessionData::class.java) - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt deleted file mode 100644 index 9f010db288..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 io.realm.annotations.PrimaryKey -import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm -import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm -import org.matrix.olm.OlmSession - -internal fun OlmSessionEntity.Companion.createPrimaryKey(sessionId: String, deviceKey: String) = "$sessionId|$deviceKey" - -// olmSessionData is a serialized OlmSession -internal open class OlmSessionEntity( - @PrimaryKey var primaryKey: String = "", - var sessionId: String? = null, - var deviceKey: String? = null, - var olmSessionData: String? = null, - var lastReceivedMessageTs: Long = 0 -) : - RealmObject() { - - fun getOlmSession(): OlmSession? { - return deserializeFromRealm(olmSessionData) - } - - fun putOlmSession(olmSession: OlmSession?) { - olmSessionData = serializeForRealm(olmSession) - } - - 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 deleted file mode 100644 index 2ebd550201..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutboundGroupSessionInfoEntity.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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, - var shouldShareHistory: Boolean = false -) : 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/store/db/model/OutgoingKeyRequestEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt deleted file mode 100644 index b10e7501d6..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2022 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 com.squareup.moshi.JsonAdapter -import com.squareup.moshi.Types -import io.realm.RealmList -import io.realm.RealmObject -import io.realm.annotations.Index -import org.matrix.android.sdk.api.extensions.tryOrNull -import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest -import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState -import org.matrix.android.sdk.api.session.crypto.RequestReply -import org.matrix.android.sdk.api.session.crypto.RequestResult -import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody -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.content.RoomKeyWithHeldContent -import org.matrix.android.sdk.api.session.events.model.toModel -import org.matrix.android.sdk.internal.di.MoshiProvider - -internal open class OutgoingKeyRequestEntity( - @Index var requestId: String? = null, - var requestedIndex: Int? = null, - var recipientsData: String? = null, - var requestedInfoStr: String? = null, - var creationTimeStamp: Long? = null, - // de-normalization for better query (if not have to query all and parse json) - @Index var roomId: String? = null, - @Index var megolmSessionId: String? = null, - - var replies: RealmList = RealmList() -) : RealmObject() { - - @Index private var requestStateStr: String = OutgoingRoomKeyRequestState.UNSENT.name - - companion object { - - private val recipientsDataMapper: JsonAdapter>> = - MoshiProvider - .providesMoshi() - .adapter( - Types.newParameterizedType(Map::class.java, String::class.java, List::class.java) - ) - } - - private fun getRequestedKeyInfo(): RoomKeyRequestBody? = RoomKeyRequestBody.fromJson(requestedInfoStr) - - fun setRequestBody(body: RoomKeyRequestBody) { - requestedInfoStr = body.toJson() - roomId = body.roomId - megolmSessionId = body.sessionId - } - - var requestState: OutgoingRoomKeyRequestState - get() { - return tryOrNull { OutgoingRoomKeyRequestState.valueOf(requestStateStr) } - ?: OutgoingRoomKeyRequestState.UNSENT - } - set(value) { - requestStateStr = value.name - } - - private fun getRecipients(): Map>? { - return this.recipientsData?.let { recipientsDataMapper.fromJson(it) } - } - - fun setRecipients(recipients: Map>) { - this.recipientsData = recipientsDataMapper.toJson(recipients) - } - - fun addReply(userId: String, fromDevice: String?, event: Event) { - val newReply = KeyRequestReplyEntity( - senderId = userId, - fromDevice = fromDevice, - eventJson = MoshiProvider.providesMoshi().adapter(Event::class.java).toJson(event) - ) - replies.add(newReply) - } - - fun toOutgoingKeyRequest(): OutgoingKeyRequest { - return OutgoingKeyRequest( - requestBody = getRequestedKeyInfo(), - recipients = getRecipients().orEmpty(), - requestId = requestId ?: "", - fromIndex = requestedIndex ?: 0, - state = requestState, - results = replies.mapNotNull { entity -> - val userId = entity.senderId ?: return@mapNotNull null - val result = entity.eventJson?.let { - MoshiProvider.providesMoshi().adapter(Event::class.java).fromJson(it) - }?.let { event -> - eventToResult(event) - } ?: return@mapNotNull null - RequestReply( - userId = userId, - fromDevice = entity.fromDevice, - result = result - ) - } - ) - } - - private fun eventToResult(event: Event): RequestResult? { - return when (event.getClearType()) { - in EventType.ROOM_KEY_WITHHELD.values -> { - event.content.toModel()?.code?.let { - RequestResult.Failure(it) - } - } - EventType.FORWARDED_ROOM_KEY -> { - RequestResult.Success((event.content?.get("chain_index") as? Number)?.toInt() ?: 0) - } - else -> null - } - } -} - -internal fun OutgoingKeyRequestEntity.deleteOnCascade() { - replies.deleteAllFromRealm() - deleteFromRealm() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/SharedSessionEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/SharedSessionEntity.kt deleted file mode 100644 index e2ae512afd..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/SharedSessionEntity.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 io.realm.annotations.Index - -/** - * Keep a record of to whom (user/device) a given session should have been shared. - * It will be used to reply to keyshare requests from other users, in order to see if - * this session was originaly shared with a given user - */ -internal open class SharedSessionEntity( - var roomId: String? = null, - var algorithm: String? = null, - @Index var sessionId: String? = null, - @Index var userId: String? = null, - @Index var deviceId: String? = null, - @Index var deviceIdentityKey: String? = null, - var chainIndex: Int? = null -) : RealmObject() { - - companion object -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/UserEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/UserEntity.kt deleted file mode 100644 index df9482bf96..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/UserEntity.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.RealmList -import io.realm.RealmObject -import io.realm.annotations.PrimaryKey -import org.matrix.android.sdk.internal.extensions.clearWith - -internal open class UserEntity( - @PrimaryKey var userId: String? = null, - var devices: RealmList = RealmList(), - var crossSigningInfoEntity: CrossSigningInfoEntity? = null, - var deviceTrackingStatus: Int = 0 -) : RealmObject() { - - companion object -} - -internal fun UserEntity.deleteOnCascade() { - devices.clearWith { it.deleteOnCascade() } - crossSigningInfoEntity?.deleteOnCascade() - deleteFromRealm() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/WithHeldSessionEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/WithHeldSessionEntity.kt deleted file mode 100644 index 93048e5775..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/WithHeldSessionEntity.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 io.realm.annotations.Index -import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode - -/** - * When an encrypted message is sent in a room, the megolm key might not be sent to all devices present in the room. - * Sometimes this may be inadvertent (for example, if the sending device is not aware of some devices that have joined), - * but some times, this may be purposeful. - * For example, the sender may have blacklisted certain devices or users, - * or may be choosing to not send the megolm key to devices that they have not verified yet. - */ -internal open class WithHeldSessionEntity( - var roomId: String? = null, - var algorithm: String? = null, - @Index var sessionId: String? = null, - @Index var senderKey: String? = null, - var codeString: String? = null, - var reason: String? = null -) : RealmObject() { - - var code: WithHeldCode? - get() { - return WithHeldCode.fromCode(codeString) - } - set(code) { - codeString = code?.value - } - - companion object -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/CrossSigningInfoEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/CrossSigningInfoEntityQueries.kt deleted file mode 100644 index 05eed9256e..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/CrossSigningInfoEntityQueries.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.query - -import io.realm.Realm -import io.realm.kotlin.createObject -import io.realm.kotlin.where -import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields - -internal fun CrossSigningInfoEntity.Companion.getOrCreate(realm: Realm, userId: String): CrossSigningInfoEntity { - return realm.where() - .equalTo(UserEntityFields.USER_ID, userId) - .findFirst() - ?: realm.createObject(userId) -} - -internal fun CrossSigningInfoEntity.Companion.get(realm: Realm, userId: String): CrossSigningInfoEntity? { - return realm.where() - .equalTo(UserEntityFields.USER_ID, userId) - .findFirst() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt deleted file mode 100644 index 0a922e79bc..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.query - -import io.realm.Realm -import io.realm.kotlin.createObject -import io.realm.kotlin.where -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.createPrimaryKey - -/** - * Get or create a device info. - */ -internal fun DeviceInfoEntity.Companion.getOrCreate(realm: Realm, userId: String, deviceId: String): DeviceInfoEntity { - val key = DeviceInfoEntity.createPrimaryKey(userId, deviceId) - - return realm.where() - .equalTo(DeviceInfoEntityFields.PRIMARY_KEY, key) - .findFirst() - ?: realm.createObject(key) - .apply { - this.deviceId = deviceId - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt deleted file mode 100644 index 85dd50c88e..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.query - -import io.realm.Realm -import io.realm.RealmResults -import io.realm.kotlin.createObject -import io.realm.kotlin.where -import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM -import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields - -internal fun SharedSessionEntity.Companion.get( - realm: Realm, - roomId: String?, - sessionId: String, - userId: String, - deviceId: String, - deviceIdentityKey: String? -): SharedSessionEntity? { - return realm.where() - .equalTo(SharedSessionEntityFields.ROOM_ID, roomId) - .equalTo(SharedSessionEntityFields.SESSION_ID, sessionId) - .equalTo(SharedSessionEntityFields.ALGORITHM, MXCRYPTO_ALGORITHM_MEGOLM) - .equalTo(SharedSessionEntityFields.USER_ID, userId) - .equalTo(SharedSessionEntityFields.DEVICE_ID, deviceId) - .equalTo(SharedSessionEntityFields.DEVICE_IDENTITY_KEY, deviceIdentityKey) - .findFirst() -} - -internal fun SharedSessionEntity.Companion.get(realm: Realm, roomId: String?, sessionId: String): RealmResults { - return realm.where() - .equalTo(SharedSessionEntityFields.ROOM_ID, roomId) - .equalTo(SharedSessionEntityFields.SESSION_ID, sessionId) - .equalTo(SharedSessionEntityFields.ALGORITHM, MXCRYPTO_ALGORITHM_MEGOLM) - .findAll() -} - -internal fun SharedSessionEntity.Companion.create( - realm: Realm, - roomId: String?, - sessionId: String, - userId: String, - deviceId: String, - deviceIdentityKey: String, - chainIndex: Int -): SharedSessionEntity { - return realm.createObject().apply { - this.roomId = roomId - this.algorithm = MXCRYPTO_ALGORITHM_MEGOLM - this.sessionId = sessionId - this.userId = userId - this.deviceId = deviceId - this.deviceIdentityKey = deviceIdentityKey - this.chainIndex = chainIndex - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt deleted file mode 100644 index 73c3997439..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.query - -import io.realm.Realm -import io.realm.kotlin.createObject -import io.realm.kotlin.where -import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields -import org.matrix.android.sdk.internal.crypto.store.db.model.deleteOnCascade - -/** - * Get or create a user. - */ -internal fun UserEntity.Companion.getOrCreate(realm: Realm, userId: String): UserEntity { - return realm.where() - .equalTo(UserEntityFields.USER_ID, userId) - .findFirst() - ?: realm.createObject(userId) -} - -/** - * Delete a user. - */ -internal fun UserEntity.Companion.delete(realm: Realm, userId: String) { - realm.where() - .equalTo(UserEntityFields.USER_ID, userId) - .findFirst() - ?.deleteOnCascade() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/WithHeldSessionQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/WithHeldSessionQueries.kt deleted file mode 100644 index c253af2bf6..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/WithHeldSessionQueries.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.query - -import io.realm.Realm -import io.realm.kotlin.createObject -import io.realm.kotlin.where -import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM -import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntityFields - -internal fun WithHeldSessionEntity.Companion.get(realm: Realm, roomId: String, sessionId: String): WithHeldSessionEntity? { - return realm.where() - .equalTo(WithHeldSessionEntityFields.ROOM_ID, roomId) - .equalTo(WithHeldSessionEntityFields.SESSION_ID, sessionId) - .equalTo(WithHeldSessionEntityFields.ALGORITHM, MXCRYPTO_ALGORITHM_MEGOLM) - .findFirst() -} - -internal fun WithHeldSessionEntity.Companion.getOrCreate(realm: Realm, roomId: String, sessionId: String): WithHeldSessionEntity? { - return get(realm, roomId, sessionId) - ?: realm.createObject().apply { - this.roomId = roomId - this.algorithm = MXCRYPTO_ALGORITHM_MEGOLM - this.sessionId = sessionId - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/Tools.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/Tools.kt deleted file mode 100644 index 052b3f4e72..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/Tools.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.tools - -import org.matrix.olm.OlmPkDecryption -import org.matrix.olm.OlmPkEncryption -import org.matrix.olm.OlmPkSigning -import org.matrix.olm.OlmUtility - -internal fun withOlmEncryption(block: (OlmPkEncryption) -> T): T { - val olmPkEncryption = OlmPkEncryption() - try { - return block(olmPkEncryption) - } finally { - olmPkEncryption.releaseEncryption() - } -} - -internal fun withOlmDecryption(block: (OlmPkDecryption) -> T): T { - val olmPkDecryption = OlmPkDecryption() - try { - return block(olmPkDecryption) - } finally { - olmPkDecryption.releaseDecryption() - } -} - -internal fun withOlmSigning(block: (OlmPkSigning) -> T): T { - val olmPkSigning = OlmPkSigning() - try { - return block(olmPkSigning) - } finally { - olmPkSigning.releaseSigning() - } -} - -internal fun withOlmUtility(block: (OlmUtility) -> T): T { - val olmUtility = OlmUtility() - try { - return block(olmUtility) - } finally { - olmUtility.releaseUtility() - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SasVerification.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SasVerification.kt index 9c8e327cd5..54f99248b1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SasVerification.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SasVerification.kt @@ -34,6 +34,7 @@ import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException import org.matrix.rustcomponents.sdk.crypto.Sas import org.matrix.rustcomponents.sdk.crypto.SasListener import org.matrix.rustcomponents.sdk.crypto.SasState +import timber.log.Timber /** Class representing a short auth string verification flow. */ internal class SasVerification @AssistedInject constructor( @@ -72,6 +73,11 @@ internal class SasVerification @AssistedInject constructor( override fun state(): SasTransactionState { return when (val state = innerState) { + SasState.Created -> { + // Note: this does not seem to be used, but emit a warning just in case. + Timber.w("SasState.Created received") + SasTransactionState.None + } SasState.Started -> SasTransactionState.SasStarted SasState.Accepted -> SasTransactionState.SasAccepted is SasState.KeysExchanged -> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt index 44ec90ed40..9528efb411 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt @@ -43,7 +43,6 @@ import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.android.sdk.internal.util.system.SystemModule import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory -import org.matrix.olm.OlmManager import java.io.File @Component( @@ -89,8 +88,6 @@ internal interface MatrixComponent { @CacheDirectory fun cacheDir(): File - fun olmManager(): OlmManager - fun taskExecutor(): TaskExecutor fun sessionParamsStore(): SessionParamsStore diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt index f2f8a5dc04..b0b0901adf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt @@ -25,7 +25,6 @@ import kotlinx.coroutines.android.asCoroutineDispatcher import kotlinx.coroutines.asCoroutineDispatcher import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.createBackgroundHandler -import org.matrix.olm.OlmManager import java.io.File import java.util.concurrent.Executors @@ -57,11 +56,4 @@ internal object MatrixModule { fun providesCacheDir(context: Context): File { return context.cacheDir } - - @JvmStatic - @Provides - @MatrixScope - fun providesOlmManager(): OlmManager { - return OlmManager() - } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/MigrateEAtoEROperation.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/MigrateEAtoEROperation.kt deleted file mode 100644 index b4944edbb9..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/MigrateEAtoEROperation.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2022 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 - -import io.realm.DynamicRealm -import io.realm.Realm -import io.realm.RealmConfiguration -import org.matrix.android.sdk.internal.crypto.store.db.migration.rust.ExtractMigrationDataUseCase -import org.matrix.android.sdk.internal.crypto.store.db.migration.rust.RealmToMigrate -import org.matrix.rustcomponents.sdk.crypto.ProgressListener -import timber.log.Timber -import java.io.File - -class MigrateEAtoEROperation(private val migrateGroupSessions: Boolean = false) { - - fun execute(cryptoRealm: RealmConfiguration, rustFilesDir: File, passphrase: String?): File { - // Temporary code for migration - if (!rustFilesDir.exists()) { - rustFilesDir.mkdir() - // perform a migration? - val extractMigrationData = ExtractMigrationDataUseCase(migrateGroupSessions) - val hasExitingData = extractMigrationData.hasExistingData(cryptoRealm) - if (!hasExitingData) return rustFilesDir - - try { - val progressListener = object : ProgressListener { - override fun onProgress(progress: Int, total: Int) { - Timber.v("OnProgress: $progress/$total") - } - } - Realm.getInstance(cryptoRealm).use { realm -> - extractMigrationData.extractData(RealmToMigrate.ClassicRealm(realm)) { - org.matrix.rustcomponents.sdk.crypto.migrate(it, rustFilesDir.path, passphrase, progressListener) - } - } - } catch (failure: Throwable) { - Timber.e(failure, "Failure while calling rust migration method") - throw failure - } - } - return rustFilesDir - } - - fun dynamicExecute(dynamicRealm: DynamicRealm, rustFilesDir: File, passphrase: String?) { - if (!rustFilesDir.exists()) { - rustFilesDir.mkdir() - } - val extractMigrationData = ExtractMigrationDataUseCase(migrateGroupSessions) - - try { - val progressListener = object : ProgressListener { - override fun onProgress(progress: Int, total: Int) { - Timber.v("OnProgress: $progress/$total") - } - } - extractMigrationData.extractData(RealmToMigrate.DynamicRealm(dynamicRealm)) { - org.matrix.rustcomponents.sdk.crypto.migrate(it, rustFilesDir.path, passphrase, progressListener) - } - } catch (failure: Throwable) { - Timber.e(failure, "Failure while calling rust migration method") - throw failure - } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ScanEncryptorUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ScanEncryptorUtils.kt index 7d14e4ed80..9cf8c90d12 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ScanEncryptorUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ScanEncryptorUtils.kt @@ -19,13 +19,14 @@ package org.matrix.android.sdk.internal.session.contentscanner import org.matrix.android.sdk.api.session.crypto.attachments.ElementToDecrypt import org.matrix.android.sdk.api.session.crypto.model.EncryptedFileInfo import org.matrix.android.sdk.api.session.crypto.model.EncryptedFileKey -import org.matrix.android.sdk.internal.crypto.tools.withOlmEncryption import org.matrix.android.sdk.internal.session.contentscanner.model.DownloadBody import org.matrix.android.sdk.internal.session.contentscanner.model.EncryptedBody import org.matrix.android.sdk.internal.session.contentscanner.model.toCanonicalJson +import org.matrix.rustcomponents.sdk.crypto.PkEncryption internal object ScanEncryptorUtils { + @Throws fun getDownloadBodyAndEncryptIfNeeded(publicServerKey: String?, mxcUrl: String, elementToDecrypt: ElementToDecrypt): DownloadBody { // TODO, upstream refactoring changed the object model here... // it's bad we have to recreate and use hardcoded values @@ -43,19 +44,18 @@ internal object ScanEncryptorUtils { v = "v2" ) return if (publicServerKey != null) { - // We should encrypt - withOlmEncryption { olm -> - olm.setRecipientKey(publicServerKey) - - val olmResult = olm.encrypt(DownloadBody(encryptedInfo).toCanonicalJson()) - DownloadBody( - encryptedBody = EncryptedBody( - cipherText = olmResult.mCipherText, - ephemeral = olmResult.mEphemeralKey, - mac = olmResult.mMac - ) - ) + // Note: fromBase64 can throw Exception + val pkEncryption = PkEncryption.fromBase64(key = publicServerKey) + val pkMessage = pkEncryption.use { + pkEncryption.encrypt(DownloadBody(encryptedInfo).toCanonicalJson()) } + DownloadBody( + encryptedBody = EncryptedBody( + cipherText = pkMessage.ciphertext, + ephemeral = pkMessage.ephemeralKey, + mac = pkMessage.mac + ) + ) } else { DownloadBody(encryptedInfo) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/ScanEncryptedTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/ScanEncryptedTask.kt index e098607eb6..4550d12f30 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/ScanEncryptedTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/ScanEncryptedTask.kt @@ -42,12 +42,10 @@ internal class DefaultScanEncryptedTask @Inject constructor( override suspend fun execute(params: ScanEncryptedTask.Params): ScanResponse { val mxcUrl = params.mxcUrl - val dlBody = ScanEncryptorUtils.getDownloadBodyAndEncryptIfNeeded(params.publicServerKey, params.mxcUrl, params.encryptedInfo) - val scannerUrl = contentScannerStore.getScannerUrl() - contentScannerStore.updateStateForContent(params.mxcUrl, ScanState.IN_PROGRESS, scannerUrl) - + contentScannerStore.updateStateForContent(mxcUrl, ScanState.IN_PROGRESS, scannerUrl) try { + val dlBody = ScanEncryptorUtils.getDownloadBodyAndEncryptIfNeeded(params.publicServerKey, mxcUrl, params.encryptedInfo) val api = contentScannerApiProvider.contentScannerApi ?: throw IllegalArgumentException() val executeRequest = executeRequest(null) { api.scanFile(dlBody) @@ -60,7 +58,7 @@ internal class DefaultScanEncryptedTask @Inject constructor( ) return executeRequest } catch (failure: Throwable) { - contentScannerStore.updateStateForContent(params.mxcUrl, ScanState.UNKNOWN, scannerUrl) + contentScannerStore.updateStateForContent(mxcUrl, ScanState.UNKNOWN, scannerUrl) throw failure.toScanFailure() ?: failure } } 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 21b59cca9d..a9d6753d3a 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 @@ -22,7 +22,6 @@ import org.matrix.android.sdk.api.session.identity.FoundThreePid 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.crypto.tools.withOlmUtility import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.identity.data.IdentityStore @@ -43,7 +42,8 @@ internal interface IdentityBulkLookupTask : Task { @@ -118,15 +118,12 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor( } private fun getHashedAddresses(threePids: List, pepper: String): List { - return withOlmUtility { olmUtility -> - threePids.map { threePid -> - base64ToBase64Url( - olmUtility.sha256( - threePid.value.lowercase(Locale.ROOT) + - " " + threePid.toMedium() + " " + pepper - ) - ) - } + return threePids.map { threePid -> + base64ToBase64Url( + sha256Converter.convertToSha256( + str = threePid.value.lowercase(Locale.ROOT) + " " + threePid.toMedium() + " " + pepper + ) + ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/TrustLevelEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/Sha256Converter.kt similarity index 54% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/TrustLevelEntity.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/Sha256Converter.kt index 5647eb8aa0..f68f7c488b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/TrustLevelEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/Sha256Converter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright (c) 2024 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. @@ -14,16 +14,16 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.crypto.store.db.model +package org.matrix.android.sdk.internal.session.identity -import io.realm.RealmObject +import org.matrix.android.sdk.api.util.toBase64NoPadding +import java.security.MessageDigest +import javax.inject.Inject -internal open class TrustLevelEntity( - var crossSignedVerified: Boolean? = null, - var locallyVerified: Boolean? = null -) : RealmObject() { +class Sha256Converter @Inject constructor() { + private val sha256 by lazy { MessageDigest.getInstance("SHA-256") } - companion object - - fun isVerified(): Boolean = crossSignedVerified == true || locallyVerified == true + fun convertToSha256(str: String): String { + return sha256.digest(str.toByteArray()).toBase64NoPadding() + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/androidsdk/crypto/data/MXDeviceInfo.java b/matrix-sdk-android/src/main/java/org/matrix/androidsdk/crypto/data/MXDeviceInfo.java deleted file mode 100755 index 4612b8d6ff..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/androidsdk/crypto/data/MXDeviceInfo.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.androidsdk.crypto.data; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -/** - * IMPORTANT: This class is imported from Riot-Android to be able to perform a migration. Do not use it for any other purpose - */ -public class MXDeviceInfo implements Serializable { - private static final long serialVersionUID = 20129670646382964L; - - // This device is a new device and the user was not warned it has been added. - public static final int DEVICE_VERIFICATION_UNKNOWN = -1; - - // The user has not yet verified this device. - public static final int DEVICE_VERIFICATION_UNVERIFIED = 0; - - // The user has verified this device. - public static final int DEVICE_VERIFICATION_VERIFIED = 1; - - // The user has blocked this device. - public static final int DEVICE_VERIFICATION_BLOCKED = 2; - - /** - * The id of this device. - */ - public String deviceId; - - /** - * the user id - */ - public String userId; - - /** - * The list of algorithms supported by this device. - */ - public List algorithms; - - /** - * A map from : to >. - */ - public Map keys; - - /** - * The signature of this MXDeviceInfo. - * A map from : to >. - */ - public Map> signatures; - - /* - * Additional data from the homeserver. - */ - public Map unsigned; - - /** - * Verification state of this device. - */ - public int mVerified; - - /** - * Constructor - */ - public MXDeviceInfo() { - mVerified = DEVICE_VERIFICATION_UNKNOWN; - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/androidsdk/crypto/data/MXOlmInboundGroupSession2.java b/matrix-sdk-android/src/main/java/org/matrix/androidsdk/crypto/data/MXOlmInboundGroupSession2.java deleted file mode 100755 index c6a8c1443c..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/androidsdk/crypto/data/MXOlmInboundGroupSession2.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.androidsdk.crypto.data; - -import org.matrix.olm.OlmInboundGroupSession; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * IMPORTANT: This class is imported from Riot-Android to be able to perform a migration. Do not use it for any other purpose - * - * This class adds more context to a OLMInboundGroupSession object. - * This allows additional checks. The class implements NSCoding so that the context can be stored. - */ -public class MXOlmInboundGroupSession2 implements Serializable { - // define a serialVersionUID to avoid having to redefine the class after updates - private static final long serialVersionUID = 201702011617L; - - // The associated olm inbound group session. - public OlmInboundGroupSession mSession; - - // The room in which this session is used. - public String mRoomId; - - // The base64-encoded curve25519 key of the sender. - public String mSenderKey; - - // Other keys the sender claims. - public Map mKeysClaimed; - - // Devices which forwarded this session to us (normally empty). - public List mForwardingCurve25519KeyChain = new ArrayList<>(); -} \ No newline at end of file diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/identity/Sha256Test.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/identity/Sha256Test.kt new file mode 100644 index 0000000000..9aa8d0b36b --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/identity/Sha256Test.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 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.identity + +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class Sha256Test { + /** + * Check that the behavior is the same than what is done in the Olm library. + * https://gitlab.matrix.org/matrix-org/olm/-/blob/master/tests/test_olm_sha256.cpp#L16 + */ + @Test + fun testSha256() { + val sut = Sha256Converter() + sut.convertToSha256("Hello, World") shouldBeEqualTo "A2daxT/5zRU1zMffzfosRYxSGDcfQY3BNvLRmsH76KU" + } +} diff --git a/tools/jitsi/build_jisti_libs.sh b/tools/jitsi/build_jitsi_libs.sh similarity index 98% rename from tools/jitsi/build_jisti_libs.sh rename to tools/jitsi/build_jitsi_libs.sh index fcdf728428..d0c6aeb54a 100755 --- a/tools/jitsi/build_jisti_libs.sh +++ b/tools/jitsi/build_jitsi_libs.sh @@ -26,7 +26,7 @@ export LIBRE_BUILD=true cd jitsi-meet # Get the latest version from the changelog: https://github.com/jitsi/jitsi-meet-release-notes/blob/master/CHANGELOG-MOBILE-SDKS.md -git checkout android-sdk-8.1.1 +git checkout mobile-sdk-10.2.0 echo echo "##################################################" diff --git a/vector-app/build.gradle b/vector-app/build.gradle index 5092f90def..8e1d1c9195 100644 --- a/vector-app/build.gradle +++ b/vector-app/build.gradle @@ -37,7 +37,7 @@ ext.versionMinor = 6 // Note: even values are reserved for regular release, odd values for hotfix release. // When creating a hotfix, you should decrease the value, since the current value // is the value for the next regular release. -ext.versionPatch = 20 +ext.versionPatch = 22 ext.scVersion = 80 diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt index 16e26ff3b5..5f34a349d6 100644 --- a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt +++ b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt @@ -85,21 +85,6 @@ class DebugFeaturesStateFactory @Inject constructor( key = DebugFeatureKeys.newAppLayoutEnabled, factory = VectorFeatures::isNewAppLayoutFeatureEnabled ), - createBooleanFeature( - label = "Enable QR Code Login", - key = DebugFeatureKeys.qrCodeLoginEnabled, - factory = VectorFeatures::isQrCodeLoginEnabled - ), - createBooleanFeature( - label = "Allow QR Code Login for all servers", - key = DebugFeatureKeys.qrCodeLoginForAllServers, - factory = VectorFeatures::isQrCodeLoginForAllServers - ), - createBooleanFeature( - label = "Show QR Code Login in Device Manager", - key = DebugFeatureKeys.reciprocateQrCodeLogin, - factory = VectorFeatures::isReciprocateQrCodeLogin - ), createBooleanFeature( label = "Enable Voice Broadcast", key = DebugFeatureKeys.voiceBroadcastEnabled, diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt index 2134c8cf2c..ffaf462244 100644 --- a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt +++ b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt @@ -76,15 +76,6 @@ class DebugVectorFeatures( override fun isNewAppLayoutFeatureEnabled(): Boolean = read(DebugFeatureKeys.newAppLayoutEnabled) ?: vectorFeatures.isNewAppLayoutFeatureEnabled() - override fun isQrCodeLoginEnabled() = read(DebugFeatureKeys.qrCodeLoginEnabled) - ?: vectorFeatures.isQrCodeLoginEnabled() - - override fun isQrCodeLoginForAllServers() = read(DebugFeatureKeys.qrCodeLoginForAllServers) - ?: vectorFeatures.isQrCodeLoginForAllServers() - - override fun isReciprocateQrCodeLogin() = read(DebugFeatureKeys.reciprocateQrCodeLogin) - ?: vectorFeatures.isReciprocateQrCodeLogin() - override fun isVoiceBroadcastEnabled(): Boolean = read(DebugFeatureKeys.voiceBroadcastEnabled) ?: vectorFeatures.isVoiceBroadcastEnabled() @@ -150,9 +141,6 @@ object DebugFeatureKeys { val screenSharing = booleanPreferencesKey("screen-sharing") val forceUsageOfOpusEncoder = booleanPreferencesKey("force-usage-of-opus-encoder") val newAppLayoutEnabled = booleanPreferencesKey("new-app-layout-enabled") - val qrCodeLoginEnabled = booleanPreferencesKey("qr-code-login-enabled") - val qrCodeLoginForAllServers = booleanPreferencesKey("qr-code-login-for-all-servers") - val reciprocateQrCodeLogin = booleanPreferencesKey("reciprocate-qr-code-login") val voiceBroadcastEnabled = booleanPreferencesKey("voice-broadcast-enabled") val unverifiedSessionsAlertEnabled = booleanPreferencesKey("unverified-sessions-alert-enabled") } diff --git a/vector/build.gradle b/vector/build.gradle index 78363f723b..6285eccd73 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -252,7 +252,7 @@ dependencies { implementation "androidx.emoji2:emoji2:1.3.0" // Jitsi - api('org.jitsi.react:jitsi-meet-sdk:8.1.1') { + api('org.jitsi.react:jitsi-meet-sdk:10.2.0') { exclude group: 'com.google.firebase' exclude group: 'com.google.android.gms' exclude group: 'com.android.installreferrer' @@ -261,6 +261,9 @@ dependencies { // The library exports a jetified artifact but doesn't remove the support library dependency // https://github.com/MatrixFrog/Android-ScalableVideoView/blob/master/gradle.properties#L1 exclude group: 'com.android.support', module: 'appcompat-v7' + + // transitive needed to pull in the react-native dependency + transitive = true } // QR-code diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 1a39c84178..3cf4f229f2 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -54,7 +54,7 @@ - + @@ -354,7 +354,6 @@ - diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt index 8751907f2a..748e672c52 100644 --- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt @@ -61,7 +61,6 @@ import im.vector.app.features.location.LocationSharingViewModel import im.vector.app.features.location.live.map.LiveLocationMapViewModel import im.vector.app.features.location.preview.LocationPreviewViewModel import im.vector.app.features.login.LoginViewModel -import im.vector.app.features.login.qr.QrCodeLoginViewModel import im.vector.app.features.matrixto.MatrixToBottomSheetViewModel import im.vector.app.features.media.VectorAttachmentViewerViewModel import im.vector.app.features.onboarding.OnboardingViewModel @@ -668,11 +667,6 @@ interface MavericksViewModelModule { @MavericksViewModelKey(RenameSessionViewModel::class) fun renameSessionViewModelFactory(factory: RenameSessionViewModel.Factory): MavericksAssistedViewModelFactory<*, *> - @Binds - @IntoMap - @MavericksViewModelKey(QrCodeLoginViewModel::class) - fun qrCodeLoginViewModelFactory(factory: QrCodeLoginViewModel.Factory): MavericksAssistedViewModelFactory<*, *> - @Binds @IntoMap @MavericksViewModelKey(SessionLearnMoreViewModel::class) diff --git a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt index 99abc15f81..65c1d03655 100644 --- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt +++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt @@ -40,9 +40,6 @@ interface VectorFeatures { * use [VectorPreferences.isNewAppLayoutEnabled] instead. */ fun isNewAppLayoutFeatureEnabled(): Boolean - fun isQrCodeLoginEnabled(): Boolean - fun isQrCodeLoginForAllServers(): Boolean - fun isReciprocateQrCodeLogin(): Boolean fun isVoiceBroadcastEnabled(): Boolean fun isUnverifiedSessionsAlertEnabled(): Boolean } @@ -60,9 +57,6 @@ class DefaultVectorFeatures : VectorFeatures { override fun isLocationSharingEnabled() = Config.ENABLE_LOCATION_SHARING override fun forceUsageOfOpusEncoder(): Boolean = false override fun isNewAppLayoutFeatureEnabled(): Boolean = true - override fun isQrCodeLoginEnabled(): Boolean = true - override fun isQrCodeLoginForAllServers(): Boolean = false - override fun isReciprocateQrCodeLogin(): Boolean = false override fun isVoiceBroadcastEnabled(): Boolean = true override fun isUnverifiedSessionsAlertEnabled(): Boolean = true } diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginAction.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginAction.kt deleted file mode 100644 index 5ea46d3dcd..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginAction.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import im.vector.app.core.platform.VectorViewModelAction - -sealed class QrCodeLoginAction : VectorViewModelAction { - data class OnQrCodeScanned(val qrCode: String) : QrCodeLoginAction() - object GenerateQrCode : QrCodeLoginAction() - object ShowQrCode : QrCodeLoginAction() - object TryAgain : QrCodeLoginAction() -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt deleted file mode 100644 index 8eb8fd1ddc..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginActivity.kt +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import android.content.Context -import android.content.Intent -import android.os.Bundle -import android.view.View -import com.airbnb.mvrx.Mavericks -import com.airbnb.mvrx.viewModel -import dagger.hilt.android.AndroidEntryPoint -import im.vector.app.core.extensions.addFragment -import im.vector.app.core.extensions.replaceFragment -import im.vector.app.core.platform.SimpleFragmentActivity -import im.vector.app.features.home.HomeActivity -import im.vector.lib.core.utils.compat.getParcelableCompat -import timber.log.Timber - -// n.b MSC3886/MSC3903/MSC3906 that this is based on are now closed. -// However, we want to keep this implementation around for some time. -// TODO define an end-of-life date for this implementation. - -@AndroidEntryPoint -class QrCodeLoginActivity : SimpleFragmentActivity() { - - private val viewModel: QrCodeLoginViewModel by viewModel() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - views.toolbar.visibility = View.GONE - - if (isFirstCreation()) { - navigateToInitialFragment() - } - - observeViewEvents() - } - - private fun navigateToInitialFragment() { - val qrCodeLoginArgs: QrCodeLoginArgs? = intent?.extras?.getParcelableCompat(Mavericks.KEY_ARG) - when (qrCodeLoginArgs?.loginType) { - QrCodeLoginType.LOGIN -> { - showInstructionsFragment(qrCodeLoginArgs) - } - QrCodeLoginType.LINK_A_DEVICE -> { - if (qrCodeLoginArgs.showQrCodeImmediately) { - handleNavigateToShowQrCodeScreen() - } else { - showInstructionsFragment(qrCodeLoginArgs) - } - } - null -> { - Timber.i("QrCodeLoginArgs is null. This is not expected.") - finish() - } - } - } - - private fun showInstructionsFragment(qrCodeLoginArgs: QrCodeLoginArgs) { - replaceFragment( - views.container, - QrCodeLoginInstructionsFragment::class.java, - qrCodeLoginArgs, - tag = FRAGMENT_QR_CODE_INSTRUCTIONS_TAG - ) - } - - private fun observeViewEvents() { - viewModel.observeViewEvents { - when (it) { - QrCodeLoginViewEvents.NavigateToStatusScreen -> handleNavigateToStatusScreen() - QrCodeLoginViewEvents.NavigateToShowQrCodeScreen -> handleNavigateToShowQrCodeScreen() - QrCodeLoginViewEvents.NavigateToHomeScreen -> handleNavigateToHomeScreen() - QrCodeLoginViewEvents.NavigateToInitialScreen -> handleNavigateToInitialScreen() - } - } - } - - private fun handleNavigateToInitialScreen() { - navigateToInitialFragment() - } - - private fun handleNavigateToShowQrCodeScreen() { - addFragment( - views.container, - QrCodeLoginShowQrCodeFragment::class.java, - tag = FRAGMENT_SHOW_QR_CODE_TAG - ) - } - - private fun handleNavigateToStatusScreen() { - addFragment( - views.container, - QrCodeLoginStatusFragment::class.java, - tag = FRAGMENT_QR_CODE_STATUS_TAG - ) - } - - private fun handleNavigateToHomeScreen() { - val intent = HomeActivity.newIntent(this, firstStartMainActivity = false, existingSession = true) - startActivity(intent) - } - - companion object { - - private const val FRAGMENT_QR_CODE_INSTRUCTIONS_TAG = "FRAGMENT_QR_CODE_INSTRUCTIONS_TAG" - private const val FRAGMENT_SHOW_QR_CODE_TAG = "FRAGMENT_SHOW_QR_CODE_TAG" - private const val FRAGMENT_QR_CODE_STATUS_TAG = "FRAGMENT_QR_CODE_STATUS_TAG" - - fun getIntent(context: Context, qrCodeLoginArgs: QrCodeLoginArgs): Intent { - return Intent(context, QrCodeLoginActivity::class.java).apply { - putExtra(Mavericks.KEY_ARG, qrCodeLoginArgs) - } - } - } -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginArgs.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginArgs.kt deleted file mode 100644 index 6c23d07c0f..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginArgs.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -@Parcelize -data class QrCodeLoginArgs( - val loginType: QrCodeLoginType, - val showQrCodeImmediately: Boolean, -) : Parcelable diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginConnectionStatus.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginConnectionStatus.kt deleted file mode 100644 index 4bef41b6c1..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginConnectionStatus.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason - -sealed class QrCodeLoginConnectionStatus { - object ConnectingToDevice : QrCodeLoginConnectionStatus() - data class Connected(val securityCode: String, val canConfirmSecurityCode: Boolean) : QrCodeLoginConnectionStatus() - object SigningIn : QrCodeLoginConnectionStatus() - data class Failed(val errorType: RendezvousFailureReason, val canTryAgain: Boolean) : QrCodeLoginConnectionStatus() -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginHeaderView.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginHeaderView.kt deleted file mode 100644 index 05c7bdffad..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginHeaderView.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import android.content.Context -import android.content.res.ColorStateList -import android.content.res.TypedArray -import android.util.AttributeSet -import android.view.LayoutInflater -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.content.res.use -import im.vector.app.core.extensions.setTextOrHide -import im.vector.app.databinding.ViewQrCodeLoginHeaderBinding - -class QrCodeLoginHeaderView @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0 -) : ConstraintLayout(context, attrs, defStyleAttr) { - - private val binding = ViewQrCodeLoginHeaderBinding.inflate( - LayoutInflater.from(context), - this - ) - - init { - context.obtainStyledAttributes( - attrs, - im.vector.lib.ui.styles.R.styleable.QrCodeLoginHeaderView, - 0, - 0 - ).use { - setTitle(it) - setDescription(it) - setImage(it) - } - } - - private fun setTitle(typedArray: TypedArray) { - val title = typedArray.getString(im.vector.lib.ui.styles.R.styleable.QrCodeLoginHeaderView_qrCodeLoginHeaderTitle) - setTitle(title) - } - - private fun setDescription(typedArray: TypedArray) { - val description = typedArray.getString(im.vector.lib.ui.styles.R.styleable.QrCodeLoginHeaderView_qrCodeLoginHeaderDescription) - setDescription(description) - } - - private fun setImage(typedArray: TypedArray) { - val imageResource = typedArray.getResourceId(im.vector.lib.ui.styles.R.styleable.QrCodeLoginHeaderView_qrCodeLoginHeaderImageResource, 0) - val backgroundTint = typedArray.getColor(im.vector.lib.ui.styles.R.styleable.QrCodeLoginHeaderView_qrCodeLoginHeaderImageBackgroundTint, 0) - setImage(imageResource, backgroundTint) - } - - fun setTitle(title: String?) { - binding.qrCodeLoginHeaderTitleTextView.setTextOrHide(title) - } - - fun setDescription(description: String?) { - binding.qrCodeLoginHeaderDescriptionTextView.setTextOrHide(description) - } - - fun setImage(imageResource: Int, backgroundTintColor: Int) { - binding.qrCodeLoginHeaderImageView.setImageResource(imageResource) - binding.qrCodeLoginHeaderImageView.backgroundTintList = ColorStateList.valueOf(backgroundTintColor) - } -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt deleted file mode 100644 index f78cae5d22..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsFragment.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import android.app.Activity -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.airbnb.mvrx.activityViewModel -import com.airbnb.mvrx.withState -import dagger.hilt.android.AndroidEntryPoint -import im.vector.app.core.extensions.registerStartForActivityResult -import im.vector.app.core.platform.VectorBaseFragment -import im.vector.app.databinding.FragmentQrCodeLoginInstructionsBinding -import im.vector.app.features.qrcode.QrCodeScannerActivity -import im.vector.lib.strings.CommonStrings -import timber.log.Timber - -@AndroidEntryPoint -class QrCodeLoginInstructionsFragment : VectorBaseFragment() { - - private val viewModel: QrCodeLoginViewModel by activityViewModel() - - override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentQrCodeLoginInstructionsBinding { - return FragmentQrCodeLoginInstructionsBinding.inflate(inflater, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initScanQrCodeButton() - initShowQrCodeButton() - } - - private fun initShowQrCodeButton() { - views.qrCodeLoginInstructionsShowQrCodeButton.debouncedClicks { - viewModel.handle(QrCodeLoginAction.ShowQrCode) - } - } - - private fun initScanQrCodeButton() { - views.qrCodeLoginInstructionsScanQrCodeButton.debouncedClicks { - QrCodeScannerActivity.startForResult(requireActivity(), scanActivityResultLauncher) - } - } - - private val scanActivityResultLauncher = registerStartForActivityResult { activityResult -> - if (activityResult.resultCode == Activity.RESULT_OK) { - val scannedQrCode = QrCodeScannerActivity.getResultText(activityResult.data) - val wasQrCode = QrCodeScannerActivity.getResultIsQrCode(activityResult.data) - - Timber.d("Scanned QR code: $scannedQrCode, was QR code: $wasQrCode") - if (wasQrCode && !scannedQrCode.isNullOrBlank()) { - onQrCodeScanned(scannedQrCode) - } else { - onQrCodeScannerFailed() - } - } - } - - private fun onQrCodeScanned(scannedQrCode: String) { - viewModel.handle(QrCodeLoginAction.OnQrCodeScanned(scannedQrCode)) - } - - private fun onQrCodeScannerFailed() { - // The user scanned something unexpected, so we try scanning again. - // This seems to happen particularly with the large QRs needed for rendezvous - // especially when the QR is partially off the screen - Timber.d("QrCodeLoginInstructionsFragment.onQrCodeScannerFailed - showing scanner again") - QrCodeScannerActivity.startForResult(requireActivity(), scanActivityResultLauncher) - } - - override fun invalidate() = withState(viewModel) { state -> - if (state.loginType == QrCodeLoginType.LOGIN) { - views.qrCodeLoginInstructionsView.setInstructions( - listOf( - getString(CommonStrings.qr_code_login_new_device_instruction_1), - getString(CommonStrings.qr_code_login_new_device_instruction_2), - getString(CommonStrings.qr_code_login_new_device_instruction_3), - ) - ) - } else { - views.qrCodeLoginInstructionsView.setInstructions( - listOf( - getString(CommonStrings.qr_code_login_link_a_device_scan_qr_code_instruction_1), - getString(CommonStrings.qr_code_login_link_a_device_scan_qr_code_instruction_2), - ) - ) - } - } -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsView.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsView.kt deleted file mode 100644 index bed4efc952..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginInstructionsView.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import android.content.Context -import android.content.res.TypedArray -import android.util.AttributeSet -import android.view.LayoutInflater -import android.widget.LinearLayout -import android.widget.TextView -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.content.res.use -import androidx.core.view.isVisible -import im.vector.app.databinding.ViewQrCodeLoginInstructionsBinding - -class QrCodeLoginInstructionsView @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0 -) : ConstraintLayout(context, attrs, defStyleAttr) { - - private val binding = ViewQrCodeLoginInstructionsBinding.inflate( - LayoutInflater.from(context), - this - ) - - init { - context.obtainStyledAttributes( - attrs, - im.vector.lib.ui.styles.R.styleable.QrCodeLoginInstructionsView, - 0, - 0 - ).use { - setInstructions(it) - } - } - - private fun setInstructions(typedArray: TypedArray) { - val instruction1 = typedArray.getString(im.vector.lib.ui.styles.R.styleable.QrCodeLoginInstructionsView_qrCodeLoginInstruction1) - val instruction2 = typedArray.getString(im.vector.lib.ui.styles.R.styleable.QrCodeLoginInstructionsView_qrCodeLoginInstruction2) - val instruction3 = typedArray.getString(im.vector.lib.ui.styles.R.styleable.QrCodeLoginInstructionsView_qrCodeLoginInstruction3) - setInstructions( - listOf( - instruction1, - instruction2, - instruction3, - ) - ) - } - - fun setInstructions(instructions: List?) { - setInstruction(binding.instructions1Layout, binding.instruction1TextView, instructions?.getOrNull(0)) - setInstruction(binding.instructions2Layout, binding.instruction2TextView, instructions?.getOrNull(1)) - setInstruction(binding.instructions3Layout, binding.instruction3TextView, instructions?.getOrNull(2)) - } - - private fun setInstruction(instructionLayout: LinearLayout, instructionTextView: TextView, instruction: String?) { - instruction?.let { - instructionLayout.isVisible = true - instructionTextView.text = instruction - } ?: run { - instructionLayout.isVisible = false - } - } -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginShowQrCodeFragment.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginShowQrCodeFragment.kt deleted file mode 100644 index e84007bd43..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginShowQrCodeFragment.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.airbnb.mvrx.activityViewModel -import com.airbnb.mvrx.withState -import dagger.hilt.android.AndroidEntryPoint -import im.vector.app.core.platform.VectorBaseFragment -import im.vector.app.databinding.FragmentQrCodeLoginShowQrCodeBinding -import im.vector.lib.strings.CommonStrings - -@AndroidEntryPoint -class QrCodeLoginShowQrCodeFragment : VectorBaseFragment() { - - private val viewModel: QrCodeLoginViewModel by activityViewModel() - - override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentQrCodeLoginShowQrCodeBinding { - return FragmentQrCodeLoginShowQrCodeBinding.inflate(inflater, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initCancelButton() - viewModel.handle(QrCodeLoginAction.GenerateQrCode) - } - - private fun initCancelButton() { - views.qrCodeLoginShowQrCodeCancelButton.debouncedClicks { - activity?.onBackPressedDispatcher?.onBackPressed() - } - } - - private fun setInstructions(loginType: QrCodeLoginType) { - if (loginType == QrCodeLoginType.LOGIN) { - views.qrCodeLoginShowQrCodeHeaderView.setDescription(getString(CommonStrings.qr_code_login_header_show_qr_code_new_device_description)) - views.qrCodeLoginShowQrCodeInstructionsView.setInstructions( - listOf( - getString(CommonStrings.qr_code_login_new_device_instruction_1), - getString(CommonStrings.qr_code_login_new_device_instruction_2), - getString(CommonStrings.qr_code_login_new_device_instruction_3), - ) - ) - } else { - views.qrCodeLoginShowQrCodeHeaderView.setDescription(getString(CommonStrings.qr_code_login_header_show_qr_code_link_a_device_description)) - views.qrCodeLoginShowQrCodeInstructionsView.setInstructions( - listOf( - getString(CommonStrings.qr_code_login_link_a_device_show_qr_code_instruction_1), - getString(CommonStrings.qr_code_login_link_a_device_show_qr_code_instruction_2), - ) - ) - } - } - - private fun showQrCode(qrCodeData: String) { - views.qrCodeLoginSHowQrCodeImageView.setData(qrCodeData) - } - - override fun invalidate() = withState(viewModel) { state -> - state.generatedQrCodeData?.let { qrCodeData -> - showQrCode(qrCodeData) - } - setInstructions(state.loginType) - } -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginStatusFragment.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginStatusFragment.kt deleted file mode 100644 index dcfcd8b06f..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginStatusFragment.kt +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.core.view.isVisible -import com.airbnb.mvrx.activityViewModel -import com.airbnb.mvrx.withState -import dagger.hilt.android.AndroidEntryPoint -import im.vector.app.R -import im.vector.app.core.platform.VectorBaseFragment -import im.vector.app.databinding.FragmentQrCodeLoginStatusBinding -import im.vector.app.features.themes.ThemeUtils -import im.vector.lib.strings.CommonStrings -import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason - -@AndroidEntryPoint -class QrCodeLoginStatusFragment : VectorBaseFragment() { - - private val viewModel: QrCodeLoginViewModel by activityViewModel() - - override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentQrCodeLoginStatusBinding { - return FragmentQrCodeLoginStatusBinding.inflate(inflater, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initCancelButton() - initTryAgainButton() - } - - private fun initTryAgainButton() { - views.qrCodeLoginStatusTryAgainButton.debouncedClicks { - viewModel.handle(QrCodeLoginAction.TryAgain) - } - } - - private fun initCancelButton() { - views.qrCodeLoginStatusCancelButton.debouncedClicks { - activity?.onBackPressedDispatcher?.onBackPressed() - } - } - - private fun handleFailed(connectionStatus: QrCodeLoginConnectionStatus.Failed) { - views.qrCodeLoginConfirmSecurityCodeLayout.isVisible = false - views.qrCodeLoginStatusLoadingLayout.isVisible = false - views.qrCodeLoginStatusHeaderView.isVisible = true - views.qrCodeLoginStatusSecurityCode.isVisible = false - views.qrCodeLoginStatusNoMatchLayout.isVisible = false - views.qrCodeLoginStatusCancelButton.isVisible = true - views.qrCodeLoginStatusTryAgainButton.isVisible = connectionStatus.canTryAgain - views.qrCodeLoginStatusHeaderView.setTitle(getString(CommonStrings.qr_code_login_header_failed_title)) - views.qrCodeLoginStatusHeaderView.setDescription(getErrorDescription(connectionStatus.errorType)) - views.qrCodeLoginStatusHeaderView.setImage( - imageResource = R.drawable.ic_qr_code_login_failed, - backgroundTintColor = ThemeUtils.getColor(requireContext(), com.google.android.material.R.attr.colorError) - ) - } - - private fun getErrorDescription(reason: RendezvousFailureReason): String { - return when (reason) { - RendezvousFailureReason.UnsupportedAlgorithm, - RendezvousFailureReason.UnsupportedTransport -> getString(CommonStrings.qr_code_login_header_failed_device_is_not_supported_description) - RendezvousFailureReason.UnsupportedHomeserver -> getString(CommonStrings.qr_code_login_header_failed_homeserver_is_not_supported_description) - RendezvousFailureReason.Expired -> getString(CommonStrings.qr_code_login_header_failed_timeout_description) - RendezvousFailureReason.UserDeclined -> getString(CommonStrings.qr_code_login_header_failed_denied_description) - RendezvousFailureReason.E2EESecurityIssue -> getString(CommonStrings.qr_code_login_header_failed_e2ee_security_issue_description) - RendezvousFailureReason.OtherDeviceAlreadySignedIn -> - getString(CommonStrings.qr_code_login_header_failed_other_device_already_signed_in_description) - RendezvousFailureReason.OtherDeviceNotSignedIn -> getString(CommonStrings.qr_code_login_header_failed_other_device_not_signed_in_description) - RendezvousFailureReason.InvalidCode -> getString(CommonStrings.qr_code_login_header_failed_invalid_qr_code_description) - RendezvousFailureReason.UserCancelled -> getString(CommonStrings.qr_code_login_header_failed_user_cancelled_description) - else -> getString(CommonStrings.qr_code_login_header_failed_other_description) - } - } - - private fun handleConnectingToDevice() { - views.qrCodeLoginConfirmSecurityCodeLayout.isVisible = false - views.qrCodeLoginStatusLoadingLayout.isVisible = true - views.qrCodeLoginStatusHeaderView.isVisible = false - views.qrCodeLoginStatusSecurityCode.isVisible = false - views.qrCodeLoginStatusNoMatchLayout.isVisible = false - views.qrCodeLoginStatusCancelButton.isVisible = true - views.qrCodeLoginStatusTryAgainButton.isVisible = false - views.qrCodeLoginStatusLoadingTextView.setText(CommonStrings.qr_code_login_connecting_to_device) - } - - private fun handleSigningIn() { - views.qrCodeLoginConfirmSecurityCodeLayout.isVisible = false - views.qrCodeLoginStatusLoadingLayout.isVisible = true - views.qrCodeLoginStatusHeaderView.apply { - isVisible = true - setTitle(getString(CommonStrings.dialog_title_success)) - setDescription("") - setImage(R.drawable.ic_tick, ThemeUtils.getColor(requireContext(), com.google.android.material.R.attr.colorPrimary)) - } - views.qrCodeLoginStatusSecurityCode.isVisible = false - views.qrCodeLoginStatusNoMatchLayout.isVisible = false - views.qrCodeLoginStatusCancelButton.isVisible = false - views.qrCodeLoginStatusTryAgainButton.isVisible = false - views.qrCodeLoginStatusLoadingTextView.setText(CommonStrings.qr_code_login_signing_in) - } - - private fun handleConnectionEstablished(connectionStatus: QrCodeLoginConnectionStatus.Connected, loginType: QrCodeLoginType) { - views.qrCodeLoginConfirmSecurityCodeLayout.isVisible = loginType == QrCodeLoginType.LINK_A_DEVICE - views.qrCodeLoginStatusLoadingLayout.isVisible = false - views.qrCodeLoginStatusHeaderView.isVisible = true - views.qrCodeLoginStatusSecurityCode.isVisible = true - views.qrCodeLoginStatusNoMatchLayout.isVisible = loginType == QrCodeLoginType.LOGIN - views.qrCodeLoginStatusCancelButton.isVisible = true - views.qrCodeLoginStatusTryAgainButton.isVisible = false - views.qrCodeLoginStatusSecurityCode.text = connectionStatus.securityCode - views.qrCodeLoginStatusHeaderView.setTitle(getString(CommonStrings.qr_code_login_header_connected_title)) - views.qrCodeLoginStatusHeaderView.setDescription(getString(CommonStrings.qr_code_login_header_connected_description)) - views.qrCodeLoginStatusHeaderView.setImage( - imageResource = R.drawable.ic_qr_code_login_connected, - backgroundTintColor = ThemeUtils.getColor(requireContext(), com.google.android.material.R.attr.colorPrimary) - ) - } - - override fun invalidate() = withState(viewModel) { state -> - when (state.connectionStatus) { - is QrCodeLoginConnectionStatus.Connected -> handleConnectionEstablished(state.connectionStatus, state.loginType) - QrCodeLoginConnectionStatus.ConnectingToDevice -> handleConnectingToDevice() - QrCodeLoginConnectionStatus.SigningIn -> handleSigningIn() - is QrCodeLoginConnectionStatus.Failed -> handleFailed(state.connectionStatus) - null -> { /* NOOP */ - } - } - } -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginType.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginType.kt deleted file mode 100644 index b4bb5b667f..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginType.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -enum class QrCodeLoginType { - LOGIN, - LINK_A_DEVICE, -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt deleted file mode 100644 index e20ea6b2e8..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewEvents.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import im.vector.app.core.platform.VectorViewEvents - -sealed class QrCodeLoginViewEvents : VectorViewEvents { - object NavigateToStatusScreen : QrCodeLoginViewEvents() - object NavigateToShowQrCodeScreen : QrCodeLoginViewEvents() - object NavigateToHomeScreen : QrCodeLoginViewEvents() - object NavigateToInitialScreen : QrCodeLoginViewEvents() -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewModel.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewModel.kt deleted file mode 100644 index 97cca9d791..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewModel.kt +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import com.airbnb.mvrx.MavericksViewModelFactory -import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject -import im.vector.app.core.di.ActiveSessionHolder -import im.vector.app.core.di.MavericksAssistedViewModelFactory -import im.vector.app.core.di.hiltMavericksViewModelFactory -import im.vector.app.core.platform.VectorViewModel -import im.vector.app.core.session.ConfigureAndStartSessionUseCase -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.auth.AuthenticationService -import org.matrix.android.sdk.api.rendezvous.Rendezvous -import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason -import org.matrix.android.sdk.api.rendezvous.model.RendezvousError -import timber.log.Timber - -class QrCodeLoginViewModel @AssistedInject constructor( - @Assisted private val initialState: QrCodeLoginViewState, - private val authenticationService: AuthenticationService, - private val activeSessionHolder: ActiveSessionHolder, - private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase, -) : VectorViewModel(initialState) { - - @AssistedFactory - interface Factory : MavericksAssistedViewModelFactory { - override fun create(initialState: QrCodeLoginViewState): QrCodeLoginViewModel - } - - companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() { - val TAG: String = QrCodeLoginViewModel::class.java.simpleName - } - - override fun handle(action: QrCodeLoginAction) { - when (action) { - is QrCodeLoginAction.OnQrCodeScanned -> handleOnQrCodeScanned(action) - QrCodeLoginAction.GenerateQrCode -> handleQrCodeViewStarted() - QrCodeLoginAction.ShowQrCode -> handleShowQrCode() - QrCodeLoginAction.TryAgain -> handleTryAgain() - } - } - - private fun handleTryAgain() { - setState { - copy( - connectionStatus = null - ) - } - _viewEvents.post(QrCodeLoginViewEvents.NavigateToInitialScreen) - } - - private fun handleShowQrCode() { - _viewEvents.post(QrCodeLoginViewEvents.NavigateToShowQrCodeScreen) - } - - private fun handleQrCodeViewStarted() { - val qrCodeData = generateQrCodeData() - setState { - copy( - generatedQrCodeData = qrCodeData - ) - } - } - - private fun handleOnQrCodeScanned(action: QrCodeLoginAction.OnQrCodeScanned) { - Timber.tag(TAG).d("Scanned code of length ${action.qrCode.length}") - - val rendezvous = try { Rendezvous.buildChannelFromCode(action.qrCode) } catch (t: Throwable) { - Timber.tag(TAG).e(t, "Error occurred during sign in") - if (t is RendezvousError) { - onFailed(t.reason) - } else { - onFailed(RendezvousFailureReason.Unknown) - } - return - } - - setState { - copy( - connectionStatus = QrCodeLoginConnectionStatus.ConnectingToDevice - ) - } - - _viewEvents.post(QrCodeLoginViewEvents.NavigateToStatusScreen) - - viewModelScope.launch(Dispatchers.IO) { - try { - val confirmationCode = rendezvous.startAfterScanningCode() - Timber.tag(TAG).i("Established secure channel with checksum: $confirmationCode") - - onConnectionEstablished(confirmationCode) - - val session = rendezvous.waitForLoginOnNewDevice(authenticationService) - onSigningIn() - - activeSessionHolder.setActiveSession(session) - authenticationService.reset() - configureAndStartSessionUseCase.execute(session) - - rendezvous.completeVerificationOnNewDevice(session) - - _viewEvents.post(QrCodeLoginViewEvents.NavigateToHomeScreen) - } catch (t: Throwable) { - Timber.tag(TAG).e(t, "Error occurred during sign in") - if (t is RendezvousError) { - onFailed(t.reason) - } else { - onFailed(RendezvousFailureReason.Unknown) - } - } - } - } - - private fun onFailed(reason: RendezvousFailureReason) { - _viewEvents.post(QrCodeLoginViewEvents.NavigateToStatusScreen) - - setState { - copy( - connectionStatus = QrCodeLoginConnectionStatus.Failed(reason, reason.canRetry) - ) - } - } - - private fun onConnectionEstablished(securityCode: String) { - val canConfirmSecurityCode = initialState.loginType == QrCodeLoginType.LINK_A_DEVICE - setState { - copy( - connectionStatus = QrCodeLoginConnectionStatus.Connected(securityCode, canConfirmSecurityCode) - ) - } - } - - private fun onSigningIn() { - setState { - copy( - connectionStatus = QrCodeLoginConnectionStatus.SigningIn - ) - } - } - - /** - * QR code generation is not currently supported and this is a placeholder for future - * functionality. - */ - private fun generateQrCodeData(): String { - return "NOT SUPPORTED" - } -} diff --git a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewState.kt b/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewState.kt deleted file mode 100644 index 0c4457c12f..0000000000 --- a/vector/src/main/java/im/vector/app/features/login/qr/QrCodeLoginViewState.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * 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 im.vector.app.features.login.qr - -import com.airbnb.mvrx.MavericksState - -data class QrCodeLoginViewState( - val loginType: QrCodeLoginType, - val connectionStatus: QrCodeLoginConnectionStatus? = null, - val generatedQrCodeData: String? = null, -) : MavericksState { - - constructor(args: QrCodeLoginArgs) : this( - loginType = args.loginType, - ) -} diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index 4d88bd3dc1..a3c6fe4354 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -71,8 +71,6 @@ import im.vector.app.features.location.live.map.LiveLocationMapViewActivity import im.vector.app.features.location.live.map.LiveLocationMapViewArgs import im.vector.app.features.login.LoginActivity import im.vector.app.features.login.LoginConfig -import im.vector.app.features.login.qr.QrCodeLoginActivity -import im.vector.app.features.login.qr.QrCodeLoginArgs import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.matrixto.OriginOfMatrixTo import im.vector.app.features.media.AttachmentData @@ -616,14 +614,6 @@ class DefaultNavigator @Inject constructor( activityResultLauncher.launch(screenCaptureIntent) } - override fun openLoginWithQrCode(context: Context, qrCodeLoginArgs: QrCodeLoginArgs) { - QrCodeLoginActivity - .getIntent(context, qrCodeLoginArgs) - .also { - context.startActivity(it) - } - } - private fun Intent.start(context: Context) { context.startActivity(this) } diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt index 7c1e825b0e..6242f655f5 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt @@ -31,7 +31,6 @@ import im.vector.app.features.home.room.threads.arguments.ThreadTimelineArgs import im.vector.app.features.location.LocationData import im.vector.app.features.location.LocationSharingMode import im.vector.app.features.login.LoginConfig -import im.vector.app.features.login.qr.QrCodeLoginArgs import im.vector.app.features.matrixto.OriginOfMatrixTo import im.vector.app.features.media.AttachmentData import im.vector.app.features.pin.PinMode @@ -204,9 +203,4 @@ interface Navigator { screenCaptureIntent: Intent, activityResultLauncher: ActivityResultLauncher ) - - fun openLoginWithQrCode( - context: Context, - qrCodeLoginArgs: QrCodeLoginArgs, - ) } diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt index 949c728aa2..21b806fda1 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt @@ -121,29 +121,6 @@ class OnboardingViewModel @AssistedInject constructor( } } - private fun checkQrCodeLoginCapability() { - if (!vectorFeatures.isQrCodeLoginEnabled()) { - setState { - copy( - canLoginWithQrCode = false - ) - } - } else if (vectorFeatures.isQrCodeLoginForAllServers()) { - // allow for all servers - setState { - copy( - canLoginWithQrCode = true - ) - } - } else { - setState { - copy( - canLoginWithQrCode = selectedHomeserver.isLoginWithQrSupported - ) - } - } - } - private val matrixOrgUrl = stringProvider.getString(im.vector.app.config.R.string.matrix_org_server_url).ensureTrailingSlash() private val defaultHomeserverUrl = mdmService.getData(MdmData.DefaultHomeserverUrl, matrixOrgUrl) @@ -710,7 +687,6 @@ class OnboardingViewModel @AssistedInject constructor( _viewEvents.post(OnboardingViewEvents.Failure(Throwable("Unable to create a HomeServerConnectionConfig"))) } else { startAuthenticationFlow(action, homeServerConnectionConfig, serverTypeOverride, suspend { - checkQrCodeLoginCapability() postAction() }) } diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt index 58b28ac4e4..defb08aeae 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt @@ -59,8 +59,6 @@ data class OnboardingViewState( @PersistState val personalizationState: PersonalizationState = PersonalizationState(), - - val canLoginWithQrCode: Boolean = false, ) : MavericksState enum class OnboardingFlow { diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedLoginFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedLoginFragment.kt index abcfcafc64..cb687f6b00 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedLoginFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedLoginFragment.kt @@ -40,8 +40,6 @@ import im.vector.app.features.VectorFeatures import im.vector.app.features.login.LoginMode import im.vector.app.features.login.SSORedirectRouterActivity import im.vector.app.features.login.SocialLoginButtonsView -import im.vector.app.features.login.qr.QrCodeLoginArgs -import im.vector.app.features.login.qr.QrCodeLoginType import im.vector.app.features.login.render import im.vector.app.features.onboarding.OnboardingAction import im.vector.app.features.onboarding.OnboardingViewEvents @@ -75,26 +73,6 @@ class FtueAuthCombinedLoginFragment : viewModel.handle(OnboardingAction.UserNameEnteredAction.Login(views.loginInput.content())) } views.loginForgotPassword.debouncedClicks { viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnForgetPasswordClicked)) } - - viewModel.onEach(OnboardingViewState::canLoginWithQrCode) { - configureQrCodeLoginButtonVisibility(it) - } - } - - private fun configureQrCodeLoginButtonVisibility(canLoginWithQrCode: Boolean) { - views.loginWithQrCode.isVisible = canLoginWithQrCode - if (canLoginWithQrCode) { - views.loginWithQrCode.debouncedClicks { - navigator - .openLoginWithQrCode( - requireActivity(), - QrCodeLoginArgs( - loginType = QrCodeLoginType.LOGIN, - showQrCodeImmediately = false, - ) - ) - } - } } private fun setupSubmitButton() { diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index d680de8aa3..0c49fd07ba 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -41,8 +41,6 @@ import im.vector.app.databinding.FragmentSettingsDevicesBinding import im.vector.app.features.VectorFeatures import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.crypto.recover.SetupMode -import im.vector.app.features.login.qr.QrCodeLoginArgs -import im.vector.app.features.login.qr.QrCodeLoginType import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.list.NUMBER_OF_OTHER_DEVICES_TO_RENDER import im.vector.app.features.settings.devices.v2.list.OtherSessionsView @@ -106,7 +104,6 @@ class VectorSettingsDevicesFragment : initOtherSessionsHeaderView() initOtherSessionsView() initSecurityRecommendationsView() - initQrLoginView() observeViewEvents() } @@ -240,38 +237,6 @@ class VectorSettingsDevicesFragment : } } - private fun initQrLoginView() { - if (!vectorFeatures.isReciprocateQrCodeLogin()) { - views.deviceListHeaderSignInWithQrCode.isVisible = false - views.deviceListHeaderScanQrCodeButton.isVisible = false - views.deviceListHeaderShowQrCodeButton.isVisible = false - return - } - - views.deviceListHeaderSignInWithQrCode.isVisible = true - views.deviceListHeaderScanQrCodeButton.isVisible = true - views.deviceListHeaderShowQrCodeButton.isVisible = true - - views.deviceListHeaderScanQrCodeButton.debouncedClicks { - navigateToQrCodeScreen(showQrCodeImmediately = false) - } - - views.deviceListHeaderShowQrCodeButton.debouncedClicks { - navigateToQrCodeScreen(showQrCodeImmediately = true) - } - } - - private fun navigateToQrCodeScreen(showQrCodeImmediately: Boolean) { - navigator - .openLoginWithQrCode( - requireActivity(), - QrCodeLoginArgs( - loginType = QrCodeLoginType.LINK_A_DEVICE, - showQrCodeImmediately = showQrCodeImmediately, - ) - ) - } - override fun onDestroyView() { cleanUpLearnMoreButtonsListeners() super.onDestroyView() diff --git a/vector/src/main/res/drawable/circle_qr_code_login_instruction_with_border.xml b/vector/src/main/res/drawable/circle_qr_code_login_instruction_with_border.xml deleted file mode 100644 index cb99e4467c..0000000000 --- a/vector/src/main/res/drawable/circle_qr_code_login_instruction_with_border.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - diff --git a/vector/src/main/res/drawable/ic_qr_code.xml b/vector/src/main/res/drawable/ic_qr_code.xml deleted file mode 100644 index 1ebdc169c9..0000000000 --- a/vector/src/main/res/drawable/ic_qr_code.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/vector/src/main/res/drawable/ic_qr_code_login_connected.xml b/vector/src/main/res/drawable/ic_qr_code_login_connected.xml deleted file mode 100644 index 48f5c6a383..0000000000 --- a/vector/src/main/res/drawable/ic_qr_code_login_connected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/vector/src/main/res/drawable/ic_qr_code_login_failed.xml b/vector/src/main/res/drawable/ic_qr_code_login_failed.xml deleted file mode 100644 index f49e07c066..0000000000 --- a/vector/src/main/res/drawable/ic_qr_code_login_failed.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/vector/src/main/res/layout/fragment_ftue_combined_login.xml b/vector/src/main/res/layout/fragment_ftue_combined_login.xml index 7eff92f4f9..a589ec6f5a 100644 --- a/vector/src/main/res/layout/fragment_ftue_combined_login.xml +++ b/vector/src/main/res/layout/fragment_ftue_combined_login.xml @@ -244,20 +244,6 @@ app:layout_constraintStart_toStartOf="@id/loginGutterStart" app:layout_constraintTop_toBottomOf="@id/loginSubmit" /> -