diff --git a/CHANGES.md b/CHANGES.md index b4ecac0bb1..8bdd42636d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,28 @@ -Changes in RiotX 0.19.0 (2020-XX-XX) +Changes in RiotX 0.20.0 (2020-XX-XX) +=================================================== + +Features ✨: + - + +Improvements 🙌: + - + +Bugfix 🐛: + - Sometimes the same device appears twice in the list of devices of a user (#1329) + +Translations 🗣: + - + +SDK API changes ⚠️: + - + +Build 🧱: + - + +Other changes: + - + +Changes in RiotX 0.19.0 (2020-05-04) =================================================== Features ✨: @@ -51,7 +75,7 @@ Bugfix 🐛: - Fix bad Shield Logic for DM (#963) Translations 🗣: - - + - Weblate now create PR directly to RiotX GitHub project SDK API changes ⚠️: - Increase targetSdkVersion to 29 diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackupScenarioData.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackupScenarioData.kt index f10f2fef0e..0270c34a37 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackupScenarioData.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackupScenarioData.kt @@ -19,13 +19,13 @@ package im.vector.matrix.android.internal.crypto.keysbackup import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.common.CommonTestHelper import im.vector.matrix.android.common.CryptoTestData -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 /** * Data class to store result of [KeysBackupTestHelper.createKeysBackupScenarioWithPassword] */ data class KeysBackupScenarioData(val cryptoTestData: CryptoTestData, - val aliceKeys: List, + val aliceKeys: List, val prepareKeysBackupDataResult: PrepareKeysBackupDataResult, val aliceSession2: Session) { fun cleanUp(testHelper: CommonTestHelper) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt index 1d3c0f4dcd..d529cf4ae5 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt @@ -446,7 +446,7 @@ internal class DefaultCryptoService @Inject constructor( } override fun getCryptoDeviceInfo(userId: String): List { - return cryptoStore.getUserDevices(userId)?.map { it.value }?.sortedBy { it.deviceId } ?: emptyList() + return cryptoStore.getUserDeviceList(userId) ?: emptyList() } override fun getLiveCryptoDeviceInfo(): LiveData> { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt index d6d8b06b5f..9e116d8223 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXOlmDevice.kt @@ -21,7 +21,7 @@ import im.vector.matrix.android.api.session.crypto.MXCryptoError import im.vector.matrix.android.api.util.JSON_DICT_PARAMETERIZED_TYPE import im.vector.matrix.android.api.util.JsonDict import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.model.OlmSessionWrapper import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.di.MoshiProvider @@ -488,7 +488,7 @@ internal class MXOlmDevice @Inject constructor( forwardingCurve25519KeyChain: List, keysClaimed: Map, exportFormat: Boolean): Boolean { - val session = OlmInboundGroupSessionWrapper(sessionKey, exportFormat) + val session = OlmInboundGroupSessionWrapper2(sessionKey, exportFormat) runCatching { getInboundGroupSession(sessionId, senderKey, roomId) } .fold( { @@ -543,18 +543,18 @@ internal class MXOlmDevice @Inject constructor( * @param megolmSessionsData the megolm sessions data * @return the successfully imported sessions. */ - fun importInboundGroupSessions(megolmSessionsData: List): List { - val sessions = ArrayList(megolmSessionsData.size) + fun importInboundGroupSessions(megolmSessionsData: List): List { + val sessions = ArrayList(megolmSessionsData.size) for (megolmSessionData in megolmSessionsData) { val sessionId = megolmSessionData.sessionId val senderKey = megolmSessionData.senderKey val roomId = megolmSessionData.roomId - var session: OlmInboundGroupSessionWrapper? = null + var session: OlmInboundGroupSessionWrapper2? = null try { - session = OlmInboundGroupSessionWrapper(megolmSessionData) + session = OlmInboundGroupSessionWrapper2(megolmSessionData) } catch (e: Exception) { Timber.e(e, "## importInboundGroupSession() : Update for megolm session $senderKey/$sessionId") } @@ -741,7 +741,7 @@ internal class MXOlmDevice @Inject constructor( * @param senderKey the base64-encoded curve25519 key of the sender. * @return the inbound group session. */ - fun getInboundGroupSession(sessionId: String?, senderKey: String?, roomId: String?): OlmInboundGroupSessionWrapper { + fun getInboundGroupSession(sessionId: String?, senderKey: String?, roomId: String?): OlmInboundGroupSessionWrapper2 { if (sessionId.isNullOrBlank() || senderKey.isNullOrBlank()) { throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_SENDER_KEY, MXCryptoError.ERROR_MISSING_PROPERTY_REASON) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt index d6538f041d..d9fa8d5955 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/SetDeviceVerificationAction.kt @@ -48,7 +48,7 @@ internal class SetDeviceVerificationAction @Inject constructor( if (device.trustLevel != trustLevel) { device.trustLevel = trustLevel - cryptoStore.storeUserDevice(userId, device) + cryptoStore.setDeviceTrust(userId, deviceId, trustLevel.crossSigningVerified, trustLevel.locallyVerified) } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt index ebef751925..38dae20a83 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt @@ -66,7 +66,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.tasks.UpdateKeysBacku import im.vector.matrix.android.internal.crypto.keysbackup.util.computeRecoveryKey import im.vector.matrix.android.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.SavedKeyBackupKeyInfo import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntity @@ -1318,7 +1318,7 @@ internal class DefaultKeysBackupService @Inject constructor( @VisibleForTesting @WorkerThread - fun encryptGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper): KeyBackupData { + fun encryptGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2): KeyBackupData { // Gather information for each key val device = cryptoStore.deviceWithIdentityKey(olmInboundGroupSessionWrapper.senderKey!!) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt index 9be08d9f2d..cf1a3b237a 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper.kt @@ -103,11 +103,10 @@ class OlmInboundGroupSessionWrapper : Serializable { /** * Export the inbound group session keys - * @param index the index to export. If null, the first known index will be used * * @return the inbound group session as MegolmSessionData if the operation succeeds */ - fun exportKeys(index: Long? = null): MegolmSessionData? { + fun exportKeys(): MegolmSessionData? { return try { if (null == forwardingCurve25519KeyChain) { forwardingCurve25519KeyChain = ArrayList() @@ -117,8 +116,6 @@ class OlmInboundGroupSessionWrapper : Serializable { return null } - val wantedIndex = index ?: olmInboundGroupSession!!.firstKnownIndex - MegolmSessionData( senderClaimedEd25519Key = keysClaimed?.get("ed25519"), forwardingCurve25519KeyChain = ArrayList(forwardingCurve25519KeyChain!!), @@ -126,7 +123,7 @@ class OlmInboundGroupSessionWrapper : Serializable { senderClaimedKeys = keysClaimed, roomId = roomId, sessionId = olmInboundGroupSession!!.sessionIdentifier(), - sessionKey = olmInboundGroupSession!!.export(wantedIndex), + sessionKey = olmInboundGroupSession!!.export(olmInboundGroupSession!!.firstKnownIndex), algorithm = MXCRYPTO_ALGORITHM_MEGOLM ) } catch (e: Exception) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt new file mode 100755 index 0000000000..c51e707aeb --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.crypto.model + +import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM +import im.vector.matrix.android.internal.crypto.MegolmSessionData +import org.matrix.olm.OlmInboundGroupSession +import timber.log.Timber +import java.io.Serializable + +/** + * This class adds more context to a OlmInboundGroupSession object. + * This allows additional checks. The class implements Serializable so that the context can be stored. + */ +class OlmInboundGroupSessionWrapper2 : Serializable { + + // The associated olm inbound group session. + var olmInboundGroupSession: OlmInboundGroupSession? = null + + // The room in which this session is used. + var roomId: String? = null + + // The base64-encoded curve25519 key of the sender. + var senderKey: String? = null + + // Other keys the sender claims. + var keysClaimed: Map? = null + + // Devices which forwarded this session to us (normally empty). + var forwardingCurve25519KeyChain: List? = ArrayList() + + /** + * @return the first known message index + */ + val firstKnownIndex: Long? + get() { + if (null != olmInboundGroupSession) { + try { + return olmInboundGroupSession!!.firstKnownIndex + } catch (e: Exception) { + Timber.e(e, "## getFirstKnownIndex() : getFirstKnownIndex failed") + } + } + + return null + } + + /** + * Constructor + * + * @param sessionKey the session key + * @param isImported true if it is an imported session key + */ + constructor(sessionKey: String, isImported: Boolean) { + try { + if (!isImported) { + olmInboundGroupSession = OlmInboundGroupSession(sessionKey) + } else { + olmInboundGroupSession = OlmInboundGroupSession.importSession(sessionKey) + } + } catch (e: Exception) { + Timber.e(e, "Cannot create") + } + } + + constructor() { + // empty + } + /** + * Create a new instance from the provided keys map. + * + * @param megolmSessionData the megolm session data + * @throws Exception if the data are invalid + */ + @Throws(Exception::class) + constructor(megolmSessionData: MegolmSessionData) { + try { + olmInboundGroupSession = OlmInboundGroupSession.importSession(megolmSessionData.sessionKey!!) + + if (olmInboundGroupSession!!.sessionIdentifier() != megolmSessionData.sessionId) { + throw Exception("Mismatched group session Id") + } + + senderKey = megolmSessionData.senderKey + keysClaimed = megolmSessionData.senderClaimedKeys + roomId = megolmSessionData.roomId + } catch (e: Exception) { + throw Exception(e.message) + } + } + + /** + * Export the inbound group session keys + * @param index the index to export. If null, the first known index will be used + * + * @return the inbound group session as MegolmSessionData if the operation succeeds + */ + fun exportKeys(index: Long? = null): MegolmSessionData? { + return try { + if (null == forwardingCurve25519KeyChain) { + forwardingCurve25519KeyChain = ArrayList() + } + + if (keysClaimed == null) { + return null + } + + val wantedIndex = index ?: olmInboundGroupSession!!.firstKnownIndex + + MegolmSessionData( + senderClaimedEd25519Key = keysClaimed?.get("ed25519"), + forwardingCurve25519KeyChain = ArrayList(forwardingCurve25519KeyChain!!), + senderKey = senderKey, + senderClaimedKeys = keysClaimed, + roomId = roomId, + sessionId = olmInboundGroupSession!!.sessionIdentifier(), + sessionKey = olmInboundGroupSession!!.export(wantedIndex), + algorithm = MXCRYPTO_ALGORITHM_MEGOLM + ) + } catch (e: Exception) { + Timber.e(e, "## export() : senderKey $senderKey failed") + null + } + } + + /** + * Export the session for a message index. + * + * @param messageIndex the message index + * @return the exported data + */ + fun exportSession(messageIndex: Long): String? { + if (null != olmInboundGroupSession) { + try { + return olmInboundGroupSession!!.export(messageIndex) + } catch (e: Exception) { + Timber.e(e, "## exportSession() : export failed") + } + } + + return null + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt index 18c85f78fb..69f0985391 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt @@ -30,7 +30,7 @@ import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest import im.vector.matrix.android.internal.crypto.OutgoingSecretRequest import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.model.OlmSessionWrapper import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody @@ -59,7 +59,7 @@ internal interface IMXCryptoStore { * * @return the list of all known group sessions, to export them. */ - fun getInboundGroupSessions(): List + fun getInboundGroupSessions(): List /** * @return true to unilaterally blacklist all unverified devices. @@ -164,14 +164,6 @@ internal interface IMXCryptoStore { */ fun saveOlmAccount() - /** - * Store a device for a user. - * - * @param userId the user's id. - * @param device the device to store. - */ - fun storeUserDevice(userId: String?, deviceInfo: CryptoDeviceInfo?) - /** * Retrieve a device for a user. * @@ -282,7 +274,7 @@ internal interface IMXCryptoStore { * * @param sessions the inbound group sessions to store. */ - fun storeInboundGroupSessions(sessions: List) + fun storeInboundGroupSessions(sessions: List) /** * Retrieve an inbound group session. @@ -291,7 +283,7 @@ internal interface IMXCryptoStore { * @param senderKey the base64-encoded curve25519 key of the sender. * @return an inbound group session. */ - fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper? + fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper2? /** * Remove an inbound group session @@ -315,7 +307,7 @@ internal interface IMXCryptoStore { * * @param sessions the sessions */ - fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List) + fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List) /** * Retrieve inbound group sessions that are not yet backed up. @@ -323,7 +315,7 @@ internal interface IMXCryptoStore { * @param limit the maximum number of sessions to return. * @return an array of non backed up inbound group sessions. */ - fun inboundGroupSessionsToBackup(limit: Int): List + fun inboundGroupSessionsToBackup(limit: Int): List /** * Number of stored inbound group sessions. @@ -415,7 +407,7 @@ internal interface IMXCryptoStore { fun getKeyBackupRecoveryKeyInfo() : SavedKeyBackupKeyInfo? fun setUserKeysAsTrusted(userId: String, trusted: Boolean = true) - fun setDeviceTrust(userId: String, deviceId: String, crossSignedVerified: Boolean, locallyVerified: Boolean) + fun setDeviceTrust(userId: String, deviceId: String, crossSignedVerified: Boolean, locallyVerified: Boolean?) fun clearOtherUserTrust() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt index c57dff046b..17f049512c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt @@ -38,7 +38,7 @@ import im.vector.matrix.android.internal.crypto.OutgoingSecretRequest import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.model.OlmSessionWrapper import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody @@ -58,7 +58,6 @@ import im.vector.matrix.android.internal.crypto.store.db.model.DeviceInfoEntityF import im.vector.matrix.android.internal.crypto.store.db.model.GossipingEventEntity import im.vector.matrix.android.internal.crypto.store.db.model.IncomingGossipingRequestEntity import im.vector.matrix.android.internal.crypto.store.db.model.IncomingGossipingRequestEntityFields -import im.vector.matrix.android.internal.crypto.store.db.model.KeyInfoEntity import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntity import im.vector.matrix.android.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity import im.vector.matrix.android.internal.crypto.store.db.model.OlmInboundGroupSessionEntity @@ -81,7 +80,6 @@ import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.session.SessionScope import io.realm.Realm import io.realm.RealmConfiguration -import io.realm.RealmList import io.realm.Sort import io.realm.kotlin.where import org.matrix.olm.OlmAccount @@ -110,7 +108,7 @@ internal class RealmCryptoStore @Inject constructor( private val olmSessionsToRelease = HashMap() // Cache for InboundGroupSession, to release them properly - private val inboundGroupSessionToRelease = HashMap() + private val inboundGroupSessionToRelease = HashMap() private val newSessionListeners = ArrayList() @@ -235,29 +233,6 @@ internal class RealmCryptoStore @Inject constructor( return olmAccount!! } - override fun storeUserDevice(userId: String?, deviceInfo: CryptoDeviceInfo?) { - if (userId == null || deviceInfo == null) { - return - } - - doRealmTransaction(realmConfiguration) { realm -> - val user = UserEntity.getOrCreate(realm, userId) - - // Create device info - val deviceInfoEntity = CryptoMapper.mapToEntity(deviceInfo) - realm.insertOrUpdate(deviceInfoEntity) -// val deviceInfoEntity = DeviceInfoEntity.getOrCreate(it, userId, deviceInfo.deviceId).apply { -// deviceId = deviceInfo.deviceId -// identityKey = deviceInfo.identityKey() -// putDeviceInfo(deviceInfo) -// } - - if (!user.devices.contains(deviceInfoEntity)) { - user.devices.add(deviceInfoEntity) - } - } - } - override fun getUserDevice(userId: String, deviceId: String): CryptoDeviceInfo? { return doWithRealm(realmConfiguration) { it.where() @@ -656,7 +631,7 @@ internal class RealmCryptoStore @Inject constructor( .toMutableSet() } - override fun storeInboundGroupSessions(sessions: List) { + override fun storeInboundGroupSessions(sessions: List) { if (sessions.isEmpty()) { return } @@ -694,7 +669,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper? { + override fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper2? { val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionId, senderKey) // If not in cache (or not found), try to read it from realm @@ -714,10 +689,10 @@ internal class RealmCryptoStore @Inject constructor( } /** - * Note: the result will be only use to export all the keys and not to use the OlmInboundGroupSessionWrapper, + * Note: the result will be only use to export all the keys and not to use the OlmInboundGroupSessionWrapper2, * so there is no need to use or update `inboundGroupSessionToRelease` for native memory management */ - override fun getInboundGroupSessions(): MutableList { + override fun getInboundGroupSessions(): MutableList { return doWithRealm(realmConfiguration) { it.where() .findAll() @@ -789,7 +764,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List) { + override fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List) { if (olmInboundGroupSessionWrappers.isEmpty()) { return } @@ -812,7 +787,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun inboundGroupSessionsToBackup(limit: Int): List { + override fun inboundGroupSessionsToBackup(limit: Int): List { return doWithRealm(realmConfiguration) { it.where() .equalTo(OlmInboundGroupSessionEntityFields.BACKED_UP, false) @@ -1278,7 +1253,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun setDeviceTrust(userId: String, deviceId: String, crossSignedVerified: Boolean, locallyVerified: Boolean) { + override fun setDeviceTrust(userId: String, deviceId: String, crossSignedVerified: Boolean, locallyVerified: Boolean?) { doRealmTransaction(realmConfiguration) { realm -> realm.where(DeviceInfoEntity::class.java) .equalTo(DeviceInfoEntityFields.PRIMARY_KEY, DeviceInfoEntity.createPrimaryKey(userId, deviceId)) @@ -1291,7 +1266,7 @@ internal class RealmCryptoStore @Inject constructor( deviceInfoEntity.trustLevelEntity = it } } else { - trustEntity.locallyVerified = locallyVerified + locallyVerified?.let { trustEntity.locallyVerified = it } trustEntity.crossSignedVerified = crossSignedVerified } } @@ -1423,22 +1398,21 @@ internal class RealmCryptoStore @Inject constructor( } private fun addOrUpdateCrossSigningInfo(realm: Realm, userId: String, info: MXCrossSigningInfo?): CrossSigningInfoEntity? { - var existing = CrossSigningInfoEntity.get(realm, userId) if (info == null) { // Delete known if needed - existing?.deleteFromRealm() + CrossSigningInfoEntity.get(realm, userId)?.deleteFromRealm() + return null // TODO notify, we might need to untrust things? } else { // Just override existing, caller should check and untrust id needed - existing = CrossSigningInfoEntity.getOrCreate(realm, userId) - // existing.crossSigningKeys.forEach { it.deleteFromRealm() } - val xkeys = RealmList() - info.crossSigningKeys.forEach { cryptoCrossSigningKey -> - val keyEntity = crossSigningKeysMapper.map(cryptoCrossSigningKey) - xkeys.add(keyEntity) - } - existing.crossSigningKeys = xkeys + val existing = CrossSigningInfoEntity.getOrCreate(realm, userId) + existing.crossSigningKeys.forEach { it.deleteFromRealm() } + existing.crossSigningKeys.addAll( + info.crossSigningKeys.map { + crossSigningKeysMapper.map(it) + } + ) + return existing } - return existing } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt index c1897c76d9..885abb776d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -21,6 +21,8 @@ import com.squareup.moshi.Types import im.vector.matrix.android.api.extensions.tryThis import im.vector.matrix.android.api.util.JsonDict import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.store.db.mapper.CrossSigningKeysMapper import im.vector.matrix.android.internal.crypto.store.db.model.CrossSigningInfoEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.CryptoMetadataEntityFields @@ -29,6 +31,7 @@ import im.vector.matrix.android.internal.crypto.store.db.model.GossipingEventEnt import im.vector.matrix.android.internal.crypto.store.db.model.IncomingGossipingRequestEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.KeyInfoEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntityFields +import im.vector.matrix.android.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.OutgoingGossipingRequestEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.TrustLevelEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.UserEntityFields @@ -42,7 +45,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi // Version 1L added Cross Signing info persistence companion object { - const val CRYPTO_STORE_SCHEMA_VERSION = 5L + const val CRYPTO_STORE_SCHEMA_VERSION = 6L } override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { @@ -53,6 +56,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi if (oldVersion <= 2) migrateTo3(realm) if (oldVersion <= 3) migrateTo4(realm) if (oldVersion <= 4) migrateTo5(realm) + if (oldVersion <= 5) migrateTo6(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -214,6 +218,23 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi } } catch (failure: Throwable) { } + + // Migrate frozen classes + val inboundGroupSessions = realm.where("OlmInboundGroupSessionEntity").findAll() + inboundGroupSessions.forEach { dynamicObject -> + dynamicObject.getString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA)?.let { serializedObject -> + try { + deserializeFromRealm(serializedObject)?.let { oldFormat -> + val newFormat = oldFormat.exportKeys()?.let { + OlmInboundGroupSessionWrapper2(it) + } + dynamicObject.setString(OlmInboundGroupSessionEntityFields.OLM_INBOUND_GROUP_SESSION_DATA, serializeForRealm(newFormat)) + } + } catch (failure: Throwable) { + Timber.e(failure, "## OlmInboundGroupSessionEntity migration failed") + } + } + } } private fun migrateTo5(realm: DynamicRealm) { @@ -235,4 +256,22 @@ internal class RealmCryptoStoreMigration @Inject constructor(private val crossSi } } } + + // Fixes duplicate devices in UserEntity#devices + private fun migrateTo6(realm: DynamicRealm) { + val userEntities = realm.where("UserEntity").findAll() + userEntities.forEach { + try { + val deviceList = it.getList(UserEntityFields.DEVICES.`$`) + ?: return@forEach + val distinct = deviceList.distinctBy { it.getString(DeviceInfoEntityFields.DEVICE_ID) } + if (distinct.size != deviceList.size) { + deviceList.clear() + deviceList.addAll(distinct) + } + } catch (failure: Throwable) { + Timber.w(failure, "Crypto Data base migration error for migrateTo6") + } + } + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt index 763e852cd1..125fc94d1e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt @@ -16,12 +16,12 @@ package im.vector.matrix.android.internal.crypto.store.db.model -import im.vector.matrix.android.api.extensions.tryThis -import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper +import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper2 import im.vector.matrix.android.internal.crypto.store.db.deserializeFromRealm import im.vector.matrix.android.internal.crypto.store.db.serializeForRealm import io.realm.RealmObject import io.realm.annotations.PrimaryKey +import timber.log.Timber internal fun OlmInboundGroupSessionEntity.Companion.createPrimaryKey(sessionId: String?, senderKey: String?) = "$sessionId|$senderKey" @@ -36,11 +36,16 @@ internal open class OlmInboundGroupSessionEntity( var backedUp: Boolean = false) : RealmObject() { - fun getInboundGroupSession(): OlmInboundGroupSessionWrapper? { - return tryThis { deserializeFromRealm(olmInboundGroupSessionData) } + fun getInboundGroupSession(): OlmInboundGroupSessionWrapper2? { + return try { + deserializeFromRealm(olmInboundGroupSessionData) + } catch (failure: Throwable) { + Timber.e(failure, "## Deserialization failure") + return null + } } - fun putInboundGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper?) { + fun putInboundGroupSession(olmInboundGroupSessionWrapper: OlmInboundGroupSessionWrapper2?) { olmInboundGroupSessionData = serializeForRealm(olmInboundGroupSessionWrapper) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt index b20235448a..0ebfc1c4c5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt @@ -36,6 +36,7 @@ import im.vector.matrix.android.internal.session.filter.FilterModule import im.vector.matrix.android.internal.session.group.GetGroupDataWorker import im.vector.matrix.android.internal.session.group.GroupModule import im.vector.matrix.android.internal.session.homeserver.HomeServerCapabilitiesModule +import im.vector.matrix.android.internal.session.openid.OpenIdModule import im.vector.matrix.android.internal.session.profile.ProfileModule import im.vector.matrix.android.internal.session.pushers.AddHttpPusherWorker import im.vector.matrix.android.internal.session.pushers.PushersModule @@ -70,6 +71,7 @@ import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers CacheModule::class, CryptoModule::class, PushersModule::class, + OpenIdModule::class, AccountDataModule::class, ProfileModule::class, SessionAssistedInjectModule::class, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/GetOpenIdTokenTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/GetOpenIdTokenTask.kt new file mode 100644 index 0000000000..c8f394dc47 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/GetOpenIdTokenTask.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.openid + +import im.vector.matrix.android.internal.di.UserId +import im.vector.matrix.android.internal.network.executeRequest +import im.vector.matrix.android.internal.task.Task +import org.greenrobot.eventbus.EventBus +import javax.inject.Inject + +internal interface GetOpenIdTokenTask : Task + +internal class DefaultGetOpenIdTokenTask @Inject constructor( + @UserId private val userId: String, + private val openIdAPI: OpenIdAPI, + private val eventBus: EventBus) : GetOpenIdTokenTask { + + override suspend fun execute(params: Unit): RequestOpenIdTokenResponse { + return executeRequest(eventBus) { + apiCall = openIdAPI.openIdToken(userId) + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/OpenIdAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/OpenIdAPI.kt new file mode 100644 index 0000000000..ee2e85a33e --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/OpenIdAPI.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.openid + +import im.vector.matrix.android.api.util.JsonDict +import im.vector.matrix.android.internal.network.NetworkConstants +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.POST +import retrofit2.http.Path + +internal interface OpenIdAPI { + + /** + * Gets a bearer token from the homeserver that the user can + * present to a third party in order to prove their ownership + * of the Matrix account they are logged into. + * Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-user-userid-openid-request-token + * + * @param userId the user id + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/openid/request_token") + fun openIdToken(@Path("userId") userId: String, @Body body: JsonDict = emptyMap()): Call +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/OpenIdModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/OpenIdModule.kt new file mode 100644 index 0000000000..c6993167e8 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/OpenIdModule.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.openid + +import dagger.Binds +import dagger.Module +import dagger.Provides +import retrofit2.Retrofit + +@Module +internal abstract class OpenIdModule { + + @Module + companion object { + @JvmStatic + @Provides + fun providesOpenIdAPI(retrofit: Retrofit): OpenIdAPI { + return retrofit.create(OpenIdAPI::class.java) + } + } + + @Binds + abstract fun bindGetOpenIdTokenTask(task: DefaultGetOpenIdTokenTask): GetOpenIdTokenTask +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/RequestOpenIdTokenResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/RequestOpenIdTokenResponse.kt new file mode 100644 index 0000000000..4beb3fe420 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/openid/RequestOpenIdTokenResponse.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.session.openid + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class RequestOpenIdTokenResponse( + /** + * Required. An access token the consumer may use to verify the identity of the person who generated the token. + * This is given to the federation API GET /openid/userinfo to verify the user's identity. + */ + @Json(name = "access_token") + val openIdToken: String, + + /** + * Required. The string "Bearer". + */ + @Json(name = "token_type") + val tokenType: String, + + /** + * Required. The homeserver domain the consumer should use when attempting to verify the user's identity. + */ + @Json(name = "matrix_server_name") + val matrixServerName: String, + + /** + * Required. The number of seconds before this token expires and a new one must be generated. + */ + @Json(name = "expires_in") + val expiresIn: Int +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataAPI.kt index 824af2d1c3..65ec05e76e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataAPI.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.internal.session.user.accountdata import im.vector.matrix.android.internal.network.NetworkConstants import retrofit2.Call import retrofit2.http.Body -import retrofit2.http.POST import retrofit2.http.PUT import retrofit2.http.Path @@ -34,15 +33,4 @@ interface AccountDataAPI { */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/account_data/{type}") fun setAccountData(@Path("userId") userId: String, @Path("type") type: String, @Body params: Any): Call - - /** - * Gets a bearer token from the homeserver that the user can - * present to a third party in order to prove their ownership - * of the Matrix account they are logged into. - * - * @param userId the user id - * @param body the body content - */ - @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/openid/request_token") - fun openIdToken(@Path("userId") userId: String, @Body body: Map): Call> } diff --git a/matrix-sdk-android/src/main/res/values-bg/strings.xml b/matrix-sdk-android/src/main/res/values-bg/strings.xml index 2a8c087e25..ad2d2e7895 100644 --- a/matrix-sdk-android/src/main/res/values-bg/strings.xml +++ b/matrix-sdk-android/src/main/res/values-bg/strings.xml @@ -202,4 +202,12 @@ %1$s настрой %2$s като основен адрес за тази стая. %1$s премахна основния адрес за тази стая. + %1$s разреши на гости да се присъединяват в стаята. + %1$s предотврати присъединяването на гости в стаята. + + %1$s включи шифроване от-край-до-край. + %1$s включи шифроване от-край-до-край (неразпознат алгоритъм %2$s). + + %s изпрати запитване за потвърждение на ключа ви, но клиентът ви не поддържа верифициране посредством чат. Ще трябва да използвате стария метод за верифициране на ключове. + diff --git a/matrix-sdk-android/src/main/res/values-bn-rIN/strings.xml b/matrix-sdk-android/src/main/res/values-bn-rIN/strings.xml new file mode 100644 index 0000000000..4400dcd9b6 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-bn-rIN/strings.xml @@ -0,0 +1,24 @@ + + + %1$s একটি ফটো পাঠিয়েছে। + %1$s একটি স্তিকার পাঠিয়েছে। + + %s এর আমন্ত্রণ + %1$s %2$s কে আমন্ত্রণ করেছে + %1$s আপনাকে আমন্ত্রণ করেছে + %1$s রুম এ যোগ দিয়েছে + %1$s রুম ছেড়ে দিয়েছে + %1$s আমন্ত্রণ টি বাতিল করেছে + %1$s %2$s কে কিক করেছে + %1$s %2$s কে নিষিদ্ধ তালিকা থেকে মুক্ত করেছে + %1$s %2$s কে নিষিদ্ধ করেছে + %1$s %2$s এর আমন্ত্রণ ফেরত নিয়েছে + %1$s নিজের অবতার পরিবর্তন করেছে + %1$s নিজের প্রদর্শন নাম %2$s রেখেছে + %1$s নিজের প্রদর্শন নাম %2$s থেকে %3$s তে পরিবর্তন করেছে + %1$s নিজের প্রদর্শন নাম মুছে দিয়েছে (%2$s) + %1$s বিষয় টি এতে পরিবর্তন করেছে: %2$s + %1$s রুম এর নাম এতে পরিবর্তন করেছে: %2$s + %s একটি ভিডিও কল স্থাপন করেছিল। + %s একটি ভয়েস কল দিয়েছে। + diff --git a/matrix-sdk-android/src/main/res/values-fi/strings.xml b/matrix-sdk-android/src/main/res/values-fi/strings.xml index ba6ed1a58b..9487aa7db4 100644 --- a/matrix-sdk-android/src/main/res/values-fi/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fi/strings.xml @@ -5,8 +5,8 @@ Käyttäjän %s kutsu %1$s kutsui käyttäjän %2$s %1$s kutsui sinut - %1$s liittyi - %1$s poistui + %1$s liittyi huoneeseen + %1$s poistui huoneesta %1$s hylkäsi kutsun %1$s poisti käyttäjän %2$s %1$s poisti porttikiellon käyttäjältä %2$s @@ -177,8 +177,8 @@ Henkilön %1$s kutsu. Syy: %2$s %1$s kutsui henkilön %2$s. Syy: %3$s %1$s kutsui sinut. Syy: %2$s - %1$s liittyi. Syy: %2$s - %1$s poistui. Syy: %2$s + %1$s liittyi huoneeseen. Syy: %2$s + %1$s poistui huoneesta. Syy: %2$s %1$s hylkäsi kutsun. Syy: %2$s %1$s poisti käyttäjän %2$s huoneesta. Syy: %3$s %1$s poisti porttikiellon käyttäjältä %2$s. Syy: %3$s @@ -206,4 +206,7 @@ %1$s salli vieraiden liittyä huoneeseen. %1$s esti vieraita liittymästä huoneeseen. + %1$s laittoi päälle osapuolten välisen salauksen. + %1$s laittoi päälle osapuolisten välisen salauksen (tuntematon algoritmi %2$s). + diff --git a/matrix-sdk-android/src/main/res/values-fr/strings.xml b/matrix-sdk-android/src/main/res/values-fr/strings.xml index 257cb82e71..ce50359c52 100644 --- a/matrix-sdk-android/src/main/res/values-fr/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fr/strings.xml @@ -7,8 +7,8 @@ invitation de %s %1$s a invité %2$s %1$s vous a invité - %1$s a rejoint la discussion - %1$s est parti + %1$s a rejoint le salon + %1$s est parti du salon %1$s a rejeté l’invitation %1$s a expulsé %2$s %1$s a révoqué le bannissement de %2$s @@ -177,7 +177,7 @@ %1$s a invité %2$s. Raison : %3$s %1$s vous a invité. Raison : %2$s %1$s a rejoint le salon. Raison : %2$s - %1$s est parti. Raison : %2$s + %1$s est parti du salon. Raison : %2$s %1$s a refusé l’invitation. Raison : %2$s %1$s a expulsé %2$s. Raison : %3$s %1$s a révoqué le bannissement de %2$s. Raison : %3$s diff --git a/matrix-sdk-android/src/main/res/values-hu/strings.xml b/matrix-sdk-android/src/main/res/values-hu/strings.xml index 792fb309f9..a83ea5058b 100644 --- a/matrix-sdk-android/src/main/res/values-hu/strings.xml +++ b/matrix-sdk-android/src/main/res/values-hu/strings.xml @@ -6,8 +6,8 @@ %s meghívója %1$s meghívta: %2$s %1$s meghívott - %1$s csatlakozott - %1$s kilépett + %1$s belépett a szobába + %1$s kilépett a szobából %1$s elutasította a meghívást %1$s kidobta: %2$s %1$s feloldotta %2$s tiltását @@ -175,8 +175,8 @@ %1$s meghívója. Ok: %2$s %1$s meghívta őt: %2$s. Ok: %3$s %1$s meghívott. Ok: %2$s - %1$s csatlakozott. Ok: %2$s - %1$s kilépett. Ok: %2$s + %1$s belépett a szobába. Mert: %2$s + %1$s kilépett a szobából. Ok: %2$s %1$s visszautasította a meghívót. Ok: %2$s %1$s kirúgta őt: %2$s. Ok: %3$s %1$s visszaengedte őt: %2$s. Ok: %3$s diff --git a/matrix-sdk-android/src/main/res/values-it/strings.xml b/matrix-sdk-android/src/main/res/values-it/strings.xml index 8c54924d9b..9cbf1637c0 100644 --- a/matrix-sdk-android/src/main/res/values-it/strings.xml +++ b/matrix-sdk-android/src/main/res/values-it/strings.xml @@ -6,8 +6,8 @@ Invito di %s %1$s ha invitato %2$s %1$s ti ha invitato - %1$s è entrato - %1$s è uscito + %1$s è entrato nella stanza + %1$s è uscito dalla stanza %1$s ha rifiutato l\'invito %1$s ha buttato fuori %2$s %1$s ha tolto il bando a %2$s @@ -176,8 +176,8 @@ Invito di %1$s. Motivo: %2$s %1$s ha invitato %2$s. Motivo: %3$s %1$s ti ha invitato. Motivo: %2$s - %1$s è entrato. Motivo: %2$s - %1$s è uscito. Motivo: %2$s + %1$s è entrato nella stanza. Motivo: %2$s + %1$s è uscito dalla stanza. Motivo: %2$s %1$s ha rifiutato l\'invito. Motivo: %2$s %1$s ha buttato fuori %2$s. Motivo: %3$s %1$s ha riammesso %2$s. Motivo: %3$s diff --git a/matrix-sdk-android/src/main/res/values-sk/strings.xml b/matrix-sdk-android/src/main/res/values-sk/strings.xml index b729932b1f..a18cff615c 100644 --- a/matrix-sdk-android/src/main/res/values-sk/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sk/strings.xml @@ -174,4 +174,18 @@ Vymazať správy na odoslanie %1$s zamietol pozvanie používateľa %2$s vstúpiť do miestnosti + Pozvanie od používateľa %1$s. Dôvod: %2$s + %1$s pozval používateľa %2$s. Dôvod: %3$s + %1$s vás pozval. Dôvod: %2$s + %1$s sa pridal. Dôvod: %2$s + Používateľ %1$s odišiel. Dôvod: %2$s + %1$s odmietol pozvanie. Dôvod: %2$s + %1$s vyhodil používateľa %2$s. Dôvod: %3$s + %1$s znovu pridaný používateľom %2$s. Dôvod: %3$s + %1$s vyhodil %2$s. Dôvod: %3$s + %1$s poslal pozvánku používateľovi %2$s, aby sa pripojil na miestnosť. Dôvod: %3$s + %1$s odvolal pozvánku pre používateľa %2$s, aby sa pripojil na miestnosť. Dôvod: %3$s + %1$s prijal pozvanie od používateľa %2$s. Dôvod: %3$s + %1$s odoprel pozvánku používateľa %2$s. Dôvod: %3$s + diff --git a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml index 7b2f3563a2..0796c0c7dd 100644 --- a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml +++ b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml @@ -6,8 +6,8 @@ %s 的邀請 %1$s 邀請了 %2$s %1$s 邀請您 - %1$s 已加入 - %1$s 已離開 + %1$s 已加入聊天室 + %1$s 已離開聊天室 %1$s 拒絕邀請 %1$s 踢出 %2$s %1$s 解除禁止 %2$s @@ -174,8 +174,8 @@ %1$s 的邀請。理由:%2$s %1$s 邀請了 %2$s。理由:%3$s %1$s 邀請了您。理由:%2$s - %1$s 已加入。理由:%2$s - %1$s 已離開。理由:%2$s + %1$s 已加入聊天室。理由:%2$s + %1$s 已離開聊天室。理由:%2$s %1$s 已回絕邀請。理由:%2$s %1$s 踢走了 %2$s。理由:%3$s %1$s 取消封鎖了 %2$s。理由:%3$s diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml index de70b21695..50169fd982 100644 --- a/matrix-sdk-android/src/main/res/values/strings.xml +++ b/matrix-sdk-android/src/main/res/values/strings.xml @@ -7,8 +7,8 @@ %s\'s invitation %1$s invited %2$s %1$s invited you - %1$s joined - %1$s left + %1$s joined the room + %1$s left the room %1$s rejected the invitation %1$s kicked %2$s %1$s unbanned %2$s @@ -246,8 +246,8 @@ %1$s\'s invitation. Reason: %2$s %1$s invited %2$s. Reason: %3$s %1$s invited you. Reason: %2$s - %1$s joined. Reason: %2$s - %1$s left. Reason: %2$s + %1$s joined the room. Reason: %2$s + %1$s left the room. Reason: %2$s %1$s rejected the invitation. Reason: %2$s %1$s kicked %2$s. Reason: %3$s %1$s unbanned %2$s. Reason: %3$s diff --git a/tools/release/sign_apk_unsafe.sh b/tools/release/sign_apk_unsafe.sh index 022f3618eb..bf021e8345 100755 --- a/tools/release/sign_apk_unsafe.sh +++ b/tools/release/sign_apk_unsafe.sh @@ -23,7 +23,7 @@ PARAM_KS_PASS=$3 PARAM_KEY_PASS=$4 # Other params -BUILD_TOOLS_VERSION="28.0.3" +BUILD_TOOLS_VERSION="29.0.3" MIN_SDK_VERSION=19 echo "Signing APK with build-tools version ${BUILD_TOOLS_VERSION} for min SDK version ${MIN_SDK_VERSION}..." diff --git a/vector/build.gradle b/vector/build.gradle index 69608cf712..459b297fd6 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -15,7 +15,7 @@ androidExtensions { } ext.versionMajor = 0 -ext.versionMinor = 19 +ext.versionMinor = 20 ext.versionPatch = 0 static def getGitTimestamp() { diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt index 0947c144d8..e334603b74 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt @@ -15,7 +15,6 @@ */ package im.vector.riotx.features.crypto.keysbackup.restore -import android.content.Context import android.os.Bundle import android.text.Editable import android.text.SpannableString @@ -70,7 +69,7 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase mPassphraseInputLayout.error = newValue }) - helperTextWithLink.text = spannableStringForHelperText(context!!) + helperTextWithLink.text = spannableStringForHelperText() viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer { val shouldBeVisible = it ?: false @@ -87,9 +86,9 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase } } - private fun spannableStringForHelperText(context: Context): SpannableString { - val clickableText = context.getString(R.string.keys_backup_restore_use_recovery_key) - val helperText = context.getString(R.string.keys_backup_restore_with_passphrase_helper_with_link, clickableText) + private fun spannableStringForHelperText(): SpannableString { + val clickableText = getString(R.string.keys_backup_restore_use_recovery_key) + val helperText = getString(R.string.keys_backup_restore_with_passphrase_helper_with_link, clickableText) val spanString = SpannableString(helperText) @@ -117,7 +116,7 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase fun onRestoreBackup() { val value = viewModel.passphrase.value if (value.isNullOrBlank()) { - viewModel.passphraseErrorText.value = context?.getString(R.string.passphrase_empty_error_message) + viewModel.passphraseErrorText.value = getString(R.string.passphrase_empty_error_message) } else { viewModel.recoverKeys(sharedViewModel) } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt index 46e8d5fa18..9c9c12b824 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt @@ -51,7 +51,7 @@ class KeysBackupRestoreFromPassphraseViewModel @Inject constructor( try { sharedViewModel.recoverUsingBackupPass(passphrase.value!!) } catch (failure: Throwable) { - passphraseErrorText.value = stringProvider.getString(R.string.keys_backup_passphrase_error_decrypt) + passphraseErrorText.postValue(stringProvider.getString(R.string.keys_backup_passphrase_error_decrypt)) } } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt index 377fc5ab4a..03c273800a 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt @@ -18,6 +18,7 @@ package im.vector.riotx.features.home.room.detail.timeline.factory 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.room.model.create.RoomCreateContent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import im.vector.matrix.android.internal.crypto.model.event.EncryptionEventContent @@ -43,6 +44,9 @@ class MergedHeaderItemFactory @Inject constructor(private val sessionHolder: Act private val collapsedEventIds = linkedSetOf() private val mergeItemCollapseStates = HashMap() + /** + * Note: nextEvent is an older event than event + */ fun create(event: TimelineEvent, nextEvent: TimelineEvent?, items: List, @@ -52,7 +56,8 @@ class MergedHeaderItemFactory @Inject constructor(private val sessionHolder: Act callback: TimelineEventController.Callback?, requestModelBuild: () -> Unit) : BasedMergedItem<*>? { - return if (nextEvent?.root?.getClearType() == EventType.STATE_ROOM_CREATE && event.isRoomConfiguration()) { + return if (nextEvent?.root?.getClearType() == EventType.STATE_ROOM_CREATE + && event.isRoomConfiguration(nextEvent.root.getClearContent()?.toModel()?.creator)) { // It's the first item before room.create // Collapse all room configuration events buildRoomCreationMergedSummary(currentPosition, items, event, eventIdToHighlight, requestModelBuild, callback) @@ -127,7 +132,7 @@ class MergedHeaderItemFactory @Inject constructor(private val sessionHolder: Act val mergedEvents = ArrayList().also { it.add(event) } var hasEncryption = false var encryptionAlgorithm: String? = null - while (prevEvent != null && prevEvent.isRoomConfiguration()) { + while (prevEvent != null && prevEvent.isRoomConfiguration(null)) { if (prevEvent.root.getClearType() == EventType.STATE_ROOM_ENCRYPTION) { hasEncryption = true encryptionAlgorithm = prevEvent.root.getClearContent()?.toModel()?.algorithm diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index 6b44b9f3d3..695da73f89 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -25,6 +25,7 @@ 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.model.ReferencesAggregatedContent import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent +import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent import im.vector.matrix.android.api.session.room.timeline.hasBeenEdited @@ -123,7 +124,9 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses } private fun getE2EDecoration(room: Room?, event: TimelineEvent): E2EDecoration { - return if (room?.isEncrypted() == true + return if ( + event.root.sendState == SendState.SYNCED + && room?.isEncrypted() == true // is user verified && session.cryptoService().crossSigningService().getUserCrossSigningKeys(event.root.senderId ?: "")?.isTrusted() == true) { val ts = room.roomSummary()?.encryptionEventTs ?: 0 diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt index 1ea3cd64ac..f1106d276e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt @@ -50,14 +50,23 @@ fun TimelineEvent.canBeMerged(): Boolean { return root.getClearType() == EventType.STATE_ROOM_MEMBER } -fun TimelineEvent.isRoomConfiguration(): Boolean { +fun TimelineEvent.isRoomConfiguration(roomCreatorUserId: String?): Boolean { return when (root.getClearType()) { EventType.STATE_ROOM_GUEST_ACCESS, EventType.STATE_ROOM_HISTORY_VISIBILITY, EventType.STATE_ROOM_JOIN_RULES, - EventType.STATE_ROOM_MEMBER, EventType.STATE_ROOM_NAME, + EventType.STATE_ROOM_TOPIC, + EventType.STATE_ROOM_AVATAR, + EventType.STATE_ROOM_ALIASES, + EventType.STATE_ROOM_CANONICAL_ALIAS, + EventType.STATE_ROOM_POWER_LEVELS, EventType.STATE_ROOM_ENCRYPTION -> true + EventType.STATE_ROOM_MEMBER -> { + // Keep only room member events regarding the room creator (when he joined the room), + // but exclude events where the room creator invite others, or where others join + roomCreatorUserId != null && root.stateKey == roomCreatorUserId + } else -> false } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt index 81050194a8..3985b3856b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt @@ -43,7 +43,8 @@ abstract class MergedRoomCreationItem : BasedMergedItem Obnovit - Neověřené přihlášení. Byli jste to Vy\? + Nové přihlášení. Byli jste to Vy\? Klepněte pro přehled & ověření Použijte tuto relaci k ověření relace nové, a tím ji udělíte přístup k zašifrovaným zprávám. To jsem nebyl(a) já diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index f6011555f8..c452fbc901 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -1783,10 +1783,10 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Eine Textnachricht wurde an %s gesendet. Bitte gebe den Verifizierungscode ein, den sie enthält. Aktiviere ausführliche Logs. - Gesprächige Logs wird den Entwicklern helfen indem sie mehr Informationen enthalten, wenn du einen Fehlerbericht sendest. Auch wenn dies aktiviert ist, werden keine Nachrichteninhalte oder andere privaten Daten aufgezeichnet. + Ausführliche Logs werden den Entwicklern helfen, indem sie mehr Informationen enthalten, wenn du einen Fehlerbericht sendest. Auch wenn dies aktiviert ist, werden keine Nachrichteninhalte oder andere privaten Daten aufgezeichnet. - Bitte erneut versuchen, nachdem du die Nutzungsbedingungendeines Home-Servers akzeptiert hast. + Bitte erneut versuchen, nachdem du die Nutzungsbedingungen deines Home-Servers akzeptiert hast. Bei Benutzung könnten Cookies gesetzt werden und es könnten Daten mit %s geteilt werden: Bei Benutzung könnten Daten mit %s geteilt werden: @@ -2280,7 +2280,7 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Neu laden - Neue Sitzung + Neue Anmeldung. Warst du das\? Tippe für eine Überprüfung & Verifikation Benutze diese Sitzung um deine neue zu verfizieren, damit sie auf verschlüsselte Nachrichten zugreifen kann. Das war ich nicht @@ -2346,4 +2346,12 @@ Verwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie eine Inkorrekter Benutzername und/oder Passwort. Das eingegebene Passwort beginnt oder endet mit Leerzeichen, bitte kontrolliere es. + Nachrichtenschlüssel + Kontopasswort + + Wiederherstellungs-Passphrase + Druck es aus und speichere es an einem sicheren Ort + Kopier es in deinen persönlichen Cloud-Speicher + + Verschlüsselung ist nicht aktiviert diff --git a/vector/src/main/res/values-fi/strings.xml b/vector/src/main/res/values-fi/strings.xml index 8215a9966f..d044bb5c1a 100644 --- a/vector/src/main/res/values-fi/strings.xml +++ b/vector/src/main/res/values-fi/strings.xml @@ -2052,4 +2052,27 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Poistutaan huoneesta… Käyttäjätunnus + Synkronoidaan tietoja ensimmäistä kertaa… + + Kehittäjämoodi + Kehittäjämoodi aktivoi piilotettuja ominaisuuksia, mutta voi tehdä sovelluksesta epävakaan. Vain kehittäjille! + Raivoravistus + Tunnistusraja + Ravista puhelintasi testataksesi tunnistusrajan + Ravistus tunnistettu! + Näytetään vain ensimmäiset tulokset, kirjoita lisää kirjaimia… + + RiotX voi kaatuilla tavallista useammin odottamattomien virheiden vuoksi + + Lisää ¯\\_(ツ)_/¯ tavallisen viestin alkuun + + Käyttämäsi sähköpostipalvelun ei ole sallittu rekisteröityä tälle palvelimelle + + Täsmäävät + Eivät täsmää + Vahvista käyttäjä tarkastamalla että seuraavat emojit vastaavat täysin heidän ruudullaan näkyviä. + Jos haluat kovaa tietoturvaa, käytä jotain toista luotettavaa viestintävälinettä tai tee toisen henkilön ollessa paikalla. + Ei turvallinen + Video. + Kuva. diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index 79429ad261..190d781f2a 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -145,7 +145,7 @@ Ne contient pas de JSON valide Liste des accusés de lecture - "Envoyer en " + Envoyer en Original Grand Moyen @@ -407,7 +407,7 @@ Importer les clés des salons Importer Chiffrer uniquement vers les sessions vérifiées - NON vérifié + Non vérifié Vérifié Sur liste noire @@ -473,7 +473,7 @@ Annuler l’envoi ? %d s - %1$dm %2$ds + %1$d min %2$d s Quitter Citer @@ -484,13 +484,13 @@ Veuillez autoriser l’accès dans la prochaine fenêtre contextuelle pour pouvoir envoyer des fichiers depuis votre téléphone. Riot a besoin d’accéder à votre appareil photo pour prendre des photos et passer des appels vidéo. - - -Veuillez autoriser l’accès dans la prochaine fenêtre contextuelle pour pouvoir effectuer l’appel. + " +\n +\nVeuillez autoriser l’accès dans la prochaine fenêtre contextuelle pour pouvoir effectuer l’appel." Riot a besoin d’accéder à votre microphone pour passer des appels audio. - - -Veuillez autoriser l’accès dans la prochaine fenêtre contextuelle pour pouvoir effectuer l’appel. + " +\n +\nVeuillez autoriser l’accès dans la prochaine fenêtre contextuelle pour pouvoir effectuer l’appel." Riot a besoin d’accéder à votre appareil photo et à votre microphone pour passer des appels vidéo. Veuillez autoriser l’accès dans les prochaines fenêtres contextuelles pour pouvoir effectuer l’appel. @@ -602,8 +602,8 @@ Attention : ce fichier peut être supprimé si l’application est désinstallé Importer les clés à partir d’un fichier local Ne jamais envoyer de messages chiffrés aux sessions non vérifiées depuis cette session. - Pour vérifier que cette session est fiable, contactez son propriétaire en utilisant un autre moyen (par ex. en personne ou par téléphone) et demandez-lui si la clé qu’il voit dans ses paramètres utilisateur pour cette session correspond à la clé ci-dessous : - Si elle correspond, appuyez sur le bouton « Vérifier » ci-dessous. Si ce n’est pas le cas, quelqu’un d’autre intercepte cette session et vous devriez probablement le bloquer. À l’avenir, ce processus de vérification sera plus évolué. + Confirmez en comparant les informations suivantes avec les paramètres utilisateur dans votre autre session : + Si elles ne correspondent pas, la sécurité de votre communication est peut-être compromise. Je confirme que les clés correspondent Riot prend désormais en charge le chiffrement de bout en bout, mais vous devez vous reconnecter pour l’activer. @@ -2136,7 +2136,7 @@ Si vous n’avez pas configuré de nouvelle méthode de récupération, un attaq Sessions actives Afficher toutes les sessions Gérer les sessions - Déconnecter cette session + Se déconnecter de cette session Aucune information cryptographique n’est disponible @@ -2192,7 +2192,7 @@ Si vous n’avez pas configuré de nouvelle méthode de récupération, un attaq Option sélectionnée Crée un sondage simple - Utiliser une méthode de récupération + Utiliser une phrase secrète ou une clé de récupération Si vous n’avez pas accès à une session existante Nouvelle connexion @@ -2227,7 +2227,7 @@ Si vous n’avez pas configuré de nouvelle méthode de récupération, un attaq Actualiser - Connexion non vérifiée. Était-ce vous \? + Nouvelle connexion. Était-ce vous \? Appuyer pour examiner et vérifier Utilisez cette session pour vérifiez la nouvelle, ce qui lui permettra d’avoir accès aux messages chiffrés. Ce n’était pas moi @@ -2358,4 +2358,39 @@ Si vous n’avez pas configuré de nouvelle méthode de récupération, un attaq Impossible d’ajouter le fichier multimédia à la galerie Définir un nouveau mot de passe de compte… + Utilisez la dernière version de Riot sur vos autres appareils : Riot Web, Riot pour Bureau, Riot iOS, RiotX pour Android, ou un autre client Matrix qui prend en charge la signature croisée + Riot Web +\nRiot pour Bureau + Riot iOS +\nRiot X pour Android + ou un autre client Matrix qui prend en charge la signature croisée + Utilisez la dernière version de Riot sur vos autre appareils : + Force la session de groupe sortante actuelle dans un salon chiffré à être abandonnée + Seulement pris en charge dans les salons chiffrés + Utilisez votre %1$s ou votre %2$s pour continuer. + Utiliser la clé de récupération + Sélectionnez votre clé de récupération ou saisissez-la manuellement avec le clavier ou en la copiant depuis le presse-papiers + La sauvegarde n’a pas pu être déchiffrée avec cette clé de récupération : veuillez vérifier que vous avez saisi la bonne clé de récupération. + Échec d’accès au coffre secret + + Vérifier manuellement avec un texte + Vérifier la connexion + Vérifier de façon interactive avec des émojis + Confirmez votre identité en vérifiant cette connexion depuis une de vos autres sessions, ce qui lui permettra d’avoir accès à vos messages chiffrés. + Marquer comme fiable + + Veuillez choisir un nom d’utilisateur. + Veuillez choisir un mot de passe. + Vérifiez ce lien + Le lien %1$s vous emmène à un autre site : %2$s. +\n +\nVoulez-vous vraiment continuer \? + + Nous n’avons pas pu créer votre conversation directe. Vérifiez les utilisateurs que vous souhaitez inviter et réessayez. + Non chiffré + Chiffré par un appareil non vérifié + Vérifiez où vous vous êtes connecté + Vérifiez toutes les sessions pour vous assurer que votre compte et vos messages sont en sécurité + Vérifiez la nouvelle connexion accédant à votre compte : %1$s + diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index 929d916c92..ca32ce03f2 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -2222,7 +2222,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Frissítés - Ismeretlen bejelentkezés. Ez te vagy\? + Új bejelentkezés. Ez te vagy\? A megtekintéshez és ellenőrzéshez koppints Az új munkamenet ellenőrzéséhez használd ezt, amivel hozzáférést adsz a titkosított üzenetekhez. Nem én voltam @@ -2353,4 +2353,33 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró A média fájlt nem sikerült hozzáadni a Galériához Új fiók jelszó beállítása… + Riot Web +\nRiot Desktop + Riot iOS +\nRiot X for Android + vagy másik eszközök közötti hitelesítésre alkalmas Matrix kliensre + A Riot legújabb kliensét használd a többi eszközödön: + A jelenlegi csoport munkamenet törlését kikényszeríti a titkosított szobában + Csak a titkosított szobákban támogatott + Használd ezt: %1$s vagy ezt: %2$s a továbblépéshez. + Használd a Visszaállítási Kulcsot + Válaszd ki a Visszaállítási Kulcsot, add meg kézzel vagy másold be a vágólapról + Ezzel a Visszaállítási Kulccsal a mentést nem lehet visszafejteni: kérlek ellenőrizd, hogy a visszaállítási kulcsot jól adtad-e meg. + A biztonsági tárolóhoz nem sikerült hozzáférni + + Titkosítatlan + Ellenőrizetlen eszközzel titkosította + Tekintsd át hol vagy bejelentkezve + Ellenőrizd minden munkamenetedet, hogy a fiókod és az üzeneteid biztonságban legyenek + Ellenőrizd ezt az új bejelentkezést ami hozzáfér a fiókodhoz: %1$s + + Manuális szöveges ellenőrzés + Belépés ellenőrzése + Közös ellenőrzés Emodzsival + Megbízhatónak jelölés + + Kérlek válasz felhasználói nevet. + Kérlek válassz jelszót. + Ezt a hivatkozást ellenőrizd le még egyszer + A közvetlen üzenetedet nem sikerült elkészíteni. Ellenőrizd azokat a felhasználókat akiket meg szeretnél hívni és próbáld újra. diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index 337966551d..25c23b6b5f 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -668,8 +668,8 @@ Togli dalla lista nera Verifica la sessione - Per verificare se questa sessione sia affidabile, contatta il suo proprietario utilizzando altre vie di comunicazione (es. di persona o per telefono) e chiedigli se la chiave che vede nelle Impostazioni Utente per questa sessione corrisponde a quella riportata sotto: - Se corrisponde, premi il pulsante di verifica qui sotto. In caso contrario, qualcun altro sta intercettando questa sessione e probabilmente dovresti metterlo in lista nera. In futuro il processo di verifica sarà più sofisticato. + Conferma confrontando la seguente con le impostazioni utente della tua altra sessione: + Se non corrispondono, la sicurezza delle tue comunicazioni potrebbe essere compromessa. Ho verificato che le chiavi corrispondono Riot supporta ora la crittografia da-utente-a-utente, ma per abilitarla devi riconnetterti. @@ -2193,7 +2193,7 @@ %d sessioni attive - Verifica questa sessione + Verifica questo accesso Gli altri utenti potrebbero non fidarsi Completa la sicurezza @@ -2237,7 +2237,7 @@ Opzione selezionata Crea un semplice sondaggio - Usa un metodo di recupero + Usa una password o chiave di recupero Se non puoi accedere a una sessione esistente Nuovo accesso @@ -2272,7 +2272,7 @@ Ricarica - Accesso non verificato. Eri tu\? + Nuovo accesso. Eri tu\? Tocca per controllare e verificare Usa questa sessione per verificare quella nuova, dandole l\'accesso ai messaggi cifrati. Non ero io @@ -2403,4 +2403,39 @@ Impossibile aggiungere il file multimediale alla galleria Imposta una nuova password dell\'account… + Usa l\'ultima versione di Riot sui tuoi altri dispositivi, Riot Web, Riot Desktop, Riot iOS, RiotX per Android o un altro client Matrix che supporti la firma incrociata + Riot Web +\nRiot Desktop + Riot iOS +\nRiot X per Android + o un altro client Matrix che supporti la firma incrociata + Usa l\'ultimo Riot sui tuoi altri dispositivi: + Forza l\'attuale sessione di gruppo in uscita in una stanza cifrata ad essere scartata + Supportato solo nelle stanze cifrate + Usa la tua %1$s o la %2$s per continuare. + Usa la chiave di recupero + Seleziona la tua chiave di recupero, oppure inseriscila a mano digitandola o incollando dagli appunti + Impossibile decifrare il backup con questa chiave di recupero: verifica di avere inserito la chiave giusta. + Accesso all\'archivio sicuro fallito + + Non cifrato + Cifrato da un dispositivo non verificato + Controlla dove hai fatto l\'accesso + Verifica tutte le tue sessioni per assicurarti che il tuo account e i messaggi siano protetti + Verifica il nuovo accesso entrando nel tuo account: %1$s + + Verifica manualmente con testo + Verifica accesso + Verifica interattivamente con emoji + Conferma la tua identità verificando questo accesso da una delle tua altre sessioni, dandole l\'accesso ai messaggi cifrati. + Segna come fidato + + Scegli un nome utente. + Scegli una password. + Verifica questo collegamento + Il collegamento %1$s ti sta portando ad un altro sito: %2$s. +\n +\nSei sicuro di volere continuare\? + + Impossibile creare il messaggio diretto. Controlla gli utenti che vuoi invitare e riprova. diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index 418af4d98e..014a8ae65c 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -632,7 +632,7 @@ Шифровать только для проверенных сессий Не отправлять зашифрованные сообщения непроверенным сессиям с этой сессии. - НЕ проверено + Не проверено Проверено В черном списке @@ -1450,12 +1450,12 @@ %1$s: 1 сообщение %1$s: %2$d сообщения - %1$s: %2$d сообщения + %1$s: %2$d сообщений %d оповещение %d оповещения - %d оповещения + %d оповещений Новое событие diff --git a/vector/src/main/res/values-sk/strings.xml b/vector/src/main/res/values-sk/strings.xml index 5dd0fcc0da..9fc9bb8ffe 100644 --- a/vector/src/main/res/values-sk/strings.xml +++ b/vector/src/main/res/values-sk/strings.xml @@ -7,7 +7,7 @@ Tmavý vzhľad Čierny vzhľad - Synchronizácia… + Prebieha synchronizácia… Spracovanie udalostí Správy @@ -1306,4 +1306,27 @@ Objavte skutočne výkonné možnosti otvorenej spolupráce s Riot.im! Prosím zadajte meno používateľa. Overiť zariadenie + Latn + + Žiadny + Zrušiť + Odpojiť sa + Náhlad + Odmietnuť + + Nebol nakonfigurovaný overovací server. + + Hovor zlyhal kvôli zle nakonfigurovanému serveru + Prosím, požiadajte administrátora vášho homeserveru (%1$s) o konfiguráciu TURN serveru, aby hovory fungovali spoľahlivo. +\n +\nPrípadně môžete skúsiť použiť verejný server %2$s, ale nebude tak spoľahlivý a bude zdielať vašu IP adresu s týmto serverom. V nastaveniach sa to dá zmeniť. + Skúste použiť %s + Viac sa nepýtať + + Nastavte e-mail na obnovenie účtu a voliteľne aby ho neskôr ľudia, ktorí vás poznajú, mohli nájsť. + Nastavte telefónne číslo, aby neskôr bolo voliteľne k nájdeniu ľuďmi, ktorí Vás poznajú. + Nastavte e-mail na obnovenie účtu. Použite e-mail alebo telefónne číslo voliteľne neskôr, aby ich našli ľudia, ktorí vás poznajú. + Nastavte e-mail na obnovenie účtu. Použite e-mail alebo telefónne číslo voliteľne neskôr, aby ich našli ľudia, ktorí vás poznajú. + Toto nie je platná adresa Matrix serveru + Homeserver nie je dostupný na tomto URL, prosím, preverte diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index 86dc7333e4..2bc18012c2 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -218,7 +218,7 @@ 群組清單 - "傳送為 " + 傳送為 原始 @@ -258,13 +258,13 @@ 請在下個彈跳視窗允許存取,來從手機傳送檔案。 Riot 需要權限存取您的相機,來拍照與視訊通話。 - - -為了要通話,請在下個彈跳視窗中允許存取。 + " +\n +\n為了要通話,請在下個彈跳視窗中允許存取。" Riot 需要權限來存取麥克風,來撥打語音通話。 - - -為了要通話,請在下個彈跳視窗中允許存取。 + " +\n +\n為了要通話,請在下個彈跳視窗中允許存取。" Riot 需要權限來存取相機及麥克風來撥打視訊通話。 為了要通話,請在下個彈跳視窗中允許存取。 @@ -736,8 +736,8 @@ 解除黑名單 驗證工作階段 - 要驗證此工作階段是否可信,請使用其他方式(例如:面對面或是打電話)聯絡它的擁有者並詢問他們在使用者設定中看到此工作階段的金鑰是否與下列的金鑰相符: - 如果符合的話,請按下方的驗證按鈕。如果沒有的話,那麼其他地方的某個人可能正在攔截此工作階段,您應該將其列入黑名單。未來,這個驗證程序會變得更加複雜。 + 透過將以下內容與您的其他工作階段中的使用者設定來確認: + 如果不符合的話,您的通訊安全可能正受到威脅。 我驗證金鑰相符 Riot 目前支援端到端加密,但您需要重新登入以啟用。 @@ -915,7 +915,7 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 目前 %1$s %1$s %2$s 前 - %1$s, + "%1$s, " %1$s 與 %2$s %1$s %2$s @@ -2093,7 +2093,7 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 %d 活躍的工作階段 - 驗證此工作階段 + 驗證此登入 其他使用者可能不會信任它 全面的安全性 @@ -2135,7 +2135,7 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 已選取的選項 建立簡易投票 - 使用復原方法 + 使用復原通關密語或金鑰 如果您無法存取既有的工作階段的話 新登入 @@ -2169,7 +2169,7 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 重新整理 - 未驗證的登入。是您嗎? + 新登入。是您嗎? 輕觸即可以審閱並驗證 使用此工作階段來驗證新的,讓它可以存取已加密的訊息。 這不是我 @@ -2300,4 +2300,39 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 無法新增媒體檔案到媒體庫中 設定新的帳號密碼…… + 在您的其他裝置上使用最新的 Riot、Riot Web、Riot 桌面版、Riot iOS、RiotX for Android 或其他有交叉簽章功能的 Matrix 客戶端 + Riot Web +\nRiot 桌面版 + Riot iOS +\nRiot X for Android + 或其他有交叉簽章功能的 Matrix 客戶端 + 在您的其他裝置上使用最新的 Riot: + 強制丟棄目前在加密聊天室中的外發群組工作階段 + 僅在加密聊天室中支援 + 使用您的 %1$s 或使用您的 %2$s 以繼續。 + 使用復原金鑰 + 選取您的復原金鑰,或是透過打字或從您的剪貼簿貼上來手動輸入 + 無法使用此復原金鑰解密備份:請驗證您是否輸入了正確的復原金鑰。 + 存取安全儲存空間失敗 + + 透過文字手動驗證 + 驗證登入 + 透過顏文字來進行互動驗證 + 從您的其他工作階段驗證此登入以確認您的身份並授予存取加密訊息的權限。 + 標記為受信任 + + 請選擇使用者名稱。 + 請選擇密碼。 + 仔細檢查此連結 + 連結 %1$s 正在將您帶往其他網站:%2$s。 +\n +\n您確定您想要繼續嗎? + + 我們無法建立您的直接訊息。請檢查您想要邀請的使用者,然後再試一次。 + 未加密 + 由未驗證的裝置加密 + 審閱您從何處登入 + 驗證您所有的工作階段以確保您的帳號與訊息都安全 + 驗證正在存取您帳號的新登入:%1$s +