Merge pull request #1060 from vector-im/feature/data_class_cleanup

Data class cleanup
This commit is contained in:
Benoit Marty 2020-02-26 10:57:10 +01:00 committed by GitHub
commit 40b4db4a64
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
78 changed files with 956 additions and 1011 deletions

View file

@ -38,9 +38,7 @@ class AccountCreationTest : InstrumentedTest {
fun createAccountTest() {
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
commonTestHelper.signout(session)
session.close()
commonTestHelper.signOutAndClose(session)
}
@Test
@ -50,14 +48,14 @@ class AccountCreationTest : InstrumentedTest {
// Log again to the same account
val session2 = commonTestHelper.logIntoAccount(session.myUserId, SessionTestParams(withInitialSync = true))
session.close()
session2.close()
commonTestHelper.signOutAndClose(session)
commonTestHelper.signOutAndClose(session2)
}
@Test
fun simpleE2eTest() {
val res = cryptoTestHelper.doE2ETestWithAliceInARoom()
res.close()
res.cleanUp(commonTestHelper)
}
}

View file

@ -28,7 +28,10 @@ import im.vector.matrix.android.api.auth.data.LoginFlowResult
import im.vector.matrix.android.api.auth.registration.RegistrationResult
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.LocalEcho
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.message.MessageContent
import im.vector.matrix.android.api.session.room.timeline.Timeline
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.api.session.room.timeline.TimelineSettings
@ -113,7 +116,7 @@ class CommonTestHelper(context: Context) {
fun sendTextMessage(room: Room, message: String, nbOfMessages: Int): List<TimelineEvent> {
val sentEvents = ArrayList<TimelineEvent>(nbOfMessages)
val latch = CountDownLatch(nbOfMessages)
val onEventSentListener = object : Timeline.Listener {
val timelineListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) {
}
@ -122,20 +125,26 @@ class CommonTestHelper(context: Context) {
}
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
// TODO Count only new messages?
if (snapshot.count { it.root.type == EventType.MESSAGE } == nbOfMessages) {
sentEvents.addAll(snapshot.filter { it.root.type == EventType.MESSAGE })
val newMessages = snapshot
.filter { LocalEcho.isLocalEchoId(it.eventId).not() }
.filter { it.root.getClearType() == EventType.MESSAGE }
.filter { it.root.getClearContent().toModel<MessageContent>()?.body?.startsWith(message) == true }
if (newMessages.size == nbOfMessages) {
sentEvents.addAll(newMessages)
latch.countDown()
}
}
}
val timeline = room.createTimeline(null, TimelineSettings(10))
timeline.addListener(onEventSentListener)
timeline.start()
timeline.addListener(timelineListener)
for (i in 0 until nbOfMessages) {
room.sendTextMessage(message + " #" + (i + 1))
}
await(latch)
timeline.removeListener(onEventSentListener)
timeline.removeListener(timelineListener)
timeline.dispose()
// Check that all events has been created
assertEquals(nbOfMessages.toLong(), sentEvents.size.toLong())
@ -283,11 +292,10 @@ class CommonTestHelper(context: Context) {
/**
* Clear all provided sessions
*/
fun Iterable<Session>.close() = forEach { it.close() }
fun Iterable<Session>.signOutAndClose() = forEach { signOutAndClose(it) }
fun signout(session: Session) {
val lock = CountDownLatch(1)
session.signOut(true, TestMatrixCallback(lock))
await(lock)
fun signOutAndClose(session: Session) {
doSync<Unit> { session.signOut(true, it) }
session.close()
}
}

View file

@ -23,9 +23,9 @@ data class CryptoTestData(val firstSession: Session,
val secondSession: Session? = null,
val thirdSession: Session? = null) {
fun close() {
firstSession.close()
secondSession?.close()
secondSession?.close()
fun cleanUp(testHelper: CommonTestHelper) {
testHelper.signOutAndClose(firstSession)
secondSession?.let { testHelper.signOutAndClose(it) }
thirdSession?.let { testHelper.signOutAndClose(it) }
}
}

View file

@ -41,16 +41,15 @@ import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import java.util.Arrays
import java.util.HashMap
import java.util.concurrent.CountDownLatch
class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
val messagesFromAlice: List<String> = Arrays.asList("0 - Hello I'm Alice!", "4 - Go!")
val messagesFromBob: List<String> = Arrays.asList("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.")
private val messagesFromAlice: List<String> = listOf("0 - Hello I'm Alice!", "4 - Go!")
private val messagesFromBob: List<String> = listOf("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.")
val defaultSessionParams = SessionTestParams(true)
private val defaultSessionParams = SessionTestParams(true)
/**
* @return alice session
@ -58,34 +57,23 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
fun doE2ETestWithAliceInARoom(): CryptoTestData {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
var roomId: String? = null
val lock1 = CountDownLatch(1)
val roomId = mTestHelper.doSync<String> {
aliceSession.createRoom(CreateRoomParams(name = "MyRoom"), it)
}
aliceSession.createRoom(CreateRoomParams(name = "MyRoom"), object : TestMatrixCallback<String>(lock1) {
override fun onSuccess(data: String) {
roomId = data
super.onSuccess(data)
}
})
val room = aliceSession.getRoom(roomId)!!
mTestHelper.await(lock1)
assertNotNull(roomId)
mTestHelper.doSync<Unit> {
room.enableEncryption(callback = it)
}
val room = aliceSession.getRoom(roomId!!)!!
val lock2 = CountDownLatch(1)
room.enableEncryption(callback = TestMatrixCallback(lock2))
mTestHelper.await(lock2)
return CryptoTestData(aliceSession, roomId!!)
return CryptoTestData(aliceSession, roomId)
}
/**
* @return alice and bob sessions
*/
fun doE2ETestWithAliceAndBobInARoom(): CryptoTestData {
val statuses = HashMap<String, String>()
val cryptoTestData = doE2ETestWithAliceInARoom()
val aliceSession = cryptoTestData.firstSession
val aliceRoomId = cryptoTestData.roomId
@ -94,7 +82,7 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams)
val lock1 = CountDownLatch(2)
val lock1 = CountDownLatch(1)
val bobRoomSummariesLive = runBlocking(Dispatchers.Main) {
bobSession.getRoomSummariesLive(roomSummaryQueryParams { })
@ -103,7 +91,6 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
val newRoomObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) {
if (t?.isNotEmpty() == true) {
statuses["onNewRoom"] = "onNewRoom"
lock1.countDown()
bobRoomSummariesLive.removeObserver(this)
}
@ -114,26 +101,20 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
bobRoomSummariesLive.observeForever(newRoomObserver)
}
aliceRoom.invite(bobSession.myUserId, callback = object : TestMatrixCallback<Unit>(lock1) {
override fun onSuccess(data: Unit) {
statuses["invite"] = "invite"
super.onSuccess(data)
}
})
mTestHelper.doSync<Unit> {
aliceRoom.invite(bobSession.myUserId, callback = it)
}
mTestHelper.await(lock1)
assertTrue(statuses.containsKey("invite") && statuses.containsKey("onNewRoom"))
val lock2 = CountDownLatch(2)
val lock = CountDownLatch(1)
val roomJoinedObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) {
if (bobSession.getRoom(aliceRoomId)
?.getRoomMember(aliceSession.myUserId)
?.membership == Membership.JOIN) {
statuses["AliceJoin"] = "AliceJoin"
lock2.countDown()
lock.countDown()
bobRoomSummariesLive.removeObserver(this)
}
}
@ -143,19 +124,15 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
bobRoomSummariesLive.observeForever(roomJoinedObserver)
}
bobSession.joinRoom(aliceRoomId, callback = TestMatrixCallback(lock2))
mTestHelper.doSync<Unit> { bobSession.joinRoom(aliceRoomId, callback = it) }
mTestHelper.await(lock2)
mTestHelper.await(lock)
// Ensure bob can send messages to the room
// val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
// assertNotNull(roomFromBobPOV.powerLevels)
// assertTrue(roomFromBobPOV.powerLevels.maySendMessage(bobSession.myUserId))
assertTrue(statuses.toString() + "", statuses.containsKey("AliceJoin"))
// bobSession.dataHandler.removeListener(bobEventListener)
return CryptoTestData(aliceSession, aliceRoomId, bobSession)
}
@ -237,7 +214,7 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
var lock = CountDownLatch(1)
val lock = CountDownLatch(1)
val bobEventsListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) {
@ -249,63 +226,35 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
}
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
val size = snapshot.filter { it.root.senderId != bobSession.myUserId && it.root.getClearType() == EventType.MESSAGE }
.size
val messages = snapshot.filter { it.root.getClearType() == EventType.MESSAGE }
.groupBy { it.root.senderId!! }
if (size == 3) {
// Alice has sent 2 messages and Bob has sent 3 messages
if (messages[aliceSession.myUserId]?.size == 2 && messages[bobSession.myUserId]?.size == 3) {
lock.countDown()
}
}
}
val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(10))
val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(20))
bobTimeline.start()
bobTimeline.addListener(bobEventsListener)
val results = HashMap<String, Any>()
// bobSession.dataHandler.addListener(object : MXEventListener() {
// override fun onToDeviceEvent(event: Event) {
// results["onToDeviceEvent"] = event
// lock.countDown()
// }
// })
// Alice sends a message
roomFromAlicePOV.sendTextMessage(messagesFromAlice[0])
assertTrue(results.containsKey("onToDeviceEvent"))
// assertEquals(1, messagesReceivedByBobCount)
// Bob send a message
lock = CountDownLatch(1)
// Bob send 3 messages
roomFromBobPOV.sendTextMessage(messagesFromBob[0])
// android does not echo the messages sent from itself
// messagesReceivedByBobCount++
mTestHelper.await(lock)
// assertEquals(2, messagesReceivedByBobCount)
// Bob send a message
lock = CountDownLatch(1)
roomFromBobPOV.sendTextMessage(messagesFromBob[1])
// android does not echo the messages sent from itself
// messagesReceivedByBobCount++
mTestHelper.await(lock)
// assertEquals(3, messagesReceivedByBobCount)
// Bob send a message
lock = CountDownLatch(1)
roomFromBobPOV.sendTextMessage(messagesFromBob[2])
// android does not echo the messages sent from itself
// messagesReceivedByBobCount++
mTestHelper.await(lock)
// assertEquals(4, messagesReceivedByBobCount)
// Alice sends a message
lock = CountDownLatch(2)
roomFromAlicePOV.sendTextMessage(messagesFromAlice[1])
mTestHelper.await(lock)
// assertEquals(5, messagesReceivedByBobCount)
bobTimeline.removeListener(bobEventsListener)
bobTimeline.dispose()
return cryptoTestData
}
@ -340,18 +289,14 @@ class CryptoTestHelper(val mTestHelper: CommonTestHelper) {
fun createFakeMegolmBackupAuthData(): MegolmBackupAuthData {
return MegolmBackupAuthData(
publicKey = "abcdefg",
signatures = HashMap<String, Map<String, String>>().apply {
this["something"] = HashMap<String, String>().apply {
this["ed25519:something"] = "hijklmnop"
}
}
signatures = mapOf("something" to mapOf("ed25519:something" to "hijklmnop"))
)
}
fun createFakeMegolmBackupCreationInfo(): MegolmBackupCreationInfo {
return MegolmBackupCreationInfo().apply {
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
authData = createFakeMegolmBackupAuthData()
}
return MegolmBackupCreationInfo(
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
authData = createFakeMegolmBackupAuthData()
)
}
}

View file

