Merge branch 'develop' into feature/room_profile

This commit is contained in:
ganfra 2020-01-14 18:35:01 +01:00
commit d3415d345f
203 changed files with 7009 additions and 791 deletions

View File

@ -20,6 +20,7 @@
<w>signin</w> <w>signin</w>
<w>signout</w> <w>signout</w>
<w>signup</w> <w>signup</w>
<w>threepid</w>
</words> </words>
</dictionary> </dictionary>
</component> </component>

View File

@ -1,22 +1,41 @@
Changes in RiotX 0.12.0 (2019-XX-XX) Changes in RiotX 0.13.0 (2020-XX-XX)
=================================================== ===================================================
Features ✨: Features ✨:
- Send and render typing events (#564)
Improvements 🙌:
- Render events m.room.encryption and m.room.guest_access in the timeline
Other changes:
- -
Bugfix 🐛:
-
Translations 🗣:
-
Build 🧱:
- Change the way versionCode is computed (#827)
Changes in RiotX 0.12.0 (2020-01-09)
===================================================
Improvements 🙌: Improvements 🙌:
- The initial sync is now handled by a foreground service - The initial sync is now handled by a foreground service
- Render aliases and canonical alias change in the timeline - Render aliases and canonical alias change in the timeline
- Fix autocompletion issues and add support for rooms and groups
- Introduce developer mode in the settings (#745, #796) - Introduce developer mode in the settings (#745, #796)
- Improve devices list screen - Improve devices list screen
- Add settings for rageshake sensibility - Add settings for rageshake sensibility
- Fix autocompletion issues and add support for rooms, groups, and emoji (#780) - Fix autocompletion issues and add support for rooms, groups, and emoji (#780)
- Show skip to bottom FAB while scrolling down (#752) - Show skip to bottom FAB while scrolling down (#752)
- Enable encryption on a room, SDK part (#212)
Other changes: Other changes:
- Change the way RiotX identifies a session to allow the SDK to support several sessions with the same user (#800) - Change the way RiotX identifies a session to allow the SDK to support several sessions with the same user (#800)
- Exclude play-services-oss-licenses library from F-Droid build (#814) - Exclude play-services-oss-licenses library from F-Droid build (#814)
- Email domain can be limited on some homeservers, i18n of the displayed error (#754)
Bugfix 🐛: Bugfix 🐛:
- Fix crash when opening room creation screen from the room filtering screen - Fix crash when opening room creation screen from the room filtering screen
@ -26,12 +45,6 @@ Bugfix 🐛:
- Fix matrix.org room directory not being browsable (#807) - Fix matrix.org room directory not being browsable (#807)
- Hide non working settings (#751) - Hide non working settings (#751)
Translations 🗣:
-
Build 🧱:
-
Changes in RiotX 0.11.0 (2019-12-19) Changes in RiotX 0.11.0 (2019-12-19)
=================================================== ===================================================
@ -290,7 +303,7 @@ Mode details here: https://medium.com/@RiotChat/introducing-the-riotx-beta-for-a
======================================================= =======================================================
Changes in RiotX 0.0.0 (2019-XX-XX) Changes in RiotX 0.0.0 (2020-XX-XX)
=================================================== ===================================================
Features ✨: Features ✨:

View File

@ -0,0 +1,63 @@
/*
* Copyright 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.account
import im.vector.matrix.android.InstrumentedTest
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 org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class AccountCreationTest : InstrumentedTest {
private val commonTestHelper = CommonTestHelper(context())
private val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
@Test
fun createAccountTest() {
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
commonTestHelper.signout(session)
session.close()
}
@Test
fun createAccountAndLoginAgainTest() {
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
// Log again to the same account
val session2 = commonTestHelper.logIntoAccount(session.myUserId, SessionTestParams(withInitialSync = true))
session.close()
session2.close()
}
@Test
fun simpleE2eTest() {
val res = cryptoTestHelper.doE2ETestWithAliceInARoom()
res.close()
}
}

View File

@ -0,0 +1,278 @@
/*
* Copyright 2016 OpenMarket Ltd
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import android.content.Context
import android.net.Uri
import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.MatrixConfiguration
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
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.room.Room
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
import org.junit.Assert.*
import java.util.*
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
/**
* This class exposes methods to be used in common cases
* Registration, login, Sync, Sending messages...
*/
class CommonTestHelper(context: Context) {
val matrix: Matrix
init {
Matrix.initialize(context, MatrixConfiguration("TestFlavor"))
matrix = Matrix.getInstance(context)
}
fun createAccount(userNamePrefix: String, testParams: SessionTestParams): Session {
return createAccount(userNamePrefix, TestConstants.PASSWORD, testParams)
}
fun logIntoAccount(userId: String, testParams: SessionTestParams): Session {
return logIntoAccount(userId, TestConstants.PASSWORD, testParams)
}
/**
* Create a Home server configuration, with Http connection allowed for test
*/
fun createHomeServerConfig(): HomeServerConnectionConfig {
return HomeServerConnectionConfig.Builder()
.withHomeServerUri(Uri.parse(TestConstants.TESTS_HOME_SERVER_URL))
.build()
}
/**
* This methods init the event stream and check for initial sync
*
* @param session the session to sync
*/
fun syncSession(session: Session) {
// val lock = CountDownLatch(1)
// val observer = androidx.lifecycle.Observer<SyncState> { syncState ->
// if (syncState is SyncState.Idle) {
// lock.countDown()
// }
// }
// TODO observe?
// while (session.syncState().value !is SyncState.Idle) {
// sleep(100)
// }
session.open()
session.startSync(true)
// await(lock)
// session.syncState().removeObserver(observer)
}
/**
* Sends text messages in a room
*
* @param room the room where to send the messages
* @param message the message to send
* @param nbOfMessages the number of time the message will be sent
*/
fun sendTextMessage(room: Room, message: String, nbOfMessages: Int): List<TimelineEvent> {
val sentEvents = ArrayList<TimelineEvent>(nbOfMessages)
val latch = CountDownLatch(nbOfMessages)
val onEventSentListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) {
}
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 })
latch.countDown()
}
}
}
val timeline = room.createTimeline(null, TimelineSettings(10))
timeline.addListener(onEventSentListener)
for (i in 0 until nbOfMessages) {
room.sendTextMessage(message + " #" + (i + 1))
}
await(latch)
timeline.removeListener(onEventSentListener)
// Check that all events has been created
assertEquals(nbOfMessages.toLong(), sentEvents.size.toLong())
return sentEvents
}
// PRIVATE METHODS *****************************************************************************
/**
* Creates a unique account
*
* @param userNamePrefix the user name prefix
* @param password the password
* @param testParams test params about the session
* @return the session associated with the newly created account
*/
private fun createAccount(userNamePrefix: String,
password: String,
testParams: SessionTestParams): Session {
val session = createAccountAndSync(
userNamePrefix + "_" + System.currentTimeMillis() + UUID.randomUUID(),
password,
testParams
)
assertNotNull(session)
return session
}
/**
* Logs into an existing account
*
* @param userId the userId to log in
* @param password the password to log in
* @param testParams test params about the session
* @return the session associated with the existing account
*/
private fun logIntoAccount(userId: String,
password: String,
testParams: SessionTestParams): Session {
val session = logAccountAndSync(userId, password, testParams)
assertNotNull(session)
return session
}
/**
* Create an account and a dedicated session
*
* @param userName the account username
* @param password the password
* @param sessionTestParams parameters for the test
*/
private fun createAccountAndSync(userName: String,
password: String,
sessionTestParams: SessionTestParams): Session {
val hs = createHomeServerConfig()
doSync<LoginFlowResult> {
matrix.authenticationService
.getLoginFlow(hs, it)
}
doSync<RegistrationResult> {
matrix.authenticationService
.getRegistrationWizard()
.createAccount(userName, password, null, it)
}
// Preform dummy step
val registrationResult = doSync<RegistrationResult> {
matrix.authenticationService
.getRegistrationWizard()
.dummy(it)
}
assertTrue(registrationResult is RegistrationResult.Success)
val session = (registrationResult as RegistrationResult.Success).session
if (sessionTestParams.withInitialSync) {
syncSession(session)
}
return session
}
/**
* Start an account login
*
* @param userName the account username
* @param password the password
* @param sessionTestParams session test params
*/
private fun logAccountAndSync(userName: String,
password: String,
sessionTestParams: SessionTestParams): Session {
val hs = createHomeServerConfig()
doSync<LoginFlowResult> {
matrix.authenticationService
.getLoginFlow(hs, it)
}
val session = doSync<Session> {
matrix.authenticationService
.getLoginWizard()
.login(userName, password, "myDevice", it)
}
if (sessionTestParams.withInitialSync) {
syncSession(session)
}
return session
}
/**
* Await for a latch and ensure the result is true
*
* @param latch
* @throws InterruptedException
*/
fun await(latch: CountDownLatch) {
assertTrue(latch.await(TestConstants.timeOutMillis, TimeUnit.MILLISECONDS))
}
// Transform a method with a MatrixCallback to a synchronous method
inline fun <reified T> doSync(block: (MatrixCallback<T>) -> Unit): T {
val lock = CountDownLatch(1)
var result: T? = null
val callback = object : TestMatrixCallback<T>(lock) {
override fun onSuccess(data: T) {
result = data
super.onSuccess(data)
}
}
block.invoke(callback)
await(lock)
assertNotNull(result)
return result!!
}
/**
* Clear all provided sessions
*/
fun Iterable<Session>.close() = forEach { it.close() }
fun signout(session: Session) {
val lock = CountDownLatch(1)
session.signOut(true, object : TestMatrixCallback<Unit>(lock) {})
await(lock)
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import im.vector.matrix.android.api.session.Session
data class CryptoTestData(val firstSession: Session,
val roomId: String,
val secondSession: Session? = null,
val thirdSession: Session? = null) {
fun close() {
firstSession.close()
secondSession?.close()
secondSession?.close()
}
}

View File

@ -0,0 +1,335 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import android.os.SystemClock
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
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
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupAuthData
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
import org.junit.Assert.*
import java.util.*
import java.util.concurrent.CountDownLatch
class CryptoTestHelper(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.")
val defaultSessionParams = SessionTestParams(true)
/**
* @return alice session
*/
fun doE2ETestWithAliceInARoom(): CryptoTestData {
val aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
var roomId: String? = null
val lock1 = CountDownLatch(1)
aliceSession.createRoom(CreateRoomParams().apply { name = "MyRoom" }, object : TestMatrixCallback<String>(lock1) {
override fun onSuccess(data: String) {
roomId = data
super.onSuccess(data)
}
})
mTestHelper.await(lock1)
assertNotNull(roomId)
val room = aliceSession.getRoom(roomId!!)!!
val lock2 = CountDownLatch(1)
room.enableEncryptionWithAlgorithm(MXCRYPTO_ALGORITHM_MEGOLM, object : TestMatrixCallback<Unit>(lock2) {})
mTestHelper.await(lock2)
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
val room = aliceSession.getRoom(aliceRoomId)!!
val bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams)
val lock1 = CountDownLatch(2)
// val bobEventListener = object : MXEventListener() {
// override fun onNewRoom(roomId: String) {
// if (TextUtils.equals(roomId, aliceRoomId)) {
// if (!statuses.containsKey("onNewRoom")) {
// statuses["onNewRoom"] = "onNewRoom"
// lock1.countDown()
// }
// }
// }
// }
//
// bobSession.dataHandler.addListener(bobEventListener)
room.invite(bobSession.myUserId, callback = object : TestMatrixCallback<Unit>(lock1) {
override fun onSuccess(data: Unit) {
statuses["invite"] = "invite"
super.onSuccess(data)
}
})
mTestHelper.await(lock1)
assertTrue(statuses.containsKey("invite") && statuses.containsKey("onNewRoom"))
// bobSession.dataHandler.removeListener(bobEventListener)
val lock2 = CountDownLatch(2)
bobSession.joinRoom(aliceRoomId, callback = TestMatrixCallback(lock2))
// room.addEventListener(object : MXEventListener() {
// override fun onLiveEvent(event: Event, roomState: RoomState) {
// if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_STATE_ROOM_MEMBER)) {
// val contentToConsider = event.contentAsJsonObject
// val member = JsonUtils.toRoomMember(contentToConsider)
//
// if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN)) {
// statuses["AliceJoin"] = "AliceJoin"
// lock2.countDown()
// }
// }
// }
// })
mTestHelper.await(lock2)
// 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)
}
/**
* @return Alice, Bob and Sam session
*/
fun doE2ETestWithAliceAndBobAndSamInARoom(): CryptoTestData {
val statuses = HashMap<String, String>()
val cryptoTestData = doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val aliceRoomId = cryptoTestData.roomId
val room = aliceSession.getRoom(aliceRoomId)!!
val samSession = mTestHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams)
val lock1 = CountDownLatch(2)
// val samEventListener = object : MXEventListener() {
// override fun onNewRoom(roomId: String) {
// if (TextUtils.equals(roomId, aliceRoomId)) {
// if (!statuses.containsKey("onNewRoom")) {
// statuses["onNewRoom"] = "onNewRoom"
// lock1.countDown()
// }
// }
// }
// }
//
// samSession.dataHandler.addListener(samEventListener)
room.invite(samSession.myUserId, null, object : TestMatrixCallback<Unit>(lock1) {
override fun onSuccess(data: Unit) {
statuses["invite"] = "invite"
super.onSuccess(data)
}
})
mTestHelper.await(lock1)
assertTrue(statuses.containsKey("invite") && statuses.containsKey("onNewRoom"))
// samSession.dataHandler.removeListener(samEventListener)
val lock2 = CountDownLatch(1)
samSession.joinRoom(aliceRoomId, null, object : TestMatrixCallback<Unit>(lock2) {
override fun onSuccess(data: Unit) {
statuses["joinRoom"] = "joinRoom"
super.onSuccess(data)
}
})
mTestHelper.await(lock2)
assertTrue(statuses.containsKey("joinRoom"))
// wait the initial sync
SystemClock.sleep(1000)
// samSession.dataHandler.removeListener(samEventListener)
return CryptoTestData(aliceSession, aliceRoomId, cryptoTestData.secondSession, samSession)
}
/**
* @return Alice and Bob sessions
*/
fun doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(): CryptoTestData {
val cryptoTestData = doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val aliceRoomId = cryptoTestData.roomId
val bobSession = cryptoTestData.secondSession!!
bobSession.setWarnOnUnknownDevices(false)
aliceSession.setWarnOnUnknownDevices(false)
val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
var lock = CountDownLatch(1)
val bobEventsListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) {
}
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
val size = snapshot.filter { it.root.senderId != bobSession.myUserId && it.root.getClearType() == EventType.MESSAGE }
.size
if (size == 3) {
lock.countDown()
}
}
}
val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(10))
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)
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)
return cryptoTestData
}
fun checkEncryptedEvent(event: Event, roomId: String, clearMessage: String, senderSession: Session) {
assertEquals(EventType.ENCRYPTED, event.type)
assertNotNull(event.content)
val eventWireContent = event.content.toContent()
assertNotNull(eventWireContent)
assertNull(eventWireContent.get("body"))
assertEquals(MXCRYPTO_ALGORITHM_MEGOLM, eventWireContent.get("algorithm"))
assertNotNull(eventWireContent.get("ciphertext"))
assertNotNull(eventWireContent.get("session_id"))
assertNotNull(eventWireContent.get("sender_key"))
assertEquals(senderSession.sessionParams.credentials.deviceId, eventWireContent.get("device_id"))
assertNotNull(event.eventId)
assertEquals(roomId, event.roomId)
assertEquals(EventType.MESSAGE, event.getClearType())
// TODO assertTrue(event.getAge() < 10000)
val eventContent = event.toContent()
assertNotNull(eventContent)
assertEquals(clearMessage, eventContent.get("body"))
assertEquals(senderSession.myUserId, event.senderId)
}
fun createFakeMegolmBackupAuthData(): MegolmBackupAuthData {
return MegolmBackupAuthData(
publicKey = "abcdefg",
signatures = HashMap<String, Map<String, String>>().apply {
this["something"] = HashMap<String, String>().apply {
this["ed25519:something"] = "hijklmnop"
}
}
)
}
fun createFakeMegolmBackupCreationInfo(): MegolmBackupCreationInfo {
return MegolmBackupCreationInfo().apply {
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
authData = createFakeMegolmBackupAuthData()
}
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import okhttp3.Interceptor
import okhttp3.Protocol
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import javax.net.ssl.HttpsURLConnection
/**
* Allows to intercept network requests for test purpose by
* - re-writing the response
* - changing the response code (200/404/etc..).
* - Test delays..
*
* Basic usage:
* <code>
* val mockInterceptor = MockOkHttpInterceptor()
* mockInterceptor.addRule(MockOkHttpInterceptor.SimpleRule(".well-known/matrix/client", 200, "{}"))
*
* RestHttpClientFactoryProvider.defaultProvider = RestClientHttpClientFactory(mockInterceptor)
* AutoDiscovery().findClientConfig("matrix.org", <callback>)
* </code>
*/
class MockOkHttpInterceptor : Interceptor {
private var rules: ArrayList<Rule> = ArrayList()
fun addRule(rule: Rule) {
rules.add(rule)
}
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
rules.forEach { rule ->
if (originalRequest.url.toString().contains(rule.match)) {
rule.process(originalRequest)?.let {
return it
}
}
}
return chain.proceed(originalRequest)
}
abstract class Rule(val match: String) {
abstract fun process(originalRequest: Request): Response?
}
/**
* Simple rule that reply with the given body for any request that matches the match param
*/
class SimpleRule(match: String,
private val code: Int = HttpsURLConnection.HTTP_OK,
private val body: String = "{}") : Rule(match) {
override fun process(originalRequest: Request): Response? {
return Response.Builder()
.protocol(Protocol.HTTP_1_1)
.request(originalRequest)
.message("mocked answer")
.body(body.toResponseBody(null))
.code(code)
.build()
}
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
data class SessionTestParams @JvmOverloads constructor(val withInitialSync: Boolean = false)

View File

@ -0,0 +1,72 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import org.junit.Assert.*
/**
* Compare two lists and their content
*/
fun assertListEquals(list1: List<Any>?, list2: List<Any>?) {
if (list1 == null) {
assertNull(list2)
} else {
assertNotNull(list2)
assertEquals("List sizes must match", list1.size, list2!!.size)
for (i in list1.indices) {
assertEquals("Elements at index $i are not equal", list1[i], list2[i])
}
}
}
/**
* Compare two maps and their content
*/
fun assertDictEquals(dict1: Map<String, Any>?, dict2: Map<String, Any>?) {
if (dict1 == null) {
assertNull(dict2)
} else {
assertNotNull(dict2)
assertEquals("Map sizes must match", dict1.size, dict2!!.size)
for (i in dict1.keys) {
assertEquals("Values for key $i are not equal", dict1[i], dict2[i])
}
}
}
/**
* Compare two byte arrays content.
* Note that if the arrays have not the same size, it also fails.
*/
fun assertByteArrayNotEqual(a1: ByteArray, a2: ByteArray) {
if (a1.size != a2.size) {
fail("Arrays have not the same size.")
}
for (index in a1.indices) {
if (a1[index] != a2[index]) {
// Difference found!
return
}
}
fail("Arrays are equals.")
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import android.os.Debug
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, when the debugger is connected. 10 minutes
private const val AWAIT_TIME_OUT_WITH_DEBUGGER_MILLIS = 10 * 60000
const val USER_ALICE = "Alice"
const val USER_BOB = "Bob"
const val USER_SAM = "Sam"
const val PASSWORD = "password"
val timeOutMillis: Long
get() = if (Debug.isDebuggerConnected()) {
// Wait more
AWAIT_TIME_OUT_WITH_DEBUGGER_MILLIS.toLong()
} else {
AWAIT_TIME_OUT_MILLIS.toLong()
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.common
import androidx.annotation.CallSuper
import im.vector.matrix.android.api.MatrixCallback
import org.junit.Assert.fail
import timber.log.Timber
import java.util.concurrent.CountDownLatch
/**
* Simple implementation of MatrixCallback, which count down the CountDownLatch on each API callback
* @param onlySuccessful true to fail if an error occurs. This is the default behavior
* @param <T>
*/
open class TestMatrixCallback<T>(private val countDownLatch: CountDownLatch,
private val onlySuccessful: Boolean = true) : MatrixCallback<T> {
@CallSuper
override fun onSuccess(data: T) {
countDownLatch.countDown()
}
@CallSuper
override fun onFailure(failure: Throwable) {
Timber.e(failure, "TestApiCallback")
if (onlySuccessful) {
fail("onFailure " + failure.localizedMessage)
}
countDownLatch.countDown()
}
}

View File

@ -0,0 +1,148 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto
import android.os.MemoryFile
import android.util.Base64
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.internal.crypto.attachments.MXEncryptedAttachments
import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileInfo
import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileKey
import org.junit.Assert.*
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.io.ByteArrayInputStream
import java.io.InputStream
/**
* Unit tests AttachmentEncryptionTest.
*/
@Suppress("SpellCheckingInspection")
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class AttachmentEncryptionTest {
private fun checkDecryption(input: String, encryptedFileInfo: EncryptedFileInfo): String {
val `in` = Base64.decode(input, Base64.DEFAULT)
val inputStream: InputStream
inputStream = if (`in`.isEmpty()) {
ByteArrayInputStream(`in`)
} else {
val memoryFile = MemoryFile("file" + System.currentTimeMillis(), `in`.size)
memoryFile.outputStream.write(`in`)
memoryFile.inputStream
}
val decryptedStream = MXEncryptedAttachments.decryptAttachment(inputStream, encryptedFileInfo)
assertNotNull(decryptedStream)
inputStream.close()
val buffer = ByteArray(100)
val len = decryptedStream!!.read(buffer)
decryptedStream.close()
return Base64.encodeToString(buffer, 0, len, Base64.DEFAULT).replace("\n".toRegex(), "").replace("=".toRegex(), "")
}
@Test
fun checkDecrypt1() {
val encryptedFileInfo = EncryptedFileInfo(
v = "v2",
hashes = mapOf("sha256" to "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU"),
key = EncryptedFileKey(
alg = "A256CTR",
k = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
key_ops = listOf("encrypt", "decrypt"),
kty = "oct",
ext = true
),
iv = "AAAAAAAAAAAAAAAAAAAAAA",
url = "dummyUrl"
)
assertEquals("", checkDecryption("", encryptedFileInfo))
}
@Test
fun checkDecrypt2() {
val encryptedFileInfo = EncryptedFileInfo(
v = "v2",
hashes = mapOf("sha256" to "YzF08lARDdOCzJpzuSwsjTNlQc4pHxpdHcXiD/wpK6k"),
key = EncryptedFileKey(
alg = "A256CTR",
k = "__________________________________________8",
key_ops = listOf("encrypt", "decrypt"),
kty = "oct",
ext = true
),
iv = "//////////8AAAAAAAAAAA",
url = "dummyUrl"
)
assertEquals("SGVsbG8sIFdvcmxk", checkDecryption("5xJZTt5cQicm+9f4", encryptedFileInfo))
}
@Test
fun checkDecrypt3() {
val encryptedFileInfo = EncryptedFileInfo(
v = "v2",
hashes = mapOf("sha256" to "IOq7/dHHB+mfHfxlRY5XMeCWEwTPmlf4cJcgrkf6fVU"),
key = EncryptedFileKey(
alg = "A256CTR",
k = "__________________________________________8",
key_ops = listOf("encrypt", "decrypt"),
kty = "oct",
ext = true
),
iv = "//////////8AAAAAAAAAAA",
url = "dummyUrl"
)
assertEquals("YWxwaGFudW1lcmljYWxseWFscGhhbnVtZXJpY2FsbHlhbHBoYW51bWVyaWNhbGx5YWxwaGFudW1lcmljYWxseQ",
checkDecryption("zhtFStAeFx0s+9L/sSQO+WQMtldqYEHqTxMduJrCIpnkyer09kxJJuA4K+adQE4w+7jZe/vR9kIcqj9rOhDR8Q",
encryptedFileInfo))
}
@Test
fun checkDecrypt4() {
val encryptedFileInfo = EncryptedFileInfo(
v = "v2",
hashes = mapOf("sha256" to "LYG/orOViuFwovJpv2YMLSsmVKwLt7pY3f8SYM7KU5E"),
key = EncryptedFileKey(
alg = "A256CTR",
k = "__________________________________________8",
key_ops = listOf("encrypt", "decrypt"),
kty = "oct",
ext = true
),
iv = "/////////////////////w",
url = "dummyUrl"
)
assertNotEquals("YWxwaGFudW1lcmljYWxseWFscGhhbnVtZXJpY2FsbHlhbHBoYW51bWVyaWNhbGx5YWxwaGFudW1lcmljYWxseQ",
checkDecryption("tJVNBVJ/vl36UQt4Y5e5m84bRUrQHhcdLPvS/7EkDvlkDLZXamBB6k8THbiawiKZ5Mnq9PZMSSbgOCvmnUBOMA",
encryptedFileInfo))
}
}

View File

@ -0,0 +1,206 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.*
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
/**
* Unit tests ExportEncryptionTest.
*/
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ExportEncryptionTest {
@Test
fun checkExportError1() {
val password = "password"
val input = "-----"
var failed = false
try {
MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
failed = true
}
assertTrue(failed)
}
@Test
fun checkExportError2() {
val password = "password"
val input = "-----BEGIN MEGOLM SESSION DATA-----\n" + "-----"
var failed = false
try {
MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
failed = true
}
assertTrue(failed)
}
@Test
fun checkExportError3() {
val password = "password"
val input = "-----BEGIN MEGOLM SESSION DATA-----\n" +
" AXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" +
" cissyYBxjsfsAn\n" +
" -----END MEGOLM SESSION DATA-----"
var failed = false
try {
MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
failed = true
}
assertTrue(failed)
}
@Test
fun checkExportDecrypt1() {
val password = "password"
val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" + "cissyYBxjsfsAndErh065A8=\n-----END MEGOLM SESSION DATA-----"
val expectedString = "plain"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
fail("## checkExportDecrypt1() failed : " + e.message)
}
assertEquals("## checkExportDecrypt1() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportDecrypt2() {
val password = "betterpassword"
val input = "-----BEGIN MEGOLM SESSION DATA-----\nAW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" + "KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n-----END MEGOLM SESSION DATA-----"
val expectedString = "Hello, World"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
fail("## checkExportDecrypt2() failed : " + e.message)
}
assertEquals("## checkExportDecrypt2() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportDecrypt3() {
val password = "SWORDFISH"
val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" + "MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\nPgg29363BGR+/Ripq/VCLKGNbw==\n-----END MEGOLM SESSION DATA-----"
val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption.decryptMegolmKeyFile(input.toByteArray(charset("UTF-8")), password)
} catch (e: Exception) {
fail("## checkExportDecrypt3() failed : " + e.message)
}
assertEquals("## checkExportDecrypt3() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportEncrypt1() {
val password = "password"
val expectedString = "plain"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption
.decryptMegolmKeyFile(MXMegolmExportEncryption.encryptMegolmKeyFile(expectedString, password, 1000), password)
} catch (e: Exception) {
fail("## checkExportEncrypt1() failed : " + e.message)
}
assertEquals("## checkExportEncrypt1() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportEncrypt2() {
val password = "betterpassword"
val expectedString = "Hello, World"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption
.decryptMegolmKeyFile(MXMegolmExportEncryption.encryptMegolmKeyFile(expectedString, password, 1000), password)
} catch (e: Exception) {
fail("## checkExportEncrypt2() failed : " + e.message)
}
assertEquals("## checkExportEncrypt2() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportEncrypt3() {
val password = "SWORDFISH"
val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption
.decryptMegolmKeyFile(MXMegolmExportEncryption.encryptMegolmKeyFile(expectedString, password, 1000), password)
} catch (e: Exception) {
fail("## checkExportEncrypt3() failed : " + e.message)
}
assertEquals("## checkExportEncrypt3() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
@Test
fun checkExportEncrypt4() {
val password = "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword"
val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"
var decodedString: String? = null
try {
decodedString = MXMegolmExportEncryption
.decryptMegolmKeyFile(MXMegolmExportEncryption.encryptMegolmKeyFile(expectedString, password, 1000), password)
} catch (e: Exception) {
fail("## checkExportEncrypt4() failed : " + e.message)
}
assertEquals("## checkExportEncrypt4() : expectedString $expectedString -- decodedString $decodedString",
expectedString,
decodedString)
}
}

View File

@ -0,0 +1,178 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.keysbackup
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.listeners.ProgressListener
import im.vector.matrix.android.common.assertByteArrayNotEqual
import org.junit.Assert.*
import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.olm.OlmManager
import org.matrix.olm.OlmPkDecryption
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class KeysBackupPasswordTest : InstrumentedTest {
@Before
fun ensureLibLoaded() {
OlmManager()
}
/**
* Check KeysBackupPassword utilities
*/
@Test
fun passwordConverter_ok() {
val generatePrivateKeyResult = generatePrivateKeyWithPassword(PASSWORD, null)
assertEquals(32, generatePrivateKeyResult.salt.length)
assertEquals(500_000, generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation
val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
generatePrivateKeyResult.salt,
generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertArrayEquals(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
}
/**
* Check generatePrivateKeyWithPassword progress listener behavior
*/
@Test
fun passwordConverter_progress_ok() {
val progressValues = ArrayList<Int>(101)
var lastTotal = 0
generatePrivateKeyWithPassword(PASSWORD, object : ProgressListener {
override fun onProgress(progress: Int, total: Int) {
if (!progressValues.contains(progress)) {
progressValues.add(progress)
}
lastTotal = total
}
})
assertEquals(100, lastTotal)
// Ensure all values are here
assertEquals(101, progressValues.size)
for (i in 0..100) {
assertTrue(progressValues[i] == i)
}
}
/**
* Check KeysBackupPassword utilities, with bad password
*/
@Test
fun passwordConverter_badPassword_ok() {
val generatePrivateKeyResult = generatePrivateKeyWithPassword(PASSWORD, null)
assertEquals(32, generatePrivateKeyResult.salt.length)
assertEquals(500_000, generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation, with bad password
val retrievedPrivateKey = retrievePrivateKeyWithPassword(BAD_PASSWORD,
generatePrivateKeyResult.salt,
generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
}
/**
* Check KeysBackupPassword utilities, with bad password
*/
@Test
fun passwordConverter_badIteration_ok() {
val generatePrivateKeyResult = generatePrivateKeyWithPassword(PASSWORD, null)
assertEquals(32, generatePrivateKeyResult.salt.length)
assertEquals(500_000, generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation, with bad iteration
val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
generatePrivateKeyResult.salt,
500_001)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
}
/**
* Check KeysBackupPassword utilities, with bad salt
*/
@Test
fun passwordConverter_badSalt_ok() {
val generatePrivateKeyResult = generatePrivateKeyWithPassword(PASSWORD, null)
assertEquals(32, generatePrivateKeyResult.salt.length)
assertEquals(500_000, generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
// Reverse operation, with bad iteration
val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
BAD_SALT,
generatePrivateKeyResult.iterations)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
}
/**
* Check [retrievePrivateKeyWithPassword] with data coming from another platform (RiotWeb).
*/
@Test
fun passwordConverter_crossPlatform_ok() {
val password = "This is a passphrase!"
val salt = "TO0lxhQ9aYgGfMsclVWPIAublg8h9Nlu"
val iteration = 500_000
val retrievedPrivateKey = retrievePrivateKeyWithPassword(password, salt, iteration)
assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
// Data from RiotWeb
val privateKeyBytes = byteArrayOf(
116.toByte(), 224.toByte(), 229.toByte(), 224.toByte(), 9.toByte(), 3.toByte(), 178.toByte(), 162.toByte(),
120.toByte(), 23.toByte(), 108.toByte(), 218.toByte(), 22.toByte(), 61.toByte(), 241.toByte(), 200.toByte(),
235.toByte(), 173.toByte(), 236.toByte(), 100.toByte(), 115.toByte(), 247.toByte(), 33.toByte(), 132.toByte(),
195.toByte(), 154.toByte(), 64.toByte(), 158.toByte(), 184.toByte(), 148.toByte(), 20.toByte(), 85.toByte())
assertArrayEquals(privateKeyBytes, retrievedPrivateKey)
}
companion object {
private const val PASSWORD = "password"
private const val BAD_PASSWORD = "passw0rd"
private const val BAD_SALT = "AA0lxhQ9aYgGfMsclVWPIAublg8h9Nlu"
}
}

View File

@ -0,0 +1,104 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.keysbackup
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupStateListener
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import java.util.concurrent.CountDownLatch
/**
* This class observe the state change of a KeysBackup object and provide a method to check the several state change
* It checks all state transitions and detected forbidden transition
*/
internal class StateObserver(private val keysBackup: KeysBackupService,
private val latch: CountDownLatch? = null,
private val expectedStateChange: Int = -1) : KeysBackupStateListener {
private val allowedStateTransitions = listOf(
KeysBackupState.BackingUp to KeysBackupState.ReadyToBackUp,
KeysBackupState.BackingUp to KeysBackupState.WrongBackUpVersion,
KeysBackupState.CheckingBackUpOnHomeserver to KeysBackupState.Disabled,
KeysBackupState.CheckingBackUpOnHomeserver to KeysBackupState.NotTrusted,
KeysBackupState.CheckingBackUpOnHomeserver to KeysBackupState.ReadyToBackUp,
KeysBackupState.CheckingBackUpOnHomeserver to KeysBackupState.Unknown,
KeysBackupState.CheckingBackUpOnHomeserver to KeysBackupState.WrongBackUpVersion,
KeysBackupState.Disabled to KeysBackupState.Enabling,
KeysBackupState.Enabling to KeysBackupState.Disabled,
KeysBackupState.Enabling to KeysBackupState.ReadyToBackUp,
KeysBackupState.NotTrusted to KeysBackupState.CheckingBackUpOnHomeserver,
// This transition happens when we trust the device
KeysBackupState.NotTrusted to KeysBackupState.ReadyToBackUp,
KeysBackupState.ReadyToBackUp to KeysBackupState.WillBackUp,
KeysBackupState.Unknown to KeysBackupState.CheckingBackUpOnHomeserver,
KeysBackupState.WillBackUp to KeysBackupState.BackingUp,
KeysBackupState.WrongBackUpVersion to KeysBackupState.CheckingBackUpOnHomeserver,
// FIXME These transitions are observed during test, and I'm not sure they should occur. Don't have time to investigate now
KeysBackupState.ReadyToBackUp to KeysBackupState.BackingUp,
KeysBackupState.ReadyToBackUp to KeysBackupState.ReadyToBackUp,
KeysBackupState.WillBackUp to KeysBackupState.ReadyToBackUp,
KeysBackupState.WillBackUp to KeysBackupState.Unknown
)
private val stateList = ArrayList<KeysBackupState>()
private var lastTransitionError: String? = null
init {
keysBackup.addListener(this)
}
// TODO Make expectedStates mandatory to enforce test
fun stopAndCheckStates(expectedStates: List<KeysBackupState>?) {
keysBackup.removeListener(this)
expectedStates?.let {
assertEquals(it.size, stateList.size)
for (i in it.indices) {
assertEquals("The state $i is not correct. states: " + stateList.joinToString(separator = " "), it[i], stateList[i])
}
}
assertNull("states: " + stateList.joinToString(separator = " "), lastTransitionError)
}
override fun onStateChange(newState: KeysBackupState) {
stateList.add(newState)
// Check that state transition is valid
if (stateList.size >= 2
&& !allowedStateTransitions.contains(stateList[stateList.size - 2] to newState)) {
// Forbidden transition detected
lastTransitionError = "Forbidden transition detected from " + stateList[stateList.size - 2] + " to " + newState
}
if (expectedStateChange == stateList.size) {
latch?.countDown()
}
}
}

View File

@ -0,0 +1,525 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.crypto.verification
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.sas.*
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.common.CommonTestHelper
import im.vector.matrix.android.common.CryptoTestHelper
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationCancel
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
import org.junit.Assert.*
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import java.util.*
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class SASTest : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
@Test
fun test_aliceStartThenAliceCancel() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceSasMgr = aliceSession.getSasVerificationService()
val bobSasMgr = bobSession!!.getSasVerificationService()
val bobTxCreatedLatch = CountDownLatch(1)
val bobListener = object : SasVerificationService.SasVerificationListener {
override fun transactionCreated(tx: SasVerificationTransaction) {}
override fun transactionUpdated(tx: SasVerificationTransaction) {
bobTxCreatedLatch.countDown()
}
override fun markedAsManuallyVerified(userId: String, deviceId: String) {}
}
bobSasMgr.addListener(bobListener)
val txID = aliceSasMgr.beginKeyVerificationSAS(bobSession.myUserId, bobSession.getMyDevice().deviceId)
assertNotNull("Alice should have a started transaction", txID)
val aliceKeyTx = aliceSasMgr.getExistingTransaction(bobSession.myUserId, txID!!)
assertNotNull("Alice should have a started transaction", aliceKeyTx)
mTestHelper.await(bobTxCreatedLatch)
bobSasMgr.removeListener(bobListener)
val bobKeyTx = bobSasMgr.getExistingTransaction(aliceSession.myUserId, txID)
assertNotNull("Bob should have started verif transaction", bobKeyTx)
assertTrue(bobKeyTx is SASVerificationTransaction)
assertNotNull("Bob should have starting a SAS transaction", bobKeyTx)
assertTrue(aliceKeyTx is SASVerificationTransaction)
assertEquals("Alice and Bob have same transaction id", aliceKeyTx!!.transactionId, bobKeyTx!!.transactionId)
val aliceSasTx = aliceKeyTx as SASVerificationTransaction?
val bobSasTx = bobKeyTx as SASVerificationTransaction?
assertEquals("Alice state should be started", SasVerificationTxState.Started, aliceSasTx!!.state)
assertEquals("Bob state should be started by alice", SasVerificationTxState.OnStarted, bobSasTx!!.state)
// Let's cancel from alice side
val cancelLatch = CountDownLatch(1)
val bobListener2 = object : SasVerificationService.SasVerificationListener {
override fun transactionCreated(tx: SasVerificationTransaction) {}
override fun transactionUpdated(tx: SasVerificationTransaction) {
if (tx.transactionId == txID) {
if ((tx as SASVerificationTransaction).state === SasVerificationTxState.OnCancelled) {
cancelLatch.countDown()
}
}
}
override fun markedAsManuallyVerified(userId: String, deviceId: String) {}
}
bobSasMgr.addListener(bobListener2)
aliceSasTx.cancel(CancelCode.User)
mTestHelper.await(cancelLatch)
assertEquals("Should be cancelled on alice side",
SasVerificationTxState.Cancelled, aliceSasTx.state)
assertEquals("Should be cancelled on bob side",
SasVerificationTxState.OnCancelled, bobSasTx.state)
assertEquals("Should be User cancelled on alice side",
CancelCode.User, aliceSasTx.cancelledReason)
assertEquals("Should be User cancelled on bob side",
CancelCode.User, aliceSasTx.cancelledReason)
assertNull(bobSasMgr.getExistingTransaction(aliceSession.myUserId, txID))
assertNull(aliceSasMgr.getExistingTransaction(bobSession.myUserId, txID))
cryptoTestData.close()
}
@Test
fun test_key_agreement_protocols_must_include_curve25519() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val bobSession = cryptoTestData.secondSession!!
val protocols = listOf("meh_dont_know")
val tid = "00000000"
// Bob should receive a cancel
var canceledToDeviceEvent: Event? = null
val cancelLatch = CountDownLatch(1)
// TODO bobSession!!.dataHandler.addListener(object : MXEventListener() {
// TODO override fun onToDeviceEvent(event: Event?) {
// TODO if (event!!.getType() == CryptoEvent.EVENT_TYPE_KEY_VERIFICATION_CANCEL) {
// TODO if (event.contentAsJsonObject?.get("transaction_id")?.asString == tid) {
// TODO canceledToDeviceEvent = event
// TODO cancelLatch.countDown()
// TODO }
// TODO }
// TODO }
// TODO })
val aliceSession = cryptoTestData.firstSession
val aliceUserID = aliceSession.myUserId
val aliceDevice = aliceSession.getMyDevice().deviceId
val aliceListener = object : SasVerificationService.SasVerificationListener {
override fun transactionCreated(tx: SasVerificationTransaction) {}
override fun transactionUpdated(tx: SasVerificationTransaction) {
if ((tx as IncomingSASVerificationTransaction).uxState === IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT) {
(tx as IncomingSASVerificationTransaction).performAccept()
}
}
override fun markedAsManuallyVerified(userId: String, deviceId: String) {}
}
aliceSession.getSasVerificationService().addListener(aliceListener)
fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, protocols = protocols)
mTestHelper.await(cancelLatch)
val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
cryptoTestData.close()
}
@Test
fun test_key_agreement_macs_Must_include_hmac_sha256() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val bobSession = cryptoTestData.secondSession!!
val mac = listOf("shaBit")
val tid = "00000000"
// Bob should receive a cancel
var canceledToDeviceEvent: Event? = null
val cancelLatch = CountDownLatch(1)
// TODO bobSession!!.dataHandler.addListener(object : MXEventListener() {
// TODO override fun onToDeviceEvent(event: Event?) {
// TODO if (event!!.getType() == CryptoEvent.EVENT_TYPE_KEY_VERIFICATION_CANCEL) {
// TODO if (event.contentAsJsonObject?.get("transaction_id")?.asString == tid) {
// TODO canceledToDeviceEvent = event
// TODO cancelLatch.countDown()
// TODO }
// TODO }
// TODO }
// TODO })
val aliceSession = cryptoTestData.firstSession
val aliceUserID = aliceSession.myUserId
val aliceDevice = aliceSession.getMyDevice().deviceId
fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, mac = mac)
mTestHelper.await(cancelLatch)
val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
cryptoTestData.close()
}
@Test
fun test_key_agreement_short_code_include_decimal() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val bobSession = cryptoTestData.secondSession!!
val codes = listOf("bin", "foo", "bar")
val tid = "00000000"
// Bob should receive a cancel
var canceledToDeviceEvent: Event? = null
val cancelLatch = CountDownLatch(1)
// TODO bobSession!!.dataHandler.addListener(object : MXEventListener() {
// TODO override fun onToDeviceEvent(event: Event?) {
// TODO if (event!!.getType() == CryptoEvent.EVENT_TYPE_KEY_VERIFICATION_CANCEL) {
// TODO if (event.contentAsJsonObject?.get("transaction_id")?.asString == tid) {
// TODO canceledToDeviceEvent = event
// TODO cancelLatch.countDown()
// TODO }
// TODO }
// TODO }
// TODO })
val aliceSession = cryptoTestData.firstSession
val aliceUserID = aliceSession.myUserId
val aliceDevice = aliceSession.getMyDevice().deviceId
fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, codes = codes)
mTestHelper.await(cancelLatch)
val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
cryptoTestData.close()
}
private fun fakeBobStart(bobSession: Session,
aliceUserID: String?,
aliceDevice: String?,
tid: String,
protocols: List<String> = SASVerificationTransaction.KNOWN_AGREEMENT_PROTOCOLS,
hashes: List<String> = SASVerificationTransaction.KNOWN_HASHES,
mac: List<String> = SASVerificationTransaction.KNOWN_MACS,
codes: List<String> = SASVerificationTransaction.KNOWN_SHORT_CODES) {
val startMessage = KeyVerificationStart()
startMessage.fromDevice = bobSession.getMyDevice().deviceId
startMessage.method = KeyVerificationStart.VERIF_METHOD_SAS
startMessage.transactionID = tid
startMessage.keyAgreementProtocols = protocols
startMessage.hashes = hashes
startMessage.messageAuthenticationCodes = mac
startMessage.shortAuthenticationStrings = codes
val contentMap = MXUsersDevicesMap<Any>()
contentMap.setObject(aliceUserID, aliceDevice, startMessage)
// TODO val sendLatch = CountDownLatch(1)
// TODO bobSession.cryptoRestClient.sendToDevice(
// TODO EventType.KEY_VERIFICATION_START,
// TODO contentMap,
// TODO tid,
// TODO TestMatrixCallback<Void>(sendLatch)
// TODO )
}
// any two devices may only have at most one key verification in flight at a time.
// If a device has two verifications in progress with the same device, then it should cancel both verifications.
@Test
fun test_aliceStartTwoRequests() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceSasMgr = aliceSession.getSasVerificationService()
val aliceCreatedLatch = CountDownLatch(2)
val aliceCancelledLatch = CountDownLatch(2)
val createdTx = ArrayList<SASVerificationTransaction>()
val aliceListener = object : SasVerificationService.SasVerificationListener {
override fun transactionCreated(tx: SasVerificationTransaction) {
createdTx.add(tx as SASVerificationTransaction)
aliceCreatedLatch.countDown()
}
override fun transactionUpdated(tx: SasVerificationTransaction) {
if ((tx as SASVerificationTransaction).state === SasVerificationTxState.OnCancelled) {
aliceCancelledLatch.countDown()
}
}
override fun markedAsManuallyVerified(userId: String, deviceId: String) {}
}
aliceSasMgr.addListener(aliceListener)
val bobUserId = bobSession!!.myUserId
val bobDeviceId = bobSession.getMyDevice().deviceId
aliceSasMgr.beginKeyVerificationSAS(bobUserId, bobDeviceId)
aliceSasMgr.beginKeyVerificationSAS(bobUserId, bobDeviceId)
mTestHelper.await(aliceCreatedLatch)
mTestHelper.await(aliceCancelledLatch)
cryptoTestData.close()
}
/**
* Test that when alice starts a 'correct' request, bob agrees.
*/
@Test
fun test_aliceAndBobAgreement() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceSasMgr = aliceSession.getSasVerificationService()
val bobSasMgr = bobSession!!.getSasVerificationService()
var accepted: KeyVerificationAccept? = null
var startReq: KeyVerificationStart? = null
val aliceAcceptedLatch = CountDownLatch(1)
val aliceListener = object : SasVerificationService.SasVerificationListener {
override fun markedAsManuallyVerified(userId: String, deviceId: String) {}
override fun transactionCreated(tx: SasVerificationTransaction) {}
override fun transactionUpdated(tx: SasVerificationTransaction) {
if ((tx as SASVerificationTransaction).state === SasVerificationTxState.OnAccepted) {
val at = tx as SASVerificationTransaction
accepted = at.accepted
startReq = at.startReq
aliceAcceptedLatch.countDown()
}
}
}
aliceSasMgr.addListener(aliceListener)
val bobListener = object : SasVerificationService.SasVerificationListener {
override fun transactionCreated(tx: SasVerificationTransaction) {}
override fun transactionUpdated(tx: SasVerificationTransaction) {
if ((tx as IncomingSASVerificationTransaction).uxState === IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT) {
val at = tx as IncomingSASVerificationTransaction
at.performAccept()
}
}
override fun markedAsManuallyVerified(userId: String, deviceId: String) {}
}
bobSasMgr.addListener(bobListener)
val bobUserId = bobSession.myUserId
val bobDeviceId = bobSession.getMyDevice().deviceId
aliceSasMgr.beginKeyVerificationSAS(bobUserId, bobDeviceId)
mTestHelper.await(aliceAcceptedLatch)
assertTrue("Should have receive a commitment", accepted!!.commitment?.trim()?.isEmpty() == false)
// check that agreement is valid
assertTrue("Agreed Protocol should be Valid", accepted!!.isValid())
assertTrue("Agreed Protocol should be known by alice", startReq!!.keyAgreementProtocols!!.contains(accepted!!.keyAgreementProtocol))
assertTrue("Hash should be known by alice", startReq!!.hashes!!.contains(accepted!!.hash))
assertTrue("Hash should be known by alice", startReq!!.messageAuthenticationCodes!!.contains(accepted!!.messageAuthenticationCode))
accepted!!.shortAuthenticationStrings?.forEach {
assertTrue("all agreed Short Code should be known by alice", startReq!!.shortAuthenticationStrings!!.contains(it))
}
cryptoTestData.close()
}
@Test
fun test_aliceAndBobSASCode() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceSasMgr = aliceSession.getSasVerificationService()
val bobSasMgr = bobSession!!.getSasVerificationService()
val aliceSASLatch = CountDownLatch(1)
val aliceListener = object : SasVerificationService.SasVerificationListener {
override fun transactionCreated(tx: SasVerificationTransaction) {}
override fun transactionUpdated(tx: SasVerificationTransaction) {
val uxState = (tx as OutgoingSASVerificationRequest).uxState
when (uxState) {
OutgoingSasVerificationRequest.UxState.SHOW_SAS -> {
aliceSASLatch.countDown()
}
else -> Unit
}
}
override fun markedAsManuallyVerified(userId: String, deviceId: String) {}
}
aliceSasMgr.addListener(aliceListener)
val bobSASLatch = CountDownLatch(1)
val bobListener = object : SasVerificationService.SasVerificationListener {
override fun transactionCreated(tx: SasVerificationTransaction) {}
override fun transactionUpdated(tx: SasVerificationTransaction) {
val uxState = (tx as IncomingSASVerificationTransaction).uxState
when (uxState) {
IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {
tx.performAccept()
}
else -> Unit
}
if (uxState === IncomingSasVerificationTransaction.UxState.SHOW_SAS) {
bobSASLatch.countDown()
}
}
override fun markedAsManuallyVerified(userId: String, deviceId: String) {}
}
bobSasMgr.addListener(bobListener)
val bobUserId = bobSession.myUserId
val bobDeviceId = bobSession.getMyDevice().deviceId
val verificationSAS = aliceSasMgr.beginKeyVerificationSAS(bobUserId, bobDeviceId)
mTestHelper.await(aliceSASLatch)
mTestHelper.await(bobSASLatch)
val aliceTx = aliceSasMgr.getExistingTransaction(bobUserId, verificationSAS!!) as SASVerificationTransaction
val bobTx = bobSasMgr.getExistingTransaction(aliceSession.myUserId, verificationSAS) as SASVerificationTransaction
assertEquals("Should have same SAS", aliceTx.getShortCodeRepresentation(SasMode.DECIMAL),
bobTx.getShortCodeRepresentation(SasMode.DECIMAL))
cryptoTestData.close()
}
@Test
fun test_happyPath() {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
val aliceSession = cryptoTestData.firstSession
val bobSession = cryptoTestData.secondSession
val aliceSasMgr = aliceSession.getSasVerificationService()
val bobSasMgr = bobSession!!.getSasVerificationService()
val aliceSASLatch = CountDownLatch(1)
val aliceListener = object : SasVerificationService.SasVerificationListener {
override fun transactionCreated(tx: SasVerificationTransaction) {}
override fun transactionUpdated(tx: SasVerificationTransaction) {
val uxState = (tx as OutgoingSASVerificationRequest).uxState
when (uxState) {
OutgoingSasVerificationRequest.UxState.SHOW_SAS -> {
tx.userHasVerifiedShortCode()
}
OutgoingSasVerificationRequest.UxState.VERIFIED -> {
aliceSASLatch.countDown()
}
else -> Unit
}
}
override fun markedAsManuallyVerified(userId: String, deviceId: String) {}
}
aliceSasMgr.addListener(aliceListener)
val bobSASLatch = CountDownLatch(1)
val bobListener = object : SasVerificationService.SasVerificationListener {
override fun transactionCreated(tx: SasVerificationTransaction) {}
override fun transactionUpdated(tx: SasVerificationTransaction) {
val uxState = (tx as IncomingSASVerificationTransaction).uxState
when (uxState) {
IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {
tx.performAccept()
}
IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
tx.userHasVerifiedShortCode()
}
IncomingSasVerificationTransaction.UxState.VERIFIED -> {
bobSASLatch.countDown()
}
else -> Unit
}
}
override fun markedAsManuallyVerified(userId: String, deviceId: String) {}
}
bobSasMgr.addListener(bobListener)
val bobUserId = bobSession.myUserId
val bobDeviceId = bobSession.getMyDevice().deviceId
aliceSasMgr.beginKeyVerificationSAS(bobUserId, bobDeviceId)
mTestHelper.await(aliceSASLatch)
mTestHelper.await(bobSASLatch)
// Assert that devices are verified
val bobDeviceInfoFromAlicePOV: MXDeviceInfo? = aliceSession.getDeviceInfo(bobUserId, bobDeviceId)
val aliceDeviceInfoFromBobPOV: MXDeviceInfo? = bobSession.getDeviceInfo(aliceSession.myUserId, aliceSession.getMyDevice().deviceId)
// latch wait a bit again
Thread.sleep(1000)
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()
}
}

