forked from GitHub-Mirror/riotX-android
Split again
This commit is contained in:
parent
e0e41d9e5c
commit
532a028e41
@ -34,7 +34,6 @@ interface KeysBackupService {
|
|||||||
fun backupAllGroupSessions(progressListener: ProgressListener?, callback: MatrixCallback<Unit>?)
|
fun backupAllGroupSessions(progressListener: ProgressListener?, callback: MatrixCallback<Unit>?)
|
||||||
fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult, callback: MatrixCallback<KeysBackupVersionTrust>)
|
fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult, callback: MatrixCallback<KeysBackupVersionTrust>)
|
||||||
fun getBackupProgress(progressListener: ProgressListener)
|
fun getBackupProgress(progressListener: ProgressListener)
|
||||||
fun maybeBackupKeys()
|
|
||||||
fun getVersion(version: String, callback: MatrixCallback<KeysVersionResult?>)
|
fun getVersion(version: String, callback: MatrixCallback<KeysVersionResult?>)
|
||||||
fun forceUsingLastVersion(callback: MatrixCallback<Boolean>)
|
fun forceUsingLastVersion(callback: MatrixCallback<Boolean>)
|
||||||
fun checkAndStartKeysBackup()
|
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.Room
|
||||||
import im.vector.matrix.android.api.session.room.RoomService
|
import im.vector.matrix.android.api.session.room.RoomService
|
||||||
import im.vector.matrix.android.api.session.room.model.Membership
|
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.actions.SetDeviceVerificationAction
|
||||||
import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting
|
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.keysbackup.KeysBackup
|
||||||
import im.vector.matrix.android.internal.crypto.model.*
|
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.event.RoomKeyContent
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
|
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.KeysUploadResponse
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
|
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.store.IMXCryptoStore
|
||||||
import im.vector.matrix.android.internal.crypto.tasks.*
|
import im.vector.matrix.android.internal.crypto.tasks.*
|
||||||
import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificationService
|
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.session.sync.model.SyncResponse
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
import im.vector.matrix.android.internal.task.configureWith
|
import im.vector.matrix.android.internal.task.configureWith
|
||||||
import im.vector.matrix.android.internal.util.convertToUTF8
|
|
||||||
import org.matrix.olm.OlmManager
|
import org.matrix.olm.OlmManager
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -71,11 +74,13 @@ import java.util.*
|
|||||||
internal class CryptoManager(
|
internal class CryptoManager(
|
||||||
// The credentials,
|
// The credentials,
|
||||||
private val mCredentials: Credentials,
|
private val mCredentials: Credentials,
|
||||||
|
private val mMyDeviceInfoHolder: MyDeviceInfoHolder,
|
||||||
// the crypto store
|
// the crypto store
|
||||||
private val mCryptoStore: IMXCryptoStore,
|
private val mCryptoStore: IMXCryptoStore,
|
||||||
// Olm device
|
// Olm device
|
||||||
private val mOlmDevice: MXOlmDevice,
|
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
|
// Device list manager
|
||||||
private val deviceListManager: DeviceListManager,
|
private val deviceListManager: DeviceListManager,
|
||||||
// The key backup service.
|
// The key backup service.
|
||||||
@ -98,6 +103,12 @@ internal class CryptoManager(
|
|||||||
private val mOlmManager: OlmManager,
|
private val mOlmManager: OlmManager,
|
||||||
// Actions
|
// Actions
|
||||||
private val mSetDeviceVerificationAction: SetDeviceVerificationAction,
|
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
|
// Tasks
|
||||||
private val mClaimOneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask,
|
private val mClaimOneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask,
|
||||||
private val mDeleteDeviceTask: DeleteDeviceTask,
|
private val mDeleteDeviceTask: DeleteDeviceTask,
|
||||||
@ -108,19 +119,11 @@ internal class CryptoManager(
|
|||||||
private val mUploadKeysTask: UploadKeysTask,
|
private val mUploadKeysTask: UploadKeysTask,
|
||||||
// TaskExecutor
|
// TaskExecutor
|
||||||
private val mTaskExecutor: TaskExecutor
|
private val mTaskExecutor: TaskExecutor
|
||||||
) : KeysBackup.KeysBackupCryptoListener,
|
) : CryptoService {
|
||||||
DefaultSasVerificationService.SasCryptoListener,
|
|
||||||
CryptoService {
|
|
||||||
|
|
||||||
// MXEncrypting instance for each room.
|
// MXEncrypting instance for each room.
|
||||||
private val mRoomEncryptors: MutableMap<String, IMXEncrypting> = HashMap()
|
private val mRoomEncryptors: MutableMap<String, IMXEncrypting> = HashMap()
|
||||||
|
|
||||||
// Our device keys
|
|
||||||
/**
|
|
||||||
* @return my device info
|
|
||||||
*/
|
|
||||||
private val myDevice: MXDeviceInfo
|
|
||||||
|
|
||||||
// the encryption is starting
|
// the encryption is starting
|
||||||
private var mIsStarting: Boolean = false
|
private var mIsStarting: Boolean = false
|
||||||
|
|
||||||
@ -148,84 +151,6 @@ internal class CryptoManager(
|
|||||||
// initialization callbacks
|
// initialization callbacks
|
||||||
private val mInitializationCallbacks = ArrayList<MatrixCallback<Unit>>()
|
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>) {
|
override fun setDeviceName(deviceId: String, deviceName: String, callback: MatrixCallback<Unit>) {
|
||||||
mSetDeviceNameTask
|
mSetDeviceNameTask
|
||||||
.configureWith(SetDeviceNameTask.Params(deviceId, deviceName))
|
.configureWith(SetDeviceNameTask.Params(deviceId, deviceName))
|
||||||
@ -245,7 +170,7 @@ internal class CryptoManager(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getMyDevice(): MXDeviceInfo {
|
override fun getMyDevice(): MXDeviceInfo {
|
||||||
return myDevice
|
return mMyDeviceInfoHolder.myDevice
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDevicesList(callback: MatrixCallback<DevicesListResponse>) {
|
override fun getDevicesList(callback: MatrixCallback<DevicesListResponse>) {
|
||||||
@ -462,7 +387,6 @@ internal class CryptoManager(
|
|||||||
*
|
*
|
||||||
* @param userId the user id
|
* @param userId the user id
|
||||||
* @param deviceId the device id
|
* @param deviceId the device id
|
||||||
* @param callback the asynchronous callback
|
|
||||||
*/
|
*/
|
||||||
override fun getDeviceInfo(userId: String, deviceId: String?): MXDeviceInfo? {
|
override fun getDeviceInfo(userId: String, deviceId: String?): MXDeviceInfo? {
|
||||||
return if (!TextUtils.isEmpty(userId) && !TextUtils.isEmpty(deviceId)) {
|
return if (!TextUtils.isEmpty(userId) && !TextUtils.isEmpty(deviceId)) {
|
||||||
@ -529,7 +453,6 @@ internal class CryptoManager(
|
|||||||
* @param verificationStatus the new verification status
|
* @param verificationStatus the new verification status
|
||||||
* @param deviceId the unique identifier for the device.
|
* @param deviceId the unique identifier for the device.
|
||||||
* @param userId the owner of the device
|
* @param userId the owner of the device
|
||||||
* @param callback the asynchronous callback
|
|
||||||
*/
|
*/
|
||||||
override fun setDeviceVerification(verificationStatus: Int, deviceId: String, userId: String) {
|
override fun setDeviceVerification(verificationStatus: Int, deviceId: String, userId: String) {
|
||||||
mSetDeviceVerificationAction.handle(verificationStatus, deviceId, userId)
|
mSetDeviceVerificationAction.handle(verificationStatus, deviceId, userId)
|
||||||
@ -555,34 +478,20 @@ internal class CryptoManager(
|
|||||||
return false
|
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!!)
|
Timber.e("## setEncryptionInRoom() : Unable to encrypt with " + algorithm!!)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
mCryptoStore.storeRoomAlgorithm(roomId, algorithm!!)
|
mCryptoStore.storeRoomAlgorithm(roomId, algorithm!!)
|
||||||
|
|
||||||
val alg: IMXEncrypting
|
val alg: IMXEncrypting = when (algorithm) {
|
||||||
|
MXCRYPTO_ALGORITHM_MEGOLM -> mMXMegolmEncryptionFactory.instantiate(roomId)
|
||||||
try {
|
else -> mMXOlmEncryptionFactory.instantiate(roomId)
|
||||||
val ctor = encryptingClass.constructors[0]
|
|
||||||
alg = ctor.newInstance() as IMXEncrypting
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "## setEncryptionInRoom() : fail to load the class")
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
alg.initWithMatrixSession(this,
|
|
||||||
mOlmDevice,
|
|
||||||
mKeysBackup,
|
|
||||||
deviceListManager,
|
|
||||||
mCredentials,
|
|
||||||
mSendToDeviceTask,
|
|
||||||
mTaskExecutor,
|
|
||||||
roomId)
|
|
||||||
|
|
||||||
synchronized(mRoomEncryptors) {
|
synchronized(mRoomEncryptors) {
|
||||||
mRoomEncryptors.put(roomId, alg)
|
mRoomEncryptors.put(roomId, alg)
|
||||||
}
|
}
|
||||||
@ -641,44 +550,7 @@ internal class CryptoManager(
|
|||||||
return if (null != map) ArrayList(map.values) else ArrayList()
|
return if (null != map) ArrayList(map.values) else ArrayList()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// TODO Remove ?
|
||||||
* 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to make sure we have established olm sessions for the given devices.
|
* Try to make sure we have established olm sessions for the given devices.
|
||||||
* It must be called in getCryptoHandler() thread.
|
* It must be called in getCryptoHandler() thread.
|
||||||
@ -689,150 +561,9 @@ internal class CryptoManager(
|
|||||||
*/
|
*/
|
||||||
fun ensureOlmSessionsForDevices(devicesByUser: Map<String, List<MXDeviceInfo>>,
|
fun ensureOlmSessionsForDevices(devicesByUser: Map<String, List<MXDeviceInfo>>,
|
||||||
callback: MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>>?) {
|
callback: MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>>?) {
|
||||||
val devicesWithoutSession = ArrayList<MXDeviceInfo>()
|
mEnsureOlmSessionsForDevicesAction.handle(devicesByUser, callback)
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt an event content according to the configuration of the room.
|
* 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.
|
// 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) {
|
val userIds = if (encryptForInvitedMembers) {
|
||||||
room.getActiveRoomMemberIds()
|
room.getActiveRoomMemberIds()
|
||||||
@ -939,7 +670,7 @@ internal class CryptoManager(
|
|||||||
val exceptions = ArrayList<MXDecryptionException>()
|
val exceptions = ArrayList<MXDecryptionException>()
|
||||||
|
|
||||||
var result: MXEventDecryptionResult? = null
|
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) {
|
if (null == alg) {
|
||||||
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, eventContent["algorithm"] as String)
|
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) {
|
if (null != result) {
|
||||||
results.add(result)
|
results.add(result) // TODO simplify
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -976,72 +707,6 @@ internal class CryptoManager(
|
|||||||
mOlmDevice.resetReplayAttackCheckInTimeline(timelineId)
|
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
|
* Handle the 'toDevice' event
|
||||||
*
|
*
|
||||||
@ -1061,13 +726,7 @@ internal class CryptoManager(
|
|||||||
*
|
*
|
||||||
* @param event the key event.
|
* @param event the key event.
|
||||||
*/
|
*/
|
||||||
private fun onRoomKeyEvent(event: Event?) {
|
private fun onRoomKeyEvent(event: Event) {
|
||||||
// sanity check
|
|
||||||
if (null == event) {
|
|
||||||
Timber.e("## onRoomKeyEvent() : null event")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val roomKeyContent = event.content.toModel<RoomKeyContent>()!!
|
val roomKeyContent = event.content.toModel<RoomKeyContent>()!!
|
||||||
|
|
||||||
if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.algorithm)) {
|
if (TextUtils.isEmpty(roomKeyContent.roomId) || TextUtils.isEmpty(roomKeyContent.algorithm)) {
|
||||||
@ -1075,14 +734,14 @@ internal class CryptoManager(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(this, roomKeyContent.roomId, roomKeyContent.algorithm)
|
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(roomKeyContent.roomId, roomKeyContent.algorithm)
|
||||||
|
|
||||||
if (null == alg) {
|
if (null == alg) {
|
||||||
Timber.e("## onRoomKeyEvent() : Unable to handle keys for " + roomKeyContent.algorithm!!)
|
Timber.e("## onRoomKeyEvent() : Unable to handle keys for " + roomKeyContent.algorithm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
alg.onRoomKeyEvent(event)
|
alg.onRoomKeyEvent(event, mKeysBackup)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1097,7 +756,7 @@ internal class CryptoManager(
|
|||||||
val room = mRoomService.getRoom(roomId)!!
|
val room = mRoomService.getRoom(roomId)!!
|
||||||
|
|
||||||
// Check whether the event content must be encrypted for the invited members.
|
// 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) {
|
val userIds = if (encryptForInvitedMembers) {
|
||||||
room.getActiveRoomMemberIds()
|
room.getActiveRoomMemberIds()
|
||||||
@ -1138,7 +797,7 @@ internal class CryptoManager(
|
|||||||
deviceListManager.startTrackingDeviceList(Arrays.asList(userId))
|
deviceListManager.startTrackingDeviceList(Arrays.asList(userId))
|
||||||
} else if (membership == Membership.INVITE
|
} else if (membership == Membership.INVITE
|
||||||
&& room.shouldEncryptForInvitedMembers()
|
&& room.shouldEncryptForInvitedMembers()
|
||||||
&& mCryptoConfig!!.mEnableEncryptionForInvitedMembers) {
|
&& mCryptoConfig.mEnableEncryptionForInvitedMembers) {
|
||||||
// track the deviceList for this invited user.
|
// track the deviceList for this invited user.
|
||||||
// Caution: there's a big edge case here in that federated servers do not
|
// 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.
|
// 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>) {
|
private fun uploadDeviceKeys(callback: MatrixCallback<KeysUploadResponse>) {
|
||||||
// Prepare the device keys data to send
|
// Prepare the device keys data to send
|
||||||
// Sign it
|
// 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
|
// For now, we set the device id explicitly, as we may not be using the
|
||||||
// same one as used in login.
|
// same one as used in login.
|
||||||
mUploadKeysTask
|
mUploadKeysTask
|
||||||
.configureWith(UploadKeysTask.Params(myDevice.toDeviceKeys(), null, myDevice.deviceId))
|
.configureWith(UploadKeysTask.Params(getMyDevice().toDeviceKeys(), null, getMyDevice().deviceId))
|
||||||
.dispatchTo(callback)
|
.dispatchTo(callback)
|
||||||
.executeBy(mTaskExecutor)
|
.executeBy(mTaskExecutor)
|
||||||
}
|
}
|
||||||
@ -1264,98 +923,7 @@ internal class CryptoManager(
|
|||||||
|
|
||||||
Timber.d("## importRoomKeys : JSON parsing " + (t2 - t1) + " ms")
|
Timber.d("## importRoomKeys : JSON parsing " + (t2 - t1) + " ms")
|
||||||
|
|
||||||
importMegolmSessionsData(importedSessions, true, progressListener, callback)
|
mMegolmSessionDataImporter.handle(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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1364,7 +932,7 @@ internal class CryptoManager(
|
|||||||
* @param warn true to warn when some unknown devices are detected.
|
* @param warn true to warn when some unknown devices are detected.
|
||||||
*/
|
*/
|
||||||
override fun setWarnOnUnknownDevices(warn: Boolean) {
|
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.
|
* Add this room to the ones which don't encrypt messages to unverified devices.
|
||||||
*
|
*
|
||||||
* @param roomId the room id
|
* @param roomId the room id
|
||||||
* @param callback the asynchronous callback
|
|
||||||
*/
|
*/
|
||||||
override fun setRoomBlacklistUnverifiedDevices(roomId: String) {
|
override fun setRoomBlacklistUnverifiedDevices(roomId: String) {
|
||||||
setRoomBlacklistUnverifiedDevices(roomId, true)
|
setRoomBlacklistUnverifiedDevices(roomId, true)
|
||||||
@ -1478,22 +1045,12 @@ internal class CryptoManager(
|
|||||||
* Remove this room to the ones which don't encrypt messages to unverified devices.
|
* Remove this room to the ones which don't encrypt messages to unverified devices.
|
||||||
*
|
*
|
||||||
* @param roomId the room id
|
* @param roomId the room id
|
||||||
* @param callback the asynchronous callback
|
|
||||||
*/
|
*/
|
||||||
override fun setRoomUnBlacklistUnverifiedDevices(roomId: String) {
|
override fun setRoomUnBlacklistUnverifiedDevices(roomId: String) {
|
||||||
setRoomBlacklistUnverifiedDevices(roomId, false)
|
setRoomBlacklistUnverifiedDevices(roomId, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// TODO Check if this method is still necessary
|
||||||
* 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel any earlier room key request
|
* Cancel any earlier room key request
|
||||||
*
|
*
|
||||||
@ -1548,7 +1105,7 @@ internal class CryptoManager(
|
|||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
override fun toString(): String {
|
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 android.content.Context
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
import im.vector.matrix.android.api.auth.data.Credentials
|
||||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
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.api.CryptoApi
|
||||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
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.api.RoomKeysApi
|
||||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.*
|
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.IMXCryptoStore
|
||||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStore
|
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStore
|
||||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreMigration
|
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreMigration
|
||||||
@ -88,7 +93,7 @@ internal class CryptoModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
RoomDecryptorProvider(get(), get(), get(), get(), get())
|
RoomDecryptorProvider(get(), get())
|
||||||
}
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
@ -113,6 +118,56 @@ internal class CryptoModule {
|
|||||||
SetDeviceVerificationAction(get(), get(), get())
|
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
|
// CryptoManager
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
@ -131,8 +186,14 @@ internal class CryptoModule {
|
|||||||
get(),
|
get(),
|
||||||
get(),
|
get(),
|
||||||
get(),
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
// Actions
|
// Actions
|
||||||
get(),
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
// Factory
|
||||||
|
get(), get(),
|
||||||
// Tasks
|
// Tasks
|
||||||
get(), get(), get(), get(), get(), get(), get(),
|
get(), get(), get(), get(), get(), get(), get(),
|
||||||
// Task executor
|
// Task executor
|
||||||
@ -200,6 +261,7 @@ internal class CryptoModule {
|
|||||||
get(),
|
get(),
|
||||||
get(),
|
get(),
|
||||||
get(),
|
get(),
|
||||||
|
get(),
|
||||||
// Task
|
// Task
|
||||||
get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(),
|
get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(),
|
||||||
// Task executor
|
// Task executor
|
||||||
@ -255,7 +317,7 @@ internal class CryptoModule {
|
|||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
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>()
|
private val mReceivedRoomKeyRequestCancellations = ArrayList<IncomingRoomKeyRequestCancellation>()
|
||||||
|
|
||||||
// the listeners
|
// the listeners
|
||||||
val mRoomKeysRequestListeners: MutableSet<RoomKeysRequestListener> = HashSet()
|
private val mRoomKeysRequestListeners: MutableSet<RoomKeysRequestListener> = HashSet()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
mReceivedRoomKeyRequests.addAll(mCryptoStore.getPendingIncomingRoomKeyRequests())
|
mReceivedRoomKeyRequests.addAll(mCryptoStore.getPendingIncomingRoomKeyRequests())
|
||||||
|
@ -17,60 +17,19 @@
|
|||||||
|
|
||||||
package im.vector.matrix.android.internal.crypto
|
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 {
|
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.
|
* Get the class implementing encryption for the provided algorithm.
|
||||||
*
|
*
|
||||||
* @param algorithm the algorithm tag.
|
* @param algorithm the algorithm tag.
|
||||||
* @return A class implementing 'IMXEncrypting'.
|
* @return A class implementing 'IMXEncrypting'.
|
||||||
*/
|
*/
|
||||||
fun encryptorClassForAlgorithm(algorithm: String?): Class<IMXEncrypting>? {
|
fun hasEncryptorClassForAlgorithm(algorithm: String?): Boolean {
|
||||||
return if (!TextUtils.isEmpty(algorithm)) {
|
return when (algorithm) {
|
||||||
mEncryptors[algorithm]
|
MXCRYPTO_ALGORITHM_MEGOLM,
|
||||||
} else {
|
MXCRYPTO_ALGORITHM_OLM -> true
|
||||||
null
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,11 +40,11 @@ internal object MXCryptoAlgorithms {
|
|||||||
* @return A class implementing 'IMXDecrypting'.
|
* @return A class implementing 'IMXDecrypting'.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fun decryptorClassForAlgorithm(algorithm: String?): Class<IMXDecrypting>? {
|
fun hasDecryptorClassForAlgorithm(algorithm: String?): Boolean {
|
||||||
return if (!TextUtils.isEmpty(algorithm)) {
|
return when (algorithm) {
|
||||||
mDecryptors[algorithm]
|
MXCRYPTO_ALGORITHM_MEGOLM,
|
||||||
} else {
|
MXCRYPTO_ALGORITHM_OLM -> true
|
||||||
null
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,6 +52,6 @@ internal object MXCryptoAlgorithms {
|
|||||||
* @return The list of registered algorithms.
|
* @return The list of registered algorithms.
|
||||||
*/
|
*/
|
||||||
fun supportedAlgorithms(): List<String> {
|
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) {
|
private val mTaskExecutor: TaskExecutor) {
|
||||||
|
|
||||||
// running
|
// running
|
||||||
var mClientRunning: Boolean = false
|
private var mClientRunning: Boolean = false
|
||||||
|
|
||||||
// transaction counter
|
// transaction counter
|
||||||
private var mTxnCtr: Int = 0
|
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
|
// But that message might never arrive leaving us stuck with duff
|
||||||
// private keys clogging up our local storage.
|
// private keys clogging up our local storage.
|
||||||
// So we need some kind of engineering compromise to balance all of
|
// 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)
|
val keyCount = data.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)
|
||||||
uploadOTK(keyCount, keyLimit, callback)
|
uploadOTK(keyCount, keyLimit, callback)
|
||||||
}
|
}
|
||||||
|
@ -17,19 +17,15 @@
|
|||||||
package im.vector.matrix.android.internal.crypto
|
package im.vector.matrix.android.internal.crypto
|
||||||
|
|
||||||
import android.text.TextUtils
|
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.algorithms.IMXDecrypting
|
||||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmDecryptionFactory
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmDecryptionFactory
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
internal class RoomDecryptorProvider(
|
internal class RoomDecryptorProvider(
|
||||||
val mCredentials: Credentials,
|
private val mMXOlmDecryptionFactory: MXOlmDecryptionFactory,
|
||||||
val olmDevice: MXOlmDevice,
|
private val mMXMegolmDecryptionFactory: MXMegolmDecryptionFactory
|
||||||
val deviceListManager: DeviceListManager,
|
|
||||||
val mSendToDeviceTask: SendToDeviceTask,
|
|
||||||
val mTaskExecutor: TaskExecutor
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// A map from algorithm to MXDecrypting instance, for each room
|
// A map from algorithm to MXDecrypting instance, for each room
|
||||||
@ -43,20 +39,15 @@ internal class RoomDecryptorProvider(
|
|||||||
* @param roomId the room id
|
* @param roomId the room id
|
||||||
* @param algorithm the crypto algorithm
|
* @param algorithm the crypto algorithm
|
||||||
* @return the decryptor
|
* @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
|
// sanity check
|
||||||
if (TextUtils.isEmpty(algorithm)) {
|
if (TextUtils.isEmpty(algorithm)) {
|
||||||
Timber.e("## getRoomDecryptor() : null algorithm")
|
Timber.e("## getRoomDecryptor() : null algorithm")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null == mRoomDecryptors) {
|
|
||||||
Timber.e("## getRoomDecryptor() : null mRoomDecryptors")
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
var alg: IMXDecrypting? = null
|
var alg: IMXDecrypting? = null
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(roomId)) {
|
if (!TextUtils.isEmpty(roomId)) {
|
||||||
@ -73,27 +64,21 @@ internal class RoomDecryptorProvider(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val decryptingClass = MXCryptoAlgorithms.decryptorClassForAlgorithm(algorithm)
|
val decryptingClass = MXCryptoAlgorithms.hasDecryptorClassForAlgorithm(algorithm)
|
||||||
|
|
||||||
if (null != decryptingClass) {
|
if (decryptingClass) {
|
||||||
try {
|
alg = when (algorithm) {
|
||||||
val ctor = decryptingClass.constructors[0]
|
MXCRYPTO_ALGORITHM_MEGOLM -> mMXMegolmDecryptionFactory.instantiate()
|
||||||
alg = ctor.newInstance() as IMXDecrypting
|
else -> mMXOlmDecryptionFactory.instantiate()
|
||||||
|
|
||||||
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 (null != alg) {
|
||||||
|
if (!TextUtils.isEmpty(roomId)) {
|
||||||
|
synchronized(mRoomDecryptors) {
|
||||||
|
mRoomDecryptors[roomId]!!.put(algorithm!!, alg!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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
|
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.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.internal.crypto.*
|
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
|
||||||
import im.vector.matrix.android.internal.crypto.CryptoManager
|
import im.vector.matrix.android.internal.crypto.MXDecryptionException
|
||||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for decrypting data
|
* An interface for decrypting data
|
||||||
*/
|
*/
|
||||||
internal interface IMXDecrypting {
|
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
|
* Decrypt an event
|
||||||
*
|
*
|
||||||
@ -57,7 +44,7 @@ internal interface IMXDecrypting {
|
|||||||
*
|
*
|
||||||
* @param event the key event.
|
* @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
|
* 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 senderKey the session sender key
|
||||||
* @param sessionId the session id
|
* @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
|
* Determine if we have the keys necessary to respond to a room key request
|
||||||
@ -73,12 +60,12 @@ internal interface IMXDecrypting {
|
|||||||
* @param request keyRequest
|
* @param request keyRequest
|
||||||
* @return true if we have the keys and could (theoretically) share
|
* @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.
|
* Send the response to a room key request.
|
||||||
*
|
*
|
||||||
* @param request keyRequest
|
* @param request keyRequest
|
||||||
*/
|
*/
|
||||||
fun shareKeysWithDevice(request: IncomingRoomKeyRequest)
|
fun shareKeysWithDevice(request: IncomingRoomKeyRequest) {}
|
||||||
}
|
}
|
||||||
|
@ -18,35 +18,13 @@
|
|||||||
package im.vector.matrix.android.internal.crypto.algorithms
|
package im.vector.matrix.android.internal.crypto.algorithms
|
||||||
|
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
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.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
|
* An interface for encrypting data
|
||||||
*/
|
*/
|
||||||
internal interface IMXEncrypting {
|
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.
|
* Encrypt an event content according to the configuration of the room.
|
||||||
*
|
*
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
package im.vector.matrix.android.internal.crypto.algorithms.megolm
|
package im.vector.matrix.android.internal.crypto.algorithms.megolm
|
||||||
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import androidx.annotation.Keep
|
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
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.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.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.internal.crypto.*
|
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.IMXDecrypting
|
||||||
import im.vector.matrix.android.internal.crypto.algorithms.MXDecryptionResult
|
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.MXDeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult
|
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.model.MXUsersDevicesMap
|
||||||
@ -42,44 +44,22 @@ import im.vector.matrix.android.internal.task.configureWith
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Keep
|
internal class MXMegolmDecryption(private val mCredentials: Credentials,
|
||||||
internal class MXMegolmDecryption : IMXDecrypting {
|
private val mOlmDevice: MXOlmDevice,
|
||||||
/**
|
private val mDeviceListManager: DeviceListManager,
|
||||||
* The olm device interface
|
private val mOutgoingRoomKeyRequestManager: MXOutgoingRoomKeyRequestManager,
|
||||||
*/
|
private val mMessageEncrypter: MessageEncrypter,
|
||||||
|
private val mEnsureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
|
||||||
// the matrix credentials
|
private val mCryptoStore: IMXCryptoStore,
|
||||||
private lateinit var mCredentials: Credentials
|
private val mSendToDeviceTask: SendToDeviceTask,
|
||||||
|
private val mTaskExecutor: TaskExecutor)
|
||||||
private lateinit var mCrypto: CryptoManager
|
: IMXDecrypting {
|
||||||
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
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Events which we couldn't decrypt due to unknown sessions / indexes: map from
|
* Events which we couldn't decrypt due to unknown sessions / indexes: map from
|
||||||
* senderKey|sessionId to timelines to list of MatrixEvents.
|
* senderKey|sessionId to timelines to list of MatrixEvents.
|
||||||
*/
|
*/
|
||||||
private var mPendingEvents: MutableMap<String /* senderKey|sessionId */, MutableMap<String /* timelineId */, MutableList<Event>>> = HashMap()
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(MXDecryptionException::class)
|
@Throws(MXDecryptionException::class)
|
||||||
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? {
|
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? {
|
||||||
@ -87,8 +67,8 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(MXDecryptionException::class)
|
@Throws(MXDecryptionException::class)
|
||||||
private fun decryptEvent(event: Event?, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult? {
|
private fun decryptEvent(event: Event, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult? {
|
||||||
// sanity check
|
// sanity check // TODO Remove check
|
||||||
if (null == event) {
|
if (null == event) {
|
||||||
Timber.e("## decryptEvent() : null event")
|
Timber.e("## decryptEvent() : null event")
|
||||||
return null
|
return null
|
||||||
@ -185,7 +165,7 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||||||
requestBody.senderKey = encryptedEventContent.senderKey
|
requestBody.senderKey = encryptedEventContent.senderKey
|
||||||
requestBody.sessionId = encryptedEventContent.sessionId
|
requestBody.sessionId = encryptedEventContent.sessionId
|
||||||
|
|
||||||
mCrypto.requestRoomKey(requestBody, recipients)
|
mOutgoingRoomKeyRequestManager.sendRoomKeyRequest(requestBody, recipients)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -217,9 +197,9 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||||||
/**
|
/**
|
||||||
* Handle a key event.
|
* 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
|
var exportFormat = false
|
||||||
val roomKeyContent = event.content.toModel<RoomKeyContent>()!!
|
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)
|
val added = mOlmDevice.addInboundGroupSession(roomKeyContent.sessionId!!, roomKeyContent.sessionKey!!, roomKeyContent.roomId!!, senderKey, forwarding_curve25519_key_chain!!, keysClaimed, exportFormat)
|
||||||
|
|
||||||
if (added) {
|
if (added) {
|
||||||
mCrypto.getKeysBackupService().maybeBackupKeys()
|
keysBackup.maybeBackupKeys()
|
||||||
|
|
||||||
val content = RoomKeyRequestBody()
|
val content = RoomKeyRequestBody()
|
||||||
|
|
||||||
@ -283,7 +263,7 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||||||
content.sessionId = roomKeyContent.sessionId
|
content.sessionId = roomKeyContent.sessionId
|
||||||
content.senderKey = senderKey
|
content.senderKey = senderKey
|
||||||
|
|
||||||
mCrypto.cancelRoomKeyRequest(content)
|
mOutgoingRoomKeyRequestManager.cancelRoomKeyRequest(content)
|
||||||
|
|
||||||
onNewSession(senderKey, roomKeyContent.sessionId!!)
|
onNewSession(senderKey, roomKeyContent.sessionId!!)
|
||||||
}
|
}
|
||||||
@ -334,14 +314,13 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean {
|
override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean {
|
||||||
return (null != request
|
return (null != request.mRequestBody
|
||||||
&& null != request.mRequestBody
|
|
||||||
&& mOlmDevice.hasInboundSessionKeys(request.mRequestBody!!.roomId!!, request.mRequestBody!!.senderKey!!, request.mRequestBody!!.sessionId!!))
|
&& mOlmDevice.hasInboundSessionKeys(request.mRequestBody!!.roomId!!, request.mRequestBody!!.senderKey!!, request.mRequestBody!!.sessionId!!))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shareKeysWithDevice(request: IncomingRoomKeyRequest) {
|
override fun shareKeysWithDevice(request: IncomingRoomKeyRequest) {
|
||||||
// sanity checks
|
// sanity checks
|
||||||
if (null == request || null == request.mRequestBody) {
|
if (request.mRequestBody == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,9 +337,9 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||||||
val devicesByUser = HashMap<String, List<MXDeviceInfo>>()
|
val devicesByUser = HashMap<String, List<MXDeviceInfo>>()
|
||||||
devicesByUser[userId] = ArrayList(Arrays.asList(deviceInfo))
|
devicesByUser[userId] = ArrayList(Arrays.asList(deviceInfo))
|
||||||
|
|
||||||
mCrypto.ensureOlmSessionsForDevices(devicesByUser, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
|
mEnsureOlmSessionsForDevicesAction.handle(devicesByUser, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
|
||||||
override fun onSuccess(map: MXUsersDevicesMap<MXOlmSessionResult>) {
|
override fun onSuccess(data: MXUsersDevicesMap<MXOlmSessionResult>) {
|
||||||
val olmSessionResult = map.getObject(deviceId, userId)
|
val olmSessionResult = data.getObject(deviceId, userId)
|
||||||
|
|
||||||
if (null == olmSessionResult || null == olmSessionResult.mSessionId) {
|
if (null == olmSessionResult || null == olmSessionResult.mSessionId) {
|
||||||
// no session with this device, probably because there
|
// no session with this device, probably because there
|
||||||
@ -380,7 +359,7 @@ internal class MXMegolmDecryption : IMXDecrypting {
|
|||||||
payloadJson["type"] = EventType.FORWARDED_ROOM_KEY
|
payloadJson["type"] = EventType.FORWARDED_ROOM_KEY
|
||||||
payloadJson["content"] = inboundGroupSession!!.exportKeys()!!
|
payloadJson["content"] = inboundGroupSession!!.exportKeys()!!
|
||||||
|
|
||||||
val encodedPayload = mCrypto.encryptMessage(payloadJson, Arrays.asList(deviceInfo))
|
val encodedPayload = mMessageEncrypter.encryptMessage(payloadJson, Arrays.asList(deviceInfo))
|
||||||
val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
||||||
sendToDeviceMap.setObject(encodedPayload, userId, deviceId)
|
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
|
package im.vector.matrix.android.internal.crypto.algorithms.megolm
|
||||||
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import androidx.annotation.Keep
|
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
import im.vector.matrix.android.api.auth.data.Credentials
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
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.Content
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
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.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.algorithms.IMXEncrypting
|
||||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
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.MXDeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult
|
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.MXQueuedEncryption
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
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.crypto.tasks.SendToDeviceTask
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
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 timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Keep
|
internal class MXMegolmEncryption(
|
||||||
internal class MXMegolmEncryption : IMXEncrypting {
|
// The id of the room we will be sending to.
|
||||||
|
private var mRoomId: String,
|
||||||
|
|
||||||
private lateinit var mCrypto: CryptoManager
|
private val olmDevice: MXOlmDevice,
|
||||||
private lateinit var olmDevice: MXOlmDevice
|
private val mKeysBackup: KeysBackup,
|
||||||
private lateinit var mKeysBackup: KeysBackup
|
private val mCryptoStore: IMXCryptoStore,
|
||||||
private lateinit var mDeviceListManager: DeviceListManager
|
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
|
// 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
|
// 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>()
|
private val mPendingEncryptions = ArrayList<MXQueuedEncryption>()
|
||||||
|
|
||||||
|
// Default rotation periods
|
||||||
|
// TODO: Make it configurable via parameters
|
||||||
// Session rotation periods
|
// Session rotation periods
|
||||||
private var mSessionRotationPeriodMsgs: Int = 0
|
private var mSessionRotationPeriodMsgs: Int = 100
|
||||||
private var mSessionRotationPeriodMs: Int = 0
|
private var mSessionRotationPeriodMs: Int = 7 * 24 * 3600 * 1000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a snapshot of the pending encryptions
|
* @return a snapshot of the pending encryptions
|
||||||
@ -87,32 +95,6 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||||||
return list
|
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,
|
override fun encryptEventContent(eventContent: Content,
|
||||||
eventType: String,
|
eventType: String,
|
||||||
userIds: List<String>,
|
userIds: List<String>,
|
||||||
@ -334,7 +316,7 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||||||
val t0 = System.currentTimeMillis()
|
val t0 = System.currentTimeMillis()
|
||||||
Timber.d("## shareUserDevicesKey() : starts")
|
Timber.d("## shareUserDevicesKey() : starts")
|
||||||
|
|
||||||
mCrypto.ensureOlmSessionsForDevices(devicesByUser, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
|
mEnsureOlmSessionsForDevicesAction.handle(devicesByUser, object : MatrixCallback<MXUsersDevicesMap<MXOlmSessionResult>> {
|
||||||
override fun onSuccess(data: MXUsersDevicesMap<MXOlmSessionResult>) {
|
override fun onSuccess(data: MXUsersDevicesMap<MXOlmSessionResult>) {
|
||||||
Timber.d("## shareUserDevicesKey() : ensureOlmSessionsForDevices succeeds after "
|
Timber.d("## shareUserDevicesKey() : ensureOlmSessionsForDevices succeeds after "
|
||||||
+ (System.currentTimeMillis() - t0) + " ms")
|
+ (System.currentTimeMillis() - t0) + " ms")
|
||||||
@ -367,7 +349,7 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||||||
|
|
||||||
Timber.d("## shareUserDevicesKey() : Sharing keys with device $userId:$deviceID")
|
Timber.d("## shareUserDevicesKey() : Sharing keys with device $userId:$deviceID")
|
||||||
//noinspection ArraysAsListWithZeroOrOneArgument,ArraysAsListWithZeroOrOneArgument
|
//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
|
haveTargets = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,7 +435,7 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||||||
|
|
||||||
// Include our device ID so that recipients can send us a
|
// Include our device ID so that recipients can send us a
|
||||||
// m.new_device message if they don't have our session key.
|
// 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()!!) }
|
CryptoAsyncHelper.getUiHandler().post { queuedEncryption.mApiCallback?.onSuccess(map.toContent()!!) }
|
||||||
|
|
||||||
@ -480,7 +462,8 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||||||
// an m.new_device.
|
// an m.new_device.
|
||||||
mDeviceListManager.downloadKeys(userIds, false, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
mDeviceListManager.downloadKeys(userIds, false, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||||
override fun onSuccess(data: 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 devicesInRoom = MXUsersDevicesMap<MXDeviceInfo>()
|
||||||
val unknownDevices = MXUsersDevicesMap<MXDeviceInfo>()
|
val unknownDevices = MXUsersDevicesMap<MXDeviceInfo>()
|
||||||
@ -491,7 +474,7 @@ internal class MXMegolmEncryption : IMXEncrypting {
|
|||||||
for (deviceId in deviceIds!!) {
|
for (deviceId in deviceIds!!) {
|
||||||
val deviceInfo = data.getObject(deviceId, userId)
|
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
|
// The device is not yet known by the user
|
||||||
unknownDevices.setObject(deviceInfo, userId, deviceId)
|
unknownDevices.setObject(deviceInfo, userId, deviceId)
|
||||||
continue
|
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
|
package im.vector.matrix.android.internal.crypto.algorithms.olm
|
||||||
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import androidx.annotation.Keep
|
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
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.crypto.MXCryptoError
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
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.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.algorithms.IMXDecrypting
|
||||||
import im.vector.matrix.android.internal.crypto.model.event.OlmEventContent
|
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.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 im.vector.matrix.android.internal.util.convertFromUTF8
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
internal class MXOlmDecryption(
|
||||||
* An interface for encrypting data
|
// The olm device interface
|
||||||
*/
|
private val mOlmDevice: MXOlmDevice,
|
||||||
@Keep
|
|
||||||
internal class MXOlmDecryption : IMXDecrypting {
|
|
||||||
|
|
||||||
// The olm device interface
|
// the matrix credentials
|
||||||
private lateinit var mOlmDevice: MXOlmDevice
|
private val mCredentials: Credentials)
|
||||||
|
: IMXDecrypting {
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(MXDecryptionException::class)
|
@Throws(MXDecryptionException::class)
|
||||||
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? {
|
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>()!!
|
val olmEventContent = event.content.toModel<OlmEventContent>()!!
|
||||||
|
|
||||||
if (null == olmEventContent.ciphertext) {
|
if (null == olmEventContent.ciphertext) {
|
||||||
@ -89,7 +59,7 @@ internal class MXOlmDecryption : IMXDecrypting {
|
|||||||
|
|
||||||
// The message for myUser
|
// The message for myUser
|
||||||
val message = olmEventContent.ciphertext!![mOlmDevice.deviceCurve25519Key] as Map<String, Any>
|
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) {
|
if (null == payloadString) {
|
||||||
Timber.e("## decryptEvent() Failed to decrypt Olm event (id= " + event.eventId + " ) from " + olmEventContent.senderKey)
|
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()
|
val result = MXEventDecryptionResult()
|
||||||
// TODO result.mClearEvent = payload
|
// FIXME result.mClearEvent = payload
|
||||||
result.mSenderCurve25519Key = olmEventContent.senderKey
|
result.mSenderCurve25519Key = olmEventContent.senderKey
|
||||||
result.mClaimedEd25519Key = olmPayloadContent.keys!!.get("ed25519")
|
result.mClaimedEd25519Key = olmPayloadContent.keys!!.get("ed25519")
|
||||||
|
|
||||||
return result
|
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.
|
* Attempt to decrypt an Olm message.
|
||||||
*
|
*
|
||||||
@ -192,8 +148,8 @@ internal class MXOlmDecryption : IMXDecrypting {
|
|||||||
* @param message message object, with 'type' and 'body' fields.
|
* @param message message object, with 'type' and 'body' fields.
|
||||||
* @return payload, if decrypted successfully.
|
* @return payload, if decrypted successfully.
|
||||||
*/
|
*/
|
||||||
private fun decryptMessage(message: Map<String, Any>, theirDeviceIdentityKey: String?): String? {
|
private fun decryptMessage(message: Map<String, Any>, theirDeviceIdentityKey: String): String? {
|
||||||
val sessionIdsSet = mOlmDevice.getSessionIds(theirDeviceIdentityKey!!)
|
val sessionIdsSet = mOlmDevice.getSessionIds(theirDeviceIdentityKey)
|
||||||
|
|
||||||
val sessionIds: List<String>
|
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
|
package im.vector.matrix.android.internal.crypto.algorithms.olm
|
||||||
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import androidx.annotation.Keep
|
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
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.Content
|
||||||
import im.vector.matrix.android.api.session.events.model.toContent
|
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.DeviceListManager
|
||||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
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.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.MXDeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXOlmSessionResult
|
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.model.MXUsersDevicesMap
|
||||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Keep
|
internal class MXOlmEncryption(
|
||||||
internal class MXOlmEncryption : IMXEncrypting {
|
private var mRoomId: String,
|
||||||
private lateinit var mCrypto: CryptoManager
|
|
||||||
private lateinit var mOlmDevice: MXOlmDevice
|
|
||||||
private lateinit var mDeviceListManager: DeviceListManager
|
|
||||||
|
|
||||||
private lateinit var mCredentials: Credentials
|
private val mOlmDevice: MXOlmDevice,
|
||||||
private lateinit var mSendToDeviceTask: SendToDeviceTask
|
private val mCryptoStore: IMXCryptoStore,
|
||||||
private lateinit var mTaskExecutor: TaskExecutor
|
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,
|
override fun encryptEventContent(eventContent: Content,
|
||||||
eventType: String,
|
eventType: String,
|
||||||
@ -75,24 +56,22 @@ internal class MXOlmEncryption : IMXEncrypting {
|
|||||||
val deviceInfos = ArrayList<MXDeviceInfo>()
|
val deviceInfos = ArrayList<MXDeviceInfo>()
|
||||||
|
|
||||||
for (userId in userIds) {
|
for (userId in userIds) {
|
||||||
val devices = mCrypto.getUserDevices(userId)
|
val devices = mCryptoStore.getUserDevices(userId)?.values ?: emptyList()
|
||||||
|
|
||||||
if (null != devices) {
|
for (device in devices) {
|
||||||
for (device in devices) {
|
val key = device.identityKey()
|
||||||
val key = device.identityKey()
|
|
||||||
|
|
||||||
if (TextUtils.equals(key, mOlmDevice.deviceCurve25519Key)) {
|
if (TextUtils.equals(key, mOlmDevice.deviceCurve25519Key)) {
|
||||||
// Don't bother setting up session to ourself
|
// Don't bother setting up session to ourself
|
||||||
continue
|
continue
|
||||||
}
|
|
||||||
|
|
||||||
if (device.isBlocked) {
|
|
||||||
// Don't bother setting up sessions with blocked users
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceInfos.add(device)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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["type"] = eventType
|
||||||
messageMap["content"] = eventContent
|
messageMap["content"] = eventContent
|
||||||
|
|
||||||
mCrypto.encryptMessage(messageMap, deviceInfos)
|
mMessageEncrypter.encryptMessage(messageMap, deviceInfos)
|
||||||
|
|
||||||
callback.onSuccess(messageMap.toContent()!!)
|
callback.onSuccess(messageMap.toContent()!!)
|
||||||
}
|
}
|
||||||
@ -118,7 +97,7 @@ internal class MXOlmEncryption : IMXEncrypting {
|
|||||||
mDeviceListManager.downloadKeys(users, false, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
mDeviceListManager.downloadKeys(users, false, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||||
|
|
||||||
override fun onSuccess(data: 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>) {
|
override fun onSuccess(data: MXUsersDevicesMap<MXOlmSessionResult>) {
|
||||||
callback?.onSuccess(Unit)
|
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.KeysBackupService
|
||||||
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
|
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
|
||||||
import im.vector.matrix.android.internal.crypto.*
|
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.KeysBackupVersionTrust
|
||||||
import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrustSignature
|
import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrustSignature
|
||||||
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupAuthData
|
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupAuthData
|
||||||
@ -67,6 +68,8 @@ internal class KeysBackup(
|
|||||||
private val mCryptoStore: IMXCryptoStore,
|
private val mCryptoStore: IMXCryptoStore,
|
||||||
private val mOlmDevice: MXOlmDevice,
|
private val mOlmDevice: MXOlmDevice,
|
||||||
private val mObjectSigner: ObjectSigner,
|
private val mObjectSigner: ObjectSigner,
|
||||||
|
// Actions
|
||||||
|
private val mMegolmSessionDataImporter: MegolmSessionDataImporter,
|
||||||
// Tasks
|
// Tasks
|
||||||
private val mCreateKeysBackupVersionTask: CreateKeysBackupVersionTask,
|
private val mCreateKeysBackupVersionTask: CreateKeysBackupVersionTask,
|
||||||
private val mDeleteBackupTask: DeleteBackupTask,
|
private val mDeleteBackupTask: DeleteBackupTask,
|
||||||
@ -115,9 +118,6 @@ internal class KeysBackup(
|
|||||||
override val currentBackupVersion: String?
|
override val currentBackupVersion: String?
|
||||||
get() = mKeysBackupVersion?.version
|
get() = mKeysBackupVersion?.version
|
||||||
|
|
||||||
// Internal listener
|
|
||||||
private lateinit var mKeysBackupCryptoListener: KeysBackupCryptoListener
|
|
||||||
|
|
||||||
override fun addListener(listener: KeysBackupService.KeysBackupStateListener) {
|
override fun addListener(listener: KeysBackupService.KeysBackupStateListener) {
|
||||||
mKeysBackupStateManager.addListener(listener)
|
mKeysBackupStateManager.addListener(listener)
|
||||||
}
|
}
|
||||||
@ -749,7 +749,20 @@ internal class KeysBackup(
|
|||||||
null
|
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) {
|
override fun onFailure(failure: Throwable) {
|
||||||
@ -887,7 +900,7 @@ internal class KeysBackup(
|
|||||||
/**
|
/**
|
||||||
* Do a backup if there are new keys, with a delay
|
* Do a backup if there are new keys, with a delay
|
||||||
*/
|
*/
|
||||||
override fun maybeBackupKeys() {
|
fun maybeBackupKeys() {
|
||||||
when {
|
when {
|
||||||
isStucked -> {
|
isStucked -> {
|
||||||
// If not already done, or in error case, check for a valid backup version on the homeserver.
|
// 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
|
@WorkerThread
|
||||||
fun encryptGroupSession(session: MXOlmInboundGroupSession2): KeyBackupData {
|
fun encryptGroupSession(session: MXOlmInboundGroupSession2): KeyBackupData {
|
||||||
// Gather information for each key
|
// 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
|
// 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
|
// 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
|
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
|
* DEBUG INFO
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
@ -22,7 +22,7 @@ import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
internal class KeysBackupStateManager(val uiHandler: Handler) {
|
internal class KeysBackupStateManager(private val uiHandler: Handler) {
|
||||||
|
|
||||||
private val mListeners = ArrayList<KeysBackupService.KeysBackupStateListener>()
|
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 ->
|
.let { u ->
|
||||||
// Add the devices
|
// Add the devices
|
||||||
// Ensure all other devices are deleted
|
// Ensure all other devices are deleted
|
||||||
u.devices.deleteAllFromRealm() // Device is null!!
|
u.devices.deleteAllFromRealm()
|
||||||
|
|
||||||
u.devices.addAll(
|
u.devices.addAll(
|
||||||
devices.map {
|
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.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
|
import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
|
||||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
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.actions.SetDeviceVerificationAction
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||||
@ -48,6 +49,7 @@ import kotlin.collections.HashMap
|
|||||||
*/
|
*/
|
||||||
internal class DefaultSasVerificationService(private val mCredentials: Credentials,
|
internal class DefaultSasVerificationService(private val mCredentials: Credentials,
|
||||||
private val mCryptoStore: IMXCryptoStore,
|
private val mCryptoStore: IMXCryptoStore,
|
||||||
|
private val mMyDeviceInfoHolder: MyDeviceInfoHolder,
|
||||||
private val deviceListManager: DeviceListManager,
|
private val deviceListManager: DeviceListManager,
|
||||||
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
||||||
private val mSendToDeviceTask: SendToDeviceTask,
|
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>()
|
private var listeners = ArrayList<SasVerificationService.SasVerificationListener>()
|
||||||
|
|
||||||
override fun addListener(listener: 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!!}")
|
Timber.d("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}")
|
||||||
val tx = IncomingSASVerificationTransaction(
|
val tx = IncomingSASVerificationTransaction(
|
||||||
this,
|
this,
|
||||||
|
setDeviceVerificationAction,
|
||||||
mCredentials,
|
mCredentials,
|
||||||
mCryptoStore,
|
mCryptoStore,
|
||||||
mSendToDeviceTask,
|
mSendToDeviceTask,
|
||||||
mTaskExecutor,
|
mTaskExecutor,
|
||||||
mCryptoListener.getMyDevice().fingerprint()!!,
|
mMyDeviceInfoHolder.myDevice.fingerprint()!!,
|
||||||
startReq.transactionID!!,
|
startReq.transactionID!!,
|
||||||
otherUserId)
|
otherUserId)
|
||||||
addTransaction(tx)
|
addTransaction(tx)
|
||||||
@ -362,11 +361,12 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||||||
if (KeyVerificationStart.VERIF_METHOD_SAS == method) {
|
if (KeyVerificationStart.VERIF_METHOD_SAS == method) {
|
||||||
val tx = OutgoingSASVerificationRequest(
|
val tx = OutgoingSASVerificationRequest(
|
||||||
this,
|
this,
|
||||||
|
setDeviceVerificationAction,
|
||||||
mCredentials,
|
mCredentials,
|
||||||
mCryptoStore,
|
mCryptoStore,
|
||||||
mSendToDeviceTask,
|
mSendToDeviceTask,
|
||||||
mTaskExecutor,
|
mTaskExecutor,
|
||||||
mCryptoListener.getMyDevice().fingerprint()!!,
|
mMyDeviceInfoHolder.myDevice.fingerprint()!!,
|
||||||
txID,
|
txID,
|
||||||
userId,
|
userId,
|
||||||
deviceID)
|
deviceID)
|
||||||
@ -424,12 +424,4 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
|||||||
})
|
})
|
||||||
.executeBy(mTaskExecutor)
|
.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.crypto.sas.SasVerificationTxState
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
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.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.store.IMXCryptoStore
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
|
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationKey
|
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationKey
|
||||||
@ -35,6 +36,7 @@ import timber.log.Timber
|
|||||||
|
|
||||||
internal class IncomingSASVerificationTransaction(
|
internal class IncomingSASVerificationTransaction(
|
||||||
private val mSasVerificationService: DefaultSasVerificationService,
|
private val mSasVerificationService: DefaultSasVerificationService,
|
||||||
|
private val mSetDeviceVerificationAction: SetDeviceVerificationAction,
|
||||||
private val mCredentials: Credentials,
|
private val mCredentials: Credentials,
|
||||||
private val mCryptoStore: IMXCryptoStore,
|
private val mCryptoStore: IMXCryptoStore,
|
||||||
private val mSendToDeviceTask: SendToDeviceTask,
|
private val mSendToDeviceTask: SendToDeviceTask,
|
||||||
@ -44,6 +46,7 @@ internal class IncomingSASVerificationTransaction(
|
|||||||
otherUserID: String)
|
otherUserID: String)
|
||||||
: SASVerificationTransaction(
|
: SASVerificationTransaction(
|
||||||
mSasVerificationService,
|
mSasVerificationService,
|
||||||
|
mSetDeviceVerificationAction,
|
||||||
mCredentials,
|
mCredentials,
|
||||||
mCryptoStore,
|
mCryptoStore,
|
||||||
mSendToDeviceTask,
|
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.OutgoingSasVerificationRequest
|
||||||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
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.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.store.IMXCryptoStore
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
|
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
|
||||||
@ -33,6 +34,7 @@ import timber.log.Timber
|
|||||||
|
|
||||||
internal class OutgoingSASVerificationRequest(
|
internal class OutgoingSASVerificationRequest(
|
||||||
private val mSasVerificationService: DefaultSasVerificationService,
|
private val mSasVerificationService: DefaultSasVerificationService,
|
||||||
|
private val mSetDeviceVerificationAction: SetDeviceVerificationAction,
|
||||||
private val mCredentials: Credentials,
|
private val mCredentials: Credentials,
|
||||||
private val mCryptoStore: IMXCryptoStore,
|
private val mCryptoStore: IMXCryptoStore,
|
||||||
private val mSendToDeviceTask: SendToDeviceTask,
|
private val mSendToDeviceTask: SendToDeviceTask,
|
||||||
@ -43,6 +45,7 @@ internal class OutgoingSASVerificationRequest(
|
|||||||
otherDeviceId: String)
|
otherDeviceId: String)
|
||||||
: SASVerificationTransaction(
|
: SASVerificationTransaction(
|
||||||
mSasVerificationService,
|
mSasVerificationService,
|
||||||
|
mSetDeviceVerificationAction,
|
||||||
mCredentials,
|
mCredentials,
|
||||||
mCryptoStore,
|
mCryptoStore,
|
||||||
mSendToDeviceTask,
|
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.crypto.sas.SasVerificationTxState
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
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.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.MXDeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXKey
|
import im.vector.matrix.android.internal.crypto.model.MXKey
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||||
@ -42,6 +43,7 @@ import kotlin.properties.Delegates
|
|||||||
*/
|
*/
|
||||||
internal abstract class SASVerificationTransaction(
|
internal abstract class SASVerificationTransaction(
|
||||||
private val mSasVerificationService: DefaultSasVerificationService,
|
private val mSasVerificationService: DefaultSasVerificationService,
|
||||||
|
private val mSetDeviceVerificationAction: SetDeviceVerificationAction,
|
||||||
private val mCredentials: Credentials,
|
private val mCredentials: Credentials,
|
||||||
private val mCryptoStore: IMXCryptoStore,
|
private val mCryptoStore: IMXCryptoStore,
|
||||||
private val mSendToDeviceTask: SendToDeviceTask,
|
private val mSendToDeviceTask: SendToDeviceTask,
|
||||||
@ -245,7 +247,7 @@ internal abstract class SASVerificationTransaction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setDeviceVerified(deviceId: String, userId: String) {
|
private fun setDeviceVerified(deviceId: String, userId: String) {
|
||||||
mSasVerificationService.setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED,
|
mSetDeviceVerificationAction.handle(MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED,
|
||||||
deviceId,
|
deviceId,
|
||||||
userId)
|
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.EmptyItem_
|
||||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
||||||
private val roomNameItemFactory: RoomNameItemFactory,
|
private val roomNameItemFactory: RoomNameItemFactory,
|
||||||
@ -59,6 +60,8 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory,
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "Error")
|
||||||
|
|
||||||
defaultItemFactory.create(event, e)
|
defaultItemFactory.create(event, e)
|
||||||
}
|
}
|
||||||
return (computedModel ?: EmptyItem_())
|
return (computedModel ?: EmptyItem_())
|
||||||
|
Loading…
Reference in New Issue
Block a user