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.lifecycle.LiveData
|
||||
import androidx.paging.PagedList
|
||||
import com.squareup.moshi.Types
|
||||
import dagger.Lazy
|
||||
import kotlinx.coroutines.CancellationException
|
||||
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.crypto.crosssigning.DeviceTrustLevel
|
||||
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.CreateKeysBackupVersionBody
|
||||
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.KeysVersionResult
|
||||
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.DeleteBackupTask
|
||||
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.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.ImportRoomKeysResult
|
||||
import org.matrix.android.sdk.internal.crypto.model.MXEncryptEventContentResult
|
||||
|
@ -137,6 +141,7 @@ internal class RequestSender @Inject constructor(
|
|||
private val deleteBackupTask: DeleteBackupTask,
|
||||
private val createKeysBackupVersionTask: CreateKeysBackupVersionTask,
|
||||
private val backupRoomKeysTask: StoreSessionsDataTask,
|
||||
private val updateKeysBackupVersionTask: UpdateKeysBackupVersionTask,
|
||||
) {
|
||||
companion object {
|
||||
const val REQUEST_RETRY_COUNT = 3
|
||||
|
@ -297,44 +302,25 @@ internal class RequestSender @Inject constructor(
|
|||
val adapter = MoshiProvider
|
||||
.providesMoshi()
|
||||
.newBuilder()
|
||||
.add(CheckNumberType.JSON_ADAPTER_FACTORY)
|
||||
.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)!!
|
||||
Timber.d("BACKUP: CONVERTED KEYS TO HASHMAP $keys")
|
||||
/*
|
||||
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 params = StoreSessionsDataTask.Params(request.version, KeysBackupData(keys))
|
||||
val response = backupRoomKeysTask.executeRetry(params, REQUEST_RETRY_COUNT)
|
||||
val responseAdapter = MoshiProvider.providesMoshi().adapter(BackupKeysResult::class.java)
|
||||
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")
|
||||
}
|
||||
|
||||
// We try to enable key backups, if the backup version on the server is trusted,
|
||||
// we're gonna continue backing up.
|
||||
tryOrNull {
|
||||
keysBackupService!!.checkAndStartKeysBackup()
|
||||
}
|
||||
|
@ -1075,7 +1063,8 @@ internal class DefaultCryptoService @Inject constructor(
|
|||
}
|
||||
is Request.KeysBackup -> {
|
||||
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.rest.UnsignedDeviceInfo
|
||||
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.OlmMachine
|
||||
import uniffi.olm.SignatureErrorException
|
||||
import uniffi.olm.SignatureException
|
||||
import uniffi.olm.VerificationRequest
|
||||
|
||||
/** Class representing a device that supports E2EE in the Matrix world
|
||||
|
@ -41,7 +41,7 @@ internal class Device(
|
|||
private val sender: RequestSender,
|
||||
private val listeners: ArrayList<VerificationService.Listener>,
|
||||
) {
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
private suspend fun refreshData() {
|
||||
val device = withContext(Dispatchers.IO) {
|
||||
machine.getDevice(inner.userId, inner.deviceId)
|
||||
|
@ -63,7 +63,7 @@ internal class Device(
|
|||
* [org.matrix.android.sdk.internal.crypto.OwnUserIdentity.requestVerification]
|
||||
* method can be used instead.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun requestVerification(methods: List<VerificationMethod>): VerificationRequest? {
|
||||
val stringMethods = prepareMethods(methods)
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
|
@ -87,7 +87,7 @@ internal class Device(
|
|||
* The [requestVerification] method should be used instead.
|
||||
*
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun startVerification(): SasVerification? {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
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
|
||||
* in the local database.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun markAsTrusted() {
|
||||
withContext(Dispatchers.IO) {
|
||||
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
|
||||
* private part of our self-signing key.
|
||||
*/
|
||||
@Throws(SignatureErrorException::class)
|
||||
@Throws(SignatureException::class)
|
||||
suspend fun verify(): Boolean {
|
||||
val request = withContext(Dispatchers.IO) {
|
||||
machine.verifyDevice(inner.userId, inner.deviceId)
|
||||
|
@ -139,7 +139,7 @@ internal class Device(
|
|||
/**
|
||||
* Get the DeviceTrustLevel of this device
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun trustLevel(): DeviceTrustLevel {
|
||||
refreshData()
|
||||
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.MutableLiveData
|
||||
import com.squareup.moshi.Types
|
||||
import java.io.File
|
||||
import java.nio.charset.Charset
|
||||
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.internal.crypto.crosssigning.DeviceTrustLevel
|
||||
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.ImportRoomKeysResult
|
||||
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.store.PrivateKeysInfo
|
||||
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.DeviceOneTimeKeysCountSyncResponse
|
||||
import org.matrix.android.sdk.internal.session.sync.model.ToDeviceSyncResponse
|
||||
import org.matrix.android.sdk.internal.util.JsonCanonicalizer
|
||||
import timber.log.Timber
|
||||
import uniffi.olm.BackupKey
|
||||
import uniffi.olm.BackupKeys
|
||||
import uniffi.olm.CrossSigningKeyExport
|
||||
import uniffi.olm.CrossSigningStatus
|
||||
import uniffi.olm.CryptoStoreErrorException
|
||||
import uniffi.olm.DecryptionErrorException
|
||||
import uniffi.olm.CryptoStoreException
|
||||
import uniffi.olm.DecryptionException
|
||||
import uniffi.olm.DeviceLists
|
||||
import uniffi.olm.KeyRequestPair
|
||||
import uniffi.olm.Logger
|
||||
|
@ -262,7 +267,7 @@ internal class OlmMachine(
|
|||
*
|
||||
* @param responseBody The body of the response that was received.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun markRequestAsSent(
|
||||
requestId: String,
|
||||
requestType: RequestType,
|
||||
|
@ -290,7 +295,7 @@ internal class OlmMachine(
|
|||
*
|
||||
* @param keyCounts The map of uploaded one-time key types and counts.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun receiveSyncChanges(
|
||||
toDevice: ToDeviceSyncResponse?,
|
||||
deviceChanges: DeviceListResponse?,
|
||||
|
@ -342,7 +347,7 @@ internal class OlmMachine(
|
|||
*
|
||||
* @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? =
|
||||
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.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun shareRoomKey(roomId: String, users: List<String>): List<Request> =
|
||||
withContext(Dispatchers.IO) { inner.shareRoomKey(roomId, users) }
|
||||
|
||||
|
@ -398,7 +403,7 @@ internal class OlmMachine(
|
|||
*
|
||||
* @return The encrypted version of the [Content]
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun encrypt(roomId: String, eventType: String, content: Content): Content =
|
||||
withContext(Dispatchers.IO) {
|
||||
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
|
||||
* will ignore the key request.
|
||||
*/
|
||||
@Throws(DecryptionErrorException::class)
|
||||
@Throws(DecryptionException::class)
|
||||
suspend fun requestRoomKey(event: Event): KeyRequestPair =
|
||||
withContext(Dispatchers.IO) {
|
||||
val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java)
|
||||
|
@ -472,7 +477,7 @@ internal class OlmMachine(
|
|||
*
|
||||
* @return the encrypted key export as a bytearray.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun exportKeys(passphrase: String, rounds: Int): ByteArray =
|
||||
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.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun importKeys(
|
||||
keys: ByteArray,
|
||||
passphrase: String,
|
||||
|
@ -501,7 +506,7 @@ internal class OlmMachine(
|
|||
ImportRoomKeysResult(result.total, result.imported)
|
||||
}
|
||||
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun getIdentity(userId: String): UserIdentities? {
|
||||
val identity = withContext(Dispatchers.IO) {
|
||||
inner.getIdentity(userId)
|
||||
|
@ -545,7 +550,7 @@ internal class OlmMachine(
|
|||
*
|
||||
* @return The Device if it found one.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun getCryptoDeviceInfo(userId: String, deviceId: String): CryptoDeviceInfo? {
|
||||
return if (userId == userId() && deviceId == deviceId()) {
|
||||
// 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? {
|
||||
val device = withContext(Dispatchers.IO) {
|
||||
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.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo> {
|
||||
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. */
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
fun discardRoomKey(roomId: String) {
|
||||
runBlocking { inner.discardRoomKey(roomId) }
|
||||
}
|
||||
|
@ -770,7 +775,7 @@ internal class OlmMachine(
|
|||
}
|
||||
}
|
||||
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun enableBackup(key: String, version: String) {
|
||||
return withContext(Dispatchers.Default) {
|
||||
val backupKey = BackupKey(key, mapOf(), null)
|
||||
|
@ -797,7 +802,7 @@ internal class OlmMachine(
|
|||
inner.saveRecoveryKey(key, version)
|
||||
}
|
||||
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun backupRoomKeys(): Request? {
|
||||
return withContext(Dispatchers.Default) {
|
||||
Timber.d("BACKUP CREATING REQUEST")
|
||||
|
@ -806,4 +811,18 @@ internal class OlmMachine(
|
|||
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.internal.crypto.crosssigning.fromBase64
|
||||
import org.matrix.android.sdk.internal.crypto.verification.UpdateDispatcher
|
||||
import uniffi.olm.CryptoStoreErrorException
|
||||
import uniffi.olm.CryptoStoreException
|
||||
import uniffi.olm.OlmMachine
|
||||
import uniffi.olm.QrCode
|
||||
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,
|
||||
* 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() {
|
||||
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.internal.crypto.verification.UpdateDispatcher
|
||||
import org.matrix.android.sdk.internal.crypto.verification.getEmojiForCode
|
||||
import uniffi.olm.CryptoStoreErrorException
|
||||
import uniffi.olm.CryptoStoreException
|
||||
import uniffi.olm.OlmMachine
|
||||
import uniffi.olm.Sas
|
||||
import uniffi.olm.Verification
|
||||
|
@ -202,7 +202,7 @@ internal class SasVerification(
|
|||
}
|
||||
}
|
||||
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
private suspend fun confirm() {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
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.model.CryptoCrossSigningKey
|
||||
import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
|
||||
import uniffi.olm.CryptoStoreErrorException
|
||||
import uniffi.olm.SignatureErrorException
|
||||
import uniffi.olm.CryptoStoreException
|
||||
import uniffi.olm.SignatureException
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
abstract suspend fun verified(): Boolean
|
||||
|
||||
/**
|
||||
|
@ -59,7 +59,7 @@ sealed class UserIdentities {
|
|||
* Throws a SignatureErrorException if we can't sign the identity,
|
||||
* if for example we don't have access to our user-signing key.
|
||||
*/
|
||||
@Throws(SignatureErrorException::class)
|
||||
@Throws(SignatureException::class)
|
||||
abstract suspend fun verify()
|
||||
|
||||
/**
|
||||
|
@ -93,7 +93,7 @@ internal class OwnUserIdentity(
|
|||
*
|
||||
* To perform an interactive verification user the [requestVerification] method instead.
|
||||
*/
|
||||
@Throws(SignatureErrorException::class)
|
||||
@Throws(SignatureException::class)
|
||||
override suspend fun verify() {
|
||||
val request = withContext(Dispatchers.Default) { olmMachine.inner().verifyIdentity(userId) }
|
||||
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.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
override suspend fun verified(): Boolean {
|
||||
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
|
||||
* side as being supported.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun requestVerification(methods: List<VerificationMethod>): VerificationRequest {
|
||||
val stringMethods = prepareMethods(methods)
|
||||
val result = this.olmMachine.inner().requestSelfVerification(stringMethods)
|
||||
|
@ -187,7 +187,7 @@ internal class UserIdentity(
|
|||
*
|
||||
* To perform an interactive verification user the [requestVerification] method instead.
|
||||
*/
|
||||
@Throws(SignatureErrorException::class)
|
||||
@Throws(SignatureException::class)
|
||||
override suspend fun verify() {
|
||||
val request = withContext(Dispatchers.Default) { olmMachine.inner().verifyIdentity(userId) }
|
||||
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
|
||||
* the `m.key.verification.request` to the room.
|
||||
*/
|
||||
@Throws(CryptoStoreErrorException::class)
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun requestVerification(
|
||||
methods: List<VerificationMethod>,
|
||||
roomId: String,
|
||||
|
|
|
@ -84,6 +84,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.internal.wait
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmBackupAuthData
|
||||
import org.matrix.olm.OlmException
|
||||
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.KeysVersion
|
||||
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.store.SavedKeyBackupKeyInfo
|
||||
import org.matrix.android.sdk.internal.extensions.foldToCallback
|
||||
|
@ -266,34 +267,148 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
|
||||
override fun backupAllGroupSessions(progressListener: ProgressListener?,
|
||||
callback: MatrixCallback<Unit>?) {
|
||||
// This is only used in tests?
|
||||
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,
|
||||
callback: MatrixCallback<KeysBackupVersionTrust>) {
|
||||
Timber.d("BACKUP: HELLOO TRYING TO CHECK THE TRUST")
|
||||
// TODO
|
||||
callback.onSuccess(KeysBackupVersionTrust(false))
|
||||
val authData = keysBackupVersion.getAuthDataAsMegolmBackupAuthData()
|
||||
|
||||
cryptoCoroutineScope.launch {
|
||||
try {
|
||||
callback.onSuccess(checkBackupTrust(authData))
|
||||
} catch (exception: Throwable) {
|
||||
callback.onFailure(exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun trustKeysBackupVersion(keysBackupVersion: KeysVersionResult,
|
||||
trust: Boolean,
|
||||
callback: MatrixCallback<Unit>) {
|
||||
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,
|
||||
recoveryKey: String,
|
||||
callback: MatrixCallback<Unit>) {
|
||||
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,
|
||||
password: String,
|
||||
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) {
|
||||
|
@ -437,8 +552,9 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
}
|
||||
|
||||
Timber.v(" -> enabling key backups")
|
||||
// TODO
|
||||
// enableKeysBackup(keyBackupVersion)
|
||||
cryptoCoroutineScope.launch {
|
||||
enableKeysBackup(keyBackupVersion)
|
||||
}
|
||||
} else {
|
||||
Timber.v("checkAndStartWithKeysBackupVersion: No usable key backup. version: ${keyBackupVersion.version}")
|
||||
if (versionInStore != null) {
|
||||
|
@ -595,7 +711,7 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_BACKUP, response)
|
||||
Timber.d("BACKUP MARKED REQUEST AS SENT")
|
||||
|
||||
// TODO again is this correct?
|
||||
// TODO, again is this correct?
|
||||
withContext(Dispatchers.Main) {
|
||||
backupKeys()
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ base64 = "0.13.0"
|
|||
thiserror = "1.0.25"
|
||||
tracing = "0.1.26"
|
||||
tracing-subscriber = "0.2.18"
|
||||
uniffi = "0.12.0"
|
||||
uniffi = "0.14.0"
|
||||
pbkdf2 = "0.8.0"
|
||||
sha2 = "0.9.5"
|
||||
rand = "0.8.4"
|
||||
|
@ -28,14 +28,14 @@ version = "0.2.1"
|
|||
features = ["lax_deserialize"]
|
||||
|
||||
[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/"
|
||||
# rev = "9bae87b0ac213f9d37c033e76ea3a336e164cf02"
|
||||
|
||||
[dependencies.matrix-sdk-crypto]
|
||||
# git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
||||
# 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"]
|
||||
|
||||
[dependencies.tokio]
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
#![deny(
|
||||
dead_code,
|
||||
missing_docs,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_extern_crates,
|
||||
unused_import_braces,
|
||||
unused_qualifications
|
||||
)]
|
||||
|
||||
//! TODO
|
||||
|
|
|
@ -1321,4 +1321,12 @@ impl OlmMachine {
|
|||
})
|
||||
.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]
|
||||
BackupKeys? get_backup_keys();
|
||||
boolean backup_enabled();
|
||||
[Throws=CryptoStoreError]
|
||||
boolean verify_backup([ByRef] string auth_data);
|
||||
};
|
||||
|
||||
dictionary PassphraseInfo {
|
||||
|
@ -389,6 +391,8 @@ interface BackupRecoveryKey {
|
|||
constructor(string key);
|
||||
[Name=from_passphrase]
|
||||
constructor(string key);
|
||||
[Name=from_base58]
|
||||
constructor(string key);
|
||||
string to_base58();
|
||||
BackupKey public_key();
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue