mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 03:48:12 +03:00
Split again
This commit is contained in:
parent
e0e41d9e5c
commit
532a028e41
32 changed files with 1041 additions and 856 deletions
|
@ -34,7 +34,6 @@ interface KeysBackupService {
|
|||
fun backupAllGroupSessions(progressListener: ProgressListener?, callback: MatrixCallback<Unit>?)
|
||||
fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult, callback: MatrixCallback<KeysBackupVersionTrust>)
|
||||
fun getBackupProgress(progressListener: ProgressListener)
|
||||
fun maybeBackupKeys()
|
||||
fun getVersion(version: String, callback: MatrixCallback<KeysVersionResult?>)
|
||||
fun forceUsingLastVersion(callback: MatrixCallback<Boolean>)
|
||||
fun checkAndStartKeysBackup()
|
||||
|
|
|
@ -37,15 +37,19 @@ import im.vector.matrix.android.api.session.events.model.toModel
|
|||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
|
||||
import im.vector.matrix.android.internal.crypto.actions.MegolmSessionDataImporter
|
||||
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmEncryptionFactory
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||
import im.vector.matrix.android.internal.crypto.model.*
|
||||
import im.vector.matrix.android.internal.crypto.model.event.RoomKeyContent
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.EncryptedMessage
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
|
||||
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.*
|
||||
import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificationService
|
||||
|
@ -53,7 +57,6 @@ import im.vector.matrix.android.internal.di.MoshiProvider
|
|||
import im.vector.matrix.android.internal.session.sync.model.SyncResponse
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.util.convertToUTF8
|
||||
import org.matrix.olm.OlmManager
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
@ -71,11 +74,13 @@ import java.util.*
|
|||
internal class CryptoManager(
|
||||
// The credentials,
|
||||
private val mCredentials: Credentials,
|
||||
private val mMyDeviceInfoHolder: MyDeviceInfoHolder,
|
||||
// the crypto store
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
// Olm device
|
||||
private val mOlmDevice: MXOlmDevice,
|
||||
cryptoConfig: MXCryptoConfig?,
|
||||
// Set of parameters used to configure/customize the end-to-end crypto.
|
||||
private val mCryptoConfig: MXCryptoConfig = MXCryptoConfig(),
|
||||
// Device list manager
|
||||
private val deviceListManager: DeviceListManager,
|
||||
// The key backup service.
|
||||
|
@ -98,6 +103,12 @@ internal class CryptoManager(
|
|||
private val mOlmManager: OlmManager,
|
||||
// Actions
|
||||
private val mSetDeviceVerificationAction: SetDeviceVerificationAction,
|
||||
private val mMegolmSessionDataImporter: MegolmSessionDataImporter,
|
||||
private val mEnsureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
|
||||
// Repository
|
||||
private val mWarnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository,
|
||||
private val mMXMegolmEncryptionFactory: MXMegolmEncryptionFactory,
|
||||
private val mMXOlmEncryptionFactory: MXOlmEncryptionFactory,
|
||||
// Tasks
|
||||
private val mClaimOneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask,
|
||||
private val mDeleteDeviceTask: DeleteDeviceTask,
|
||||
|
@ -108,19 +119,11 @@ internal class CryptoManager(
|
|||
private val mUploadKeysTask: UploadKeysTask,
|
||||
// TaskExecutor
|
||||
private val mTaskExecutor: TaskExecutor
|
||||
) : KeysBackup.KeysBackupCryptoListener,
|
||||
DefaultSasVerificationService.SasCryptoListener,
|
||||
CryptoService {
|
||||
) : CryptoService {
|
||||
|
||||
// MXEncrypting instance for each room.
|
||||
private val mRoomEncryptors: MutableMap<String, IMXEncrypting> = HashMap()
|
||||
|
||||
// Our device keys
|
||||
/**
|
||||
* @return my device info
|
||||
*/
|
||||
private val myDevice: MXDeviceInfo
|
||||
|
||||
// the encryption is starting
|
||||
private var mIsStarting: Boolean = false
|
||||
|
||||
|
@ -148,84 +151,6 @@ internal class CryptoManager(
|
|||
// initialization callbacks
|
||||
private val mInitializationCallbacks = ArrayList<MatrixCallback<Unit>>()
|
||||
|
||||
// Warn the user if some new devices are detected while encrypting a message.
|
||||
private var mWarnOnUnknownDevices = true
|
||||
|
||||
// Set of parameters used to configure/customize the end-to-end crypto.
|
||||
private var mCryptoConfig: MXCryptoConfig? = null
|
||||
|
||||
init {
|
||||
if (null != cryptoConfig) {
|
||||
mCryptoConfig = cryptoConfig
|
||||
} else {
|
||||
// Consider the default configuration value
|
||||
mCryptoConfig = MXCryptoConfig()
|
||||
}
|
||||
|
||||
var deviceId = mCredentials.deviceId
|
||||
// deviceId should always be defined
|
||||
val refreshDevicesList = !TextUtils.isEmpty(deviceId)
|
||||
|
||||
if (TextUtils.isEmpty(deviceId)) {
|
||||
// use the stored one
|
||||
deviceId = this.mCryptoStore.getDeviceId()
|
||||
|
||||
// Should not happen anymore
|
||||
TODO()
|
||||
//mSession.setDeviceId(deviceId)
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(deviceId)) {
|
||||
deviceId = UUID.randomUUID().toString()
|
||||
// Should not happen anymore
|
||||
TODO()
|
||||
//mSession.setDeviceId(deviceId)
|
||||
Timber.d("Warning: No device id in MXCredentials. An id was created. Think of storing it")
|
||||
this.mCryptoStore.storeDeviceId(deviceId)
|
||||
}
|
||||
|
||||
myDevice = MXDeviceInfo(deviceId!!, mCredentials.userId)
|
||||
|
||||
val keys = HashMap<String, String>()
|
||||
|
||||
if (!TextUtils.isEmpty(mOlmDevice.deviceEd25519Key)) {
|
||||
keys["ed25519:" + mCredentials.deviceId] = mOlmDevice.deviceEd25519Key!!
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(mOlmDevice.deviceCurve25519Key)) {
|
||||
keys["curve25519:" + mCredentials.deviceId] = mOlmDevice.deviceCurve25519Key!!
|
||||
}
|
||||
|
||||
myDevice.keys = keys
|
||||
|
||||
myDevice.algorithms = MXCryptoAlgorithms.supportedAlgorithms()
|
||||
myDevice.mVerified = MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED
|
||||
|
||||
// Add our own deviceinfo to the store
|
||||
val endToEndDevicesForUser = this.mCryptoStore.getUserDevices(mCredentials.userId)
|
||||
|
||||
val myDevices: MutableMap<String, MXDeviceInfo>
|
||||
|
||||
if (null != endToEndDevicesForUser) {
|
||||
myDevices = HashMap(endToEndDevicesForUser)
|
||||
} else {
|
||||
myDevices = HashMap()
|
||||
}
|
||||
|
||||
myDevices[myDevice.deviceId] = myDevice
|
||||
|
||||
this.mCryptoStore.storeUserDevices(mCredentials.userId, myDevices)
|
||||
|
||||
if (refreshDevicesList) {
|
||||
// ensure to have the up-to-date devices list
|
||||
// got some issues when upgrading from Riot < 0.6.4
|
||||
deviceListManager.handleDeviceListsChanges(listOf(mCredentials.userId), null)
|
||||
}
|
||||
|
||||
mKeysBackup.setCryptoInternalListener(this)
|
||||
mSasVerificationService.setCryptoInternalListener(this)
|
||||
}
|
||||
|
||||
override fun setDeviceName(deviceId: String, deviceName: String, callback: MatrixCallback<Unit>) {
|
||||
mSetDeviceNameTask
|
||||
.configureWith(SetDeviceNameTask.Params(deviceId, deviceName))
|
||||
|
@ -245,7 +170,7 @@ internal class CryptoManager(
|
|||
}
|
||||
|
||||
override fun getMyDevice(): MXDeviceInfo {
|
||||
return myDevice
|
||||
return mMyDeviceInfoHolder.myDevice
|
||||
}
|
||||
|
||||
override fun getDevicesList(callback: MatrixCallback<DevicesListResponse>) {
|
||||
|
@ -462,7 +387,6 @@ internal class CryptoManager(
|
|||
*
|
||||
* @param userId the user id
|
||||
* @param deviceId the device id
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
override fun getDeviceInfo(userId: String, deviceId: String?): MXDeviceInfo? {
|
||||
return if (!TextUtils.isEmpty(userId) && !TextUtils.isEmpty(deviceId)) {
|
||||
|
@ -529,7 +453,6 @@ internal class CryptoManager(
|
|||
* @param verificationStatus the new verification status
|
||||
* @param deviceId the unique identifier for the device.
|
||||
* @param userId the owner of the device
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
override fun setDeviceVerification(verificationStatus: Int, deviceId: String, userId: String) {
|
||||
mSetDeviceVerificationAction.handle(verificationStatus, deviceId, userId)
|
||||
|
@ -555,34 +478,20 @@ internal class CryptoManager(
|
|||
return false
|
||||
}
|
||||
|
||||
val encryptingClass = MXCryptoAlgorithms.encryptorClassForAlgorithm(algorithm)
|
||||
val encryptingClass = MXCryptoAlgorithms.hasEncryptorClassForAlgorithm(algorithm)
|
||||
|
||||
if (null == encryptingClass) {
|
||||
if (!encryptingClass) {
|
||||
Timber.e("## setEncryptionInRoom() : Unable to encrypt with " + algorithm!!)
|
||||
return false
|
||||
}
|
||||
|
||||
mCryptoStore.storeRoomAlgorithm(roomId, algorithm!!)
|
||||
|
||||
val alg: IMXEncrypting
|
||||
|
||||
try {
|
||||
val ctor = encryptingClass.constructors[0]
|
||||
alg = ctor.newInstance() as IMXEncrypting
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## setEncryptionInRoom() : fail to load the class")
|
||||
return false
|
||||
val alg: IMXEncrypting = when (algorithm) {
|
||||
MXCRYPTO_ALGORITHM_MEGOLM -> mMXMegolmEncryptionFactory.instantiate(roomId)
|
||||
else -> mMXOlmEncryptionFactory.instantiate(roomId)
|
||||
}
|
||||
|
||||
alg.initWithMatrixSession(this,
|
||||
mOlmDevice,
|
||||
mKeysBackup,
|
||||
deviceListManager,
|
||||
mCredentials,
|
||||
mSendToDeviceTask,
|
||||
mTaskExecutor,
|
||||
roomId)
|
||||
|
||||
synchronized(mRoomEncryptors) {
|
||||
mRoomEncryptors.put(roomId, alg)
|
||||
}
|
||||
|
@ -641,44 +550,7 @@ internal class CryptoManager(
|
|||
return if (null != map) ArrayList(map.values) else ArrayList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to make sure we have established olm sessions for the given users.
|
||||
* It must be called in getEncryptingThreadHandler() thread.
|
||||
* The callback is called in the UI thread.
|
||||
*
|
||||
* @param users a list of user ids.
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
fun ensureOlmSessionsForUsers(users: List<String>, callback: MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>>) {
|
||||
Timber.d("## ensureOlmSessionsForUsers() : ensureOlmSessionsForUsers $users")
|
||||
|
||||
val devicesByUser = HashMap<String /* userId */, MutableList<MXDeviceInfo>>()
|
||||
|
||||
for (userId in users) {
|
||||
devicesByUser[userId] = ArrayList()
|
||||
|
||||
val devices = getUserDevices(userId)
|
||||
|
||||
for (device in devices) {
|
||||
val key = device.identityKey()
|
||||
|
||||
if (TextUtils.equals(key, mOlmDevice.deviceCurve25519Key)) {
|
||||
// Don't bother setting up session to ourself
|
||||
continue
|
||||
}
|
||||
|
||||
if (device.isVerified) {
|
||||
// Don't bother setting up sessions with blocked users
|
||||
continue
|
||||
}
|
||||
|
||||
devicesByUser[userId]!!.add(device)
|
||||
}
|
||||
}
|
||||
|
||||
ensureOlmSessionsForDevices(devicesByUser, callback)
|
||||
}
|
||||
|
||||
// TODO Remove ?
|
||||
/**
|
||||
* Try to make sure we have established olm sessions for the given devices.
|
||||
* It must be called in getCryptoHandler() thread.
|
||||
|
@ -689,150 +561,9 @@ internal class CryptoManager(
|
|||
*/
|
||||
fun ensureOlmSessionsForDevices(devicesByUser: Map<String, List<MXDeviceInfo>>,
|
||||
callback: MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>>?) {
|
||||
val devicesWithoutSession = ArrayList<MXDeviceInfo>()
|
||||
|
||||
val results = MXUsersDevicesMap<MXOlmSessionResult>()
|
||||
|
||||
val userIds = devicesByUser.keys
|
||||
|
||||
for (userId in userIds) {
|
||||
val deviceInfos = devicesByUser[userId]
|
||||
|
||||
for (deviceInfo in deviceInfos!!) {
|
||||
val deviceId = deviceInfo.deviceId
|
||||
val key = deviceInfo.identityKey()
|
||||
|
||||
val sessionId = mOlmDevice.getSessionId(key!!)
|
||||
|
||||
if (TextUtils.isEmpty(sessionId)) {
|
||||
devicesWithoutSession.add(deviceInfo)
|
||||
}
|
||||
|
||||
val olmSessionResult = MXOlmSessionResult(deviceInfo, sessionId)
|
||||
results.setObject(olmSessionResult, userId, deviceId)
|
||||
}
|
||||
}
|
||||
|
||||
if (devicesWithoutSession.size == 0) {
|
||||
callback?.onSuccess(results)
|
||||
return
|
||||
}
|
||||
|
||||
// Prepare the request for claiming one-time keys
|
||||
val usersDevicesToClaim = MXUsersDevicesMap<String>()
|
||||
|
||||
val oneTimeKeyAlgorithm = MXKey.KEY_SIGNED_CURVE_25519_TYPE
|
||||
|
||||
for (device in devicesWithoutSession) {
|
||||
usersDevicesToClaim.setObject(oneTimeKeyAlgorithm, device.userId, device.deviceId)
|
||||
}
|
||||
|
||||
// TODO: this has a race condition - if we try to send another message
|
||||
// while we are claiming a key, we will end up claiming two and setting up
|
||||
// two sessions.
|
||||
//
|
||||
// That should eventually resolve itself, but it's poor form.
|
||||
|
||||
Timber.d("## claimOneTimeKeysForUsersDevices() : $usersDevicesToClaim")
|
||||
|
||||
mClaimOneTimeKeysForUsersDeviceTask
|
||||
.configureWith(ClaimOneTimeKeysForUsersDeviceTask.Params(usersDevicesToClaim))
|
||||
.dispatchTo(object : MatrixCallback<MXUsersDevicesMap<MXKey>> {
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXKey>) {
|
||||
try {
|
||||
Timber.d("## claimOneTimeKeysForUsersDevices() : keysClaimResponse.oneTimeKeys: $data")
|
||||
|
||||
for (userId in userIds) {
|
||||
val deviceInfos = devicesByUser[userId]
|
||||
|
||||
for (deviceInfo in deviceInfos!!) {
|
||||
|
||||
var oneTimeKey: MXKey? = null
|
||||
|
||||
val deviceIds = data.getUserDeviceIds(userId)
|
||||
|
||||
if (null != deviceIds) {
|
||||
for (deviceId in deviceIds) {
|
||||
val olmSessionResult = results.getObject(deviceId, userId)
|
||||
|
||||
if (null != olmSessionResult!!.mSessionId) {
|
||||
// We already have a result for this device
|
||||
continue
|
||||
}
|
||||
|
||||
val key = data.getObject(deviceId, userId)
|
||||
|
||||
if (TextUtils.equals(key!!.type, oneTimeKeyAlgorithm)) {
|
||||
oneTimeKey = key
|
||||
}
|
||||
|
||||
if (null == oneTimeKey) {
|
||||
Timber.d("## ensureOlmSessionsForDevices() : No one-time keys " + oneTimeKeyAlgorithm
|
||||
+ " for device " + userId + " : " + deviceId)
|
||||
continue
|
||||
}
|
||||
|
||||
// Update the result for this device in results
|
||||
olmSessionResult.mSessionId = verifyKeyAndStartSession(oneTimeKey, userId, deviceInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## ensureOlmSessionsForDevices() " + e.message)
|
||||
}
|
||||
|
||||
callback?.onSuccess(results)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e(failure, "## ensureOlmSessionsForUsers(): claimOneTimeKeysForUsersDevices request failed")
|
||||
|
||||
callback?.onFailure(failure)
|
||||
}
|
||||
})
|
||||
.executeBy(mTaskExecutor)
|
||||
mEnsureOlmSessionsForDevicesAction.handle(devicesByUser, callback)
|
||||
}
|
||||
|
||||
private fun verifyKeyAndStartSession(oneTimeKey: MXKey, userId: String, deviceInfo: MXDeviceInfo): String? {
|
||||
var sessionId: String? = null
|
||||
|
||||
val deviceId = deviceInfo.deviceId
|
||||
val signKeyId = "ed25519:$deviceId"
|
||||
val signature = oneTimeKey.signatureForUserId(userId, signKeyId)
|
||||
|
||||
if (!TextUtils.isEmpty(signature) && !TextUtils.isEmpty(deviceInfo.fingerprint())) {
|
||||
var isVerified = false
|
||||
var errorMessage: String? = null
|
||||
|
||||
try {
|
||||
mOlmDevice.verifySignature(deviceInfo.fingerprint()!!, oneTimeKey.signalableJSONDictionary(), signature)
|
||||
isVerified = true
|
||||
} catch (e: Exception) {
|
||||
errorMessage = e.message
|
||||
}
|
||||
|
||||
// Check one-time key signature
|
||||
if (isVerified) {
|
||||
sessionId = mOlmDevice.createOutboundSession(deviceInfo.identityKey()!!, oneTimeKey.value)
|
||||
|
||||
if (!TextUtils.isEmpty(sessionId)) {
|
||||
Timber.d("## verifyKeyAndStartSession() : Started new sessionid " + sessionId
|
||||
+ " for device " + deviceInfo + "(theirOneTimeKey: " + oneTimeKey.value + ")")
|
||||
} else {
|
||||
// Possibly a bad key
|
||||
Timber.e("## verifyKeyAndStartSession() : Error starting session with device $userId:$deviceId")
|
||||
}
|
||||
} else {
|
||||
Timber.e("## verifyKeyAndStartSession() : Unable to verify signature on one-time key for device " + userId
|
||||
+ ":" + deviceId + " Error " + errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
return sessionId
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encrypt an event content according to the configuration of the room.
|
||||
*
|
||||
|
@ -865,7 +596,7 @@ internal class CryptoManager(
|
|||
}
|
||||
|
||||
// Check whether the event content must be encrypted for the invited members.
|
||||
val encryptForInvitedMembers = mCryptoConfig!!.mEnableEncryptionForInvitedMembers && room.shouldEncryptForInvitedMembers()
|
||||
val encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers && room.shouldEncryptForInvitedMembers()
|
||||
|
||||
val userIds = if (encryptForInvitedMembers) {
|
||||
room.getActiveRoomMemberIds()
|
||||
|
@ -939,7 +670,7 @@ internal class CryptoManager(
|
|||
val exceptions = ArrayList<MXDecryptionException>()
|
||||
|
||||
var result: MXEventDecryptionResult? = null
|
||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(this, event.roomId, eventContent["algorithm"] as String)
|
||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, eventContent["algorithm"] as String)
|
||||
|
||||
if (null == alg) {
|
||||
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, eventContent["algorithm"] as String)
|
||||
|
@ -954,7 +685,7 @@ internal class CryptoManager(
|
|||
}
|
||||
|
||||
if (null != result) {
|
||||
results.add(result)
|
||||
results.add(result) // TODO simplify
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -976,72 +707,6 @@ internal class CryptoManager(
|
|||
mOlmDevice.resetReplayAttackCheckInTimeline(timelineId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt an event payload for a list of devices.
|
||||
* This method must be called from the getCryptoHandler() thread.
|
||||
*
|
||||
* @param payloadFields fields to include in the encrypted payload.
|
||||
* @param deviceInfos list of device infos to encrypt for.
|
||||
* @return the content for an m.room.encrypted event.
|
||||
*/
|
||||
fun encryptMessage(payloadFields: Map<String, Any>, deviceInfos: List<MXDeviceInfo>): EncryptedMessage {
|
||||
val deviceInfoParticipantKey = HashMap<String, MXDeviceInfo>()
|
||||
val participantKeys = ArrayList<String>()
|
||||
|
||||
for (di in deviceInfos) {
|
||||
participantKeys.add(di.identityKey()!!)
|
||||
deviceInfoParticipantKey[di.identityKey()!!] = di
|
||||
}
|
||||
|
||||
val payloadJson = HashMap(payloadFields)
|
||||
|
||||
payloadJson["sender"] = mCredentials.userId
|
||||
payloadJson["sender_device"] = mCredentials.deviceId
|
||||
|
||||
// Include the Ed25519 key so that the recipient knows what
|
||||
// device this message came from.
|
||||
// We don't need to include the curve25519 key since the
|
||||
// recipient will already know this from the olm headers.
|
||||
// When combined with the device keys retrieved from the
|
||||
// homeserver signed by the ed25519 key this proves that
|
||||
// the curve25519 key and the ed25519 key are owned by
|
||||
// the same device.
|
||||
val keysMap = HashMap<String, String>()
|
||||
keysMap["ed25519"] = mOlmDevice.deviceEd25519Key!!
|
||||
payloadJson["keys"] = keysMap
|
||||
|
||||
val ciphertext = HashMap<String, Any>()
|
||||
|
||||
for (deviceKey in participantKeys) {
|
||||
val sessionId = mOlmDevice.getSessionId(deviceKey)
|
||||
|
||||
if (!TextUtils.isEmpty(sessionId)) {
|
||||
Timber.d("Using sessionid $sessionId for device $deviceKey")
|
||||
val deviceInfo = deviceInfoParticipantKey[deviceKey]
|
||||
|
||||
payloadJson["recipient"] = deviceInfo!!.userId
|
||||
|
||||
val recipientsKeysMap = HashMap<String, String>()
|
||||
recipientsKeysMap["ed25519"] = deviceInfo.fingerprint()!!
|
||||
payloadJson["recipient_keys"] = recipientsKeysMap
|
||||
|
||||
// FIXME We have to canonicalize the JSON
|
||||
//JsonUtility.canonicalize(JsonUtility.getGson(false).toJsonTree(payloadJson)).toString()
|
||||
|
||||
val payloadString = convertToUTF8(MoshiProvider.getCanonicalJson(Map::class.java, payloadJson))
|
||||
ciphertext[deviceKey] = mOlmDevice.encryptMessage(deviceKey, sessionId!!, payloadString!!)!!
|
||||
}
|
||||
}
|
||||
|
||||
val res = EncryptedMessage()
|
||||
|
||||
res.algorithm = MXCRYPTO_ALGORITHM_OLM
|
||||
res.senderKey = mOlmDevice.deviceCurve25519Key
|
||||
res.cipherText = ciphertext
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the 'toDevice' event
|
||||
*
|
||||
|
@ -1061,13 +726,7 @@ internal class CryptoManager(
|
|||
*
|
||||
* @param event the key event.
|
||||
*/
|
||||
private fun onRoomKeyEvent(event: Event?) {
|
||||
// sanity check
|
||||
if (null == event) {
|
||||
Timber.e("## onRoomKeyEvent() : null event")
|
||||
return
|
||||
}
|
||||
|
||||
private fun onRoomKeyEvent(event: Event) {
|
||||
val roomKeyContent = event.content.toModel<RoomKeyContent>()!!
|
||||
|
||||
if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.algorithm)) {
|
||||
|
@ -1075,14 +734,14 @@ internal class CryptoManager(
|
|||
return
|
||||
}
|
||||
|
||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(this, roomKeyContent.roomId, roomKeyContent.algorithm)
|
||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(roomKeyContent.roomId, roomKeyContent.algorithm)
|
||||
|
||||
if (null == alg) {
|
||||
Timber.e("## onRoomKeyEvent() : Unable to handle keys for " + roomKeyContent.algorithm!!)
|
||||
Timber.e("## onRoomKeyEvent() : Unable to handle keys for " + roomKeyContent.algorithm)
|
||||
return
|
||||
}
|
||||
|
||||
alg.onRoomKeyEvent(event)
|
||||
alg.onRoomKeyEvent(event, mKeysBackup)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1097,7 +756,7 @@ internal class CryptoManager(
|
|||
val room = mRoomService.getRoom(roomId)!!
|
||||
|
||||
// Check whether the event content must be encrypted for the invited members.
|
||||
val encryptForInvitedMembers = mCryptoConfig!!.mEnableEncryptionForInvitedMembers && room.shouldEncryptForInvitedMembers()
|
||||
val encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers && room.shouldEncryptForInvitedMembers()
|
||||
|
||||
val userIds = if (encryptForInvitedMembers) {
|
||||
room.getActiveRoomMemberIds()
|
||||
|
@ -1138,7 +797,7 @@ internal class CryptoManager(
|
|||
deviceListManager.startTrackingDeviceList(Arrays.asList(userId))
|
||||
} else if (membership == Membership.INVITE
|
||||
&& room.shouldEncryptForInvitedMembers()
|
||||
&& mCryptoConfig!!.mEnableEncryptionForInvitedMembers) {
|
||||
&& mCryptoConfig.mEnableEncryptionForInvitedMembers) {
|
||||
// track the deviceList for this invited user.
|
||||
// Caution: there's a big edge case here in that federated servers do not
|
||||
// know what other servers are in the room at the time they've been invited.
|
||||
|
@ -1159,14 +818,14 @@ internal class CryptoManager(
|
|||
private fun uploadDeviceKeys(callback: MatrixCallback<KeysUploadResponse>) {
|
||||
// Prepare the device keys data to send
|
||||
// Sign it
|
||||
val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, myDevice.signalableJSONDictionary())
|
||||
val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary())
|
||||
|
||||
myDevice.signatures = mObjectSigner.signObject(canonicalJson)
|
||||
getMyDevice().signatures = mObjectSigner.signObject(canonicalJson)
|
||||
|
||||
// For now, we set the device id explicitly, as we may not be using the
|
||||
// same one as used in login.
|
||||
mUploadKeysTask
|
||||
.configureWith(UploadKeysTask.Params(myDevice.toDeviceKeys(), null, myDevice.deviceId))
|
||||
.configureWith(UploadKeysTask.Params(getMyDevice().toDeviceKeys(), null, getMyDevice().deviceId))
|
||||
.dispatchTo(callback)
|
||||
.executeBy(mTaskExecutor)
|
||||
}
|
||||
|
@ -1264,98 +923,7 @@ internal class CryptoManager(
|
|||
|
||||
Timber.d("## importRoomKeys : JSON parsing " + (t2 - t1) + " ms")
|
||||
|
||||
importMegolmSessionsData(importedSessions, true, progressListener, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a list of megolm session keys.
|
||||
*
|
||||
* @param megolmSessionsData megolm sessions.
|
||||
* @param backUpKeys true to back up them to the homeserver.
|
||||
* @param progressListener the progress listener
|
||||
* @param callback
|
||||
*/
|
||||
override fun importMegolmSessionsData(megolmSessionsData: List<MegolmSessionData>,
|
||||
backUpKeys: Boolean,
|
||||
progressListener: ProgressListener?,
|
||||
callback: MatrixCallback<ImportRoomKeysResult>) {
|
||||
val t0 = System.currentTimeMillis()
|
||||
|
||||
val totalNumbersOfKeys = megolmSessionsData.size
|
||||
var cpt = 0
|
||||
var lastProgress = 0
|
||||
var totalNumbersOfImportedKeys = 0
|
||||
|
||||
if (progressListener != null) {
|
||||
progressListener.onProgress(0, 100)
|
||||
}
|
||||
|
||||
val sessions = mOlmDevice.importInboundGroupSessions(megolmSessionsData)
|
||||
|
||||
for (megolmSessionData in megolmSessionsData) {
|
||||
cpt++
|
||||
|
||||
|
||||
val decrypting = roomDecryptorProvider.getOrCreateRoomDecryptor(this, megolmSessionData.roomId, megolmSessionData.algorithm)
|
||||
|
||||
if (null != decrypting) {
|
||||
try {
|
||||
val sessionId = megolmSessionData.sessionId
|
||||
Timber.d("## importRoomKeys retrieve mSenderKey " + megolmSessionData.senderKey + " sessionId " + sessionId)
|
||||
|
||||
totalNumbersOfImportedKeys++
|
||||
|
||||
// cancel any outstanding room key requests for this session
|
||||
val roomKeyRequestBody = RoomKeyRequestBody()
|
||||
|
||||
roomKeyRequestBody.algorithm = megolmSessionData.algorithm
|
||||
roomKeyRequestBody.roomId = megolmSessionData.roomId
|
||||
roomKeyRequestBody.senderKey = megolmSessionData.senderKey
|
||||
roomKeyRequestBody.sessionId = megolmSessionData.sessionId
|
||||
|
||||
cancelRoomKeyRequest(roomKeyRequestBody)
|
||||
|
||||
// Have another go at decrypting events sent with this session
|
||||
decrypting.onNewSession(megolmSessionData.senderKey!!, sessionId!!)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## importRoomKeys() : onNewSession failed")
|
||||
}
|
||||
}
|
||||
|
||||
if (progressListener != null) {
|
||||
val progress = 100 * cpt / totalNumbersOfKeys
|
||||
|
||||
if (lastProgress != progress) {
|
||||
lastProgress = progress
|
||||
|
||||
progressListener.onProgress(progress, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not back up the key if it comes from a backup recovery
|
||||
if (backUpKeys) {
|
||||
mKeysBackup.maybeBackupKeys()
|
||||
} else {
|
||||
mCryptoStore.markBackupDoneForInboundGroupSessions(sessions)
|
||||
}
|
||||
|
||||
val t1 = System.currentTimeMillis()
|
||||
|
||||
Timber.d("## importMegolmSessionsData : sessions import " + (t1 - t0) + " ms (" + megolmSessionsData.size + " sessions)")
|
||||
|
||||
val finalTotalNumbersOfImportedKeys = totalNumbersOfImportedKeys
|
||||
|
||||
callback.onSuccess(ImportRoomKeysResult(totalNumbersOfKeys, finalTotalNumbersOfImportedKeys))
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the encryption must fail if some unknown devices are detected.
|
||||
*
|
||||
* @return true to warn when some unknown devices are detected.
|
||||
*/
|
||||
fun warnOnUnknownDevices(): Boolean {
|
||||
return mWarnOnUnknownDevices
|
||||
mMegolmSessionDataImporter.handle(importedSessions, true, progressListener, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1364,7 +932,7 @@ internal class CryptoManager(
|
|||
* @param warn true to warn when some unknown devices are detected.
|
||||
*/
|
||||
override fun setWarnOnUnknownDevices(warn: Boolean) {
|
||||
mWarnOnUnknownDevices = warn
|
||||
mWarnOnUnknownDevicesRepository.setWarnOnUnknownDevices(warn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1468,7 +1036,6 @@ internal class CryptoManager(
|
|||
* Add this room to the ones which don't encrypt messages to unverified devices.
|
||||
*
|
||||
* @param roomId the room id
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
override fun setRoomBlacklistUnverifiedDevices(roomId: String) {
|
||||
setRoomBlacklistUnverifiedDevices(roomId, true)
|
||||
|
@ -1478,22 +1045,12 @@ internal class CryptoManager(
|
|||
* Remove this room to the ones which don't encrypt messages to unverified devices.
|
||||
*
|
||||
* @param roomId the room id
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
override fun setRoomUnBlacklistUnverifiedDevices(roomId: String) {
|
||||
setRoomBlacklistUnverifiedDevices(roomId, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request for some room keys, if we have not already done so.
|
||||
*
|
||||
* @param requestBody requestBody
|
||||
* @param recipients recipients
|
||||
*/
|
||||
fun requestRoomKey(requestBody: RoomKeyRequestBody, recipients: List<Map<String, String>>) {
|
||||
mOutgoingRoomKeyRequestManager.sendRoomKeyRequest(requestBody, recipients)
|
||||
}
|
||||
|
||||
// TODO Check if this method is still necessary
|
||||
/**
|
||||
* Cancel any earlier room key request
|
||||
*
|
||||
|
@ -1548,7 +1105,7 @@ internal class CryptoManager(
|
|||
* ========================================================================================== */
|
||||
|
||||
override fun toString(): String {
|
||||
return myDevice.userId + " (" + myDevice.deviceId + ")"
|
||||
return "CryptoManager of " + mCredentials.userId + " (" + mCredentials.deviceId + ")"
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -19,11 +19,16 @@ package im.vector.matrix.android.internal.crypto
|
|||
import android.content.Context
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import im.vector.matrix.android.internal.crypto.actions.*
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmDecryptionFactory
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmDecryptionFactory
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmEncryptionFactory
|
||||
import im.vector.matrix.android.internal.crypto.api.CryptoApi
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.*
|
||||
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreMigration
|
||||
|
@ -88,7 +93,7 @@ internal class CryptoModule {
|
|||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomDecryptorProvider(get(), get(), get(), get(), get())
|
||||
RoomDecryptorProvider(get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
|
@ -113,6 +118,56 @@ internal class CryptoModule {
|
|||
SetDeviceVerificationAction(get(), get(), get())
|
||||
}
|
||||
|
||||
// Device info
|
||||
scope(DefaultSession.SCOPE) {
|
||||
MyDeviceInfoHolder(get(), get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
EnsureOlmSessionsForDevicesAction(get(), get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
EnsureOlmSessionsForUsersAction(get(), get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
MegolmSessionDataImporter(get(), get(), get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
MessageEncrypter(get(), get())
|
||||
}
|
||||
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
WarnOnUnknownDeviceRepository()
|
||||
}
|
||||
|
||||
// Factories
|
||||
scope(DefaultSession.SCOPE) {
|
||||
MXMegolmDecryptionFactory(
|
||||
get(), get(), get(), get(), get(), get(), get(), get(), get()
|
||||
)
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
MXMegolmEncryptionFactory(
|
||||
get(), get(), get(), get(), get(), get(), get(), get(), get(), get()
|
||||
)
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
MXOlmDecryptionFactory(
|
||||
get(), get()
|
||||
)
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
MXOlmEncryptionFactory(
|
||||
get(), get(), get(), get(), get()
|
||||
)
|
||||
}
|
||||
|
||||
// CryptoManager
|
||||
scope(DefaultSession.SCOPE) {
|
||||
|
@ -131,8 +186,14 @@ internal class CryptoModule {
|
|||
get(),
|
||||
get(),
|
||||
get(),
|
||||
get(),
|
||||
get(),
|
||||
// Actions
|
||||
get(),
|
||||
get(),
|
||||
get(),
|
||||
// Factory
|
||||
get(), get(),
|
||||
// Tasks
|
||||
get(), get(), get(), get(), get(), get(), get(),
|
||||
// Task executor
|
||||
|
@ -200,6 +261,7 @@ internal class CryptoModule {
|
|||
get(),
|
||||
get(),
|
||||
get(),
|
||||
get(),
|
||||
// Task
|
||||
get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(),
|
||||
// Task executor
|
||||
|
@ -255,7 +317,7 @@ internal class CryptoModule {
|
|||
* ========================================================================================== */
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultSasVerificationService(get(), get(), get(), get(), get())
|
||||
DefaultSasVerificationService(get(), get(), get(), get(), get(), get(), get())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ internal class IncomingRoomKeyRequestManager(
|
|||
private val mReceivedRoomKeyRequestCancellations = ArrayList<IncomingRoomKeyRequestCancellation>()
|
||||
|
||||
// the listeners
|
||||
val mRoomKeysRequestListeners: MutableSet<RoomKeysRequestListener> = HashSet()
|
||||
private val mRoomKeysRequestListeners: MutableSet<RoomKeysRequestListener> = HashSet()
|
||||
|
||||
init {
|
||||
mReceivedRoomKeyRequests.addAll(mCryptoStore.getPendingIncomingRoomKeyRequests())
|
||||
|
|
|
@ -17,60 +17,19 @@
|
|||
|
||||
package im.vector.matrix.android.internal.crypto
|
||||
|
||||
import android.text.TextUtils
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.IMXDecrypting
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
internal object MXCryptoAlgorithms {
|
||||
|
||||
// encryptors map
|
||||
private val mEncryptors: MutableMap<String, Class<IMXEncrypting>>
|
||||
|
||||
// decryptors map
|
||||
private val mDecryptors: MutableMap<String, Class<IMXDecrypting>>
|
||||
|
||||
init {
|
||||
mEncryptors = HashMap()
|
||||
try {
|
||||
mEncryptors[MXCRYPTO_ALGORITHM_MEGOLM] = Class.forName("im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmEncryption") as Class<IMXEncrypting>
|
||||
} catch (e: Exception) {
|
||||
Timber.e("## MXCryptoAlgorithms() : fails to add MXCRYPTO_ALGORITHM_MEGOLM")
|
||||
}
|
||||
|
||||
try {
|
||||
mEncryptors[MXCRYPTO_ALGORITHM_OLM] = Class.forName("im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmEncryption") as Class<IMXEncrypting>
|
||||
} catch (e: Exception) {
|
||||
Timber.e("## MXCryptoAlgorithms() : fails to add MXCRYPTO_ALGORITHM_OLM")
|
||||
}
|
||||
|
||||
mDecryptors = HashMap()
|
||||
try {
|
||||
mDecryptors[MXCRYPTO_ALGORITHM_MEGOLM] = Class.forName("im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmDecryption") as Class<IMXDecrypting>
|
||||
} catch (e: Exception) {
|
||||
Timber.e("## MXCryptoAlgorithms() : fails to add MXCRYPTO_ALGORITHM_MEGOLM")
|
||||
}
|
||||
|
||||
try {
|
||||
mDecryptors[MXCRYPTO_ALGORITHM_OLM] = Class.forName("im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmDecryption") as Class<IMXDecrypting>
|
||||
} catch (e: Exception) {
|
||||
Timber.e("## MXCryptoAlgorithms() : fails to add MXCRYPTO_ALGORITHM_OLM")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class implementing encryption for the provided algorithm.
|
||||
*
|
||||
* @param algorithm the algorithm tag.
|
||||
* @return A class implementing 'IMXEncrypting'.
|
||||
*/
|
||||
fun encryptorClassForAlgorithm(algorithm: String?): Class<IMXEncrypting>? {
|
||||
return if (!TextUtils.isEmpty(algorithm)) {
|
||||
mEncryptors[algorithm]
|
||||
} else {
|
||||
null
|
||||
fun hasEncryptorClassForAlgorithm(algorithm: String?): Boolean {
|
||||
return when (algorithm) {
|
||||
MXCRYPTO_ALGORITHM_MEGOLM,
|
||||
MXCRYPTO_ALGORITHM_OLM -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,11 +40,11 @@ internal object MXCryptoAlgorithms {
|
|||
* @return A class implementing 'IMXDecrypting'.
|
||||
*/
|
||||
|
||||
fun decryptorClassForAlgorithm(algorithm: String?): Class<IMXDecrypting>? {
|
||||
return if (!TextUtils.isEmpty(algorithm)) {
|
||||
mDecryptors[algorithm]
|
||||
} else {
|
||||
null
|
||||
fun hasDecryptorClassForAlgorithm(algorithm: String?): Boolean {
|
||||
return when (algorithm) {
|
||||
MXCRYPTO_ALGORITHM_MEGOLM,
|
||||
MXCRYPTO_ALGORITHM_OLM -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,6 +52,6 @@ internal object MXCryptoAlgorithms {
|
|||
* @return The list of registered algorithms.
|
||||
*/
|
||||
fun supportedAlgorithms(): List<String> {
|
||||
return ArrayList(mEncryptors.keys)
|
||||
return listOf(MXCRYPTO_ALGORITHM_MEGOLM, MXCRYPTO_ALGORITHM_OLM)
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ internal class MXOutgoingRoomKeyRequestManager(
|
|||
private val mTaskExecutor: TaskExecutor) {
|
||||
|
||||
// running
|
||||
var mClientRunning: Boolean = false
|
||||
private var mClientRunning: Boolean = false
|
||||
|
||||
// transaction counter
|
||||
private var mTxnCtr: Int = 0
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2019 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 android.text.TextUtils
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import java.util.*
|
||||
|
||||
internal class MyDeviceInfoHolder(
|
||||
// The credentials,
|
||||
credentials: Credentials,
|
||||
// the crypto store
|
||||
cryptoStore: IMXCryptoStore,
|
||||
// Olm device
|
||||
olmDevice: MXOlmDevice
|
||||
) {
|
||||
// Our device keys
|
||||
/**
|
||||
* my device info
|
||||
*/
|
||||
val myDevice: MXDeviceInfo = MXDeviceInfo(credentials.deviceId!!, credentials.userId)
|
||||
|
||||
init {
|
||||
val keys = HashMap<String, String>()
|
||||
|
||||
if (!TextUtils.isEmpty(olmDevice.deviceEd25519Key)) {
|
||||
keys["ed25519:" + credentials.deviceId] = olmDevice.deviceEd25519Key!!
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(olmDevice.deviceCurve25519Key)) {
|
||||
keys["curve25519:" + credentials.deviceId] = olmDevice.deviceCurve25519Key!!
|
||||
}
|
||||
|
||||
myDevice.keys = keys
|
||||
|
||||
myDevice.algorithms = MXCryptoAlgorithms.supportedAlgorithms()
|
||||
myDevice.mVerified = MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED
|
||||
|
||||
// Add our own deviceinfo to the store
|
||||
val endToEndDevicesForUser = cryptoStore.getUserDevices(credentials.userId)
|
||||
|
||||
val myDevices: MutableMap<String, MXDeviceInfo>
|
||||
|
||||
if (null != endToEndDevicesForUser) {
|
||||
myDevices = HashMap(endToEndDevicesForUser)
|
||||
} else {
|
||||
myDevices = HashMap()
|
||||
}
|
||||
|
||||
myDevices[myDevice.deviceId] = myDevice
|
||||
|
||||
cryptoStore.storeUserDevices(credentials.userId, myDevices)
|
||||
}
|
||||
}
|
|
@ -108,7 +108,9 @@ internal class OneTimeKeysManager(
|
|||
// But that message might never arrive leaving us stuck with duff
|
||||
// private keys clogging up our local storage.
|
||||
// So we need some kind of engineering compromise to balance all of
|
||||
// these factors. // TODO Why we do not set mOneTimeKeyCount here?
|
||||
// these factors.
|
||||
// TODO Why we do not set mOneTimeKeyCount here?
|
||||
// TODO This is not needed anymore, see https://github.com/matrix-org/matrix-js-sdk/pull/493 (TODO on iOS also)
|
||||
val keyCount = data.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)
|
||||
uploadOTK(keyCount, keyLimit, callback)
|
||||
}
|
||||
|
|
|
@ -17,19 +17,15 @@
|
|||
package im.vector.matrix.android.internal.crypto
|
||||
|
||||
import android.text.TextUtils
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.IMXDecrypting
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmDecryptionFactory
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmDecryptionFactory
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
internal class RoomDecryptorProvider(
|
||||
val mCredentials: Credentials,
|
||||
val olmDevice: MXOlmDevice,
|
||||
val deviceListManager: DeviceListManager,
|
||||
val mSendToDeviceTask: SendToDeviceTask,
|
||||
val mTaskExecutor: TaskExecutor
|
||||
private val mMXOlmDecryptionFactory: MXOlmDecryptionFactory,
|
||||
private val mMXMegolmDecryptionFactory: MXMegolmDecryptionFactory
|
||||
) {
|
||||
|
||||
// A map from algorithm to MXDecrypting instance, for each room
|
||||
|
@ -43,20 +39,15 @@ internal class RoomDecryptorProvider(
|
|||
* @param roomId the room id
|
||||
* @param algorithm the crypto algorithm
|
||||
* @return the decryptor
|
||||
* TODO do not provide cryptoManager? // TODO Create another method for the case of roomId is null
|
||||
* // TODO Create another method for the case of roomId is null
|
||||
*/
|
||||
fun getOrCreateRoomDecryptor(cryptoManager: CryptoManager, roomId: String?, algorithm: String?): IMXDecrypting? {
|
||||
fun getOrCreateRoomDecryptor(roomId: String?, algorithm: String?): IMXDecrypting? {
|
||||
// sanity check
|
||||
if (TextUtils.isEmpty(algorithm)) {
|
||||
Timber.e("## getRoomDecryptor() : null algorithm")
|
||||
return null
|
||||
}
|
||||
|
||||
if (null == mRoomDecryptors) {
|
||||
Timber.e("## getRoomDecryptor() : null mRoomDecryptors")
|
||||
return null
|
||||
}
|
||||
|
||||
var alg: IMXDecrypting? = null
|
||||
|
||||
if (!TextUtils.isEmpty(roomId)) {
|
||||
|
@ -73,27 +64,21 @@ internal class RoomDecryptorProvider(
|
|||
}
|
||||
}
|
||||
|
||||
val decryptingClass = MXCryptoAlgorithms.decryptorClassForAlgorithm(algorithm)
|
||||
val decryptingClass = MXCryptoAlgorithms.hasDecryptorClassForAlgorithm(algorithm)
|
||||
|
||||
if (null != decryptingClass) {
|
||||
try {
|
||||
val ctor = decryptingClass.constructors[0]
|
||||
alg = ctor.newInstance() as IMXDecrypting
|
||||
|
||||
if (null != alg) {
|
||||
alg!!.initWithMatrixSession(mCredentials, cryptoManager, olmDevice, deviceListManager, mSendToDeviceTask, mTaskExecutor)
|
||||
|
||||
if (!TextUtils.isEmpty(roomId)) {
|
||||
synchronized(mRoomDecryptors) {
|
||||
mRoomDecryptors[roomId]!!.put(algorithm!!, alg!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## getRoomDecryptor() : fail to load the class")
|
||||
return null
|
||||
if (decryptingClass) {
|
||||
alg = when (algorithm) {
|
||||
MXCRYPTO_ALGORITHM_MEGOLM -> mMXMegolmDecryptionFactory.instantiate()
|
||||
else -> mMXOlmDecryptionFactory.instantiate()
|
||||
}
|
||||
|
||||
if (null != alg) {
|
||||
if (!TextUtils.isEmpty(roomId)) {
|
||||
synchronized(mRoomDecryptors) {
|
||||
mRoomDecryptors[roomId]!!.put(algorithm!!, alg!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alg
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Copyright 2019 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.actions
|
||||
|
||||
import android.text.TextUtils
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.MXKey
|
||||
import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
import im.vector.matrix.android.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
internal class EnsureOlmSessionsForDevicesAction(private val mOlmDevice: MXOlmDevice,
|
||||
private val mClaimOneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask,
|
||||
private val mTaskExecutor: TaskExecutor) {
|
||||
|
||||
|
||||
fun handle(devicesByUser: Map<String, List<MXDeviceInfo>>, callback: MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>>?) {
|
||||
val devicesWithoutSession = ArrayList<MXDeviceInfo>()
|
||||
|
||||
val results = MXUsersDevicesMap<MXOlmSessionResult>()
|
||||
|
||||
val userIds = devicesByUser.keys
|
||||
|
||||
for (userId in userIds) {
|
||||
val deviceInfos = devicesByUser[userId]
|
||||
|
||||
for (deviceInfo in deviceInfos!!) {
|
||||
val deviceId = deviceInfo.deviceId
|
||||
val key = deviceInfo.identityKey()
|
||||
|
||||
val sessionId = mOlmDevice.getSessionId(key!!)
|
||||
|
||||
if (TextUtils.isEmpty(sessionId)) {
|
||||
devicesWithoutSession.add(deviceInfo)
|
||||
}
|
||||
|
||||
val olmSessionResult = MXOlmSessionResult(deviceInfo, sessionId)
|
||||
results.setObject(olmSessionResult, userId, deviceId)
|
||||
}
|
||||
}
|
||||
|
||||
if (devicesWithoutSession.size == 0) {
|
||||
callback?.onSuccess(results)
|
||||
return
|
||||
}
|
||||
|
||||
// Prepare the request for claiming one-time keys
|
||||
val usersDevicesToClaim = MXUsersDevicesMap<String>()
|
||||
|
||||
val oneTimeKeyAlgorithm = MXKey.KEY_SIGNED_CURVE_25519_TYPE
|
||||
|
||||
for (device in devicesWithoutSession) {
|
||||
usersDevicesToClaim.setObject(oneTimeKeyAlgorithm, device.userId, device.deviceId)
|
||||
}
|
||||
|
||||
// TODO: this has a race condition - if we try to send another message
|
||||
// while we are claiming a key, we will end up claiming two and setting up
|
||||
// two sessions.
|
||||
//
|
||||
// That should eventually resolve itself, but it's poor form.
|
||||
|
||||
Timber.d("## claimOneTimeKeysForUsersDevices() : $usersDevicesToClaim")
|
||||
|
||||
mClaimOneTimeKeysForUsersDeviceTask
|
||||
.configureWith(ClaimOneTimeKeysForUsersDeviceTask.Params(usersDevicesToClaim))
|
||||
.dispatchTo(object : MatrixCallback<MXUsersDevicesMap<MXKey>> {
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXKey>) {
|
||||
try {
|
||||
Timber.d("## claimOneTimeKeysForUsersDevices() : keysClaimResponse.oneTimeKeys: $data")
|
||||
|
||||
for (userId in userIds) {
|
||||
val deviceInfos = devicesByUser[userId]
|
||||
|
||||
for (deviceInfo in deviceInfos!!) {
|
||||
|
||||
var oneTimeKey: MXKey? = null
|
||||
|
||||
val deviceIds = data.getUserDeviceIds(userId)
|
||||
|
||||
if (null != deviceIds) {
|
||||
for (deviceId in deviceIds) {
|
||||
val olmSessionResult = results.getObject(deviceId, userId)
|
||||
|
||||
if (null != olmSessionResult!!.mSessionId) {
|
||||
// We already have a result for this device
|
||||
continue
|
||||
}
|
||||
|
||||
val key = data.getObject(deviceId, userId)
|
||||
|
||||
if (TextUtils.equals(key!!.type, oneTimeKeyAlgorithm)) {
|
||||
oneTimeKey = key
|
||||
}
|
||||
|
||||
if (null == oneTimeKey) {
|
||||
Timber.d("## ensureOlmSessionsForDevices() : No one-time keys " + oneTimeKeyAlgorithm
|
||||
+ " for device " + userId + " : " + deviceId)
|
||||
continue
|
||||
}
|
||||
|
||||
// Update the result for this device in results
|
||||
olmSessionResult.mSessionId = verifyKeyAndStartSession(oneTimeKey, userId, deviceInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## ensureOlmSessionsForDevices() " + e.message)
|
||||
}
|
||||
|
||||
callback?.onSuccess(results)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e(failure, "## ensureOlmSessionsForUsers(): claimOneTimeKeysForUsersDevices request failed")
|
||||
|
||||
callback?.onFailure(failure)
|
||||
}
|
||||
})
|
||||
.executeBy(mTaskExecutor)
|
||||
}
|
||||
|
||||
|
||||
private fun verifyKeyAndStartSession(oneTimeKey: MXKey, userId: String, deviceInfo: MXDeviceInfo): String? {
|
||||
var sessionId: String? = null
|
||||
|
||||
val deviceId = deviceInfo.deviceId
|
||||
val signKeyId = "ed25519:$deviceId"
|
||||
val signature = oneTimeKey.signatureForUserId(userId, signKeyId)
|
||||
|
||||
if (!TextUtils.isEmpty(signature) && !TextUtils.isEmpty(deviceInfo.fingerprint())) {
|
||||
var isVerified = false
|
||||
var errorMessage: String? = null
|
||||
|
||||
try {
|
||||
mOlmDevice.verifySignature(deviceInfo.fingerprint()!!, oneTimeKey.signalableJSONDictionary(), signature)
|
||||
isVerified = true
|
||||
} catch (e: Exception) {
|
||||
errorMessage = e.message
|
||||
}
|
||||
|
||||
// Check one-time key signature
|
||||
if (isVerified) {
|
||||
sessionId = mOlmDevice.createOutboundSession(deviceInfo.identityKey()!!, oneTimeKey.value)
|
||||
|
||||
if (!TextUtils.isEmpty(sessionId)) {
|
||||
Timber.d("## verifyKeyAndStartSession() : Started new sessionid " + sessionId
|
||||
+ " for device " + deviceInfo + "(theirOneTimeKey: " + oneTimeKey.value + ")")
|
||||
} else {
|
||||
// Possibly a bad key
|
||||
Timber.e("## verifyKeyAndStartSession() : Error starting session with device $userId:$deviceId")
|
||||
}
|
||||
} else {
|
||||
Timber.e("## verifyKeyAndStartSession() : Unable to verify signature on one-time key for device " + userId
|
||||
+ ":" + deviceId + " Error " + errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
return sessionId
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2019 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.actions
|
||||
|
||||
import android.text.TextUtils
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
internal class EnsureOlmSessionsForUsersAction(private val mOlmDevice: MXOlmDevice,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mEnsureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction) {
|
||||
|
||||
/**
|
||||
* Try to make sure we have established olm sessions for the given users.
|
||||
* It must be called in getEncryptingThreadHandler() thread.
|
||||
* The callback is called in the UI thread.
|
||||
*
|
||||
* @param users a list of user ids.
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
fun handle(users: List<String>, callback: MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>>) {
|
||||
Timber.d("## ensureOlmSessionsForUsers() : ensureOlmSessionsForUsers $users")
|
||||
|
||||
val devicesByUser = HashMap<String /* userId */, MutableList<MXDeviceInfo>>()
|
||||
|
||||
for (userId in users) {
|
||||
devicesByUser[userId] = ArrayList()
|
||||
|
||||
val devices = mCryptoStore.getUserDevices(userId)?.values ?: emptyList()
|
||||
|
||||
for (device in devices) {
|
||||
val key = device.identityKey()
|
||||
|
||||
if (TextUtils.equals(key, mOlmDevice.deviceCurve25519Key)) {
|
||||
// Don't bother setting up session to ourself
|
||||
continue
|
||||
}
|
||||
|
||||
if (device.isVerified) {
|
||||
// Don't bother setting up sessions with blocked users
|
||||
continue
|
||||
}
|
||||
|
||||
devicesByUser[userId]!!.add(device)
|
||||
}
|
||||
}
|
||||
|
||||
mEnsureOlmSessionsForDevicesAction.handle(devicesByUser, callback)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2019 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.actions
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.listeners.ProgressListener
|
||||
import im.vector.matrix.android.internal.crypto.*
|
||||
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MegolmSessionDataImporter(private val mOlmDevice: MXOlmDevice,
|
||||
private val roomDecryptorProvider: RoomDecryptorProvider,
|
||||
private val mOutgoingRoomKeyRequestManager: MXOutgoingRoomKeyRequestManager,
|
||||
private val mCryptoStore: IMXCryptoStore) {
|
||||
|
||||
/**
|
||||
* Import a list of megolm session keys.
|
||||
*
|
||||
* @param megolmSessionsData megolm sessions.
|
||||
* @param backUpKeys true to back up them to the homeserver.
|
||||
* @param progressListener the progress listener
|
||||
* @param callback
|
||||
*/
|
||||
fun handle(megolmSessionsData: List<MegolmSessionData>,
|
||||
fromBackup: Boolean,
|
||||
progressListener: ProgressListener?,
|
||||
callback: MatrixCallback<ImportRoomKeysResult>) {
|
||||
val t0 = System.currentTimeMillis()
|
||||
|
||||
val totalNumbersOfKeys = megolmSessionsData.size
|
||||
var cpt = 0
|
||||
var lastProgress = 0
|
||||
var totalNumbersOfImportedKeys = 0
|
||||
|
||||
if (progressListener != null) {
|
||||
CryptoAsyncHelper.getUiHandler().post {
|
||||
progressListener.onProgress(0, 100)
|
||||
}
|
||||
}
|
||||
|
||||
val sessions = mOlmDevice.importInboundGroupSessions(megolmSessionsData)
|
||||
|
||||
for (megolmSessionData in megolmSessionsData) {
|
||||
cpt++
|
||||
|
||||
|
||||
val decrypting = roomDecryptorProvider.getOrCreateRoomDecryptor(megolmSessionData.roomId, megolmSessionData.algorithm)
|
||||
|
||||
if (null != decrypting) {
|
||||
try {
|
||||
val sessionId = megolmSessionData.sessionId
|
||||
Timber.d("## importRoomKeys retrieve mSenderKey " + megolmSessionData.senderKey + " sessionId " + sessionId)
|
||||
|
||||
totalNumbersOfImportedKeys++
|
||||
|
||||
// cancel any outstanding room key requests for this session
|
||||
val roomKeyRequestBody = RoomKeyRequestBody()
|
||||
|
||||
roomKeyRequestBody.algorithm = megolmSessionData.algorithm
|
||||
roomKeyRequestBody.roomId = megolmSessionData.roomId
|
||||
roomKeyRequestBody.senderKey = megolmSessionData.senderKey
|
||||
roomKeyRequestBody.sessionId = megolmSessionData.sessionId
|
||||
|
||||
mOutgoingRoomKeyRequestManager.cancelRoomKeyRequest(roomKeyRequestBody)
|
||||
|
||||
// Have another go at decrypting events sent with this session
|
||||
decrypting.onNewSession(megolmSessionData.senderKey!!, sessionId!!)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## importRoomKeys() : onNewSession failed")
|
||||
}
|
||||
}
|
||||
|
||||
if (progressListener != null) {
|
||||
CryptoAsyncHelper.getUiHandler().post {
|
||||
val progress = 100 * cpt / totalNumbersOfKeys
|
||||
|
||||
if (lastProgress != progress) {
|
||||
lastProgress = progress
|
||||
|
||||
progressListener.onProgress(progress, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not back up the key if it comes from a backup recovery
|
||||
if (fromBackup) {
|
||||
mCryptoStore.markBackupDoneForInboundGroupSessions(sessions)
|
||||
}
|
||||
|
||||
val t1 = System.currentTimeMillis()
|
||||
|
||||
Timber.d("## importMegolmSessionsData : sessions import " + (t1 - t0) + " ms (" + megolmSessionsData.size + " sessions)")
|
||||
|
||||
val finalTotalNumbersOfImportedKeys = totalNumbersOfImportedKeys
|
||||
|
||||
CryptoAsyncHelper.getUiHandler().post {
|
||||
callback.onSuccess(ImportRoomKeysResult(totalNumbersOfKeys, finalTotalNumbersOfImportedKeys))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2019 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.actions
|
||||
|
||||
import android.text.TextUtils
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_OLM
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.EncryptedMessage
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
import im.vector.matrix.android.internal.util.convertToUTF8
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
internal class MessageEncrypter(private val mCredentials: Credentials,
|
||||
private val mOlmDevice: MXOlmDevice) {
|
||||
|
||||
/**
|
||||
* Encrypt an event payload for a list of devices.
|
||||
* This method must be called from the getCryptoHandler() thread.
|
||||
*
|
||||
* @param payloadFields fields to include in the encrypted payload.
|
||||
* @param deviceInfos list of device infos to encrypt for.
|
||||
* @return the content for an m.room.encrypted event.
|
||||
*/
|
||||
fun encryptMessage(payloadFields: Map<String, Any>, deviceInfos: List<MXDeviceInfo>): EncryptedMessage {
|
||||
val deviceInfoParticipantKey = HashMap<String, MXDeviceInfo>()
|
||||
val participantKeys = ArrayList<String>()
|
||||
|
||||
for (di in deviceInfos) {
|
||||
participantKeys.add(di.identityKey()!!)
|
||||
deviceInfoParticipantKey[di.identityKey()!!] = di
|
||||
}
|
||||
|
||||
val payloadJson = HashMap(payloadFields)
|
||||
|
||||
payloadJson["sender"] = mCredentials.userId
|
||||
payloadJson["sender_device"] = mCredentials.deviceId
|
||||
|
||||
// Include the Ed25519 key so that the recipient knows what
|
||||
// device this message came from.
|
||||
// We don't need to include the curve25519 key since the
|
||||
// recipient will already know this from the olm headers.
|
||||
// When combined with the device keys retrieved from the
|
||||
// homeserver signed by the ed25519 key this proves that
|
||||
// the curve25519 key and the ed25519 key are owned by
|
||||
// the same device.
|
||||
val keysMap = HashMap<String, String>()
|
||||
keysMap["ed25519"] = mOlmDevice.deviceEd25519Key!!
|
||||
payloadJson["keys"] = keysMap
|
||||
|
||||
val ciphertext = HashMap<String, Any>()
|
||||
|
||||
for (deviceKey in participantKeys) {
|
||||
val sessionId = mOlmDevice.getSessionId(deviceKey)
|
||||
|
||||
if (!TextUtils.isEmpty(sessionId)) {
|
||||
Timber.d("Using sessionid $sessionId for device $deviceKey")
|
||||
val deviceInfo = deviceInfoParticipantKey[deviceKey]
|
||||
|
||||
payloadJson["recipient"] = deviceInfo!!.userId
|
||||
|
||||
val recipientsKeysMap = HashMap<String, String>()
|
||||
recipientsKeysMap["ed25519"] = deviceInfo.fingerprint()!!
|
||||
payloadJson["recipient_keys"] = recipientsKeysMap
|
||||
|
||||
// FIXME We have to canonicalize the JSON
|
||||
//JsonUtility.canonicalize(JsonUtility.getGson(false).toJsonTree(payloadJson)).toString()
|
||||
|
||||
val payloadString = convertToUTF8(MoshiProvider.getCanonicalJson(Map::class.java, payloadJson))
|
||||
ciphertext[deviceKey] = mOlmDevice.encryptMessage(deviceKey, sessionId!!, payloadString!!)!!
|
||||
}
|
||||
}
|
||||
|
||||
val res = EncryptedMessage()
|
||||
|
||||
res.algorithm = MXCRYPTO_ALGORITHM_OLM
|
||||
res.senderKey = mOlmDevice.deviceCurve25519Key
|
||||
res.cipherText = ciphertext
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
}
|
|
@ -17,30 +17,17 @@
|
|||
|
||||
package im.vector.matrix.android.internal.crypto.algorithms
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.internal.crypto.*
|
||||
import im.vector.matrix.android.internal.crypto.CryptoManager
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
|
||||
import im.vector.matrix.android.internal.crypto.MXDecryptionException
|
||||
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||
|
||||
/**
|
||||
* An interface for decrypting data
|
||||
*/
|
||||
internal interface IMXDecrypting {
|
||||
|
||||
/**
|
||||
* Init the object fields
|
||||
*
|
||||
* @param matrixSession the session
|
||||
*/
|
||||
fun initWithMatrixSession(credentials: Credentials,
|
||||
crypto: CryptoManager,
|
||||
olmDevice: MXOlmDevice,
|
||||
deviceListManager: DeviceListManager,
|
||||
sendToDeviceTask: SendToDeviceTask,
|
||||
taskExecutor: TaskExecutor)
|
||||
|
||||
/**
|
||||
* Decrypt an event
|
||||
*
|
||||
|
@ -57,7 +44,7 @@ internal interface IMXDecrypting {
|
|||
*
|
||||
* @param event the key event.
|
||||
*/
|
||||
fun onRoomKeyEvent(event: Event)
|
||||
fun onRoomKeyEvent(event: Event, keysBackup: KeysBackup) {}
|
||||
|
||||
/**
|
||||
* Check if the some messages can be decrypted with a new session
|
||||
|
@ -65,7 +52,7 @@ internal interface IMXDecrypting {
|
|||
* @param senderKey the session sender key
|
||||
* @param sessionId the session id
|
||||
*/
|
||||
fun onNewSession(senderKey: String, sessionId: String)
|
||||
fun onNewSession(senderKey: String, sessionId: String) {}
|
||||
|
||||
/**
|
||||
* Determine if we have the keys necessary to respond to a room key request
|
||||
|
@ -73,12 +60,12 @@ internal interface IMXDecrypting {
|
|||
* @param request keyRequest
|
||||
* @return true if we have the keys and could (theoretically) share
|
||||
*/
|
||||
fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean
|
||||
fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean = false
|
||||
|
||||
/**
|
||||
* Send the response to a room key request.
|
||||
*
|
||||
* @param request keyRequest
|
||||
*/
|
||||
fun shareKeysWithDevice(request: IncomingRoomKeyRequest)
|
||||
fun shareKeysWithDevice(request: IncomingRoomKeyRequest) {}
|
||||
}
|
||||
|
|
|
@ -18,35 +18,13 @@
|
|||
package im.vector.matrix.android.internal.crypto.algorithms
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.events.model.Content
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.CryptoManager
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
|
||||
/**
|
||||
* An interface for encrypting data
|
||||
*/
|
||||
internal interface IMXEncrypting {
|
||||
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
* @param matrixSession the related 'MXSession'.
|
||||
* @param roomId the id of the room we will be sending to.
|
||||
*/
|
||||
fun initWithMatrixSession(crypto: CryptoManager,
|
||||
olmDevice: MXOlmDevice,
|
||||
keysBackup: KeysBackup,
|
||||
deviceListManager: DeviceListManager,
|
||||
credentials: Credentials,
|
||||
sendToDeviceTask: SendToDeviceTask,
|
||||
taskExecutor: TaskExecutor,
|
||||
roomId: String)
|
||||
|
||||
/**
|
||||
* Encrypt an event content according to the configuration of the room.
|
||||
*
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package im.vector.matrix.android.internal.crypto.algorithms.megolm
|
||||
|
||||
import android.text.TextUtils
|
||||
import androidx.annotation.Keep
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
||||
|
@ -26,8 +25,11 @@ import im.vector.matrix.android.api.session.events.model.Event
|
|||
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.*
|
||||
import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
|
||||
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.IMXDecrypting
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.MXDecryptionResult
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
|
@ -42,44 +44,22 @@ import im.vector.matrix.android.internal.task.configureWith
|
|||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
@Keep
|
||||
internal class MXMegolmDecryption : IMXDecrypting {
|
||||
/**
|
||||
* The olm device interface
|
||||
*/
|
||||
|
||||
// the matrix credentials
|
||||
private lateinit var mCredentials: Credentials
|
||||
|
||||
private lateinit var mCrypto: CryptoManager
|
||||
private lateinit var mOlmDevice: MXOlmDevice
|
||||
private lateinit var mDeviceListManager: DeviceListManager
|
||||
private lateinit var mCryptoStore: IMXCryptoStore
|
||||
private lateinit var mSendToDeviceTask: SendToDeviceTask
|
||||
private lateinit var mTaskExecutor: TaskExecutor
|
||||
internal class MXMegolmDecryption(private val mCredentials: Credentials,
|
||||
private val mOlmDevice: MXOlmDevice,
|
||||
private val mDeviceListManager: DeviceListManager,
|
||||
private val mOutgoingRoomKeyRequestManager: MXOutgoingRoomKeyRequestManager,
|
||||
private val mMessageEncrypter: MessageEncrypter,
|
||||
private val mEnsureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mSendToDeviceTask: SendToDeviceTask,
|
||||
private val mTaskExecutor: TaskExecutor)
|
||||
: IMXDecrypting {
|
||||
|
||||
/**
|
||||
* Events which we couldn't decrypt due to unknown sessions / indexes: map from
|
||||
* senderKey|sessionId to timelines to list of MatrixEvents.
|
||||
*/
|
||||
private var mPendingEvents: MutableMap<String /* senderKey|sessionId */, MutableMap<String /* timelineId */, MutableList<Event>>> = HashMap()
|
||||
|
||||
/**
|
||||
* Init the object fields
|
||||
*/
|
||||
override fun initWithMatrixSession(credentials: Credentials,
|
||||
crypto: CryptoManager,
|
||||
olmDevice: MXOlmDevice,
|
||||
deviceListManager: DeviceListManager,
|
||||
sendToDeviceTask: SendToDeviceTask,
|
||||
taskExecutor: TaskExecutor) {
|
||||
mCredentials = credentials
|
||||
mCrypto = crypto
|
||||
mOlmDevice = olmDevice
|
||||
mDeviceListManager = deviceListManager
|
||||
mSendToDeviceTask = sendToDeviceTask
|
||||
mTaskExecutor = taskExecutor
|
||||
}
|
||||
private var mPendingEvents: MutableMap<String /* senderKey|sessionId */, MutableMap<String /* timelineId */, MutableList<Event>>> = HashMap()
|
||||
|
||||
@Throws(MXDecryptionException::class)
|
||||
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? {
|
||||
|
@ -87,8 +67,8 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||
}
|
||||
|
||||
@Throws(MXDecryptionException::class)
|
||||
private fun decryptEvent(event: Event?, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult? {
|
||||
// sanity check
|
||||
private fun decryptEvent(event: Event, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult? {
|
||||
// sanity check // TODO Remove check
|
||||
if (null == event) {
|
||||
Timber.e("## decryptEvent() : null event")
|
||||
return null
|
||||
|
@ -185,7 +165,7 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||
requestBody.senderKey = encryptedEventContent.senderKey
|
||||
requestBody.sessionId = encryptedEventContent.sessionId
|
||||
|
||||
mCrypto.requestRoomKey(requestBody, recipients)
|
||||
mOutgoingRoomKeyRequestManager.sendRoomKeyRequest(requestBody, recipients)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -217,9 +197,9 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||
/**
|
||||
* Handle a key event.
|
||||
*
|
||||
* @param roomKeyEvent the key event.
|
||||
* @param event the key event.
|
||||
*/
|
||||
override fun onRoomKeyEvent(event: Event) {
|
||||
override fun onRoomKeyEvent(event: Event, keysBackup: KeysBackup) {
|
||||
var exportFormat = false
|
||||
val roomKeyContent = event.content.toModel<RoomKeyContent>()!!
|
||||
|
||||
|
@ -274,7 +254,7 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||
val added = mOlmDevice.addInboundGroupSession(roomKeyContent.sessionId!!, roomKeyContent.sessionKey!!, roomKeyContent.roomId!!, senderKey, forwarding_curve25519_key_chain!!, keysClaimed, exportFormat)
|
||||
|
||||
if (added) {
|
||||
mCrypto.getKeysBackupService().maybeBackupKeys()
|
||||
keysBackup.maybeBackupKeys()
|
||||
|
||||
val content = RoomKeyRequestBody()
|
||||
|
||||
|
@ -283,7 +263,7 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||
content.sessionId = roomKeyContent.sessionId
|
||||
content.senderKey = senderKey
|
||||
|
||||
mCrypto.cancelRoomKeyRequest(content)
|
||||
mOutgoingRoomKeyRequestManager.cancelRoomKeyRequest(content)
|
||||
|
||||
onNewSession(senderKey, roomKeyContent.sessionId!!)
|
||||
}
|
||||
|
@ -334,14 +314,13 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||
}
|
||||
|
||||
override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean {
|
||||
return (null != request
|
||||
&& null != request.mRequestBody
|
||||
return (null != request.mRequestBody
|
||||
&& mOlmDevice.hasInboundSessionKeys(request.mRequestBody!!.roomId!!, request.mRequestBody!!.senderKey!!, request.mRequestBody!!.sessionId!!))
|
||||
}
|
||||
|
||||
override fun shareKeysWithDevice(request: IncomingRoomKeyRequest) {
|
||||
// sanity checks
|
||||
if (null == request || null == request.mRequestBody) {
|
||||
if (request.mRequestBody == null) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -358,9 +337,9 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||
val devicesByUser = HashMap<String, List<MXDeviceInfo>>()
|
||||
devicesByUser[userId] = ArrayList(Arrays.asList(deviceInfo))
|
||||
|
||||
mCrypto.ensureOlmSessionsForDevices(devicesByUser, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
|
||||
override fun onSuccess(map: MXUsersDevicesMap<MXOlmSessionResult>) {
|
||||
val olmSessionResult = map.getObject(deviceId, userId)
|
||||
mEnsureOlmSessionsForDevicesAction.handle(devicesByUser, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXOlmSessionResult>) {
|
||||
val olmSessionResult = data.getObject(deviceId, userId)
|
||||
|
||||
if (null == olmSessionResult || null == olmSessionResult.mSessionId) {
|
||||
// no session with this device, probably because there
|
||||
|
@ -380,7 +359,7 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||
payloadJson["type"] = EventType.FORWARDED_ROOM_KEY
|
||||
payloadJson["content"] = inboundGroupSession!!.exportKeys()!!
|
||||
|
||||
val encodedPayload = mCrypto.encryptMessage(payloadJson, Arrays.asList(deviceInfo))
|
||||
val encodedPayload = mMessageEncrypter.encryptMessage(payloadJson, Arrays.asList(deviceInfo))
|
||||
val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
||||
sendToDeviceMap.setObject(encodedPayload, userId, deviceId)
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2019 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.algorithms.megolm
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.MXOutgoingRoomKeyRequestManager
|
||||
import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
|
||||
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
|
||||
internal class MXMegolmDecryptionFactory(private val mCredentials: Credentials,
|
||||
private val mOlmDevice: MXOlmDevice,
|
||||
private val mDeviceListManager: DeviceListManager,
|
||||
private val mOutgoingRoomKeyRequestManager: MXOutgoingRoomKeyRequestManager,
|
||||
private val mMessageEncrypter: MessageEncrypter,
|
||||
private val mEnsureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mSendToDeviceTask: SendToDeviceTask,
|
||||
private val mTaskExecutor: TaskExecutor) {
|
||||
|
||||
fun instantiate(): MXMegolmDecryption {
|
||||
return MXMegolmDecryption(
|
||||
mCredentials,
|
||||
mOlmDevice,
|
||||
mDeviceListManager,
|
||||
mOutgoingRoomKeyRequestManager,
|
||||
mMessageEncrypter,
|
||||
mEnsureOlmSessionsForDevicesAction,
|
||||
mCryptoStore,
|
||||
mSendToDeviceTask,
|
||||
mTaskExecutor)
|
||||
}
|
||||
}
|
|
@ -19,7 +19,6 @@
|
|||
package im.vector.matrix.android.internal.crypto.algorithms.megolm
|
||||
|
||||
import android.text.TextUtils
|
||||
import androidx.annotation.Keep
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
|
@ -27,13 +26,20 @@ import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
|||
import im.vector.matrix.android.api.session.events.model.Content
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toContent
|
||||
import im.vector.matrix.android.internal.crypto.*
|
||||
import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
|
||||
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult
|
||||
import im.vector.matrix.android.internal.crypto.model.MXQueuedEncryption
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
|
@ -42,22 +48,22 @@ import im.vector.matrix.android.internal.util.convertToUTF8
|
|||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
@Keep
|
||||
internal class MXMegolmEncryption : IMXEncrypting {
|
||||
internal class MXMegolmEncryption(
|
||||
// The id of the room we will be sending to.
|
||||
private var mRoomId: String,
|
||||
|
||||
private lateinit var mCrypto: CryptoManager
|
||||
private lateinit var olmDevice: MXOlmDevice
|
||||
private lateinit var mKeysBackup: KeysBackup
|
||||
private lateinit var mDeviceListManager: DeviceListManager
|
||||
private val olmDevice: MXOlmDevice,
|
||||
private val mKeysBackup: KeysBackup,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mDeviceListManager: DeviceListManager,
|
||||
private val mEnsureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
|
||||
private val mCredentials: Credentials,
|
||||
private val mSendToDeviceTask: SendToDeviceTask,
|
||||
private val mTaskExecutor: TaskExecutor,
|
||||
private val mMessageEncrypter: MessageEncrypter,
|
||||
private val mWarnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository
|
||||
) : IMXEncrypting {
|
||||
|
||||
private lateinit var mCredentials: Credentials
|
||||
private lateinit var mSendToDeviceTask: SendToDeviceTask
|
||||
private lateinit var mTaskExecutor: TaskExecutor
|
||||
|
||||
// The id of the room we will be sending to.
|
||||
private lateinit var mRoomId: String
|
||||
|
||||
private var mDeviceId: String? = null
|
||||
|
||||
// OutboundSessionInfo. Null if we haven't yet started setting one up. Note
|
||||
// that even if this is non-null, it may not be ready for use (in which
|
||||
|
@ -69,9 +75,11 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||
|
||||
private val mPendingEncryptions = ArrayList<MXQueuedEncryption>()
|
||||
|
||||
// Default rotation periods
|
||||
// TODO: Make it configurable via parameters
|
||||
// Session rotation periods
|
||||
private var mSessionRotationPeriodMsgs: Int = 0
|
||||
private var mSessionRotationPeriodMs: Int = 0
|
||||
private var mSessionRotationPeriodMsgs: Int = 100
|
||||
private var mSessionRotationPeriodMs: Int = 7 * 24 * 3600 * 1000
|
||||
|
||||
/**
|
||||
* @return a snapshot of the pending encryptions
|
||||
|
@ -87,32 +95,6 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||
return list
|
||||
}
|
||||
|
||||
override fun initWithMatrixSession(crypto: CryptoManager,
|
||||
olmDevice: MXOlmDevice,
|
||||
keysBackup: KeysBackup,
|
||||
deviceListManager: DeviceListManager,
|
||||
credentials: Credentials,
|
||||
sendToDeviceTask: SendToDeviceTask,
|
||||
taskExecutor: TaskExecutor,
|
||||
roomId: String) {
|
||||
mCrypto = crypto
|
||||
this.olmDevice = olmDevice
|
||||
mDeviceListManager = deviceListManager
|
||||
mKeysBackup = keysBackup
|
||||
mCredentials = credentials
|
||||
mSendToDeviceTask = sendToDeviceTask
|
||||
mTaskExecutor = taskExecutor
|
||||
|
||||
mRoomId = roomId
|
||||
mDeviceId = mCredentials.deviceId
|
||||
|
||||
|
||||
// Default rotation periods
|
||||
// TODO: Make it configurable via parameters
|
||||
mSessionRotationPeriodMsgs = 100
|
||||
mSessionRotationPeriodMs = 7 * 24 * 3600 * 1000
|
||||
}
|
||||
|
||||
override fun encryptEventContent(eventContent: Content,
|
||||
eventType: String,
|
||||
userIds: List<String>,
|
||||
|
@ -334,7 +316,7 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||
val t0 = System.currentTimeMillis()
|
||||
Timber.d("## shareUserDevicesKey() : starts")
|
||||
|
||||
mCrypto.ensureOlmSessionsForDevices(devicesByUser, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
|
||||
mEnsureOlmSessionsForDevicesAction.handle(devicesByUser, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXOlmSessionResult>) {
|
||||
Timber.d("## shareUserDevicesKey() : ensureOlmSessionsForDevices succeeds after "
|
||||
+ (System.currentTimeMillis() - t0) + " ms")
|
||||
|
@ -367,7 +349,7 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||
|
||||
Timber.d("## shareUserDevicesKey() : Sharing keys with device $userId:$deviceID")
|
||||
//noinspection ArraysAsListWithZeroOrOneArgument,ArraysAsListWithZeroOrOneArgument
|
||||
contentMap.setObject(mCrypto.encryptMessage(payload, Arrays.asList(sessionResult.mDevice)), userId, deviceID)
|
||||
contentMap.setObject(mMessageEncrypter.encryptMessage(payload, Arrays.asList(sessionResult.mDevice)), userId, deviceID)
|
||||
haveTargets = true
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +435,7 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||
|
||||
// Include our device ID so that recipients can send us a
|
||||
// m.new_device message if they don't have our session key.
|
||||
map["device_id"] = mDeviceId!!
|
||||
map["device_id"] = mCredentials.deviceId!!
|
||||
|
||||
CryptoAsyncHelper.getUiHandler().post { queuedEncryption.mApiCallback?.onSuccess(map.toContent()!!) }
|
||||
|
||||
|
@ -480,7 +462,8 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||
// an m.new_device.
|
||||
mDeviceListManager.downloadKeys(userIds, false, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXDeviceInfo>) {
|
||||
val encryptToVerifiedDevicesOnly = mCrypto.getGlobalBlacklistUnverifiedDevices() || mCrypto.isRoomBlacklistUnverifiedDevices(mRoomId)
|
||||
val encryptToVerifiedDevicesOnly = mCryptoStore.getGlobalBlacklistUnverifiedDevices()
|
||||
|| mCryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(mRoomId)
|
||||
|
||||
val devicesInRoom = MXUsersDevicesMap<MXDeviceInfo>()
|
||||
val unknownDevices = MXUsersDevicesMap<MXDeviceInfo>()
|
||||
|
@ -491,7 +474,7 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||
for (deviceId in deviceIds!!) {
|
||||
val deviceInfo = data.getObject(deviceId, userId)
|
||||
|
||||
if (mCrypto.warnOnUnknownDevices() && deviceInfo!!.isUnknown) {
|
||||
if (mWarnOnUnknownDevicesRepository.warnOnUnknownDevices() && deviceInfo!!.isUnknown) {
|
||||
// The device is not yet known by the user
|
||||
unknownDevices.setObject(deviceInfo, userId, deviceId)
|
||||
continue
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2019 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.algorithms.megolm
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
|
||||
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
|
||||
internal class MXMegolmEncryptionFactory(
|
||||
private val olmDevice: MXOlmDevice,
|
||||
private val mKeysBackup: KeysBackup,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mDeviceListManager: DeviceListManager,
|
||||
private val mEnsureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
|
||||
|
||||
private val mCredentials: Credentials,
|
||||
private val mSendToDeviceTask: SendToDeviceTask,
|
||||
private val mTaskExecutor: TaskExecutor,
|
||||
private val mMessageEncrypter: MessageEncrypter,
|
||||
private val mWarnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository) {
|
||||
|
||||
fun instantiate(roomId: String): MXMegolmEncryption {
|
||||
return MXMegolmEncryption(
|
||||
roomId,
|
||||
|
||||
olmDevice,
|
||||
mKeysBackup,
|
||||
mCryptoStore,
|
||||
mDeviceListManager,
|
||||
mEnsureOlmSessionsForDevicesAction,
|
||||
mCredentials,
|
||||
mSendToDeviceTask,
|
||||
mTaskExecutor,
|
||||
mMessageEncrypter,
|
||||
mWarnOnUnknownDevicesRepository)
|
||||
}
|
||||
}
|
|
@ -18,60 +18,30 @@
|
|||
package im.vector.matrix.android.internal.crypto.algorithms.olm
|
||||
|
||||
import android.text.TextUtils
|
||||
import androidx.annotation.Keep
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
||||
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.*
|
||||
import im.vector.matrix.android.internal.crypto.MXDecryptionException
|
||||
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.IMXDecrypting
|
||||
import im.vector.matrix.android.internal.crypto.model.event.OlmEventContent
|
||||
import im.vector.matrix.android.internal.crypto.model.event.OlmPayloadContent
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.util.convertFromUTF8
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* An interface for encrypting data
|
||||
*/
|
||||
@Keep
|
||||
internal class MXOlmDecryption : IMXDecrypting {
|
||||
internal class MXOlmDecryption(
|
||||
// The olm device interface
|
||||
private val mOlmDevice: MXOlmDevice,
|
||||
|
||||
// The olm device interface
|
||||
private lateinit var mOlmDevice: MXOlmDevice
|
||||
|
||||
// the matrix credentials
|
||||
private lateinit var mCredentials: Credentials
|
||||
|
||||
private lateinit var mCrypto: CryptoManager
|
||||
private lateinit var mCryptoStore: IMXCryptoStore
|
||||
private lateinit var mSendToDeviceTask: SendToDeviceTask
|
||||
private lateinit var mTaskExecutor: TaskExecutor
|
||||
|
||||
override fun initWithMatrixSession(credentials: Credentials,
|
||||
crypto: CryptoManager,
|
||||
olmDevice: MXOlmDevice,
|
||||
deviceListManager: DeviceListManager,
|
||||
sendToDeviceTask: SendToDeviceTask,
|
||||
taskExecutor: TaskExecutor) {
|
||||
mCredentials = credentials
|
||||
mCrypto = crypto
|
||||
mOlmDevice = olmDevice
|
||||
mSendToDeviceTask = sendToDeviceTask
|
||||
mTaskExecutor = taskExecutor
|
||||
}
|
||||
// the matrix credentials
|
||||
private val mCredentials: Credentials)
|
||||
: IMXDecrypting {
|
||||
|
||||
@Throws(MXDecryptionException::class)
|
||||
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? {
|
||||
// sanity check
|
||||
if (null == event) {
|
||||
Timber.e("## decryptEvent() : null event")
|
||||
return null
|
||||
}
|
||||
|
||||
val olmEventContent = event.content.toModel<OlmEventContent>()!!
|
||||
|
||||
if (null == olmEventContent.ciphertext) {
|
||||
|
@ -89,7 +59,7 @@ internal class MXOlmDecryption : IMXDecrypting {
|
|||
|
||||
// The message for myUser
|
||||
val message = olmEventContent.ciphertext!![mOlmDevice.deviceCurve25519Key] as Map<String, Any>
|
||||
val payloadString = decryptMessage(message, olmEventContent.senderKey)
|
||||
val payloadString = decryptMessage(message, olmEventContent.senderKey!!)
|
||||
|
||||
if (null == payloadString) {
|
||||
Timber.e("## decryptEvent() Failed to decrypt Olm event (id= " + event.eventId + " ) from " + olmEventContent.senderKey)
|
||||
|
@ -164,27 +134,13 @@ internal class MXOlmDecryption : IMXDecrypting {
|
|||
}
|
||||
|
||||
val result = MXEventDecryptionResult()
|
||||
// TODO result.mClearEvent = payload
|
||||
// FIXME result.mClearEvent = payload
|
||||
result.mSenderCurve25519Key = olmEventContent.senderKey
|
||||
result.mClaimedEd25519Key = olmPayloadContent.keys!!.get("ed25519")
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun onRoomKeyEvent(event: Event) {
|
||||
// No impact for olm
|
||||
}
|
||||
|
||||
override fun onNewSession(senderKey: String, sessionId: String) {
|
||||
// No impact for olm
|
||||
}
|
||||
|
||||
override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shareKeysWithDevice(request: IncomingRoomKeyRequest) {}
|
||||
|
||||
/**
|
||||
* Attempt to decrypt an Olm message.
|
||||
*
|
||||
|
@ -192,8 +148,8 @@ internal class MXOlmDecryption : IMXDecrypting {
|
|||
* @param message message object, with 'type' and 'body' fields.
|
||||
* @return payload, if decrypted successfully.
|
||||
*/
|
||||
private fun decryptMessage(message: Map<String, Any>, theirDeviceIdentityKey: String?): String? {
|
||||
val sessionIdsSet = mOlmDevice.getSessionIds(theirDeviceIdentityKey!!)
|
||||
private fun decryptMessage(message: Map<String, Any>, theirDeviceIdentityKey: String): String? {
|
||||
val sessionIdsSet = mOlmDevice.getSessionIds(theirDeviceIdentityKey)
|
||||
|
||||
val sessionIds: List<String>
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2019 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.algorithms.olm
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
|
||||
internal class MXOlmDecryptionFactory(private val mOlmDevice: MXOlmDevice,
|
||||
private val mCredentials: Credentials) {
|
||||
|
||||
fun instantiate(): MXOlmDecryption {
|
||||
return MXOlmDecryption(
|
||||
mOlmDevice,
|
||||
mCredentials)
|
||||
}
|
||||
}
|
|
@ -19,49 +19,30 @@
|
|||
package im.vector.matrix.android.internal.crypto.algorithms.olm
|
||||
|
||||
import android.text.TextUtils
|
||||
import androidx.annotation.Keep
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.events.model.Content
|
||||
import im.vector.matrix.android.api.session.events.model.toContent
|
||||
import im.vector.matrix.android.internal.crypto.CryptoManager
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForUsersAction
|
||||
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import java.util.*
|
||||
|
||||
@Keep
|
||||
internal class MXOlmEncryption : IMXEncrypting {
|
||||
private lateinit var mCrypto: CryptoManager
|
||||
private lateinit var mOlmDevice: MXOlmDevice
|
||||
private lateinit var mDeviceListManager: DeviceListManager
|
||||
internal class MXOlmEncryption(
|
||||
private var mRoomId: String,
|
||||
|
||||
private lateinit var mCredentials: Credentials
|
||||
private lateinit var mSendToDeviceTask: SendToDeviceTask
|
||||
private lateinit var mTaskExecutor: TaskExecutor
|
||||
private val mOlmDevice: MXOlmDevice,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mMessageEncrypter: MessageEncrypter,
|
||||
private val mDeviceListManager: DeviceListManager,
|
||||
private val mEnsureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction)
|
||||
: IMXEncrypting {
|
||||
|
||||
private lateinit var mRoomId: String
|
||||
|
||||
override fun initWithMatrixSession(crypto: CryptoManager,
|
||||
olmDevice: MXOlmDevice,
|
||||
keysBackup: KeysBackup,
|
||||
deviceListManager: DeviceListManager,
|
||||
credentials: Credentials,
|
||||
sendToDeviceTask: SendToDeviceTask,
|
||||
taskExecutor: TaskExecutor,
|
||||
roomId: String) {
|
||||
mCrypto = crypto
|
||||
mOlmDevice = olmDevice
|
||||
mDeviceListManager = deviceListManager
|
||||
|
||||
mRoomId = roomId
|
||||
}
|
||||
|
||||
override fun encryptEventContent(eventContent: Content,
|
||||
eventType: String,
|
||||
|
@ -75,24 +56,22 @@ internal class MXOlmEncryption : IMXEncrypting {
|
|||
val deviceInfos = ArrayList<MXDeviceInfo>()
|
||||
|
||||
for (userId in userIds) {
|
||||
val devices = mCrypto.getUserDevices(userId)
|
||||
val devices = mCryptoStore.getUserDevices(userId)?.values ?: emptyList()
|
||||
|
||||
if (null != devices) {
|
||||
for (device in devices) {
|
||||
val key = device.identityKey()
|
||||
for (device in devices) {
|
||||
val key = device.identityKey()
|
||||
|
||||
if (TextUtils.equals(key, mOlmDevice.deviceCurve25519Key)) {
|
||||
// Don't bother setting up session to ourself
|
||||
continue
|
||||
}
|
||||
|
||||
if (device.isBlocked) {
|
||||
// Don't bother setting up sessions with blocked users
|
||||
continue
|
||||
}
|
||||
|
||||
deviceInfos.add(device)
|
||||
if (TextUtils.equals(key, mOlmDevice.deviceCurve25519Key)) {
|
||||
// Don't bother setting up session to ourself
|
||||
continue
|
||||
}
|
||||
|
||||
if (device.isBlocked) {
|
||||
// Don't bother setting up sessions with blocked users
|
||||
continue
|
||||
}
|
||||
|
||||
deviceInfos.add(device)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +80,7 @@ internal class MXOlmEncryption : IMXEncrypting {
|
|||
messageMap["type"] = eventType
|
||||
messageMap["content"] = eventContent
|
||||
|
||||
mCrypto.encryptMessage(messageMap, deviceInfos)
|
||||
mMessageEncrypter.encryptMessage(messageMap, deviceInfos)
|
||||
|
||||
callback.onSuccess(messageMap.toContent()!!)
|
||||
}
|
||||
|
@ -118,7 +97,7 @@ internal class MXOlmEncryption : IMXEncrypting {
|
|||
mDeviceListManager.downloadKeys(users, false, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXDeviceInfo>) {
|
||||
mCrypto.ensureOlmSessionsForUsers(users, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
|
||||
mEnsureOlmSessionsForUsersAction.handle(users, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXOlmSessionResult>) {
|
||||
callback?.onSuccess(Unit)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2019 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.algorithms.olm
|
||||
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForUsersAction
|
||||
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
|
||||
internal class MXOlmEncryptionFactory(private val mOlmDevice: MXOlmDevice,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mMessageEncrypter: MessageEncrypter,
|
||||
private val mDeviceListManager: DeviceListManager,
|
||||
private val mEnsureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction) {
|
||||
|
||||
fun instantiate(roomId: String): MXOlmEncryption {
|
||||
return MXOlmEncryption(
|
||||
roomId,
|
||||
|
||||
mOlmDevice,
|
||||
mCryptoStore,
|
||||
mMessageEncrypter,
|
||||
mDeviceListManager,
|
||||
mEnsureOlmSessionsForUsersAction)
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ import im.vector.matrix.android.api.listeners.StepProgressListener
|
|||
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService
|
||||
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
|
||||
import im.vector.matrix.android.internal.crypto.*
|
||||
import im.vector.matrix.android.internal.crypto.actions.MegolmSessionDataImporter
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrust
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrustSignature
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupAuthData
|
||||
|
@ -67,6 +68,8 @@ internal class KeysBackup(
|
|||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mOlmDevice: MXOlmDevice,
|
||||
private val mObjectSigner: ObjectSigner,
|
||||
// Actions
|
||||
private val mMegolmSessionDataImporter: MegolmSessionDataImporter,
|
||||
// Tasks
|
||||
private val mCreateKeysBackupVersionTask: CreateKeysBackupVersionTask,
|
||||
private val mDeleteBackupTask: DeleteBackupTask,
|
||||
|
@ -115,9 +118,6 @@ internal class KeysBackup(
|
|||
override val currentBackupVersion: String?
|
||||
get() = mKeysBackupVersion?.version
|
||||
|
||||
// Internal listener
|
||||
private lateinit var mKeysBackupCryptoListener: KeysBackupCryptoListener
|
||||
|
||||
override fun addListener(listener: KeysBackupService.KeysBackupStateListener) {
|
||||
mKeysBackupStateManager.addListener(listener)
|
||||
}
|
||||
|
@ -749,7 +749,20 @@ internal class KeysBackup(
|
|||
null
|
||||
}
|
||||
|
||||
mKeysBackupCryptoListener.importMegolmSessionsData(sessionsData, backUp, progressListener, callback)
|
||||
mMegolmSessionDataImporter.handle(sessionsData, !backUp, progressListener, object : MatrixCallback<ImportRoomKeysResult> {
|
||||
override fun onSuccess(data: ImportRoomKeysResult) {
|
||||
// Do not back up the key if it comes from a backup recovery
|
||||
if (backUp) {
|
||||
maybeBackupKeys()
|
||||
}
|
||||
|
||||
callback.onSuccess(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
callback.onFailure(failure)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
|
@ -887,7 +900,7 @@ internal class KeysBackup(
|
|||
/**
|
||||
* Do a backup if there are new keys, with a delay
|
||||
*/
|
||||
override fun maybeBackupKeys() {
|
||||
fun maybeBackupKeys() {
|
||||
when {
|
||||
isStucked -> {
|
||||
// If not already done, or in error case, check for a valid backup version on the homeserver.
|
||||
|
@ -1388,7 +1401,7 @@ internal class KeysBackup(
|
|||
@WorkerThread
|
||||
fun encryptGroupSession(session: MXOlmInboundGroupSession2): KeyBackupData {
|
||||
// Gather information for each key
|
||||
val device = mKeysBackupCryptoListener.deviceWithIdentityKey(session.mSenderKey!!, MXCRYPTO_ALGORITHM_MEGOLM)
|
||||
val device = mCryptoStore.deviceWithIdentityKey(session.mSenderKey!!)
|
||||
|
||||
// Build the m.megolm_backup.v1.curve25519-aes-sha2 data as defined at
|
||||
// https://github.com/uhoreg/matrix-doc/blob/e2e_backup/proposals/1219-storing-megolm-keys-serverside.md#mmegolm_backupv1curve25519-aes-sha2-key-format
|
||||
|
@ -1479,21 +1492,6 @@ internal class KeysBackup(
|
|||
private const val KEY_BACKUP_SEND_KEYS_MAX_COUNT = 100
|
||||
}
|
||||
|
||||
|
||||
fun setCryptoInternalListener(listener: KeysBackupCryptoListener) {
|
||||
mKeysBackupCryptoListener = listener
|
||||
}
|
||||
|
||||
interface KeysBackupCryptoListener {
|
||||
fun importMegolmSessionsData(megolmSessionsData: List<MegolmSessionData>,
|
||||
backUpKeys: Boolean,
|
||||
progressListener: ProgressListener?,
|
||||
callback: MatrixCallback<ImportRoomKeysResult>)
|
||||
|
||||
fun deviceWithIdentityKey(senderKey: String, algorithm: String): MXDeviceInfo?
|
||||
}
|
||||
|
||||
|
||||
/* ==========================================================================================
|
||||
* DEBUG INFO
|
||||
* ========================================================================================== */
|
||||
|
|
|
@ -22,7 +22,7 @@ import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
|
|||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
internal class KeysBackupStateManager(val uiHandler: Handler) {
|
||||
internal class KeysBackupStateManager(private val uiHandler: Handler) {
|
||||
|
||||
private val mListeners = ArrayList<KeysBackupService.KeysBackupStateListener>()
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2019 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.repository
|
||||
|
||||
internal class WarnOnUnknownDeviceRepository {
|
||||
|
||||
// Warn the user if some new devices are detected while encrypting a message.
|
||||
private var mWarnOnUnknownDevices = true
|
||||
|
||||
/**
|
||||
* Tells if the encryption must fail if some unknown devices are detected.
|
||||
*
|
||||
* @return true to warn when some unknown devices are detected.
|
||||
*/
|
||||
fun warnOnUnknownDevices() = mWarnOnUnknownDevices
|
||||
|
||||
/**
|
||||
* Update the warn status when some unknown devices are detected.
|
||||
*
|
||||
* @param warn true to warn when some unknown devices are detected.
|
||||
*/
|
||||
fun setWarnOnUnknownDevices(warn: Boolean) {
|
||||
mWarnOnUnknownDevices = warn
|
||||
}
|
||||
|
||||
}
|
|
@ -201,7 +201,7 @@ internal class RealmCryptoStore(private val enableFileEncryption: Boolean = fals
|
|||
.let { u ->
|
||||
// Add the devices
|
||||
// Ensure all other devices are deleted
|
||||
u.devices.deleteAllFromRealm() // Device is null!!
|
||||
u.devices.deleteAllFromRealm()
|
||||
|
||||
u.devices.addAll(
|
||||
devices.map {
|
||||
|
|
|
@ -29,6 +29,7 @@ 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.CryptoAsyncHelper
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
import im.vector.matrix.android.internal.crypto.MyDeviceInfoHolder
|
||||
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
|
@ -48,6 +49,7 @@ import kotlin.collections.HashMap
|
|||
*/
|
||||
internal class DefaultSasVerificationService(private val mCredentials: Credentials,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mMyDeviceInfoHolder: MyDeviceInfoHolder,
|
||||
private val deviceListManager: DeviceListManager,
|
||||
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
||||
private val mSendToDeviceTask: SendToDeviceTask,
|
||||
|
@ -86,10 +88,6 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||
}
|
||||
}
|
||||
|
||||
// Internal listener
|
||||
private lateinit var mCryptoListener: SasCryptoListener
|
||||
|
||||
|
||||
private var listeners = ArrayList<SasVerificationService.SasVerificationListener>()
|
||||
|
||||
override fun addListener(listener: SasVerificationService.SasVerificationListener) {
|
||||
|
@ -188,11 +186,12 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||
Timber.d("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}")
|
||||
val tx = IncomingSASVerificationTransaction(
|
||||
this,
|
||||
setDeviceVerificationAction,
|
||||
mCredentials,
|
||||
mCryptoStore,
|
||||
mSendToDeviceTask,
|
||||
mTaskExecutor,
|
||||
mCryptoListener.getMyDevice().fingerprint()!!,
|
||||
mMyDeviceInfoHolder.myDevice.fingerprint()!!,
|
||||
startReq.transactionID!!,
|
||||
otherUserId)
|
||||
addTransaction(tx)
|
||||
|
@ -362,11 +361,12 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||
if (KeyVerificationStart.VERIF_METHOD_SAS == method) {
|
||||
val tx = OutgoingSASVerificationRequest(
|
||||
this,
|
||||
setDeviceVerificationAction,
|
||||
mCredentials,
|
||||
mCryptoStore,
|
||||
mSendToDeviceTask,
|
||||
mTaskExecutor,
|
||||
mCryptoListener.getMyDevice().fingerprint()!!,
|
||||
mMyDeviceInfoHolder.myDevice.fingerprint()!!,
|
||||
txID,
|
||||
userId,
|
||||
deviceID)
|
||||
|
@ -424,12 +424,4 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||
})
|
||||
.executeBy(mTaskExecutor)
|
||||
}
|
||||
|
||||
fun setCryptoInternalListener(listener: SasCryptoListener) {
|
||||
mCryptoListener = listener
|
||||
}
|
||||
|
||||
interface SasCryptoListener {
|
||||
fun getMyDevice(): MXDeviceInfo
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.crypto.sas.SasMode
|
|||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
|
||||
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationKey
|
||||
|
@ -35,6 +36,7 @@ import timber.log.Timber
|
|||
|
||||
internal class IncomingSASVerificationTransaction(
|
||||
private val mSasVerificationService: DefaultSasVerificationService,
|
||||
private val mSetDeviceVerificationAction: SetDeviceVerificationAction,
|
||||
private val mCredentials: Credentials,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mSendToDeviceTask: SendToDeviceTask,
|
||||
|
@ -44,6 +46,7 @@ internal class IncomingSASVerificationTransaction(
|
|||
otherUserID: String)
|
||||
: SASVerificationTransaction(
|
||||
mSasVerificationService,
|
||||
mSetDeviceVerificationAction,
|
||||
mCredentials,
|
||||
mCryptoStore,
|
||||
mSendToDeviceTask,
|
||||
|
|
|
@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
|||
import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest
|
||||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
|
||||
|
@ -33,6 +34,7 @@ import timber.log.Timber
|
|||
|
||||
internal class OutgoingSASVerificationRequest(
|
||||
private val mSasVerificationService: DefaultSasVerificationService,
|
||||
private val mSetDeviceVerificationAction: SetDeviceVerificationAction,
|
||||
private val mCredentials: Credentials,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mSendToDeviceTask: SendToDeviceTask,
|
||||
|
@ -43,6 +45,7 @@ internal class OutgoingSASVerificationRequest(
|
|||
otherDeviceId: String)
|
||||
: SASVerificationTransaction(
|
||||
mSasVerificationService,
|
||||
mSetDeviceVerificationAction,
|
||||
mCredentials,
|
||||
mCryptoStore,
|
||||
mSendToDeviceTask,
|
||||
|
|
|
@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.crypto.sas.SasMode
|
|||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
|
||||
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.MXKey
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
|
@ -42,6 +43,7 @@ import kotlin.properties.Delegates
|
|||
*/
|
||||
internal abstract class SASVerificationTransaction(
|
||||
private val mSasVerificationService: DefaultSasVerificationService,
|
||||
private val mSetDeviceVerificationAction: SetDeviceVerificationAction,
|
||||
private val mCredentials: Credentials,
|
||||
private val mCryptoStore: IMXCryptoStore,
|
||||
private val mSendToDeviceTask: SendToDeviceTask,
|
||||
|
@ -245,7 +247,7 @@ internal abstract class SASVerificationTransaction(
|
|||
}
|
||||
|
||||
private fun setDeviceVerified(deviceId: String, userId: String) {
|
||||
mSasVerificationService.setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED,
|
||||
mSetDeviceVerificationAction.handle(MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED,
|
||||
deviceId,
|
||||
userId)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
|||
import im.vector.riotredesign.core.epoxy.EmptyItem_
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||
import timber.log.Timber
|
||||
|
||||
class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
||||
private val roomNameItemFactory: RoomNameItemFactory,
|
||||
|
@ -59,6 +60,8 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
|||
else -> null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error")
|
||||
|
||||
defaultItemFactory.create(event, e)
|
||||
}
|
||||
return (computedModel ?: EmptyItem_())
|
||||
|
|
Loading…
Reference in a new issue