@ -22,11 +22,11 @@ object TestConstants {
const val TESTS_HOME_SERVER_URL = "http://10.0.2.2:8080"
// Time out to use when waiting for server response. 60s
private const val AWAIT_TIME_OUT_MILLIS = 60000
// Time out to use when waiting for server response. 10s
private const val AWAIT_TIME_OUT_MILLIS = 10_000
// Time out to use when waiting for server response, when the debugger is connected. 10 minutes
private const val AWAIT_TIME_OUT_WITH_DEBUGGER_MILLIS = 10 * 60000
private const val AWAIT_TIME_OUT_WITH_DEBUGGER_MILLIS = 10 * 60_000
const val USER_ALICE = "Alice"
const val USER_BOB = "Bob"

View file

@ -2,12 +2,10 @@ package im.vector.matrix.android.internal.crypto.crosssigning
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.common.CommonTestHelper
import im.vector.matrix.android.common.CryptoTestHelper
import im.vector.matrix.android.common.SessionTestParams
import im.vector.matrix.android.common.TestConstants
import im.vector.matrix.android.common.TestMatrixCallback
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
@ -21,7 +19,6 @@ import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@ -34,14 +31,13 @@ class XSigningTest : InstrumentedTest {
fun test_InitializeAndStoreKeys() {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
val aliceLatch = CountDownLatch(1)
aliceSession.cryptoService().crossSigningService()
.initializeCrossSigning(UserPasswordAuth(
user = aliceSession.myUserId,
password = TestConstants.PASSWORD
), TestMatrixCallback(aliceLatch))
mTestHelper.await(aliceLatch)
mTestHelper.doSync<Unit> {
aliceSession.cryptoService().crossSigningService()
.initializeCrossSigning(UserPasswordAuth(
user = aliceSession.myUserId,
password = TestConstants.PASSWORD
), it)
}
val myCrossSigningKeys = aliceSession.cryptoService().crossSigningService().getMyCrossSigningKeys()
val masterPubKey = myCrossSigningKeys?.masterKey()
@ -55,7 +51,7 @@ class XSigningTest : InstrumentedTest {
assertTrue("Signing Keys should be trusted", aliceSession.cryptoService().crossSigningService().checkUserTrust(aliceSession.myUserId).isVerified())
mTestHelper.signout(aliceSession)
mTestHelper.signOutAndClose(aliceSession)
}
@Test
@ -74,17 +70,11 @@ class XSigningTest : InstrumentedTest {
password = TestConstants.PASSWORD
)
val latch = CountDownLatch(2)
aliceSession.cryptoService().crossSigningService().initializeCrossSigning(aliceAuthParams, TestMatrixCallback(latch))
bobSession.cryptoService().crossSigningService().initializeCrossSigning(bobAuthParams, TestMatrixCallback(latch))
mTestHelper.await(latch)
mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(aliceAuthParams, it) }
mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(bobAuthParams, it) }
// Check that alice can see bob keys
val downloadLatch = CountDownLatch(1)
aliceSession.cryptoService().downloadKeys(listOf(bobSession.myUserId), true, TestMatrixCallback(downloadLatch))
mTestHelper.await(downloadLatch)
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobSession.myUserId), true, it) }
val bobKeysFromAlicePOV = aliceSession.cryptoService().crossSigningService().getUserCrossSigningKeys(bobSession.myUserId)
assertNotNull("Alice can see bob Master key", bobKeysFromAlicePOV!!.masterKey())
@ -96,8 +86,8 @@ class XSigningTest : InstrumentedTest {
assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted())
mTestHelper.signout(aliceSession)
mTestHelper.signout(bobSession)
mTestHelper.signOutAndClose(aliceSession)
mTestHelper.signOutAndClose(bobSession)
}
@Test
@ -116,94 +106,56 @@ class XSigningTest : InstrumentedTest {
password = TestConstants.PASSWORD
)
val latch = CountDownLatch(2)
aliceSession.cryptoService().crossSigningService().initializeCrossSigning(aliceAuthParams, TestMatrixCallback(latch))
bobSession.cryptoService().crossSigningService().initializeCrossSigning(bobAuthParams, TestMatrixCallback(latch))
mTestHelper.await(latch)
mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().initializeCrossSigning(aliceAuthParams, it) }
mTestHelper.doSync<Unit> { bobSession.cryptoService().crossSigningService().initializeCrossSigning(bobAuthParams, it) }
// Check that alice can see bob keys
val downloadLatch = CountDownLatch(1)
val bobUserId = bobSession.myUserId
aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, TestMatrixCallback(downloadLatch))
mTestHelper.await(downloadLatch)
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> { aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, it) }
val bobKeysFromAlicePOV = aliceSession.cryptoService().crossSigningService().getUserCrossSigningKeys(bobUserId)
assertTrue("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV?.isTrusted() == false)
val trustLatch = CountDownLatch(1)
aliceSession.cryptoService().crossSigningService().trustUser(bobUserId, object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
trustLatch.countDown()
}
override fun onFailure(failure: Throwable) {
fail("Failed to trust bob")
}
})
mTestHelper.await(trustLatch)
mTestHelper.doSync<Unit> { aliceSession.cryptoService().crossSigningService().trustUser(bobUserId, it) }
// Now bobs logs in on a new device and verifies it
// We will want to test that in alice POV, this new device would be trusted by cross signing
val bobSession2 = mTestHelper.logIntoAccount(bobUserId, SessionTestParams(true))
val bobSecondDeviceId = bobSession2.sessionParams.credentials.deviceId
val bobSecondDeviceId = bobSession2.sessionParams.credentials.deviceId!!
// Check that bob first session sees the new login
val bobKeysLatch = CountDownLatch(1)
bobSession.cryptoService().downloadKeys(listOf(bobUserId), true, object : MatrixCallback<MXUsersDevicesMap<CryptoDeviceInfo>> {
override fun onFailure(failure: Throwable) {
fail("Failed to get device")
}
val data = mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
bobSession.cryptoService().downloadKeys(listOf(bobUserId), true, it)
}
override fun onSuccess(data: MXUsersDevicesMap<CryptoDeviceInfo>) {
if (data.getUserDeviceIds(bobUserId)?.contains(bobSecondDeviceId!!) == false) {
fail("Bob should see the new device")
}
bobKeysLatch.countDown()
}
})
mTestHelper.await(bobKeysLatch)
if (data.getUserDeviceIds(bobUserId)?.contains(bobSecondDeviceId) == false) {
fail("Bob should see the new device")
}
val bobSecondDevicePOVFirstDevice = bobSession.cryptoService().getDeviceInfo(bobUserId, bobSecondDeviceId)
assertNotNull("Bob Second device should be known and persisted from first", bobSecondDevicePOVFirstDevice)
// Manually mark it as trusted from first session
val bobSignLatch = CountDownLatch(1)
bobSession.cryptoService().crossSigningService().signDevice(bobSecondDeviceId!!, object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
bobSignLatch.countDown()
}
override fun onFailure(failure: Throwable) {
fail("Failed to trust bob ${failure.localizedMessage}")
}
})
mTestHelper.await(bobSignLatch)
mTestHelper.doSync<Unit> {
bobSession.cryptoService().crossSigningService().signDevice(bobSecondDeviceId, it)
}
// Now alice should cross trust bob's second device
val aliceKeysLatch = CountDownLatch(1)
aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, object : MatrixCallback<MXUsersDevicesMap<CryptoDeviceInfo>> {
override fun onFailure(failure: Throwable) {
fail("Failed to get device")
}
val data2 = mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
aliceSession.cryptoService().downloadKeys(listOf(bobUserId), true, it)
}
override fun onSuccess(data: MXUsersDevicesMap<CryptoDeviceInfo>) {
// check that the device is seen
if (data.getUserDeviceIds(bobUserId)?.contains(bobSecondDeviceId) == false) {
fail("Alice should see the new device")
}
aliceKeysLatch.countDown()
}
})
mTestHelper.await(aliceKeysLatch)
// check that the device is seen
if (data2.getUserDeviceIds(bobUserId)?.contains(bobSecondDeviceId) == false) {
fail("Alice should see the new device")
}
val result = aliceSession.cryptoService().crossSigningService().checkDeviceTrust(bobUserId, bobSecondDeviceId, null)
assertTrue("Bob second device should be trusted from alice POV", result.isCrossSignedVerified())
mTestHelper.signout(aliceSession)
mTestHelper.signout(bobSession)
mTestHelper.signout(bobSession2)
mTestHelper.signOutAndClose(aliceSession)
mTestHelper.signOutAndClose(bobSession)
mTestHelper.signOutAndClose(bobSession2)
}
}

View file

