Merge pull request #8366 from vector-im/feature/bca/rust_integration_test_wf

add workflow for rust test
This commit is contained in:
Valere 2023-05-05 10:53:47 +02:00 committed by GitHub
commit e7c122ef1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 288 additions and 73 deletions

102
.github/workflows/tests-rust.yml vendored Normal file
View file

@ -0,0 +1,102 @@
name: Test
on:
pull_request: { }
push:
branches: [ main, develop ]
paths-ignore:
- '.github/**'
# Enrich gradle.properties for CI/CD
env:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 4 --no-daemon
jobs:
tests:
name: Runs all tests with rust crypto
runs-on: buildjet-4vcpu-ubuntu-2204
timeout-minutes: 90 # We might need to increase it if the time for tests grows
strategy:
matrix:
api-level: [28]
# Allow all jobs on main and develop. Just one per PR.
concurrency:
group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-rust-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-rust-{0}', github.sha) || format('unit-tests-rust-{0}', github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v3
with:
lfs: true
fetch-depth: 0
- uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: '11'
- uses: gradle/gradle-build-action@v2
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
gradle-home-cache-cleanup: ${{ github.ref == 'refs/heads/develop' }}
# - name: Run screenshot tests
# run: ./gradlew verifyScreenshots $CI_GRADLE_ARG_PROPERTIES
# - name: Archive Screenshot Results on Error
# if: failure()
# uses: actions/upload-artifact@v3
# with:
# name: screenshot-results
# path: |
# **/out/failures/
# **/build/reports/tests/*UnitTest/
- uses: actions/setup-python@v4
with:
python-version: 3.8
- uses: michaelkaye/setup-matrix-synapse@v1.0.4
with:
uploadLogs: true
httpPort: 8080
disableRateLimiting: true
public_baseurl: "http://10.0.2.2:8080/"
- name: Run all the codecoverage tests at once
uses: reactivecircus/android-emulator-runner@v2
# continue-on-error: true
with:
api-level: ${{ matrix.api-level }}
arch: x86
profile: Nexus 5X
target: playstore
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
# emulator-build: 7425822
script: |
./gradlew gatherGplayRustCryptoDebugStringTemplates $CI_GRADLE_ARG_PROPERTIES
./gradlew instrumentationTestsRustWithCoverage $CI_GRADLE_ARG_PROPERTIES
./gradlew generateCoverageReport $CI_GRADLE_ARG_PROPERTIES
- name: Upload Rust Integration Test Report Log
uses: actions/upload-artifact@v3
if: always()
with:
name: integration-test-rust-error-results
path: |
*/build/outputs/androidTest-results/connected/
*/build/reports/androidTests/connected/
# For now ignore sonar
# - name: Publish results to Sonar
# env:
# GITHUB_TOKEN: ${{ secrets.SONARQUBE_GITHUB_API_TOKEN }} # Needed to get PR information, if any
# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
# ORG_GRADLE_PROJECT_SONAR_LOGIN: ${{ secrets.SONAR_TOKEN }}
# if: ${{ always() && env.GITHUB_TOKEN != '' && env.SONAR_TOKEN != '' && env.ORG_GRADLE_PROJECT_SONAR_LOGIN != '' }}
# run: ./gradlew sonar $CI_GRADLE_ARG_PROPERTIES
- name: Format unit test results
if: always()
run: python3 ./tools/ci/render_test_output.py unit ./**/build/test-results/**/*.xml

1
changelog.d/8366.misc Normal file
View file

@ -0,0 +1 @@
CI: Add workflow to run test with crypto flavor

View file

@ -89,3 +89,9 @@ task instrumentationTestsWithCoverage(type: GradleBuild) {
startParameter.projectProperties['android.testInstrumentationRunnerArguments.notPackage'] = 'im.vector.app.ui'
tasks = [':vector-app:connectedGplayKotlinCryptoDebugAndroidTest', ':vector:connectedKotlinCryptoDebugAndroidTest', 'matrix-sdk-android:connectedKotlinCryptoDebugAndroidTest']
}
task instrumentationTestsRustWithCoverage(type: GradleBuild) {
startParameter.projectProperties.coverage = "true"
startParameter.projectProperties['android.testInstrumentationRunnerArguments.notPackage'] = 'im.vector.app.ui'
tasks = [':vector-app:connectedGplayRustCryptoDebugAndroidTest', ':vector:connectedRustCryptoDebugAndroidTest', 'matrix-sdk-android:connectedRustCryptoDebugAndroidTest']
}

