crypto: Use the rust crypto layer to upload device/one-time keys

This commit is contained in:
Damir Jelić 2021-02-12 16:45:31 +01:00
parent 1eeb97ec51
commit 3ddbe7e69b
5 changed files with 83 additions and 30 deletions

View File

@ -72,6 +72,7 @@ import org.matrix.android.sdk.internal.crypto.tasks.DefaultSendToDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultSendVerificationMessageTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultSendVerificationMessageTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultSetDeviceNameTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultSetDeviceNameTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadKeysTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadKeysTask
import org.matrix.android.sdk.internal.crypto.tasks.NewDefaultUploadKeysTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadSignaturesTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadSignaturesTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadSigningKeysTask import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadSigningKeysTask
import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask
@ -86,6 +87,7 @@ import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.SendVerificationMessageTask import org.matrix.android.sdk.internal.crypto.tasks.SendVerificationMessageTask
import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
import org.matrix.android.sdk.internal.crypto.tasks.NewUploadKeysTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadSignaturesTask import org.matrix.android.sdk.internal.crypto.tasks.UploadSignaturesTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadSigningKeysTask import org.matrix.android.sdk.internal.crypto.tasks.UploadSigningKeysTask
import org.matrix.android.sdk.internal.database.RealmKeysUtils import org.matrix.android.sdk.internal.database.RealmKeysUtils
@ -177,6 +179,9 @@ internal abstract class CryptoModule {
@Binds @Binds
abstract fun bindUploadKeysTask(task: DefaultUploadKeysTask): UploadKeysTask abstract fun bindUploadKeysTask(task: DefaultUploadKeysTask): UploadKeysTask
@Binds
abstract fun bindNewUploadKeysTask(task: NewDefaultUploadKeysTask): NewUploadKeysTask
@Binds @Binds
abstract fun bindUploadSigningKeysTask(task: DefaultUploadSigningKeysTask): UploadSigningKeysTask abstract fun bindUploadSigningKeysTask(task: DefaultUploadSigningKeysTask): UploadSigningKeysTask

View File

@ -55,6 +55,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.OlmMachine import org.matrix.android.sdk.internal.OlmMachine
import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
@ -76,14 +77,15 @@ import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyWithHeldContent
import org.matrix.android.sdk.internal.crypto.model.event.SecretSendEventContent import org.matrix.android.sdk.internal.crypto.model.event.SecretSendEventContent
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse
import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody
import org.matrix.android.sdk.internal.crypto.model.toRest
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceWithUserPasswordTask import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceWithUserPasswordTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask
import org.matrix.android.sdk.internal.crypto.tasks.NewUploadKeysTask
import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService
@ -99,11 +101,11 @@ import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.TaskThread import org.matrix.android.sdk.internal.task.TaskThread
import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.task.launchToCallback import org.matrix.android.sdk.internal.task.launchToCallback
import org.matrix.android.sdk.internal.util.JsonCanonicalizer
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import org.matrix.olm.OlmManager import org.matrix.olm.OlmManager
import timber.log.Timber import timber.log.Timber
import uniffi.olm.Request import uniffi.olm.Request
import uniffi.olm.RequestType
/** /**
* A `CryptoService` class instance manages the end-to-end crypto for a session. * A `CryptoService` class instance manages the end-to-end crypto for a session.
@ -166,6 +168,7 @@ internal class DefaultCryptoService @Inject constructor(
private val getDeviceInfoTask: GetDeviceInfoTask, private val getDeviceInfoTask: GetDeviceInfoTask,
private val setDeviceNameTask: SetDeviceNameTask, private val setDeviceNameTask: SetDeviceNameTask,
private val uploadKeysTask: UploadKeysTask, private val uploadKeysTask: UploadKeysTask,
private val newUploadKeysTask: NewUploadKeysTask,
private val loadRoomMembersTask: LoadRoomMembersTask, private val loadRoomMembersTask: LoadRoomMembersTask,
private val cryptoSessionInfoProvider: CryptoSessionInfoProvider, private val cryptoSessionInfoProvider: CryptoSessionInfoProvider,
private val coroutineDispatchers: MatrixCoroutineDispatchers, private val coroutineDispatchers: MatrixCoroutineDispatchers,
@ -337,7 +340,7 @@ internal class DefaultCryptoService @Inject constructor(
uploadDeviceKeys() uploadDeviceKeys()
} }
oneTimeKeysUploader.maybeUploadOneTimeKeys() // oneTimeKeysUploader.maybeUploadOneTimeKeys()
// this can throw if no backup // this can throw if no backup
tryOrNull { tryOrNull {
keysBackupService.checkAndStartKeysBackup() keysBackupService.checkAndStartKeysBackup()
@ -374,16 +377,7 @@ internal class DefaultCryptoService @Inject constructor(
try { try {
olmMachine = OlmMachine(userId, deviceId!!, dataDir) olmMachine = OlmMachine(userId, deviceId!!, dataDir)
Timber.v("HELLLO WORLD STARTING CRYPTO ${olmMachine?.identityKeys()}") Timber.v("HELLLO WORLD STARTING $dataDir CRYPTO ${olmMachine?.identityKeys()}")
// TODO sent out those requests in a sensible place.
for (request in olmMachine!!.outgoingRequests()) {
when (request) {
is Request.KeysUpload -> Timber.v("HELLO KEYS UPLOAD REQUEST ${request.body}")
is Request.KeysQuery -> Timber.v("HELLO KEYS QUERY REQUEST ${request.body}")
is Request.ToDevice -> Timber.v("HELLO TO DEVICE REQUEST ${request.body}")
}
}
} catch (throwable: Throwable) { } catch (throwable: Throwable) {
Timber.v("HELLLO WORLD FAILED CRYPTO $throwable") Timber.v("HELLLO WORLD FAILED CRYPTO $throwable")
} }
@ -444,7 +438,11 @@ internal class DefaultCryptoService @Inject constructor(
* *
* @param syncResponse the syncResponse * @param syncResponse the syncResponse
*/ */
fun onSyncCompleted(syncResponse: SyncResponse) { suspend fun onSyncCompleted(syncResponse: SyncResponse) {
if (isStarted()) {
sendOutgoingRequests()
}
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
runCatching { runCatching {
if (syncResponse.deviceLists != null) { if (syncResponse.deviceLists != null) {
@ -457,7 +455,7 @@ internal class DefaultCryptoService @Inject constructor(
if (isStarted()) { if (isStarted()) {
// Make sure we process to-device messages before generating new one-time-keys #2782 // Make sure we process to-device messages before generating new one-time-keys #2782
deviceListManager.refreshOutdatedDeviceLists() deviceListManager.refreshOutdatedDeviceLists()
oneTimeKeysUploader.maybeUploadOneTimeKeys() // oneTimeKeysUploader.maybeUploadOneTimeKeys()
incomingGossipingRequestManager.processReceivedGossipingRequests() incomingGossipingRequestManager.processReceivedGossipingRequests()
} }
} }
@ -939,27 +937,49 @@ internal class DefaultCryptoService @Inject constructor(
} }
} }
private suspend fun sendOutgoingRequests() {
// TODO these requests should be sent out in parallel
for (outgoingRequest in olmMachine!!.outgoingRequests()) {
when (outgoingRequest) {
is Request.KeysUpload -> {
Timber.v("HELLO UPLOADING RUSTY KEYS")
val body = MoshiProvider.providesMoshi().adapter<JsonDict>(Map::class.java).fromJson(outgoingRequest.body)!!
val request = NewUploadKeysTask.Params(body)
val response = newUploadKeysTask.execute(request)
val adapter = MoshiProvider.providesMoshi().adapter<KeysUploadResponse>(KeysUploadResponse::class.java)
val json_response = adapter.toJson(response)!!
olmMachine!!.markRequestAsSent(outgoingRequest.requestId, RequestType.KEYS_UPLOAD, json_response)
Timber.v("HELLO UPLOADED KEYS $response")
}
is Request.KeysQuery -> Timber.v("HELLO KEYS QUERY REQUEST ${outgoingRequest.body}")
is Request.ToDevice -> Timber.v("HELLO TO DEVICE REQUEST ${outgoingRequest.body}")
}
}
}
/** /**
* Upload my user's device keys. * Upload my user's device keys.
*/ */
private suspend fun uploadDeviceKeys() { private suspend fun uploadDeviceKeys() {
if (cryptoStore.getDeviceKeysUploaded()) { // sendOutgoingRequests()
Timber.d("Keys already uploaded, nothing to do") // if (cryptoStore.getDeviceKeysUploaded()) {
return // Timber.d("Keys already uploaded, nothing to do")
} // return
// Prepare the device keys data to send // }
// Sign it // // Prepare the device keys data to send
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary()) // // Sign it
var rest = getMyDevice().toRest() // val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary())
// var rest = getMyDevice().toRest()
rest = rest.copy( // rest = rest.copy(
signatures = objectSigner.signObject(canonicalJson) // signatures = objectSigner.signObject(canonicalJson)
) // )
val uploadDeviceKeysParams = UploadKeysTask.Params(rest, null) // val uploadDeviceKeysParams = UploadKeysTask.Params(rest, null)
uploadKeysTask.execute(uploadDeviceKeysParams) // uploadKeysTask.execute(uploadDeviceKeysParams)
cryptoStore.setDeviceKeysUploaded(true) // cryptoStore.setDeviceKeysUploaded(true)
} }
/** /**

View File

@ -15,6 +15,7 @@
*/ */
package org.matrix.android.sdk.internal.crypto.api package org.matrix.android.sdk.internal.crypto.api
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.crypto.model.rest.DeleteDeviceParams import org.matrix.android.sdk.internal.crypto.model.rest.DeleteDeviceParams
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse
@ -64,6 +65,13 @@ internal interface CryptoApi {
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "keys/upload") @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "keys/upload")
fun uploadKeys(@Body body: KeysUploadBody): Call<KeysUploadResponse> fun uploadKeys(@Body body: KeysUploadBody): Call<KeysUploadResponse>
/**
* Upload device and one-time keys
* @param body the keys to be sent.
*/
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "keys/upload")
fun newUploadKeys(@Body body: JsonDict): Call<KeysUploadResponse>
/** /**
* Download device keys. * Download device keys.
* Doc: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-keys-query * Doc: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-keys-query

View File

@ -54,3 +54,23 @@ internal class DefaultUploadKeysTask @Inject constructor(
} }
} }
} }
internal interface NewUploadKeysTask : Task<NewUploadKeysTask.Params, KeysUploadResponse> {
data class Params(
val body: JsonDict
)
}
internal class NewDefaultUploadKeysTask @Inject constructor(
private val cryptoApi: CryptoApi,
private val globalErrorReceiver: GlobalErrorReceiver
) : NewUploadKeysTask {
override suspend fun execute(params: NewUploadKeysTask.Params): KeysUploadResponse {
Timber.i("## Uploading device keys -> $params.body")
return executeRequest(globalErrorReceiver) {
apiCall = cryptoApi.newUploadKeys(params.body)
}
}
}

View File

@ -52,7 +52,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
} }
} }
fun onSyncCompleted(syncResponse: SyncResponse) { suspend fun onSyncCompleted(syncResponse: SyncResponse) {
cryptoService.onSyncCompleted(syncResponse) cryptoService.onSyncCompleted(syncResponse)
} }