crypto: Fill out all the methods to support backups
This commit is contained in:
parent
021041fc2e
commit
3b93d6b08c
@ -20,6 +20,7 @@ import android.content.Context
|
|||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.paging.PagedList
|
import androidx.paging.PagedList
|
||||||
|
import com.squareup.moshi.Types
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@ -57,17 +58,20 @@ import org.matrix.android.sdk.api.util.JsonDict
|
|||||||
import org.matrix.android.sdk.internal.auth.registration.handleUIA
|
import org.matrix.android.sdk.internal.auth.registration.handleUIA
|
||||||
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.RustKeyBackupService
|
import org.matrix.android.sdk.internal.crypto.keysbackup.RustKeyBackupService
|
||||||
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.CreateKeysBackupVersionBody
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.CreateKeysBackupVersionBody
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData
|
||||||
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.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.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.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.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.model.CryptoDeviceInfo
|
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||||
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
|
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
|
||||||
import org.matrix.android.sdk.internal.crypto.model.MXEncryptEventContentResult
|
import org.matrix.android.sdk.internal.crypto.model.MXEncryptEventContentResult
|
||||||
@ -137,6 +141,7 @@ internal class RequestSender @Inject constructor(
|
|||||||
private val deleteBackupTask: DeleteBackupTask,
|
private val deleteBackupTask: DeleteBackupTask,
|
||||||
private val createKeysBackupVersionTask: CreateKeysBackupVersionTask,
|
private val createKeysBackupVersionTask: CreateKeysBackupVersionTask,
|
||||||
private val backupRoomKeysTask: StoreSessionsDataTask,
|
private val backupRoomKeysTask: StoreSessionsDataTask,
|
||||||
|
private val updateKeysBackupVersionTask: UpdateKeysBackupVersionTask,
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
const val REQUEST_RETRY_COUNT = 3
|
const val REQUEST_RETRY_COUNT = 3
|
||||||
@ -297,44 +302,25 @@ internal class RequestSender @Inject constructor(
|
|||||||
val adapter = MoshiProvider
|
val adapter = MoshiProvider
|
||||||
.providesMoshi()
|
.providesMoshi()
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
|
.add(CheckNumberType.JSON_ADAPTER_FACTORY)
|
||||||
.build()
|
.build()
|
||||||
.adapter<MutableMap<String, RoomKeysBackupData>>(MutableMap::class.java)
|
.adapter<MutableMap<String, RoomKeysBackupData>>(
|
||||||
|
Types.newParameterizedType(
|
||||||
|
Map::class.java,
|
||||||
|
String::class.java,
|
||||||
|
RoomKeysBackupData::class.java
|
||||||
|
))
|
||||||
val keys = adapter.fromJson(request.rooms)!!
|
val keys = adapter.fromJson(request.rooms)!!
|
||||||
Timber.d("BACKUP: CONVERTED KEYS TO HASHMAP $keys")
|
val params = StoreSessionsDataTask.Params(request.version, KeysBackupData(keys))
|
||||||
/*
|
val response = backupRoomKeysTask.executeRetry(params, REQUEST_RETRY_COUNT)
|
||||||
val keyAdapter = MoshiProvider.providesMoshi().adapter(KeyBackupData::class.java)
|
|
||||||
val keysBackupData = KeysBackupData()
|
|
||||||
for (room in keys) {
|
|
||||||
val sessions = room.value.getOrDefault("sessions", mapOf())
|
|
||||||
|
|
||||||
for (session in sessions) {
|
|
||||||
Timber.d("BACKUP: HEEELOO CONVERTING KEY ${session.value}")
|
|
||||||
val key = keyAdapter.fromJson(session.value)!!
|
|
||||||
Timber.d("BACKUP: HEEELOO CONVERTED KEY $key")
|
|
||||||
|
|
||||||
keysBackupData
|
|
||||||
.roomIdToRoomKeysBackupData
|
|
||||||
.getOrPut(room.key, { RoomKeysBackupData() })
|
|
||||||
.sessionIdToKeyBackupData[session.key] = key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
for ((roomId, backupData) in keys) {
|
|
||||||
val roomData = backup.roomIdToRoomKeysBackupData.getOrPut(roomId, { RoomKeysBackupData() })
|
|
||||||
for ((sessionId, key) in backupData.sessionIdToKeyBackupData) {
|
|
||||||
Timber.d("BACKUP INSERTING KEY $key")
|
|
||||||
roomData.sessionIdToKeyBackupData[sessionId] = key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
val params = StoreSessionsDataTask.Params(request.version, KeysBackupData())
|
|
||||||
val response = backupRoomKeysTask.execute(params)
|
|
||||||
val responseAdapter = MoshiProvider.providesMoshi().adapter(BackupKeysResult::class.java)
|
val responseAdapter = MoshiProvider.providesMoshi().adapter(BackupKeysResult::class.java)
|
||||||
return responseAdapter.toJson(response)!!
|
return responseAdapter.toJson(response)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun updateBackup(keysBackupVersion: KeysVersionResult, body: UpdateKeysBackupVersionBody) {
|
||||||
|
val params = UpdateKeysBackupVersionTask.Params(keysBackupVersion.version, body)
|
||||||
|
updateKeysBackupVersionTask.executeRetry(params, REQUEST_RETRY_COUNT)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -566,6 +552,8 @@ internal class DefaultCryptoService @Inject constructor(
|
|||||||
Timber.v("Failed create an Olm machine: $throwable")
|
Timber.v("Failed create an Olm machine: $throwable")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We try to enable key backups, if the backup version on the server is trusted,
|
||||||
|
// we're gonna continue backing up.
|
||||||
tryOrNull {
|
tryOrNull {
|
||||||
keysBackupService!!.checkAndStartKeysBackup()
|
keysBackupService!!.checkAndStartKeysBackup()
|
||||||
}
|
}
|
||||||
@ -1075,7 +1063,8 @@ internal class DefaultCryptoService @Inject constructor(
|
|||||||
}
|
}
|
||||||
is Request.KeysBackup -> {
|
is Request.KeysBackup -> {
|
||||||
async {
|
async {
|
||||||
TODO()
|
// The rust-sdk won't ever produce KeysBackup requests here,
|
||||||
|
// those only get explicitly created.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,10 @@ import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
|
|||||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.UnsignedDeviceInfo
|
import org.matrix.android.sdk.internal.crypto.model.rest.UnsignedDeviceInfo
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
|
import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
|
||||||
import uniffi.olm.CryptoStoreErrorException
|
import uniffi.olm.CryptoStoreException
|
||||||
import uniffi.olm.Device as InnerDevice
|
import uniffi.olm.Device as InnerDevice
|
||||||
import uniffi.olm.OlmMachine
|
import uniffi.olm.OlmMachine
|
||||||
import uniffi.olm.SignatureErrorException
|
import uniffi.olm.SignatureException
|
||||||
import uniffi.olm.VerificationRequest
|
import uniffi.olm.VerificationRequest
|
||||||
|
|
||||||
/** Class representing a device that supports E2EE in the Matrix world
|
/** Class representing a device that supports E2EE in the Matrix world
|
||||||
@ -41,7 +41,7 @@ internal class Device(
|
|||||||
private val sender: RequestSender,
|
private val sender: RequestSender,
|
||||||
private val listeners: ArrayList<VerificationService.Listener>,
|
private val listeners: ArrayList<VerificationService.Listener>,
|
||||||
) {
|
) {
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
private suspend fun refreshData() {
|
private suspend fun refreshData() {
|
||||||
val device = withContext(Dispatchers.IO) {
|
val device = withContext(Dispatchers.IO) {
|
||||||
machine.getDevice(inner.userId, inner.deviceId)
|
machine.getDevice(inner.userId, inner.deviceId)
|
||||||
@ -63,7 +63,7 @@ internal class Device(
|
|||||||
* [org.matrix.android.sdk.internal.crypto.OwnUserIdentity.requestVerification]
|
* [org.matrix.android.sdk.internal.crypto.OwnUserIdentity.requestVerification]
|
||||||
* method can be used instead.
|
* method can be used instead.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun requestVerification(methods: List<VerificationMethod>): VerificationRequest? {
|
suspend fun requestVerification(methods: List<VerificationMethod>): VerificationRequest? {
|
||||||
val stringMethods = prepareMethods(methods)
|
val stringMethods = prepareMethods(methods)
|
||||||
val result = withContext(Dispatchers.IO) {
|
val result = withContext(Dispatchers.IO) {
|
||||||
@ -87,7 +87,7 @@ internal class Device(
|
|||||||
* The [requestVerification] method should be used instead.
|
* The [requestVerification] method should be used instead.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun startVerification(): SasVerification? {
|
suspend fun startVerification(): SasVerification? {
|
||||||
val result = withContext(Dispatchers.IO) {
|
val result = withContext(Dispatchers.IO) {
|
||||||
machine.startSasWithDevice(inner.userId, inner.deviceId)
|
machine.startSasWithDevice(inner.userId, inner.deviceId)
|
||||||
@ -109,7 +109,7 @@ internal class Device(
|
|||||||
* This won't upload any signatures, it will only mark the device as trusted
|
* This won't upload any signatures, it will only mark the device as trusted
|
||||||
* in the local database.
|
* in the local database.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun markAsTrusted() {
|
suspend fun markAsTrusted() {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
machine.markDeviceAsTrusted(inner.userId, inner.deviceId)
|
machine.markDeviceAsTrusted(inner.userId, inner.deviceId)
|
||||||
@ -125,7 +125,7 @@ internal class Device(
|
|||||||
* This will fail if the device doesn't belong to use or if we don't have the
|
* This will fail if the device doesn't belong to use or if we don't have the
|
||||||
* private part of our self-signing key.
|
* private part of our self-signing key.
|
||||||
*/
|
*/
|
||||||
@Throws(SignatureErrorException::class)
|
@Throws(SignatureException::class)
|
||||||
suspend fun verify(): Boolean {
|
suspend fun verify(): Boolean {
|
||||||
val request = withContext(Dispatchers.IO) {
|
val request = withContext(Dispatchers.IO) {
|
||||||
machine.verifyDevice(inner.userId, inner.deviceId)
|
machine.verifyDevice(inner.userId, inner.deviceId)
|
||||||
@ -139,7 +139,7 @@ internal class Device(
|
|||||||
/**
|
/**
|
||||||
* Get the DeviceTrustLevel of this device
|
* Get the DeviceTrustLevel of this device
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun trustLevel(): DeviceTrustLevel {
|
suspend fun trustLevel(): DeviceTrustLevel {
|
||||||
refreshData()
|
refreshData()
|
||||||
return DeviceTrustLevel(crossSigningVerified = inner.crossSigningTrusted, locallyVerified = inner.locallyTrusted)
|
return DeviceTrustLevel(crossSigningVerified = inner.crossSigningTrusted, locallyVerified = inner.locallyTrusted)
|
||||||
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto
|
|||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.squareup.moshi.Types
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
@ -37,6 +38,8 @@ import org.matrix.android.sdk.api.util.Optional
|
|||||||
import org.matrix.android.sdk.api.util.toOptional
|
import org.matrix.android.sdk.api.util.toOptional
|
||||||
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.crosssigning.UserTrustResult
|
import org.matrix.android.sdk.internal.crypto.crosssigning.UserTrustResult
|
||||||
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData
|
||||||
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.RoomKeysBackupData
|
||||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||||
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
|
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
|
||||||
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
|
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
|
||||||
@ -44,16 +47,18 @@ import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo
|
|||||||
import org.matrix.android.sdk.internal.crypto.model.rest.UnsignedDeviceInfo
|
import org.matrix.android.sdk.internal.crypto.model.rest.UnsignedDeviceInfo
|
||||||
import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
|
import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
import org.matrix.android.sdk.internal.network.parsing.CheckNumberType
|
||||||
import org.matrix.android.sdk.internal.session.sync.model.DeviceListResponse
|
import org.matrix.android.sdk.internal.session.sync.model.DeviceListResponse
|
||||||
import org.matrix.android.sdk.internal.session.sync.model.DeviceOneTimeKeysCountSyncResponse
|
import org.matrix.android.sdk.internal.session.sync.model.DeviceOneTimeKeysCountSyncResponse
|
||||||
import org.matrix.android.sdk.internal.session.sync.model.ToDeviceSyncResponse
|
import org.matrix.android.sdk.internal.session.sync.model.ToDeviceSyncResponse
|
||||||
|
import org.matrix.android.sdk.internal.util.JsonCanonicalizer
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uniffi.olm.BackupKey
|
import uniffi.olm.BackupKey
|
||||||
import uniffi.olm.BackupKeys
|
import uniffi.olm.BackupKeys
|
||||||
import uniffi.olm.CrossSigningKeyExport
|
import uniffi.olm.CrossSigningKeyExport
|
||||||
import uniffi.olm.CrossSigningStatus
|
import uniffi.olm.CrossSigningStatus
|
||||||
import uniffi.olm.CryptoStoreErrorException
|
import uniffi.olm.CryptoStoreException
|
||||||
import uniffi.olm.DecryptionErrorException
|
import uniffi.olm.DecryptionException
|
||||||
import uniffi.olm.DeviceLists
|
import uniffi.olm.DeviceLists
|
||||||
import uniffi.olm.KeyRequestPair
|
import uniffi.olm.KeyRequestPair
|
||||||
import uniffi.olm.Logger
|
import uniffi.olm.Logger
|
||||||
@ -262,7 +267,7 @@ internal class OlmMachine(
|
|||||||
*
|
*
|
||||||
* @param responseBody The body of the response that was received.
|
* @param responseBody The body of the response that was received.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun markRequestAsSent(
|
suspend fun markRequestAsSent(
|
||||||
requestId: String,
|
requestId: String,
|
||||||
requestType: RequestType,
|
requestType: RequestType,
|
||||||
@ -290,7 +295,7 @@ internal class OlmMachine(
|
|||||||
*
|
*
|
||||||
* @param keyCounts The map of uploaded one-time key types and counts.
|
* @param keyCounts The map of uploaded one-time key types and counts.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun receiveSyncChanges(
|
suspend fun receiveSyncChanges(
|
||||||
toDevice: ToDeviceSyncResponse?,
|
toDevice: ToDeviceSyncResponse?,
|
||||||
deviceChanges: DeviceListResponse?,
|
deviceChanges: DeviceListResponse?,
|
||||||
@ -342,7 +347,7 @@ internal class OlmMachine(
|
|||||||
*
|
*
|
||||||
* @return A [Request.KeysClaim] request that needs to be sent out to the server.
|
* @return A [Request.KeysClaim] request that needs to be sent out to the server.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun getMissingSessions(users: List<String>): Request? =
|
suspend fun getMissingSessions(users: List<String>): Request? =
|
||||||
withContext(Dispatchers.IO) { inner.getMissingSessions(users) }
|
withContext(Dispatchers.IO) { inner.getMissingSessions(users) }
|
||||||
|
|
||||||
@ -364,7 +369,7 @@ internal class OlmMachine(
|
|||||||
*
|
*
|
||||||
* @return The list of [Request.ToDevice] that need to be sent out.
|
* @return The list of [Request.ToDevice] that need to be sent out.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun shareRoomKey(roomId: String, users: List<String>): List<Request> =
|
suspend fun shareRoomKey(roomId: String, users: List<String>): List<Request> =
|
||||||
withContext(Dispatchers.IO) { inner.shareRoomKey(roomId, users) }
|
withContext(Dispatchers.IO) { inner.shareRoomKey(roomId, users) }
|
||||||
|
|
||||||
@ -398,7 +403,7 @@ internal class OlmMachine(
|
|||||||
*
|
*
|
||||||
* @return The encrypted version of the [Content]
|
* @return The encrypted version of the [Content]
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun encrypt(roomId: String, eventType: String, content: Content): Content =
|
suspend fun encrypt(roomId: String, eventType: String, content: Content): Content =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val adapter = MoshiProvider.providesMoshi().adapter<Content>(Map::class.java)
|
val adapter = MoshiProvider.providesMoshi().adapter<Content>(Map::class.java)
|
||||||
@ -453,7 +458,7 @@ internal class OlmMachine(
|
|||||||
* request itself. The cancellation *must* be sent out before the request, otherwise devices
|
* request itself. The cancellation *must* be sent out before the request, otherwise devices
|
||||||
* will ignore the key request.
|
* will ignore the key request.
|
||||||
*/
|
*/
|
||||||
@Throws(DecryptionErrorException::class)
|
@Throws(DecryptionException::class)
|
||||||
suspend fun requestRoomKey(event: Event): KeyRequestPair =
|
suspend fun requestRoomKey(event: Event): KeyRequestPair =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java)
|
val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java)
|
||||||
@ -472,7 +477,7 @@ internal class OlmMachine(
|
|||||||
*
|
*
|
||||||
* @return the encrypted key export as a bytearray.
|
* @return the encrypted key export as a bytearray.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun exportKeys(passphrase: String, rounds: Int): ByteArray =
|
suspend fun exportKeys(passphrase: String, rounds: Int): ByteArray =
|
||||||
withContext(Dispatchers.IO) { inner.exportKeys(passphrase, rounds).toByteArray() }
|
withContext(Dispatchers.IO) { inner.exportKeys(passphrase, rounds).toByteArray() }
|
||||||
|
|
||||||
@ -485,7 +490,7 @@ internal class OlmMachine(
|
|||||||
*
|
*
|
||||||
* @param listener A callback that can be used to introspect the progress of the key import.
|
* @param listener A callback that can be used to introspect the progress of the key import.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun importKeys(
|
suspend fun importKeys(
|
||||||
keys: ByteArray,
|
keys: ByteArray,
|
||||||
passphrase: String,
|
passphrase: String,
|
||||||
@ -501,7 +506,7 @@ internal class OlmMachine(
|
|||||||
ImportRoomKeysResult(result.total, result.imported)
|
ImportRoomKeysResult(result.total, result.imported)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun getIdentity(userId: String): UserIdentities? {
|
suspend fun getIdentity(userId: String): UserIdentities? {
|
||||||
val identity = withContext(Dispatchers.IO) {
|
val identity = withContext(Dispatchers.IO) {
|
||||||
inner.getIdentity(userId)
|
inner.getIdentity(userId)
|
||||||
@ -545,7 +550,7 @@ internal class OlmMachine(
|
|||||||
*
|
*
|
||||||
* @return The Device if it found one.
|
* @return The Device if it found one.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun getCryptoDeviceInfo(userId: String, deviceId: String): CryptoDeviceInfo? {
|
suspend fun getCryptoDeviceInfo(userId: String, deviceId: String): CryptoDeviceInfo? {
|
||||||
return if (userId == userId() && deviceId == deviceId()) {
|
return if (userId == userId() && deviceId == deviceId()) {
|
||||||
// Our own device isn't part of our store on the Rust side, return it
|
// Our own device isn't part of our store on the Rust side, return it
|
||||||
@ -556,7 +561,7 @@ internal class OlmMachine(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun getDevice(userId: String, deviceId: String): Device? {
|
suspend fun getDevice(userId: String, deviceId: String): Device? {
|
||||||
val device = withContext(Dispatchers.IO) {
|
val device = withContext(Dispatchers.IO) {
|
||||||
inner.getDevice(userId, deviceId)
|
inner.getDevice(userId, deviceId)
|
||||||
@ -578,7 +583,7 @@ internal class OlmMachine(
|
|||||||
*
|
*
|
||||||
* @return The list of Devices or an empty list if there aren't any.
|
* @return The list of Devices or an empty list if there aren't any.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo> {
|
suspend fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo> {
|
||||||
val devices = this.getUserDevices(userId).map { it.toCryptoDeviceInfo() }.toMutableList()
|
val devices = this.getUserDevices(userId).map { it.toCryptoDeviceInfo() }.toMutableList()
|
||||||
|
|
||||||
@ -658,7 +663,7 @@ internal class OlmMachine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Discard the currently active room key for the given room if there is one. */
|
/** Discard the currently active room key for the given room if there is one. */
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
fun discardRoomKey(roomId: String) {
|
fun discardRoomKey(roomId: String) {
|
||||||
runBlocking { inner.discardRoomKey(roomId) }
|
runBlocking { inner.discardRoomKey(roomId) }
|
||||||
}
|
}
|
||||||
@ -770,7 +775,7 @@ internal class OlmMachine(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun enableBackup(key: String, version: String) {
|
suspend fun enableBackup(key: String, version: String) {
|
||||||
return withContext(Dispatchers.Default) {
|
return withContext(Dispatchers.Default) {
|
||||||
val backupKey = BackupKey(key, mapOf(), null)
|
val backupKey = BackupKey(key, mapOf(), null)
|
||||||
@ -797,7 +802,7 @@ internal class OlmMachine(
|
|||||||
inner.saveRecoveryKey(key, version)
|
inner.saveRecoveryKey(key, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun backupRoomKeys(): Request? {
|
suspend fun backupRoomKeys(): Request? {
|
||||||
return withContext(Dispatchers.Default) {
|
return withContext(Dispatchers.Default) {
|
||||||
Timber.d("BACKUP CREATING REQUEST")
|
Timber.d("BACKUP CREATING REQUEST")
|
||||||
@ -806,4 +811,18 @@ internal class OlmMachine(
|
|||||||
request
|
request
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(CryptoStoreException::class)
|
||||||
|
suspend fun checkAuthDataSignature(authData: MegolmBackupAuthData): Boolean {
|
||||||
|
return withContext(Dispatchers.Default) {
|
||||||
|
val adapter = MoshiProvider
|
||||||
|
.providesMoshi()
|
||||||
|
.newBuilder()
|
||||||
|
.add(CheckNumberType.JSON_ADAPTER_FACTORY)
|
||||||
|
.build()
|
||||||
|
.adapter(MegolmBackupAuthData::class.java)
|
||||||
|
val serializedAuthData = adapter.toJson(authData)
|
||||||
|
inner.verifyBackup(serializedAuthData)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxStat
|
|||||||
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
|
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
|
||||||
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.verification.UpdateDispatcher
|
import org.matrix.android.sdk.internal.crypto.verification.UpdateDispatcher
|
||||||
import uniffi.olm.CryptoStoreErrorException
|
import uniffi.olm.CryptoStoreException
|
||||||
import uniffi.olm.OlmMachine
|
import uniffi.olm.OlmMachine
|
||||||
import uniffi.olm.QrCode
|
import uniffi.olm.QrCode
|
||||||
import uniffi.olm.Verification
|
import uniffi.olm.Verification
|
||||||
@ -172,7 +172,7 @@ internal class QrCodeVerification(
|
|||||||
* The method turns into a noop if we're not yet ready to confirm the scanning,
|
* The method turns into a noop if we're not yet ready to confirm the scanning,
|
||||||
* i.e. we didn't yet receive a m.key.verification.start event from the other side.
|
* i.e. we didn't yet receive a m.key.verification.start event from the other side.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
private suspend fun confirm() {
|
private suspend fun confirm() {
|
||||||
val result = withContext(Dispatchers.IO)
|
val result = withContext(Dispatchers.IO)
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxStat
|
|||||||
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
|
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.UpdateDispatcher
|
import org.matrix.android.sdk.internal.crypto.verification.UpdateDispatcher
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.getEmojiForCode
|
import org.matrix.android.sdk.internal.crypto.verification.getEmojiForCode
|
||||||
import uniffi.olm.CryptoStoreErrorException
|
import uniffi.olm.CryptoStoreException
|
||||||
import uniffi.olm.OlmMachine
|
import uniffi.olm.OlmMachine
|
||||||
import uniffi.olm.Sas
|
import uniffi.olm.Sas
|
||||||
import uniffi.olm.Verification
|
import uniffi.olm.Verification
|
||||||
@ -202,7 +202,7 @@ internal class SasVerification(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
private suspend fun confirm() {
|
private suspend fun confirm() {
|
||||||
val result = withContext(Dispatchers.IO) {
|
val result = withContext(Dispatchers.IO) {
|
||||||
machine.confirmVerification(inner.otherUserId, inner.flowId)
|
machine.confirmVerification(inner.otherUserId, inner.flowId)
|
||||||
|
@ -25,8 +25,8 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
|||||||
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.model.CryptoCrossSigningKey
|
import org.matrix.android.sdk.internal.crypto.model.CryptoCrossSigningKey
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
|
import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
|
||||||
import uniffi.olm.CryptoStoreErrorException
|
import uniffi.olm.CryptoStoreException
|
||||||
import uniffi.olm.SignatureErrorException
|
import uniffi.olm.SignatureException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sealed class representing user identities.
|
* A sealed class representing user identities.
|
||||||
@ -46,7 +46,7 @@ sealed class UserIdentities {
|
|||||||
*
|
*
|
||||||
* @return True if the identity is considered to be verified and trusted, false otherwise.
|
* @return True if the identity is considered to be verified and trusted, false otherwise.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
abstract suspend fun verified(): Boolean
|
abstract suspend fun verified(): Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,7 +59,7 @@ sealed class UserIdentities {
|
|||||||
* Throws a SignatureErrorException if we can't sign the identity,
|
* Throws a SignatureErrorException if we can't sign the identity,
|
||||||
* if for example we don't have access to our user-signing key.
|
* if for example we don't have access to our user-signing key.
|
||||||
*/
|
*/
|
||||||
@Throws(SignatureErrorException::class)
|
@Throws(SignatureException::class)
|
||||||
abstract suspend fun verify()
|
abstract suspend fun verify()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,7 +93,7 @@ internal class OwnUserIdentity(
|
|||||||
*
|
*
|
||||||
* To perform an interactive verification user the [requestVerification] method instead.
|
* To perform an interactive verification user the [requestVerification] method instead.
|
||||||
*/
|
*/
|
||||||
@Throws(SignatureErrorException::class)
|
@Throws(SignatureException::class)
|
||||||
override suspend fun verify() {
|
override suspend fun verify() {
|
||||||
val request = withContext(Dispatchers.Default) { olmMachine.inner().verifyIdentity(userId) }
|
val request = withContext(Dispatchers.Default) { olmMachine.inner().verifyIdentity(userId) }
|
||||||
this.requestSender.sendSignatureUpload(request)
|
this.requestSender.sendSignatureUpload(request)
|
||||||
@ -104,7 +104,7 @@ internal class OwnUserIdentity(
|
|||||||
*
|
*
|
||||||
* @return True if the identity is considered to be verified and trusted, false otherwise.
|
* @return True if the identity is considered to be verified and trusted, false otherwise.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
override suspend fun verified(): Boolean {
|
override suspend fun verified(): Boolean {
|
||||||
return withContext(Dispatchers.IO) { olmMachine.inner().isIdentityVerified(userId) }
|
return withContext(Dispatchers.IO) { olmMachine.inner().isIdentityVerified(userId) }
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ internal class OwnUserIdentity(
|
|||||||
* @param methods The list of [VerificationMethod] that we wish to advertise to the other
|
* @param methods The list of [VerificationMethod] that we wish to advertise to the other
|
||||||
* side as being supported.
|
* side as being supported.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun requestVerification(methods: List<VerificationMethod>): VerificationRequest {
|
suspend fun requestVerification(methods: List<VerificationMethod>): VerificationRequest {
|
||||||
val stringMethods = prepareMethods(methods)
|
val stringMethods = prepareMethods(methods)
|
||||||
val result = this.olmMachine.inner().requestSelfVerification(stringMethods)
|
val result = this.olmMachine.inner().requestSelfVerification(stringMethods)
|
||||||
@ -187,7 +187,7 @@ internal class UserIdentity(
|
|||||||
*
|
*
|
||||||
* To perform an interactive verification user the [requestVerification] method instead.
|
* To perform an interactive verification user the [requestVerification] method instead.
|
||||||
*/
|
*/
|
||||||
@Throws(SignatureErrorException::class)
|
@Throws(SignatureException::class)
|
||||||
override suspend fun verify() {
|
override suspend fun verify() {
|
||||||
val request = withContext(Dispatchers.Default) { olmMachine.inner().verifyIdentity(userId) }
|
val request = withContext(Dispatchers.Default) { olmMachine.inner().verifyIdentity(userId) }
|
||||||
this.requestSender.sendSignatureUpload(request)
|
this.requestSender.sendSignatureUpload(request)
|
||||||
@ -225,7 +225,7 @@ internal class UserIdentity(
|
|||||||
* @param transactionId The transaction id that should be used for the request that sends
|
* @param transactionId The transaction id that should be used for the request that sends
|
||||||
* the `m.key.verification.request` to the room.
|
* the `m.key.verification.request` to the room.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreErrorException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun requestVerification(
|
suspend fun requestVerification(
|
||||||
methods: List<VerificationMethod>,
|
methods: List<VerificationMethod>,
|
||||||
roomId: String,
|
roomId: String,
|
||||||
|
@ -84,6 +84,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import okhttp3.internal.wait
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmBackupAuthData
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmBackupAuthData
|
||||||
import org.matrix.olm.OlmException
|
import org.matrix.olm.OlmException
|
||||||
import org.matrix.olm.OlmPkDecryption
|
import org.matrix.olm.OlmPkDecryption
|
||||||
|
@ -42,6 +42,7 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmB
|
|||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.CreateKeysBackupVersionBody
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.CreateKeysBackupVersionBody
|
||||||
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.rest.KeysVersionResult
|
||||||
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.UpdateKeysBackupVersionBody
|
||||||
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
|
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
|
||||||
import org.matrix.android.sdk.internal.crypto.store.SavedKeyBackupKeyInfo
|
import org.matrix.android.sdk.internal.crypto.store.SavedKeyBackupKeyInfo
|
||||||
import org.matrix.android.sdk.internal.extensions.foldToCallback
|
import org.matrix.android.sdk.internal.extensions.foldToCallback
|
||||||
@ -266,34 +267,148 @@ internal class RustKeyBackupService @Inject constructor(
|
|||||||
|
|
||||||
override fun backupAllGroupSessions(progressListener: ProgressListener?,
|
override fun backupAllGroupSessions(progressListener: ProgressListener?,
|
||||||
callback: MatrixCallback<Unit>?) {
|
callback: MatrixCallback<Unit>?) {
|
||||||
|
// This is only used in tests?
|
||||||
TODO()
|
TODO()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun checkBackupTrust(authData: MegolmBackupAuthData?): KeysBackupVersionTrust {
|
||||||
|
return if (authData == null || authData.publicKey.isEmpty() || authData.signatures.isEmpty()) {
|
||||||
|
Timber.v("getKeysBackupTrust: Key backup is absent or missing required data")
|
||||||
|
KeysBackupVersionTrust()
|
||||||
|
} else {
|
||||||
|
KeysBackupVersionTrust(olmMachine.checkAuthDataSignature(authData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult,
|
override fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult,
|
||||||
callback: MatrixCallback<KeysBackupVersionTrust>) {
|
callback: MatrixCallback<KeysBackupVersionTrust>) {
|
||||||
Timber.d("BACKUP: HELLOO TRYING TO CHECK THE TRUST")
|
val authData = keysBackupVersion.getAuthDataAsMegolmBackupAuthData()
|
||||||
// TODO
|
|
||||||
callback.onSuccess(KeysBackupVersionTrust(false))
|
cryptoCoroutineScope.launch {
|
||||||
|
try {
|
||||||
|
callback.onSuccess(checkBackupTrust(authData))
|
||||||
|
} catch (exception: Throwable) {
|
||||||
|
callback.onFailure(exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun trustKeysBackupVersion(keysBackupVersion: KeysVersionResult,
|
override fun trustKeysBackupVersion(keysBackupVersion: KeysVersionResult,
|
||||||
trust: Boolean,
|
trust: Boolean,
|
||||||
callback: MatrixCallback<Unit>) {
|
callback: MatrixCallback<Unit>) {
|
||||||
Timber.v("trustKeyBackupVersion: $trust, version ${keysBackupVersion.version}")
|
Timber.v("trustKeyBackupVersion: $trust, version ${keysBackupVersion.version}")
|
||||||
TODO()
|
|
||||||
|
// Get auth data to update it
|
||||||
|
val authData = getMegolmBackupAuthData(keysBackupVersion)
|
||||||
|
|
||||||
|
if (authData == null) {
|
||||||
|
Timber.w("trustKeyBackupVersion:trust: Key backup is missing required data")
|
||||||
|
|
||||||
|
callback.onFailure(IllegalArgumentException("Missing element"))
|
||||||
|
} else {
|
||||||
|
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
||||||
|
val body = withContext(coroutineDispatchers.crypto) {
|
||||||
|
// Get current signatures, or create an empty set
|
||||||
|
val userId = olmMachine.userId()
|
||||||
|
val signatures = authData.signatures[userId].orEmpty().toMutableMap()
|
||||||
|
|
||||||
|
if (trust) {
|
||||||
|
// Add current device signature
|
||||||
|
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, authData.signalableJSONDictionary())
|
||||||
|
val deviceSignature = olmMachine.sign(canonicalJson)
|
||||||
|
|
||||||
|
deviceSignature[userId]?.forEach { entry ->
|
||||||
|
signatures[entry.key] = entry.value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
signatures.remove("ed25519:${olmMachine.deviceId()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
val newAuthData = authData.copy()
|
||||||
|
val newSignatures = newAuthData.signatures.toMutableMap()
|
||||||
|
newSignatures[userId] = signatures
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
UpdateKeysBackupVersionBody(
|
||||||
|
algorithm = keysBackupVersion.algorithm,
|
||||||
|
authData = newAuthData.copy(signatures = newSignatures).toJsonDict(),
|
||||||
|
version = keysBackupVersion.version)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
sender.updateBackup(keysBackupVersion, body)
|
||||||
|
|
||||||
|
val newKeysBackupVersion = KeysVersionResult(
|
||||||
|
algorithm = keysBackupVersion.algorithm,
|
||||||
|
authData = body.authData,
|
||||||
|
version = keysBackupVersion.version,
|
||||||
|
hash = keysBackupVersion.hash,
|
||||||
|
count = keysBackupVersion.count
|
||||||
|
)
|
||||||
|
|
||||||
|
checkAndStartWithKeysBackupVersion(newKeysBackupVersion)
|
||||||
|
callback.onSuccess(Unit)
|
||||||
|
} catch (exception: Throwable) {
|
||||||
|
callback.onFailure(exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the recovery key matches to the public key that we downloaded from the server.
|
||||||
|
// If they match, we can trust the public key and enable backups since we have the private key.
|
||||||
|
private fun checkRecoveryKey(recoveryKey: BackupRecoveryKey, keysBackupData: KeysVersionResult) {
|
||||||
|
val backupKey = recoveryKey.publicKey()
|
||||||
|
val authData = getMegolmBackupAuthData(keysBackupData)
|
||||||
|
|
||||||
|
when {
|
||||||
|
authData == null -> {
|
||||||
|
Timber.w("isValidRecoveryKeyForKeysBackupVersion: Key backup is missing required data")
|
||||||
|
throw IllegalArgumentException("Missing element")
|
||||||
|
|
||||||
|
}
|
||||||
|
backupKey.publicKey != authData.publicKey -> {
|
||||||
|
Timber.w("isValidRecoveryKeyForKeysBackupVersion: Public keys mismatch")
|
||||||
|
throw IllegalArgumentException("Invalid recovery key or password")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// This case is fine, the public key on the server matches the public key the
|
||||||
|
// recovery key produced.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult,
|
override fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult,
|
||||||
recoveryKey: String,
|
recoveryKey: String,
|
||||||
callback: MatrixCallback<Unit>) {
|
callback: MatrixCallback<Unit>) {
|
||||||
Timber.v("trustKeysBackupVersionWithRecoveryKey: version ${keysBackupVersion.version}")
|
Timber.v("trustKeysBackupVersionWithRecoveryKey: version ${keysBackupVersion.version}")
|
||||||
TODO()
|
|
||||||
|
cryptoCoroutineScope.launch {
|
||||||
|
try {
|
||||||
|
// This is ~nowhere mentioned, the string here is actually a base58 encoded key.
|
||||||
|
// This not really supported by the spec for the backup key, the 4S key supports
|
||||||
|
// base58 encoding and the same method seems to be used here.
|
||||||
|
val key = BackupRecoveryKey.fromBase58(recoveryKey)
|
||||||
|
checkRecoveryKey(key, keysBackupVersion)
|
||||||
|
trustKeysBackupVersion(keysBackupVersion, true, callback)
|
||||||
|
|
||||||
|
} catch (exception: Throwable) {
|
||||||
|
callback.onFailure(exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun trustKeysBackupVersionWithPassphrase(keysBackupVersion: KeysVersionResult,
|
override fun trustKeysBackupVersionWithPassphrase(keysBackupVersion: KeysVersionResult,
|
||||||
password: String,
|
password: String,
|
||||||
callback: MatrixCallback<Unit>) {
|
callback: MatrixCallback<Unit>) {
|
||||||
TODO()
|
cryptoCoroutineScope.launch {
|
||||||
|
try {
|
||||||
|
val key = BackupRecoveryKey.fromPassphrase(password)
|
||||||
|
checkRecoveryKey(key, keysBackupVersion)
|
||||||
|
trustKeysBackupVersion(keysBackupVersion, true, callback)
|
||||||
|
} catch (exception: Throwable) {
|
||||||
|
callback.onFailure(exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSecretKeyGossip(secret: String) {
|
override fun onSecretKeyGossip(secret: String) {
|
||||||
@ -437,8 +552,9 @@ internal class RustKeyBackupService @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Timber.v(" -> enabling key backups")
|
Timber.v(" -> enabling key backups")
|
||||||
// TODO
|
cryptoCoroutineScope.launch {
|
||||||
// enableKeysBackup(keyBackupVersion)
|
enableKeysBackup(keyBackupVersion)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.v("checkAndStartWithKeysBackupVersion: No usable key backup. version: ${keyBackupVersion.version}")
|
Timber.v("checkAndStartWithKeysBackupVersion: No usable key backup. version: ${keyBackupVersion.version}")
|
||||||
if (versionInStore != null) {
|
if (versionInStore != null) {
|
||||||
@ -595,7 +711,7 @@ internal class RustKeyBackupService @Inject constructor(
|
|||||||
olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_BACKUP, response)
|
olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_BACKUP, response)
|
||||||
Timber.d("BACKUP MARKED REQUEST AS SENT")
|
Timber.d("BACKUP MARKED REQUEST AS SENT")
|
||||||
|
|
||||||
// TODO again is this correct?
|
// TODO, again is this correct?
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
backupKeys()
|
backupKeys()
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ base64 = "0.13.0"
|
|||||||
thiserror = "1.0.25"
|
thiserror = "1.0.25"
|
||||||
tracing = "0.1.26"
|
tracing = "0.1.26"
|
||||||
tracing-subscriber = "0.2.18"
|
tracing-subscriber = "0.2.18"
|
||||||
uniffi = "0.12.0"
|
uniffi = "0.14.0"
|
||||||
pbkdf2 = "0.8.0"
|
pbkdf2 = "0.8.0"
|
||||||
sha2 = "0.9.5"
|
sha2 = "0.9.5"
|
||||||
rand = "0.8.4"
|
rand = "0.8.4"
|
||||||
@ -28,14 +28,14 @@ version = "0.2.1"
|
|||||||
features = ["lax_deserialize"]
|
features = ["lax_deserialize"]
|
||||||
|
|
||||||
[dependencies.matrix-sdk-common]
|
[dependencies.matrix-sdk-common]
|
||||||
path = "/home/poljar/werk/priv/nio-rust/crates/matrix-sdk-common/"
|
path = "/home/poljar/werk/matrix/nio-rust/crates/matrix-sdk-common/"
|
||||||
# git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
# git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
||||||
# rev = "9bae87b0ac213f9d37c033e76ea3a336e164cf02"
|
# rev = "9bae87b0ac213f9d37c033e76ea3a336e164cf02"
|
||||||
|
|
||||||
[dependencies.matrix-sdk-crypto]
|
[dependencies.matrix-sdk-crypto]
|
||||||
# git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
# git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
||||||
# rev = "9bae87b0ac213f9d37c033e76ea3a336e164cf02"
|
# rev = "9bae87b0ac213f9d37c033e76ea3a336e164cf02"
|
||||||
path = "/home/poljar/werk/priv/nio-rust/crates/matrix-sdk-crypto/"
|
path = "/home/poljar/werk/matrix/nio-rust/crates/matrix-sdk-crypto/"
|
||||||
features = ["sled_cryptostore", "qrcode", "backups_v1"]
|
features = ["sled_cryptostore", "qrcode", "backups_v1"]
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
missing_docs,
|
|
||||||
trivial_casts,
|
trivial_casts,
|
||||||
trivial_numeric_casts,
|
trivial_numeric_casts,
|
||||||
unused_extern_crates,
|
unused_extern_crates,
|
||||||
unused_import_braces,
|
unused_import_braces,
|
||||||
unused_qualifications
|
|
||||||
)]
|
)]
|
||||||
|
|
||||||
//! TODO
|
//! TODO
|
||||||
|
@ -1321,4 +1321,12 @@ impl OlmMachine {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
pub fn verify_backup(&self, auth_data: &str) -> Result<bool, CryptoStoreError> {
|
||||||
|
let auth_data = serde_json::from_str(auth_data)?;
|
||||||
|
Ok(self
|
||||||
|
.runtime
|
||||||
|
.block_on(self.inner.backup_machine().verify_backup(auth_data))?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,6 +360,8 @@ interface OlmMachine {
|
|||||||
[Throws=CryptoStoreError]
|
[Throws=CryptoStoreError]
|
||||||
BackupKeys? get_backup_keys();
|
BackupKeys? get_backup_keys();
|
||||||
boolean backup_enabled();
|
boolean backup_enabled();
|
||||||
|
[Throws=CryptoStoreError]
|
||||||
|
boolean verify_backup([ByRef] string auth_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary PassphraseInfo {
|
dictionary PassphraseInfo {
|
||||||
@ -389,6 +391,8 @@ interface BackupRecoveryKey {
|
|||||||
constructor(string key);
|
constructor(string key);
|
||||||
[Name=from_passphrase]
|
[Name=from_passphrase]
|
||||||
constructor(string key);
|
constructor(string key);
|
||||||
|
[Name=from_base58]
|
||||||
|
constructor(string key);
|
||||||
string to_base58();
|
string to_base58();
|
||||||
BackupKey public_key();
|
BackupKey public_key();
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user