Merge pull request #5703 from vector-im/feature/bma/avoid_error_log

Feature/bma/avoid error log
This commit is contained in:
Benoit Marty 2022-04-06 15:08:20 +02:00 committed by GitHub
commit 9c1cdf6488
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 253 additions and 161 deletions

1
changelog.d/5703.misc Normal file
View File

@ -0,0 +1 @@
Reduce error logs

1
changelog.d/5703.sdk Normal file
View File

@ -0,0 +1 @@
KeysBackupService.getCurrentVersion takes a new type `KeysBackupLastVersionResult` in the callback.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 New Vector Ltd * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 New Vector Ltd * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -39,10 +39,11 @@ import org.matrix.android.sdk.common.TestConstants
import org.matrix.android.sdk.common.TestMatrixCallback import org.matrix.android.sdk.common.TestMatrixCallback
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupLastVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.toKeysVersionResult
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
import java.util.Collections import java.util.Collections
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
@ -403,9 +404,9 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
// - Retrieve the last version from the server // - Retrieve the last version from the server
val keysVersionResult = testHelper.doSync<KeysVersionResult?> { val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> {
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it) testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
} }.toKeysVersionResult()
// - It must be the same // - It must be the same
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version) assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
@ -463,9 +464,9 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
// - Retrieve the last version from the server // - Retrieve the last version from the server
val keysVersionResult = testHelper.doSync<KeysVersionResult?> { val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> {
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it) testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
} }.toKeysVersionResult()
// - It must be the same // - It must be the same
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version) assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
@ -565,9 +566,9 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
// - Retrieve the last version from the server // - Retrieve the last version from the server
val keysVersionResult = testHelper.doSync<KeysVersionResult?> { val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> {
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it) testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
} }.toKeysVersionResult()
// - It must be the same // - It must be the same
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version) assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
@ -835,9 +836,9 @@ class KeysBackupTest : InstrumentedTest {
keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup) keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
// Get key backup version from the homeserver // Get key backup version from the homeserver
val keysVersionResult = testHelper.doSync<KeysVersionResult?> { val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> {
keysBackup.getCurrentVersion(it) keysBackup.getCurrentVersion(it)
} }.toKeysVersionResult()
// - Check the returned KeyBackupVersion is trusted // - Check the returned KeyBackupVersion is trusted
val keysBackupVersionTrust = testHelper.doSync<KeysBackupVersionTrust> { val keysBackupVersionTrust = testHelper.doSync<KeysBackupVersionTrust> {

View File

@ -29,6 +29,11 @@ fun Throwable.is401() =
httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED && /* 401 */ httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED && /* 401 */
error.code == MatrixError.M_UNAUTHORIZED error.code == MatrixError.M_UNAUTHORIZED
fun Throwable.is404() =
this is Failure.ServerError &&
httpCode == HttpsURLConnection.HTTP_NOT_FOUND && /* 404 */
error.code == MatrixError.M_NOT_FOUND
fun Throwable.isTokenError() = fun Throwable.isTokenError() =
this is Failure.ServerError && this is Failure.ServerError &&
(error.code == MatrixError.M_UNKNOWN_TOKEN || (error.code == MatrixError.M_UNKNOWN_TOKEN ||

View File

@ -19,6 +19,7 @@ package org.matrix.android.sdk.api.session.crypto.keysbackup
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.api.listeners.StepProgressListener import org.matrix.android.sdk.api.listeners.StepProgressListener
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupLastVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
@ -31,9 +32,9 @@ interface KeysBackupService {
* Retrieve the current version of the backup from the homeserver * Retrieve the current version of the backup from the homeserver
* *
* It can be different than keysBackupVersion. * It can be different than keysBackupVersion.
* @param callback onSuccess(null) will be called if there is no backup on the server * @param callback Asynchronous callback
*/ */
fun getCurrentVersion(callback: MatrixCallback<KeysVersionResult?>) fun getCurrentVersion(callback: MatrixCallback<KeysBackupLastVersionResult>)
/** /**
* Create a new keys backup version and enable it, using the information return from [prepareKeysBackupVersion]. * Create a new keys backup version and enable it, using the information return from [prepareKeysBackupVersion].

View File

@ -202,7 +202,9 @@ data class Event(
fun getDecryptedTextSummary(): String? { fun getDecryptedTextSummary(): String? {
if (isRedacted()) return "Message Deleted" if (isRedacted()) return "Message Deleted"
val text = getDecryptedValue() ?: run { val text = getDecryptedValue() ?: run {
if (isPoll()) { return getPollQuestion() ?: "created a poll." } if (isPoll()) {
return getPollQuestion() ?: "created a poll."
}
return null return null
} }
@ -300,57 +302,67 @@ data class Event(
} }
} }
/**
* Return the value of "content.msgtype", if the Event type is "m.room.message"
* and if the content has it, and if it is a String
*/
fun Event.getMsgType(): String? {
if (getClearType() != EventType.MESSAGE) return null
return getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY) as? String
}
fun Event.isTextMessage(): Boolean { fun Event.isTextMessage(): Boolean {
return getClearType() == EventType.MESSAGE && return when (getMsgType()) {
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) { MessageType.MSGTYPE_TEXT,
MessageType.MSGTYPE_TEXT, MessageType.MSGTYPE_EMOTE,
MessageType.MSGTYPE_EMOTE, MessageType.MSGTYPE_NOTICE -> true
MessageType.MSGTYPE_NOTICE -> true else -> false
else -> false }
}
} }
fun Event.isImageMessage(): Boolean { fun Event.isImageMessage(): Boolean {
return getClearType() == EventType.MESSAGE && return when (getMsgType()) {
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) { MessageType.MSGTYPE_IMAGE -> true
MessageType.MSGTYPE_IMAGE -> true else -> false
else -> false }
}
} }
fun Event.isVideoMessage(): Boolean { fun Event.isVideoMessage(): Boolean {
return getClearType() == EventType.MESSAGE && return when (getMsgType()) {
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) { MessageType.MSGTYPE_VIDEO -> true
MessageType.MSGTYPE_VIDEO -> true else -> false
else -> false }
}
} }
fun Event.isAudioMessage(): Boolean { fun Event.isAudioMessage(): Boolean {
return getClearType() == EventType.MESSAGE && return when (getMsgType()) {
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) { MessageType.MSGTYPE_AUDIO -> true
MessageType.MSGTYPE_AUDIO -> true else -> false
else -> false }
}
} }
fun Event.isFileMessage(): Boolean { fun Event.isFileMessage(): Boolean {
return getClearType() == EventType.MESSAGE && return when (getMsgType()) {
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) { MessageType.MSGTYPE_FILE -> true
MessageType.MSGTYPE_FILE -> true else -> false
else -> false }
}
} }
fun Event.isAttachmentMessage(): Boolean { fun Event.isAttachmentMessage(): Boolean {
return getClearType() == EventType.MESSAGE && return when (getMsgType()) {
when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) { MessageType.MSGTYPE_IMAGE,
MessageType.MSGTYPE_IMAGE, MessageType.MSGTYPE_AUDIO,
MessageType.MSGTYPE_AUDIO, MessageType.MSGTYPE_VIDEO,
MessageType.MSGTYPE_VIDEO, MessageType.MSGTYPE_FILE -> true
MessageType.MSGTYPE_FILE -> true else -> false
else -> false }
} }
fun Event.isLocationMessage(): Boolean {
return when (getMsgType()) {
MessageType.MSGTYPE_LOCATION -> true
else -> false
}
} }
fun Event.isPoll(): Boolean = getClearType() in EventType.POLL_START || getClearType() in EventType.POLL_END fun Event.isPoll(): Boolean = getClearType() in EventType.POLL_START || getClearType() in EventType.POLL_END