View File

@ -18,6 +18,7 @@ package im.vector.matrix.android.api.auth.data
import com.squareup.moshi.Json import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.util.md5
/** /**
* This data class hold credentials user data. * This data class hold credentials user data.
@ -34,3 +35,7 @@ data class Credentials(
// Optional data that may contain info to override home server and/or identity server // Optional data that may contain info to override home server and/or identity server
@Json(name = "well_known") val wellKnown: WellKnown? = null @Json(name = "well_known") val wellKnown: WellKnown? = null
) )
internal fun Credentials.sessionId(): String {
return (if (deviceId.isNullOrBlank()) userId else "$userId|$deviceId").md5()
}

View File

@ -75,6 +75,11 @@ interface Session :
val myUserId: String val myUserId: String
get() = sessionParams.credentials.userId get() = sessionParams.credentials.userId
/**
* The sessionId
*/
val sessionId: String
/** /**
* This method allow to open a session. It does start some service on the background. * This method allow to open a session. It does start some service on the background.
*/ */

View File

@ -25,7 +25,6 @@ object EventType {
const val MESSAGE = "m.room.message" const val MESSAGE = "m.room.message"
const val STICKER = "m.sticker" const val STICKER = "m.sticker"
const val ENCRYPTED = "m.room.encrypted" const val ENCRYPTED = "m.room.encrypted"
const val ENCRYPTION = "m.room.encryption"
const val FEEDBACK = "m.room.message.feedback" const val FEEDBACK = "m.room.message.feedback"
const val TYPING = "m.typing" const val TYPING = "m.typing"
const val REDACTION = "m.room.redaction" const val REDACTION = "m.room.redaction"
@ -54,6 +53,7 @@ object EventType {
const val STATE_ROOM_HISTORY_VISIBILITY = "m.room.history_visibility" const val STATE_ROOM_HISTORY_VISIBILITY = "m.room.history_visibility"
const val STATE_ROOM_RELATED_GROUPS = "m.room.related_groups" const val STATE_ROOM_RELATED_GROUPS = "m.room.related_groups"
const val STATE_ROOM_PINNED_EVENT = "m.room.pinned_events" const val STATE_ROOM_PINNED_EVENT = "m.room.pinned_events"
const val STATE_ROOM_ENCRYPTION = "m.room.encryption"
// Call Events // Call Events
@ -91,7 +91,8 @@ object EventType {
STATE_ROOM_CANONICAL_ALIAS, STATE_ROOM_CANONICAL_ALIAS,
STATE_ROOM_HISTORY_VISIBILITY, STATE_ROOM_HISTORY_VISIBILITY,
STATE_ROOM_RELATED_GROUPS, STATE_ROOM_RELATED_GROUPS,
STATE_ROOM_PINNED_EVENT STATE_ROOM_PINNED_EVENT,
STATE_ROOM_ENCRYPTION
) )
fun isStateEvent(type: String): Boolean { fun isStateEvent(type: String): Boolean {

View File

@ -22,12 +22,13 @@ import im.vector.matrix.android.api.session.room.members.MembershipService
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.relation.RelationService import im.vector.matrix.android.api.session.room.model.relation.RelationService
import im.vector.matrix.android.api.session.room.notification.RoomPushRuleService import im.vector.matrix.android.api.session.room.notification.RoomPushRuleService
import im.vector.matrix.android.api.session.room.reporting.ReportingService
import im.vector.matrix.android.api.session.room.read.ReadService import im.vector.matrix.android.api.session.room.read.ReadService
import im.vector.matrix.android.api.session.room.reporting.ReportingService
import im.vector.matrix.android.api.session.room.send.DraftService import im.vector.matrix.android.api.session.room.send.DraftService
import im.vector.matrix.android.api.session.room.send.SendService import im.vector.matrix.android.api.session.room.send.SendService
import im.vector.matrix.android.api.session.room.state.StateService import im.vector.matrix.android.api.session.room.state.StateService
import im.vector.matrix.android.api.session.room.timeline.TimelineService import im.vector.matrix.android.api.session.room.timeline.TimelineService
import im.vector.matrix.android.api.session.room.typing.TypingService
import im.vector.matrix.android.api.util.Optional import im.vector.matrix.android.api.util.Optional
/** /**
@ -38,6 +39,7 @@ interface Room :
SendService, SendService,
DraftService, DraftService,
ReadService, ReadService,
TypingService,
MembershipService, MembershipService,
StateService, StateService,
ReportingService, ReportingService,

View File

@ -16,6 +16,8 @@
package im.vector.matrix.android.api.session.room.crypto package im.vector.matrix.android.api.session.room.crypto
import im.vector.matrix.android.api.MatrixCallback
interface RoomCryptoService { interface RoomCryptoService {
fun isEncrypted(): Boolean fun isEncrypted(): Boolean
@ -23,4 +25,6 @@ interface RoomCryptoService {
fun encryptionAlgorithm(): String? fun encryptionAlgorithm(): String?
fun shouldEncryptForInvitedMembers(): Boolean fun shouldEncryptForInvitedMembers(): Boolean
fun enableEncryptionWithAlgorithm(algorithm: String, callback: MatrixCallback<Unit>)
} }

View File

@ -29,7 +29,8 @@ fun roomMemberQueryParams(init: (RoomMemberQueryParams.Builder.() -> Unit) = {})
data class RoomMemberQueryParams( data class RoomMemberQueryParams(
val displayName: QueryStringValue, val displayName: QueryStringValue,
val memberships: List<Membership>, val memberships: List<Membership>,
val userId: QueryStringValue val userId: QueryStringValue,
val excludeSelf: Boolean
) { ) {
class Builder { class Builder {
@ -37,11 +38,13 @@ data class RoomMemberQueryParams(
var userId: QueryStringValue = QueryStringValue.NoCondition var userId: QueryStringValue = QueryStringValue.NoCondition
var displayName: QueryStringValue = QueryStringValue.IsNotEmpty var displayName: QueryStringValue = QueryStringValue.IsNotEmpty
var memberships: List<Membership> = Membership.all() var memberships: List<Membership> = Membership.all()
var excludeSelf: Boolean = false
fun build() = RoomMemberQueryParams( fun build() = RoomMemberQueryParams(
displayName = displayName, displayName = displayName,
memberships = memberships, memberships = memberships,
userId = userId userId = userId,
excludeSelf = excludeSelf
) )
} }
} }

View File

@ -0,0 +1,37 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.room.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
* Class representing the EventType.STATE_ROOM_GUEST_ACCESS state event content
* Ref: https://matrix.org/docs/spec/client_server/latest#m-room-guest-access
*/
@JsonClass(generateAdapter = true)
data class RoomGuestAccessContent(
// Required. Whether guests can join the room. One of: ["can_join", "forbidden"]
@Json(name = "guest_access") val guestAccess: GuestAccess? = null
)
enum class GuestAccess(val value: String) {
@Json(name = "can_join")
CanJoin("can_join"),
@Json(name = "forbidden")
Forbidden("forbidden")
}

View File

@ -44,7 +44,8 @@ data class RoomSummary(
val versioningState: VersioningState = VersioningState.NONE, val versioningState: VersioningState = VersioningState.NONE,
val readMarkerId: String? = null, val readMarkerId: String? = null,
val userDrafts: List<UserDraft> = emptyList(), val userDrafts: List<UserDraft> = emptyList(),
var isEncrypted: Boolean var isEncrypted: Boolean,
val typingRoomMemberIds: List<String> = emptyList()
) { ) {
val isVersioned: Boolean val isVersioned: Boolean

View File

@ -28,6 +28,8 @@ import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility
import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility
import im.vector.matrix.android.internal.auth.data.ThreePidMedium import im.vector.matrix.android.internal.auth.data.ThreePidMedium
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import timber.log.Timber
/** /**
* Parameter to create a room, with facilities functions to configure it * Parameter to create a room, with facilities functions to configure it
@ -88,7 +90,7 @@ class CreateRoomParams {
* A list of state events to set in the new room. * A list of state events to set in the new room.
* This allows the user to override the default state events set in the new room. * This allows the user to override the default state events set in the new room.
* The expected format of the state events are an object with type, state_key and content keys set. * The expected format of the state events are an object with type, state_key and content keys set.
* Takes precedence over events set by presets, but gets overriden by name and topic keys. * Takes precedence over events set by presets, but gets overridden by name and topic keys.
*/ */
@Json(name = "initial_state") @Json(name = "initial_state")
var initialStates: MutableList<Event>? = null var initialStates: MutableList<Event>? = null
@ -120,12 +122,12 @@ class CreateRoomParams {
* *
* @param algorithm the algorithm * @param algorithm the algorithm
*/ */
fun addCryptoAlgorithm(algorithm: String) { fun enableEncryptionWithAlgorithm(algorithm: String) {
if (algorithm.isNotBlank()) { if (algorithm == MXCRYPTO_ALGORITHM_MEGOLM) {
val contentMap = HashMap<String, String>() val contentMap = mapOf("algorithm" to algorithm)
contentMap["algorithm"] = algorithm
val algoEvent = Event(type = EventType.ENCRYPTION, val algoEvent = Event(
type = EventType.STATE_ROOM_ENCRYPTION,
stateKey = "", stateKey = "",
content = contentMap.toContent() content = contentMap.toContent()
) )
@ -135,6 +137,8 @@ class CreateRoomParams {
} else { } else {
initialStates!!.add(algoEvent) initialStates!!.add(algoEvent)
} }
} else {
Timber.e("Unsupported algorithm: $algorithm")
} }
} }
@ -145,13 +149,13 @@ class CreateRoomParams {
*/ */
fun setHistoryVisibility(historyVisibility: RoomHistoryVisibility?) { fun setHistoryVisibility(historyVisibility: RoomHistoryVisibility?) {
// Remove the existing value if any. // Remove the existing value if any.
initialStates?.removeAll { it.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY } initialStates?.removeAll { it.type == EventType.STATE_ROOM_HISTORY_VISIBILITY }
if (historyVisibility != null) { if (historyVisibility != null) {
val contentMap = HashMap<String, RoomHistoryVisibility>() val contentMap = mapOf("history_visibility" to historyVisibility)
contentMap["history_visibility"] = historyVisibility
val historyVisibilityEvent = Event(type = EventType.STATE_ROOM_HISTORY_VISIBILITY, val historyVisibilityEvent = Event(
type = EventType.STATE_ROOM_HISTORY_VISIBILITY,
stateKey = "", stateKey = "",
content = contentMap.toContent()) content = contentMap.toContent())

View File

@ -28,6 +28,11 @@ interface StateService {
*/ */
fun updateTopic(topic: String, callback: MatrixCallback<Unit>) fun updateTopic(topic: String, callback: MatrixCallback<Unit>)
/**
* Enable encryption of the room
*/
fun enableEncryption(algorithm: String, callback: MatrixCallback<Unit>)
fun getStateEvent(eventType: String): Event? fun getStateEvent(eventType: String): Event?
fun getStateEventLive(eventType: String): LiveData<Optional<Event>> fun getStateEventLive(eventType: String): LiveData<Optional<Event>>

View File

@ -0,0 +1,38 @@
/*
* Copyright 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.api.session.room.typing
/**
* This interface defines methods to handle typing data. It's implemented at the room level.
*/
interface TypingService {
/**
* To call when user is typing a message in the room
* The SDK will handle the requests scheduling to the homeserver:
* - No more than one typing request per 10s
* - If not called after 10s, the SDK will notify the homeserver that the user is not typing anymore
*/
fun userIsTyping()
/**
* To call when user stops typing in the room
* Notify immediately the homeserver that the user is not typing anymore in the room, for
* instance when user has emptied the composer, or when the user quits the timeline screen.
*/
fun userStopsTyping()
}

View File

@ -40,8 +40,8 @@ interface SignOutService {
/** /**
* Sign out, and release the session, clear all the session data, including crypto data * Sign out, and release the session, clear all the session data, including crypto data
* @param sigOutFromHomeserver true if the sign out request has to be done * @param signOutFromHomeserver true if the sign out request has to be done
*/ */
fun signOut(sigOutFromHomeserver: Boolean, fun signOut(signOutFromHomeserver: Boolean,
callback: MatrixCallback<Unit>): Cancelable callback: MatrixCallback<Unit>): Cancelable
} }

View File

@ -17,6 +17,7 @@
package im.vector.matrix.android.internal package im.vector.matrix.android.internal
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.auth.data.sessionId
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.auth.SessionParamsStore import im.vector.matrix.android.internal.auth.SessionParamsStore
import im.vector.matrix.android.internal.di.MatrixComponent import im.vector.matrix.android.internal.di.MatrixComponent
@ -29,10 +30,11 @@ import javax.inject.Inject
internal class SessionManager @Inject constructor(private val matrixComponent: MatrixComponent, internal class SessionManager @Inject constructor(private val matrixComponent: MatrixComponent,
private val sessionParamsStore: SessionParamsStore) { private val sessionParamsStore: SessionParamsStore) {
// SessionId -> SessionComponent
private val sessionComponents = HashMap<String, SessionComponent>() private val sessionComponents = HashMap<String, SessionComponent>()
fun getSessionComponent(userId: String): SessionComponent? { fun getSessionComponent(sessionId: String): SessionComponent? {
val sessionParams = sessionParamsStore.get(userId) ?: return null val sessionParams = sessionParamsStore.get(sessionId) ?: return null
return getOrCreateSessionComponent(sessionParams) return getOrCreateSessionComponent(sessionParams)
} }
@ -40,17 +42,17 @@ internal class SessionManager @Inject constructor(private val matrixComponent: M
return getOrCreateSessionComponent(sessionParams).session() return getOrCreateSessionComponent(sessionParams).session()
} }
fun releaseSession(userId: String) { fun releaseSession(sessionId: String) {
if (sessionComponents.containsKey(userId).not()) { if (sessionComponents.containsKey(sessionId).not()) {
throw RuntimeException("You don't have a session for the user $userId") throw RuntimeException("You don't have a session for id $sessionId")
} }
sessionComponents.remove(userId)?.also { sessionComponents.remove(sessionId)?.also {
it.session().close() it.session().close()
} }
} }
private fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent { private fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent {
return sessionComponents.getOrPut(sessionParams.credentials.userId) { return sessionComponents.getOrPut(sessionParams.credentials.sessionId()) {
DaggerSessionComponent DaggerSessionComponent
.factory() .factory()
.create(matrixComponent, sessionParams) .create(matrixComponent, sessionParams)

View File

@ -45,7 +45,8 @@ import okhttp3.OkHttpClient
import javax.inject.Inject import javax.inject.Inject
import javax.net.ssl.HttpsURLConnection import javax.net.ssl.HttpsURLConnection
internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated internal class DefaultAuthenticationService @Inject constructor(
@Unauthenticated
private val okHttpClient: Lazy<OkHttpClient>, private val okHttpClient: Lazy<OkHttpClient>,
private val retrofitFactory: RetrofitFactory, private val retrofitFactory: RetrofitFactory,
private val coroutineDispatchers: MatrixCoroutineDispatchers, private val coroutineDispatchers: MatrixCoroutineDispatchers,
@ -112,7 +113,7 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
// First check the homeserver version // First check the homeserver version
runCatching { runCatching {
executeRequest<Versions> { executeRequest<Versions>(null) {
apiCall = authAPI.versions() apiCall = authAPI.versions()
} }
} }
@ -141,7 +142,7 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
val authAPI = buildAuthAPI(homeServerConnectionConfig) val authAPI = buildAuthAPI(homeServerConnectionConfig)
// Ok, try to get the config.json file of a RiotWeb client // Ok, try to get the config.json file of a RiotWeb client
val riotConfig = executeRequest<RiotConfig> { val riotConfig = executeRequest<RiotConfig>(null) {
apiCall = authAPI.getRiotConfig() apiCall = authAPI.getRiotConfig()
} }
@ -153,7 +154,7 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig) val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig)
val versions = executeRequest<Versions> { val versions = executeRequest<Versions>(null) {
apiCall = newAuthAPI.versions() apiCall = newAuthAPI.versions()
} }
@ -167,7 +168,7 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
private suspend fun getLoginFlowResult(authAPI: AuthAPI, versions: Versions, homeServerUrl: String): LoginFlowResult { private suspend fun getLoginFlowResult(authAPI: AuthAPI, versions: Versions, homeServerUrl: String): LoginFlowResult {
return if (versions.isSupportedBySdk()) { return if (versions.isSupportedBySdk()) {
// Get the login flow // Get the login flow
val loginFlowResponse = executeRequest<LoginFlowResponse> { val loginFlowResponse = executeRequest<LoginFlowResponse>(null) {
apiCall = authAPI.getLoginFlows() apiCall = authAPI.getLoginFlows()
} }
LoginFlowResult.Success(loginFlowResponse, versions.isLoginAndRegistrationSupportedBySdk(), homeServerUrl) LoginFlowResult.Success(loginFlowResponse, versions.isLoginAndRegistrationSupportedBySdk(), homeServerUrl)

View File

@ -21,7 +21,7 @@ import im.vector.matrix.android.api.auth.data.SessionParams
internal interface SessionParamsStore { internal interface SessionParamsStore {
fun get(userId: String): SessionParams? fun get(sessionId: String): SessionParams?
fun getLast(): SessionParams? fun getLast(): SessionParams?
@ -29,11 +29,11 @@ internal interface SessionParamsStore {
suspend fun save(sessionParams: SessionParams) suspend fun save(sessionParams: SessionParams)
suspend fun setTokenInvalid(userId: String) suspend fun setTokenInvalid(sessionId: String)
suspend fun updateCredentials(newCredentials: Credentials) suspend fun updateCredentials(newCredentials: Credentials)
suspend fun delete(userId: String) suspend fun delete(sessionId: String)
suspend fun deleteAll() suspend fun deleteAll()
} }

View File

@ -17,7 +17,7 @@
package im.vector.matrix.android.internal.auth.db package im.vector.matrix.android.internal.auth.db
import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.internal.auth.createSessionId import im.vector.matrix.android.api.auth.data.sessionId
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.di.MoshiProvider
import io.realm.DynamicRealm import io.realm.DynamicRealm
import io.realm.RealmMigration import io.realm.RealmMigration
@ -71,14 +71,13 @@ internal object AuthRealmMigration : RealmMigration {
?.addField(SessionParamsEntityFields.SESSION_ID, String::class.java) ?.addField(SessionParamsEntityFields.SESSION_ID, String::class.java)
?.setRequired(SessionParamsEntityFields.SESSION_ID, true) ?.setRequired(SessionParamsEntityFields.SESSION_ID, true)
?.transform { ?.transform {
val userId = it.getString(SessionParamsEntityFields.USER_ID)
val credentialsJson = it.getString(SessionParamsEntityFields.CREDENTIALS_JSON) val credentialsJson = it.getString(SessionParamsEntityFields.CREDENTIALS_JSON)
val credentials = MoshiProvider.providesMoshi() val credentials = MoshiProvider.providesMoshi()
.adapter(Credentials::class.java) .adapter(Credentials::class.java)
.fromJson(credentialsJson) .fromJson(credentialsJson)
it.set(SessionParamsEntityFields.SESSION_ID, createSessionId(userId, credentials?.deviceId)) it.set(SessionParamsEntityFields.SESSION_ID, credentials!!.sessionId())
} }
?.addPrimaryKey(SessionParamsEntityFields.SESSION_ID) ?.addPrimaryKey(SessionParamsEntityFields.SESSION_ID)
} }

View File

@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.auth.db
import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.auth.data.sessionId
import im.vector.matrix.android.internal.auth.SessionParamsStore import im.vector.matrix.android.internal.auth.SessionParamsStore
import im.vector.matrix.android.internal.database.awaitTransaction import im.vector.matrix.android.internal.database.awaitTransaction
import im.vector.matrix.android.internal.di.AuthDatabase import im.vector.matrix.android.internal.di.AuthDatabase
@ -42,11 +43,11 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S
} }
} }
override fun get(userId: String): SessionParams? { override fun get(sessionId: String): SessionParams? {
return Realm.getInstance(realmConfiguration).use { realm -> return Realm.getInstance(realmConfiguration).use { realm ->
realm realm
.where(SessionParamsEntity::class.java) .where(SessionParamsEntity::class.java)
.equalTo(SessionParamsEntityFields.USER_ID, userId) .equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
.findAll() .findAll()
.map { mapper.map(it) } .map { mapper.map(it) }
.firstOrNull() .firstOrNull()
@ -76,17 +77,17 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S
} }
} }
override suspend fun setTokenInvalid(userId: String) { override suspend fun setTokenInvalid(sessionId: String) {
awaitTransaction(realmConfiguration) { realm -> awaitTransaction(realmConfiguration) { realm ->
val currentSessionParams = realm val currentSessionParams = realm
.where(SessionParamsEntity::class.java) .where(SessionParamsEntity::class.java)
.equalTo(SessionParamsEntityFields.USER_ID, userId) .equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
.findAll() .findAll()
.firstOrNull() .firstOrNull()
if (currentSessionParams == null) { if (currentSessionParams == null) {
// Should not happen // Should not happen
"Session param not found for user $userId" "Session param not found for id $sessionId"
.let { Timber.w(it) } .let { Timber.w(it) }
.also { error(it) } .also { error(it) }
} else { } else {
@ -99,14 +100,14 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S
awaitTransaction(realmConfiguration) { realm -> awaitTransaction(realmConfiguration) { realm ->
val currentSessionParams = realm val currentSessionParams = realm
.where(SessionParamsEntity::class.java) .where(SessionParamsEntity::class.java)
.equalTo(SessionParamsEntityFields.USER_ID, newCredentials.userId) .equalTo(SessionParamsEntityFields.SESSION_ID, newCredentials.sessionId())
.findAll() .findAll()
.map { mapper.map(it) } .map { mapper.map(it) }
.firstOrNull() .firstOrNull()
if (currentSessionParams == null) { if (currentSessionParams == null) {
// Should not happen // Should not happen
"Session param not found for user ${newCredentials.userId}" "Session param not found for id ${newCredentials.sessionId()}"
.let { Timber.w(it) } .let { Timber.w(it) }
.also { error(it) } .also { error(it) }
} else { } else {
@ -123,10 +124,10 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S
} }
} }
override suspend fun delete(userId: String) { override suspend fun delete(sessionId: String) {
awaitTransaction(realmConfiguration) { awaitTransaction(realmConfiguration) {
it.where(SessionParamsEntity::class.java) it.where(SessionParamsEntity::class.java)
.equalTo(SessionParamsEntityFields.USER_ID, userId) .equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
.findAll() .findAll()
.deleteAllFromRealm() .deleteAllFromRealm()
} }

View File

@ -20,7 +20,7 @@ import com.squareup.moshi.Moshi
import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.internal.auth.createSessionId import im.vector.matrix.android.api.auth.data.sessionId
import javax.inject.Inject import javax.inject.Inject
internal class SessionParamsMapper @Inject constructor(moshi: Moshi) { internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
@ -50,7 +50,7 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
return null return null
} }
return SessionParamsEntity( return SessionParamsEntity(
createSessionId(sessionParams.credentials.userId, sessionParams.credentials.deviceId), sessionParams.credentials.sessionId(),
sessionParams.credentials.userId, sessionParams.credentials.userId,
credentialsJson, credentialsJson,
homeServerConnectionConfigJson, homeServerConnectionConfigJson,

View File

@ -72,7 +72,7 @@ internal class DefaultLoginWizard(
} else { } else {
PasswordLoginParams.userIdentifier(login, password, deviceName) PasswordLoginParams.userIdentifier(login, password, deviceName)
} }
val credentials = executeRequest<Credentials> { val credentials = executeRequest<Credentials>(null) {
apiCall = authAPI.login(loginParams) apiCall = authAPI.login(loginParams)
} }
@ -95,7 +95,7 @@ internal class DefaultLoginWizard(
pendingSessionData = pendingSessionData.copy(sendAttempt = pendingSessionData.sendAttempt + 1) pendingSessionData = pendingSessionData.copy(sendAttempt = pendingSessionData.sendAttempt + 1)
.also { pendingSessionStore.savePendingSessionData(it) } .also { pendingSessionStore.savePendingSessionData(it) }
val result = executeRequest<AddThreePidRegistrationResponse> { val result = executeRequest<AddThreePidRegistrationResponse>(null) {
apiCall = authAPI.resetPassword(AddThreePidRegistrationParams.from(param)) apiCall = authAPI.resetPassword(AddThreePidRegistrationParams.from(param))
} }
@ -120,7 +120,7 @@ internal class DefaultLoginWizard(
resetPasswordData.newPassword resetPasswordData.newPassword
) )
executeRequest<Unit> { executeRequest<Unit>(null) {
apiCall = authAPI.resetPasswordMailConfirmed(param) apiCall = authAPI.resetPasswordMailConfirmed(param)
} }

View File

@ -29,11 +29,12 @@ internal interface RegisterAddThreePidTask : Task<RegisterAddThreePidTask.Params
) )
} }
internal class DefaultRegisterAddThreePidTask(private val authAPI: AuthAPI) internal class DefaultRegisterAddThreePidTask(
: RegisterAddThreePidTask { private val authAPI: AuthAPI
) : RegisterAddThreePidTask {
override suspend fun execute(params: RegisterAddThreePidTask.Params): AddThreePidRegistrationResponse { override suspend fun execute(params: RegisterAddThreePidTask.Params): AddThreePidRegistrationResponse {
return executeRequest { return executeRequest(null) {
apiCall = authAPI.add3Pid(params.threePid.toPath(), AddThreePidRegistrationParams.from(params)) apiCall = authAPI.add3Pid(params.threePid.toPath(), AddThreePidRegistrationParams.from(params))
} }
} }

View File

@ -29,12 +29,13 @@ internal interface RegisterTask : Task<RegisterTask.Params, Credentials> {
) )
} }
internal class DefaultRegisterTask(private val authAPI: AuthAPI) internal class DefaultRegisterTask(
: RegisterTask { private val authAPI: AuthAPI
) : RegisterTask {
override suspend fun execute(params: RegisterTask.Params): Credentials { override suspend fun execute(params: RegisterTask.Params): Credentials {
try { try {
return executeRequest { return executeRequest(null) {
apiCall = authAPI.register(params.registrationParams) apiCall = authAPI.register(params.registrationParams)
} }
} catch (throwable: Throwable) { } catch (throwable: Throwable) {

View File

@ -27,11 +27,12 @@ internal interface ValidateCodeTask : Task<ValidateCodeTask.Params, SuccessResul
) )
} }
internal class DefaultValidateCodeTask(private val authAPI: AuthAPI) internal class DefaultValidateCodeTask(
: ValidateCodeTask { private val authAPI: AuthAPI
) : ValidateCodeTask {
override suspend fun execute(params: ValidateCodeTask.Params): SuccessResult { override suspend fun execute(params: ValidateCodeTask.Params): SuccessResult {
return executeRequest { return executeRequest(null) {
apiCall = authAPI.validate3Pid(params.url, params.body) apiCall = authAPI.validate3Pid(params.url, params.body)
} }
} }

View File

@ -147,7 +147,7 @@ internal class DefaultCryptoService @Inject constructor(
fun onStateEvent(roomId: String, event: Event) { fun onStateEvent(roomId: String, event: Event) {
when { when {
event.getClearType() == EventType.ENCRYPTION -> onRoomEncryptionEvent(roomId, event) event.getClearType() == EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
event.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) event.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
} }
@ -155,7 +155,7 @@ internal class DefaultCryptoService @Inject constructor(
fun onLiveEvent(roomId: String, event: Event) { fun onLiveEvent(roomId: String, event: Event) {
when { when {
event.getClearType() == EventType.ENCRYPTION -> onRoomEncryptionEvent(roomId, event) event.getClearType() == EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
event.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) event.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
} }
@ -482,7 +482,7 @@ internal class DefaultCryptoService @Inject constructor(
*/ */
override fun isRoomEncrypted(roomId: String): Boolean { override fun isRoomEncrypted(roomId: String): Boolean {
val encryptionEvent = monarchy.fetchCopied { val encryptionEvent = monarchy.fetchCopied {
EventEntity.where(it, roomId = roomId, type = EventType.ENCRYPTION).findFirst() EventEntity.where(it, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION).findFirst()
} }
return encryptionEvent != null return encryptionEvent != null
} }

View File

@ -22,7 +22,8 @@ import im.vector.matrix.android.internal.di.UserId
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
internal class SetDeviceVerificationAction @Inject constructor(private val cryptoStore: IMXCryptoStore, internal class SetDeviceVerificationAction @Inject constructor(
private val cryptoStore: IMXCryptoStore,
@UserId private val userId: String, @UserId private val userId: String,
private val keysBackup: KeysBackup) { private val keysBackup: KeysBackup) {

View File

@ -1339,6 +1339,31 @@ internal class KeysBackup @Inject constructor(
return sessionBackupData return sessionBackupData
} }
/* ==========================================================================================
* For test only
* ========================================================================================== */
// Direct access for test only
@VisibleForTesting
val store
get() = cryptoStore
@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?
createKeysBackupVersionTask
.configureWith(createKeysBackupVersionBody) {
this.callback = callback
}
.executeBy(taskExecutor)
}
companion object { companion object {
// Maximum delay in ms in {@link maybeBackupKeys} // Maximum delay in ms in {@link maybeBackupKeys}
private const val KEY_BACKUP_WAITING_TIME_TO_SEND_KEY_BACKUP_MILLIS = 10_000L private const val KEY_BACKUP_WAITING_TIME_TO_SEND_KEY_BACKUP_MILLIS = 10_000L

View File

@ -21,15 +21,18 @@ import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.CreateKeys
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface CreateKeysBackupVersionTask : Task<CreateKeysBackupVersionBody, KeysVersion> internal interface CreateKeysBackupVersionTask : Task<CreateKeysBackupVersionBody, KeysVersion>
internal class DefaultCreateKeysBackupVersionTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultCreateKeysBackupVersionTask @Inject constructor(
: CreateKeysBackupVersionTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : CreateKeysBackupVersionTask {
override suspend fun execute(params: CreateKeysBackupVersionBody): KeysVersion { override suspend fun execute(params: CreateKeysBackupVersionBody): KeysVersion {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.createKeysBackupVersion(params) apiCall = roomKeysApi.createKeysBackupVersion(params)
} }
} }

View File

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.crypto.keysbackup.tasks
import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface DeleteBackupTask : Task<DeleteBackupTask.Params, Unit> { internal interface DeleteBackupTask : Task<DeleteBackupTask.Params, Unit> {
@ -27,11 +28,13 @@ internal interface DeleteBackupTask : Task<DeleteBackupTask.Params, Unit> {
) )
} }
internal class DefaultDeleteBackupTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultDeleteBackupTask @Inject constructor(
: DeleteBackupTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : DeleteBackupTask {
override suspend fun execute(params: DeleteBackupTask.Params) { override suspend fun execute(params: DeleteBackupTask.Params) {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.deleteBackup(params.version) apiCall = roomKeysApi.deleteBackup(params.version)
} }
} }

View File

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.crypto.keysbackup.tasks
import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface DeleteRoomSessionDataTask : Task<DeleteRoomSessionDataTask.Params, Unit> { internal interface DeleteRoomSessionDataTask : Task<DeleteRoomSessionDataTask.Params, Unit> {
@ -29,11 +30,13 @@ internal interface DeleteRoomSessionDataTask : Task<DeleteRoomSessionDataTask.Pa
) )
} }
internal class DefaultDeleteRoomSessionDataTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultDeleteRoomSessionDataTask @Inject constructor(
: DeleteRoomSessionDataTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : DeleteRoomSessionDataTask {
override suspend fun execute(params: DeleteRoomSessionDataTask.Params) { override suspend fun execute(params: DeleteRoomSessionDataTask.Params) {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.deleteRoomSessionData( apiCall = roomKeysApi.deleteRoomSessionData(
params.roomId, params.roomId,
params.sessionId, params.sessionId,

View File

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.crypto.keysbackup.tasks
import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface DeleteRoomSessionsDataTask : Task<DeleteRoomSessionsDataTask.Params, Unit> { internal interface DeleteRoomSessionsDataTask : Task<DeleteRoomSessionsDataTask.Params, Unit> {
@ -28,11 +29,13 @@ internal interface DeleteRoomSessionsDataTask : Task<DeleteRoomSessionsDataTask.
) )
} }
internal class DefaultDeleteRoomSessionsDataTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultDeleteRoomSessionsDataTask @Inject constructor(
: DeleteRoomSessionsDataTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : DeleteRoomSessionsDataTask {
override suspend fun execute(params: DeleteRoomSessionsDataTask.Params) { override suspend fun execute(params: DeleteRoomSessionsDataTask.Params) {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.deleteRoomSessionsData( apiCall = roomKeysApi.deleteRoomSessionsData(
params.roomId, params.roomId,
params.version) params.version)

View File

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.crypto.keysbackup.tasks
import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface DeleteSessionsDataTask : Task<DeleteSessionsDataTask.Params, Unit> { internal interface DeleteSessionsDataTask : Task<DeleteSessionsDataTask.Params, Unit> {
@ -27,11 +28,13 @@ internal interface DeleteSessionsDataTask : Task<DeleteSessionsDataTask.Params,
) )
} }
internal class DefaultDeleteSessionsDataTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultDeleteSessionsDataTask @Inject constructor(
: DeleteSessionsDataTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : DeleteSessionsDataTask {
override suspend fun execute(params: DeleteSessionsDataTask.Params) { override suspend fun execute(params: DeleteSessionsDataTask.Params) {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.deleteSessionsData(params.version) apiCall = roomKeysApi.deleteSessionsData(params.version)
} }
} }

View File

@ -20,15 +20,18 @@ import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetKeysBackupLastVersionTask : Task<Unit, KeysVersionResult> internal interface GetKeysBackupLastVersionTask : Task<Unit, KeysVersionResult>
internal class DefaultGetKeysBackupLastVersionTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultGetKeysBackupLastVersionTask @Inject constructor(
: GetKeysBackupLastVersionTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : GetKeysBackupLastVersionTask {
override suspend fun execute(params: Unit): KeysVersionResult { override suspend fun execute(params: Unit): KeysVersionResult {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.getKeysBackupLastVersion() apiCall = roomKeysApi.getKeysBackupLastVersion()
} }
} }

View File

@ -20,15 +20,18 @@ import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetKeysBackupVersionTask : Task<String, KeysVersionResult> internal interface GetKeysBackupVersionTask : Task<String, KeysVersionResult>
internal class DefaultGetKeysBackupVersionTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultGetKeysBackupVersionTask @Inject constructor(
: GetKeysBackupVersionTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : GetKeysBackupVersionTask {
override suspend fun execute(params: String): KeysVersionResult { override suspend fun execute(params: String): KeysVersionResult {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.getKeysBackupVersion(params) apiCall = roomKeysApi.getKeysBackupVersion(params)
} }
} }

View File

@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeyBackupData import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeyBackupData
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetRoomSessionDataTask : Task<GetRoomSessionDataTask.Params, KeyBackupData> { internal interface GetRoomSessionDataTask : Task<GetRoomSessionDataTask.Params, KeyBackupData> {
@ -30,11 +31,13 @@ internal interface GetRoomSessionDataTask : Task<GetRoomSessionDataTask.Params,
) )
} }
internal class DefaultGetRoomSessionDataTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultGetRoomSessionDataTask @Inject constructor(
: GetRoomSessionDataTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : GetRoomSessionDataTask {
override suspend fun execute(params: GetRoomSessionDataTask.Params): KeyBackupData { override suspend fun execute(params: GetRoomSessionDataTask.Params): KeyBackupData {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.getRoomSessionData( apiCall = roomKeysApi.getRoomSessionData(
params.roomId, params.roomId,
params.sessionId, params.sessionId,

View File

@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.RoomKeysBackupData import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.RoomKeysBackupData
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetRoomSessionsDataTask : Task<GetRoomSessionsDataTask.Params, RoomKeysBackupData> { internal interface GetRoomSessionsDataTask : Task<GetRoomSessionsDataTask.Params, RoomKeysBackupData> {
@ -29,11 +30,13 @@ internal interface GetRoomSessionsDataTask : Task<GetRoomSessionsDataTask.Params
) )
} }
internal class DefaultGetRoomSessionsDataTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultGetRoomSessionsDataTask @Inject constructor(
: GetRoomSessionsDataTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : GetRoomSessionsDataTask {
override suspend fun execute(params: GetRoomSessionsDataTask.Params): RoomKeysBackupData { override suspend fun execute(params: GetRoomSessionsDataTask.Params): RoomKeysBackupData {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.getRoomSessionsData( apiCall = roomKeysApi.getRoomSessionsData(
params.roomId, params.roomId,
params.version) params.version)

View File

@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysBackupData import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysBackupData
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetSessionsDataTask : Task<GetSessionsDataTask.Params, KeysBackupData> { internal interface GetSessionsDataTask : Task<GetSessionsDataTask.Params, KeysBackupData> {
@ -28,11 +29,13 @@ internal interface GetSessionsDataTask : Task<GetSessionsDataTask.Params, KeysBa
) )
} }
internal class DefaultGetSessionsDataTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultGetSessionsDataTask @Inject constructor(
: GetSessionsDataTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : GetSessionsDataTask {
override suspend fun execute(params: GetSessionsDataTask.Params): KeysBackupData { override suspend fun execute(params: GetSessionsDataTask.Params): KeysBackupData {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.getSessionsData(params.version) apiCall = roomKeysApi.getSessionsData(params.version)
} }
} }

View File

@ -21,6 +21,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.BackupKeys
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeyBackupData import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeyBackupData
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface StoreRoomSessionDataTask : Task<StoreRoomSessionDataTask.Params, BackupKeysResult> { internal interface StoreRoomSessionDataTask : Task<StoreRoomSessionDataTask.Params, BackupKeysResult> {
@ -32,11 +33,13 @@ internal interface StoreRoomSessionDataTask : Task<StoreRoomSessionDataTask.Para
) )
} }
internal class DefaultStoreRoomSessionDataTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultStoreRoomSessionDataTask @Inject constructor(
: StoreRoomSessionDataTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : StoreRoomSessionDataTask {
override suspend fun execute(params: StoreRoomSessionDataTask.Params): BackupKeysResult { override suspend fun execute(params: StoreRoomSessionDataTask.Params): BackupKeysResult {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.storeRoomSessionData( apiCall = roomKeysApi.storeRoomSessionData(
params.roomId, params.roomId,
params.sessionId, params.sessionId,

View File

@ -21,6 +21,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.BackupKeys
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.RoomKeysBackupData import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.RoomKeysBackupData
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface StoreRoomSessionsDataTask : Task<StoreRoomSessionsDataTask.Params, BackupKeysResult> { internal interface StoreRoomSessionsDataTask : Task<StoreRoomSessionsDataTask.Params, BackupKeysResult> {
@ -31,11 +32,13 @@ internal interface StoreRoomSessionsDataTask : Task<StoreRoomSessionsDataTask.Pa
) )
} }
internal class DefaultStoreRoomSessionsDataTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultStoreRoomSessionsDataTask @Inject constructor(
: StoreRoomSessionsDataTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : StoreRoomSessionsDataTask {
override suspend fun execute(params: StoreRoomSessionsDataTask.Params): BackupKeysResult { override suspend fun execute(params: StoreRoomSessionsDataTask.Params): BackupKeysResult {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.storeRoomSessionsData( apiCall = roomKeysApi.storeRoomSessionsData(
params.roomId, params.roomId,
params.version, params.version,

View File

@ -21,6 +21,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.BackupKeys
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysBackupData import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysBackupData
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface StoreSessionsDataTask : Task<StoreSessionsDataTask.Params, BackupKeysResult> { internal interface StoreSessionsDataTask : Task<StoreSessionsDataTask.Params, BackupKeysResult> {
@ -30,11 +31,13 @@ internal interface StoreSessionsDataTask : Task<StoreSessionsDataTask.Params, Ba
) )
} }
internal class DefaultStoreSessionsDataTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultStoreSessionsDataTask @Inject constructor(
: StoreSessionsDataTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : StoreSessionsDataTask {
override suspend fun execute(params: StoreSessionsDataTask.Params): BackupKeysResult { override suspend fun execute(params: StoreSessionsDataTask.Params): BackupKeysResult {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.storeSessionsData( apiCall = roomKeysApi.storeSessionsData(
params.version, params.version,
params.keysBackupData) params.keysBackupData)

View File

@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.UpdateKeysBackupVersionBody import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.UpdateKeysBackupVersionBody
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface UpdateKeysBackupVersionTask : Task<UpdateKeysBackupVersionTask.Params, Unit> { internal interface UpdateKeysBackupVersionTask : Task<UpdateKeysBackupVersionTask.Params, Unit> {
@ -29,11 +30,13 @@ internal interface UpdateKeysBackupVersionTask : Task<UpdateKeysBackupVersionTas
) )
} }
internal class DefaultUpdateKeysBackupVersionTask @Inject constructor(private val roomKeysApi: RoomKeysApi) internal class DefaultUpdateKeysBackupVersionTask @Inject constructor(
: UpdateKeysBackupVersionTask { private val roomKeysApi: RoomKeysApi,
private val eventBus: EventBus
) : UpdateKeysBackupVersionTask {
override suspend fun execute(params: UpdateKeysBackupVersionTask.Params) { override suspend fun execute(params: UpdateKeysBackupVersionTask.Params) {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomKeysApi.updateKeysBackupVersion(params.version, params.keysBackupVersionBody) apiCall = roomKeysApi.updateKeysBackupVersion(params.version, params.keysBackupVersionBody)
} }
} }

View File

@ -23,6 +23,7 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeysClaimBody
import im.vector.matrix.android.internal.crypto.model.rest.KeysClaimResponse import im.vector.matrix.android.internal.crypto.model.rest.KeysClaimResponse
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -33,13 +34,15 @@ internal interface ClaimOneTimeKeysForUsersDeviceTask : Task<ClaimOneTimeKeysFor
) )
} }
internal class DefaultClaimOneTimeKeysForUsersDevice @Inject constructor(private val cryptoApi: CryptoApi) internal class DefaultClaimOneTimeKeysForUsersDevice @Inject constructor(
: ClaimOneTimeKeysForUsersDeviceTask { private val cryptoApi: CryptoApi,
private val eventBus: EventBus
) : ClaimOneTimeKeysForUsersDeviceTask {
override suspend fun execute(params: ClaimOneTimeKeysForUsersDeviceTask.Params): MXUsersDevicesMap<MXKey> { override suspend fun execute(params: ClaimOneTimeKeysForUsersDeviceTask.Params): MXUsersDevicesMap<MXKey> {
val body = KeysClaimBody(oneTimeKeys = params.usersDevicesKeyTypesMap.map) val body = KeysClaimBody(oneTimeKeys = params.usersDevicesKeyTypesMap.map)
val keysClaimResponse = executeRequest<KeysClaimResponse> { val keysClaimResponse = executeRequest<KeysClaimResponse>(eventBus) {
apiCall = cryptoApi.claimOneTimeKeysForUsersDevices(body) apiCall = cryptoApi.claimOneTimeKeysForUsersDevices(body)
} }
val map = MXUsersDevicesMap<MXKey>() val map = MXUsersDevicesMap<MXKey>()

View File

@ -23,6 +23,7 @@ import im.vector.matrix.android.internal.crypto.model.rest.DeleteDeviceParams
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface DeleteDeviceTask : Task<DeleteDeviceTask.Params, Unit> { internal interface DeleteDeviceTask : Task<DeleteDeviceTask.Params, Unit> {
@ -31,12 +32,14 @@ internal interface DeleteDeviceTask : Task<DeleteDeviceTask.Params, Unit> {
) )
} }
internal class DefaultDeleteDeviceTask @Inject constructor(private val cryptoApi: CryptoApi) internal class DefaultDeleteDeviceTask @Inject constructor(
: DeleteDeviceTask { private val cryptoApi: CryptoApi,
private val eventBus: EventBus
) : DeleteDeviceTask {
override suspend fun execute(params: DeleteDeviceTask.Params) { override suspend fun execute(params: DeleteDeviceTask.Params) {
try { try {
executeRequest<Unit> { executeRequest<Unit>(eventBus) {
apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams()) apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams())
} }
} catch (throwable: Throwable) { } catch (throwable: Throwable) {

View File

@ -23,6 +23,7 @@ import im.vector.matrix.android.internal.crypto.model.rest.DeleteDeviceParams
import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface DeleteDeviceWithUserPasswordTask : Task<DeleteDeviceWithUserPasswordTask.Params, Unit> { internal interface DeleteDeviceWithUserPasswordTask : Task<DeleteDeviceWithUserPasswordTask.Params, Unit> {
@ -33,12 +34,14 @@ internal interface DeleteDeviceWithUserPasswordTask : Task<DeleteDeviceWithUserP
) )
} }
internal class DefaultDeleteDeviceWithUserPasswordTask @Inject constructor(private val cryptoApi: CryptoApi, internal class DefaultDeleteDeviceWithUserPasswordTask @Inject constructor(
@UserId private val userId: String) private val cryptoApi: CryptoApi,
: DeleteDeviceWithUserPasswordTask { @UserId private val userId: String,
private val eventBus: EventBus
) : DeleteDeviceWithUserPasswordTask {
override suspend fun execute(params: DeleteDeviceWithUserPasswordTask.Params) { override suspend fun execute(params: DeleteDeviceWithUserPasswordTask.Params) {
return executeRequest { return executeRequest(eventBus) {
apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams() apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams()
.apply { .apply {
deleteDeviceAuth = DeleteDeviceAuth() deleteDeviceAuth = DeleteDeviceAuth()

View File

@ -21,6 +21,7 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeysQueryBody
import im.vector.matrix.android.internal.crypto.model.rest.KeysQueryResponse import im.vector.matrix.android.internal.crypto.model.rest.KeysQueryResponse
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface DownloadKeysForUsersTask : Task<DownloadKeysForUsersTask.Params, KeysQueryResponse> { internal interface DownloadKeysForUsersTask : Task<DownloadKeysForUsersTask.Params, KeysQueryResponse> {
@ -31,8 +32,10 @@ internal interface DownloadKeysForUsersTask : Task<DownloadKeysForUsersTask.Para
val token: String?) val token: String?)
} }
internal class DefaultDownloadKeysForUsers @Inject constructor(private val cryptoApi: CryptoApi) internal class DefaultDownloadKeysForUsers @Inject constructor(
: DownloadKeysForUsersTask { private val cryptoApi: CryptoApi,
private val eventBus: EventBus
) : DownloadKeysForUsersTask {
override suspend fun execute(params: DownloadKeysForUsersTask.Params): KeysQueryResponse { override suspend fun execute(params: DownloadKeysForUsersTask.Params): KeysQueryResponse {
val downloadQuery = params.userIds?.associateWith { emptyMap<String, Any>() }.orEmpty() val downloadQuery = params.userIds?.associateWith { emptyMap<String, Any>() }.orEmpty()
@ -45,7 +48,7 @@ internal class DefaultDownloadKeysForUsers @Inject constructor(private val crypt
body.token = params.token body.token = params.token
} }
return executeRequest { return executeRequest(eventBus) {
apiCall = cryptoApi.downloadKeysForUsers(body) apiCall = cryptoApi.downloadKeysForUsers(body)
} }
} }

View File

@ -20,17 +20,20 @@ import im.vector.matrix.android.internal.crypto.api.CryptoApi
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetDeviceInfoTask : Task<GetDeviceInfoTask.Params, DeviceInfo> { internal interface GetDeviceInfoTask : Task<GetDeviceInfoTask.Params, DeviceInfo> {
data class Params(val deviceId: String) data class Params(val deviceId: String)
} }
internal class DefaultGetDeviceInfoTask @Inject constructor(private val cryptoApi: CryptoApi) internal class DefaultGetDeviceInfoTask @Inject constructor(
: GetDeviceInfoTask { private val cryptoApi: CryptoApi,
private val eventBus: EventBus
) : GetDeviceInfoTask {
override suspend fun execute(params: GetDeviceInfoTask.Params): DeviceInfo { override suspend fun execute(params: GetDeviceInfoTask.Params): DeviceInfo {
return executeRequest { return executeRequest(eventBus) {
apiCall = cryptoApi.getDeviceInfo(params.deviceId) apiCall = cryptoApi.getDeviceInfo(params.deviceId)
} }
} }

View File

@ -20,15 +20,18 @@ import im.vector.matrix.android.internal.crypto.api.CryptoApi
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetDevicesTask : Task<Unit, DevicesListResponse> internal interface GetDevicesTask : Task<Unit, DevicesListResponse>
internal class DefaultGetDevicesTask @Inject constructor(private val cryptoApi: CryptoApi) internal class DefaultGetDevicesTask @Inject constructor(
: GetDevicesTask { private val cryptoApi: CryptoApi,
private val eventBus: EventBus
) : GetDevicesTask {
override suspend fun execute(params: Unit): DevicesListResponse { override suspend fun execute(params: Unit): DevicesListResponse {
return executeRequest { return executeRequest(eventBus) {
apiCall = cryptoApi.getDevices() apiCall = cryptoApi.getDevices()
} }
} }

View File

@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.crypto.api.CryptoApi
import im.vector.matrix.android.internal.crypto.model.rest.KeyChangesResponse import im.vector.matrix.android.internal.crypto.model.rest.KeyChangesResponse
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetKeyChangesTask : Task<GetKeyChangesTask.Params, KeyChangesResponse> { internal interface GetKeyChangesTask : Task<GetKeyChangesTask.Params, KeyChangesResponse> {
@ -31,11 +32,13 @@ internal interface GetKeyChangesTask : Task<GetKeyChangesTask.Params, KeyChanges
) )
} }
internal class DefaultGetKeyChangesTask @Inject constructor(private val cryptoApi: CryptoApi) internal class DefaultGetKeyChangesTask @Inject constructor(
: GetKeyChangesTask { private val cryptoApi: CryptoApi,
private val eventBus: EventBus
) : GetKeyChangesTask {
override suspend fun execute(params: GetKeyChangesTask.Params): KeyChangesResponse { override suspend fun execute(params: GetKeyChangesTask.Params): KeyChangesResponse {
return executeRequest { return executeRequest(eventBus) {
apiCall = cryptoApi.getKeyChanges(params.from, params.to) apiCall = cryptoApi.getKeyChanges(params.from, params.to)
} }
} }

View File

@ -21,6 +21,7 @@ import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.rest.SendToDeviceBody import im.vector.matrix.android.internal.crypto.model.rest.SendToDeviceBody
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
import kotlin.random.Random import kotlin.random.Random
@ -35,14 +36,16 @@ internal interface SendToDeviceTask : Task<SendToDeviceTask.Params, Unit> {
) )
} }
internal class DefaultSendToDeviceTask @Inject constructor(private val cryptoApi: CryptoApi) internal class DefaultSendToDeviceTask @Inject constructor(
: SendToDeviceTask { private val cryptoApi: CryptoApi,
private val eventBus: EventBus
) : SendToDeviceTask {
override suspend fun execute(params: SendToDeviceTask.Params) { override suspend fun execute(params: SendToDeviceTask.Params) {
val sendToDeviceBody = SendToDeviceBody() val sendToDeviceBody = SendToDeviceBody()
sendToDeviceBody.messages = params.contentMap.map sendToDeviceBody.messages = params.contentMap.map
return executeRequest { return executeRequest(eventBus) {
apiCall = cryptoApi.sendToDevice( apiCall = cryptoApi.sendToDevice(
params.eventType, params.eventType,
params.transactionId ?: Random.nextInt(Integer.MAX_VALUE).toString(), params.transactionId ?: Random.nextInt(Integer.MAX_VALUE).toString(),

View File

@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.crypto.api.CryptoApi
import im.vector.matrix.android.internal.crypto.model.rest.UpdateDeviceInfoBody import im.vector.matrix.android.internal.crypto.model.rest.UpdateDeviceInfoBody
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface SetDeviceNameTask : Task<SetDeviceNameTask.Params, Unit> { internal interface SetDeviceNameTask : Task<SetDeviceNameTask.Params, Unit> {
@ -31,14 +32,16 @@ internal interface SetDeviceNameTask : Task<SetDeviceNameTask.Params, Unit> {
) )
} }
internal class DefaultSetDeviceNameTask @Inject constructor(private val cryptoApi: CryptoApi) internal class DefaultSetDeviceNameTask @Inject constructor(
: SetDeviceNameTask { private val cryptoApi: CryptoApi,
private val eventBus: EventBus
) : SetDeviceNameTask {
override suspend fun execute(params: SetDeviceNameTask.Params) { override suspend fun execute(params: SetDeviceNameTask.Params) {
val body = UpdateDeviceInfoBody( val body = UpdateDeviceInfoBody(
displayName = params.deviceName displayName = params.deviceName
) )
return executeRequest { return executeRequest(eventBus) {
apiCall = cryptoApi.updateDeviceInfo(params.deviceId, body) apiCall = cryptoApi.updateDeviceInfo(params.deviceId, body)
} }
} }

View File

@ -24,6 +24,7 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.convertToUTF8 import im.vector.matrix.android.internal.util.convertToUTF8
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface UploadKeysTask : Task<UploadKeysTask.Params, KeysUploadResponse> { internal interface UploadKeysTask : Task<UploadKeysTask.Params, KeysUploadResponse> {
@ -36,8 +37,10 @@ internal interface UploadKeysTask : Task<UploadKeysTask.Params, KeysUploadRespon
val deviceId: String) val deviceId: String)
} }
internal class DefaultUploadKeysTask @Inject constructor(private val cryptoApi: CryptoApi) internal class DefaultUploadKeysTask @Inject constructor(
: UploadKeysTask { private val cryptoApi: CryptoApi,
private val eventBus: EventBus
) : UploadKeysTask {
override suspend fun execute(params: UploadKeysTask.Params): KeysUploadResponse { override suspend fun execute(params: UploadKeysTask.Params): KeysUploadResponse {
val encodedDeviceId = convertToUTF8(params.deviceId) val encodedDeviceId = convertToUTF8(params.deviceId)
@ -52,7 +55,7 @@ internal class DefaultUploadKeysTask @Inject constructor(private val cryptoApi:
body.oneTimeKeys = params.oneTimeKeys body.oneTimeKeys = params.oneTimeKeys
} }
return executeRequest { return executeRequest(eventBus) {
apiCall = if (encodedDeviceId.isBlank()) { apiCall = if (encodedDeviceId.isBlank()) {
cryptoApi.uploadKeys(body) cryptoApi.uploadKeys(body)
} else { } else {

View File

@ -22,7 +22,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.tag.RoomTag import im.vector.matrix.android.api.session.room.model.tag.RoomTag
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import java.util.UUID import java.util.*
import javax.inject.Inject import javax.inject.Inject
internal class RoomSummaryMapper @Inject constructor( internal class RoomSummaryMapper @Inject constructor(
@ -73,7 +73,8 @@ internal class RoomSummaryMapper @Inject constructor(
userDrafts = roomSummaryEntity.userDrafts?.userDrafts?.map { DraftMapper.map(it) } ?: emptyList(), userDrafts = roomSummaryEntity.userDrafts?.userDrafts?.map { DraftMapper.map(it) } ?: emptyList(),
canonicalAlias = roomSummaryEntity.canonicalAlias, canonicalAlias = roomSummaryEntity.canonicalAlias,
aliases = roomSummaryEntity.aliases.toList(), aliases = roomSummaryEntity.aliases.toList(),
isEncrypted = roomSummaryEntity.isEncrypted isEncrypted = roomSummaryEntity.isEncrypted,
typingRoomMemberIds = roomSummaryEntity.typingUserIds.toList()
) )
} }
} }

View File

@ -44,7 +44,8 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
var aliases: RealmList<String> = RealmList(), var aliases: RealmList<String> = RealmList(),
// this is required for querying // this is required for querying
var flatAliases: String = "", var flatAliases: String = "",
var isEncrypted: Boolean = false var isEncrypted: Boolean = false,
var typingUserIds: RealmList<String> = RealmList()
) : RealmObject() { ) : RealmObject() {
private var membershipStr: String = Membership.NONE.name private var membershipStr: String = Membership.NONE.name

View File

@ -17,13 +17,13 @@
package im.vector.matrix.android.internal.network package im.vector.matrix.android.internal.network
import im.vector.matrix.android.internal.auth.SessionParamsStore import im.vector.matrix.android.internal.auth.SessionParamsStore
import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.di.SessionId
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Response import okhttp3.Response
import javax.inject.Inject import javax.inject.Inject
internal class AccessTokenInterceptor @Inject constructor( internal class AccessTokenInterceptor @Inject constructor(
@UserId private val userId: String, @SessionId private val sessionId: String,
private val sessionParamsStore: SessionParamsStore) : Interceptor { private val sessionParamsStore: SessionParamsStore) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
@ -40,5 +40,5 @@ internal class AccessTokenInterceptor @Inject constructor(
} }
private val accessToken private val accessToken
get() = sessionParamsStore.get(userId)?.credentials?.accessToken get() = sessionParamsStore.get(sessionId)?.credentials?.accessToken
} }

View File

@ -18,12 +18,14 @@ package im.vector.matrix.android.internal.network
import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.failure.Failure
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import org.greenrobot.eventbus.EventBus
import retrofit2.Call import retrofit2.Call
import java.io.IOException import java.io.IOException
internal suspend inline fun <DATA> executeRequest(block: Request<DATA>.() -> Unit) = Request<DATA>().apply(block).execute() internal suspend inline fun <DATA> executeRequest(eventBus: EventBus?,
block: Request<DATA>.() -> Unit) = Request<DATA>(eventBus).apply(block).execute()
internal class Request<DATA> { internal class Request<DATA>(private val eventBus: EventBus?) {
lateinit var apiCall: Call<DATA> lateinit var apiCall: Call<DATA>
@ -34,7 +36,7 @@ internal class Request<DATA> {
response.body() response.body()
?: throw IllegalStateException("The request returned a null body") ?: throw IllegalStateException("The request returned a null body")
} else { } else {
throw response.toFailure() throw response.toFailure(eventBus)
} }
} catch (exception: Throwable) { } catch (exception: Throwable) {
throw when (exception) { throw when (exception) {

View File

@ -74,18 +74,18 @@ internal suspend fun okhttp3.Call.awaitResponse(): okhttp3.Response {
/** /**
* Convert a retrofit Response to a Failure, and eventually parse errorBody to convert it to a MatrixError * Convert a retrofit Response to a Failure, and eventually parse errorBody to convert it to a MatrixError
*/ */
internal fun <T> Response<T>.toFailure(): Failure { internal fun <T> Response<T>.toFailure(eventBus: EventBus?): Failure {
return toFailure(errorBody(), code()) return toFailure(errorBody(), code(), eventBus)
} }
/** /**
* Convert a okhttp3 Response to a Failure, and eventually parse errorBody to convert it to a MatrixError * Convert a okhttp3 Response to a Failure, and eventually parse errorBody to convert it to a MatrixError
*/ */
internal fun okhttp3.Response.toFailure(): Failure { internal fun okhttp3.Response.toFailure(eventBus: EventBus?): Failure {
return toFailure(body, code) return toFailure(body, code, eventBus)
} }
private fun toFailure(errorBody: ResponseBody?, httpCode: Int): Failure { private fun toFailure(errorBody: ResponseBody?, httpCode: Int, eventBus: EventBus?): Failure {
if (errorBody == null) { if (errorBody == null) {
return Failure.Unknown(RuntimeException("errorBody should not be null")) return Failure.Unknown(RuntimeException("errorBody should not be null"))
} }
@ -100,11 +100,11 @@ private fun toFailure(errorBody: ResponseBody?, httpCode: Int): Failure {
if (matrixError != null) { if (matrixError != null) {
if (matrixError.code == MatrixError.M_CONSENT_NOT_GIVEN && !matrixError.consentUri.isNullOrBlank()) { if (matrixError.code == MatrixError.M_CONSENT_NOT_GIVEN && !matrixError.consentUri.isNullOrBlank()) {
// Also send this error to the bus, for a global management // Also send this error to the bus, for a global management
EventBus.getDefault().post(GlobalError.ConsentNotGivenError(matrixError.consentUri)) eventBus?.post(GlobalError.ConsentNotGivenError(matrixError.consentUri))
} else if (httpCode == HttpURLConnection.HTTP_UNAUTHORIZED /* 401 */ } else if (httpCode == HttpURLConnection.HTTP_UNAUTHORIZED /* 401 */
&& matrixError.code == MatrixError.M_UNKNOWN_TOKEN) { && matrixError.code == MatrixError.M_UNKNOWN_TOKEN) {
// Also send this error to the bus, for a global management // Also send this error to the bus, for a global management
EventBus.getDefault().post(GlobalError.InvalidToken(matrixError.isSoftLogout)) eventBus?.post(GlobalError.InvalidToken(matrixError.isSoftLogout))
} }
return Failure.ServerError(matrixError, httpCode) return Failure.ServerError(matrixError, httpCode)

View File

@ -17,7 +17,6 @@
package im.vector.matrix.android.internal.session package im.vector.matrix.android.internal.session
import android.content.Context import android.content.Context
import android.os.Looper
import androidx.annotation.MainThread import androidx.annotation.MainThread
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import dagger.Lazy import dagger.Lazy
@ -46,6 +45,7 @@ import im.vector.matrix.android.api.session.user.UserService
import im.vector.matrix.android.internal.auth.SessionParamsStore import im.vector.matrix.android.internal.auth.SessionParamsStore
import im.vector.matrix.android.internal.crypto.DefaultCryptoService import im.vector.matrix.android.internal.crypto.DefaultCryptoService
import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.database.LiveEntityObserver
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.session.sync.SyncTaskSequencer import im.vector.matrix.android.internal.session.sync.SyncTaskSequencer
import im.vector.matrix.android.internal.session.sync.SyncTokenStore import im.vector.matrix.android.internal.session.sync.SyncTokenStore
import im.vector.matrix.android.internal.session.sync.job.SyncThread import im.vector.matrix.android.internal.session.sync.job.SyncThread
@ -61,8 +61,12 @@ import javax.inject.Inject
import javax.inject.Provider import javax.inject.Provider
@SessionScope @SessionScope
internal class DefaultSession @Inject constructor(override val sessionParams: SessionParams, internal class DefaultSession @Inject constructor(
override val sessionParams: SessionParams,
private val context: Context, private val context: Context,
private val eventBus: EventBus,
@SessionId
override val sessionId: String,
private val liveEntityObservers: Set<@JvmSuppressWildcards LiveEntityObserver>, private val liveEntityObservers: Set<@JvmSuppressWildcards LiveEntityObserver>,
private val sessionListeners: SessionListeners, private val sessionListeners: SessionListeners,
private val roomService: Lazy<RoomService>, private val roomService: Lazy<RoomService>,
@ -107,23 +111,22 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
private var syncThread: SyncThread? = null private var syncThread: SyncThread? = null
override val isOpenable: Boolean override val isOpenable: Boolean
get() = sessionParamsStore.get(myUserId)?.isTokenValid ?: false get() = sessionParamsStore.get(sessionId)?.isTokenValid ?: false
@MainThread @MainThread
override fun open() { override fun open() {
assertMainThread()
assert(!isOpen) assert(!isOpen)
isOpen = true isOpen = true
liveEntityObservers.forEach { it.start() } liveEntityObservers.forEach { it.start() }
EventBus.getDefault().register(this) eventBus.register(this)
} }
override fun requireBackgroundSync() { override fun requireBackgroundSync() {
SyncWorker.requireBackgroundSync(context, myUserId) SyncWorker.requireBackgroundSync(context, sessionId)
} }
override fun startAutomaticBackgroundSync(repeatDelay: Long) { override fun startAutomaticBackgroundSync(repeatDelay: Long) {
SyncWorker.automaticallyBackgroundSync(context, myUserId, 0, repeatDelay) SyncWorker.automaticallyBackgroundSync(context, sessionId, 0, repeatDelay)
} }
override fun stopAnyBackgroundSync() { override fun stopAnyBackgroundSync() {
@ -155,7 +158,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
liveEntityObservers.forEach { it.dispose() } liveEntityObservers.forEach { it.dispose() }
cryptoService.get().close() cryptoService.get().close()
isOpen = false isOpen = false
EventBus.getDefault().unregister(this) eventBus.unregister(this)
syncTaskSequencer.close() syncTaskSequencer.close()
} }
@ -186,7 +189,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
&& globalError.softLogout) { && globalError.softLogout) {
// Mark the token has invalid // Mark the token has invalid
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
sessionParamsStore.setTokenInvalid(myUserId) sessionParamsStore.setTokenInvalid(sessionId)
} }
} }
@ -204,12 +207,4 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
override fun removeListener(listener: Session.Listener) { override fun removeListener(listener: Session.Listener) {
sessionListeners.removeListener(listener) sessionListeners.removeListener(listener)
} }
// Private methods *****************************************************************************
private fun assertMainThread() {
if (Looper.getMainLooper().thread !== Thread.currentThread()) {
throw IllegalStateException("This method can only be called on the main thread!")
}
}
} }

View File

@ -26,11 +26,11 @@ import dagger.multibindings.IntoSet
import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.auth.data.sessionId
import im.vector.matrix.android.api.session.InitialSyncProgressService import im.vector.matrix.android.api.session.InitialSyncProgressService
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService
import im.vector.matrix.android.api.session.securestorage.SecureStorageService import im.vector.matrix.android.api.session.securestorage.SecureStorageService
import im.vector.matrix.android.internal.auth.createSessionId
import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.database.LiveEntityObserver
import im.vector.matrix.android.internal.database.SessionRealmConfigurationFactory import im.vector.matrix.android.internal.database.SessionRealmConfigurationFactory
import im.vector.matrix.android.internal.di.* import im.vector.matrix.android.internal.di.*
@ -47,6 +47,7 @@ import im.vector.matrix.android.internal.session.securestorage.DefaultSecureStor
import im.vector.matrix.android.internal.util.md5 import im.vector.matrix.android.internal.util.md5
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.greenrobot.eventbus.EventBus
import retrofit2.Retrofit import retrofit2.Retrofit
import java.io.File import java.io.File
@ -87,7 +88,7 @@ internal abstract class SessionModule {
@SessionId @SessionId
@Provides @Provides
fun providesSessionId(credentials: Credentials): String { fun providesSessionId(credentials: Credentials): String {
return createSessionId(credentials.userId, credentials.deviceId) return credentials.sessionId()
} }
@JvmStatic @JvmStatic
@ -154,6 +155,13 @@ internal abstract class SessionModule {
return retrofitFactory return retrofitFactory
.create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUri.toString()) .create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUri.toString())
} }
@JvmStatic
@Provides
@SessionScope
fun providesEventBus(): EventBus {
return EventBus.builder().build()
}
} }
@Binds @Binds

View File

@ -29,12 +29,14 @@ import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import org.greenrobot.eventbus.EventBus
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import javax.inject.Inject import javax.inject.Inject
internal class FileUploader @Inject constructor(@Authenticated internal class FileUploader @Inject constructor(@Authenticated
private val okHttpClient: OkHttpClient, private val okHttpClient: OkHttpClient,
private val eventBus: EventBus,
sessionParams: SessionParams, sessionParams: SessionParams,
moshi: Moshi) { moshi: Moshi) {
@ -73,7 +75,7 @@ internal class FileUploader @Inject constructor(@Authenticated
return okHttpClient.newCall(request).awaitResponse().use { response -> return okHttpClient.newCall(request).awaitResponse().use { response ->
if (!response.isSuccessful) { if (!response.isSuccessful) {
throw response.toFailure() throw response.toFailure(eventBus)
} else { } else {
response.body?.source()?.let { response.body?.source()?.let {
responseAdapter.fromJson(it) responseAdapter.fromJson(it)

View File

@ -42,7 +42,7 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal data class Params( internal data class Params(
override val userId: String, override val sessionId: String,
val roomId: String, val roomId: String,
val event: Event, val event: Event,
val attachment: ContentAttachmentData, val attachment: ContentAttachmentData,
@ -64,7 +64,7 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
return Result.success(inputData) return Result.success(inputData)
} }
val sessionComponent = getSessionComponent(params.userId) ?: return Result.success() val sessionComponent = getSessionComponent(params.sessionId) ?: return Result.success()
sessionComponent.inject(this) sessionComponent.inject(this)
val eventId = params.event.eventId ?: return Result.success() val eventId = params.event.eventId ?: return Result.success()
@ -169,7 +169,7 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
Timber.v("handleSuccess $attachmentUrl, work is stopped $isStopped") Timber.v("handleSuccess $attachmentUrl, work is stopped $isStopped")
contentUploadStateTracker.setSuccess(params.event.eventId!!) contentUploadStateTracker.setSuccess(params.event.eventId!!)
val event = updateEvent(params.event, attachmentUrl, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo) val event = updateEvent(params.event, attachmentUrl, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo)
val sendParams = SendEventWorker.Params(params.userId, params.roomId, event) val sendParams = SendEventWorker.Params(params.sessionId, params.roomId, event)
return Result.success(WorkerParamsFactory.toData(sendParams)) return Result.success(WorkerParamsFactory.toData(sendParams))
} }

View File

@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -32,9 +33,11 @@ internal interface SaveFilterTask : Task<SaveFilterTask.Params, Unit> {
) )
} }
internal class DefaultSaveFilterTask @Inject constructor(@UserId private val userId: String, internal class DefaultSaveFilterTask @Inject constructor(
@UserId private val userId: String,
private val filterAPI: FilterApi, private val filterAPI: FilterApi,
private val filterRepository: FilterRepository private val filterRepository: FilterRepository,
private val eventBus: EventBus
) : SaveFilterTask { ) : SaveFilterTask {
override suspend fun execute(params: SaveFilterTask.Params) { override suspend fun execute(params: SaveFilterTask.Params) {
@ -56,7 +59,7 @@ internal class DefaultSaveFilterTask @Inject constructor(@UserId private val use
} }
val updated = filterRepository.storeFilter(filterBody, roomFilter) val updated = filterRepository.storeFilter(filterBody, roomFilter)
if (updated) { if (updated) {
val filterResponse = executeRequest<FilterResponse> { val filterResponse = executeRequest<FilterResponse>(eventBus) {
// TODO auto retry // TODO auto retry
apiCall = filterAPI.uploadFilter(userId, filterBody) apiCall = filterAPI.uploadFilter(userId, filterBody)
} }

View File

@ -25,6 +25,7 @@ import im.vector.matrix.android.internal.session.group.model.GroupRooms
import im.vector.matrix.android.internal.session.group.model.GroupSummaryResponse import im.vector.matrix.android.internal.session.group.model.GroupSummaryResponse
import im.vector.matrix.android.internal.session.group.model.GroupUsers import im.vector.matrix.android.internal.session.group.model.GroupUsers
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetGroupDataTask : Task<GetGroupDataTask.Params, Unit> { internal interface GetGroupDataTask : Task<GetGroupDataTask.Params, Unit> {
@ -34,18 +35,19 @@ internal interface GetGroupDataTask : Task<GetGroupDataTask.Params, Unit> {
internal class DefaultGetGroupDataTask @Inject constructor( internal class DefaultGetGroupDataTask @Inject constructor(
private val groupAPI: GroupAPI, private val groupAPI: GroupAPI,
private val monarchy: Monarchy private val monarchy: Monarchy,
private val eventBus: EventBus
) : GetGroupDataTask { ) : GetGroupDataTask {
override suspend fun execute(params: GetGroupDataTask.Params) { override suspend fun execute(params: GetGroupDataTask.Params) {
val groupId = params.groupId val groupId = params.groupId
val groupSummary = executeRequest<GroupSummaryResponse> { val groupSummary = executeRequest<GroupSummaryResponse>(eventBus) {
apiCall = groupAPI.getSummary(groupId) apiCall = groupAPI.getSummary(groupId)
} }
val groupRooms = executeRequest<GroupRooms> { val groupRooms = executeRequest<GroupRooms>(eventBus) {
apiCall = groupAPI.getRooms(groupId) apiCall = groupAPI.getRooms(groupId)
} }
val groupUsers = executeRequest<GroupUsers> { val groupUsers = executeRequest<GroupUsers>(eventBus) {
apiCall = groupAPI.getUsers(groupId) apiCall = groupAPI.getUsers(groupId)
} }
insertInDb(groupSummary, groupRooms, groupUsers, groupId) insertInDb(groupSummary, groupRooms, groupUsers, groupId)

View File

@ -29,7 +29,7 @@ internal class GetGroupDataWorker(context: Context, params: WorkerParameters) :
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal data class Params( internal data class Params(
override val userId: String, override val sessionId: String,
val groupIds: List<String>, val groupIds: List<String>,
override val lastFailureMessage: String? = null override val lastFailureMessage: String? = null
) : SessionWorkerParams ) : SessionWorkerParams
@ -40,7 +40,7 @@ internal class GetGroupDataWorker(context: Context, params: WorkerParameters) :
val params = WorkerParamsFactory.fromData<Params>(inputData) val params = WorkerParamsFactory.fromData<Params>(inputData)
?: return Result.failure() ?: return Result.failure()
val sessionComponent = getSessionComponent(params.userId) ?: return Result.success() val sessionComponent = getSessionComponent(params.sessionId) ?: return Result.success()
sessionComponent.inject(this) sessionComponent.inject(this)
val results = params.groupIds.map { groupId -> val results = params.groupIds.map { groupId ->
runCatching { fetchGroupData(groupId) } runCatching { fetchGroupData(groupId) }

View File

@ -26,7 +26,7 @@ import im.vector.matrix.android.internal.database.awaitTransaction
import im.vector.matrix.android.internal.database.model.GroupEntity import im.vector.matrix.android.internal.database.model.GroupEntity
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.worker.WorkManagerUtil import im.vector.matrix.android.internal.worker.WorkManagerUtil
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.worker.WorkerParamsFactory import im.vector.matrix.android.internal.worker.WorkerParamsFactory
@ -37,8 +37,9 @@ import javax.inject.Inject
private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER" private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
internal class GroupSummaryUpdater @Inject constructor(private val context: Context, internal class GroupSummaryUpdater @Inject constructor(
@UserId private val userId: String, private val context: Context,
@SessionId private val sessionId: String,
private val monarchy: Monarchy) private val monarchy: Monarchy)
: RealmLiveEntityObserver<GroupEntity>(monarchy.realmConfiguration) { : RealmLiveEntityObserver<GroupEntity>(monarchy.realmConfiguration) {
@ -67,7 +68,7 @@ internal class GroupSummaryUpdater @Inject constructor(private val context: Cont
} }
private fun fetchGroupsData(groupIds: List<String>) { private fun fetchGroupsData(groupIds: List<String>) {
val getGroupDataWorkerParams = GetGroupDataWorker.Params(userId, groupIds) val getGroupDataWorkerParams = GetGroupDataWorker.Params(sessionId, groupIds)
val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams) val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams)

View File

@ -23,14 +23,16 @@ import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction import im.vector.matrix.android.internal.util.awaitTransaction
import java.util.Date import org.greenrobot.eventbus.EventBus
import java.util.*
import javax.inject.Inject import javax.inject.Inject
internal interface GetHomeServerCapabilitiesTask : Task<Unit, Unit> internal interface GetHomeServerCapabilitiesTask : Task<Unit, Unit>
internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
private val capabilitiesAPI: CapabilitiesAPI, private val capabilitiesAPI: CapabilitiesAPI,
private val monarchy: Monarchy private val monarchy: Monarchy,
private val eventBus: EventBus
) : GetHomeServerCapabilitiesTask { ) : GetHomeServerCapabilitiesTask {
override suspend fun execute(params: Unit) { override suspend fun execute(params: Unit) {
@ -45,7 +47,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
return return
} }
val uploadCapabilities = executeRequest<GetUploadCapabilitiesResult> { val uploadCapabilities = executeRequest<GetUploadCapabilitiesResult>(eventBus) {
apiCall = capabilitiesAPI.getUploadCapabilities() apiCall = capabilitiesAPI.getUploadCapabilities()
} }

View File

@ -20,6 +20,7 @@ package im.vector.matrix.android.internal.session.profile
import im.vector.matrix.android.api.util.JsonDict import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal abstract class GetProfileInfoTask : Task<GetProfileInfoTask.Params, JsonDict> { internal abstract class GetProfileInfoTask : Task<GetProfileInfoTask.Params, JsonDict> {
@ -28,10 +29,11 @@ internal abstract class GetProfileInfoTask : Task<GetProfileInfoTask.Params, Jso
) )
} }
internal class DefaultGetProfileInfoTask @Inject constructor(private val profileAPI: ProfileAPI) : GetProfileInfoTask() { internal class DefaultGetProfileInfoTask @Inject constructor(private val profileAPI: ProfileAPI,
private val eventBus: EventBus) : GetProfileInfoTask() {
override suspend fun execute(params: Params): JsonDict { override suspend fun execute(params: Params): JsonDict {
return executeRequest { return executeRequest(eventBus) {
apiCall = profileAPI.getProfile(params.userId) apiCall = profileAPI.getProfile(params.userId)
} }
} }

View File

@ -27,8 +27,10 @@ import im.vector.matrix.android.internal.database.model.PusherEntity
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.util.awaitTransaction import im.vector.matrix.android.internal.util.awaitTransaction
import im.vector.matrix.android.internal.worker.SessionWorkerParams
import im.vector.matrix.android.internal.worker.WorkerParamsFactory import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import im.vector.matrix.android.internal.worker.getSessionComponent import im.vector.matrix.android.internal.worker.getSessionComponent
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal class AddHttpPusherWorker(context: Context, params: WorkerParameters) internal class AddHttpPusherWorker(context: Context, params: WorkerParameters)
@ -36,18 +38,20 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters)
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal data class Params( internal data class Params(
override val sessionId: String,
val pusher: JsonPusher, val pusher: JsonPusher,
val userId: String override val lastFailureMessage: String? = null
) ) : SessionWorkerParams
@Inject lateinit var pushersAPI: PushersAPI @Inject lateinit var pushersAPI: PushersAPI
@Inject lateinit var monarchy: Monarchy @Inject lateinit var monarchy: Monarchy
@Inject lateinit var eventBus: EventBus
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
val params = WorkerParamsFactory.fromData<Params>(inputData) val params = WorkerParamsFactory.fromData<Params>(inputData)
?: return Result.failure() ?: return Result.failure()
val sessionComponent = getSessionComponent(params.userId) ?: return Result.success() val sessionComponent = getSessionComponent(params.sessionId) ?: return Result.success()
sessionComponent.inject(this) sessionComponent.inject(this)
val pusher = params.pusher val pusher = params.pusher
@ -76,7 +80,7 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters)
} }
private suspend fun setPusher(pusher: JsonPusher) { private suspend fun setPusher(pusher: JsonPusher) {
executeRequest<Unit> { executeRequest<Unit>(eventBus) {
apiCall = pushersAPI.setPusher(pusher) apiCall = pushersAPI.setPusher(pusher)
} }
monarchy.awaitTransaction { realm -> monarchy.awaitTransaction { realm ->

View File

@ -19,6 +19,7 @@ import im.vector.matrix.android.api.pushrules.RuleKind
import im.vector.matrix.android.api.pushrules.rest.PushRule import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface AddPushRuleTask : Task<AddPushRuleTask.Params, Unit> { internal interface AddPushRuleTask : Task<AddPushRuleTask.Params, Unit> {
@ -28,11 +29,13 @@ internal interface AddPushRuleTask : Task<AddPushRuleTask.Params, Unit> {
) )
} }
internal class DefaultAddPushRuleTask @Inject constructor(private val pushRulesApi: PushRulesApi) internal class DefaultAddPushRuleTask @Inject constructor(
: AddPushRuleTask { private val pushRulesApi: PushRulesApi,
private val eventBus: EventBus
) : AddPushRuleTask {
override suspend fun execute(params: AddPushRuleTask.Params) { override suspend fun execute(params: AddPushRuleTask.Params) {
return executeRequest { return executeRequest(eventBus) {
apiCall = pushRulesApi.addRule(params.kind.value, params.pushRule.ruleId, params.pushRule) apiCall = pushRulesApi.addRule(params.kind.value, params.pushRule.ruleId, params.pushRule)
} }
} }

View File

@ -26,19 +26,20 @@ import im.vector.matrix.android.api.session.pushers.PushersService
import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.PusherEntity import im.vector.matrix.android.internal.database.model.PusherEntity
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.worker.WorkManagerUtil import im.vector.matrix.android.internal.worker.WorkManagerUtil
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.worker.WorkerParamsFactory import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import java.util.UUID import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
internal class DefaultPusherService @Inject constructor(private val context: Context, internal class DefaultPusherService @Inject constructor(
private val context: Context,
private val monarchy: Monarchy, private val monarchy: Monarchy,
@UserId private val userId: String, @SessionId private val sessionId: String,
private val getPusherTask: GetPushersTask, private val getPusherTask: GetPushersTask,
private val removePusherTask: RemovePusherTask, private val removePusherTask: RemovePusherTask,
private val taskExecutor: TaskExecutor private val taskExecutor: TaskExecutor
@ -65,7 +66,7 @@ internal class DefaultPusherService @Inject constructor(private val context: Con
data = JsonPusherData(url, if (withEventIdOnly) PushersService.EVENT_ID_ONLY else null), data = JsonPusherData(url, if (withEventIdOnly) PushersService.EVENT_ID_ONLY else null),
append = append) append = append)
val params = AddHttpPusherWorker.Params(pusher, userId) val params = AddHttpPusherWorker.Params(sessionId, pusher)
val request = matrixOneTimeWorkRequestBuilder<AddHttpPusherWorker>() val request = matrixOneTimeWorkRequestBuilder<AddHttpPusherWorker>()
.setConstraints(WorkManagerUtil.workConstraints) .setConstraints(WorkManagerUtil.workConstraints)

View File

@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.pushers
import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetPushRulesTask : Task<GetPushRulesTask.Params, Unit> { internal interface GetPushRulesTask : Task<GetPushRulesTask.Params, Unit> {
@ -27,11 +28,14 @@ internal interface GetPushRulesTask : Task<GetPushRulesTask.Params, Unit> {
/** /**
* We keep this task, but it should not be used anymore, the push rules comes from the sync response * We keep this task, but it should not be used anymore, the push rules comes from the sync response
*/ */
internal class DefaultGetPushRulesTask @Inject constructor(private val pushRulesApi: PushRulesApi, internal class DefaultGetPushRulesTask @Inject constructor(
private val savePushRulesTask: SavePushRulesTask) : GetPushRulesTask { private val pushRulesApi: PushRulesApi,
private val savePushRulesTask: SavePushRulesTask,
private val eventBus: EventBus
) : GetPushRulesTask {
override suspend fun execute(params: GetPushRulesTask.Params) { override suspend fun execute(params: GetPushRulesTask.Params) {
val response = executeRequest<GetPushRulesResponse> { val response = executeRequest<GetPushRulesResponse>(eventBus) {
apiCall = pushRulesApi.getAllRules() apiCall = pushRulesApi.getAllRules()
} }

View File

@ -22,15 +22,19 @@ import im.vector.matrix.android.internal.database.model.PusherEntity
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction import im.vector.matrix.android.internal.util.awaitTransaction
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetPushersTask : Task<Unit, Unit> internal interface GetPushersTask : Task<Unit, Unit>
internal class DefaultGetPushersTask @Inject constructor(private val pushersAPI: PushersAPI, internal class DefaultGetPushersTask @Inject constructor(
private val monarchy: Monarchy) : GetPushersTask { private val pushersAPI: PushersAPI,
private val monarchy: Monarchy,
private val eventBus: EventBus
) : GetPushersTask {
override suspend fun execute(params: Unit) { override suspend fun execute(params: Unit) {
val response = executeRequest<GetPushersResponse> { val response = executeRequest<GetPushersResponse>(eventBus) {
apiCall = pushersAPI.getPushers() apiCall = pushersAPI.getPushers()
} }
monarchy.awaitTransaction { realm -> monarchy.awaitTransaction { realm ->

View File

@ -19,6 +19,7 @@ import im.vector.matrix.android.api.pushrules.RuleKind
import im.vector.matrix.android.api.pushrules.rest.PushRule import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface RemovePushRuleTask : Task<RemovePushRuleTask.Params, Unit> { internal interface RemovePushRuleTask : Task<RemovePushRuleTask.Params, Unit> {
@ -28,11 +29,13 @@ internal interface RemovePushRuleTask : Task<RemovePushRuleTask.Params, Unit> {
) )
} }
internal class DefaultRemovePushRuleTask @Inject constructor(private val pushRulesApi: PushRulesApi) internal class DefaultRemovePushRuleTask @Inject constructor(
: RemovePushRuleTask { private val pushRulesApi: PushRulesApi,
private val eventBus: EventBus
) : RemovePushRuleTask {
override suspend fun execute(params: RemovePushRuleTask.Params) { override suspend fun execute(params: RemovePushRuleTask.Params) {
return executeRequest { return executeRequest(eventBus) {
apiCall = pushRulesApi.deleteRule(params.kind.value, params.pushRule.ruleId) apiCall = pushRulesApi.deleteRule(params.kind.value, params.pushRule.ruleId)
} }
} }

View File

@ -25,6 +25,7 @@ import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm import io.realm.Realm
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> { internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> {
@ -34,7 +35,8 @@ internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> {
internal class DefaultRemovePusherTask @Inject constructor( internal class DefaultRemovePusherTask @Inject constructor(
private val pushersAPI: PushersAPI, private val pushersAPI: PushersAPI,
private val monarchy: Monarchy private val monarchy: Monarchy,
private val eventBus: EventBus
) : RemovePusherTask { ) : RemovePusherTask {
override suspend fun execute(params: RemovePusherTask.Params) { override suspend fun execute(params: RemovePusherTask.Params) {
@ -59,7 +61,7 @@ internal class DefaultRemovePusherTask @Inject constructor(
data = JsonPusherData(existing.data.url, existing.data.format), data = JsonPusherData(existing.data.url, existing.data.format),
append = false append = false
) )
executeRequest<Unit> { executeRequest<Unit>(eventBus) {
apiCall = pushersAPI.setPusher(deleteBody) apiCall = pushersAPI.setPusher(deleteBody)
} }
monarchy.awaitTransaction { monarchy.awaitTransaction {

View File

@ -19,6 +19,7 @@ import im.vector.matrix.android.api.pushrules.RuleKind
import im.vector.matrix.android.api.pushrules.rest.PushRule import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface UpdatePushRuleEnableStatusTask : Task<UpdatePushRuleEnableStatusTask.Params, Unit> { internal interface UpdatePushRuleEnableStatusTask : Task<UpdatePushRuleEnableStatusTask.Params, Unit> {
@ -27,11 +28,13 @@ internal interface UpdatePushRuleEnableStatusTask : Task<UpdatePushRuleEnableSta
val enabled: Boolean) val enabled: Boolean)
} }
internal class DefaultUpdatePushRuleEnableStatusTask @Inject constructor(private val pushRulesApi: PushRulesApi) internal class DefaultUpdatePushRuleEnableStatusTask @Inject constructor(
: UpdatePushRuleEnableStatusTask { private val pushRulesApi: PushRulesApi,
private val eventBus: EventBus
) : UpdatePushRuleEnableStatusTask {
override suspend fun execute(params: UpdatePushRuleEnableStatusTask.Params) { override suspend fun execute(params: UpdatePushRuleEnableStatusTask.Params) {
return executeRequest { return executeRequest(eventBus) {
apiCall = pushRulesApi.updateEnableRuleStatus(params.kind.value, params.pushRule.ruleId, params.enabled) apiCall = pushRulesApi.updateEnableRuleStatus(params.kind.value, params.pushRule.ruleId, params.enabled)
} }
} }

View File

@ -19,18 +19,20 @@ package im.vector.matrix.android.internal.session.room
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations import androidx.lifecycle.Transformations
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.crypto.CryptoService
import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.members.MembershipService import im.vector.matrix.android.api.session.room.members.MembershipService
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.relation.RelationService import im.vector.matrix.android.api.session.room.model.relation.RelationService
import im.vector.matrix.android.api.session.room.notification.RoomPushRuleService import im.vector.matrix.android.api.session.room.notification.RoomPushRuleService
import im.vector.matrix.android.api.session.room.reporting.ReportingService
import im.vector.matrix.android.api.session.room.read.ReadService import im.vector.matrix.android.api.session.room.read.ReadService
import im.vector.matrix.android.api.session.room.reporting.ReportingService
import im.vector.matrix.android.api.session.room.send.DraftService import im.vector.matrix.android.api.session.room.send.DraftService
import im.vector.matrix.android.api.session.room.send.SendService import im.vector.matrix.android.api.session.room.send.SendService
import im.vector.matrix.android.api.session.room.state.StateService import im.vector.matrix.android.api.session.room.state.StateService
import im.vector.matrix.android.api.session.room.timeline.TimelineService import im.vector.matrix.android.api.session.room.timeline.TimelineService
import im.vector.matrix.android.api.session.room.typing.TypingService
import im.vector.matrix.android.api.util.Optional import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.api.util.toOptional import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
@ -48,6 +50,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
private val stateService: StateService, private val stateService: StateService,
private val reportingService: ReportingService, private val reportingService: ReportingService,
private val readService: ReadService, private val readService: ReadService,
private val typingService: TypingService,
private val cryptoService: CryptoService, private val cryptoService: CryptoService,
private val relationService: RelationService, private val relationService: RelationService,
private val roomMembersService: MembershipService, private val roomMembersService: MembershipService,
@ -59,6 +62,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
StateService by stateService, StateService by stateService,
ReportingService by reportingService, ReportingService by reportingService,
ReadService by readService, ReadService by readService,
TypingService by typingService,
RelationService by relationService, RelationService by relationService,
MembershipService by roomMembersService, MembershipService by roomMembersService,
RoomPushRuleService by roomPushRuleService { RoomPushRuleService by roomPushRuleService {
@ -91,4 +95,12 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
override fun shouldEncryptForInvitedMembers(): Boolean { override fun shouldEncryptForInvitedMembers(): Boolean {
return cryptoService.shouldEncryptForInvitedMembers(roomId) return cryptoService.shouldEncryptForInvitedMembers(roomId)
} }
override fun enableEncryptionWithAlgorithm(algorithm: String, callback: MatrixCallback<Unit>) {
if (isEncrypted()) {
callback.onFailure(IllegalStateException("Encryption is already enabled for this room"))
} else {
stateService.enableEncryption(algorithm, callback)
}
}
} }

View File

@ -36,7 +36,8 @@ import javax.inject.Inject
* The summaries can then be extracted and added (as a decoration) to a TimelineEvent for final display. * The summaries can then be extracted and added (as a decoration) to a TimelineEvent for final display.
*/ */
internal class EventRelationsAggregationUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration, internal class EventRelationsAggregationUpdater @Inject constructor(
@SessionDatabase realmConfiguration: RealmConfiguration,
@UserId private val userId: String, @UserId private val userId: String,
private val task: EventRelationsAggregationTask) : private val task: EventRelationsAggregationTask) :
RealmLiveEntityObserver<EventEntity>(realmConfiguration) { RealmLiveEntityObserver<EventEntity>(realmConfiguration) {

View File

@ -18,13 +18,13 @@ package im.vector.matrix.android.internal.session.room
import im.vector.matrix.android.api.session.events.model.Content import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.internal.session.room.alias.RoomAliasDescription
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.api.session.room.model.create.CreateRoomResponse import im.vector.matrix.android.api.session.room.model.create.CreateRoomResponse
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsParams import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsParams
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse
import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol
import im.vector.matrix.android.internal.network.NetworkConstants import im.vector.matrix.android.internal.network.NetworkConstants
import im.vector.matrix.android.internal.session.room.alias.RoomAliasDescription
import im.vector.matrix.android.internal.session.room.membership.RoomMembersResponse import im.vector.matrix.android.internal.session.room.membership.RoomMembersResponse
import im.vector.matrix.android.internal.session.room.membership.joining.InviteBody import im.vector.matrix.android.internal.session.room.membership.joining.InviteBody
import im.vector.matrix.android.internal.session.room.relation.RelationsResponse import im.vector.matrix.android.internal.session.room.relation.RelationsResponse
@ -32,6 +32,7 @@ import im.vector.matrix.android.internal.session.room.reporting.ReportContentBod
import im.vector.matrix.android.internal.session.room.send.SendResponse import im.vector.matrix.android.internal.session.room.send.SendResponse
import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse
import im.vector.matrix.android.internal.session.room.timeline.PaginationResponse import im.vector.matrix.android.internal.session.room.timeline.PaginationResponse
import im.vector.matrix.android.internal.session.room.typing.TypingBody
import retrofit2.Call import retrofit2.Call
import retrofit2.http.* import retrofit2.http.*
@ -268,4 +269,12 @@ internal interface RoomAPI {
*/ */
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "directory/room/{roomAlias}") @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "directory/room/{roomAlias}")
fun getRoomIdByAlias(@Path("roomAlias") roomAlias: String): Call<RoomAliasDescription> fun getRoomIdByAlias(@Path("roomAlias") roomAlias: String): Call<RoomAliasDescription>
/**
* Inform that the user is starting to type or has stopped typing
*/
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/typing/{userId}")
fun sendTypingState(@Path("roomId") roomId: String,
@Path("userId") userId: String,
@Body body: TypingBody): Call<Unit>
} }

View File

@ -30,6 +30,7 @@ import im.vector.matrix.android.internal.session.room.reporting.DefaultReporting
import im.vector.matrix.android.internal.session.room.send.DefaultSendService import im.vector.matrix.android.internal.session.room.send.DefaultSendService
import im.vector.matrix.android.internal.session.room.state.DefaultStateService import im.vector.matrix.android.internal.session.room.state.DefaultStateService
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService
import im.vector.matrix.android.internal.session.room.typing.DefaultTypingService
import javax.inject.Inject import javax.inject.Inject
internal interface RoomFactory { internal interface RoomFactory {
@ -46,6 +47,7 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
private val stateServiceFactory: DefaultStateService.Factory, private val stateServiceFactory: DefaultStateService.Factory,
private val reportingServiceFactory: DefaultReportingService.Factory, private val reportingServiceFactory: DefaultReportingService.Factory,
private val readServiceFactory: DefaultReadService.Factory, private val readServiceFactory: DefaultReadService.Factory,
private val typingServiceFactory: DefaultTypingService.Factory,
private val relationServiceFactory: DefaultRelationService.Factory, private val relationServiceFactory: DefaultRelationService.Factory,
private val membershipServiceFactory: DefaultMembershipService.Factory, private val membershipServiceFactory: DefaultMembershipService.Factory,
private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory) : private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory) :
@ -62,6 +64,7 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
stateServiceFactory.create(roomId), stateServiceFactory.create(roomId),
reportingServiceFactory.create(roomId), reportingServiceFactory.create(roomId),
readServiceFactory.create(roomId), readServiceFactory.create(roomId),
typingServiceFactory.create(roomId),
cryptoService, cryptoService,
relationServiceFactory.create(roomId), relationServiceFactory.create(roomId),
membershipServiceFactory.create(roomId), membershipServiceFactory.create(roomId),

View File

@ -52,6 +52,8 @@ import im.vector.matrix.android.internal.session.room.reporting.ReportContentTas
import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask
import im.vector.matrix.android.internal.session.room.state.SendStateTask import im.vector.matrix.android.internal.session.room.state.SendStateTask
import im.vector.matrix.android.internal.session.room.timeline.* import im.vector.matrix.android.internal.session.room.timeline.*
import im.vector.matrix.android.internal.session.room.typing.DefaultSendTypingTask
import im.vector.matrix.android.internal.session.room.typing.SendTypingTask
import retrofit2.Retrofit import retrofit2.Retrofit
@Module @Module
@ -68,74 +70,77 @@ internal abstract class RoomModule {
} }
@Binds @Binds
abstract fun bindRoomFactory(roomFactory: DefaultRoomFactory): RoomFactory abstract fun bindRoomFactory(factory: DefaultRoomFactory): RoomFactory
@Binds @Binds
abstract fun bindRoomService(roomService: DefaultRoomService): RoomService abstract fun bindRoomService(service: DefaultRoomService): RoomService
@Binds @Binds
abstract fun bindRoomDirectoryService(roomDirectoryService: DefaultRoomDirectoryService): RoomDirectoryService abstract fun bindRoomDirectoryService(service: DefaultRoomDirectoryService): RoomDirectoryService
@Binds @Binds
abstract fun bindEventRelationsAggregationTask(eventRelationsAggregationTask: DefaultEventRelationsAggregationTask): EventRelationsAggregationTask abstract fun bindFileService(service: DefaultFileService): FileService
@Binds @Binds
abstract fun bindCreateRoomTask(createRoomTask: DefaultCreateRoomTask): CreateRoomTask abstract fun bindEventRelationsAggregationTask(task: DefaultEventRelationsAggregationTask): EventRelationsAggregationTask
@Binds @Binds
abstract fun bindGetPublicRoomTask(getPublicRoomTask: DefaultGetPublicRoomTask): GetPublicRoomTask abstract fun bindCreateRoomTask(task: DefaultCreateRoomTask): CreateRoomTask
@Binds @Binds
abstract fun bindGetThirdPartyProtocolsTask(getThirdPartyProtocolsTask: DefaultGetThirdPartyProtocolsTask): GetThirdPartyProtocolsTask abstract fun bindGetPublicRoomTask(task: DefaultGetPublicRoomTask): GetPublicRoomTask
@Binds @Binds
abstract fun bindInviteTask(inviteTask: DefaultInviteTask): InviteTask abstract fun bindGetThirdPartyProtocolsTask(task: DefaultGetThirdPartyProtocolsTask): GetThirdPartyProtocolsTask
@Binds @Binds
abstract fun bindJoinRoomTask(joinRoomTask: DefaultJoinRoomTask): JoinRoomTask abstract fun bindInviteTask(task: DefaultInviteTask): InviteTask
@Binds @Binds
abstract fun bindLeaveRoomTask(leaveRoomTask: DefaultLeaveRoomTask): LeaveRoomTask abstract fun bindJoinRoomTask(task: DefaultJoinRoomTask): JoinRoomTask
@Binds @Binds
abstract fun bindLoadRoomMembersTask(loadRoomMembersTask: DefaultLoadRoomMembersTask): LoadRoomMembersTask abstract fun bindLeaveRoomTask(task: DefaultLeaveRoomTask): LeaveRoomTask
@Binds @Binds
abstract fun bindPruneEventTask(pruneEventTask: DefaultPruneEventTask): PruneEventTask abstract fun bindLoadRoomMembersTask(task: DefaultLoadRoomMembersTask): LoadRoomMembersTask
@Binds @Binds
abstract fun bindSetReadMarkersTask(setReadMarkersTask: DefaultSetReadMarkersTask): SetReadMarkersTask abstract fun bindPruneEventTask(task: DefaultPruneEventTask): PruneEventTask
@Binds @Binds
abstract fun bindMarkAllRoomsReadTask(markAllRoomsReadTask: DefaultMarkAllRoomsReadTask): MarkAllRoomsReadTask abstract fun bindSetReadMarkersTask(task: DefaultSetReadMarkersTask): SetReadMarkersTask
@Binds @Binds
abstract fun bindFindReactionEventForUndoTask(findReactionEventForUndoTask: DefaultFindReactionEventForUndoTask): FindReactionEventForUndoTask abstract fun bindMarkAllRoomsReadTask(task: DefaultMarkAllRoomsReadTask): MarkAllRoomsReadTask
@Binds @Binds
abstract fun bindUpdateQuickReactionTask(updateQuickReactionTask: DefaultUpdateQuickReactionTask): UpdateQuickReactionTask abstract fun bindFindReactionEventForUndoTask(task: DefaultFindReactionEventForUndoTask): FindReactionEventForUndoTask
@Binds @Binds
abstract fun bindSendStateTask(sendStateTask: DefaultSendStateTask): SendStateTask abstract fun bindUpdateQuickReactionTask(task: DefaultUpdateQuickReactionTask): UpdateQuickReactionTask
@Binds @Binds
abstract fun bindReportContentTask(reportContentTask: DefaultReportContentTask): ReportContentTask abstract fun bindSendStateTask(task: DefaultSendStateTask): SendStateTask
@Binds @Binds
abstract fun bindGetContextOfEventTask(getContextOfEventTask: DefaultGetContextOfEventTask): GetContextOfEventTask abstract fun bindReportContentTask(task: DefaultReportContentTask): ReportContentTask
@Binds @Binds
abstract fun bindClearUnlinkedEventsTask(clearUnlinkedEventsTask: DefaultClearUnlinkedEventsTask): ClearUnlinkedEventsTask abstract fun bindGetContextOfEventTask(task: DefaultGetContextOfEventTask): GetContextOfEventTask
@Binds @Binds
abstract fun bindPaginationTask(paginationTask: DefaultPaginationTask): PaginationTask abstract fun bindClearUnlinkedEventsTask(task: DefaultClearUnlinkedEventsTask): ClearUnlinkedEventsTask
@Binds @Binds
abstract fun bindFileService(fileService: DefaultFileService): FileService abstract fun bindPaginationTask(task: DefaultPaginationTask): PaginationTask
@Binds @Binds
abstract fun bindFetchEditHistoryTask(fetchEditHistoryTask: DefaultFetchEditHistoryTask): FetchEditHistoryTask abstract fun bindFetchEditHistoryTask(task: DefaultFetchEditHistoryTask): FetchEditHistoryTask
@Binds @Binds
abstract fun bindGetRoomIdByAliasTask(getRoomIdByAliasTask: DefaultGetRoomIdByAliasTask): GetRoomIdByAliasTask abstract fun bindGetRoomIdByAliasTask(task: DefaultGetRoomIdByAliasTask): GetRoomIdByAliasTask
@Binds
abstract fun bindSendTypingTask(task: DefaultSendTypingTask): SendTypingTask
} }

View File

@ -29,19 +29,17 @@ import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.* import im.vector.matrix.android.internal.database.query.*
import im.vector.matrix.android.internal.database.query.isEventRead
import im.vector.matrix.android.internal.database.query.latestEvent
import im.vector.matrix.android.internal.database.query.prev
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
import im.vector.matrix.android.internal.session.sync.RoomSyncHandler
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
import im.vector.matrix.android.internal.session.sync.model.RoomSyncUnreadNotifications import im.vector.matrix.android.internal.session.sync.model.RoomSyncUnreadNotifications
import io.realm.Realm import io.realm.Realm
import javax.inject.Inject import javax.inject.Inject
internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId: String, internal class RoomSummaryUpdater @Inject constructor(
@UserId private val userId: String,
private val roomDisplayNameResolver: RoomDisplayNameResolver, private val roomDisplayNameResolver: RoomDisplayNameResolver,
private val roomAvatarResolver: RoomAvatarResolver, private val roomAvatarResolver: RoomAvatarResolver,
private val monarchy: Monarchy) { private val monarchy: Monarchy) {
@ -57,7 +55,7 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
EventType.CALL_HANGUP, EventType.CALL_HANGUP,
EventType.CALL_ANSWER, EventType.CALL_ANSWER,
EventType.ENCRYPTED, EventType.ENCRYPTED,
EventType.ENCRYPTION, EventType.STATE_ROOM_ENCRYPTION,
EventType.STATE_ROOM_THIRD_PARTY_INVITE, EventType.STATE_ROOM_THIRD_PARTY_INVITE,
EventType.STICKER, EventType.STICKER,
EventType.STATE_ROOM_CREATE EventType.STATE_ROOM_CREATE
@ -68,7 +66,8 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
membership: Membership? = null, membership: Membership? = null,
roomSummary: RoomSyncSummary? = null, roomSummary: RoomSyncSummary? = null,
unreadNotifications: RoomSyncUnreadNotifications? = null, unreadNotifications: RoomSyncUnreadNotifications? = null,
updateMembers: Boolean = false) { updateMembers: Boolean = false,
ephemeralResult: RoomSyncHandler.EphemeralResult? = null) {
val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId) val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId)
if (roomSummary != null) { if (roomSummary != null) {
if (roomSummary.heroes.isNotEmpty()) { if (roomSummary.heroes.isNotEmpty()) {
@ -93,7 +92,7 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev() val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()
val lastCanonicalAliasEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_CANONICAL_ALIAS).prev() val lastCanonicalAliasEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_CANONICAL_ALIAS).prev()
val lastAliasesEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_ALIASES).prev() val lastAliasesEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_ALIASES).prev()
val encryptionEvent = EventEntity.where(realm, roomId, EventType.ENCRYPTION).prev() val encryptionEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_ENCRYPTION).prev()
roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0 roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0
// avoid this call if we are sure there are unread events // avoid this call if we are sure there are unread events
@ -112,6 +111,8 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
roomSummaryEntity.aliases.addAll(roomAliases) roomSummaryEntity.aliases.addAll(roomAliases)
roomSummaryEntity.flatAliases = roomAliases.joinToString(separator = "|", prefix = "|") roomSummaryEntity.flatAliases = roomAliases.joinToString(separator = "|", prefix = "|")
roomSummaryEntity.isEncrypted = encryptionEvent != null roomSummaryEntity.isEncrypted = encryptionEvent != null
roomSummaryEntity.typingUserIds.clear()
roomSummaryEntity.typingUserIds.addAll(ephemeralResult?.typingUserIds.orEmpty())
if (updateMembers) { if (updateMembers) {
val otherRoomMembers = RoomMemberHelper(realm, roomId) val otherRoomMembers = RoomMemberHelper(realm, roomId)

View File

@ -24,6 +24,7 @@ import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.room.RoomAPI import im.vector.matrix.android.internal.session.room.RoomAPI
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import io.realm.Realm import io.realm.Realm
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetRoomIdByAliasTask : Task<GetRoomIdByAliasTask.Params, Optional<String>> { internal interface GetRoomIdByAliasTask : Task<GetRoomIdByAliasTask.Params, Optional<String>> {
@ -33,8 +34,11 @@ internal interface GetRoomIdByAliasTask : Task<GetRoomIdByAliasTask.Params, Opti
) )
} }
internal class DefaultGetRoomIdByAliasTask @Inject constructor(private val monarchy: Monarchy, internal class DefaultGetRoomIdByAliasTask @Inject constructor(
private val roomAPI: RoomAPI) : GetRoomIdByAliasTask { private val monarchy: Monarchy,
private val roomAPI: RoomAPI,
private val eventBus: EventBus
) : GetRoomIdByAliasTask {
override suspend fun execute(params: GetRoomIdByAliasTask.Params): Optional<String> { override suspend fun execute(params: GetRoomIdByAliasTask.Params): Optional<String> {
var roomId = Realm.getInstance(monarchy.realmConfiguration).use { var roomId = Realm.getInstance(monarchy.realmConfiguration).use {
@ -45,7 +49,7 @@ internal class DefaultGetRoomIdByAliasTask @Inject constructor(private val monar
} else if (!params.searchOnServer) { } else if (!params.searchOnServer) {
Optional.from<String>(null) Optional.from<String>(null)
} else { } else {
roomId = executeRequest<RoomAliasDescription> { roomId = executeRequest<RoomAliasDescription>(eventBus) {
apiCall = roomAPI.getRoomIdByAlias(params.roomAlias) apiCall = roomAPI.getRoomIdByAlias(params.roomAlias)
}.roomId }.roomId
Optional.from(roomId) Optional.from(roomId)

View File

@ -35,21 +35,25 @@ import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.TimeoutCancellationException
import org.greenrobot.eventbus.EventBus
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
internal interface CreateRoomTask : Task<CreateRoomParams, String> internal interface CreateRoomTask : Task<CreateRoomParams, String>
internal class DefaultCreateRoomTask @Inject constructor(private val roomAPI: RoomAPI, internal class DefaultCreateRoomTask @Inject constructor(
private val roomAPI: RoomAPI,
private val monarchy: Monarchy, private val monarchy: Monarchy,
private val directChatsHelper: DirectChatsHelper, private val directChatsHelper: DirectChatsHelper,
private val updateUserAccountDataTask: UpdateUserAccountDataTask, private val updateUserAccountDataTask: UpdateUserAccountDataTask,
private val readMarkersTask: SetReadMarkersTask, private val readMarkersTask: SetReadMarkersTask,
@SessionDatabase @SessionDatabase
private val realmConfiguration: RealmConfiguration) : CreateRoomTask { private val realmConfiguration: RealmConfiguration,
private val eventBus: EventBus
) : CreateRoomTask {
override suspend fun execute(params: CreateRoomParams): String { override suspend fun execute(params: CreateRoomParams): String {
val createRoomResponse = executeRequest<CreateRoomResponse> { val createRoomResponse = executeRequest<CreateRoomResponse>(eventBus) {
apiCall = roomAPI.createRoom(params) apiCall = roomAPI.createRoom(params)
} }
val roomId = createRoomResponse.roomId!! val roomId = createRoomResponse.roomId!!

View File

@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRooms
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.room.RoomAPI import im.vector.matrix.android.internal.session.room.RoomAPI
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetPublicRoomTask : Task<GetPublicRoomTask.Params, PublicRoomsResponse> { internal interface GetPublicRoomTask : Task<GetPublicRoomTask.Params, PublicRoomsResponse> {
@ -30,10 +31,13 @@ internal interface GetPublicRoomTask : Task<GetPublicRoomTask.Params, PublicRoom
) )
} }
internal class DefaultGetPublicRoomTask @Inject constructor(private val roomAPI: RoomAPI) : GetPublicRoomTask { internal class DefaultGetPublicRoomTask @Inject constructor(
private val roomAPI: RoomAPI,
private val eventBus: EventBus
) : GetPublicRoomTask {
override suspend fun execute(params: GetPublicRoomTask.Params): PublicRoomsResponse { override suspend fun execute(params: GetPublicRoomTask.Params): PublicRoomsResponse {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomAPI.publicRooms(params.server, params.publicRoomsParams) apiCall = roomAPI.publicRooms(params.server, params.publicRoomsParams)
} }
} }

View File

@ -20,14 +20,18 @@ import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProt
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.room.RoomAPI import im.vector.matrix.android.internal.session.room.RoomAPI
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject import javax.inject.Inject
internal interface GetThirdPartyProtocolsTask : Task<Unit, Map<String, ThirdPartyProtocol>> internal interface GetThirdPartyProtocolsTask : Task<Unit, Map<String, ThirdPartyProtocol>>
internal class DefaultGetThirdPartyProtocolsTask @Inject constructor(private val roomAPI: RoomAPI) : GetThirdPartyProtocolsTask { internal class DefaultGetThirdPartyProtocolsTask @Inject constructor(
private val roomAPI: RoomAPI,
private val eventBus: EventBus
) : GetThirdPartyProtocolsTask {
override suspend fun execute(params: Unit): Map<String, ThirdPartyProtocol> { override suspend fun execute(params: Unit): Map<String, ThirdPartyProtocol> {
return executeRequest { return executeRequest(eventBus) {
apiCall = roomAPI.thirdPartyProtocols() apiCall = roomAPI.thirdPartyProtocols()
} }
} }

View File

@ -29,6 +29,7 @@ import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.RoomMemberSummaryEntity import im.vector.matrix.android.internal.database.model.RoomMemberSummaryEntity
import im.vector.matrix.android.internal.database.model.RoomMemberSummaryEntityFields import im.vector.matrix.android.internal.database.model.RoomMemberSummaryEntityFields
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.query.process import im.vector.matrix.android.internal.query.process
import im.vector.matrix.android.internal.session.room.membership.joining.InviteTask import im.vector.matrix.android.internal.session.room.membership.joining.InviteTask
import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask
@ -39,13 +40,16 @@ import im.vector.matrix.android.internal.util.fetchCopied
import io.realm.Realm import io.realm.Realm
import io.realm.RealmQuery import io.realm.RealmQuery
internal class DefaultMembershipService @AssistedInject constructor(@Assisted private val roomId: String, internal class DefaultMembershipService @AssistedInject constructor(
@Assisted private val roomId: String,
private val monarchy: Monarchy, private val monarchy: Monarchy,
private val taskExecutor: TaskExecutor, private val taskExecutor: TaskExecutor,
private val loadRoomMembersTask: LoadRoomMembersTask, private val loadRoomMembersTask: LoadRoomMembersTask,
private val inviteTask: InviteTask, private val inviteTask: InviteTask,
private val joinTask: JoinRoomTask, private val joinTask: JoinRoomTask,
private val leaveRoomTask: LeaveRoomTask private val leaveRoomTask: LeaveRoomTask,
@UserId
private val userId: String
) : MembershipService { ) : MembershipService {
@AssistedInject.Factory @AssistedInject.Factory
@ -91,11 +95,17 @@ internal class DefaultMembershipService @AssistedInject constructor(@Assisted pr
) )
} }
private fun roomMembersQuery(realm: Realm, queryParams: RoomMemberQueryParams): RealmQuery<RoomMemberSummaryEntity> { private fun roomMembersQuery(realm: Realm, queryParams: RoomMemberQueryParams): RealmQuery<RoomMemberSummaryEntity> {
return RoomMemberHelper(realm, roomId).queryRoomMembersEvent() return RoomMemberHelper(realm, roomId).queryRoomMembersEvent()
.process(RoomMemberSummaryEntityFields.USER_ID, queryParams.userId) .process(RoomMemberSummaryEntityFields.USER_ID, queryParams.userId)
.process(RoomMemberSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships) .process(RoomMemberSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
.process(RoomMemberSummaryEntityFields.DISPLAY_NAME, queryParams.displayName) .process(RoomMemberSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
.apply {
if (queryParams.excludeSelf) {
notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId)
}
}
} }
override fun getNumberOfJoinedMembers(): Int { override fun getNumberOfJoinedMembers(): Int {

Some files were not shown because too many files have changed in this diff Show More