Incoming Secret Share request support

crypto DB migration
This commit is contained in:
Valere 2020-02-26 19:11:20 +01:00
parent 8ff31ac49d
commit b67735c31a
30 changed files with 871 additions and 329 deletions

View file

@ -34,7 +34,6 @@ import im.vector.matrix.android.common.assertDictEquals
import im.vector.matrix.android.common.assertListEquals
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
import im.vector.matrix.android.internal.crypto.MegolmSessionData
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel
import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrust
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
@ -335,9 +334,9 @@ class KeysBackupTest : InstrumentedTest {
// - Check the SDK sent key share requests
val cryptoStore2 = (testData.aliceSession2.cryptoService().keysBackupService() as DefaultKeysBackupService).store
val unsentRequest = cryptoStore2
.getOutgoingRoomKeyRequestByState(setOf(OutgoingRoomKeyRequest.RequestState.UNSENT))
.getOutgoingRoomKeyRequestByState(setOf(ShareRequestState.UNSENT))
val sentRequest = cryptoStore2
.getOutgoingRoomKeyRequestByState(setOf(OutgoingRoomKeyRequest.RequestState.SENT))
.getOutgoingRoomKeyRequestByState(setOf(ShareRequestState.SENT))
// Request is either sent or unsent
assertTrue(unsentRequest != null || sentRequest != null)
@ -357,9 +356,9 @@ class KeysBackupTest : InstrumentedTest {
// - There must be no more pending key share requests
val unsentRequestAfterRestoration = cryptoStore2
.getOutgoingRoomKeyRequestByState(setOf(OutgoingRoomKeyRequest.RequestState.UNSENT))
.getOutgoingRoomKeyRequestByState(setOf(ShareRequestState.UNSENT))
val sentRequestAfterRestoration = cryptoStore2
.getOutgoingRoomKeyRequestByState(setOf(OutgoingRoomKeyRequest.RequestState.SENT))
.getOutgoingRoomKeyRequestByState(setOf(ShareRequestState.SENT))
// Request is either sent or unsent
assertTrue(unsentRequestAfterRestoration == null && sentRequestAfterRestoration == null)

View file

@ -22,7 +22,7 @@ import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.listeners.ProgressListener
import im.vector.matrix.android.api.session.crypto.crosssigning.CrossSigningService
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService
import im.vector.matrix.android.api.session.crypto.keyshare.RoomKeysRequestListener
import im.vector.matrix.android.api.session.crypto.keyshare.GossipingRequestListener
import im.vector.matrix.android.api.session.crypto.verification.VerificationService
import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.api.session.events.model.Event
@ -91,9 +91,9 @@ interface CryptoService {
fun cancelRoomKeyRequest(requestBody: RoomKeyRequestBody)
fun addRoomKeysRequestListener(listener: RoomKeysRequestListener)
fun addRoomKeysRequestListener(listener: GossipingRequestListener)
fun removeRoomKeysRequestListener(listener: RoomKeysRequestListener)
fun removeRoomKeysRequestListener(listener: GossipingRequestListener)
fun getDevicesList(callback: MatrixCallback<DevicesListResponse>)

View file

@ -17,12 +17,13 @@
package im.vector.matrix.android.api.session.crypto.keyshare
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequestCancellation
import im.vector.matrix.android.internal.crypto.IncomingRequestCancellation
import im.vector.matrix.android.internal.crypto.IncomingSecretShareRequest
/**
* Room keys events listener
*/
interface RoomKeysRequestListener {
interface GossipingRequestListener {
/**
* An room key request has been received.
*
@ -30,10 +31,16 @@ interface RoomKeysRequestListener {
*/
fun onRoomKeyRequest(request: IncomingRoomKeyRequest)
/**
* Returns the secret value to be shared
* @return true if is handled
*/
fun onSecretShareRequest(request: IncomingSecretShareRequest) : Boolean
/**
* A room key request cancellation has been received.
*
* @param request the cancellation request
*/
fun onRoomKeyRequestCancellation(request: IncomingRoomKeyRequestCancellation)
fun onRoomKeyRequestCancellation(request: IncomingRequestCancellation)
}

View file

@ -33,7 +33,7 @@ import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.listeners.ProgressListener
import im.vector.matrix.android.api.session.crypto.CryptoService
import im.vector.matrix.android.api.session.crypto.MXCryptoError
import im.vector.matrix.android.api.session.crypto.keyshare.RoomKeysRequestListener
import im.vector.matrix.android.api.session.crypto.keyshare.GossipingRequestListener
import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
@ -308,7 +308,7 @@ internal class DefaultCryptoService @Inject constructor(
deviceListManager.invalidateAllDeviceLists()
deviceListManager.refreshOutdatedDeviceLists()
} else {
incomingRoomKeyRequestManager.processReceivedRoomKeyRequests()
incomingRoomKeyRequestManager.processReceivedGossipingRequests()
}
}.fold(
{
@ -369,7 +369,7 @@ internal class DefaultCryptoService @Inject constructor(
// Make sure we process to-device messages before generating new one-time-keys #2782
deviceListManager.refreshOutdatedDeviceLists()
oneTimeKeysUploader.maybeUploadOneTimeKeys()
incomingRoomKeyRequestManager.processReceivedRoomKeyRequests()
incomingRoomKeyRequestManager.processReceivedGossipingRequests()
}
}
}
@ -694,8 +694,13 @@ internal class DefaultCryptoService @Inject constructor(
EventType.ROOM_KEY, EventType.FORWARDED_ROOM_KEY -> {
onRoomKeyEvent(event)
}
EventType.REQUEST_SECRET,
EventType.ROOM_KEY_REQUEST -> {
incomingRoomKeyRequestManager.onRoomKeyRequestEvent(event)
incomingRoomKeyRequestManager.onGossipingRequestEvent(event)
}
EventType.SEND_SECRET -> {
// incomingRoomKeyRequestManager.onGossipingRequestEvent(event)
}
else -> {
// ignore
@ -1031,20 +1036,20 @@ internal class DefaultCryptoService @Inject constructor(
}
/**
* Add a RoomKeysRequestListener listener.
* Add a GossipingRequestListener listener.
*
* @param listener listener
*/
override fun addRoomKeysRequestListener(listener: RoomKeysRequestListener) {
override fun addRoomKeysRequestListener(listener: GossipingRequestListener) {
incomingRoomKeyRequestManager.addRoomKeysRequestListener(listener)
}
/**
* Add a RoomKeysRequestListener listener.
* Add a GossipingRequestListener listener.
*
* @param listener listener
*/
override fun removeRoomKeysRequestListener(listener: RoomKeysRequestListener) {
override fun removeRoomKeysRequestListener(listener: GossipingRequestListener) {
incomingRoomKeyRequestManager.removeRoomKeysRequestListener(listener)
}

View file

@ -18,12 +18,12 @@ package im.vector.matrix.android.internal.crypto
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyShareCancellation
import im.vector.matrix.android.internal.crypto.model.rest.ShareRequestCancellation
/**
* IncomingRoomKeyRequestCancellation describes the incoming room key cancellation.
* IncomingRequestCancellation describes the incoming room key cancellation.
*/
data class IncomingRoomKeyRequestCancellation(
data class IncomingRequestCancellation(
/**
* The user id
*/
@ -38,18 +38,18 @@ data class IncomingRoomKeyRequestCancellation(
* The request id
*/
override val requestId: String? = null
) : IncomingRoomKeyRequestCommon {
) : IncomingShareRequestCommon {
companion object {
/**
* Factory
*
* @param event the event
*/
fun fromEvent(event: Event): IncomingRoomKeyRequestCancellation? {
fun fromEvent(event: Event): IncomingRequestCancellation? {
return event.getClearContent()
.toModel<RoomKeyShareCancellation>()
.toModel<ShareRequestCancellation>()
?.let {
IncomingRoomKeyRequestCancellation(
IncomingRequestCancellation(
userId = event.senderId,
deviceId = it.requestingDeviceId,
requestId = it.requestId

View file

@ -57,7 +57,7 @@ data class IncomingRoomKeyRequest(
*/
@Transient
var ignore: Runnable? = null
) : IncomingRoomKeyRequestCommon {
) : IncomingShareRequestCommon {
companion object {
/**
* Factory

View file

@ -17,9 +17,14 @@
package im.vector.matrix.android.internal.crypto
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.crypto.keyshare.RoomKeysRequestListener
import im.vector.matrix.android.api.session.crypto.crosssigning.CrossSigningService
import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.keyshare.GossipingRequestListener
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyShare
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.internal.crypto.model.rest.GossipingToDeviceObject
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.session.SessionScope
import timber.log.Timber
@ -29,18 +34,21 @@ import javax.inject.Inject
internal class IncomingRoomKeyRequestManager @Inject constructor(
private val credentials: Credentials,
private val cryptoStore: IMXCryptoStore,
private val crossSigningService: CrossSigningService,
private val secrSecretCryptoProvider: ShareSecretCryptoProvider,
private val roomDecryptorProvider: RoomDecryptorProvider) {
// list of IncomingRoomKeyRequests/IncomingRoomKeyRequestCancellations
// we received in the current sync.
private val receivedRoomKeyRequests = ArrayList<IncomingRoomKeyRequest>()
private val receivedRoomKeyRequestCancellations = ArrayList<IncomingRoomKeyRequestCancellation>()
private val receiveGossipingRequests = ArrayList<IncomingShareRequestCommon>()
private val receivedRequestCancellations = ArrayList<IncomingRequestCancellation>()
// the listeners
private val roomKeysRequestListeners: MutableSet<RoomKeysRequestListener> = HashSet()
private val gossipingRequestListeners: MutableSet<GossipingRequestListener> = HashSet()
init {
receivedRoomKeyRequests.addAll(cryptoStore.getPendingIncomingRoomKeyRequests())
receiveGossipingRequests.addAll(cryptoStore.getPendingIncomingSecretShareRequests())
receiveGossipingRequests.addAll(cryptoStore.getPendingIncomingRoomKeyRequests())
}
/**
@ -49,101 +57,53 @@ internal class IncomingRoomKeyRequestManager @Inject constructor(
*
* @param event the announcement event.
*/
fun onRoomKeyRequestEvent(event: Event) {
when (val roomKeyShareAction = event.getClearContent()?.get("action") as? String) {
RoomKeyShare.ACTION_SHARE_REQUEST -> IncomingRoomKeyRequest.fromEvent(event)?.let { receivedRoomKeyRequests.add(it) }
RoomKeyShare.ACTION_SHARE_CANCELLATION -> IncomingRoomKeyRequestCancellation.fromEvent(event)?.let { receivedRoomKeyRequestCancellations.add(it) }
else -> Timber.e("## onRoomKeyRequestEvent() : unsupported action $roomKeyShareAction")
fun onGossipingRequestEvent(event: Event) {
val roomKeyShare = event.getClearContent().toModel<GossipingToDeviceObject>()
when (roomKeyShare?.action) {
GossipingToDeviceObject.ACTION_SHARE_REQUEST -> {
if (event.getClearType() == EventType.REQUEST_SECRET) {
IncomingSecretShareRequest.fromEvent(event)?.let {
receiveGossipingRequests.add(it)
}
} else if (event.getClearType() == EventType.ROOM_KEY_REQUEST) {
IncomingRoomKeyRequest.fromEvent(event)?.let {
receiveGossipingRequests.add(it)
}
}
}
GossipingToDeviceObject.ACTION_SHARE_CANCELLATION -> IncomingRequestCancellation.fromEvent(event)?.let { receivedRequestCancellations.add(it) }
else -> Timber.e("## onGossipingRequestEvent() : unsupported action ${roomKeyShare?.action}")
}
}
/**
* Process any m.room_key_request events which were queued up during the
* Process any m.room_key_request or m.secret.request events which were queued up during the
* current sync.
* It must be called on CryptoThread
*/
fun processReceivedRoomKeyRequests() {
val roomKeyRequestsToProcess = receivedRoomKeyRequests.toList()
receivedRoomKeyRequests.clear()
fun processReceivedGossipingRequests() {
val roomKeyRequestsToProcess = receiveGossipingRequests.toList()
receiveGossipingRequests.clear()
for (request in roomKeyRequestsToProcess) {
val userId = request.userId
val deviceId = request.deviceId
val body = request.requestBody
val roomId = body!!.roomId
val alg = body.algorithm
Timber.v("m.room_key_request from $userId:$deviceId for $roomId / ${body.sessionId} id ${request.requestId}")
if (userId == null || credentials.userId != userId) {
// TODO: determine if we sent this device the keys already: in
Timber.w("## processReceivedRoomKeyRequests() : Ignoring room key request from other user for now")
return
}
// TODO: should we queue up requests we don't yet have keys for, in case they turn up later?
// if we don't have a decryptor for this room/alg, we don't have
// the keys for the requested events, and can drop the requests.
val decryptor = roomDecryptorProvider.getRoomDecryptor(roomId, alg)
if (null == decryptor) {
Timber.w("## processReceivedRoomKeyRequests() : room key request for unknown $alg in room $roomId")
continue
}
if (!decryptor.hasKeysForKeyRequest(request)) {
Timber.w("## processReceivedRoomKeyRequests() : room key request for unknown session ${body.sessionId!!}")
cryptoStore.deleteIncomingRoomKeyRequest(request)
continue
}
if (credentials.deviceId == deviceId && credentials.userId == userId) {
Timber.v("## processReceivedRoomKeyRequests() : oneself device - ignored")
cryptoStore.deleteIncomingRoomKeyRequest(request)
continue
}
request.share = Runnable {
decryptor.shareKeysWithDevice(request)
cryptoStore.deleteIncomingRoomKeyRequest(request)
}
request.ignore = Runnable {
cryptoStore.deleteIncomingRoomKeyRequest(request)
}
// if the device is verified already, share the keys
val device = cryptoStore.getUserDevice(userId, deviceId!!)
if (device != null) {
if (device.isVerified) {
Timber.v("## processReceivedRoomKeyRequests() : device is already verified: sharing keys")
cryptoStore.deleteIncomingRoomKeyRequest(request)
request.share?.run()
continue
}
if (device.isBlocked) {
Timber.v("## processReceivedRoomKeyRequests() : device is blocked -> ignored")
cryptoStore.deleteIncomingRoomKeyRequest(request)
continue
}
}
// If cross signing is available on account we automatically discard untrust devices request
if (cryptoStore.getMyCrossSigningInfo() != null) {
// At this point the device is unknown, we don't want to bother user with that
cryptoStore.deleteIncomingRoomKeyRequest(request)
continue
}
cryptoStore.storeIncomingRoomKeyRequest(request)
onRoomKeyRequest(request)
}
var receivedRoomKeyRequestCancellations: List<IncomingRoomKeyRequestCancellation>? = null
synchronized(this.receivedRoomKeyRequestCancellations) {
if (this.receivedRoomKeyRequestCancellations.isNotEmpty()) {
receivedRoomKeyRequestCancellations = this.receivedRoomKeyRequestCancellations.toList()
this.receivedRoomKeyRequestCancellations.clear()
if (request is IncomingRoomKeyRequest) {
processIncomingRoomKeyRequest(request)
} else if (request is IncomingSecretShareRequest) {
processIncomingSecretShareRequest(request)
}
}
if (null != receivedRoomKeyRequestCancellations) {
for (request in receivedRoomKeyRequestCancellations!!) {
Timber.v("## ## processReceivedRoomKeyRequests() : m.room_key_request cancellation for " + request.userId
var receivedRequestCancellations: List<IncomingRequestCancellation>? = null
synchronized(this.receivedRequestCancellations) {
if (this.receivedRequestCancellations.isNotEmpty()) {
receivedRequestCancellations = this.receivedRequestCancellations.toList()
this.receivedRequestCancellations.clear()
}
}
if (null != receivedRequestCancellations) {
for (request in receivedRequestCancellations!!) {
Timber.v("## ## processReceivedGossipingRequests() : m.room_key_request cancellation for " + request.userId
+ ":" + request.deviceId + " id " + request.requestId)
// we should probably only notify the app of cancellations we told it
@ -155,14 +115,122 @@ internal class IncomingRoomKeyRequestManager @Inject constructor(
}
}
private fun processIncomingRoomKeyRequest(request: IncomingRoomKeyRequest) {
val userId = request.userId
val deviceId = request.deviceId
val body = request.requestBody
val roomId = body!!.roomId
val alg = body.algorithm
Timber.v("m.room_key_request from $userId:$deviceId for $roomId / ${body.sessionId} id ${request.requestId}")
if (userId == null || credentials.userId != userId) {
// TODO: determine if we sent this device the keys already: in
Timber.w("## processReceivedGossipingRequests() : Ignoring room key request from other user for now")
cryptoStore.deleteIncomingRoomKeyRequest(request)
return
}
// TODO: should we queue up requests we don't yet have keys for, in case they turn up later?
// if we don't have a decryptor for this room/alg, we don't have
// the keys for the requested events, and can drop the requests.
val decryptor = roomDecryptorProvider.getRoomDecryptor(roomId, alg)
if (null == decryptor) {
Timber.w("## processReceivedGossipingRequests() : room key request for unknown $alg in room $roomId")
return
}
if (!decryptor.hasKeysForKeyRequest(request)) {
Timber.w("## processReceivedGossipingRequests() : room key request for unknown session ${body.sessionId!!}")
cryptoStore.deleteIncomingRoomKeyRequest(request)
return
}
if (credentials.deviceId == deviceId && credentials.userId == userId) {
Timber.v("## processReceivedGossipingRequests() : oneself device - ignored")
cryptoStore.deleteIncomingRoomKeyRequest(request)
return
}
request.share = Runnable {
decryptor.shareKeysWithDevice(request)
cryptoStore.deleteIncomingRoomKeyRequest(request)
}
request.ignore = Runnable {
cryptoStore.deleteIncomingRoomKeyRequest(request)
}
// if the device is verified already, share the keys
val device = cryptoStore.getUserDevice(userId, deviceId!!)
if (device != null) {
if (device.isVerified) {
Timber.v("## processReceivedGossipingRequests() : device is already verified: sharing keys")
cryptoStore.deleteIncomingRoomKeyRequest(request)
request.share?.run()
return
}
if (device.isBlocked) {
Timber.v("## processReceivedGossipingRequests() : device is blocked -> ignored")
cryptoStore.deleteIncomingRoomKeyRequest(request)
return
}
}
// If cross signing is available on account we automatically discard untrust devices request
if (cryptoStore.getMyCrossSigningInfo() != null) {
// At this point the device is unknown, we don't want to bother user with that
cryptoStore.deleteIncomingRoomKeyRequest(request)
return
}
cryptoStore.storeIncomingRoomKeyRequest(request)
// Legacy, pass to application layer to decide what to do
onRoomKeyRequest(request)
}
private fun processIncomingSecretShareRequest(request: IncomingSecretShareRequest) {
val secretName = request.secretName ?: return Unit.also {
cryptoStore.deleteIncomingSecretRequest(request)
Timber.v("## processIncomingSecretShareRequest() : Missing secret name")
}
val userId = request.userId
if (userId == null || credentials.userId != userId) {
Timber.e("## processIncomingSecretShareRequest() : Ignoring secret share request from other user")
cryptoStore.deleteIncomingRoomKeyRequest(request)
return
}
when (secretName) {
SELF_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.selfSigned
USER_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.user
else -> null
}?.let { secretValue ->
// TODO check if locally trusted and not outdated
if (cryptoStore.getUserDevice(userId, request.deviceId ?: "")?.trustLevel?.isLocallyVerified() == true) {
secrSecretCryptoProvider.shareSecretWithDevice(request, secretValue)
cryptoStore.deleteIncomingRoomKeyRequest(request)
}
return
}
request.ignore = Runnable {
cryptoStore.deleteIncomingRoomKeyRequest(request)
}
request.share = { secretValue ->
secrSecretCryptoProvider.shareSecretWithDevice(request, secretValue)
cryptoStore.deleteIncomingRoomKeyRequest(request)
}
onShareRequest(request)
}
/**
* Dispatch onRoomKeyRequest
*
* @param request the request
*/
private fun onRoomKeyRequest(request: IncomingRoomKeyRequest) {
synchronized(roomKeysRequestListeners) {
for (listener in roomKeysRequestListeners) {
synchronized(gossipingRequestListeners) {
for (listener in gossipingRequestListeners) {
try {
listener.onRoomKeyRequest(request)
} catch (e: Exception) {
@ -172,14 +240,33 @@ internal class IncomingRoomKeyRequestManager @Inject constructor(
}
}
/**
* Ask for a value to the listeners, and take the first one
*/
private fun onShareRequest(request: IncomingSecretShareRequest) {
synchronized(gossipingRequestListeners) {
for (listener in gossipingRequestListeners) {
try {
if (listener.onSecretShareRequest(request)) {
return
}
} catch (e: Exception) {
Timber.e(e, "## onRoomKeyRequest() failed")
}
}
}
// Not handled, ignore
request.ignore?.run()
}
/**
* A room key request cancellation has been received.
*
* @param request the cancellation request
*/
private fun onRoomKeyRequestCancellation(request: IncomingRoomKeyRequestCancellation) {
synchronized(roomKeysRequestListeners) {
for (listener in roomKeysRequestListeners) {
private fun onRoomKeyRequestCancellation(request: IncomingRequestCancellation) {
synchronized(gossipingRequestListeners) {
for (listener in gossipingRequestListeners) {
try {
listener.onRoomKeyRequestCancellation(request)
} catch (e: Exception) {
@ -189,15 +276,15 @@ internal class IncomingRoomKeyRequestManager @Inject constructor(
}
}
fun addRoomKeysRequestListener(listener: RoomKeysRequestListener) {
synchronized(roomKeysRequestListeners) {
roomKeysRequestListeners.add(listener)
fun addRoomKeysRequestListener(listener: GossipingRequestListener) {
synchronized(gossipingRequestListeners) {
gossipingRequestListeners.add(listener)
}
}
fun removeRoomKeysRequestListener(listener: RoomKeysRequestListener) {
synchronized(roomKeysRequestListeners) {
roomKeysRequestListeners.remove(listener)
fun removeRoomKeysRequestListener(listener: GossipingRequestListener) {
synchronized(gossipingRequestListeners) {
gossipingRequestListeners.remove(listener)
}
}
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.internal.crypto.model.rest.SecretShareRequest
/**
* IncomingRoomKeyRequest class defines the incoming room keys request.
*/
data class IncomingSecretShareRequest(
/**
* The user id
*/
override val userId: String? = null,
/**
* The device id
*/
override val deviceId: String? = null,
/**
* The request id
*/
override val requestId: String? = null,
/**
* The request body
*/
val secretName: String? = null,
/**
* The runnable to call to accept to share the keys
*/
@Transient
var share: ((String) -> Unit)? = null,
/**
* The runnable to call to ignore the key share request.
*/
@Transient
var ignore: Runnable? = null
) : IncomingShareRequestCommon {
companion object {
/**
* Factory
*
* @param event the event
*/
fun fromEvent(event: Event): IncomingSecretShareRequest? {
return event.getClearContent()
.toModel<SecretShareRequest>()
?.let {
IncomingSecretShareRequest(
userId = event.senderId,
deviceId = it.requestingDeviceId,
requestId = it.requestId,
secretName = it.secretName
)
}
}
}
}

View file

@ -16,7 +16,7 @@
package im.vector.matrix.android.internal.crypto
interface IncomingRoomKeyRequestCommon {
interface IncomingShareRequestCommon {
/**
* The user id
*/

View file

@ -25,14 +25,14 @@ import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
class OutgoingRoomKeyRequest(
// RequestBody
var requestBody: RoomKeyRequestBody?, // list of recipients for the request
var recipients: List<Map<String, String>>, // Unique id for this request. Used for both
override var recipients: List<Map<String, String>>, // Unique id for this request. Used for both
// an id within the request for later pairing with a cancellation, and for
// the transaction id when sending the to_device messages to our local
var requestId: String, // current state of this request
var state: RequestState) {
override var requestId: String, // current state of this request
override var state: ShareRequestState) : OutgoingShareRequest {
// transaction id for the cancellation, if any
var cancellationTxnId: String? = null
override var cancellationTxnId: String? = null
/**
* Used only for log.
@ -53,66 +53,4 @@ class OutgoingRoomKeyRequest(
get() = if (null != requestBody) {
requestBody!!.sessionId
} else null
/**
* possible states for a room key request
*
*
* The state machine looks like:
* <pre>
*
* |
* V
* UNSENT -----------------------------+
* | |
* | (send successful) | (cancellation requested)
* V |
* SENT |
* |-------------------------------- | --------------+
* | | |
* | | | (cancellation requested with intent
* | | | to resend a new request)
* | (cancellation requested) | |
* V | V
* CANCELLATION_PENDING | CANCELLATION_PENDING_AND_WILL_RESEND
* | | |
* | (cancellation sent) | | (cancellation sent. Create new request
* | | | in the UNSENT state)
* V | |
* (deleted) <---------------------------+----------------+
* </pre>
*/
enum class RequestState {
/**
* request not yet sent
*/
UNSENT,
/**
* request sent, awaiting reply
*/
SENT,
/**
* reply received, cancellation not yet sent
*/
CANCELLATION_PENDING,
/**
* Cancellation not yet sent, once sent, a new request will be done
*/
CANCELLATION_PENDING_AND_WILL_RESEND,
/**
* sending failed
*/
FAILED;
companion object {
fun from(state: Int) = when (state) {
0 -> UNSENT
1 -> SENT
2 -> CANCELLATION_PENDING
3 -> CANCELLATION_PENDING_AND_WILL_RESEND
else /*4*/ -> FAILED
}
}
}
}

View file

@ -21,7 +21,7 @@ import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyShareCancellation
import im.vector.matrix.android.internal.crypto.model.rest.ShareRequestCancellation
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyShareRequest
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
@ -89,9 +89,9 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
*/
fun sendRoomKeyRequest(requestBody: RoomKeyRequestBody?, recipients: List<Map<String, String>>) {
val req = cryptoStore.getOrAddOutgoingRoomKeyRequest(
OutgoingRoomKeyRequest(requestBody, recipients, makeTxnId(), OutgoingRoomKeyRequest.RequestState.UNSENT))
OutgoingRoomKeyRequest(requestBody, recipients, makeTxnId(), ShareRequestState.UNSENT))
if (req?.state == OutgoingRoomKeyRequest.RequestState.UNSENT) {
if (req?.state == ShareRequestState.UNSENT) {
startTimer()
}
}
@ -132,20 +132,20 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
Timber.v("cancelRoomKeyRequest: requestId: " + req.requestId + " state: " + req.state + " andResend: " + andResend)
when (req.state) {
OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING,
OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> {
ShareRequestState.CANCELLATION_PENDING,
ShareRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> {
// nothing to do here
}
OutgoingRoomKeyRequest.RequestState.UNSENT,
OutgoingRoomKeyRequest.RequestState.FAILED -> {
ShareRequestState.UNSENT,
ShareRequestState.FAILED -> {
Timber.v("## cancelRoomKeyRequest() : deleting unnecessary room key request for $requestBody")
cryptoStore.deleteOutgoingRoomKeyRequest(req.requestId)
}
OutgoingRoomKeyRequest.RequestState.SENT -> {
ShareRequestState.SENT -> {
if (andResend) {
req.state = OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING_AND_WILL_RESEND
req.state = ShareRequestState.CANCELLATION_PENDING_AND_WILL_RESEND
} else {
req.state = OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING
req.state = ShareRequestState.CANCELLATION_PENDING
}
req.cancellationTxnId = makeTxnId()
cryptoStore.updateOutgoingRoomKeyRequest(req)
@ -187,9 +187,9 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
Timber.v("## sendOutgoingRoomKeyRequests() : Looking for queued outgoing room key requests")
val outgoingRoomKeyRequest = cryptoStore.getOutgoingRoomKeyRequestByState(
setOf(OutgoingRoomKeyRequest.RequestState.UNSENT,
OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING,
OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING_AND_WILL_RESEND))
setOf(ShareRequestState.UNSENT,
ShareRequestState.CANCELLATION_PENDING,
ShareRequestState.CANCELLATION_PENDING_AND_WILL_RESEND))
if (null == outgoingRoomKeyRequest) {
Timber.v("## sendOutgoingRoomKeyRequests() : No more outgoing room key requests")
@ -197,7 +197,7 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
return
}
if (OutgoingRoomKeyRequest.RequestState.UNSENT === outgoingRoomKeyRequest.state) {
if (ShareRequestState.UNSENT === outgoingRoomKeyRequest.state) {
sendOutgoingRoomKeyRequest(outgoingRoomKeyRequest)
} else {
sendOutgoingRoomKeyRequestCancellation(outgoingRoomKeyRequest)
@ -220,8 +220,8 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
)
sendMessageToDevices(requestMessage, request.recipients, request.requestId, object : MatrixCallback<Unit> {
private fun onDone(state: OutgoingRoomKeyRequest.RequestState) {
if (request.state !== OutgoingRoomKeyRequest.RequestState.UNSENT) {
private fun onDone(state: ShareRequestState) {
if (request.state !== ShareRequestState.UNSENT) {
Timber.v("## sendOutgoingRoomKeyRequest() : Cannot update room key request from UNSENT as it was already updated to ${request.state}")
} else {
request.state = state
@ -234,12 +234,12 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
override fun onSuccess(data: Unit) {
Timber.v("## sendOutgoingRoomKeyRequest succeed")
onDone(OutgoingRoomKeyRequest.RequestState.SENT)
onDone(ShareRequestState.SENT)
}
override fun onFailure(failure: Throwable) {
Timber.e("## sendOutgoingRoomKeyRequest failed")
onDone(OutgoingRoomKeyRequest.RequestState.FAILED)
onDone(ShareRequestState.FAILED)
}
})
}
@ -254,7 +254,7 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
+ " to " + request.recipients
+ " cancellation id " + request.cancellationTxnId)
val roomKeyShareCancellation = RoomKeyShareCancellation(
val roomKeyShareCancellation = ShareRequestCancellation(
requestingDeviceId = cryptoStore.getDeviceId(),
requestId = request.cancellationTxnId
)
@ -268,7 +268,7 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
override fun onSuccess(data: Unit) {
Timber.v("## sendOutgoingRoomKeyRequestCancellation() : done")
val resend = request.state === OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING_AND_WILL_RESEND
val resend = request.state === ShareRequestState.CANCELLATION_PENDING_AND_WILL_RESEND
onDone()

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto
/**
* Represents an outgoing room key request
*/
class OutgoingSecretRequest(
// Secret Name
var secretName: String?,
// list of recipients for the request
override var recipients: List<Map<String, String>>,
// Unique id for this request. Used for both
// an id within the request for later pairing with a cancellation, and for
// the transaction id when sending the to_device messages to our local
override var requestId: String,
// current state of this request
override var state: ShareRequestState) : OutgoingShareRequest {
// transaction id for the cancellation, if any
override var cancellationTxnId: String? = null
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto
interface OutgoingShareRequest {
var recipients: List<Map<String, String>>
var requestId: String
var state: ShareRequestState
// transaction id for the cancellation, if any
var cancellationTxnId: String?
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto
/**
* possible states for a room key request
*
*
* The state machine looks like:
* <pre>
*
* |
* V
* UNSENT -----------------------------+
* | |
* | (send successful) | (cancellation requested)
* V |
* SENT |
* |-------------------------------- | --------------+
* | | |
* | | | (cancellation requested with intent
* | | | to resend a new request)
* | (cancellation requested) | |
* V | V
* CANCELLATION_PENDING | CANCELLATION_PENDING_AND_WILL_RESEND
* | | |
* | (cancellation sent) | | (cancellation sent. Create new request
* | | | in the UNSENT state)
* V | |
* (deleted) <---------------------------+----------------+
* </pre>
*/
enum class ShareRequestState {
/**
* request not yet sent
*/
UNSENT,
/**
* request sent, awaiting reply
*/
SENT,
/**
* reply received, cancellation not yet sent
*/
CANCELLATION_PENDING,
/**
* Cancellation not yet sent, once sent, a new request will be done
*/
CANCELLATION_PENDING_AND_WILL_RESEND,
/**
* sending failed
*/
FAILED;
companion object {
fun from(state: Int) = when (state) {
0 -> UNSENT
1 -> SENT
2 -> CANCELLATION_PENDING
3 -> CANCELLATION_PENDING_AND_WILL_RESEND
else /*4*/ -> FAILED
}
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.event.SecretSendEventContent
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
internal class ShareSecretCryptoProvider @Inject constructor(
val messageEncrypter: MessageEncrypter,
val sendToDeviceTask: SendToDeviceTask,
val deviceListManager: DeviceListManager,
val cryptoCoroutineScope: CoroutineScope,
val cryptoStore: IMXCryptoStore,
val coroutineDispatchers: MatrixCoroutineDispatchers
) {
fun shareSecretWithDevice(request: IncomingSecretShareRequest, secretValue: String) {
val userId = request.userId ?: return
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
runCatching { deviceListManager.downloadKeys(listOf(userId), false) }
.mapCatching {
val deviceId = request.deviceId
val deviceInfo = cryptoStore.getUserDevice(userId, deviceId ?: "") ?: throw RuntimeException()
Timber.i("## shareSecretWithDevice() : sharing secret ${request.secretName} with device $userId:$deviceId")
val payloadJson = mutableMapOf<String, Any>("type" to EventType.SEND_SECRET)
payloadJson["content"] = SecretSendEventContent(
requestId = request.requestId ?: "",
secretValue = secretValue
)
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
val sendToDeviceMap = MXUsersDevicesMap<Any>()
sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
Timber.i("## shareSecretWithDevice() : sending to $userId:$deviceId")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
sendToDeviceTask.execute(sendToDeviceParams)
}
}
}
}

View file

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.crypto.algorithms
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.IncomingSecretShareRequest
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.crypto.keysbackup.DefaultKeysBackupService
@ -65,4 +66,6 @@ internal interface IMXDecrypting {
* @param request keyRequest
*/
fun shareKeysWithDevice(request: IncomingRoomKeyRequest) {}
fun shareSecretWithDevice(request: IncomingSecretShareRequest, secretValue : String) {}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.model.event
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
* Class representing an encrypted event content
*/
@JsonClass(generateAdapter = true)
data class SecretSendEventContent(
@Json(name = "request_id") val requestId: String,
@Json(name = "secret") val secretValue: String
)

View file

@ -19,7 +19,7 @@ package im.vector.matrix.android.internal.crypto.model.rest
* Interface representing an room key action request
* Note: this class cannot be abstract because of [org.matrix.androidsdk.core.JsonUtils.toRoomKeyShare]
*/
internal interface RoomKeyShare : SendToDeviceObject {
internal interface GossipingToDeviceObject : SendToDeviceObject {
val action: String?

View file

@ -25,7 +25,7 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class RoomKeyShareRequest(
@Json(name = "action")
override val action: String? = RoomKeyShare.ACTION_SHARE_REQUEST,
override val action: String? = GossipingToDeviceObject.ACTION_SHARE_REQUEST,
@Json(name = "requesting_device_id")
override val requestingDeviceId: String? = null,
@ -35,4 +35,4 @@ internal data class RoomKeyShareRequest(
@Json(name = "body")
val body: RoomKeyRequestBody? = null
) : RoomKeyShare
) : GossipingToDeviceObject

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.model.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
* Class representing a room key request content
*/
@JsonClass(generateAdapter = true)
internal data class SecretShareRequest(
@Json(name = "action")
override val action: String? = GossipingToDeviceObject.ACTION_SHARE_REQUEST,
@Json(name = "requesting_device_id")
override val requestingDeviceId: String? = null,
@Json(name = "request_id")
override val requestId: String? = null,
@Json(name = "name")
val secretName: String? = null
) : GossipingToDeviceObject

View file

@ -17,18 +17,19 @@ package im.vector.matrix.android.internal.crypto.model.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.crypto.model.rest.GossipingToDeviceObject.Companion.ACTION_SHARE_CANCELLATION
/**
* Class representing a room key request cancellation content
*/
@JsonClass(generateAdapter = true)
internal data class RoomKeyShareCancellation(
internal data class ShareRequestCancellation(
@Json(name = "action")
override val action: String? = RoomKeyShare.ACTION_SHARE_CANCELLATION,
override val action: String? = ACTION_SHARE_CANCELLATION,
@Json(name = "requesting_device_id")
override val requestingDeviceId: String? = null,
@Json(name = "request_id")
override val requestId: String? = null
) : RoomKeyShare
) : GossipingToDeviceObject

View file

@ -20,10 +20,12 @@ package im.vector.matrix.android.internal.crypto.store
import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.crypto.IncomingShareRequestCommon
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequestCommon
import im.vector.matrix.android.internal.crypto.IncomingSecretShareRequest
import im.vector.matrix.android.internal.crypto.NewSessionListener
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.ShareRequestState
import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper
@ -116,6 +118,7 @@ internal interface IMXCryptoStore {
* @return the pending IncomingRoomKeyRequest requests
*/
fun getPendingIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest>
fun getPendingIncomingSecretShareRequests(): List<IncomingSecretShareRequest>
/**
* Indicate if the store contains data for the passed account.
@ -355,7 +358,7 @@ internal interface IMXCryptoStore {
* @param states the states
* @return an OutgoingRoomKeyRequest or null
*/
fun getOutgoingRoomKeyRequestByState(states: Set<OutgoingRoomKeyRequest.RequestState>): OutgoingRoomKeyRequest?
fun getOutgoingRoomKeyRequestByState(states: Set<ShareRequestState>): OutgoingRoomKeyRequest?
/**
* Update an existing outgoing request.
@ -383,7 +386,9 @@ internal interface IMXCryptoStore {
*
* @param incomingRoomKeyRequest the incoming key request
*/
fun deleteIncomingRoomKeyRequest(incomingRoomKeyRequest: IncomingRoomKeyRequestCommon)
fun deleteIncomingRoomKeyRequest(incomingRoomKeyRequest: IncomingShareRequestCommon)
fun deleteIncomingSecretRequest(request: IncomingSecretShareRequest)
/**
* Search an IncomingRoomKeyRequest

View file

@ -24,9 +24,11 @@ import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningIn
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequestCommon
import im.vector.matrix.android.internal.crypto.IncomingSecretShareRequest
import im.vector.matrix.android.internal.crypto.IncomingShareRequestCommon
import im.vector.matrix.android.internal.crypto.NewSessionListener
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.ShareRequestState
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel
import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
@ -46,6 +48,8 @@ import im.vector.matrix.android.internal.crypto.store.db.model.DeviceInfoEntity
import im.vector.matrix.android.internal.crypto.store.db.model.DeviceInfoEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.IncomingRoomKeyRequestEntity
import im.vector.matrix.android.internal.crypto.store.db.model.IncomingRoomKeyRequestEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.IncomingSecretRequestEntity
import im.vector.matrix.android.internal.crypto.store.db.model.IncomingSecretRequestEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.KeyInfoEntity
import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntity
import im.vector.matrix.android.internal.crypto.store.db.model.OlmInboundGroupSessionEntity
@ -832,7 +836,7 @@ internal class RealmCryptoStore @Inject constructor(
return request
}
override fun getOutgoingRoomKeyRequestByState(states: Set<OutgoingRoomKeyRequest.RequestState>): OutgoingRoomKeyRequest? {
override fun getOutgoingRoomKeyRequestByState(states: Set<ShareRequestState>): OutgoingRoomKeyRequest? {
val statesIndex = states.map { it.ordinal }.toTypedArray()
return doRealmQueryAndCopy(realmConfiguration) {
it.where<OutgoingRoomKeyRequestEntity>()
@ -889,7 +893,7 @@ internal class RealmCryptoStore @Inject constructor(
}
}
override fun deleteIncomingRoomKeyRequest(incomingRoomKeyRequest: IncomingRoomKeyRequestCommon) {
override fun deleteIncomingRoomKeyRequest(incomingRoomKeyRequest: IncomingShareRequestCommon) {
doRealmTransaction(realmConfiguration) {
it.where<IncomingRoomKeyRequestEntity>()
.equalTo(IncomingRoomKeyRequestEntityFields.USER_ID, incomingRoomKeyRequest.userId)
@ -900,6 +904,18 @@ internal class RealmCryptoStore @Inject constructor(
}
}
override fun deleteIncomingSecretRequest(request: IncomingSecretShareRequest) {
doRealmTransaction(realmConfiguration) {
it.where<IncomingSecretRequestEntity>()
.equalTo(IncomingSecretRequestEntityFields.USER_ID, request.userId)
.equalTo(IncomingSecretRequestEntityFields.DEVICE_ID, request.deviceId)
.equalTo(IncomingSecretRequestEntityFields.REQUEST_ID, request.requestId)
.equalTo(IncomingSecretRequestEntityFields.SECRET_NAME, request.secretName)
.findAll()
.deleteAllFromRealm()
}
}
override fun getIncomingRoomKeyRequest(userId: String, deviceId: String, requestId: String): IncomingRoomKeyRequest? {
return doRealmQueryAndCopy(realmConfiguration) {
it.where<IncomingRoomKeyRequestEntity>()
@ -922,6 +938,15 @@ internal class RealmCryptoStore @Inject constructor(
.toMutableList()
}
override fun getPendingIncomingSecretShareRequests(): List<IncomingSecretShareRequest> {
return doRealmQueryAndCopyList(realmConfiguration) {
it.where<IncomingSecretRequestEntity>()
.findAll()
}.map {
it.toIncomingSecretShareRequest()
}
}
/* ==========================================================================================
* Cross Signing
* ========================================================================================== */

View file

@ -23,7 +23,9 @@ import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.store.db.model.CrossSigningInfoEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.CryptoMetadataEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.DeviceInfoEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.IncomingSecretRequestEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.KeyInfoEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.OutgoingSecretRequestEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.TrustLevelEntityFields
import im.vector.matrix.android.internal.crypto.store.db.model.UserEntityFields
import im.vector.matrix.android.internal.di.SerializeNulls
@ -34,102 +36,125 @@ import timber.log.Timber
internal object RealmCryptoStoreMigration : RealmMigration {
// Version 1L added Cross Signing info persistence
const val CRYPTO_STORE_SCHEMA_VERSION = 1L
const val CRYPTO_STORE_SCHEMA_VERSION = 2L
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
Timber.v("Migrating Realm Crypto from $oldVersion to $newVersion")
if (oldVersion <= 0) {
Timber.d("Step 0 -> 1")
Timber.d("Create KeyInfoEntity")
if (oldVersion <= 0) migrateTo1(realm)
if (oldVersion <= 1) migrateTo2(realm)
}
val trustLevelentityEntitySchema = realm.schema.create("TrustLevelEntity")
.addField(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, Boolean::class.java)
.setNullable(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, true)
.addField(TrustLevelEntityFields.LOCALLY_VERIFIED, Boolean::class.java)
.setNullable(TrustLevelEntityFields.LOCALLY_VERIFIED, true)
private fun migrateTo1(realm: DynamicRealm) {
Timber.d("Step 0 -> 1")
Timber.d("Create KeyInfoEntity")
val keyInfoEntitySchema = realm.schema.create("KeyInfoEntity")
.addField(KeyInfoEntityFields.PUBLIC_KEY_BASE64, String::class.java)
.addField(KeyInfoEntityFields.SIGNATURES, String::class.java)
.addRealmListField(KeyInfoEntityFields.USAGES.`$`, String::class.java)
.addRealmObjectField(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelentityEntitySchema)
val trustLevelentityEntitySchema = realm.schema.create("TrustLevelEntity")
.addField(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, Boolean::class.java)
.setNullable(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, true)
.addField(TrustLevelEntityFields.LOCALLY_VERIFIED, Boolean::class.java)
.setNullable(TrustLevelEntityFields.LOCALLY_VERIFIED, true)
Timber.d("Create CrossSigningInfoEntity")
val keyInfoEntitySchema = realm.schema.create("KeyInfoEntity")
.addField(KeyInfoEntityFields.PUBLIC_KEY_BASE64, String::class.java)
.addField(KeyInfoEntityFields.SIGNATURES, String::class.java)
.addRealmListField(KeyInfoEntityFields.USAGES.`$`, String::class.java)
.addRealmObjectField(KeyInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelentityEntitySchema)
val crossSigningInfoSchema = realm.schema.create("CrossSigningInfoEntity")
.addField(CrossSigningInfoEntityFields.USER_ID, String::class.java)
.addPrimaryKey(CrossSigningInfoEntityFields.USER_ID)
.addRealmListField(CrossSigningInfoEntityFields.CROSS_SIGNING_KEYS.`$`, keyInfoEntitySchema)
Timber.d("Create CrossSigningInfoEntity")
Timber.d("Updating UserEntity table")
realm.schema.get("UserEntity")
?.addRealmObjectField(UserEntityFields.CROSS_SIGNING_INFO_ENTITY.`$`, crossSigningInfoSchema)
val crossSigningInfoSchema = realm.schema.create("CrossSigningInfoEntity")
.addField(CrossSigningInfoEntityFields.USER_ID, String::class.java)
.addPrimaryKey(CrossSigningInfoEntityFields.USER_ID)
.addRealmListField(CrossSigningInfoEntityFields.CROSS_SIGNING_KEYS.`$`, keyInfoEntitySchema)
Timber.d("Updating CryptoMetadataEntity table")
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.X_SIGN_MASTER_PRIVATE_KEY, String::class.java)
?.addField(CryptoMetadataEntityFields.X_SIGN_USER_PRIVATE_KEY, String::class.java)
?.addField(CryptoMetadataEntityFields.X_SIGN_SELF_SIGNED_PRIVATE_KEY, String::class.java)
Timber.d("Updating UserEntity table")
realm.schema.get("UserEntity")
?.addRealmObjectField(UserEntityFields.CROSS_SIGNING_INFO_ENTITY.`$`, crossSigningInfoSchema)
val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build()
val listMigrationAdapter = moshi.adapter<List<String>>(Types.newParameterizedType(
List::class.java,
String::class.java,
Any::class.java
))
val mapMigrationAdapter = moshi.adapter<JsonDict>(Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
))
Timber.d("Updating CryptoMetadataEntity table")
realm.schema.get("CryptoMetadataEntity")
?.addField(CryptoMetadataEntityFields.X_SIGN_MASTER_PRIVATE_KEY, String::class.java)
?.addField(CryptoMetadataEntityFields.X_SIGN_USER_PRIVATE_KEY, String::class.java)
?.addField(CryptoMetadataEntityFields.X_SIGN_SELF_SIGNED_PRIVATE_KEY, String::class.java)
realm.schema.get("DeviceInfoEntity")
?.addField(DeviceInfoEntityFields.USER_ID, String::class.java)
?.addField(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.KEYS_MAP_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.IS_BLOCKED, Boolean::class.java)
?.setNullable(DeviceInfoEntityFields.IS_BLOCKED, true)
?.addRealmObjectField(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelentityEntitySchema)
?.transform { obj ->
val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build()
val listMigrationAdapter = moshi.adapter<List<String>>(Types.newParameterizedType(
List::class.java,
String::class.java,
Any::class.java
))
val mapMigrationAdapter = moshi.adapter<JsonDict>(Types.newParameterizedType(
Map::class.java,
String::class.java,
Any::class.java
))
val oldSerializedData = obj.getString("deviceInfoData")
deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { oldDevice ->
realm.schema.get("DeviceInfoEntity")
?.addField(DeviceInfoEntityFields.USER_ID, String::class.java)
?.addField(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.KEYS_MAP_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, String::class.java)
?.addField(DeviceInfoEntityFields.IS_BLOCKED, Boolean::class.java)
?.setNullable(DeviceInfoEntityFields.IS_BLOCKED, true)
?.addRealmObjectField(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevelentityEntitySchema)
?.transform { obj ->
val trustLevel = realm.createObject("TrustLevelEntity")
when (oldDevice.verified) {
MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> {
obj.setNull(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`)
}
MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> {
trustLevel.setNull(TrustLevelEntityFields.LOCALLY_VERIFIED)
trustLevel.setNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED)
obj.setBoolean(DeviceInfoEntityFields.IS_BLOCKED, oldDevice.isBlocked)
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
}
MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED -> {
trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, false)
trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false)
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
}
MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> {
trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, true)
trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false)
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
}
val oldSerializedData = obj.getString("deviceInfoData")
deserializeFromRealm<MXDeviceInfo>(oldSerializedData)?.let { oldDevice ->
val trustLevel = realm.createObject("TrustLevelEntity")
when (oldDevice.verified) {
MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> {
obj.setNull(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`)
}
MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> {
trustLevel.setNull(TrustLevelEntityFields.LOCALLY_VERIFIED)
trustLevel.setNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED)
obj.setBoolean(DeviceInfoEntityFields.IS_BLOCKED, oldDevice.isBlocked)
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
}
MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED -> {
trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, false)
trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false)
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
}
MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> {
trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, true)
trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false)
obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
}
obj.setString(DeviceInfoEntityFields.USER_ID, oldDevice.userId)
obj.setString(DeviceInfoEntityFields.IDENTITY_KEY, oldDevice.identityKey())
obj.setString(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, listMigrationAdapter.toJson(oldDevice.algorithms))
obj.setString(DeviceInfoEntityFields.KEYS_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.keys))
obj.setString(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.signatures))
obj.setString(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.unsigned))
}
obj.setString(DeviceInfoEntityFields.USER_ID, oldDevice.userId)
obj.setString(DeviceInfoEntityFields.IDENTITY_KEY, oldDevice.identityKey())
obj.setString(DeviceInfoEntityFields.ALGORITHM_LIST_JSON, listMigrationAdapter.toJson(oldDevice.algorithms))
obj.setString(DeviceInfoEntityFields.KEYS_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.keys))
obj.setString(DeviceInfoEntityFields.SIGNATURE_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.signatures))
obj.setString(DeviceInfoEntityFields.UNSIGNED_MAP_JSON, mapMigrationAdapter.toJson(oldDevice.unsigned))
}
?.removeField("deviceInfoData")
}
}
?.removeField("deviceInfoData")
}
private fun migrateTo2(realm: DynamicRealm) {
Timber.d("Step 1 -> 2")
realm.schema.create("IncomingSecretRequestEntity")
.addField(IncomingSecretRequestEntityFields.DEVICE_ID, String::class.java)
.addField(IncomingSecretRequestEntityFields.SECRET_NAME, String::class.java)
.addField(IncomingSecretRequestEntityFields.REQUEST_ID, String::class.java)
.addField(IncomingSecretRequestEntityFields.USER_ID, String::class.java)
realm.schema.create("OutgoingSecretRequestEntity")
.addField(OutgoingSecretRequestEntityFields.REQUEST_ID, String::class.java)
.addPrimaryKey(OutgoingSecretRequestEntityFields.REQUEST_ID)
.addField(OutgoingSecretRequestEntityFields.SECRET_NAME, String::class.java)
.addField(OutgoingSecretRequestEntityFields.CANCELLATION_TXN_ID, String::class.java)
.addField(OutgoingSecretRequestEntityFields.RECIPIENTS_DATA, String::class.java)
.addField(OutgoingSecretRequestEntityFields.STATE, Int::class.java)
}
}

View file

@ -21,11 +21,13 @@ import im.vector.matrix.android.internal.crypto.store.db.model.CryptoMetadataEnt
import im.vector.matrix.android.internal.crypto.store.db.model.CryptoRoomEntity
import im.vector.matrix.android.internal.crypto.store.db.model.DeviceInfoEntity
import im.vector.matrix.android.internal.crypto.store.db.model.IncomingRoomKeyRequestEntity
import im.vector.matrix.android.internal.crypto.store.db.model.IncomingSecretRequestEntity
import im.vector.matrix.android.internal.crypto.store.db.model.KeyInfoEntity
import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntity
import im.vector.matrix.android.internal.crypto.store.db.model.OlmInboundGroupSessionEntity
import im.vector.matrix.android.internal.crypto.store.db.model.OlmSessionEntity
import im.vector.matrix.android.internal.crypto.store.db.model.OutgoingRoomKeyRequestEntity
import im.vector.matrix.android.internal.crypto.store.db.model.OutgoingSecretRequestEntity
import im.vector.matrix.android.internal.crypto.store.db.model.TrustLevelEntity
import im.vector.matrix.android.internal.crypto.store.db.model.UserEntity
import io.realm.annotations.RealmModule
@ -46,6 +48,8 @@ import io.realm.annotations.RealmModule
UserEntity::class,
KeyInfoEntity::class,
CrossSigningInfoEntity::class,
TrustLevelEntity::class
TrustLevelEntity::class,
IncomingSecretRequestEntity::class,
OutgoingSecretRequestEntity::class
])
internal class RealmCryptoStoreModule

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.store.db.model
import im.vector.matrix.android.internal.crypto.IncomingSecretShareRequest
import io.realm.RealmObject
internal open class IncomingSecretRequestEntity(
var requestId: String? = null,
var userId: String? = null,
var deviceId: String? = null,
var secretName: String? = null
) : RealmObject() {
fun toIncomingSecretShareRequest(): IncomingSecretShareRequest {
return IncomingSecretShareRequest(
requestId = requestId,
userId = userId,
deviceId = deviceId,
secretName = secretName
)
}
}

View file

@ -17,6 +17,7 @@
package im.vector.matrix.android.internal.crypto.store.db.model
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.ShareRequestState
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
import im.vector.matrix.android.internal.crypto.store.db.deserializeFromRealm
import im.vector.matrix.android.internal.crypto.store.db.serializeForRealm
@ -51,7 +52,7 @@ internal open class OutgoingRoomKeyRequestEntity(
),
getRecipients()!!,
requestId!!,
OutgoingRoomKeyRequest.RequestState.from(state)
ShareRequestState.from(state)
).apply {
this.cancellationTxnId = cancellationTxnId
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.store.db.model
import im.vector.matrix.android.internal.crypto.OutgoingSecretRequest
import im.vector.matrix.android.internal.crypto.ShareRequestState
import im.vector.matrix.android.internal.crypto.store.db.deserializeFromRealm
import im.vector.matrix.android.internal.crypto.store.db.serializeForRealm
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
internal open class OutgoingSecretRequestEntity(
@PrimaryKey var requestId: String? = null,
var cancellationTxnId: String? = null,
// Serialized Json
var recipientsData: String? = null,
// RoomKeyRequestBody fields
var secretName: String? = null,
// State
var state: Int = 0
) : RealmObject() {
/**
* Convert to OutgoingRoomKeyRequest
*/
fun toOutgoingSecretRequest(): OutgoingSecretRequest {
val cancellationTxnId = this.cancellationTxnId
return OutgoingSecretRequest(
secretName,
getRecipients() ?: emptyList(),
requestId!!,
ShareRequestState.from(state)
).apply {
this.cancellationTxnId = cancellationTxnId
}
}
private fun getRecipients(): List<Map<String, String>>? {
return try {
deserializeFromRealm(recipientsData)
} catch (failure: Throwable) {
null
}
}
fun putRecipients(recipients: List<Map<String, String>>?) {
recipientsData = serializeForRealm(recipients)
}
}

View file

@ -22,13 +22,14 @@ package im.vector.riotx.features.crypto.keysrequest
import android.content.Context
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.keyshare.RoomKeysRequestListener
import im.vector.matrix.android.api.session.crypto.keyshare.GossipingRequestListener
import im.vector.matrix.android.api.session.crypto.verification.SasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationService
import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequestCancellation
import im.vector.matrix.android.internal.crypto.IncomingRequestCancellation
import im.vector.matrix.android.internal.crypto.IncomingSecretShareRequest
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
@ -54,7 +55,7 @@ import javax.inject.Singleton
@Singleton
class KeyRequestHandler @Inject constructor(private val context: Context)
: RoomKeysRequestListener,
: GossipingRequestListener,
VerificationService.Listener {
private val alertsToRequests = HashMap<String, ArrayList<IncomingRoomKeyRequest>>()
@ -73,6 +74,13 @@ class KeyRequestHandler @Inject constructor(private val context: Context)
session = null
}
override fun onSecretShareRequest(request: IncomingSecretShareRequest) : Boolean {
// By default riotX will not prompt if the SDK has decided that the request should not be fulfilled
Timber.v("## onSecretShareRequest() : Ignoring $request")
request.ignore?.run()
return true
}
/**
* Handle incoming key request.
*
@ -194,20 +202,6 @@ class KeyRequestHandler @Inject constructor(private val context: Context)
denyAllRequests(mappingKey)
}
// TODO send to the new profile page
// alert.addButton(
// context.getString(R.string.start_verification_short_label),
// Runnable {
// alert.weakCurrentActivity?.get()?.let {
// val intent = SASVerificationActivity.outgoingIntent(it,
// session?.myUserId ?: "",
// userId, deviceId)
// it.startActivity(intent)
// }
// },
// false
// )
alert.addButton(context.getString(R.string.share_without_verifying_short_label), Runnable {
shareAllSessions(mappingKey)
})
@ -238,7 +232,7 @@ class KeyRequestHandler @Inject constructor(private val context: Context)
*
* @param request the cancellation request.
*/
override fun onRoomKeyRequestCancellation(request: IncomingRoomKeyRequestCancellation) {
override fun onRoomKeyRequestCancellation(request: IncomingRequestCancellation) {
// see if we can find the request in the queue
val userId = request.userId
val deviceId = request.deviceId

View file

@ -187,7 +187,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
fun refreshNotificationDrawer() {
// Implement last throttler
Timber.w("refreshNotificationDrawer()")
Timber.v("refreshNotificationDrawer()")
backgroundHandler.removeCallbacksAndMessages(null)
backgroundHandler.postDelayed(
{
@ -197,7 +197,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
@WorkerThread
private fun refreshNotificationDrawerBg() {
Timber.w("refreshNotificationDrawerBg()")
Timber.v("refreshNotificationDrawerBg()")
val session = activeSessionHolder.getSafeActiveSession() ?: return