View File

@ -41,6 +41,7 @@ import org.matrix.android.sdk.internal.crypto.MegolmSessionData
import org.matrix.android.sdk.internal.crypto.ObjectSigner import org.matrix.android.sdk.internal.crypto.ObjectSigner
import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupLastVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrustSignature import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrustSignature
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData
@ -54,6 +55,7 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.RoomKeysBackupData import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.RoomKeysBackupData
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.UpdateKeysBackupVersionBody import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.UpdateKeysBackupVersionBody
import org.matrix.android.sdk.internal.crypto.keysbackup.model.toKeysVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.CreateKeysBackupVersionTask import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.CreateKeysBackupVersionTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DeleteBackupTask import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DeleteBackupTask
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DeleteRoomSessionDataTask import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DeleteRoomSessionDataTask
@ -586,21 +588,28 @@ internal class DefaultKeysBackupService @Inject constructor(
cryptoCoroutineScope.launch(coroutineDispatchers.main) { cryptoCoroutineScope.launch(coroutineDispatchers.main) {
try { try {
val keysBackupVersion = getKeysBackupLastVersionTask.execute(Unit) when (val keysBackupLastVersionResult = getKeysBackupLastVersionTask.execute(Unit)) {
val recoveryKey = computeRecoveryKey(secret.fromBase64()) KeysBackupLastVersionResult.NoKeysBackup -> {
if (isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)) { Timber.d("No keys backup found")
awaitCallback<Unit> {
trustKeysBackupVersion(keysBackupVersion, true, it)
} }
val importResult = awaitCallback<ImportRoomKeysResult> { is KeysBackupLastVersionResult.KeysBackup -> {
restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, null, null, null, it) val keysBackupVersion = keysBackupLastVersionResult.keysVersionResult
val recoveryKey = computeRecoveryKey(secret.fromBase64())
if (isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)) {
awaitCallback<Unit> {
trustKeysBackupVersion(keysBackupVersion, true, it)
}
val importResult = awaitCallback<ImportRoomKeysResult> {
restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, null, null, null, it)
}
withContext(coroutineDispatchers.crypto) {
cryptoStore.saveBackupRecoveryKey(recoveryKey, keysBackupVersion.version)
}
Timber.i("onSecretKeyGossip: Recovered keys $importResult")
} else {
Timber.e("onSecretKeyGossip: Recovery key is not valid ${keysBackupVersion.version}")
}
} }
withContext(coroutineDispatchers.crypto) {
cryptoStore.saveBackupRecoveryKey(recoveryKey, keysBackupVersion.version)
}
Timber.i("onSecretKeyGossip: Recovered keys ${importResult.successfullyNumberOfImportedKeys} out of ${importResult.totalNumberOfKeys}")
} else {
Timber.e("onSecretKeyGossip: Recovery key is not valid ${keysBackupVersion.version}")
} }
} catch (failure: Throwable) { } catch (failure: Throwable) {
Timber.e("onSecretKeyGossip: failed to trust key backup version ${keysBackupVersion?.version}") Timber.e("onSecretKeyGossip: failed to trust key backup version ${keysBackupVersion?.version}")
@ -875,63 +884,49 @@ internal class DefaultKeysBackupService @Inject constructor(
.executeBy(taskExecutor) .executeBy(taskExecutor)
} }
override fun getCurrentVersion(callback: MatrixCallback<KeysVersionResult?>) { override fun getCurrentVersion(callback: MatrixCallback<KeysBackupLastVersionResult>) {
getKeysBackupLastVersionTask getKeysBackupLastVersionTask
.configureWith { .configureWith {
this.callback = object : MatrixCallback<KeysVersionResult> { this.callback = callback
override fun onSuccess(data: KeysVersionResult) {
callback.onSuccess(data)
}
override fun onFailure(failure: Throwable) {
if (failure is Failure.ServerError &&
failure.error.code == MatrixError.M_NOT_FOUND) {
// Workaround because the homeserver currently returns M_NOT_FOUND when there is no key backup
callback.onSuccess(null)
} else {
// Transmit the error
callback.onFailure(failure)
}
}
}
} }
.executeBy(taskExecutor) .executeBy(taskExecutor)
} }
override fun forceUsingLastVersion(callback: MatrixCallback<Boolean>) { override fun forceUsingLastVersion(callback: MatrixCallback<Boolean>) {
getCurrentVersion(object : MatrixCallback<KeysVersionResult?> { getCurrentVersion(object : MatrixCallback<KeysBackupLastVersionResult> {
override fun onSuccess(data: KeysVersionResult?) { override fun onSuccess(data: KeysBackupLastVersionResult) {
val localBackupVersion = keysBackupVersion?.version val localBackupVersion = keysBackupVersion?.version
val serverBackupVersion = data?.version when (data) {
KeysBackupLastVersionResult.NoKeysBackup -> {
if (serverBackupVersion == null) { if (localBackupVersion == null) {
if (localBackupVersion == null) { // No backup on the server, and backup is not active
// No backup on the server, and backup is not active
callback.onSuccess(true)
} else {
// No backup on the server, and we are currently backing up, so stop backing up
callback.onSuccess(false)
resetKeysBackupData()
keysBackupVersion = null
keysBackupStateManager.state = KeysBackupState.Disabled
}
} else {
if (localBackupVersion == null) {
// backup on the server, and backup is not active
callback.onSuccess(false)
// Do a check
checkAndStartWithKeysBackupVersion(data)
} else {
// Backup on the server, and we are currently backing up, compare version
if (localBackupVersion == serverBackupVersion) {
// We are already using the last version of the backup
callback.onSuccess(true) callback.onSuccess(true)
} else { } else {
// We are not using the last version, so delete the current version we are using on the server // No backup on the server, and we are currently backing up, so stop backing up
callback.onSuccess(false) callback.onSuccess(false)
resetKeysBackupData()
keysBackupVersion = null
keysBackupStateManager.state = KeysBackupState.Disabled
}
}
is KeysBackupLastVersionResult.KeysBackup -> {
if (localBackupVersion == null) {
// backup on the server, and backup is not active
callback.onSuccess(false)
// Do a check
checkAndStartWithKeysBackupVersion(data.keysVersionResult)
} else {
// Backup on the server, and we are currently backing up, compare version
if (localBackupVersion == data.keysVersionResult.version) {
// We are already using the last version of the backup
callback.onSuccess(true)
} else {
// We are not using the last version, so delete the current version we are using on the server
callback.onSuccess(false)
// This will automatically check for the last version then // This will automatically check for the last version then
deleteBackup(localBackupVersion, null) deleteBackup(localBackupVersion, null)
}
} }
} }
} }
@ -954,9 +949,9 @@ internal class DefaultKeysBackupService @Inject constructor(
keysBackupVersion = null keysBackupVersion = null
keysBackupStateManager.state = KeysBackupState.CheckingBackUpOnHomeserver keysBackupStateManager.state = KeysBackupState.CheckingBackUpOnHomeserver
getCurrentVersion(object : MatrixCallback<KeysVersionResult?> { getCurrentVersion(object : MatrixCallback<KeysBackupLastVersionResult> {
override fun onSuccess(data: KeysVersionResult?) { override fun onSuccess(data: KeysBackupLastVersionResult) {
checkAndStartWithKeysBackupVersion(data) checkAndStartWithKeysBackupVersion(data.toKeysVersionResult())
} }
override fun onFailure(failure: Throwable) { override fun onFailure(failure: Throwable) {

View File

@ -0,0 +1,30 @@
/*
* 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.keysbackup.model
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
sealed interface KeysBackupLastVersionResult {
// No Keys backup found (404 error)
object NoKeysBackup : KeysBackupLastVersionResult
data class KeysBackup(val keysVersionResult: KeysVersionResult) : KeysBackupLastVersionResult
}
fun KeysBackupLastVersionResult.toKeysVersionResult(): KeysVersionResult? = when (this) {
is KeysBackupLastVersionResult.KeysBackup -> keysVersionResult
KeysBackupLastVersionResult.NoKeysBackup -> null
}

View File

@ -16,23 +16,34 @@
package org.matrix.android.sdk.internal.crypto.keysbackup.tasks package org.matrix.android.sdk.internal.crypto.keysbackup.tasks
import org.matrix.android.sdk.api.failure.is404
import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupLastVersionResult
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.task.Task
import javax.inject.Inject import javax.inject.Inject
internal interface GetKeysBackupLastVersionTask : Task<Unit, KeysVersionResult> internal interface GetKeysBackupLastVersionTask : Task<Unit, KeysBackupLastVersionResult>
internal class DefaultGetKeysBackupLastVersionTask @Inject constructor( internal class DefaultGetKeysBackupLastVersionTask @Inject constructor(
private val roomKeysApi: RoomKeysApi, private val roomKeysApi: RoomKeysApi,
private val globalErrorReceiver: GlobalErrorReceiver private val globalErrorReceiver: GlobalErrorReceiver
) : GetKeysBackupLastVersionTask { ) : GetKeysBackupLastVersionTask {
override suspend fun execute(params: Unit): KeysVersionResult { override suspend fun execute(params: Unit): KeysBackupLastVersionResult {
return executeRequest(globalErrorReceiver) { return try {
roomKeysApi.getKeysBackupLastVersion() val keysVersionResult = executeRequest(globalErrorReceiver) {
roomKeysApi.getKeysBackupLastVersion()
}
KeysBackupLastVersionResult.KeysBackup(keysVersionResult)
} catch (throwable: Throwable) {
if (throwable.is404()) {
KeysBackupLastVersionResult.NoKeysBackup
} else {
// Propagate other errors
throw throwable
}
} }
} }
} }

View File

@ -66,7 +66,7 @@ echo "Search for forbidden patterns in code..."
${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_code.txt \ ${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_code.txt \
./matrix-sdk-android/src/main/java \ ./matrix-sdk-android/src/main/java \
./matrix-sdk-android-rx/src/main/java \ ./matrix-sdk-android-flow/src/main/java \
./vector/src/main/java \ ./vector/src/main/java \
./vector/src/debug/java \ ./vector/src/debug/java \
./vector/src/release/java \ ./vector/src/release/java \
@ -80,7 +80,7 @@ echo "Search for forbidden patterns specific for SDK code..."
${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_code_sdk.txt \ ${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_code_sdk.txt \
./matrix-sdk-android/src \ ./matrix-sdk-android/src \
./matrix-sdk-android-rx/src ./matrix-sdk-android-flow/src
resultForbiddenStringInCodeSdk=$? resultForbiddenStringInCodeSdk=$?
@ -131,7 +131,7 @@ echo "Search for kotlin files with more than ${maxLines} lines..."
${checkLongFilesScript} ${maxLines} \ ${checkLongFilesScript} ${maxLines} \
./matrix-sdk-android/src/main/java \ ./matrix-sdk-android/src/main/java \
./matrix-sdk-android-rx/src/main/java \ ./matrix-sdk-android-flow/src/main/java \
./vector/src/androidTest/java \ ./vector/src/androidTest/java \
./vector/src/debug/java \ ./vector/src/debug/java \
./vector/src/fdroid/java \ ./vector/src/fdroid/java \

View File

@ -33,7 +33,7 @@ import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.glide.GlideApp import im.vector.app.core.glide.GlideApp
import im.vector.app.features.displayname.getBestName import im.vector.app.features.displayname.getBestName
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider import im.vector.app.features.home.room.detail.timeline.action.LocationUiData
import im.vector.app.features.home.room.detail.timeline.item.BindingOptions import im.vector.app.features.home.room.detail.timeline.item.BindingOptions
import im.vector.app.features.home.room.detail.timeline.tools.findPillsAndProcess import im.vector.app.features.home.room.detail.timeline.tools.findPillsAndProcess
import im.vector.app.features.media.ImageContentRenderer import im.vector.app.features.media.ImageContentRenderer
@ -71,13 +71,7 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel<BottomSheetMessa
var time: String? = null var time: String? = null
@EpoxyAttribute @EpoxyAttribute
var locationUrl: String? = null var locationUiData: LocationUiData? = null
@EpoxyAttribute
var locationPinProvider: LocationPinProvider? = null
@EpoxyAttribute
var locationOwnerId: String? = null
@EpoxyAttribute @EpoxyAttribute
var movementMethod: MovementMethod? = null var movementMethod: MovementMethod? = null
@ -101,18 +95,15 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel<BottomSheetMessa
body.charSequence.findPillsAndProcess(coroutineScope) { it.bind(holder.body) } body.charSequence.findPillsAndProcess(coroutineScope) { it.bind(holder.body) }
holder.timestamp.setTextOrHide(time) holder.timestamp.setTextOrHide(time)
if (locationUrl == null) { holder.body.isVisible = locationUiData == null
holder.body.isVisible = true holder.mapViewContainer.isVisible = locationUiData != null
holder.mapViewContainer.isVisible = false locationUiData?.let { safeLocationUiData ->
} else {
holder.body.isVisible = false
holder.mapViewContainer.isVisible = true
GlideApp.with(holder.staticMapImageView) GlideApp.with(holder.staticMapImageView)
.load(locationUrl) .load(safeLocationUiData.locationUrl)
.apply(RequestOptions.centerCropTransform()) .apply(RequestOptions.centerCropTransform())
.into(holder.staticMapImageView) .into(holder.staticMapImageView)
locationPinProvider?.create(locationOwnerId) { pinDrawable -> safeLocationUiData.locationPinProvider.create(safeLocationUiData.locationOwnerId) { pinDrawable ->
GlideApp.with(holder.staticMapPinImageView) GlideApp.with(holder.staticMapPinImageView)
.load(pinDrawable) .load(pinDrawable)
.into(holder.staticMapPinImageView) .into(holder.staticMapPinImageView)

View File

@ -32,7 +32,9 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_S
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupLastVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.toKeysVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.util.computeRecoveryKey import org.matrix.android.sdk.internal.crypto.keysbackup.util.computeRecoveryKey
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.android.sdk.internal.util.awaitCallback
@ -117,9 +119,9 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
val version = awaitCallback<KeysVersionResult?> { val version = awaitCallback<KeysBackupLastVersionResult> {
keysBackup.getCurrentVersion(it) keysBackup.getCurrentVersion(it)
} }.toKeysVersionResult()
if (version?.version == null) { if (version?.version == null) {
loadingEvent.postValue(null) loadingEvent.postValue(null)
_keyVersionResultError.postValue(LiveEvent(stringProvider.getString(R.string.keys_backup_get_version_error, ""))) _keyVersionResultError.postValue(LiveEvent(stringProvider.getString(R.string.keys_backup_get_version_error, "")))

View File

@ -27,9 +27,10 @@ import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupLastVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.toKeysVersionResult
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -150,9 +151,9 @@ class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() {
creatingBackupError.value = null creatingBackupError.value = null
keysBackup.getCurrentVersion(object : MatrixCallback<KeysVersionResult?> { keysBackup.getCurrentVersion(object : MatrixCallback<KeysBackupLastVersionResult> {
override fun onSuccess(data: KeysVersionResult?) { override fun onSuccess(data: KeysBackupLastVersionResult) {
if (data?.version.isNullOrBlank() || forceOverride) { if (data.toKeysVersionResult()?.version.isNullOrBlank() || forceOverride) {
processOnCreate() processOnCreate()
} else { } else {
loadingStatus.value = null loadingStatus.value = null

View File

@ -33,9 +33,10 @@ import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageServi
import org.matrix.android.sdk.api.session.securestorage.SsssKeyCreationInfo import org.matrix.android.sdk.api.session.securestorage.SsssKeyCreationInfo
import org.matrix.android.sdk.api.session.securestorage.SsssKeySpec import org.matrix.android.sdk.api.session.securestorage.SsssKeySpec
import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupLastVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.toKeysVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey
import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.android.sdk.internal.util.awaitCallback
import timber.log.Timber import timber.log.Timber
@ -221,10 +222,9 @@ class BootstrapCrossSigningTask @Inject constructor(
Timber.d("## BootstrapCrossSigningTask: Creating 4S - Checking megolm backup") Timber.d("## BootstrapCrossSigningTask: Creating 4S - Checking megolm backup")
// First ensure that in sync // First ensure that in sync
var serverVersion = awaitCallback<KeysVersionResult?> { var serverVersion = awaitCallback<KeysBackupLastVersionResult> {
session.cryptoService().keysBackupService().getCurrentVersion(it) session.cryptoService().keysBackupService().getCurrentVersion(it)
} }.toKeysVersionResult()
val knownMegolmSecret = session.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo() val knownMegolmSecret = session.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()
val isMegolmBackupSecretKnown = knownMegolmSecret != null && knownMegolmSecret.version == serverVersion?.version val isMegolmBackupSecretKnown = knownMegolmSecret != null && knownMegolmSecret.version == serverVersion?.version
val shouldCreateKeyBackup = serverVersion == null || val shouldCreateKeyBackup = serverVersion == null ||
@ -236,9 +236,9 @@ class BootstrapCrossSigningTask @Inject constructor(
awaitCallback<Unit> { awaitCallback<Unit> {
session.cryptoService().keysBackupService().deleteBackup(serverVersion!!.version, it) session.cryptoService().keysBackupService().deleteBackup(serverVersion!!.version, it)
} }
serverVersion = awaitCallback { serverVersion = awaitCallback<KeysBackupLastVersionResult> {
session.cryptoService().keysBackupService().getCurrentVersion(it) session.cryptoService().keysBackupService().getCurrentVersion(it)
} }.toKeysVersionResult()
} }
Timber.d("## BootstrapCrossSigningTask: Creating 4S - Create megolm backup") Timber.d("## BootstrapCrossSigningTask: Creating 4S - Create megolm backup")

View File

@ -45,7 +45,9 @@ import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupLastVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.toKeysVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey
import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.android.sdk.internal.util.awaitCallback
@ -103,9 +105,9 @@ class BootstrapSharedViewModel @AssistedInject constructor(
// We need to check if there is an existing backup // We need to check if there is an existing backup
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val version = awaitCallback<KeysVersionResult?> { val version = awaitCallback<KeysBackupLastVersionResult> {
session.cryptoService().keysBackupService().getCurrentVersion(it) session.cryptoService().keysBackupService().getCurrentVersion(it)
} }.toKeysVersionResult()
if (version == null) { if (version == null) {
// we just resume plain bootstrap // we just resume plain bootstrap
doesKeyBackupExist = false doesKeyBackupExist = false

View File

@ -52,7 +52,8 @@ import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupLastVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.model.toKeysVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.util.computeRecoveryKey import org.matrix.android.sdk.internal.crypto.keysbackup.util.computeRecoveryKey
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.android.sdk.internal.util.awaitCallback
@ -426,9 +427,9 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
Timber.v("## Keybackup secret not restored from SSSS") Timber.v("## Keybackup secret not restored from SSSS")
} }
val version = awaitCallback<KeysVersionResult?> { val version = awaitCallback<KeysBackupLastVersionResult> {
session.cryptoService().keysBackupService().getCurrentVersion(it) session.cryptoService().keysBackupService().getCurrentVersion(it)
} ?: return@launch }.toKeysVersionResult() ?: return@launch
awaitCallback<ImportRoomKeysResult> { awaitCallback<ImportRoomKeysResult> {
session.cryptoService().keysBackupService().restoreKeysWithRecoveryKey( session.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(

View File

@ -0,0 +1,28 @@
/*
* 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.home.room.detail.timeline.action
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
/**
* Data used to display Location data in the message bottom sheet
*/
data class LocationUiData(
val locationUrl: String,
val locationOwnerId: String?,
val locationPinProvider: LocationPinProvider,
)

View File

@ -46,8 +46,8 @@ import im.vector.app.features.media.ImageContentRenderer
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.orTrue
import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.events.model.isLocationMessage
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.message.MessageLocationContent import org.matrix.android.sdk.api.session.room.model.message.MessageLocationContent
import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.send.SendState
@ -80,12 +80,7 @@ class MessageActionsEpoxyController @Inject constructor(
val formattedDate = dateFormatter.format(date, DateFormatKind.MESSAGE_DETAIL) val formattedDate = dateFormatter.format(date, DateFormatKind.MESSAGE_DETAIL)
val body = state.messageBody.linkify(host.listener) val body = state.messageBody.linkify(host.listener)
val bindingOptions = spanUtils.getBindingOptions(body) val bindingOptions = spanUtils.getBindingOptions(body)
val locationUiData = buildLocationUiData(state)
val locationContent = state.timelineEvent()?.root?.getClearContent()
?.toModel<MessageLocationContent>(catchError = true)
val locationUrl = locationContent?.toLocationData()
?.let { urlMapProvider.buildStaticMapUrl(it, INITIAL_MAP_ZOOM_IN_TIMELINE, 1200, 800) }
val locationOwnerId = if (locationContent?.isSelfLocation().orTrue()) state.informationData.matrixItem.id else null
bottomSheetMessagePreviewItem { bottomSheetMessagePreviewItem {
id("preview") id("preview")
@ -99,9 +94,7 @@ class MessageActionsEpoxyController @Inject constructor(
body(body.toEpoxyCharSequence()) body(body.toEpoxyCharSequence())
bodyDetails(host.eventDetailsFormatter.format(state.timelineEvent()?.root)?.toEpoxyCharSequence()) bodyDetails(host.eventDetailsFormatter.format(state.timelineEvent()?.root)?.toEpoxyCharSequence())
time(formattedDate) time(formattedDate)
locationUrl(locationUrl) locationUiData(locationUiData)
locationPinProvider(host.locationPinProvider)
locationOwnerId(locationOwnerId)
} }
// Send state // Send state
@ -222,6 +215,23 @@ class MessageActionsEpoxyController @Inject constructor(
} }
} }
private fun buildLocationUiData(state: MessageActionState): LocationUiData? {
if (state.timelineEvent()?.root?.isLocationMessage() != true) return null
val locationContent = state.timelineEvent()?.root?.getClearContent().toModel<MessageLocationContent>(catchError = true)
?: return null
val locationUrl = locationContent.toLocationData()
?.let { urlMapProvider.buildStaticMapUrl(it, INITIAL_MAP_ZOOM_IN_TIMELINE, 1200, 800) }
?: return null
val locationOwnerId = if (locationContent.isSelfLocation()) state.informationData.matrixItem.id else null
return LocationUiData(
locationUrl = locationUrl,
locationOwnerId = locationOwnerId,
locationPinProvider = locationPinProvider,
)
}
private fun EventSharedAction.shouldShowBetaLabel(): Boolean = private fun EventSharedAction.shouldShowBetaLabel(): Boolean =
this is EventSharedAction.ReplyInThread && !vectorPreferences.areThreadMessagesEnabled() this is EventSharedAction.ReplyInThread && !vectorPreferences.areThreadMessagesEnabled()