View file

@ -216,7 +216,7 @@ dependencies {
implementation libs.google.phonenumber
rustCryptoImplementation("org.matrix.rustcomponents:crypto-android:0.3.5")
rustCryptoImplementation("org.matrix.rustcomponents:crypto-android:0.3.7")
// rustCryptoApi project(":library:rustCrypto")
testImplementation libs.tests.junit

View file

@ -26,6 +26,7 @@ import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Ignore
import org.junit.Test
@ -128,6 +129,7 @@ class KeysBackupTest : InstrumentedTest {
@Test
fun createKeysBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
Log.d("#E2E", "Initializing crosssigning for ${bobSession.myUserId.take(8)}")
cryptoTestHelper.initializeCrossSigning(bobSession)
val keysBackup = bobSession.cryptoService().keysBackupService()
@ -136,12 +138,14 @@ class KeysBackupTest : InstrumentedTest {
assertFalse(keysBackup.isEnabled())
Log.d("#E2E", "prepareKeysBackupVersion")
val megolmBackupCreationInfo =
keysBackup.prepareKeysBackupVersion(null, null)
assertFalse(keysBackup.isEnabled())
// Create the version
Log.d("#E2E", "createKeysBackupVersion")
val version = keysBackup.createKeysBackupVersion(megolmBackupCreationInfo)
// Backup must be enable now
@ -151,6 +155,7 @@ class KeysBackupTest : InstrumentedTest {
val versionResult = keysBackup.getVersion(version.version)
val trust = keysBackup.getKeysBackupTrust(versionResult!!)
Log.d("#E2E", "Check backup signatures")
assertEquals("Should have 2 signatures", 2, trust.signatures.size)
trust.signatures
@ -432,9 +437,13 @@ class KeysBackupTest : InstrumentedTest {
.keysBackupService()
.getKeysBackupTrust(keysVersionResult)
// - It must be trusted and must have 2 signatures now
// The backup should have a valid signature from that device now
assertTrue(keysBackupVersionTrust.usable)
assertEquals(2, keysBackupVersionTrust.signatures.size)
val signature = keysBackupVersionTrust.signatures
.filterIsInstance<KeysBackupVersionTrustSignature.DeviceSignature>()
.firstOrNull { it.deviceId == testData.aliceSession2.cryptoService().getMyCryptoDevice().deviceId }
assertNotNull(signature)
assertTrue(signature!!.valid)
stateObserver.stopAndCheckStates(null)
}
@ -492,9 +501,16 @@ class KeysBackupTest : InstrumentedTest {
.keysBackupService()
.getKeysBackupTrust(keysVersionResult)
// - It must be trusted and must have 2 signatures now
// // - It must be trusted and must have 2 signatures now
// assertTrue(keysBackupVersionTrust.usable)
// assertEquals(2, keysBackupVersionTrust.signatures.size)
// The backup should have a valid signature from that device now
assertTrue(keysBackupVersionTrust.usable)
assertEquals(2, keysBackupVersionTrust.signatures.size)
val signature = keysBackupVersionTrust.signatures
.filterIsInstance<KeysBackupVersionTrustSignature.DeviceSignature>()
.firstOrNull { it.deviceId == testData.aliceSession2.cryptoService().getMyCryptoDevice().deviceId }
assertNotNull(signature)
assertTrue(signature!!.valid)
stateObserver.stopAndCheckStates(null)
}
@ -590,9 +606,17 @@ class KeysBackupTest : InstrumentedTest {
.keysBackupService()
.getKeysBackupTrust(keysVersionResult)
// - It must be trusted and must have 2 signatures now
// // - It must be trusted and must have 2 signatures now
// assertTrue(keysBackupVersionTrust.usable)
// assertEquals(2, keysBackupVersionTrust.signatures.size)
// - It must be trusted and signed by current device
assertTrue(keysBackupVersionTrust.usable)
assertEquals(2, keysBackupVersionTrust.signatures.size)
val signature = keysBackupVersionTrust.signatures
.filterIsInstance<KeysBackupVersionTrustSignature.DeviceSignature>()
.firstOrNull { it.deviceId == testData.aliceSession2.cryptoService().getMyCryptoDevice().deviceId }
assertNotNull(signature)
assertTrue(signature!!.valid)
stateObserver.stopAndCheckStates(null)
}
@ -672,11 +696,16 @@ class KeysBackupTest : InstrumentedTest {
*/
@Test
fun testBackupWithPassword() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
val password = "password"
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
Assume.assumeTrue(
"Can't report progress same way in rust",
testData.cryptoTestData.firstSession.cryptoService().name() != "rust-sdk"
)
// - Restore the e2e backup with the password
val steps = ArrayList<StepProgressListener.Step>()
@ -887,6 +916,7 @@ class KeysBackupTest : InstrumentedTest {
* -> It must success
*/
@Test
@Ignore("Instable on both flavors")
fun testBackupAfterVerifyingADevice() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
@ -930,9 +960,13 @@ class KeysBackupTest : InstrumentedTest {
assertEquals("Backup state must be NotTrusted", KeysBackupState.NotTrusted, keysBackup2.getState())
assertFalse("Backup should not be enabled", keysBackup2.isEnabled())
val signatures = keysBackup2.getCurrentVersion()?.toKeysVersionResult()?.getAuthDataAsMegolmBackupAuthData()?.signatures
Log.d("#E2E", "keysBackup2 signatures: $signatures")
// - Validate the old device from the new one
cryptoTestHelper.verifyNewSession(cryptoTestData.firstSession, aliceSession2)
cryptoTestData.firstSession.cryptoService().keysBackupService().checkAndStartKeysBackup()
// -> Backup should automatically enable on the new device
suspendCancellableCoroutine<Unit> { continuation ->
val listener = object : KeysBackupStateListener {
@ -954,11 +988,11 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(oldKeyBackupVersion, aliceSession2.cryptoService().keysBackupService().currentBackupVersion)
// aliceSession2.cryptoService().keysBackupService().backupAllGroupSessions(null, it)
testHelper.retryPeriodically {
testHelper.retryWithBackoff {
keysBackup2.getTotalNumbersOfKeys() == keysBackup2.getTotalNumbersOfBackedUpKeys()
}
testHelper.retryPeriodically {
testHelper.retryWithBackoff {
aliceSession2.cryptoService().keysBackupService().getState() == KeysBackupState.ReadyToBackUp
}

View file

@ -26,6 +26,7 @@ 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
@ -65,6 +66,16 @@ class ElementAndroidToElementRMigrationTest : InstrumentedTest {
@Test
fun given_a_valid_crypto_store_realm_file_then_migration_should_be_successful() {
testMigrate(false)
}
@Test
@Ignore("We don't migrate group session for now, and it makes 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 realmName = "crypto_store_migration_16.realm"
val migration = RealmCryptoStoreMigration(object : Clock {
override fun epochMillis() = 0L
@ -86,7 +97,7 @@ class ElementAndroidToElementRMigrationTest : InstrumentedTest {
val deviceId = metaData.deviceId!!
val olmAccount = metaData.getOlmAccount()!!
val extractor = MigrateEAtoEROperation()
val extractor = MigrateEAtoEROperation(migrateGroupSessions)
val targetFile = File(configurationFactory.root, "rust-sdk")
@ -101,14 +112,16 @@ class ElementAndroidToElementRMigrationTest : InstrumentedTest {
assertTrue(crossSigningStatus.hasSelfSigning)
assertTrue(crossSigningStatus.hasUserSigning)
val inboundGroupSessionEntities = realm!!.where<OlmInboundGroupSessionEntity>().findAll()
assertEquals(inboundGroupSessionEntities.size, machine.roomKeyCounts().total.toInt())
if (migrateGroupSessions) {
val inboundGroupSessionEntities = realm!!.where<OlmInboundGroupSessionEntity>().findAll()
assertEquals(inboundGroupSessionEntities.size, machine.roomKeyCounts().total.toInt())
val backedUpInboundGroupSessionEntities = realm!!
.where<OlmInboundGroupSessionEntity>()
.equalTo(OlmInboundGroupSessionEntityFields.BACKED_UP, true)
.findAll()
assertEquals(backedUpInboundGroupSessionEntities.size, machine.roomKeyCounts().backedUp.toInt())
val backedUpInboundGroupSessionEntities = realm!!
.where<OlmInboundGroupSessionEntity>()
.equalTo(OlmInboundGroupSessionEntityFields.BACKED_UP, true)
.findAll()
assertEquals(backedUpInboundGroupSessionEntities.size, machine.roomKeyCounts().backedUp.toInt())
}
}
// @Test

View file

@ -20,11 +20,11 @@ import io.realm.RealmConfiguration
import timber.log.Timber
import java.io.File
class MigrateEAtoEROperation {
class MigrateEAtoEROperation(private val migrateGroupSessions: Boolean = false) {
fun execute(cryptoRealm: RealmConfiguration, sessionFilesDir: File, passphrase: String?): File {
// to remove unused warning
Timber.v("Not used in kotlin crypto $cryptoRealm ${"*".repeat(passphrase?.length ?: 0)}")
Timber.v("Not used in kotlin crypto $cryptoRealm ${"*".repeat(passphrase?.length ?: 0)} lazy:$migrateGroupSessions")
// no op in kotlinCrypto
return sessionFilesDir
}

View file

@ -82,6 +82,7 @@ import org.matrix.rustcomponents.sdk.crypto.RequestType
import org.matrix.rustcomponents.sdk.crypto.RoomKeyCounts
import org.matrix.rustcomponents.sdk.crypto.ShieldColor
import org.matrix.rustcomponents.sdk.crypto.ShieldState
import org.matrix.rustcomponents.sdk.crypto.SignatureVerification
import org.matrix.rustcomponents.sdk.crypto.setLogger
import timber.log.Timber
import java.io.File
@ -916,7 +917,7 @@ internal class OlmMachine @Inject constructor(
}
@Throws(CryptoStoreException::class)
suspend fun checkAuthDataSignature(authData: KeysAlgorithmAndData): Boolean {
suspend fun checkAuthDataSignature(authData: KeysAlgorithmAndData): SignatureVerification {
return withContext(coroutineDispatchers.computation) {
val adapter = moshi
.newBuilder()
@ -929,7 +930,7 @@ internal class OlmMachine @Inject constructor(
)
)
inner.verifyBackup(serializedAuthData).trusted
inner.verifyBackup(serializedAuthData)
}
}
}

View file

@ -28,10 +28,13 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.crypto.network.OutgoingRequestsProcessor
import org.matrix.rustcomponents.sdk.crypto.Request
import javax.inject.Inject
internal class RustCrossSigningService @Inject constructor(
private val olmMachine: OlmMachine,
private val outgoingRequestsProcessor: OutgoingRequestsProcessor,
private val computeShieldForGroup: ComputeShieldForGroupUseCase
) : CrossSigningService {
@ -78,6 +81,10 @@ internal class RustCrossSigningService @Inject constructor(
* Users needs to enter credentials
*/
override suspend fun initializeCrossSigning(uiaInterceptor: UserInteractiveAuthInterceptor?) {
// ensure our keys are sent before initialising
outgoingRequestsProcessor.processOutgoingRequests(olmMachine) {
it is Request.KeysUpload
}
olmMachine.bootstrapCrossSigning(uiaInterceptor)
}

View file

@ -43,6 +43,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrust
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrustSignature
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAuthData
@ -67,6 +68,8 @@ 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.SignatureState
import org.matrix.rustcomponents.sdk.crypto.SignatureVerification
import timber.log.Timber
import java.security.InvalidParameterException
import javax.inject.Inject
@ -266,14 +269,56 @@ internal class RustKeyBackupService @Inject constructor(
private suspend fun checkBackupTrust(algAndData: KeysAlgorithmAndData?): KeysBackupVersionTrust {
if (algAndData == null) return KeysBackupVersionTrust(usable = false)
try {
val isTrusted = olmMachine.checkAuthDataSignature(algAndData)
return KeysBackupVersionTrust(isTrusted)
val authData = olmMachine.checkAuthDataSignature(algAndData)
val signatures = authData.mapRustToAPI()
return KeysBackupVersionTrust(authData.trusted, signatures)
} catch (failure: Throwable) {
Timber.w(failure, "Failed to trust backup")
return KeysBackupVersionTrust(usable = false)
}
}
private suspend fun SignatureVerification.mapRustToAPI(): List<KeysBackupVersionTrustSignature> {
val signatures = mutableListOf<KeysBackupVersionTrustSignature>()
// signature state of own device
val ownDeviceState = this.deviceSignature
if (ownDeviceState != SignatureState.MISSING && ownDeviceState != SignatureState.INVALID) {
// we can add it
signatures.add(
KeysBackupVersionTrustSignature.DeviceSignature(
olmMachine.deviceId(),
olmMachine.getCryptoDeviceInfo(olmMachine.userId(), olmMachine.deviceId()),
ownDeviceState == SignatureState.VALID_AND_TRUSTED
)
)
}
// signature state of our own identity
val ownIdentityState = this.userIdentitySignature
if (ownIdentityState != SignatureState.MISSING && ownIdentityState != SignatureState.INVALID) {
// we can add it
val masterKey = olmMachine.getIdentity(olmMachine.userId())?.toMxCrossSigningInfo()?.masterKey()
signatures.add(
KeysBackupVersionTrustSignature.UserSignature(
masterKey?.unpaddedBase64PublicKey,
masterKey,
ownIdentityState == SignatureState.VALID_AND_TRUSTED
)
)
}
signatures.addAll(
this.otherDevicesSignatures
.filter { it.value == SignatureState.VALID_AND_TRUSTED || it.value == SignatureState.VALID_BUT_NOT_TRUSTED }
.map {
KeysBackupVersionTrustSignature.DeviceSignature(
it.key,
olmMachine.getCryptoDeviceInfo(olmMachine.userId(), it.key),
ownDeviceState == SignatureState.VALID_AND_TRUSTED
)
}
)
return signatures
}
override suspend fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult): KeysBackupVersionTrust {
return withContext(coroutineDispatchers.crypto) {
checkBackupTrust(keysBackupVersion)
@ -341,7 +386,7 @@ internal class RustKeyBackupService @Inject constructor(
val authData = getMegolmBackupAuthData(keysBackupData)
when {
authData == null -> {
authData == null -> {
Timber.w("isValidRecoveryKeyForKeysBackupVersion: Key backup is missing required data")
throw IllegalArgumentException("Missing element")
}
@ -349,7 +394,7 @@ internal class RustKeyBackupService @Inject constructor(
Timber.w("isValidRecoveryKeyForKeysBackupVersion: Public keys mismatch")
throw IllegalArgumentException("Invalid recovery key or password")
}
else -> {
else -> {
// This case is fine, the public key on the server matches the public key the
// recovery key produced.
}
@ -428,10 +473,10 @@ internal class RustKeyBackupService @Inject constructor(
roomId != null && sessionId != null -> {
sender.downloadBackedUpKeys(version, roomId, sessionId)
}
roomId != null -> {
roomId != null -> {
sender.downloadBackedUpKeys(version, roomId)
}
else -> {
else -> {
sender.downloadBackedUpKeys(version)
}
}
@ -570,20 +615,24 @@ internal class RustKeyBackupService @Inject constructor(
}
}
override suspend fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult,
recoveryKey: IBackupRecoveryKey,
roomId: String?,
sessionId: String?,
stepProgressListener: StepProgressListener?): ImportRoomKeysResult {
override suspend fun restoreKeysWithRecoveryKey(
keysVersionResult: KeysVersionResult,
recoveryKey: IBackupRecoveryKey,
roomId: String?,
sessionId: String?,
stepProgressListener: StepProgressListener?
): ImportRoomKeysResult {
Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}")
return restoreBackup(keysVersionResult, recoveryKey, roomId, sessionId, stepProgressListener)
}
override suspend fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult,
password: String,
roomId: String?,
sessionId: String?,
stepProgressListener: StepProgressListener?): ImportRoomKeysResult {
override suspend fun restoreKeyBackupWithPassword(
keysBackupVersion: KeysVersionResult,
password: String,
roomId: String?,
sessionId: String?,
stepProgressListener: StepProgressListener?
): ImportRoomKeysResult {
Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}")
val recoveryKey = withContext(coroutineDispatchers.crypto) {
recoveryKeyFromPassword(password, keysBackupVersion)
@ -752,13 +801,13 @@ internal class RustKeyBackupService @Inject constructor(
val authData = getMegolmBackupAuthData(keysBackupData)
return when {
authData == null -> {
authData == null -> {
throw IllegalArgumentException("recoveryKeyFromPassword: invalid parameter")
}
authData.privateKeySalt.isNullOrBlank() || authData.privateKeyIterations == null -> {
throw java.lang.IllegalArgumentException("recoveryKeyFromPassword: Salt and/or iterations not found in key backup auth data")
}
else -> {
else -> {
BackupRecoveryKey.fromPassphrase(password, authData.privateKeySalt, authData.privateKeyIterations)
}
}
@ -811,7 +860,7 @@ internal class RustKeyBackupService @Inject constructor(
suspend fun maybeBackupKeys() {
withContext(coroutineDispatchers.crypto) {
when {
isStuck() -> {
isStuck() -> {
// If not already done, or in error case, check for a valid backup version on the homeserver.
// If there is one, maybeBackupKeys will be called again.
checkAndStartKeysBackup()
@ -829,7 +878,7 @@ internal class RustKeyBackupService @Inject constructor(
tryOrNull("AUTO backup failed") { backupKeys() }
}
}
else -> {
else -> {
Timber.v("maybeBackupKeys: Skip it because state: ${getState()}")
}
}
@ -907,7 +956,7 @@ internal class RustKeyBackupService @Inject constructor(
// is available on the homeserver
checkAndStartKeysBackup()
}
else ->
else ->
// Come back to the ready state so that we will retry on the next received key
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
}

View file

@ -38,7 +38,7 @@ import kotlin.system.measureTimeMillis
private val charset = Charset.forName("UTF-8")
internal class ExtractMigrationDataUseCase {
internal class ExtractMigrationDataUseCase(val migrateGroupSessions: Boolean = false) {
fun extractData(realm: Realm, importPartial: ((MigrationData) -> Unit)) {
return try {
@ -143,35 +143,37 @@ internal class ExtractMigrationDataUseCase {
Timber.i("Migration: rust import time $writeTime")
}
// We don't migrate outbound session directly after migration
// We don't migrate outbound session by default directly after migration
// We are going to do it lazyly when decryption fails
// var migratedInboundGroupSessionCount = 0
// readTime = 0
// writeTime = 0
// measureTimeMillis {
// realm.where<OlmInboundGroupSessionEntity>()
// .findAll()
// .chunked(chunkSize) { chunk ->
// val export: List<PickledInboundGroupSession>
// measureTimeMillis {
// export = chunk.mapNotNull { it.toPickledInboundGroupSession(pickleKey) }
// }.also {
// readTime += it
// }
// migratedInboundGroupSessionCount+=export.size
// measureTimeMillis {
// importPartial(
// baseExtract.copy(inboundGroupSessions = export)
// )
// }.also {
// writeTime += it
// }
// }
// }.also {
// Timber.i("Migration: took $it ms to migrate $migratedInboundGroupSessionCount group sessions")
// Timber.i("Migration: extract time $readTime")
// Timber.i("Migration: rust import time $writeTime")
// }
if (migrateGroupSessions) {
var migratedInboundGroupSessionCount = 0
readTime = 0
writeTime = 0
measureTimeMillis {
realm.where<OlmInboundGroupSessionEntity>()
.findAll()
.chunked(chunkSize) { chunk ->
val export: List<PickledInboundGroupSession>
measureTimeMillis {
export = chunk.mapNotNull { it.toPickledInboundGroupSession(pickleKey) }
}.also {
readTime += it
}
migratedInboundGroupSessionCount += export.size
measureTimeMillis {
importPartial(
baseExtract.copy(inboundGroupSessions = export)
)
}.also {
writeTime += it
}
}
}.also {
Timber.i("Migration: took $it ms to migrate $migratedInboundGroupSessionCount group sessions")
Timber.i("Migration: extract time $readTime")
Timber.i("Migration: rust import time $writeTime")
}
}
// return baseExtract
}

View file

@ -23,14 +23,14 @@ import org.matrix.rustcomponents.sdk.crypto.ProgressListener
import timber.log.Timber
import java.io.File
class MigrateEAtoEROperation {
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()
val extractMigrationData = ExtractMigrationDataUseCase(migrateGroupSessions)
val hasExitingData = extractMigrationData.hasExistingData(cryptoRealm)
if (!hasExitingData) return rustFilesDir