@ -18,7 +18,6 @@ package im.vector.matrix.android.internal.crypto.keysbackup
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.listeners.ProgressListener
import im.vector.matrix.android.api.listeners.StepProgressListener
import im.vector.matrix.android.api.session.Session
@ -58,7 +57,7 @@ import java.util.Collections
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FixMethodOrder(MethodSorters.JVM)
class KeysBackupTest : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
@ -103,6 +102,8 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(sessionsCount, sessions3.size)
assertEquals(sessionsCount, cryptoTestData.firstSession.cryptoService().inboundGroupSessionsCount(false))
assertEquals(0, cryptoTestData.firstSession.cryptoService().inboundGroupSessionsCount(true))
cryptoTestData.cleanUp(mTestHelper)
}
/**
@ -120,31 +121,18 @@ class KeysBackupTest : InstrumentedTest {
assertFalse(keysBackup.isEnabled)
val latch = CountDownLatch(1)
val megolmBackupCreationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
keysBackup.prepareKeysBackupVersion(null, null, it)
}
keysBackup.prepareKeysBackupVersion(null, null, object : MatrixCallback<MegolmBackupCreationInfo> {
override fun onSuccess(data: MegolmBackupCreationInfo) {
assertNotNull(data)
assertEquals(MXCRYPTO_ALGORITHM_MEGOLM_BACKUP, data.algorithm)
assertNotNull(data.authData)
assertNotNull(data.authData!!.publicKey)
assertNotNull(data.authData!!.signatures)
assertNotNull(data.recoveryKey)
latch.countDown()
}
override fun onFailure(failure: Throwable) {
fail(failure.localizedMessage)
latch.countDown()
}
})
mTestHelper.await(latch)
assertEquals(MXCRYPTO_ALGORITHM_MEGOLM_BACKUP, megolmBackupCreationInfo.algorithm)
assertNotNull(megolmBackupCreationInfo.authData)
assertNotNull(megolmBackupCreationInfo.authData!!.publicKey)
assertNotNull(megolmBackupCreationInfo.authData!!.signatures)
assertNotNull(megolmBackupCreationInfo.recoveryKey)
stateObserver.stopAndCheckStates(null)
bobSession.close()
mTestHelper.signOutAndClose(bobSession)
}
/**
@ -160,45 +148,22 @@ class KeysBackupTest : InstrumentedTest {
assertFalse(keysBackup.isEnabled)
var megolmBackupCreationInfo: MegolmBackupCreationInfo? = null
val latch = CountDownLatch(1)
keysBackup.prepareKeysBackupVersion(null, null, object : MatrixCallback<MegolmBackupCreationInfo> {
override fun onSuccess(data: MegolmBackupCreationInfo) {
megolmBackupCreationInfo = data
latch.countDown()
}
override fun onFailure(failure: Throwable) {
fail(failure.localizedMessage)
latch.countDown()
}
})
mTestHelper.await(latch)
assertNotNull(megolmBackupCreationInfo)
val megolmBackupCreationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
keysBackup.prepareKeysBackupVersion(null, null, it)
}
assertFalse(keysBackup.isEnabled)
val latch2 = CountDownLatch(1)
// Create the version
keysBackup.createKeysBackupVersion(megolmBackupCreationInfo!!, object : TestMatrixCallback<KeysVersion>(latch2) {
override fun onSuccess(data: KeysVersion) {
assertNotNull(data)
assertNotNull(data.version)
super.onSuccess(data)
}
})
mTestHelper.await(latch2)
mTestHelper.doSync<KeysVersion> {
keysBackup.createKeysBackupVersion(megolmBackupCreationInfo, it)
}
// Backup must be enable now
assertTrue(keysBackup.isEnabled)
stateObserver.stopAndCheckStates(null)
bobSession.close()
mTestHelper.signOutAndClose(bobSession)
}
/**
@ -238,7 +203,7 @@ class KeysBackupTest : InstrumentedTest {
KeysBackupState.ReadyToBackUp
)
)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
/**
@ -259,18 +224,17 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(2, nbOfKeys)
val latch = CountDownLatch(1)
var lastBackedUpKeysProgress = 0
keysBackup.backupAllGroupSessions(object : ProgressListener {
override fun onProgress(progress: Int, total: Int) {
assertEquals(nbOfKeys, total)
lastBackedUpKeysProgress = progress
}
}, TestMatrixCallback(latch))
mTestHelper.doSync<Unit> {
keysBackup.backupAllGroupSessions(object : ProgressListener {
override fun onProgress(progress: Int, total: Int) {
assertEquals(nbOfKeys, total)
lastBackedUpKeysProgress = progress
}
}, it)
}
mTestHelper.await(latch)
assertEquals(nbOfKeys, lastBackedUpKeysProgress)
val backedUpKeys = cryptoTestData.firstSession.cryptoService().inboundGroupSessionsCount(true)
@ -278,7 +242,7 @@ class KeysBackupTest : InstrumentedTest {
assertEquals("All keys must have been marked as backed up", nbOfKeys, backedUpKeys)
stateObserver.stopAndCheckStates(null)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
/**
@ -321,7 +285,7 @@ class KeysBackupTest : InstrumentedTest {
assertKeysEquals(session.exportKeys(), sessionData)
stateObserver.stopAndCheckStates(null)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
/**
@ -335,25 +299,19 @@ class KeysBackupTest : InstrumentedTest {
val testData = createKeysBackupScenarioWithPassword(null)
// - Restore the e2e backup from the homeserver
val latch2 = CountDownLatch(1)
var importRoomKeysResult: ImportRoomKeysResult? = null
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null,
null,
null,
object : TestMatrixCallback<ImportRoomKeysResult>(latch2) {
override fun onSuccess(data: ImportRoomKeysResult) {
importRoomKeysResult = data
super.onSuccess(data)
}
}
)
mTestHelper.await(latch2)
val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null,
null,
null,
it
)
}
checkRestoreSuccess(testData, importRoomKeysResult!!.totalNumberOfKeys, importRoomKeysResult!!.successfullyNumberOfImportedKeys)
checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -370,6 +328,8 @@ class KeysBackupTest : InstrumentedTest {
*/
@Test
fun restoreKeysBackupAndKeyShareRequestTest() {
fail("Check with Valere for this test. I think we do not send key share request")
val testData = createKeysBackupScenarioWithPassword(null)
// - Check the SDK sent key share requests
@ -383,23 +343,17 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(unsentRequest != null || sentRequest != null)
// - Restore the e2e backup from the homeserver
val latch2 = CountDownLatch(1)
var importRoomKeysResult: ImportRoomKeysResult? = null
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null,
null,
null,
object : TestMatrixCallback<ImportRoomKeysResult>(latch2) {
override fun onSuccess(data: ImportRoomKeysResult) {
importRoomKeysResult = data
super.onSuccess(data)
}
}
)
mTestHelper.await(latch2)
val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null,
null,
null,
it
)
}
checkRestoreSuccess(testData, importRoomKeysResult!!.totalNumberOfKeys, importRoomKeysResult!!.successfullyNumberOfImportedKeys)
checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
// - There must be no more pending key share requests
val unsentRequestAfterRestoration = cryptoStore2
@ -410,7 +364,7 @@ class KeysBackupTest : InstrumentedTest {
// Request is either sent or unsent
assertTrue(unsentRequestAfterRestoration == null && sentRequestAfterRestoration == null)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -437,13 +391,13 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
// - Trust the backup from the new device
val latch = CountDownLatch(1)
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersion(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
true,
TestMatrixCallback(latch)
)
mTestHelper.await(latch)
mTestHelper.doSync<Unit> {
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersion(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
true,
it
)
}
// Wait for backup state to be ReadyToBackUp
waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
@ -453,38 +407,23 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
// - Retrieve the last version from the server
val latch2 = CountDownLatch(1)
var keysVersionResult: KeysVersionResult? = null
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(
object : TestMatrixCallback<KeysVersionResult?>(latch2) {
override fun onSuccess(data: KeysVersionResult?) {
keysVersionResult = data
super.onSuccess(data)
}
}
)
mTestHelper.await(latch2)
val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
}
// - It must be the same
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
val latch3 = CountDownLatch(1)
var keysBackupVersionTrust: KeysBackupVersionTrust? = null
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult!!,
object : TestMatrixCallback<KeysBackupVersionTrust>(latch3) {
override fun onSuccess(data: KeysBackupVersionTrust) {
keysBackupVersionTrust = data
super.onSuccess(data)
}
})
mTestHelper.await(latch3)
val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult, it)
}
// - It must be trusted and must have 2 signatures now
assertTrue(keysBackupVersionTrust!!.usable)
assertEquals(2, keysBackupVersionTrust!!.signatures.size)
assertTrue(keysBackupVersionTrust.usable)
assertEquals(2, keysBackupVersionTrust.signatures.size)
stateObserver.stopAndCheckStates(null)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -511,13 +450,13 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
// - Trust the backup from the new device with the recovery key
val latch = CountDownLatch(1)
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithRecoveryKey(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
TestMatrixCallback(latch)
)
mTestHelper.await(latch)
mTestHelper.doSync<Unit> {
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithRecoveryKey(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
it
)
}
// Wait for backup state to be ReadyToBackUp
waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
@ -527,38 +466,23 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
// - Retrieve the last version from the server
val latch2 = CountDownLatch(1)
var keysVersionResult: KeysVersionResult? = null
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(
object : TestMatrixCallback<KeysVersionResult?>(latch2) {
override fun onSuccess(data: KeysVersionResult?) {
keysVersionResult = data
super.onSuccess(data)
}
}
)
mTestHelper.await(latch2)
val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
}
// - It must be the same
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
val latch3 = CountDownLatch(1)
var keysBackupVersionTrust: KeysBackupVersionTrust? = null
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult!!,
object : TestMatrixCallback<KeysBackupVersionTrust>(latch3) {
override fun onSuccess(data: KeysBackupVersionTrust) {
keysBackupVersionTrust = data
super.onSuccess(data)
}
})
mTestHelper.await(latch3)
val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult, it)
}
// - It must be trusted and must have 2 signatures now
assertTrue(keysBackupVersionTrust!!.usable)
assertEquals(2, keysBackupVersionTrust!!.signatures.size)
assertTrue(keysBackupVersionTrust.usable)
assertEquals(2, keysBackupVersionTrust.signatures.size)
stateObserver.stopAndCheckStates(null)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -597,7 +521,7 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
stateObserver.stopAndCheckStates(null)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -626,13 +550,13 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
// - Trust the backup from the new device with the password
val latch = CountDownLatch(1)
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithPassphrase(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
password,
TestMatrixCallback(latch)
)
mTestHelper.await(latch)
mTestHelper.doSync<Unit> {
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithPassphrase(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
password,
it
)
}
// Wait for backup state to be ReadyToBackUp
waitForKeysBackupToBeInState(testData.aliceSession2, KeysBackupState.ReadyToBackUp)
@ -642,38 +566,23 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
// - Retrieve the last version from the server
val latch2 = CountDownLatch(1)
var keysVersionResult: KeysVersionResult? = null
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(
object : TestMatrixCallback<KeysVersionResult?>(latch2) {
override fun onSuccess(data: KeysVersionResult?) {
keysVersionResult = data
super.onSuccess(data)
}
}
)
mTestHelper.await(latch2)
val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
testData.aliceSession2.cryptoService().keysBackupService().getCurrentVersion(it)
}
// - It must be the same
assertEquals(testData.prepareKeysBackupDataResult.version, keysVersionResult!!.version)
val latch3 = CountDownLatch(1)
var keysBackupVersionTrust: KeysBackupVersionTrust? = null
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult!!,
object : TestMatrixCallback<KeysBackupVersionTrust>(latch3) {
override fun onSuccess(data: KeysBackupVersionTrust) {
keysBackupVersionTrust = data
super.onSuccess(data)
}
})
mTestHelper.await(latch3)
val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
testData.aliceSession2.cryptoService().keysBackupService().getKeysBackupTrust(keysVersionResult, it)
}
// - It must be trusted and must have 2 signatures now
assertTrue(keysBackupVersionTrust!!.usable)
assertEquals(2, keysBackupVersionTrust!!.signatures.size)
assertTrue(keysBackupVersionTrust.usable)
assertEquals(2, keysBackupVersionTrust.signatures.size)
stateObserver.stopAndCheckStates(null)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -715,7 +624,7 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
stateObserver.stopAndCheckStates(null)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -748,7 +657,7 @@ class KeysBackupTest : InstrumentedTest {
// onSuccess may not have been called
assertNull(importRoomKeysResult)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -764,27 +673,21 @@ class KeysBackupTest : InstrumentedTest {
val testData = createKeysBackupScenarioWithPassword(password)
// - Restore the e2e backup with the password
val latch2 = CountDownLatch(1)
var importRoomKeysResult: ImportRoomKeysResult? = null
val steps = ArrayList<StepProgressListener.Step>()
testData.aliceSession2.cryptoService().keysBackupService().restoreKeyBackupWithPassword(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
password,
null,
null,
object : StepProgressListener {
override fun onStepProgress(step: StepProgressListener.Step) {
steps.add(step)
}
},
object : TestMatrixCallback<ImportRoomKeysResult>(latch2) {
override fun onSuccess(data: ImportRoomKeysResult) {
importRoomKeysResult = data
super.onSuccess(data)
}
}
)
mTestHelper.await(latch2)
val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
testData.aliceSession2.cryptoService().keysBackupService().restoreKeyBackupWithPassword(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
password,
null,
null,
object : StepProgressListener {
override fun onStepProgress(step: StepProgressListener.Step) {
steps.add(step)
}
},
it
)
}
// Check steps
assertEquals(105, steps.size)
@ -807,9 +710,9 @@ class KeysBackupTest : InstrumentedTest {
assertEquals(50, (steps[103] as StepProgressListener.Step.ImportingKey).progress)
assertEquals(100, (steps[104] as StepProgressListener.Step.ImportingKey).progress)
checkRestoreSuccess(testData, importRoomKeysResult!!.totalNumberOfKeys, importRoomKeysResult!!.successfullyNumberOfImportedKeys)
checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -845,7 +748,7 @@ class KeysBackupTest : InstrumentedTest {
// onSuccess may not have been called
assertNull(importRoomKeysResult)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -861,25 +764,19 @@ class KeysBackupTest : InstrumentedTest {
val testData = createKeysBackupScenarioWithPassword(password)
// - Restore the e2e backup with the recovery key.
val latch2 = CountDownLatch(1)
var importRoomKeysResult: ImportRoomKeysResult? = null
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null,
null,
null,
object : TestMatrixCallback<ImportRoomKeysResult>(latch2) {
override fun onSuccess(data: ImportRoomKeysResult) {
importRoomKeysResult = data
super.onSuccess(data)
}
}
)
mTestHelper.await(latch2)
val importRoomKeysResult = mTestHelper.doSync<ImportRoomKeysResult> {
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
null,
null,
null,
it
)
}
checkRestoreSuccess(testData, importRoomKeysResult!!.totalNumberOfKeys, importRoomKeysResult!!.successfullyNumberOfImportedKeys)
checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -912,7 +809,7 @@ class KeysBackupTest : InstrumentedTest {
// onSuccess may not have been called
assertNull(importRoomKeysResult)
testData.cryptoTestData.close()
testData.cleanUp(mTestHelper)
}
/**
@ -932,46 +829,27 @@ class KeysBackupTest : InstrumentedTest {
prepareAndCreateKeysBackupData(keysBackup)
// Get key backup version from the home server
var keysVersionResult: KeysVersionResult? = null
val lock = CountDownLatch(1)
keysBackup.getCurrentVersion(object : TestMatrixCallback<KeysVersionResult?>(lock) {
override fun onSuccess(data: KeysVersionResult?) {
keysVersionResult = data
super.onSuccess(data)
}
})
mTestHelper.await(lock)
assertNotNull(keysVersionResult)
val keysVersionResult = mTestHelper.doSync<KeysVersionResult?> {
keysBackup.getCurrentVersion(it)
}
// - Check the returned KeyBackupVersion is trusted
val latch = CountDownLatch(1)
var keysBackupVersionTrust: KeysBackupVersionTrust? = null
keysBackup.getKeysBackupTrust(keysVersionResult!!, object : MatrixCallback<KeysBackupVersionTrust> {
override fun onSuccess(data: KeysBackupVersionTrust) {
keysBackupVersionTrust = data
latch.countDown()
}
override fun onFailure(failure: Throwable) {
super.onFailure(failure)
latch.countDown()
}
})
mTestHelper.await(latch)
val keysBackupVersionTrust = mTestHelper.doSync<KeysBackupVersionTrust> {
keysBackup.getKeysBackupTrust(keysVersionResult!!, it)
}
assertNotNull(keysBackupVersionTrust)
assertTrue(keysBackupVersionTrust!!.usable)
assertEquals(1, keysBackupVersionTrust!!.signatures.size)
assertTrue(keysBackupVersionTrust.usable)
assertEquals(1, keysBackupVersionTrust.signatures.size)
val signature = keysBackupVersionTrust!!.signatures[0]
val signature = keysBackupVersionTrust.signatures[0]
assertTrue(signature.valid)
assertNotNull(signature.device)
assertEquals(cryptoTestData.firstSession.cryptoService().getMyDevice().deviceId, signature.deviceId)
assertEquals(signature.device!!.deviceId, cryptoTestData.firstSession.sessionParams.credentials.deviceId)
stateObserver.stopAndCheckStates(null)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
/**
@ -983,6 +861,7 @@ class KeysBackupTest : InstrumentedTest {
*/
@Test
fun testCheckAndStartKeysBackupWhenRestartingAMatrixSession() {
fail("This test still fail. To investigate")
// - Create a backup version
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
@ -1000,7 +879,7 @@ class KeysBackupTest : InstrumentedTest {
// - Log Alice on a new device
val aliceSession2 = mTestHelper.logIntoAccount(cryptoTestData.firstSession.myUserId, defaultSessionParamsWithInitialSync)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
val keysBackup2 = aliceSession2.cryptoService().keysBackupService()
@ -1012,12 +891,12 @@ class KeysBackupTest : InstrumentedTest {
keysBackup2.addListener(object : KeysBackupStateListener {
override fun onStateChange(newState: KeysBackupState) {
// Check the backup completes
if (keysBackup.state == KeysBackupState.ReadyToBackUp) {
if (newState == KeysBackupState.ReadyToBackUp) {
count++
if (count == 2) {
// Remove itself from the list of listeners
keysBackup.removeListener(this)
keysBackup2.removeListener(this)
latch.countDown()
}
@ -1030,7 +909,7 @@ class KeysBackupTest : InstrumentedTest {
stateObserver.stopAndCheckStates(null)
stateObserver2.stopAndCheckStates(null)
aliceSession2.close()
mTestHelper.signOutAndClose(aliceSession2)
}
/**
@ -1079,21 +958,17 @@ class KeysBackupTest : InstrumentedTest {
mTestHelper.await(latch0)
// - Create a new backup with fake data on the homeserver, directly using the rest client
val latch = CountDownLatch(1)
val megolmBackupCreationInfo = mCryptoTestHelper.createFakeMegolmBackupCreationInfo()
(keysBackup as DefaultKeysBackupService).createFakeKeysBackupVersion(megolmBackupCreationInfo, TestMatrixCallback(latch))
mTestHelper.await(latch)
mTestHelper.doSync<KeysVersion> {
(keysBackup as DefaultKeysBackupService).createFakeKeysBackupVersion(megolmBackupCreationInfo, it)
}
// Reset the store backup status for keys
(cryptoTestData.firstSession.cryptoService().keysBackupService() as DefaultKeysBackupService).store.resetBackupMarkers()
// - Make alice back up all her keys again
val latch2 = CountDownLatch(1)
keysBackup.backupAllGroupSessions(object : ProgressListener {
override fun onProgress(progress: Int, total: Int) {
}
}, TestMatrixCallback(latch2, false))
keysBackup.backupAllGroupSessions(null, TestMatrixCallback(latch2, false))
mTestHelper.await(latch2)
// -> That must fail and her backup state must be WrongBackUpVersion
@ -1101,7 +976,7 @@ class KeysBackupTest : InstrumentedTest {
assertFalse(keysBackup.isEnabled)
stateObserver.stopAndCheckStates(null)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
/**
@ -1129,20 +1004,14 @@ class KeysBackupTest : InstrumentedTest {
prepareAndCreateKeysBackupData(keysBackup)
// Wait for keys backup to finish by asking again to backup keys.
val latch = CountDownLatch(1)
keysBackup.backupAllGroupSessions(object : ProgressListener {
override fun onProgress(progress: Int, total: Int) {
}
}, TestMatrixCallback(latch))
mTestHelper.await(latch)
mTestHelper.doSync<Unit> {
keysBackup.backupAllGroupSessions(null, it)
}
val oldDeviceId = cryptoTestData.firstSession.sessionParams.credentials.deviceId!!
val oldKeyBackupVersion = keysBackup.currentBackupVersion
val aliceUserId = cryptoTestData.firstSession.myUserId
// Close first Alice session, else they will share the same Crypto store and the test fails.
cryptoTestData.firstSession.close()
// - Log Alice on a new device
val aliceSession2 = mTestHelper.logIntoAccount(aliceUserId, defaultSessionParamsWithInitialSync)
@ -1160,15 +1029,14 @@ class KeysBackupTest : InstrumentedTest {
var isSuccessful = false
val latch2 = CountDownLatch(1)
keysBackup2.backupAllGroupSessions(object : ProgressListener {
override fun onProgress(progress: Int, total: Int) {
}
}, object : TestMatrixCallback<Unit>(latch2, false) {
override fun onSuccess(data: Unit) {
isSuccessful = true
super.onSuccess(data)
}
})
keysBackup2.backupAllGroupSessions(
null,
object : TestMatrixCallback<Unit>(latch2, false) {
override fun onSuccess(data: Unit) {
isSuccessful = true
super.onSuccess(data)
}
})
mTestHelper.await(latch2)
assertFalse(isSuccessful)
@ -1178,7 +1046,7 @@ class KeysBackupTest : InstrumentedTest {
assertFalse(keysBackup2.isEnabled)
// - Validate the old device from the new one
aliceSession2.cryptoService().setDeviceVerification(DeviceTrustLevel(false, true), aliceSession2.myUserId, oldDeviceId)
aliceSession2.cryptoService().setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession2.myUserId, oldDeviceId)
// -> Backup should automatically enable on the new device
val latch4 = CountDownLatch(1)
@ -1198,17 +1066,17 @@ class KeysBackupTest : InstrumentedTest {
// -> It must use the same backup version
assertEquals(oldKeyBackupVersion, aliceSession2.cryptoService().keysBackupService().currentBackupVersion)
val latch5 = CountDownLatch(1)
aliceSession2.cryptoService().keysBackupService().backupAllGroupSessions(null, TestMatrixCallback(latch5))
mTestHelper.await(latch5)
mTestHelper.doSync<Unit> {
aliceSession2.cryptoService().keysBackupService().backupAllGroupSessions(null, it)
}
// -> It must success
assertTrue(aliceSession2.cryptoService().keysBackupService().isEnabled)
stateObserver.stopAndCheckStates(null)
stateObserver2.stopAndCheckStates(null)
aliceSession2.close()
cryptoTestData.close()
mTestHelper.signOutAndClose(aliceSession2)
cryptoTestData.cleanUp(mTestHelper)
}
/**
@ -1230,18 +1098,14 @@ class KeysBackupTest : InstrumentedTest {
assertTrue(keysBackup.isEnabled)
val latch = CountDownLatch(1)
// Delete the backup
keysBackup.deleteBackup(keyBackupCreationInfo.version, TestMatrixCallback(latch))
mTestHelper.await(latch)
mTestHelper.doSync<Unit> { keysBackup.deleteBackup(keyBackupCreationInfo.version, it) }
// Backup is now disabled
assertFalse(keysBackup.isEnabled)
stateObserver.stopAndCheckStates(null)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
/* ==========================================================================================
@ -1280,49 +1144,26 @@ class KeysBackupTest : InstrumentedTest {
password: String? = null): PrepareKeysBackupDataResult {
val stateObserver = StateObserver(keysBackup)
var megolmBackupCreationInfo: MegolmBackupCreationInfo? = null
val latch = CountDownLatch(1)
keysBackup.prepareKeysBackupVersion(password, null, object : MatrixCallback<MegolmBackupCreationInfo> {
override fun onSuccess(data: MegolmBackupCreationInfo) {
megolmBackupCreationInfo = data
latch.countDown()
}
override fun onFailure(failure: Throwable) {
fail(failure.localizedMessage)
latch.countDown()
}
})
mTestHelper.await(latch)
val megolmBackupCreationInfo = mTestHelper.doSync<MegolmBackupCreationInfo> {
keysBackup.prepareKeysBackupVersion(password, null, it)
}
assertNotNull(megolmBackupCreationInfo)
assertFalse(keysBackup.isEnabled)
val latch2 = CountDownLatch(1)
// Create the version
var version: String? = null
keysBackup.createKeysBackupVersion(megolmBackupCreationInfo!!, object : TestMatrixCallback<KeysVersion>(latch2) {
override fun onSuccess(data: KeysVersion) {
assertNotNull(data)
assertNotNull(data.version)
val keysVersion = mTestHelper.doSync<KeysVersion> {
keysBackup.createKeysBackupVersion(megolmBackupCreationInfo, it)
}
version = data.version
super.onSuccess(data)
}
})
mTestHelper.await(latch2)
assertNotNull(keysVersion.version)
// Backup must be enable now
assertTrue(keysBackup.isEnabled)
assertNotNull(version)
stateObserver.stopAndCheckStates(null)
return PrepareKeysBackupDataResult(megolmBackupCreationInfo!!, version!!)
return PrepareKeysBackupDataResult(megolmBackupCreationInfo, keysVersion.version!!)
}
private fun assertKeysEquals(keys1: MegolmSessionData?, keys2: MegolmSessionData?) {
@ -1347,7 +1188,12 @@ class KeysBackupTest : InstrumentedTest {
private data class KeysBackupScenarioData(val cryptoTestData: CryptoTestData,
val aliceKeys: List<OlmInboundGroupSessionWrapper>,
val prepareKeysBackupDataResult: PrepareKeysBackupDataResult,
val aliceSession2: Session)
val aliceSession2: Session) {
fun cleanUp(testHelper: CommonTestHelper) {
cryptoTestData.cleanUp(testHelper)
testHelper.signOutAndClose(aliceSession2)
}
}
/**
* Common initial condition
@ -1369,27 +1215,22 @@ class KeysBackupTest : InstrumentedTest {
// - Do an e2e backup to the homeserver
val prepareKeysBackupDataResult = prepareAndCreateKeysBackupData(keysBackup, password)
val latch = CountDownLatch(1)
var lastProgress = 0
var lastTotal = 0
keysBackup.backupAllGroupSessions(object : ProgressListener {
override fun onProgress(progress: Int, total: Int) {
lastProgress = progress
lastTotal = total
}
}, TestMatrixCallback(latch))
mTestHelper.await(latch)
mTestHelper.doSync<Unit> {
keysBackup.backupAllGroupSessions(object : ProgressListener {
override fun onProgress(progress: Int, total: Int) {
lastProgress = progress
lastTotal = total
}
}, it)
}
assertEquals(2, lastProgress)
assertEquals(2, lastTotal)
val aliceUserId = cryptoTestData.firstSession.myUserId
// Logout first Alice session, else they will share the same Crypto store and some tests may fail.
val latch2 = CountDownLatch(1)
cryptoTestData.firstSession.signOut(true, TestMatrixCallback(latch2))
mTestHelper.await(latch2)
// - Log Alice on a new device
val aliceSession2 = mTestHelper.logIntoAccount(aliceUserId, defaultSessionParamsWithInitialSync)

View file

@ -128,7 +128,7 @@ class QuadSTests : InstrumentedTest {
assertNotNull(defaultKeyAccountData?.content)
assertEquals("Unexpected default key ${defaultKeyAccountData?.content}", TEST_KEY_ID, defaultKeyAccountData?.content?.get("key"))
mTestHelper.signout(aliceSession)
mTestHelper.signOutAndClose(aliceSession)
}
@Test
@ -172,7 +172,7 @@ class QuadSTests : InstrumentedTest {
}
assertEquals("Secret mismatch", clearSecret, decryptedSecret)
mTestHelper.signout(aliceSession)
mTestHelper.signOutAndClose(aliceSession)
}
@Test
@ -192,7 +192,7 @@ class QuadSTests : InstrumentedTest {
quadS.setDefaultKey(TEST_KEY_ID, it)
}
mTestHelper.signout(aliceSession)
mTestHelper.signOutAndClose(aliceSession)
}
@Test
@ -239,7 +239,7 @@ class QuadSTests : InstrumentedTest {
)
}
mTestHelper.signout(aliceSession)
mTestHelper.signOutAndClose(aliceSession)
}
@Test
@ -298,7 +298,7 @@ class QuadSTests : InstrumentedTest {
)
}
mTestHelper.signout(aliceSession)
mTestHelper.signOutAndClose(aliceSession)
}
private fun assertAccountData(session: Session, type: String): UserAccountDataEvent {

View file

@ -132,7 +132,7 @@ class SASTest : InstrumentedTest {
assertNull(bobVerificationService.getExistingTransaction(aliceSession.myUserId, txID))
assertNull(aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID))
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
@Test
@ -189,7 +189,7 @@ class SASTest : InstrumentedTest {
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod, cancelReason)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
@Test
@ -227,7 +227,7 @@ class SASTest : InstrumentedTest {
val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
@Test
@ -265,7 +265,7 @@ class SASTest : InstrumentedTest {
val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
private fun fakeBobStart(bobSession: Session,
@ -334,7 +334,7 @@ class SASTest : InstrumentedTest {
mTestHelper.await(aliceCreatedLatch)
mTestHelper.await(aliceCancelledLatch)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
/**
@ -393,7 +393,7 @@ class SASTest : InstrumentedTest {
assertTrue("all agreed Short Code should be known by alice", startReq!!.shortAuthenticationStrings!!.contains(it))
}
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
@Test
@ -449,7 +449,7 @@ class SASTest : InstrumentedTest {
assertEquals("Should have same SAS", aliceTx.getShortCodeRepresentation(SasMode.DECIMAL),
bobTx.getShortCodeRepresentation(SasMode.DECIMAL))
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
@Test
@ -514,6 +514,6 @@ class SASTest : InstrumentedTest {
assertTrue("alice device should be verified from bob point of view", aliceDeviceInfoFromBobPOV!!.isVerified)
assertTrue("bob device should be verified from alice point of view", bobDeviceInfoFromAlicePOV!!.isVerified)
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
}

View file

@ -227,6 +227,6 @@ class VerificationTest : InstrumentedTest {
pr.otherCanScanQrCode() shouldBe expectedResultForBob.otherCanScanQrCode
}
cryptoTestData.close()
cryptoTestData.cleanUp(mTestHelper)
}
}

View file

@ -46,13 +46,13 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class WellKnown(
@Json(name = "m.homeserver")
var homeServer: WellKnownBaseConfig? = null,
val homeServer: WellKnownBaseConfig? = null,
@Json(name = "m.identity_server")
var identityServer: WellKnownBaseConfig? = null,
val identityServer: WellKnownBaseConfig? = null,
@Json(name = "m.integrations")
var integrations: Map<String, @JvmSuppressWildcards Any>? = null
val integrations: Map<String, @JvmSuppressWildcards Any>? = null
) {
/**
* Returns the list of integration managers proposed

View file

@ -24,7 +24,7 @@ internal data class CreateRoomResponse(
/**
* Required. The created room's ID.
*/
@Json(name = "room_id") var roomId: String
@Json(name = "room_id") val roomId: String
)
internal typealias JoinRoomResponse = CreateRoomResponse

View file

@ -27,5 +27,5 @@ data class PublicRoomsFilter(
* A string to search for in the room metadata, e.g. name, topic, canonical alias etc. (Optional).
*/
@Json(name = "generic_search_term")
var searchTerm: String? = null
val searchTerm: String? = null
)

View file

@ -28,30 +28,30 @@ data class PublicRoomsParams(
* Limit the number of results returned.
*/
@Json(name = "limit")
var limit: Int? = null,
val limit: Int? = null,
/**
* A pagination token from a previous request, allowing clients to get the next (or previous) batch of rooms.
* The direction of pagination is specified solely by which token is supplied, rather than via an explicit flag.
*/
@Json(name = "since")
var since: String? = null,
val since: String? = null,
/**
* Filter to apply to the results.
*/
@Json(name = "filter")
var filter: PublicRoomsFilter? = null,
val filter: PublicRoomsFilter? = null,
/**
* Whether or not to include all known networks/protocols from application services on the homeserver. Defaults to false.
*/
@Json(name = "include_all_networks")
var includeAllNetworks: Boolean = false,
val includeAllNetworks: Boolean = false,
/**
* The specific third party network/protocol to request from the homeserver. Can only be used if include_all_networks is false.
*/
@Json(name = "third_party_instance_id")
var thirdPartyInstanceId: String? = null
val thirdPartyInstanceId: String? = null
)

View file

@ -26,7 +26,7 @@ data class ThirdPartyProtocol(
* where higher groupings are ordered first. For example, the name of a network should be searched before the nickname of a user.
*/
@Json(name = "user_fields")
var userFields: List<String>? = null,
val userFields: List<String>? = null,
/**
* Required. Fields which may be used to identify a third party location. These should be ordered to suggest the way that
@ -34,15 +34,15 @@ data class ThirdPartyProtocol(
* searched before the name of a channel.
*/
@Json(name = "location_fields")
var locationFields: List<String>? = null,
val locationFields: List<String>? = null,
/**
* Required. A content URI representing an icon for the third party protocol.
*
* FIXDOC: This field was not present in legacy Riot, and it is sometimes sent by the server (no not Required?)
* FIXDOC: This field was not present in legacy Riot, and it is sometimes sent by the server (so not Required?)
*/
@Json(name = "icon")
var icon: String? = null,
val icon: String? = null,
/**
* Required. The type definitions for the fields defined in the user_fields and location_fields. Each entry in those arrays MUST have an entry here.
@ -51,12 +51,12 @@ data class ThirdPartyProtocol(
* May be an empty object if no fields are defined.
*/
@Json(name = "field_types")
var fieldTypes: Map<String, FieldType>? = null,
val fieldTypes: Map<String, FieldType>? = null,
/**
* Required. A list of objects representing independent instances of configuration. For example, multiple networks on IRC
* if multiple are provided by the same application service.
*/
@Json(name = "instances")
var instances: List<ThirdPartyProtocolInstance>? = null
val instances: List<ThirdPartyProtocolInstance>? = null
)

View file

@ -25,35 +25,35 @@ data class ThirdPartyProtocolInstance(
* Required. A human-readable description for the protocol, such as the name.
*/
@Json(name = "desc")
var desc: String? = null,
val desc: String? = null,
/**
* An optional content URI representing the protocol. Overrides the one provided at the higher level Protocol object.
*/
@Json(name = "icon")
var icon: String? = null,
val icon: String? = null,
/**
* Required. Preset values for fields the client may use to search by.
*/
@Json(name = "fields")
var fields: Map<String, Any>? = null,
val fields: Map<String, Any>? = null,
/**
* Required. A unique identifier across all instances.
*/
@Json(name = "network_id")
var networkId: String? = null,
val networkId: String? = null,
/**
* FIXDOC Not documented on matrix.org doc
*/
@Json(name = "instance_id")
var instanceId: String? = null,
val instanceId: String? = null,
/**
* FIXDOC Not documented on matrix.org doc
*/
@Json(name = "bot_user_id")
var botUserId: String? = null
val botUserId: String? = null
)

View file

@ -41,12 +41,12 @@ interface Timeline {
fun removeAllListeners()
/**
* This should be called before any other method after creating the timeline. It ensures the underlying database is open
* This must be called before any other method after creating the timeline. It ensures the underlying database is open
*/
fun start()
/**
* This should be called when you don't need the timeline. It ensures the underlying database get closed.
* This must be called when you don't need the timeline. It ensures the underlying database get closed.
*/
fun dispose()

View file

@ -27,6 +27,9 @@ interface TimelineService {
/**
* Instantiate a [Timeline] with an optional initial eventId, to be used with permalink.
* You can also configure some settings with the [settings] param.
*
* Important: the returned Timeline has to be started
*
* @param eventId the optional initial eventId.
* @param settings settings to configure the timeline.
* @return the instantiated timeline

View file

@ -32,20 +32,20 @@ data class RegistrationFlowResponse(
* The list of flows.
*/
@Json(name = "flows")
var flows: List<InteractiveAuthenticationFlow>? = null,
val flows: List<InteractiveAuthenticationFlow>? = null,
/**
* The list of stages the client has completed successfully.
*/
@Json(name = "completed")
var completedStages: List<String>? = null,
val completedStages: List<String>? = null,
/**
* The session identifier that the client must pass back to the home server, if one is provided,
* in subsequent attempts to authenticate in the same API call.
*/
@Json(name = "session")
var session: String? = null,
val session: String? = null,
/**
* The information that the client will need to know in order to use a given type of authentication.
@ -53,7 +53,7 @@ data class RegistrationFlowResponse(
* For example, the public key of reCAPTCHA stage could be given here.
*/
@Json(name = "params")
var params: JsonDict? = null
val params: JsonDict? = null
/**
* WARNING,

View file

@ -1021,12 +1021,12 @@ internal class DefaultCryptoService @Inject constructor(
return
}
val requestBody = RoomKeyRequestBody()
requestBody.roomId = event.roomId
requestBody.algorithm = wireContent["algorithm"]?.toString()
requestBody.senderKey = wireContent["sender_key"]?.toString()
requestBody.sessionId = wireContent["session_id"]?.toString()
val requestBody = RoomKeyRequestBody(
algorithm = wireContent["algorithm"]?.toString(),
roomId = event.roomId,
senderKey = wireContent["sender_key"]?.toString(),
sessionId = wireContent["session_id"]?.toString()
)
outgoingRoomKeyRequestManager.resendRoomKeyRequest(requestBody)
}

View file

@ -25,54 +25,56 @@ import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyShareRequest
/**
* IncomingRoomKeyRequest class defines the incoming room keys request.
*/
open class IncomingRoomKeyRequest {
/**
* The user id
*/
var userId: String? = null
data class IncomingRoomKeyRequest(
/**
* The user id
*/
override val userId: String? = null,
/**
* The device id
*/
var deviceId: String? = null
/**
* The device id
*/
override val deviceId: String? = null,
/**
* The request id
*/
var requestId: String? = null
/**
* The request id
*/
override val requestId: String? = null,
/**
* The request body
*/
var requestBody: RoomKeyRequestBody? = null
/**
* The request body
*/
val requestBody: RoomKeyRequestBody? = null,
/**
* The runnable to call to accept to share the keys
*/
@Transient
var share: Runnable? = null
/**
* The runnable to call to accept to share the keys
*/
@Transient
var share: Runnable? = null,
/**
* The runnable to call to ignore the key share request.
*/
@Transient
var ignore: Runnable? = null
/**
* Constructor
*
* @param event the event
*/
constructor(event: Event) {
userId = event.senderId
val roomKeyShareRequest = event.getClearContent().toModel<RoomKeyShareRequest>()!!
deviceId = roomKeyShareRequest.requestingDeviceId
requestId = roomKeyShareRequest.requestId
requestBody = if (null != roomKeyShareRequest.body) roomKeyShareRequest.body else RoomKeyRequestBody()
/**
* The runnable to call to ignore the key share request.
*/
@Transient
var ignore: Runnable? = null
) : IncomingRoomKeyRequestCommon {
companion object {
/**
* Factory
*
* @param event the event
*/
fun fromEvent(event: Event): IncomingRoomKeyRequest? {
return event.getClearContent()
.toModel<RoomKeyShareRequest>()
?.let {
IncomingRoomKeyRequest(
userId = event.senderId,
deviceId = it.requestingDeviceId,
requestId = it.requestId,
requestBody = it.body ?: RoomKeyRequestBody()
)
}
}
}
/**
* Constructor for object creation from crypto store
*/
constructor()
}

View file

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

View file

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

View file

@ -53,8 +53,8 @@ internal class IncomingRoomKeyRequestManager @Inject constructor(
fun onRoomKeyRequestEvent(event: Event) {
val roomKeyShare = event.getClearContent().toModel<RoomKeyShare>()
when (roomKeyShare?.action) {
RoomKeyShare.ACTION_SHARE_REQUEST -> receivedRoomKeyRequests.add(IncomingRoomKeyRequest(event))
RoomKeyShare.ACTION_SHARE_CANCELLATION -> receivedRoomKeyRequestCancellations.add(IncomingRoomKeyRequestCancellation(event))
RoomKeyShare.ACTION_SHARE_REQUEST -> IncomingRoomKeyRequest.fromEvent(event)?.let { receivedRoomKeyRequests.add(it) }
RoomKeyShare.ACTION_SHARE_CANCELLATION -> IncomingRoomKeyRequestCancellation.fromEvent(event)?.let { receivedRoomKeyRequestCancellations.add(it) }
else -> Timber.e("## onRoomKeyRequestEvent() : unsupported action ${roomKeyShare?.action}")
}
}

View file

@ -28,46 +28,46 @@ data class MegolmSessionData(
* The algorithm used.
*/
@Json(name = "algorithm")
var algorithm: String? = null,
val algorithm: String? = null,
/**
* Unique id for the session.
*/
@Json(name = "session_id")
var sessionId: String? = null,
val sessionId: String? = null,
/**
* Sender's Curve25519 device key.
*/
@Json(name = "sender_key")
var senderKey: String? = null,
val senderKey: String? = null,
/**
* Room this session is used in.
*/
@Json(name = "room_id")
var roomId: String? = null,
val roomId: String? = null,
/**
* Base64'ed key data.
*/
@Json(name = "session_key")
var sessionKey: String? = null,
val sessionKey: String? = null,
/**
* Other keys the sender claims.
*/
@Json(name = "sender_claimed_keys")
var senderClaimedKeys: Map<String, String>? = null,
val senderClaimedKeys: Map<String, String>? = null,
// This is a shortcut for sender_claimed_keys.get("ed25519")
// Keep it for compatibility reason.
@Json(name = "sender_claimed_ed25519_key")
var senderClaimedEd25519Key: String? = null,
val senderClaimedEd25519Key: String? = null,
/**
* Devices which forwarded this session to us (normally empty).
*/
@Json(name = "forwarding_curve25519_key_chain")
var forwardingCurve25519KeyChain: List<String>? = null
val forwardingCurve25519KeyChain: List<String>? = null
)

View file

@ -213,10 +213,11 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
Timber.v("## sendOutgoingRoomKeyRequest() : Requesting keys " + request.requestBody
+ " from " + request.recipients + " id " + request.requestId)
val requestMessage = RoomKeyShareRequest()
requestMessage.requestingDeviceId = cryptoStore.getDeviceId()
requestMessage.requestId = request.requestId
requestMessage.body = request.requestBody
val requestMessage = RoomKeyShareRequest(
requestingDeviceId = cryptoStore.getDeviceId(),
requestId = request.requestId,
body = request.requestBody
)
sendMessageToDevices(requestMessage, request.recipients, request.requestId, object : MatrixCallback<Unit> {
private fun onDone(state: OutgoingRoomKeyRequest.RequestState) {
@ -253,9 +254,10 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
+ " to " + request.recipients
+ " cancellation id " + request.cancellationTxnId)
val roomKeyShareCancellation = RoomKeyShareCancellation()
roomKeyShareCancellation.requestingDeviceId = cryptoStore.getDeviceId()
roomKeyShareCancellation.requestId = request.cancellationTxnId
val roomKeyShareCancellation = RoomKeyShareCancellation(
requestingDeviceId = cryptoStore.getDeviceId(),
requestId = request.cancellationTxnId
)
sendMessageToDevices(roomKeyShareCancellation, request.recipients, request.cancellationTxnId, object : MatrixCallback<Unit> {
private fun onDone() {

View file

@ -66,12 +66,12 @@ internal class MegolmSessionDataImporter @Inject constructor(private val olmDevi
totalNumbersOfImportedKeys++
// cancel any outstanding room key requests for this session
val roomKeyRequestBody = RoomKeyRequestBody()
roomKeyRequestBody.algorithm = megolmSessionData.algorithm
roomKeyRequestBody.roomId = megolmSessionData.roomId
roomKeyRequestBody.senderKey = megolmSessionData.senderKey
roomKeyRequestBody.sessionId = megolmSessionData.sessionId
val roomKeyRequestBody = RoomKeyRequestBody(
algorithm = megolmSessionData.algorithm,
roomId = megolmSessionData.roomId,
senderKey = megolmSessionData.senderKey,
sessionId = megolmSessionData.sessionId
)
outgoingRoomKeyRequestManager.cancelRoomKeyRequest(roomKeyRequestBody)
@ -83,7 +83,7 @@ internal class MegolmSessionDataImporter @Inject constructor(private val olmDevi
}
if (progressListener != null) {
val progress = 100 * cpt / totalNumbersOfKeys
val progress = 100 * (cpt + 1) / totalNumbersOfKeys
if (lastProgress != progress) {
lastProgress = progress

View file

@ -163,12 +163,12 @@ internal class MXMegolmDecryption(private val userId: String,
recipients.add(senderMap)
}
val requestBody = RoomKeyRequestBody()
requestBody.roomId = event.roomId
requestBody.algorithm = encryptedEventContent.algorithm
requestBody.senderKey = encryptedEventContent.senderKey
requestBody.sessionId = encryptedEventContent.sessionId
val requestBody = RoomKeyRequestBody(
roomId = event.roomId,
algorithm = encryptedEventContent.algorithm,
senderKey = encryptedEventContent.senderKey,
sessionId = encryptedEventContent.sessionId
)
outgoingRoomKeyRequestManager.sendRoomKeyRequest(requestBody, recipients)
}
@ -264,12 +264,12 @@ internal class MXMegolmDecryption(private val userId: String,
if (added) {
defaultKeysBackupService.maybeBackupKeys()
val content = RoomKeyRequestBody()
content.algorithm = roomKeyContent.algorithm
content.roomId = roomKeyContent.roomId
content.sessionId = roomKeyContent.sessionId
content.senderKey = senderKey
val content = RoomKeyRequestBody(
algorithm = roomKeyContent.algorithm,
roomId = roomKeyContent.roomId,
sessionId = roomKeyContent.sessionId,
senderKey = senderKey
)
outgoingRoomKeyRequestManager.cancelRoomKeyRequest(content)
@ -290,8 +290,8 @@ internal class MXMegolmDecryption(private val userId: String,
override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean {
val roomId = request.requestBody?.roomId ?: return false
val senderKey = request.requestBody?.senderKey ?: return false
val sessionId = request.requestBody?.sessionId ?: return false
val senderKey = request.requestBody.senderKey ?: return false
val sessionId = request.requestBody.sessionId ?: return false
return olmDevice.hasInboundSessionKeys(roomId, senderKey, sessionId)
}
@ -319,15 +319,14 @@ internal class MXMegolmDecryption(private val userId: String,
return@mapCatching
}
Timber.v("## shareKeysWithDevice() : sharing keys for session" +
" ${body?.senderKey}|${body?.sessionId} with device $userId:$deviceId")
" ${body.senderKey}|${body.sessionId} with device $userId:$deviceId")
val payloadJson = mutableMapOf<String, Any>("type" to EventType.FORWARDED_ROOM_KEY)
runCatching { olmDevice.getInboundGroupSession(body?.sessionId, body?.senderKey, body?.roomId) }
runCatching { olmDevice.getInboundGroupSession(body.sessionId, body.senderKey, body.roomId) }
.fold(
{
// TODO
payloadJson["content"] = it.exportKeys()
?: ""
payloadJson["content"] = it.exportKeys() ?: ""
},
{
// TODO

View file

@ -28,6 +28,7 @@ import io.realm.RealmConfiguration
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
import javax.inject.Inject
@ -47,6 +48,8 @@ internal class ShieldTrustUpdater @Inject constructor(
private val backgroundCryptoRealm = AtomicReference<Realm>()
private val backgroundSessionRealm = AtomicReference<Realm>()
private val isStarted = AtomicBoolean()
// private var cryptoDevicesResult: RealmResults<DeviceInfoEntity>? = null
// private val cryptoDeviceChangeListener = object : OrderedRealmCollectionChangeListener<RealmResults<DeviceInfoEntity>> {
@ -57,38 +60,46 @@ internal class ShieldTrustUpdater @Inject constructor(
// }
fun start() {
eventBus.register(this)
BACKGROUND_HANDLER.post {
val cryptoRealm = Realm.getInstance(cryptoRealmConfiguration)
backgroundCryptoRealm.set(cryptoRealm)
if (isStarted.compareAndSet(false, true)) {
eventBus.register(this)
BACKGROUND_HANDLER.post {
val cryptoRealm = Realm.getInstance(cryptoRealmConfiguration)
backgroundCryptoRealm.set(cryptoRealm)
// cryptoDevicesResult = cryptoRealm.where<DeviceInfoEntity>().findAll()
// cryptoDevicesResult?.addChangeListener(cryptoDeviceChangeListener)
backgroundSessionRealm.set(Realm.getInstance(sessionRealmConfiguration))
backgroundSessionRealm.set(Realm.getInstance(sessionRealmConfiguration))
}
}
}
fun stop() {
eventBus.unregister(this)
BACKGROUND_HANDLER.post {
// cryptoDevicesResult?.removeAllChangeListeners()
backgroundCryptoRealm.getAndSet(null).also {
it?.close()
}
backgroundSessionRealm.getAndSet(null).also {
it?.close()
if (isStarted.compareAndSet(true, false)) {
eventBus.unregister(this)
BACKGROUND_HANDLER.post {
// cryptoDevicesResult?.removeAllChangeListeners()
backgroundCryptoRealm.getAndSet(null).also {
it?.close()
}
backgroundSessionRealm.getAndSet(null).also {
it?.close()
}
}
}
}
@Subscribe
fun onRoomMemberChange(update: SessionToCryptoRoomMembersUpdate) {
if (!isStarted.get()) {
return
}
taskExecutor.executorScope.launch {
val updatedTrust = computeTrustTask.execute(ComputeTrustTask.Params(update.userIds))
// We need to send that back to session base
BACKGROUND_HANDLER.post {
backgroundSessionRealm.get().executeTransaction { realm ->
backgroundSessionRealm.get()?.executeTransaction { realm ->
roomSummaryUpdater.updateShieldTrust(realm, update.roomId, updatedTrust)
}
}
@ -97,6 +108,10 @@ internal class ShieldTrustUpdater @Inject constructor(
@Subscribe
fun onTrustUpdate(update: CryptoToSessionUserTrustChange) {
if (!isStarted.get()) {
return
}
onCryptoDevicesChange(update.userIds)
}
@ -123,7 +138,7 @@ internal class ShieldTrustUpdater @Inject constructor(
taskExecutor.executorScope.launch {
val updatedTrust = computeTrustTask.execute(ComputeTrustTask.Params(userList))
BACKGROUND_HANDLER.post {
backgroundSessionRealm.get().executeTransaction { realm ->
backgroundSessionRealm.get()?.executeTransaction { realm ->
roomSummaryUpdater.updateShieldTrust(realm, roomId, updatedTrust)
}
}

View file

@ -80,6 +80,7 @@ import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import im.vector.matrix.android.internal.util.awaitCallback
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.matrix.olm.OlmException
@ -167,9 +168,7 @@ internal class DefaultKeysBackupService @Inject constructor(
runCatching {
withContext(coroutineDispatchers.crypto) {
val olmPkDecryption = OlmPkDecryption()
val megolmBackupAuthData = MegolmBackupAuthData()
if (password != null) {
val megolmBackupAuthData = if (password != null) {
// Generate a private key from the password
val backgroundProgressListener = if (progressListener == null) {
null
@ -188,25 +187,30 @@ internal class DefaultKeysBackupService @Inject constructor(
}
val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
megolmBackupAuthData.publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey)
megolmBackupAuthData.privateKeySalt = generatePrivateKeyResult.salt
megolmBackupAuthData.privateKeyIterations = generatePrivateKeyResult.iterations
MegolmBackupAuthData(
publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey),
privateKeySalt = generatePrivateKeyResult.salt,
privateKeyIterations = generatePrivateKeyResult.iterations
)
} else {
val publicKey = olmPkDecryption.generateKey()
megolmBackupAuthData.publicKey = publicKey
MegolmBackupAuthData(
publicKey = publicKey
)
}
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, megolmBackupAuthData.signalableJSONDictionary())
megolmBackupAuthData.signatures = objectSigner.signObject(canonicalJson)
val signedMegolmBackupAuthData = megolmBackupAuthData.copy(
signatures = objectSigner.signObject(canonicalJson)
)
val megolmBackupCreationInfo = MegolmBackupCreationInfo()
megolmBackupCreationInfo.algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
megolmBackupCreationInfo.authData = megolmBackupAuthData
megolmBackupCreationInfo.recoveryKey = computeRecoveryKey(olmPkDecryption.privateKey())
megolmBackupCreationInfo
MegolmBackupCreationInfo(
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
authData = signedMegolmBackupAuthData,
recoveryKey = computeRecoveryKey(olmPkDecryption.privateKey())
)
}
}.foldToCallback(callback)
}
@ -214,11 +218,12 @@ internal class DefaultKeysBackupService @Inject constructor(
override fun createKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo,
callback: MatrixCallback<KeysVersion>) {
val createKeysBackupVersionBody = CreateKeysBackupVersionBody()
createKeysBackupVersionBody.algorithm = keysBackupCreationInfo.algorithm
@Suppress("UNCHECKED_CAST")
createKeysBackupVersionBody.authData = MoshiProvider.providesMoshi().adapter(Map::class.java)
.fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict?
val createKeysBackupVersionBody = CreateKeysBackupVersionBody(
algorithm = keysBackupCreationInfo.algorithm,
authData = MoshiProvider.providesMoshi().adapter(Map::class.java)
.fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict?
)
keysBackupStateManager.state = KeysBackupState.Enabling
@ -229,14 +234,14 @@ internal class DefaultKeysBackupService @Inject constructor(
// Reset backup markers.
cryptoStore.resetBackupMarkers()
val keyBackupVersion = KeysVersionResult()
keyBackupVersion.algorithm = createKeysBackupVersionBody.algorithm
keyBackupVersion.authData = createKeysBackupVersionBody.authData
keyBackupVersion.version = data.version
// We can consider that the server does not have keys yet
keyBackupVersion.count = 0
keyBackupVersion.hash = null
val keyBackupVersion = KeysVersionResult(
algorithm = createKeysBackupVersionBody.algorithm,
authData = createKeysBackupVersionBody.authData,
version = data.version,
// We can consider that the server does not have keys yet
count = 0,
hash = null
)
enableKeysBackup(keyBackupVersion)
@ -406,7 +411,7 @@ internal class DefaultKeysBackupService @Inject constructor(
return keysBackupVersionTrust
}
val mySigs = authData.signatures?.get(userId)
val mySigs = authData.signatures[userId]
if (mySigs.isNullOrEmpty()) {
Timber.v("getKeysBackupTrust: Ignoring key backup because it lacks any signatures from this user")
return keysBackupVersionTrust
@ -469,8 +474,7 @@ internal class DefaultKeysBackupService @Inject constructor(
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) {
// Get current signatures, or create an empty set
val myUserSignatures = authData.signatures?.get(userId)?.toMutableMap()
?: HashMap()
val myUserSignatures = authData.signatures?.get(userId)?.toMutableMap() ?: HashMap()
if (trust) {
// Add current device signature
@ -487,24 +491,23 @@ internal class DefaultKeysBackupService @Inject constructor(
}
// Create an updated version of KeysVersionResult
val updateKeysBackupVersionBody = UpdateKeysBackupVersionBody(keysBackupVersion.version!!)
updateKeysBackupVersionBody.algorithm = keysBackupVersion.algorithm
val newMegolmBackupAuthData = authData.copy()
val newSignatures = newMegolmBackupAuthData.signatures!!.toMutableMap()
newSignatures[userId] = myUserSignatures
newMegolmBackupAuthData.signatures = newSignatures
val newMegolmBackupAuthDataWithNewSignature = newMegolmBackupAuthData.copy(
signatures = newSignatures
)
val moshi = MoshiProvider.providesMoshi()
val adapter = moshi.adapter(Map::class.java)
@Suppress("UNCHECKED_CAST")
updateKeysBackupVersionBody.authData = adapter.fromJson(newMegolmBackupAuthData.toJsonString()) as Map<String, Any>?
updateKeysBackupVersionBody
UpdateKeysBackupVersionBody(
algorithm = keysBackupVersion.algorithm,
authData = adapter.fromJson(newMegolmBackupAuthDataWithNewSignature.toJsonString()) as Map<String, Any>?,
version = keysBackupVersion.version!!)
}
// And send it to the homeserver
@ -513,13 +516,13 @@ internal class DefaultKeysBackupService @Inject constructor(
this.callback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
// Relaunch the state machine on this updated backup version
val newKeysBackupVersion = KeysVersionResult()
newKeysBackupVersion.version = keysBackupVersion.version
newKeysBackupVersion.algorithm = keysBackupVersion.algorithm
newKeysBackupVersion.count = keysBackupVersion.count
newKeysBackupVersion.hash = keysBackupVersion.hash
newKeysBackupVersion.authData = updateKeysBackupVersionBody.authData
val newKeysBackupVersion = KeysVersionResult(
algorithm = keysBackupVersion.algorithm,
authData = updateKeysBackupVersionBody.authData,
version = keysBackupVersion.version,
hash = keysBackupVersion.hash,
count = keysBackupVersion.count
)
checkAndStartWithKeysBackupVersion(newKeysBackupVersion)
@ -807,7 +810,10 @@ internal class DefaultKeysBackupService @Inject constructor(
// new key is sent
val delayInMs = Random.nextLong(KEY_BACKUP_WAITING_TIME_TO_SEND_KEY_BACKUP_MILLIS)
uiHandler.postDelayed({ backupKeys() }, delayInMs)
cryptoCoroutineScope.launch {
delay(delayInMs)
uiHandler.post { backupKeys() }
}
}
else -> {
Timber.v("maybeBackupKeys: Skip it because state: $state")
@ -1024,7 +1030,7 @@ internal class DefaultKeysBackupService @Inject constructor(
}
// Extract the recovery key from the passphrase
val data = retrievePrivateKeyWithPassword(password, authData.privateKeySalt!!, authData.privateKeyIterations!!, progressListener)
val data = retrievePrivateKeyWithPassword(password, authData.privateKeySalt, authData.privateKeyIterations, progressListener)
return computeRecoveryKey(data)
}
@ -1178,14 +1184,16 @@ internal class DefaultKeysBackupService @Inject constructor(
// Gather data to send to the homeserver
// roomId -> sessionId -> MXKeyBackupData
val keysBackupData = KeysBackupData()
keysBackupData.roomIdToRoomKeysBackupData = HashMap()
val keysBackupData = KeysBackupData(
roomIdToRoomKeysBackupData = HashMap()
)
for (olmInboundGroupSessionWrapper in olmInboundGroupSessionWrappers) {
val keyBackupData = encryptGroupSession(olmInboundGroupSessionWrapper)
if (keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId] == null) {
val roomKeysBackupData = RoomKeysBackupData()
roomKeysBackupData.sessionIdToKeyBackupData = HashMap()
val roomKeysBackupData = RoomKeysBackupData(
sessionIdToKeyBackupData = HashMap()
)
keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId!!] = roomKeysBackupData
}
@ -1301,24 +1309,21 @@ internal class DefaultKeysBackupService @Inject constructor(
}
// Build backup data for that key
val keyBackupData = KeyBackupData()
try {
keyBackupData.firstMessageIndex = olmInboundGroupSessionWrapper.olmInboundGroupSession!!.firstKnownIndex
} catch (e: OlmException) {
Timber.e(e, "OlmException")
}
return KeyBackupData(
firstMessageIndex = try {
olmInboundGroupSessionWrapper.olmInboundGroupSession!!.firstKnownIndex
} catch (e: OlmException) {
Timber.e(e, "OlmException")
0L
},
forwardedCount = olmInboundGroupSessionWrapper.forwardingCurve25519KeyChain!!.size,
isVerified = device?.isVerified == true,
keyBackupData.forwardedCount = olmInboundGroupSessionWrapper.forwardingCurve25519KeyChain!!.size
keyBackupData.isVerified = device?.isVerified == true
val data = mapOf(
"ciphertext" to encryptedSessionBackupData!!.mCipherText,
"mac" to encryptedSessionBackupData.mMac,
"ephemeral" to encryptedSessionBackupData.mEphemeralKey)
keyBackupData.sessionData = data
return keyBackupData
sessionData = mapOf(
"ciphertext" to encryptedSessionBackupData!!.mCipherText,
"mac" to encryptedSessionBackupData.mMac,
"ephemeral" to encryptedSessionBackupData.mEphemeralKey)
)
}
@VisibleForTesting
@ -1350,8 +1355,10 @@ internal class DefaultKeysBackupService @Inject constructor(
}
if (sessionBackupData != null) {
sessionBackupData.sessionId = sessionId
sessionBackupData.roomId = roomId
sessionBackupData = sessionBackupData.copy(
sessionId = sessionId,
roomId = roomId
)
}
}
@ -1370,11 +1377,12 @@ internal class DefaultKeysBackupService @Inject constructor(
@VisibleForTesting
fun createFakeKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo,
callback: MatrixCallback<KeysVersion>) {
val createKeysBackupVersionBody = CreateKeysBackupVersionBody()
createKeysBackupVersionBody.algorithm = keysBackupCreationInfo.algorithm
@Suppress("UNCHECKED_CAST")
createKeysBackupVersionBody.authData = MoshiProvider.providesMoshi().adapter(Map::class.java)
.fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict?
val createKeysBackupVersionBody = CreateKeysBackupVersionBody(
algorithm = keysBackupCreationInfo.algorithm,
authData = MoshiProvider.providesMoshi().adapter(Map::class.java)
.fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict?
)
createKeysBackupVersionTask
.configureWith(createKeysBackupVersionBody) {

View file

@ -30,26 +30,27 @@ data class MegolmBackupAuthData(
* The curve25519 public key used to encrypt the backups.
*/
@Json(name = "public_key")
var publicKey: String = "",
val publicKey: String = "",
/**
* In case of a backup created from a password, the salt associated with the backup
* private key.
*/
@Json(name = "private_key_salt")
var privateKeySalt: String? = null,
val privateKeySalt: String? = null,
/**
* In case of a backup created from a password, the number of key derivations.
*/
@Json(name = "private_key_iterations")
var privateKeyIterations: Int? = null,
val privateKeyIterations: Int? = null,
/**
* Signatures of the public key.
* userId -> (deviceSignKeyId -> signature)
*/
var signatures: Map<String, Map<String, String>>? = null
@Json(name = "signatures")
val signatures: Map<String, Map<String, String>>? = null
) {
fun toJsonString(): String {

View file

@ -19,20 +19,19 @@ package im.vector.matrix.android.internal.crypto.keysbackup.model
/**
* Data retrieved from Olm library. algorithm and authData will be send to the homeserver, and recoveryKey will be displayed to the user
*/
class MegolmBackupCreationInfo {
data class MegolmBackupCreationInfo(
/**
* The algorithm used for storing backups [org.matrix.androidsdk.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP].
*/
val algorithm: String = "",
/**
* The algorithm used for storing backups [org.matrix.androidsdk.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP].
*/
var algorithm: String = ""
/**
* Authentication data.
*/
val authData: MegolmBackupAuthData? = null,
/**
* Authentication data.
*/
var authData: MegolmBackupAuthData? = null
/**
* The Base58 recovery key.
*/
var recoveryKey: String = ""
}
/**
* The Base58 recovery key.
*/
val recoveryKey: String = ""
)

View file

@ -16,7 +16,21 @@
package im.vector.matrix.android.internal.crypto.keysbackup.model.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.util.JsonDict
@JsonClass(generateAdapter = true)
class CreateKeysBackupVersionBody : KeysAlgorithmAndData()
data class CreateKeysBackupVersionBody(
/**
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
*/
@Json(name = "algorithm")
override val algorithm: String? = null,
/**
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [im.vector.matrix.android.internal.crypto.keysbackup.MegolmBackupAuthData]
*/
@Json(name = "auth_data")
override val authData: JsonDict? = null
) : KeysAlgorithmAndData

View file

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.crypto.keysbackup.model.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.network.parsing.ForceToBoolean
/**
* Backup data for one key.
@ -29,25 +30,27 @@ data class KeyBackupData(
* Required. The index of the first message in the session that the key can decrypt.
*/
@Json(name = "first_message_index")
var firstMessageIndex: Long = 0,
val firstMessageIndex: Long = 0,
/**
* Required. The number of times this key has been forwarded.
*/
@Json(name = "forwarded_count")
var forwardedCount: Int = 0,
val forwardedCount: Int = 0,
/**
* Whether the device backing up the key has verified the device that the key is from.
* Force to boolean because of https://github.com/matrix-org/synapse/issues/6977
*/
@ForceToBoolean
@Json(name = "is_verified")
var isVerified: Boolean = false,
val isVerified: Boolean = false,
/**
* Algorithm-dependent data.
*/
@Json(name = "session_data")
var sessionData: Map<String, Any>? = null
val sessionData: Map<String, Any>? = null
) {
fun toJsonString(): String {

View file

@ -16,7 +16,6 @@
package im.vector.matrix.android.internal.crypto.keysbackup.model.rest
import com.squareup.moshi.Json
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupAuthData
import im.vector.matrix.android.internal.di.MoshiProvider
@ -38,19 +37,17 @@ import im.vector.matrix.android.internal.di.MoshiProvider
* }
* </pre>
*/
open class KeysAlgorithmAndData {
interface KeysAlgorithmAndData {
/**
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
*/
@Json(name = "algorithm")
var algorithm: String? = null
val algorithm: String?
/**
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [im.vector.matrix.android.internal.crypto.keysbackup.MegolmBackupAuthData]
*/
@Json(name = "auth_data")
var authData: JsonDict? = null
val authData: JsonDict?
/**
* Facility method to convert authData to a MegolmBackupAuthData object

View file

@ -24,9 +24,7 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = true)
data class KeysBackupData(
// the keys are the room IDs, and the values are RoomKeysBackupData
@Json(name = "rooms")
var roomIdToRoomKeysBackupData: MutableMap<String, RoomKeysBackupData> = HashMap()
val roomIdToRoomKeysBackupData: MutableMap<String, RoomKeysBackupData> = HashMap()
)

View file

@ -16,16 +16,33 @@
package im.vector.matrix.android.internal.crypto.keysbackup.model.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.util.JsonDict
@JsonClass(generateAdapter = true)
data class KeysVersionResult(
/**
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
*/
@Json(name = "algorithm")
override val algorithm: String? = null,
/**
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [im.vector.matrix.android.internal.crypto.keysbackup.MegolmBackupAuthData]
*/
@Json(name = "auth_data")
override val authData: JsonDict? = null,
// the backup version
var version: String? = null,
@Json(name = "version")
val version: String? = null,
// The hash value which is an opaque string representing stored keys in the backup
var hash: String? = null,
@Json(name = "hash")
val hash: String? = null,
// The number of keys stored in the backup.
var count: Int? = null
) : KeysAlgorithmAndData()
@Json(name = "count")
val count: Int? = null
) : KeysAlgorithmAndData

View file

@ -24,8 +24,7 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = true)
data class RoomKeysBackupData(
// the keys are the session IDs, and the values are KeyBackupData
@Json(name = "sessions")
var sessionIdToKeyBackupData: MutableMap<String, KeyBackupData> = HashMap()
val sessionIdToKeyBackupData: MutableMap<String, KeyBackupData> = HashMap()
)

View file

@ -16,10 +16,25 @@
package im.vector.matrix.android.internal.crypto.keysbackup.model.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.util.JsonDict
@JsonClass(generateAdapter = true)
data class UpdateKeysBackupVersionBody(
/**
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
*/
@Json(name = "algorithm")
override val algorithm: String? = null,
/**
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [im.vector.matrix.android.internal.crypto.keysbackup.MegolmBackupAuthData]
*/
@Json(name = "auth_data")
override val authData: JsonDict? = null,
// the backup version, mandatory
@Json(name = "version")
val version: String
) : KeysAlgorithmAndData()
) : KeysAlgorithmAndData

View file

@ -26,48 +26,47 @@ import java.io.Serializable
@JsonClass(generateAdapter = true)
data class MXDeviceInfo(
/**
* The id of this device.
*/
@Json(name = "device_id")
var deviceId: String,
val deviceId: String,
/**
* the user id
*/
@Json(name = "user_id")
var userId: String,
val userId: String,
/**
* The list of algorithms supported by this device.
*/
@Json(name = "algorithms")
var algorithms: List<String>? = null,
val algorithms: List<String>? = null,
/**
* A map from "<key type>:<deviceId>" to "<base64-encoded key>".
*/
@Json(name = "keys")
var keys: Map<String, String>? = null,
val keys: Map<String, String>? = null,
/**
* The signature of this MXDeviceInfo.
* A map from "<userId>" to a map from "<key type>:<deviceId>" to "<signature>"
*/
@Json(name = "signatures")
var signatures: Map<String, Map<String, String>>? = null,
val signatures: Map<String, Map<String, String>>? = null,
/*
* Additional data from the home server.
*/
@Json(name = "unsigned")
var unsigned: JsonDict? = null,
val unsigned: JsonDict? = null,
/**
* Verification state of this device.
*/
var verified: Int = DEVICE_VERIFICATION_UNKNOWN
val verified: Int = DEVICE_VERIFICATION_UNKNOWN
) : Serializable {
/**
* Tells if the device is unknown
@ -137,11 +136,11 @@ data class MXDeviceInfo(
map["user_id"] = userId
if (null != algorithms) {
map["algorithms"] = algorithms!!
map["algorithms"] = algorithms
}
if (null != keys) {
map["keys"] = keys!!
map["keys"] = keys
}
return map

View file

@ -116,16 +116,16 @@ class OlmInboundGroupSessionWrapper : Serializable {
return null
}
MegolmSessionData().also {
it.senderClaimedEd25519Key = keysClaimed?.get("ed25519")
it.forwardingCurve25519KeyChain = ArrayList(forwardingCurve25519KeyChain!!)
it.senderKey = senderKey
it.senderClaimedKeys = keysClaimed
it.roomId = roomId
it.sessionId = olmInboundGroupSession!!.sessionIdentifier()
it.sessionKey = olmInboundGroupSession!!.export(olmInboundGroupSession!!.firstKnownIndex)
it.algorithm = MXCRYPTO_ALGORITHM_MEGOLM
}
MegolmSessionData(
senderClaimedEd25519Key = keysClaimed?.get("ed25519"),
forwardingCurve25519KeyChain = ArrayList(forwardingCurve25519KeyChain!!),
senderKey = senderKey,
senderClaimedKeys = keysClaimed,
roomId = roomId,
sessionId = olmInboundGroupSession!!.sessionIdentifier(),
sessionKey = olmInboundGroupSession!!.export(olmInboundGroupSession!!.firstKnownIndex),
algorithm = MXCRYPTO_ALGORITHM_MEGOLM
)
} catch (e: Exception) {
Timber.e(e, "## export() : senderKey $senderKey failed")
null

View file

@ -23,22 +23,21 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = true)
data class EncryptionEventContent(
/**
* Required. The encryption algorithm to be used to encrypt messages sent in this room. Must be 'm.megolm.v1.aes-sha2'.
*/
@Json(name = "algorithm")
var algorithm: String,
val algorithm: String,
/**
* How long the session should be used before changing it. 604800000 (a week) is the recommended default.
*/
@Json(name = "rotation_period_ms")
var rotationPeriodMs: Long? = null,
val rotationPeriodMs: Long? = null,
/**
* How many messages should be sent before changing the session. 100 is the recommended default.
*/
@Json(name = "rotation_period_msgs")
var rotationPeriodMsgs: Long? = null
val rotationPeriodMsgs: Long? = null
)

View file

@ -20,12 +20,11 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class NewDeviceContent(
// the device id
@Json(name = "device_id")
var deviceId: String? = null,
val deviceId: String? = null,
// the room ids list
@Json(name = "rooms")
var rooms: List<String>? = null
val rooms: List<String>? = null
)

View file

@ -27,11 +27,11 @@ data class OlmEventContent(
*
*/
@Json(name = "ciphertext")
var ciphertext: Map<String, Any>? = null,
val ciphertext: Map<String, Any>? = null,
/**
* the sender key
*/
@Json(name = "sender_key")
var senderKey: String? = null
val senderKey: String? = null
)

View file

@ -30,31 +30,31 @@ data class DeviceInfo(
* The owner user id (not documented and useless but the homeserver sent it. You should not need it)
*/
@Json(name = "user_id")
var user_id: String? = null,
val user_id: String? = null,
/**
* The device id
*/
@Json(name = "device_id")
var deviceId: String? = null,
val deviceId: String? = null,
/**
* The device display name
*/
@Json(name = "display_name")
var displayName: String? = null,
val displayName: String? = null,
/**
* The last time this device has been seen.
*/
@Json(name = "last_seen_ts")
var lastSeenTs: Long? = null,
val lastSeenTs: Long? = null,
/**
* The last ip address
*/
@Json(name = "last_seen_ip")
var lastSeenIp: String? = null
val lastSeenIp: String? = null
) : DatedObject {
override val date: Long

View file

@ -24,5 +24,5 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class DevicesListResponse(
@Json(name = "devices")
var devices: List<DeviceInfo>? = null
val devices: List<DeviceInfo>? = null
)

View file

@ -27,38 +27,38 @@ data class EncryptedFileInfo(
* Required. The URL to the file.
*/
@Json(name = "url")
var url: String? = null,
val url: String? = null,
/**
* Not documented
*/
@Json(name = "mimetype")
var mimetype: String? = null,
val mimetype: String? = null,
/**
* Required. A JSON Web Key object.
*/
@Json(name = "key")
var key: EncryptedFileKey? = null,
val key: EncryptedFileKey? = null,
/**
* Required. The Initialisation Vector used by AES-CTR, encoded as unpadded base64.
*/
@Json(name = "iv")
var iv: String? = null,
val iv: String? = null,
/**
* Required. A map from an algorithm name to a hash of the ciphertext, encoded as unpadded base64.
* Clients should support the SHA-256 hash, which uses the key "sha256".
*/
@Json(name = "hashes")
var hashes: Map<String, String>? = null,
val hashes: Map<String, String>? = null,
/**
* Required. Version of the encrypted attachments protocol. Must be "v2".
*/
@Json(name = "v")
var v: String? = null
val v: String? = null
) {
/**
* Check what the spec tells us

View file

@ -24,31 +24,31 @@ data class EncryptedFileKey(
* Required. Algorithm. Must be "A256CTR".
*/
@Json(name = "alg")
var alg: String? = null,
val alg: String? = null,
/**
* Required. Extractable. Must be true. This is a W3C extension.
*/
@Json(name = "ext")
var ext: Boolean? = null,
val ext: Boolean? = null,
/**
* Required. Key operations. Must at least contain "encrypt" and "decrypt".
*/
@Json(name = "key_ops")
var key_ops: List<String>? = null,
val key_ops: List<String>? = null,
/**
* Required. Key type. Must be "oct".
*/
@Json(name = "kty")
var kty: String? = null,
val kty: String? = null,
/**
* Required. The key, encoded as urlsafe unpadded base64.
*/
@Json(name = "k")
var k: String? = null
val k: String? = null
) {
/**
* Check what the spec tells us
@ -62,7 +62,7 @@ data class EncryptedFileKey(
return false
}
if (key_ops?.contains("encrypt") != true || key_ops?.contains("decrypt") != true) {
if (key_ops?.contains("encrypt") != true || !key_ops.contains("decrypt")) {
return false
}

View file

@ -21,11 +21,12 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class EncryptedMessage(
var algorithm: String? = null,
@Json(name = "algorithm")
val algorithm: String? = null,
@Json(name = "sender_key")
var senderKey: String? = null,
val senderKey: String? = null,
@Json(name = "ciphertext")
var cipherText: Map<String, Any>? = null
val cipherText: Map<String, Any>? = null
) : SendToDeviceObject

View file

@ -25,9 +25,9 @@ import com.squareup.moshi.JsonClass
internal data class KeyChangesResponse(
// list of user ids which have new devices
@Json(name = "changed")
var changed: List<String>? = null,
val changed: List<String>? = null,
// List of user ids who are no more tracked.
@Json(name = "left")
var left: List<String>? = null
val left: List<String>? = null
)

View file

@ -24,7 +24,7 @@ import im.vector.matrix.android.internal.crypto.verification.VerificationInfoDon
*/
@JsonClass(generateAdapter = true)
internal data class KeyVerificationDone(
@Json(name = "transaction_id") override var transactionID: String? = null
@Json(name = "transaction_id") override val transactionID: String? = null
) : SendToDeviceObject, VerificationInfoDone {
override fun toSendToDeviceObject() = this

View file

@ -27,7 +27,7 @@ internal data class KeyVerificationRequest(
@Json(name = "from_device") override val fromDevice: String?,
@Json(name = "methods") override val methods: List<String>,
@Json(name = "timestamp") override val timestamp: Long?,
@Json(name = "transaction_id") override var transactionID: String? = null
@Json(name = "transaction_id") override val transactionID: String? = null
) : SendToDeviceObject, VerificationInfoRequest {

View file

@ -24,16 +24,15 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = true)
internal 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,
val timeout: Int? = null,
/**
* Required. The keys to be claimed. A map from user ID, to a map from device ID to algorithm name.
*/
@Json(name = "one_time_keys")
var oneTimeKeys: Map<String, Map<String, String>>
val oneTimeKeys: Map<String, Map<String, String>>
)

View file

@ -24,11 +24,10 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = true)
internal data class KeysClaimResponse(
/**
* The requested keys ordered by device by user.
* TODO Type does not match spec, should be Map<String, JsonDict>
*/
@Json(name = "one_time_keys")
var oneTimeKeys: Map<String, Map<String, Map<String, Map<String, Any>>>>? = null
val oneTimeKeys: Map<String, Map<String, Map<String, Map<String, Any>>>>? = null
)

View file

@ -25,12 +25,11 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = true)
internal data class KeysQueryBody(
/**
* 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,
val timeout: Int? = null,
/**
* Required. The keys to be downloaded.
@ -45,6 +44,5 @@ internal data class KeysQueryBody(
* by the notification in that sync.
*/
@Json(name = "token")
var token: String? = null
val token: String? = null
)

View file

@ -23,13 +23,11 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = true)
internal data class KeysUploadResponse(
/**
* The count per algorithm as returned by the home server: a map (algorithm to count).
*/
@Json(name = "one_time_key_counts")
var oneTimeKeyCounts: Map<String, Int>? = null
val oneTimeKeyCounts: Map<String, Int>? = null
) {
/**
* Helper methods to extract information from 'oneTimeKeyCounts'

View file

@ -25,14 +25,14 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class RoomKeyRequestBody(
@Json(name = "algorithm")
var algorithm: String? = null,
val algorithm: String? = null,
@Json(name = "room_id")
var roomId: String? = null,
val roomId: String? = null,
@Json(name = "sender_key")
var senderKey: String? = null,
val senderKey: String? = null,
@Json(name = "session_id")
var sessionId: String? = null
val sessionId: String? = null
)

View file

@ -15,21 +15,17 @@
*/
package im.vector.matrix.android.internal.crypto.model.rest
import com.squareup.moshi.Json
/**
* Parent class representing an room key action request
* Interface representing an room key action request
* Note: this class cannot be abstract because of [org.matrix.androidsdk.core.JsonUtils.toRoomKeyShare]
*/
internal open class RoomKeyShare : SendToDeviceObject {
internal interface RoomKeyShare : SendToDeviceObject {
var action: String? = null
val action: String?
@Json(name = "requesting_device_id")
var requestingDeviceId: String? = null
val requestingDeviceId: String?
@Json(name = "request_id")
var requestId: String? = null
val requestId: String?
companion object {
const val ACTION_SHARE_REQUEST = "request"

View file

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

View file

@ -16,16 +16,23 @@
*/
package im.vector.matrix.android.internal.crypto.model.rest
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
* Class representing an room key request content
* Class representing a room key request content
*/
@JsonClass(generateAdapter = true)
internal class RoomKeyShareRequest : RoomKeyShare() {
var body: RoomKeyRequestBody? = null
internal data class RoomKeyShareRequest(
@Json(name = "action")
override val action: String? = RoomKeyShare.ACTION_SHARE_REQUEST,
init {
action = ACTION_SHARE_REQUEST
}
}
@Json(name = "requesting_device_id")
override val requestingDeviceId: String? = null,
@Json(name = "request_id")
override val requestId: String? = null,
@Json(name = "body")
val body: RoomKeyRequestBody? = null
) : RoomKeyShare

View file

@ -25,5 +25,5 @@ internal data class UpdateDeviceInfoBody(
* The new display name for this device. If not given, the display name is unchanged.
*/
@Json(name = "display_name")
var displayName: String? = null
val displayName: String? = null
)

View file

@ -20,6 +20,7 @@ package im.vector.matrix.android.internal.crypto.store
import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequestCommon
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.NewSessionListener
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest
@ -382,7 +383,7 @@ internal interface IMXCryptoStore {
*
* @param incomingRoomKeyRequest the incoming key request
*/
fun deleteIncomingRoomKeyRequest(incomingRoomKeyRequest: IncomingRoomKeyRequest)
fun deleteIncomingRoomKeyRequest(incomingRoomKeyRequest: IncomingRoomKeyRequestCommon)
/**
* Search an IncomingRoomKeyRequest

View file

@ -23,6 +23,7 @@ import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequestCommon
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.NewSessionListener
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequest
@ -888,7 +889,7 @@ internal class RealmCryptoStore @Inject constructor(
}
}
override fun deleteIncomingRoomKeyRequest(incomingRoomKeyRequest: IncomingRoomKeyRequest) {
override fun deleteIncomingRoomKeyRequest(incomingRoomKeyRequest: IncomingRoomKeyRequestCommon) {
doRealmTransaction(realmConfiguration) {
it.where<IncomingRoomKeyRequestEntity>()
.equalTo(IncomingRoomKeyRequestEntityFields.USER_ID, incomingRoomKeyRequest.userId)

View file

@ -32,17 +32,17 @@ internal open class IncomingRoomKeyRequestEntity(
) : RealmObject() {
fun toIncomingRoomKeyRequest(): IncomingRoomKeyRequest {
return IncomingRoomKeyRequest().also {
it.requestId = requestId
it.userId = userId
it.deviceId = deviceId
it.requestBody = RoomKeyRequestBody().apply {
algorithm = requestBodyAlgorithm
roomId = requestBodyRoomId
senderKey = requestBodySenderKey
sessionId = requestBodySessionId
}
}
return IncomingRoomKeyRequest(
requestId = requestId,
userId = userId,
deviceId = deviceId,
requestBody = RoomKeyRequestBody(
algorithm = requestBodyAlgorithm,
roomId = requestBodyRoomId,
senderKey = requestBodySenderKey,
sessionId = requestBodySessionId
)
)
}
fun putRequestBody(requestBody: RoomKeyRequestBody?) {

View file

@ -43,12 +43,12 @@ internal open class OutgoingRoomKeyRequestEntity(
fun toOutgoingRoomKeyRequest(): OutgoingRoomKeyRequest {
val cancellationTxnId = this.cancellationTxnId
return OutgoingRoomKeyRequest(
RoomKeyRequestBody().apply {
algorithm = requestBodyAlgorithm
roomId = requestBodyRoomId
senderKey = requestBodySenderKey
sessionId = requestBodySessionId
},
RoomKeyRequestBody(
algorithm = requestBodyAlgorithm,
roomId = requestBodyRoomId,
senderKey = requestBodySenderKey,
sessionId = requestBodySessionId
),
getRecipients()!!,
requestId!!,
OutgoingRoomKeyRequest.RequestState.from(state)

View file

@ -29,7 +29,8 @@ internal interface DownloadKeysForUsersTask : Task<DownloadKeysForUsersTask.Para
// the list of users to get keys for.
val userIds: List<String>?,
// the up-to token
val token: String?)
val token: String?
)
}
internal class DefaultDownloadKeysForUsers @Inject constructor(
@ -41,13 +42,10 @@ internal class DefaultDownloadKeysForUsers @Inject constructor(
val downloadQuery = params.userIds?.associateWith { emptyMap<String, Any>() }.orEmpty()
val body = KeysQueryBody(
deviceKeys = downloadQuery
deviceKeys = downloadQuery,
token = params.token?.takeIf { it.isNotEmpty() }
)
if (!params.token.isNullOrEmpty()) {
body.token = params.token
}
return executeRequest(eventBus) {
apiCall = cryptoApi.downloadKeysForUsers(body)
}

View file

@ -17,7 +17,21 @@
package im.vector.matrix.android.internal.di
import com.squareup.moshi.Moshi
import im.vector.matrix.android.api.session.room.model.message.*
import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent
import im.vector.matrix.android.api.session.room.model.message.MessageContent
import im.vector.matrix.android.api.session.room.model.message.MessageDefaultContent
import im.vector.matrix.android.api.session.room.model.message.MessageEmoteContent
import im.vector.matrix.android.api.session.room.model.message.MessageFileContent
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
import im.vector.matrix.android.api.session.room.model.message.MessageLocationContent
import im.vector.matrix.android.api.session.room.model.message.MessageNoticeContent
import im.vector.matrix.android.api.session.room.model.message.MessageOptionsContent
import im.vector.matrix.android.api.session.room.model.message.MessagePollResponseContent
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
import im.vector.matrix.android.api.session.room.model.message.MessageType
import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
import im.vector.matrix.android.internal.network.parsing.ForceToBooleanJsonAdapter
import im.vector.matrix.android.internal.network.parsing.RuntimeJsonAdapterFactory
import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
@ -31,6 +45,7 @@ object MoshiProvider {
private val moshi: Moshi = Moshi.Builder()
.add(UriMoshiAdapter())
.add(ForceToBooleanJsonAdapter())
.add(RuntimeJsonAdapterFactory.of(UserAccountData::class.java, "type", UserAccountDataEvent::class.java)
.registerSubtype(UserAccountDataDirectMessages::class.java, UserAccountData.TYPE_DIRECT_MESSAGES)
.registerSubtype(UserAccountDataIgnoredUsers::class.java, UserAccountData.TYPE_IGNORED_USER_LIST)

View file

@ -0,0 +1,49 @@
/*
* 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.network.parsing
import com.squareup.moshi.FromJson
import com.squareup.moshi.JsonQualifier
import com.squareup.moshi.JsonReader
import com.squareup.moshi.ToJson
import timber.log.Timber
@JsonQualifier
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FUNCTION)
annotation class ForceToBoolean
internal class ForceToBooleanJsonAdapter {
@ToJson
fun toJson(@ForceToBoolean b: Boolean): Boolean {
return b
}
@FromJson
@ForceToBoolean
fun fromJson(reader: JsonReader): Boolean {
return when (val token = reader.peek()) {
JsonReader.Token.NUMBER -> reader.nextInt() != 0
JsonReader.Token.BOOLEAN -> reader.nextBoolean()
else -> {
Timber.e("Expecting a boolean or a int but get: $token")
reader.skipValue()
false
}
}
}
}

View file

@ -217,4 +217,9 @@ internal class DefaultSession @Inject constructor(
override fun removeListener(listener: Session.Listener) {
sessionListeners.removeListener(listener)
}
// For easy debugging
override fun toString(): String {
return "$myUserId - ${sessionParams.credentials.deviceId}"
}
}

View file

@ -24,13 +24,13 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = true)
data class Filter(
@Json(name = "limit") var limit: Int? = null,
@Json(name = "senders") var senders: MutableList<String>? = null,
@Json(name = "not_senders") var notSenders: MutableList<String>? = null,
@Json(name = "types") var types: MutableList<String>? = null,
@Json(name = "not_types") var notTypes: MutableList<String>? = null,
@Json(name = "rooms") var rooms: MutableList<String>? = null,
@Json(name = "not_rooms") var notRooms: MutableList<String>? = null
@Json(name = "limit") val limit: Int? = null,
@Json(name = "senders") val senders: List<String>? = null,
@Json(name = "not_senders") val notSenders: List<String>? = null,
@Json(name = "types") val types: List<String>? = null,
@Json(name = "not_types") val notTypes: List<String>? = null,
@Json(name = "rooms") val rooms: List<String>? = null,
@Json(name = "not_rooms") val notRooms: List<String>? = null
) {
fun hasData(): Boolean {
return (limit != null

View file

@ -26,11 +26,11 @@ import im.vector.matrix.android.internal.di.MoshiProvider
*/
@JsonClass(generateAdapter = true)
internal data class FilterBody(
@Json(name = "event_fields") var eventFields: List<String>? = null,
@Json(name = "event_format") var eventFormat: String? = null,
@Json(name = "presence") var presence: Filter? = null,
@Json(name = "account_data") var accountData: Filter? = null,
@Json(name = "room") var room: RoomFilter? = null
@Json(name = "event_fields") val eventFields: List<String>? = null,
@Json(name = "event_format") val eventFormat: String? = null,
@Json(name = "presence") val presence: Filter? = null,
@Json(name = "account_data") val accountData: Filter? = null,
@Json(name = "room") val room: RoomFilter? = null
) {
fun toJSONString(): String {

View file

@ -21,32 +21,30 @@ import im.vector.matrix.android.api.session.events.model.EventType
internal object FilterFactory {
fun createDefaultFilterBody(): FilterBody {
val filterBody = FilterBody()
FilterUtil.enableLazyLoading(filterBody, true)
return filterBody
return FilterUtil.enableLazyLoading(FilterBody(), true)
}
fun createRiotFilterBody(): FilterBody {
val filterBody = FilterBody()
filterBody.room = RoomFilter().apply {
timeline = createRiotTimelineFilter()
state = createRiotStateFilter()
}
return filterBody
return FilterBody(
room = RoomFilter(
timeline = createRiotTimelineFilter(),
state = createRiotStateFilter()
)
)
}
fun createDefaultRoomFilter(): RoomEventFilter {
return RoomEventFilter().apply {
lazyLoadMembers = true
}
return RoomEventFilter(
lazyLoadMembers = true
)
}
fun createRiotRoomFilter(): RoomEventFilter {
return RoomEventFilter().apply {
lazyLoadMembers = true
// TODO Enable this for optimization
// types = (listOfSupportedEventTypes + listOfSupportedStateEventTypes).toMutableList()
}
return RoomEventFilter(
lazyLoadMembers = true
// TODO Enable this for optimization
// types = (listOfSupportedEventTypes + listOfSupportedStateEventTypes).toMutableList()
)
}
private fun createRiotTimelineFilter(): RoomEventFilter {
@ -57,9 +55,9 @@ internal object FilterFactory {
}
private fun createRiotStateFilter(): RoomEventFilter {
return RoomEventFilter().apply {
lazyLoadMembers = true
}
return RoomEventFilter(
lazyLoadMembers = true
)
}
// Get only managed types by Riot

View file

@ -24,5 +24,5 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = true)
data class FilterResponse(
@Json(name = "filter_id") var filterId: String
@Json(name = "filter_id") val filterId: String
)

View file

@ -21,7 +21,6 @@ internal object FilterUtil {
/**
* Patch the filterBody to enable or disable the data save mode
*
*
* If data save mode is on, FilterBody will contains
* FIXME New expected filter:
* "{\"room\": {\"ephemeral\": {\"notTypes\": [\"m.typing\"]}}, \"presence\":{\"notTypes\": [\"*\"]}}"
@ -29,6 +28,7 @@ internal object FilterUtil {
* @param filterBody filterBody to patch
* @param useDataSaveMode true to enable data save mode
*/
/*
fun enableDataSaveMode(filterBody: FilterBody, useDataSaveMode: Boolean) {
if (useDataSaveMode) {
// Enable data save mode
@ -78,10 +78,10 @@ internal object FilterUtil {
filterBody.presence = null
}
}
}
} */
/**
* Patch the filterBody to enable or disable the lazy loading
* Compute a new filterBody to enable or disable the lazy loading
*
*
* If lazy loading is on, the filterBody will looks like
@ -90,29 +90,23 @@ internal object FilterUtil {
* @param filterBody filterBody to patch
* @param useLazyLoading true to enable lazy loading
*/
fun enableLazyLoading(filterBody: FilterBody, useLazyLoading: Boolean) {
fun enableLazyLoading(filterBody: FilterBody, useLazyLoading: Boolean): FilterBody {
if (useLazyLoading) {
// Enable lazy loading
if (filterBody.room == null) {
filterBody.room = RoomFilter()
}
if (filterBody.room!!.state == null) {
filterBody.room!!.state = RoomEventFilter()
}
filterBody.room!!.state!!.lazyLoadMembers = true
return filterBody.copy(
room = filterBody.room?.copy(
state = filterBody.room.state?.copy(lazyLoadMembers = true)
?: RoomEventFilter(lazyLoadMembers = true)
)
?: RoomFilter(state = RoomEventFilter(lazyLoadMembers = true))
)
} else {
if (filterBody.room != null && filterBody.room!!.state != null) {
filterBody.room!!.state!!.lazyLoadMembers = null
val newRoomEventFilter = filterBody.room?.state?.copy(lazyLoadMembers = null)?.takeIf { it.hasData() }
val newRoomFilter = filterBody.room?.copy(state = newRoomEventFilter)?.takeIf { it.hasData() }
if (!filterBody.room!!.state!!.hasData()) {
filterBody.room!!.state = null
}
if (!filterBody.room!!.hasData()) {
filterBody.room = null
}
}
return filterBody.copy(
room = newRoomFilter
)
}
}
}

View file

@ -26,14 +26,14 @@ import im.vector.matrix.android.internal.di.MoshiProvider
@JsonClass(generateAdapter = true)
data class RoomEventFilter(
@Json(name = "limit") var limit: Int? = null,
@Json(name = "not_senders") var notSenders: MutableList<String>? = null,
@Json(name = "not_types") var notTypes: MutableList<String>? = null,
@Json(name = "senders") var senders: MutableList<String>? = null,
@Json(name = "types") var types: MutableList<String>? = null,
@Json(name = "rooms") var rooms: MutableList<String>? = null,
@Json(name = "not_rooms") var notRooms: List<String>? = null,
@Json(name = "contains_url") var containsUrl: Boolean? = null,
@Json(name = "lazy_load_members") var lazyLoadMembers: Boolean? = null
@Json(name = "not_senders") val notSenders: List<String>? = null,
@Json(name = "not_types") val notTypes: List<String>? = null,
@Json(name = "senders") val senders: List<String>? = null,
@Json(name = "types") val types: List<String>? = null,
@Json(name = "rooms") val rooms: List<String>? = null,
@Json(name = "not_rooms") val notRooms: List<String>? = null,
@Json(name = "contains_url") val containsUrl: Boolean? = null,
@Json(name = "lazy_load_members") val lazyLoadMembers: Boolean? = null
) {
fun toJSONString(): String {

View file

@ -24,13 +24,13 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = true)
data class RoomFilter(
@Json(name = "not_rooms") var notRooms: List<String>? = null,
@Json(name = "rooms") var rooms: List<String>? = null,
@Json(name = "ephemeral") var ephemeral: RoomEventFilter? = null,
@Json(name = "include_leave") var includeLeave: Boolean? = null,
@Json(name = "state") var state: RoomEventFilter? = null,
@Json(name = "timeline") var timeline: RoomEventFilter? = null,
@Json(name = "account_data") var accountData: RoomEventFilter? = null
@Json(name = "not_rooms") val notRooms: List<String>? = null,
@Json(name = "rooms") val rooms: List<String>? = null,
@Json(name = "ephemeral") val ephemeral: RoomEventFilter? = null,
@Json(name = "include_leave") val includeLeave: Boolean? = null,
@Json(name = "state") val state: RoomEventFilter? = null,
@Json(name = "timeline") val timeline: RoomEventFilter? = null,
@Json(name = "account_data") val accountData: RoomEventFilter? = null
) {
fun hasData(): Boolean {

View file

@ -24,10 +24,10 @@ internal data class GroupSyncProfile(
/**
* The name of the group, if any. May be nil.
*/
@Json(name = "name") var name: String? = null,
@Json(name = "name") val name: String? = null,
/**
* The URL for the group's avatar. May be nil.
*/
@Json(name = "avatar_url") var avatarUrl: String? = null
@Json(name = "avatar_url") val avatarUrl: String? = null
)

View file

@ -67,9 +67,10 @@ DO NOT COMMIT
### invalid formatting
\s{8}/\*\n \*
[^\w]if\(
while\(
for\(
# Now checked by ktlint
# [^\w]if\(
# while\(
# for\(
# Add space after //
# DISABLED To re-enable when code will be formatted globally