Fix unneeded re-uploade of key got from backup
and disabled prompting for untrusted key sharing
This commit is contained in:
parent
cc107498eb
commit
88cf1a5e67
|
@ -20,6 +20,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.asCoroutineDispatcher
|
import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||||
|
@ -168,6 +169,11 @@ internal class OutgoingKeyRequestManager @Inject constructor(
|
||||||
sequencer.post {
|
sequencer.post {
|
||||||
cryptoStore.deleteOutgoingRoomKeyRequestInState(OutgoingRoomKeyRequestState.SENT)
|
cryptoStore.deleteOutgoingRoomKeyRequestInState(OutgoingRoomKeyRequestState.SENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sequencer.post {
|
||||||
|
delay(1000)
|
||||||
|
perSessionBackupQueryRateLimiter.refreshBackupInfoIfNeeded(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ internal class PerSessionBackupQueryRateLimiter @Inject constructor(
|
||||||
var backupWasCheckedFromServer: Boolean = false
|
var backupWasCheckedFromServer: Boolean = false
|
||||||
var now = System.currentTimeMillis()
|
var now = System.currentTimeMillis()
|
||||||
|
|
||||||
private fun refreshBackupInfoIfNeeded(force: Boolean = false) {
|
fun refreshBackupInfoIfNeeded(force: Boolean = false) {
|
||||||
if (backupWasCheckedFromServer && !force) return
|
if (backupWasCheckedFromServer && !force) return
|
||||||
Timber.tag(loggerTag.value).v("Checking if can access a backup")
|
Timber.tag(loggerTag.value).v("Checking if can access a backup")
|
||||||
backupWasCheckedFromServer = true
|
backupWasCheckedFromServer = true
|
||||||
|
|
|
@ -63,16 +63,11 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.RoomKeysBack
|
||||||
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.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.DeleteRoomSessionsDataTask
|
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DeleteSessionsDataTask
|
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetKeysBackupLastVersionTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetKeysBackupLastVersionTask
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetKeysBackupVersionTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetKeysBackupVersionTask
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetRoomSessionDataTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetRoomSessionDataTask
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetRoomSessionsDataTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetRoomSessionsDataTask
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetSessionsDataTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetSessionsDataTask
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessionDataTask
|
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessionsDataTask
|
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
|
import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
|
||||||
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
|
import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
|
||||||
|
@ -112,16 +107,11 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
// Tasks
|
// Tasks
|
||||||
private val createKeysBackupVersionTask: CreateKeysBackupVersionTask,
|
private val createKeysBackupVersionTask: CreateKeysBackupVersionTask,
|
||||||
private val deleteBackupTask: DeleteBackupTask,
|
private val deleteBackupTask: DeleteBackupTask,
|
||||||
private val deleteRoomSessionDataTask: DeleteRoomSessionDataTask,
|
|
||||||
private val deleteRoomSessionsDataTask: DeleteRoomSessionsDataTask,
|
|
||||||
private val deleteSessionDataTask: DeleteSessionsDataTask,
|
|
||||||
private val getKeysBackupLastVersionTask: GetKeysBackupLastVersionTask,
|
private val getKeysBackupLastVersionTask: GetKeysBackupLastVersionTask,
|
||||||
private val getKeysBackupVersionTask: GetKeysBackupVersionTask,
|
private val getKeysBackupVersionTask: GetKeysBackupVersionTask,
|
||||||
private val getRoomSessionDataTask: GetRoomSessionDataTask,
|
private val getRoomSessionDataTask: GetRoomSessionDataTask,
|
||||||
private val getRoomSessionsDataTask: GetRoomSessionsDataTask,
|
private val getRoomSessionsDataTask: GetRoomSessionsDataTask,
|
||||||
private val getSessionsDataTask: GetSessionsDataTask,
|
private val getSessionsDataTask: GetSessionsDataTask,
|
||||||
private val storeRoomSessionDataTask: StoreRoomSessionDataTask,
|
|
||||||
private val storeSessionsDataTask: StoreRoomSessionsDataTask,
|
|
||||||
private val storeSessionDataTask: StoreSessionsDataTask,
|
private val storeSessionDataTask: StoreSessionsDataTask,
|
||||||
private val updateKeysBackupVersionTask: UpdateKeysBackupVersionTask,
|
private val updateKeysBackupVersionTask: UpdateKeysBackupVersionTask,
|
||||||
// Task executor
|
// Task executor
|
||||||
|
@ -168,58 +158,63 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
override fun prepareKeysBackupVersion(password: String?,
|
override fun prepareKeysBackupVersion(password: String?,
|
||||||
progressListener: ProgressListener?,
|
progressListener: ProgressListener?,
|
||||||
callback: MatrixCallback<MegolmBackupCreationInfo>) {
|
callback: MatrixCallback<MegolmBackupCreationInfo>) {
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||||
runCatching {
|
try {
|
||||||
withContext(coroutineDispatchers.crypto) {
|
val olmPkDecryption = OlmPkDecryption()
|
||||||
val olmPkDecryption = OlmPkDecryption()
|
val signalableMegolmBackupAuthData = if (password != null) {
|
||||||
val signalableMegolmBackupAuthData = if (password != null) {
|
// Generate a private key from the password
|
||||||
// Generate a private key from the password
|
val backgroundProgressListener = if (progressListener == null) {
|
||||||
val backgroundProgressListener = if (progressListener == null) {
|
null
|
||||||
null
|
} else {
|
||||||
} else {
|
object : ProgressListener {
|
||||||
object : ProgressListener {
|
override fun onProgress(progress: Int, total: Int) {
|
||||||
override fun onProgress(progress: Int, total: Int) {
|
uiHandler.post {
|
||||||
uiHandler.post {
|
try {
|
||||||
try {
|
progressListener.onProgress(progress, total)
|
||||||
progressListener.onProgress(progress, total)
|
} catch (e: Exception) {
|
||||||
} catch (e: Exception) {
|
Timber.e(e, "prepareKeysBackupVersion: onProgress failure")
|
||||||
Timber.e(e, "prepareKeysBackupVersion: onProgress failure")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
|
|
||||||
SignalableMegolmBackupAuthData(
|
|
||||||
publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey),
|
|
||||||
privateKeySalt = generatePrivateKeyResult.salt,
|
|
||||||
privateKeyIterations = generatePrivateKeyResult.iterations
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
val publicKey = olmPkDecryption.generateKey()
|
|
||||||
|
|
||||||
SignalableMegolmBackupAuthData(
|
|
||||||
publicKey = publicKey
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableMegolmBackupAuthData.signalableJSONDictionary())
|
val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
|
||||||
|
SignalableMegolmBackupAuthData(
|
||||||
val signedMegolmBackupAuthData = MegolmBackupAuthData(
|
publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey),
|
||||||
publicKey = signalableMegolmBackupAuthData.publicKey,
|
privateKeySalt = generatePrivateKeyResult.salt,
|
||||||
privateKeySalt = signalableMegolmBackupAuthData.privateKeySalt,
|
privateKeyIterations = generatePrivateKeyResult.iterations
|
||||||
privateKeyIterations = signalableMegolmBackupAuthData.privateKeyIterations,
|
|
||||||
signatures = objectSigner.signObject(canonicalJson)
|
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
val publicKey = olmPkDecryption.generateKey()
|
||||||
|
|
||||||
MegolmBackupCreationInfo(
|
SignalableMegolmBackupAuthData(
|
||||||
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
|
publicKey = publicKey
|
||||||
authData = signedMegolmBackupAuthData,
|
|
||||||
recoveryKey = computeRecoveryKey(olmPkDecryption.privateKey())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}.foldToCallback(callback)
|
|
||||||
|
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableMegolmBackupAuthData.signalableJSONDictionary())
|
||||||
|
|
||||||
|
val signedMegolmBackupAuthData = MegolmBackupAuthData(
|
||||||
|
publicKey = signalableMegolmBackupAuthData.publicKey,
|
||||||
|
privateKeySalt = signalableMegolmBackupAuthData.privateKeySalt,
|
||||||
|
privateKeyIterations = signalableMegolmBackupAuthData.privateKeyIterations,
|
||||||
|
signatures = objectSigner.signObject(canonicalJson)
|
||||||
|
)
|
||||||
|
|
||||||
|
val creationInfo = MegolmBackupCreationInfo(
|
||||||
|
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
|
||||||
|
authData = signedMegolmBackupAuthData,
|
||||||
|
recoveryKey = computeRecoveryKey(olmPkDecryption.privateKey())
|
||||||
|
)
|
||||||
|
uiHandler.post {
|
||||||
|
callback.onSuccess(creationInfo)
|
||||||
|
}
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
uiHandler.post {
|
||||||
|
callback.onFailure(failure)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,41 +262,39 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteBackup(version: String, callback: MatrixCallback<Unit>?) {
|
override fun deleteBackup(version: String, callback: MatrixCallback<Unit>?) {
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||||
withContext(coroutineDispatchers.crypto) {
|
// If we're currently backing up to this backup... stop.
|
||||||
// If we're currently backing up to this backup... stop.
|
// (We start using it automatically in createKeysBackupVersion so this is symmetrical).
|
||||||
// (We start using it automatically in createKeysBackupVersion so this is symmetrical).
|
if (keysBackupVersion != null && version == keysBackupVersion?.version) {
|
||||||
if (keysBackupVersion != null && version == keysBackupVersion?.version) {
|
resetKeysBackupData()
|
||||||
resetKeysBackupData()
|
keysBackupVersion = null
|
||||||
keysBackupVersion = null
|
keysBackupStateManager.state = KeysBackupState.Unknown
|
||||||
keysBackupStateManager.state = KeysBackupState.Unknown
|
}
|
||||||
}
|
|
||||||
|
|
||||||
deleteBackupTask
|
deleteBackupTask
|
||||||
.configureWith(DeleteBackupTask.Params(version)) {
|
.configureWith(DeleteBackupTask.Params(version)) {
|
||||||
this.callback = object : MatrixCallback<Unit> {
|
this.callback = object : MatrixCallback<Unit> {
|
||||||
private fun eventuallyRestartBackup() {
|
private fun eventuallyRestartBackup() {
|
||||||
// Do not stay in KeysBackupState.Unknown but check what is available on the homeserver
|
// Do not stay in KeysBackupState.Unknown but check what is available on the homeserver
|
||||||
if (state == KeysBackupState.Unknown) {
|
if (state == KeysBackupState.Unknown) {
|
||||||
checkAndStartKeysBackup()
|
checkAndStartKeysBackup()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSuccess(data: Unit) {
|
|
||||||
eventuallyRestartBackup()
|
|
||||||
|
|
||||||
uiHandler.post { callback?.onSuccess(Unit) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
|
||||||
eventuallyRestartBackup()
|
|
||||||
|
|
||||||
uiHandler.post { callback?.onFailure(failure) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(data: Unit) {
|
||||||
|
eventuallyRestartBackup()
|
||||||
|
|
||||||
|
uiHandler.post { callback?.onSuccess(Unit) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
eventuallyRestartBackup()
|
||||||
|
|
||||||
|
uiHandler.post { callback?.onFailure(failure) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.executeBy(taskExecutor)
|
}
|
||||||
}
|
.executeBy(taskExecutor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,10 +473,11 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
|
|
||||||
if (authData == null) {
|
if (authData == null) {
|
||||||
Timber.w("trustKeyBackupVersion:trust: Key backup is missing required data")
|
Timber.w("trustKeyBackupVersion:trust: Key backup is missing required data")
|
||||||
|
uiHandler.post {
|
||||||
callback.onFailure(IllegalArgumentException("Missing element"))
|
callback.onFailure(IllegalArgumentException("Missing element"))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||||
val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) {
|
val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) {
|
||||||
// Get current signatures, or create an empty set
|
// Get current signatures, or create an empty set
|
||||||
val myUserSignatures = authData.signatures?.get(userId).orEmpty().toMutableMap()
|
val myUserSignatures = authData.signatures?.get(userId).orEmpty().toMutableMap()
|
||||||
|
@ -535,11 +529,15 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
|
|
||||||
checkAndStartWithKeysBackupVersion(newKeysBackupVersion)
|
checkAndStartWithKeysBackupVersion(newKeysBackupVersion)
|
||||||
|
|
||||||
callback.onSuccess(data)
|
uiHandler.post {
|
||||||
|
callback.onSuccess(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
callback.onFailure(failure)
|
uiHandler.post {
|
||||||
|
callback.onFailure(failure)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -553,15 +551,14 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
callback: MatrixCallback<Unit>) {
|
callback: MatrixCallback<Unit>) {
|
||||||
Timber.v("trustKeysBackupVersionWithRecoveryKey: version ${keysBackupVersion.version}")
|
Timber.v("trustKeysBackupVersionWithRecoveryKey: version ${keysBackupVersion.version}")
|
||||||
|
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||||
val isValid = withContext(coroutineDispatchers.crypto) {
|
val isValid = isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)
|
||||||
isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
Timber.w("trustKeyBackupVersionWithRecoveryKey: Invalid recovery key.")
|
Timber.w("trustKeyBackupVersionWithRecoveryKey: Invalid recovery key.")
|
||||||
|
uiHandler.post {
|
||||||
callback.onFailure(IllegalArgumentException("Invalid recovery key or password"))
|
callback.onFailure(IllegalArgumentException("Invalid recovery key or password"))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
trustKeysBackupVersion(keysBackupVersion, true, callback)
|
trustKeysBackupVersion(keysBackupVersion, true, callback)
|
||||||
}
|
}
|
||||||
|
@ -573,15 +570,14 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
callback: MatrixCallback<Unit>) {
|
callback: MatrixCallback<Unit>) {
|
||||||
Timber.v("trustKeysBackupVersionWithPassphrase: version ${keysBackupVersion.version}")
|
Timber.v("trustKeysBackupVersionWithPassphrase: version ${keysBackupVersion.version}")
|
||||||
|
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||||
val recoveryKey = withContext(coroutineDispatchers.crypto) {
|
val recoveryKey = recoveryKeyFromPassword(password, keysBackupVersion, null)
|
||||||
recoveryKeyFromPassword(password, keysBackupVersion, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recoveryKey == null) {
|
if (recoveryKey == null) {
|
||||||
Timber.w("trustKeysBackupVersionWithPassphrase: Key backup is missing required data")
|
Timber.w("trustKeysBackupVersionWithPassphrase: Key backup is missing required data")
|
||||||
|
uiHandler.post {
|
||||||
callback.onFailure(IllegalArgumentException("Missing element"))
|
callback.onFailure(IllegalArgumentException("Missing element"))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check trust using the recovery key
|
// Check trust using the recovery key
|
||||||
trustKeysBackupVersionWithRecoveryKey(keysBackupVersion, recoveryKey, callback)
|
trustKeysBackupVersionWithRecoveryKey(keysBackupVersion, recoveryKey, callback)
|
||||||
|
@ -592,30 +588,23 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
override fun onSecretKeyGossip(secret: String) {
|
override fun onSecretKeyGossip(secret: String) {
|
||||||
Timber.i("## CrossSigning - onSecretKeyGossip")
|
Timber.i("## CrossSigning - onSecretKeyGossip")
|
||||||
|
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||||
try {
|
try {
|
||||||
when (val keysBackupLastVersionResult = getKeysBackupLastVersionTask.execute(Unit)) {
|
when (val keysBackupLastVersionResult = getKeysBackupLastVersionTask.execute(Unit)) {
|
||||||
KeysBackupLastVersionResult.NoKeysBackup -> {
|
KeysBackupLastVersionResult.NoKeysBackup -> {
|
||||||
Timber.d("No keys backup found")
|
Timber.d("No keys backup found")
|
||||||
}
|
}
|
||||||
is KeysBackupLastVersionResult.KeysBackup -> {
|
// we don't want to start immediately downloading all as it can take very long
|
||||||
val keysBackupVersion = keysBackupLastVersionResult.keysVersionResult
|
|
||||||
val recoveryKey = computeRecoveryKey(secret.fromBase64())
|
// val importResult = awaitCallback<ImportRoomKeysResult> {
|
||||||
if (isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)) {
|
// restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, null, null, null, it)
|
||||||
awaitCallback<Unit> {
|
// }
|
||||||
trustKeysBackupVersion(keysBackupVersion, true, it)
|
withContext(coroutineDispatchers.crypto) {
|
||||||
}
|
cryptoStore.saveBackupRecoveryKey(recoveryKey, keysBackupVersion.version)
|
||||||
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}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Timber.i("onSecretKeyGossip: saved valid backup key")
|
||||||
|
} 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}")
|
||||||
|
@ -678,9 +667,9 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
callback: MatrixCallback<ImportRoomKeysResult>) {
|
callback: MatrixCallback<ImportRoomKeysResult>) {
|
||||||
Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}")
|
Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}")
|
||||||
|
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val decryption = withContext(coroutineDispatchers.crypto) {
|
val decryption = withContext(coroutineDispatchers.computation) {
|
||||||
// Check if the recovery is valid before going any further
|
// Check if the recovery is valid before going any further
|
||||||
if (!isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysVersionResult)) {
|
if (!isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysVersionResult)) {
|
||||||
Timber.e("restoreKeysWithRecoveryKey: Invalid recovery key for this keys version")
|
Timber.e("restoreKeysWithRecoveryKey: Invalid recovery key for this keys version")
|
||||||
|
@ -749,7 +738,19 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}.foldToCallback(callback)
|
}.foldToCallback(object : MatrixCallback<ImportRoomKeysResult> {
|
||||||
|
override fun onSuccess(data: ImportRoomKeysResult) {
|
||||||
|
uiHandler.post {
|
||||||
|
callback.onSuccess(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
uiHandler.post {
|
||||||
|
callback.onFailure(failure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,7 +762,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
callback: MatrixCallback<ImportRoomKeysResult>) {
|
callback: MatrixCallback<ImportRoomKeysResult>) {
|
||||||
Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}")
|
Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}")
|
||||||
|
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.io) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val progressListener = if (stepProgressListener != null) {
|
val progressListener = if (stepProgressListener != null) {
|
||||||
object : ProgressListener {
|
object : ProgressListener {
|
||||||
|
@ -786,7 +787,19 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||||
restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, roomId, sessionId, stepProgressListener, it)
|
restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, roomId, sessionId, stepProgressListener, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.foldToCallback(callback)
|
}.foldToCallback(object : MatrixCallback<ImportRoomKeysResult> {
|
||||||
|
override fun onSuccess(data: ImportRoomKeysResult) {
|
||||||
|
uiHandler.post {
|
||||||
|
callback.onSuccess(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
uiHandler.post {
|
||||||
|
callback.onFailure(failure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -740,14 +740,23 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
if (sessionIdentifier != null) {
|
if (sessionIdentifier != null) {
|
||||||
val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionIdentifier, session.senderKey)
|
val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionIdentifier, session.senderKey)
|
||||||
|
|
||||||
val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
|
val existing = realm.where<OlmInboundGroupSessionEntity>()
|
||||||
primaryKey = key
|
.equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
|
||||||
sessionId = sessionIdentifier
|
.findFirst()
|
||||||
senderKey = session.senderKey
|
|
||||||
putInboundGroupSession(session)
|
|
||||||
}
|
|
||||||
|
|
||||||
realm.insertOrUpdate(realmOlmInboundGroupSession)
|
if (existing != null) {
|
||||||
|
// we want to keep the existing backup status
|
||||||
|
existing.putInboundGroupSession(session)
|
||||||
|
} else {
|
||||||
|
val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
|
||||||
|
primaryKey = key
|
||||||
|
sessionId = sessionIdentifier
|
||||||
|
senderKey = session.senderKey
|
||||||
|
putInboundGroupSession(session)
|
||||||
|
}
|
||||||
|
|
||||||
|
realm.insertOrUpdate(realmOlmInboundGroupSession)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -876,17 +885,32 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
doRealmTransaction(realmConfiguration) {
|
doRealmTransaction(realmConfiguration) { realm ->
|
||||||
olmInboundGroupSessionWrappers.forEach { olmInboundGroupSessionWrapper ->
|
olmInboundGroupSessionWrappers.forEach { olmInboundGroupSessionWrapper ->
|
||||||
try {
|
try {
|
||||||
|
val sessionIdentifier = olmInboundGroupSessionWrapper.olmInboundGroupSession?.sessionIdentifier()
|
||||||
val key = OlmInboundGroupSessionEntity.createPrimaryKey(
|
val key = OlmInboundGroupSessionEntity.createPrimaryKey(
|
||||||
olmInboundGroupSessionWrapper.olmInboundGroupSession?.sessionIdentifier(),
|
sessionIdentifier,
|
||||||
olmInboundGroupSessionWrapper.senderKey)
|
olmInboundGroupSessionWrapper.senderKey)
|
||||||
|
|
||||||
it.where<OlmInboundGroupSessionEntity>()
|
val existing = realm.where<OlmInboundGroupSessionEntity>()
|
||||||
.equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
|
.equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
?.backedUp = true
|
|
||||||
|
if (existing != null) {
|
||||||
|
existing.backedUp = true
|
||||||
|
} else {
|
||||||
|
// ... might be in cache but not yet persisted, create a record to persist backedup state
|
||||||
|
val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
|
||||||
|
primaryKey = key
|
||||||
|
sessionId = sessionIdentifier
|
||||||
|
senderKey = olmInboundGroupSessionWrapper.senderKey
|
||||||
|
putInboundGroupSession(olmInboundGroupSessionWrapper)
|
||||||
|
backedUp = true
|
||||||
|
}
|
||||||
|
|
||||||
|
realm.insertOrUpdate(realmOlmInboundGroupSession)
|
||||||
|
}
|
||||||
} catch (e: OlmException) {
|
} catch (e: OlmException) {
|
||||||
Timber.e(e, "OlmException")
|
Timber.e(e, "OlmException")
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,9 @@ class KeyRequestHandler @Inject constructor(
|
||||||
|
|
||||||
var session: Session? = null
|
var session: Session? = null
|
||||||
|
|
||||||
|
// This functionality is disabled in element for now. As it could be prone to social attacks
|
||||||
|
var enablePromptingForRequest = false
|
||||||
|
|
||||||
fun start(session: Session) {
|
fun start(session: Session) {
|
||||||
this.session = session
|
this.session = session
|
||||||
session.cryptoService().verificationService().addListener(this)
|
session.cryptoService().verificationService().addListener(this)
|
||||||
|
@ -92,6 +95,8 @@ class KeyRequestHandler @Inject constructor(
|
||||||
* @param request the key request.
|
* @param request the key request.
|
||||||
*/
|
*/
|
||||||
override fun onRoomKeyRequest(request: IncomingRoomKeyRequest) {
|
override fun onRoomKeyRequest(request: IncomingRoomKeyRequest) {
|
||||||
|
if (!enablePromptingForRequest) return
|
||||||
|
|
||||||
val userId = request.userId
|
val userId = request.userId
|
||||||
val deviceId = request.deviceId
|
val deviceId = request.deviceId
|
||||||
val requestId = request.requestId
|
val requestId = request.requestId
|
||||||
|
|
Loading…
Reference in New Issue