mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Merge pull request #292 from vector-im/feature/sonar_fix
Feature sonar fix and convert remaining Java files to Kotlin
This commit is contained in:
commit
60d46538de
24
build.gradle
24
build.gradle
@ -42,6 +42,10 @@ task clean(type: Delete) {
|
||||
|
||||
apply plugin: 'org.sonarqube'
|
||||
|
||||
// To run a sonar analysis:
|
||||
// Run './gradlew sonarqube -Dsonar.login=<REPLACE_WITH_SONAR_KEY>'
|
||||
// The SONAR_KEY is stored in passbolt
|
||||
|
||||
sonarqube {
|
||||
properties {
|
||||
property "sonar.projectName", "RiotX-Android"
|
||||
@ -67,3 +71,23 @@ project(":vector") {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//project(":matrix-sdk-android") {
|
||||
// sonarqube {
|
||||
// properties {
|
||||
// property "sonar.sources", project(":matrix-sdk-android").android.sourceSets.main.java.srcDirs
|
||||
// // exclude source code from analyses separated by a colon (:)
|
||||
// // property "sonar.exclusions", "**/*.*"
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//project(":matrix-sdk-android-rx") {
|
||||
// sonarqube {
|
||||
// properties {
|
||||
// property "sonar.sources", project(":matrix-sdk-android-rx").android.sourceSets.main.java.srcDirs
|
||||
// // exclude source code from analyses separated by a colon (:)
|
||||
// // property "sonar.exclusions", "**/*.*"
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
@ -19,25 +19,18 @@ package im.vector.matrix.android.auth
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.rule.GrantPermissionRule
|
||||
import androidx.test.runner.AndroidJUnit4
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.InstrumentedTest
|
||||
import im.vector.matrix.android.OkReplayRuleChainNoActivity
|
||||
import im.vector.matrix.android.api.auth.Authenticator
|
||||
import im.vector.matrix.android.internal.auth.AuthModule
|
||||
import im.vector.matrix.android.internal.di.MatrixModule
|
||||
import im.vector.matrix.android.internal.di.NetworkModule
|
||||
import okreplay.*
|
||||
import org.junit.ClassRule
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.koin.standalone.StandAloneContext.loadKoinModules
|
||||
import org.koin.standalone.inject
|
||||
import org.koin.test.KoinTest
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
internal class AuthenticatorTest : InstrumentedTest, KoinTest {
|
||||
internal class AuthenticatorTest : InstrumentedTest {
|
||||
|
||||
lateinit var authenticator: Authenticator
|
||||
lateinit var okReplayInterceptor: OkReplayInterceptor
|
||||
|
@ -1039,10 +1039,10 @@ internal class CryptoManager @Inject constructor(
|
||||
for (userId in userIds) {
|
||||
val deviceIds = devicesInRoom.getUserDeviceIds(userId)
|
||||
for (deviceId in deviceIds!!) {
|
||||
val deviceInfo = devicesInRoom.getObject(deviceId, userId)
|
||||
val deviceInfo = devicesInRoom.getObject(userId, deviceId)
|
||||
|
||||
if (deviceInfo!!.isUnknown) {
|
||||
unknownDevices.setObject(deviceInfo, userId, deviceId)
|
||||
if (deviceInfo?.isUnknown == true) {
|
||||
unknownDevices.setObject(userId, deviceId, deviceInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||
Timber.v("Device list for $userId now up to date")
|
||||
}
|
||||
// And the response result
|
||||
usersDevicesInfoMap.setObjects(devices, userId)
|
||||
usersDevicesInfoMap.setObjects(userId, devices)
|
||||
}
|
||||
}
|
||||
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
||||
@ -239,7 +239,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||
*/
|
||||
suspend fun downloadKeys(userIds: List<String>?, forceDownload: Boolean): Try<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||
Timber.v("## downloadKeys() : forceDownload $forceDownload : $userIds")
|
||||
// Map from userid -> deviceid -> DeviceInfo
|
||||
// Map from userId -> deviceId -> MXDeviceInfo
|
||||
val stored = MXUsersDevicesMap<MXDeviceInfo>()
|
||||
|
||||
// List of user ids we need to download keys for
|
||||
@ -258,7 +258,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
|
||||
val devices = cryptoStore.getUserDevices(userId)
|
||||
// should always be true
|
||||
if (devices != null) {
|
||||
stored.setObjects(devices, userId)
|
||||
stored.setObjects(userId, devices)
|
||||
} else {
|
||||
downloadUsers.add(userId)
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
|
||||
|
||||
for (recipient in recipients) {
|
||||
// TODO Change this two hard coded key to something better
|
||||
contentMap.setObject(message, recipient["userId"], recipient["deviceId"])
|
||||
contentMap.setObject(recipient["userId"], recipient["deviceId"], message)
|
||||
}
|
||||
|
||||
sendToDeviceTask.configureWith(SendToDeviceTask.Params(EventType.ROOM_KEY_REQUEST, contentMap, transactionId))
|
||||
|
@ -24,7 +24,6 @@ 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.session.SessionScope
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
@ -54,7 +53,7 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(private val
|
||||
}
|
||||
|
||||
val olmSessionResult = MXOlmSessionResult(deviceInfo, sessionId)
|
||||
results.setObject(olmSessionResult, userId, deviceId)
|
||||
results.setObject(userId, deviceId, olmSessionResult)
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +67,7 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(private val
|
||||
val oneTimeKeyAlgorithm = MXKey.KEY_SIGNED_CURVE_25519_TYPE
|
||||
|
||||
for (device in devicesWithoutSession) {
|
||||
usersDevicesToClaim.setObject(oneTimeKeyAlgorithm, device.userId, device.deviceId)
|
||||
usersDevicesToClaim.setObject(device.userId, device.deviceId, oneTimeKeyAlgorithm)
|
||||
}
|
||||
|
||||
// TODO: this has a race condition - if we try to send another message
|
||||
@ -91,12 +90,12 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(private val
|
||||
val deviceIds = it.getUserDeviceIds(userId)
|
||||
if (null != deviceIds) {
|
||||
for (deviceId in deviceIds) {
|
||||
val olmSessionResult = results.getObject(deviceId, userId)
|
||||
val olmSessionResult = results.getObject(userId, deviceId)
|
||||
if (olmSessionResult!!.sessionId != null) {
|
||||
// We already have a result for this device
|
||||
continue
|
||||
}
|
||||
val key = it.getObject(deviceId, userId)
|
||||
val key = it.getObject(userId, deviceId)
|
||||
if (key?.type == oneTimeKeyAlgorithm) {
|
||||
oneTimeKey = key
|
||||
}
|
||||
@ -126,11 +125,13 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(private val
|
||||
var isVerified = false
|
||||
var errorMessage: String? = null
|
||||
|
||||
try {
|
||||
olmDevice.verifySignature(deviceInfo.fingerprint()!!, oneTimeKey.signalableJSONDictionary(), signature)
|
||||
isVerified = true
|
||||
} catch (e: Exception) {
|
||||
errorMessage = e.message
|
||||
if (signature != null) {
|
||||
try {
|
||||
olmDevice.verifySignature(deviceInfo.fingerprint()!!, oneTimeKey.signalableJSONDictionary(), signature)
|
||||
isVerified = true
|
||||
} catch (e: Exception) {
|
||||
errorMessage = e.message
|
||||
}
|
||||
}
|
||||
|
||||
// Check one-time key signature
|
||||
|
@ -309,7 +309,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
|
||||
.handle(devicesByUser)
|
||||
.flatMap {
|
||||
val body = request.requestBody
|
||||
val olmSessionResult = it.getObject(deviceId, userId)
|
||||
val olmSessionResult = it.getObject(userId, deviceId)
|
||||
if (olmSessionResult?.sessionId == null) {
|
||||
// no session with this device, probably because there
|
||||
// were no one-time keys.
|
||||
@ -325,7 +325,7 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
|
||||
|
||||
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, Arrays.asList(deviceInfo))
|
||||
val sendToDeviceMap = MXUsersDevicesMap<Any>()
|
||||
sendToDeviceMap.setObject(encodedPayload, userId, deviceId)
|
||||
sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
|
||||
Timber.v("## shareKeysWithDevice() : sending to $userId:$deviceId")
|
||||
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
|
||||
sendToDeviceTask.execute(sendToDeviceParams)
|
||||
|
@ -118,8 +118,8 @@ internal class MXMegolmEncryption(
|
||||
for (userId in userIds) {
|
||||
val deviceIds = devicesInRoom.getUserDeviceIds(userId)
|
||||
for (deviceId in deviceIds!!) {
|
||||
val deviceInfo = devicesInRoom.getObject(deviceId, userId)
|
||||
if (null == safeSession.sharedWithDevices.getObject(deviceId, userId)) {
|
||||
val deviceInfo = devicesInRoom.getObject(userId, deviceId)
|
||||
if (deviceInfo != null && null == safeSession.sharedWithDevices.getObject(userId, deviceId)) {
|
||||
if (!shareMap.containsKey(userId)) {
|
||||
shareMap[userId] = ArrayList()
|
||||
}
|
||||
@ -201,7 +201,7 @@ internal class MXMegolmEncryption(
|
||||
for (userId in userIds) {
|
||||
val devicesToShareWith = devicesByUser[userId]
|
||||
for ((deviceID) in devicesToShareWith!!) {
|
||||
val sessionResult = it.getObject(deviceID, userId)
|
||||
val sessionResult = it.getObject(userId, deviceID)
|
||||
if (sessionResult?.sessionId == null) {
|
||||
// no session with this device, probably because there
|
||||
// were no one-time keys.
|
||||
@ -218,7 +218,7 @@ internal class MXMegolmEncryption(
|
||||
}
|
||||
Timber.v("## shareUserDevicesKey() : Sharing keys with device $userId:$deviceID")
|
||||
//noinspection ArraysAsListWithZeroOrOneArgument,ArraysAsListWithZeroOrOneArgument
|
||||
contentMap.setObject(messageEncrypter.encryptMessage(payload, Arrays.asList(sessionResult.deviceInfo)), userId, deviceID)
|
||||
contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, Arrays.asList(sessionResult.deviceInfo)))
|
||||
haveTargets = true
|
||||
}
|
||||
}
|
||||
@ -239,7 +239,7 @@ internal class MXMegolmEncryption(
|
||||
for (userId in devicesByUser.keys) {
|
||||
val devicesToShareWith = devicesByUser[userId]
|
||||
for ((deviceId) in devicesToShareWith!!) {
|
||||
session.sharedWithDevices.setObject(chainIndex, userId, deviceId)
|
||||
session.sharedWithDevices.setObject(userId, deviceId, chainIndex)
|
||||
}
|
||||
}
|
||||
Unit
|
||||
@ -303,10 +303,10 @@ internal class MXMegolmEncryption(
|
||||
for (userId in it.userIds) {
|
||||
val deviceIds = it.getUserDeviceIds(userId) ?: continue
|
||||
for (deviceId in deviceIds) {
|
||||
val deviceInfo = it.getObject(deviceId, userId) ?: continue
|
||||
val deviceInfo = it.getObject(userId, deviceId) ?: continue
|
||||
if (warnOnUnknownDevicesRepository.warnOnUnknownDevices() && deviceInfo.isUnknown) {
|
||||
// The device is not yet known by the user
|
||||
unknownDevices.setObject(deviceInfo, userId, deviceId)
|
||||
unknownDevices.setObject(userId, deviceId, deviceInfo)
|
||||
continue
|
||||
}
|
||||
if (deviceInfo.isBlocked) {
|
||||
@ -322,7 +322,7 @@ internal class MXMegolmEncryption(
|
||||
// Don't bother sending to ourself
|
||||
continue
|
||||
}
|
||||
devicesInRoom.setObject(deviceInfo, userId, deviceId)
|
||||
devicesInRoom.setObject(userId, deviceId, deviceInfo)
|
||||
}
|
||||
}
|
||||
if (unknownDevices.isEmpty) {
|
||||
|
@ -64,7 +64,7 @@ internal class MXOutboundSessionInfo(
|
||||
val deviceIds = sharedWithDevices.getUserDeviceIds(userId)
|
||||
|
||||
for (deviceId in deviceIds!!) {
|
||||
if (null == devicesInRoom.getObject(deviceId, userId)) {
|
||||
if (null == devicesInRoom.getObject(userId, deviceId)) {
|
||||
Timber.v("## sharedWithTooManyDevices() : Starting new session because we shared with $userId:$deviceId")
|
||||
return true
|
||||
}
|
||||
|
@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 OpenMarket Ltd
|
||||
* Copyright 2018 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.crypto.model;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class MXKey implements Serializable {
|
||||
/**
|
||||
* Key types.
|
||||
*/
|
||||
public static final String KEY_CURVE_25519_TYPE = "curve25519";
|
||||
public static final String KEY_SIGNED_CURVE_25519_TYPE = "signed_curve25519";
|
||||
//public static final String KEY_ED_25519_TYPE = "ed25519";
|
||||
|
||||
/**
|
||||
* The type of the key.
|
||||
*/
|
||||
public String type;
|
||||
|
||||
/**
|
||||
* The id of the key.
|
||||
*/
|
||||
public String keyId;
|
||||
|
||||
/**
|
||||
* The key.
|
||||
*/
|
||||
public String value;
|
||||
|
||||
/**
|
||||
* signature user Id to [deviceid][signature]
|
||||
*/
|
||||
public Map<String, Map<String, String>> signatures;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public MXKey() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a map to a MXKey
|
||||
*
|
||||
* @param map the map to convert
|
||||
*/
|
||||
public MXKey(Map<String, Map<String, Object>> map) {
|
||||
if ((null != map) && (map.size() > 0)) {
|
||||
List<String> mapKeys = new ArrayList<>(map.keySet());
|
||||
|
||||
String firstEntry = mapKeys.get(0);
|
||||
setKeyFullId(firstEntry);
|
||||
|
||||
Map<String, Object> params = map.get(firstEntry);
|
||||
value = (String) params.get("key");
|
||||
signatures = (Map<String, Map<String, String>>) params.get("signatures");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key full id
|
||||
*/
|
||||
public String getKeyFullId() {
|
||||
return type + ":" + keyId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the key fields with a key full id
|
||||
*
|
||||
* @param keyFullId the key full id
|
||||
*/
|
||||
private void setKeyFullId(String keyFullId) {
|
||||
if (!TextUtils.isEmpty(keyFullId)) {
|
||||
try {
|
||||
String[] components = keyFullId.split(":");
|
||||
|
||||
if (components.length == 2) {
|
||||
type = components[0];
|
||||
keyId = components[1];
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Timber.e(e, "## setKeyFullId() failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the signed data map
|
||||
*/
|
||||
public Map<String, Object> signalableJSONDictionary() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
|
||||
if (null != value) {
|
||||
map.put("key", value);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a signature for an user Id and a signkey
|
||||
*
|
||||
* @param userId the user id
|
||||
* @param signkey the sign key
|
||||
* @return the signature
|
||||
*/
|
||||
public String signatureForUserId(String userId, String signkey) {
|
||||
// sanity checks
|
||||
if (!TextUtils.isEmpty(userId) && !TextUtils.isEmpty(signkey)) {
|
||||
if ((null != signatures) && signatures.containsKey(userId)) {
|
||||
return signatures.get(userId).get(signkey);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.model
|
||||
|
||||
import im.vector.matrix.android.api.util.JsonDict
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
data class MXKey(
|
||||
/**
|
||||
* The type of the key (in the example: "signed_curve25519").
|
||||
*/
|
||||
val type: String,
|
||||
|
||||
/**
|
||||
* The id of the key (in the example: "AAAAFw").
|
||||
*/
|
||||
private val keyId: String,
|
||||
|
||||
/**
|
||||
* The key (in the example: "IjwIcskng7YjYcn0tS8TUOT2OHHtBSfMpcfIczCgXj4").
|
||||
*/
|
||||
val value: String,
|
||||
|
||||
/**
|
||||
* signature user Id to [deviceid][signature]
|
||||
*/
|
||||
private val signatures: Map<String, Map<String, String>>
|
||||
) {
|
||||
|
||||
/**
|
||||
* @return the signed data map
|
||||
*/
|
||||
fun signalableJSONDictionary(): Map<String, Any> {
|
||||
val map = HashMap<String, Any>()
|
||||
|
||||
map["key"] = value
|
||||
|
||||
return map
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a signature for an user Id and a signkey
|
||||
*
|
||||
* @param userId the user id
|
||||
* @param signkey the sign key
|
||||
* @return the signature
|
||||
*/
|
||||
fun signatureForUserId(userId: String, signkey: String): String? {
|
||||
// sanity checks
|
||||
if (userId.isNotBlank() && signkey.isNotBlank()) {
|
||||
if (signatures.containsKey(userId)) {
|
||||
return signatures[userId]?.get(signkey)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Key types.
|
||||
*/
|
||||
const val KEY_CURVE_25519_TYPE = "curve25519"
|
||||
const val KEY_SIGNED_CURVE_25519_TYPE = "signed_curve25519"
|
||||
// const val KEY_ED_25519_TYPE = "ed25519"
|
||||
|
||||
/**
|
||||
* Convert a map to a MXKey
|
||||
*
|
||||
* @param map the map to convert
|
||||
*
|
||||
* Json Example:
|
||||
*
|
||||
* <pre>
|
||||
* "signed_curve25519:AAAAFw": {
|
||||
* "key": "IjwIcskng7YjYcn0tS8TUOT2OHHtBSfMpcfIczCgXj4",
|
||||
* "signatures": {
|
||||
* "@userId:matrix.org": {
|
||||
* "ed25519:GMJRREOASV": "EUjp6pXzK9u3SDFR\/qLbzpOi3bEREeI6qMnKzXu992HsfuDDZftfJfiUXv9b\/Hqq1og4qM\/vCQJGTHAWMmgkCg"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* into several val members
|
||||
*/
|
||||
fun from(map: Map<String, JsonDict>?): MXKey? {
|
||||
if (map?.isNotEmpty() == true) {
|
||||
val firstKey = map.keys.first()
|
||||
|
||||
val components = firstKey.split(":").dropLastWhile { it.isEmpty() }
|
||||
|
||||
if (components.size == 2) {
|
||||
val params = map[firstKey]
|
||||
if (params != null) {
|
||||
if (params["key"] is String) {
|
||||
return MXKey(
|
||||
type = components[0],
|
||||
keyId = components[1],
|
||||
value = params["key"] as String,
|
||||
signatures = params["signatures"] as Map<String, Map<String, String>>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error case
|
||||
Timber.e("## Unable to parse map")
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 OpenMarket Ltd
|
||||
* Copyright 2018 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.crypto.model;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class MXUsersDevicesMap<E> implements Serializable {
|
||||
|
||||
// The device keys as returned by the homeserver: a map of a map (userId -> deviceId -> Object).
|
||||
private final Map<String, Map<String, E>> mMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* @return the inner map
|
||||
*/
|
||||
public Map<String, Map<String, E>> getMap() {
|
||||
return mMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor constructor
|
||||
*/
|
||||
public MXUsersDevicesMap() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
* @param map the map
|
||||
*/
|
||||
public MXUsersDevicesMap(Map<String, Map<String, E>> map) {
|
||||
if (null != map) {
|
||||
Set<String> keys = map.keySet();
|
||||
|
||||
for (String key : keys) {
|
||||
mMap.put(key, new HashMap<>(map.get(key)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a deep copy
|
||||
*/
|
||||
public MXUsersDevicesMap<E> deepCopy() {
|
||||
MXUsersDevicesMap<E> copy = new MXUsersDevicesMap<>();
|
||||
|
||||
Set<String> keys = mMap.keySet();
|
||||
|
||||
for (String key : keys) {
|
||||
copy.mMap.put(key, new HashMap<>(mMap.get(key)));
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the user Ids
|
||||
*/
|
||||
public List<String> getUserIds() {
|
||||
return new ArrayList<>(mMap.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the device ids list for an user id
|
||||
*
|
||||
* @param userId the user id
|
||||
* @return the device ids list
|
||||
*/
|
||||
public List<String> getUserDeviceIds(String userId) {
|
||||
if (!TextUtils.isEmpty(userId) && mMap.containsKey(userId)) {
|
||||
return new ArrayList<>(mMap.get(userId).keySet());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the object for a device id and an user Id
|
||||
*
|
||||
* @param deviceId the device id
|
||||
* @param userId the object id
|
||||
* @return the object
|
||||
*/
|
||||
public E getObject(String deviceId, String userId) {
|
||||
if (!TextUtils.isEmpty(userId) && mMap.containsKey(userId) && !TextUtils.isEmpty(deviceId)) {
|
||||
return mMap.get(userId).get(deviceId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an object for a dedicated user Id and device Id
|
||||
*
|
||||
* @param object the object to set
|
||||
* @param userId the user Id
|
||||
* @param deviceId the device id
|
||||
*/
|
||||
public void setObject(E object, String userId, String deviceId) {
|
||||
if ((null != object) && !TextUtils.isEmpty(userId) && !TextUtils.isEmpty(deviceId)) {
|
||||
Map<String, E> subMap = mMap.get(userId);
|
||||
|
||||
if (null == subMap) {
|
||||
subMap = new HashMap<>();
|
||||
mMap.put(userId, subMap);
|
||||
}
|
||||
|
||||
subMap.put(deviceId, object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the objects map for an user Id
|
||||
*
|
||||
* @param objectsPerDevices the objects maps
|
||||
* @param userId the user id
|
||||
*/
|
||||
public void setObjects(Map<String, E> objectsPerDevices, String userId) {
|
||||
if (!TextUtils.isEmpty(userId)) {
|
||||
if (null == objectsPerDevices) {
|
||||
mMap.remove(userId);
|
||||
} else {
|
||||
mMap.put(userId, new HashMap<>(objectsPerDevices));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes objects for a dedicated user
|
||||
*
|
||||
* @param userId the user id.
|
||||
*/
|
||||
public void removeUserObjects(String userId) {
|
||||
if (!TextUtils.isEmpty(userId)) {
|
||||
mMap.remove(userId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the internal dictionary
|
||||
*/
|
||||
public void removeAllObjects() {
|
||||
mMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add entries from another MXUsersDevicesMap
|
||||
*
|
||||
* @param other the other one
|
||||
*/
|
||||
public void addEntriesFromMap(MXUsersDevicesMap<E> other) {
|
||||
if (null != other) {
|
||||
mMap.putAll(other.getMap());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty(){
|
||||
return mMap.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (null != mMap) {
|
||||
return "MXUsersDevicesMap " + mMap.toString();
|
||||
} else {
|
||||
return "MXDeviceInfo : null map";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.model
|
||||
|
||||
import java.util.*
|
||||
|
||||
class MXUsersDevicesMap<E> {
|
||||
|
||||
// A map of maps (userId -> (deviceId -> Object)).
|
||||
val map = HashMap<String /* userId */, HashMap<String /* deviceId */, E>>()
|
||||
|
||||
/**
|
||||
* @return the user Ids
|
||||
*/
|
||||
val userIds: List<String>
|
||||
get() = ArrayList(map.keys)
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = map.isEmpty()
|
||||
|
||||
/**
|
||||
* Provides the device ids list for a user id
|
||||
* FIXME Should maybe return emptyList and not null, to avoid many !! in the code
|
||||
*
|
||||
* @param userId the user id
|
||||
* @return the device ids list
|
||||
*/
|
||||
fun getUserDeviceIds(userId: String?): List<String>? {
|
||||
return if (userId?.isNotBlank() == true && map.containsKey(userId)) {
|
||||
map[userId]!!.keys.toList()
|
||||
} else null
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the object for a device id and a user Id
|
||||
*
|
||||
* @param deviceId the device id
|
||||
* @param userId the object id
|
||||
* @return the object
|
||||
*/
|
||||
fun getObject(userId: String?, deviceId: String?): E? {
|
||||
return if (userId?.isNotBlank() == true && deviceId?.isNotBlank() == true && map.containsKey(userId)) {
|
||||
map[userId]!![deviceId]
|
||||
} else null
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an object for a dedicated user Id and device Id
|
||||
*
|
||||
* @param userId the user Id
|
||||
* @param deviceId the device id
|
||||
* @param o the object to set
|
||||
*/
|
||||
fun setObject(userId: String?, deviceId: String?, o: E?) {
|
||||
if (null != o && userId?.isNotBlank() == true && deviceId?.isNotBlank() == true) {
|
||||
if (map[userId] == null) {
|
||||
map[userId] = HashMap()
|
||||
}
|
||||
|
||||
map[userId]!![deviceId] = o
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the objects map for a user Id
|
||||
*
|
||||
* @param objectsPerDevices the objects maps
|
||||
* @param userId the user id
|
||||
*/
|
||||
fun setObjects(userId: String?, objectsPerDevices: Map<String, E>?) {
|
||||
if (userId?.isNotBlank() == true) {
|
||||
if (null == objectsPerDevices) {
|
||||
map.remove(userId)
|
||||
} else {
|
||||
map[userId] = HashMap(objectsPerDevices)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes objects for a dedicated user
|
||||
*
|
||||
* @param userId the user id.
|
||||
*/
|
||||
fun removeUserObjects(userId: String?) {
|
||||
if (userId?.isNotBlank() == true) {
|
||||
map.remove(userId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the internal dictionary
|
||||
*/
|
||||
fun removeAllObjects() {
|
||||
map.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Add entries from another MXUsersDevicesMap
|
||||
*
|
||||
* @param other the other one
|
||||
*/
|
||||
fun addEntriesFromMap(other: MXUsersDevicesMap<E>?) {
|
||||
if (null != other) {
|
||||
map.putAll(other.map)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "MXUsersDevicesMap $map"
|
||||
}
|
||||
}
|
@ -20,11 +20,14 @@ import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This class represents the response to /keys/query request made by claimOneTimeKeysForUsersDevices.
|
||||
* This class represents the response to /keys/claim request made by claimOneTimeKeysForUsersDevices.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class KeysClaimBody(
|
||||
|
||||
/**
|
||||
* The time (in milliseconds) to wait when downloading keys from remote servers. 10 seconds is the recommended default.
|
||||
*/
|
||||
@Json(name = "timeout")
|
||||
var timeout: Int? = null,
|
||||
|
||||
|
@ -20,7 +20,7 @@ import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* This class represents the response to /keys/query request made by claimOneTimeKeysForUsersDevices.
|
||||
* This class represents the response to /keys/claim request made by claimOneTimeKeysForUsersDevices.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class KeysClaimResponse(
|
||||
|
@ -18,8 +18,9 @@ package im.vector.matrix.android.internal.crypto.model.rest
|
||||
|
||||
class SendToDeviceBody {
|
||||
|
||||
// `Any` should implement SendToDeviceObject, but we cannot use interface here because of Gson serialization
|
||||
/**
|
||||
* `Any` should implement [SendToDeviceObject], but we cannot use interface here because of Json serialization
|
||||
*
|
||||
* The messages to send. A map from user ID, to a map from device ID to message body.
|
||||
* The device ID may also be *, meaning all known devices for the user.
|
||||
*/
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
package im.vector.matrix.android.internal.crypto.store.db.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
|
||||
import io.realm.RealmObject
|
||||
|
||||
internal open class IncomingRoomKeyRequestEntity(
|
||||
var requestId: String? = null,
|
||||
@ -32,11 +32,11 @@ internal open class IncomingRoomKeyRequestEntity(
|
||||
) : RealmObject() {
|
||||
|
||||
fun toIncomingRoomKeyRequest(): IncomingRoomKeyRequest {
|
||||
return IncomingRoomKeyRequest().apply {
|
||||
requestId = requestId
|
||||
userId = userId
|
||||
deviceId = deviceId
|
||||
requestBody = RoomKeyRequestBody().apply {
|
||||
return IncomingRoomKeyRequest().also {
|
||||
it.requestId = requestId
|
||||
it.userId = userId
|
||||
it.deviceId = deviceId
|
||||
it.requestBody = RoomKeyRequestBody().apply {
|
||||
algorithm = requestBodyAlgorithm
|
||||
roomId = requestBodyRoomId
|
||||
senderKey = requestBodySenderKey
|
||||
|
@ -23,10 +23,8 @@ import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeysClaimBody
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeysClaimResponse
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface ClaimOneTimeKeysForUsersDeviceTask : Task<ClaimOneTimeKeysForUsersDeviceTask.Params, MXUsersDevicesMap<MXKey>> {
|
||||
@ -46,30 +44,25 @@ internal class DefaultClaimOneTimeKeysForUsersDevice @Inject constructor(private
|
||||
apiCall = cryptoApi.claimOneTimeKeysForUsersDevices(body)
|
||||
}.flatMap { keysClaimResponse ->
|
||||
Try {
|
||||
val map = HashMap<String, Map<String, MXKey>>()
|
||||
val map = MXUsersDevicesMap<MXKey>()
|
||||
|
||||
if (null != keysClaimResponse.oneTimeKeys) {
|
||||
for (userId in keysClaimResponse.oneTimeKeys!!.keys) {
|
||||
val mapByUserId = keysClaimResponse.oneTimeKeys!![userId]
|
||||
|
||||
val keysMap = HashMap<String, MXKey>()
|
||||
|
||||
for (deviceId in mapByUserId!!.keys) {
|
||||
try {
|
||||
keysMap[deviceId] = MXKey(mapByUserId[deviceId])
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## claimOneTimeKeysForUsersDevices : fail to create a MXKey ")
|
||||
val mxKey = MXKey.from(mapByUserId[deviceId])
|
||||
|
||||
if (mxKey != null) {
|
||||
map.setObject(userId, deviceId, mxKey)
|
||||
} else {
|
||||
Timber.e("## claimOneTimeKeysForUsersDevices : fail to create a MXKey")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (keysMap.size != 0) {
|
||||
map[userId] = keysMap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MXUsersDevicesMap(map)
|
||||
map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
|
||||
.fold(
|
||||
{ error() },
|
||||
{
|
||||
if (it.getUserDeviceIds(otherUserId).contains(startReq.fromDevice)) {
|
||||
if (it.getUserDeviceIds(otherUserId)?.contains(startReq.fromDevice) == true) {
|
||||
success(it)
|
||||
} else {
|
||||
error()
|
||||
@ -410,7 +410,7 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
|
||||
fun cancelTransaction(transactionId: String, userId: String, userDevice: String, code: CancelCode) {
|
||||
val cancelMessage = KeyVerificationCancel.create(transactionId, code)
|
||||
val contentMap = MXUsersDevicesMap<Any>()
|
||||
contentMap.setObject(cancelMessage, userId, userDevice)
|
||||
contentMap.setObject(userId, userDevice, cancelMessage)
|
||||
|
||||
sendToDeviceTask.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap, transactionId))
|
||||
.dispatchTo(object : MatrixCallback<Unit> {
|
||||
|
@ -21,12 +21,11 @@ import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRe
|
||||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationKey
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationMac
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
@ -61,22 +60,22 @@ internal class OutgoingSASVerificationRequest(
|
||||
override val uxState: OutgoingSasVerificationRequest.UxState
|
||||
get() {
|
||||
return when (state) {
|
||||
SasVerificationTxState.None -> OutgoingSasVerificationRequest.UxState.WAIT_FOR_START
|
||||
SasVerificationTxState.None -> OutgoingSasVerificationRequest.UxState.WAIT_FOR_START
|
||||
SasVerificationTxState.SendingStart,
|
||||
SasVerificationTxState.Started,
|
||||
SasVerificationTxState.OnAccepted,
|
||||
SasVerificationTxState.SendingKey,
|
||||
SasVerificationTxState.KeySent,
|
||||
SasVerificationTxState.OnKeyReceived -> OutgoingSasVerificationRequest.UxState.WAIT_FOR_KEY_AGREEMENT
|
||||
SasVerificationTxState.OnKeyReceived -> OutgoingSasVerificationRequest.UxState.WAIT_FOR_KEY_AGREEMENT
|
||||
SasVerificationTxState.ShortCodeReady -> OutgoingSasVerificationRequest.UxState.SHOW_SAS
|
||||
SasVerificationTxState.ShortCodeAccepted,
|
||||
SasVerificationTxState.SendingMac,
|
||||
SasVerificationTxState.MacSent,
|
||||
SasVerificationTxState.Verifying -> OutgoingSasVerificationRequest.UxState.WAIT_FOR_VERIFICATION
|
||||
SasVerificationTxState.Verified -> OutgoingSasVerificationRequest.UxState.VERIFIED
|
||||
SasVerificationTxState.OnCancelled -> OutgoingSasVerificationRequest.UxState.CANCELLED_BY_ME
|
||||
SasVerificationTxState.Cancelled -> OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER
|
||||
else -> OutgoingSasVerificationRequest.UxState.UNKNOWN
|
||||
SasVerificationTxState.Verifying -> OutgoingSasVerificationRequest.UxState.WAIT_FOR_VERIFICATION
|
||||
SasVerificationTxState.Verified -> OutgoingSasVerificationRequest.UxState.VERIFIED
|
||||
SasVerificationTxState.OnCancelled -> OutgoingSasVerificationRequest.UxState.CANCELLED_BY_ME
|
||||
SasVerificationTxState.Cancelled -> OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER
|
||||
else -> OutgoingSasVerificationRequest.UxState.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,8 +101,6 @@ internal class OutgoingSASVerificationRequest(
|
||||
startMessage.shortAuthenticationStrings = KNOWN_SHORT_CODES
|
||||
|
||||
startReq = startMessage
|
||||
val contentMap = MXUsersDevicesMap<Any>()
|
||||
contentMap.setObject(startMessage, otherUserId, otherDeviceId)
|
||||
state = SasVerificationTxState.SendingStart
|
||||
|
||||
sendToOther(
|
||||
|
@ -285,7 +285,7 @@ internal abstract class SASVerificationTransaction(
|
||||
onErrorReason: CancelCode,
|
||||
onDone: (() -> Unit)?) {
|
||||
val contentMap = MXUsersDevicesMap<Any>()
|
||||
contentMap.setObject(keyToDevice, otherUserId, otherDeviceId)
|
||||
contentMap.setObject(otherUserId, otherDeviceId, keyToDevice)
|
||||
|
||||
sendToDeviceTask.configureWith(SendToDeviceTask.Params(type, contentMap, transactionId))
|
||||
.dispatchTo(object : MatrixCallback<Unit> {
|
||||
|
@ -103,7 +103,7 @@ class KeyRequestHandler @Inject constructor(val context: Context)
|
||||
//Add a notification for every incoming request
|
||||
session?.downloadKeys(Arrays.asList(userId), false, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXDeviceInfo>) {
|
||||
val deviceInfo = data.getObject(deviceId, userId)
|
||||
val deviceInfo = data.getObject(userId, deviceId)
|
||||
|
||||
if (null == deviceInfo) {
|
||||
Timber.e("## displayKeyShareDialog() : No details found for device $userId:$deviceId")
|
||||
|
@ -63,6 +63,7 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St
|
||||
else -> {
|
||||
|
||||
//If the event can be displayed, display it as is
|
||||
Timber.w("NotifiableEventResolver Received an unsupported event matching a bing rule")
|
||||
//TODO Better event text display
|
||||
val bodyPreview = event.type
|
||||
|
||||
@ -75,11 +76,6 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St
|
||||
title = stringProvider.getString(R.string.notification_unknown_new_event),
|
||||
soundName = null,
|
||||
type = event.type)
|
||||
|
||||
|
||||
//Unsupported event
|
||||
Timber.w("NotifiableEventResolver Received an unsupported event matching a bing rule")
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,8 +92,8 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St
|
||||
// Ok room is not known in store, but we can still display something
|
||||
val body =
|
||||
event.annotations?.editSummary?.aggregatedContent?.toModel<MessageContent>()?.body
|
||||
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
||||
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
||||
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
||||
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
||||
val roomName = stringProvider.getString(R.string.notification_unknown_room_name)
|
||||
val senderDisplayName = event.senderName ?: event.root.senderId
|
||||
|
||||
@ -115,8 +111,8 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St
|
||||
return notifiableEvent
|
||||
} else {
|
||||
val body = event.annotations?.editSummary?.aggregatedContent?.toModel<MessageContent>()?.body
|
||||
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
||||
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
||||
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
||||
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
||||
val roomName = room.roomSummary()?.displayName ?: ""
|
||||
val senderDisplayName = event.senderName ?: event.root.senderId
|
||||
|
||||
@ -138,15 +134,15 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St
|
||||
// TODO They will be not displayed the first time (known limitation)
|
||||
notifiableEvent.roomAvatarPath = session.contentUrlResolver()
|
||||
.resolveThumbnail(room.roomSummary()?.avatarUrl,
|
||||
250,
|
||||
250,
|
||||
ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||
250,
|
||||
250,
|
||||
ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||
|
||||
notifiableEvent.senderAvatarPath = session.contentUrlResolver()
|
||||
.resolveThumbnail(event.senderAvatar,
|
||||
250,
|
||||
250,
|
||||
ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||
250,
|
||||
250,
|
||||
ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||
|
||||
return notifiableEvent
|
||||
}
|
||||
@ -159,7 +155,7 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St
|
||||
val dName = event.senderId?.let { session.getUser(it)?.displayName }
|
||||
if (Membership.INVITE == content.membership) {
|
||||
val body = noticeEventFormatter.format(event, dName)
|
||||
?: stringProvider.getString(R.string.notification_new_invitation)
|
||||
?: stringProvider.getString(R.string.notification_new_invitation)
|
||||
return InviteNotifiableEvent(
|
||||
session.sessionParams.credentials.userId,
|
||||
eventId = event.eventId!!,
|
||||
|
Loading…
Reference in New Issue
Block a user