mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Merge branch 'develop' into feature/room_profile
This commit is contained in:
commit
d3415d345f
@ -20,6 +20,7 @@
|
||||
<w>signin</w>
|
||||
<w>signout</w>
|
||||
<w>signup</w>
|
||||
<w>threepid</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
31
CHANGES.md
31
CHANGES.md
@ -1,22 +1,41 @@
|
||||
Changes in RiotX 0.12.0 (2019-XX-XX)
|
||||
Changes in RiotX 0.13.0 (2020-XX-XX)
|
||||
===================================================
|
||||
|
||||
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 🙌:
|
||||
- The initial sync is now handled by a foreground service
|
||||
- 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)
|
||||
- Improve devices list screen
|
||||
- Add settings for rageshake sensibility
|
||||
- Fix autocompletion issues and add support for rooms, groups, and emoji (#780)
|
||||
- Show skip to bottom FAB while scrolling down (#752)
|
||||
- Enable encryption on a room, SDK part (#212)
|
||||
|
||||
Other changes:
|
||||
- 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)
|
||||
- Email domain can be limited on some homeservers, i18n of the displayed error (#754)
|
||||
|
||||
Bugfix 🐛:
|
||||
- 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)
|
||||
- Hide non working settings (#751)
|
||||
|
||||
Translations 🗣:
|
||||
-
|
||||
|
||||
Build 🧱:
|
||||
-
|
||||
|
||||
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 ✨:
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
@ -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.")
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.api.auth.data
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.internal.util.md5
|
||||
|
||||
/**
|
||||
* 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
|
||||
@Json(name = "well_known") val wellKnown: WellKnown? = null
|
||||
)
|
||||
|
||||
internal fun Credentials.sessionId(): String {
|
||||
return (if (deviceId.isNullOrBlank()) userId else "$userId|$deviceId").md5()
|
||||
}
|
||||
|
@ -75,6 +75,11 @@ interface Session :
|
||||
val myUserId: String
|
||||
get() = sessionParams.credentials.userId
|
||||
|
||||
/**
|
||||
* The sessionId
|
||||
*/
|
||||
val sessionId: String
|
||||
|
||||
/**
|
||||
* This method allow to open a session. It does start some service on the background.
|
||||
*/
|
||||
|
@ -25,7 +25,6 @@ object EventType {
|
||||
const val MESSAGE = "m.room.message"
|
||||
const val STICKER = "m.sticker"
|
||||
const val ENCRYPTED = "m.room.encrypted"
|
||||
const val ENCRYPTION = "m.room.encryption"
|
||||
const val FEEDBACK = "m.room.message.feedback"
|
||||
const val TYPING = "m.typing"
|
||||
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_RELATED_GROUPS = "m.room.related_groups"
|
||||
const val STATE_ROOM_PINNED_EVENT = "m.room.pinned_events"
|
||||
const val STATE_ROOM_ENCRYPTION = "m.room.encryption"
|
||||
|
||||
// Call Events
|
||||
|
||||
@ -91,7 +91,8 @@ object EventType {
|
||||
STATE_ROOM_CANONICAL_ALIAS,
|
||||
STATE_ROOM_HISTORY_VISIBILITY,
|
||||
STATE_ROOM_RELATED_GROUPS,
|
||||
STATE_ROOM_PINNED_EVENT
|
||||
STATE_ROOM_PINNED_EVENT,
|
||||
STATE_ROOM_ENCRYPTION
|
||||
)
|
||||
|
||||
fun isStateEvent(type: String): Boolean {
|
||||
|
@ -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.relation.RelationService
|
||||
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.reporting.ReportingService
|
||||
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.state.StateService
|
||||
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
|
||||
|
||||
/**
|
||||
@ -38,6 +39,7 @@ interface Room :
|
||||
SendService,
|
||||
DraftService,
|
||||
ReadService,
|
||||
TypingService,
|
||||
MembershipService,
|
||||
StateService,
|
||||
ReportingService,
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package im.vector.matrix.android.api.session.room.crypto
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
|
||||
interface RoomCryptoService {
|
||||
|
||||
fun isEncrypted(): Boolean
|
||||
@ -23,4 +25,6 @@ interface RoomCryptoService {
|
||||
fun encryptionAlgorithm(): String?
|
||||
|
||||
fun shouldEncryptForInvitedMembers(): Boolean
|
||||
|
||||
fun enableEncryptionWithAlgorithm(algorithm: String, callback: MatrixCallback<Unit>)
|
||||
}
|
||||
|
@ -29,7 +29,8 @@ fun roomMemberQueryParams(init: (RoomMemberQueryParams.Builder.() -> Unit) = {})
|
||||
data class RoomMemberQueryParams(
|
||||
val displayName: QueryStringValue,
|
||||
val memberships: List<Membership>,
|
||||
val userId: QueryStringValue
|
||||
val userId: QueryStringValue,
|
||||
val excludeSelf: Boolean
|
||||
) {
|
||||
|
||||
class Builder {
|
||||
@ -37,11 +38,13 @@ data class RoomMemberQueryParams(
|
||||
var userId: QueryStringValue = QueryStringValue.NoCondition
|
||||
var displayName: QueryStringValue = QueryStringValue.IsNotEmpty
|
||||
var memberships: List<Membership> = Membership.all()
|
||||
var excludeSelf: Boolean = false
|
||||
|
||||
fun build() = RoomMemberQueryParams(
|
||||
displayName = displayName,
|
||||
memberships = memberships,
|
||||
userId = userId
|
||||
userId = userId,
|
||||
excludeSelf = excludeSelf
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
@ -44,7 +44,8 @@ data class RoomSummary(
|
||||
val versioningState: VersioningState = VersioningState.NONE,
|
||||
val readMarkerId: String? = null,
|
||||
val userDrafts: List<UserDraft> = emptyList(),
|
||||
var isEncrypted: Boolean
|
||||
var isEncrypted: Boolean,
|
||||
val typingRoomMemberIds: List<String> = emptyList()
|
||||
) {
|
||||
|
||||
val isVersioned: Boolean
|
||||
|
@ -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.RoomHistoryVisibility
|
||||
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
|
||||
@ -88,7 +90,7 @@ class CreateRoomParams {
|
||||
* 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.
|
||||
* 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")
|
||||
var initialStates: MutableList<Event>? = null
|
||||
@ -120,12 +122,12 @@ class CreateRoomParams {
|
||||
*
|
||||
* @param algorithm the algorithm
|
||||
*/
|
||||
fun addCryptoAlgorithm(algorithm: String) {
|
||||
if (algorithm.isNotBlank()) {
|
||||
val contentMap = HashMap<String, String>()
|
||||
contentMap["algorithm"] = algorithm
|
||||
fun enableEncryptionWithAlgorithm(algorithm: String) {
|
||||
if (algorithm == MXCRYPTO_ALGORITHM_MEGOLM) {
|
||||
val contentMap = mapOf("algorithm" to algorithm)
|
||||
|
||||
val algoEvent = Event(type = EventType.ENCRYPTION,
|
||||
val algoEvent = Event(
|
||||
type = EventType.STATE_ROOM_ENCRYPTION,
|
||||
stateKey = "",
|
||||
content = contentMap.toContent()
|
||||
)
|
||||
@ -135,6 +137,8 @@ class CreateRoomParams {
|
||||
} else {
|
||||
initialStates!!.add(algoEvent)
|
||||
}
|
||||
} else {
|
||||
Timber.e("Unsupported algorithm: $algorithm")
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,13 +149,13 @@ class CreateRoomParams {
|
||||
*/
|
||||
fun setHistoryVisibility(historyVisibility: RoomHistoryVisibility?) {
|
||||
// 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) {
|
||||
val contentMap = HashMap<String, RoomHistoryVisibility>()
|
||||
contentMap["history_visibility"] = historyVisibility
|
||||
val contentMap = mapOf("history_visibility" to historyVisibility)
|
||||
|
||||
val historyVisibilityEvent = Event(type = EventType.STATE_ROOM_HISTORY_VISIBILITY,
|
||||
val historyVisibilityEvent = Event(
|
||||
type = EventType.STATE_ROOM_HISTORY_VISIBILITY,
|
||||
stateKey = "",
|
||||
content = contentMap.toContent())
|
||||
|
||||
|
@ -28,6 +28,11 @@ interface StateService {
|
||||
*/
|
||||
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 getStateEventLive(eventType: String): LiveData<Optional<Event>>
|
||||
|
@ -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()
|
||||
}
|
@ -40,8 +40,8 @@ interface SignOutService {
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package im.vector.matrix.android.internal
|
||||
|
||||
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.internal.auth.SessionParamsStore
|
||||
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,
|
||||
private val sessionParamsStore: SessionParamsStore) {
|
||||
|
||||
// SessionId -> SessionComponent
|
||||
private val sessionComponents = HashMap<String, SessionComponent>()
|
||||
|
||||
fun getSessionComponent(userId: String): SessionComponent? {
|
||||
val sessionParams = sessionParamsStore.get(userId) ?: return null
|
||||
fun getSessionComponent(sessionId: String): SessionComponent? {
|
||||
val sessionParams = sessionParamsStore.get(sessionId) ?: return null
|
||||
return getOrCreateSessionComponent(sessionParams)
|
||||
}
|
||||
|
||||
@ -40,17 +42,17 @@ internal class SessionManager @Inject constructor(private val matrixComponent: M
|
||||
return getOrCreateSessionComponent(sessionParams).session()
|
||||
}
|
||||
|
||||
fun releaseSession(userId: String) {
|
||||
if (sessionComponents.containsKey(userId).not()) {
|
||||
throw RuntimeException("You don't have a session for the user $userId")
|
||||
fun releaseSession(sessionId: String) {
|
||||
if (sessionComponents.containsKey(sessionId).not()) {
|
||||
throw RuntimeException("You don't have a session for id $sessionId")
|
||||
}
|
||||
sessionComponents.remove(userId)?.also {
|
||||
sessionComponents.remove(sessionId)?.also {
|
||||
it.session().close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent {
|
||||
return sessionComponents.getOrPut(sessionParams.credentials.userId) {
|
||||
return sessionComponents.getOrPut(sessionParams.credentials.sessionId()) {
|
||||
DaggerSessionComponent
|
||||
.factory()
|
||||
.create(matrixComponent, sessionParams)
|
||||
|
@ -45,7 +45,8 @@ import okhttp3.OkHttpClient
|
||||
import javax.inject.Inject
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
|
||||
internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
|
||||
internal class DefaultAuthenticationService @Inject constructor(
|
||||
@Unauthenticated
|
||||
private val okHttpClient: Lazy<OkHttpClient>,
|
||||
private val retrofitFactory: RetrofitFactory,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
@ -112,7 +113,7 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
|
||||
|
||||
// First check the homeserver version
|
||||
runCatching {
|
||||
executeRequest<Versions> {
|
||||
executeRequest<Versions>(null) {
|
||||
apiCall = authAPI.versions()
|
||||
}
|
||||
}
|
||||
@ -141,7 +142,7 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
|
||||
val authAPI = buildAuthAPI(homeServerConnectionConfig)
|
||||
|
||||
// Ok, try to get the config.json file of a RiotWeb client
|
||||
val riotConfig = executeRequest<RiotConfig> {
|
||||
val riotConfig = executeRequest<RiotConfig>(null) {
|
||||
apiCall = authAPI.getRiotConfig()
|
||||
}
|
||||
|
||||
@ -153,7 +154,7 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
|
||||
|
||||
val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig)
|
||||
|
||||
val versions = executeRequest<Versions> {
|
||||
val versions = executeRequest<Versions>(null) {
|
||||
apiCall = newAuthAPI.versions()
|
||||
}
|
||||
|
||||
@ -167,7 +168,7 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
|
||||
private suspend fun getLoginFlowResult(authAPI: AuthAPI, versions: Versions, homeServerUrl: String): LoginFlowResult {
|
||||
return if (versions.isSupportedBySdk()) {
|
||||
// Get the login flow
|
||||
val loginFlowResponse = executeRequest<LoginFlowResponse> {
|
||||
val loginFlowResponse = executeRequest<LoginFlowResponse>(null) {
|
||||
apiCall = authAPI.getLoginFlows()
|
||||
}
|
||||
LoginFlowResult.Success(loginFlowResponse, versions.isLoginAndRegistrationSupportedBySdk(), homeServerUrl)
|
||||
|
@ -21,7 +21,7 @@ import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
|
||||
internal interface SessionParamsStore {
|
||||
|
||||
fun get(userId: String): SessionParams?
|
||||
fun get(sessionId: String): SessionParams?
|
||||
|
||||
fun getLast(): SessionParams?
|
||||
|
||||
@ -29,11 +29,11 @@ internal interface SessionParamsStore {
|
||||
|
||||
suspend fun save(sessionParams: SessionParams)
|
||||
|
||||
suspend fun setTokenInvalid(userId: String)
|
||||
suspend fun setTokenInvalid(sessionId: String)
|
||||
|
||||
suspend fun updateCredentials(newCredentials: Credentials)
|
||||
|
||||
suspend fun delete(userId: String)
|
||||
suspend fun delete(sessionId: String)
|
||||
|
||||
suspend fun deleteAll()
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
package im.vector.matrix.android.internal.auth.db
|
||||
|
||||
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 io.realm.DynamicRealm
|
||||
import io.realm.RealmMigration
|
||||
@ -71,14 +71,13 @@ internal object AuthRealmMigration : RealmMigration {
|
||||
?.addField(SessionParamsEntityFields.SESSION_ID, String::class.java)
|
||||
?.setRequired(SessionParamsEntityFields.SESSION_ID, true)
|
||||
?.transform {
|
||||
val userId = it.getString(SessionParamsEntityFields.USER_ID)
|
||||
val credentialsJson = it.getString(SessionParamsEntityFields.CREDENTIALS_JSON)
|
||||
|
||||
val credentials = MoshiProvider.providesMoshi()
|
||||
.adapter(Credentials::class.java)
|
||||
.fromJson(credentialsJson)
|
||||
|
||||
it.set(SessionParamsEntityFields.SESSION_ID, createSessionId(userId, credentials?.deviceId))
|
||||
it.set(SessionParamsEntityFields.SESSION_ID, credentials!!.sessionId())
|
||||
}
|
||||
?.addPrimaryKey(SessionParamsEntityFields.SESSION_ID)
|
||||
}
|
||||
|
@ -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.SessionParams
|
||||
import im.vector.matrix.android.api.auth.data.sessionId
|
||||
import im.vector.matrix.android.internal.auth.SessionParamsStore
|
||||
import im.vector.matrix.android.internal.database.awaitTransaction
|
||||
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 ->
|
||||
realm
|
||||
.where(SessionParamsEntity::class.java)
|
||||
.equalTo(SessionParamsEntityFields.USER_ID, userId)
|
||||
.equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
|
||||
.findAll()
|
||||
.map { mapper.map(it) }
|
||||
.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 ->
|
||||
val currentSessionParams = realm
|
||||
.where(SessionParamsEntity::class.java)
|
||||
.equalTo(SessionParamsEntityFields.USER_ID, userId)
|
||||
.equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
|
||||
.findAll()
|
||||
.firstOrNull()
|
||||
|
||||
if (currentSessionParams == null) {
|
||||
// Should not happen
|
||||
"Session param not found for user $userId"
|
||||
"Session param not found for id $sessionId"
|
||||
.let { Timber.w(it) }
|
||||
.also { error(it) }
|
||||
} else {
|
||||
@ -99,14 +100,14 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S
|
||||
awaitTransaction(realmConfiguration) { realm ->
|
||||
val currentSessionParams = realm
|
||||
.where(SessionParamsEntity::class.java)
|
||||
.equalTo(SessionParamsEntityFields.USER_ID, newCredentials.userId)
|
||||
.equalTo(SessionParamsEntityFields.SESSION_ID, newCredentials.sessionId())
|
||||
.findAll()
|
||||
.map { mapper.map(it) }
|
||||
.firstOrNull()
|
||||
|
||||
if (currentSessionParams == null) {
|
||||
// Should not happen
|
||||
"Session param not found for user ${newCredentials.userId}"
|
||||
"Session param not found for id ${newCredentials.sessionId()}"
|
||||
.let { Timber.w(it) }
|
||||
.also { error(it) }
|
||||
} 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) {
|
||||
it.where(SessionParamsEntity::class.java)
|
||||
.equalTo(SessionParamsEntityFields.USER_ID, userId)
|
||||
.equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
}
|
||||
|
@ -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.HomeServerConnectionConfig
|
||||
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
|
||||
|
||||
internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
|
||||
@ -50,7 +50,7 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
|
||||
return null
|
||||
}
|
||||
return SessionParamsEntity(
|
||||
createSessionId(sessionParams.credentials.userId, sessionParams.credentials.deviceId),
|
||||
sessionParams.credentials.sessionId(),
|
||||
sessionParams.credentials.userId,
|
||||
credentialsJson,
|
||||
homeServerConnectionConfigJson,
|
||||
|
@ -72,7 +72,7 @@ internal class DefaultLoginWizard(
|
||||
} else {
|
||||
PasswordLoginParams.userIdentifier(login, password, deviceName)
|
||||
}
|
||||
val credentials = executeRequest<Credentials> {
|
||||
val credentials = executeRequest<Credentials>(null) {
|
||||
apiCall = authAPI.login(loginParams)
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ internal class DefaultLoginWizard(
|
||||
pendingSessionData = pendingSessionData.copy(sendAttempt = pendingSessionData.sendAttempt + 1)
|
||||
.also { pendingSessionStore.savePendingSessionData(it) }
|
||||
|
||||
val result = executeRequest<AddThreePidRegistrationResponse> {
|
||||
val result = executeRequest<AddThreePidRegistrationResponse>(null) {
|
||||
apiCall = authAPI.resetPassword(AddThreePidRegistrationParams.from(param))
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ internal class DefaultLoginWizard(
|
||||
resetPasswordData.newPassword
|
||||
)
|
||||
|
||||
executeRequest<Unit> {
|
||||
executeRequest<Unit>(null) {
|
||||
apiCall = authAPI.resetPasswordMailConfirmed(param)
|
||||
}
|
||||
|
||||
|
@ -29,11 +29,12 @@ internal interface RegisterAddThreePidTask : Task<RegisterAddThreePidTask.Params
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultRegisterAddThreePidTask(private val authAPI: AuthAPI)
|
||||
: RegisterAddThreePidTask {
|
||||
internal class DefaultRegisterAddThreePidTask(
|
||||
private val authAPI: AuthAPI
|
||||
) : RegisterAddThreePidTask {
|
||||
|
||||
override suspend fun execute(params: RegisterAddThreePidTask.Params): AddThreePidRegistrationResponse {
|
||||
return executeRequest {
|
||||
return executeRequest(null) {
|
||||
apiCall = authAPI.add3Pid(params.threePid.toPath(), AddThreePidRegistrationParams.from(params))
|
||||
}
|
||||
}
|
||||
|
@ -29,12 +29,13 @@ internal interface RegisterTask : Task<RegisterTask.Params, Credentials> {
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultRegisterTask(private val authAPI: AuthAPI)
|
||||
: RegisterTask {
|
||||
internal class DefaultRegisterTask(
|
||||
private val authAPI: AuthAPI
|
||||
) : RegisterTask {
|
||||
|
||||
override suspend fun execute(params: RegisterTask.Params): Credentials {
|
||||
try {
|
||||
return executeRequest {
|
||||
return executeRequest(null) {
|
||||
apiCall = authAPI.register(params.registrationParams)
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
|
@ -27,11 +27,12 @@ internal interface ValidateCodeTask : Task<ValidateCodeTask.Params, SuccessResul
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultValidateCodeTask(private val authAPI: AuthAPI)
|
||||
: ValidateCodeTask {
|
||||
internal class DefaultValidateCodeTask(
|
||||
private val authAPI: AuthAPI
|
||||
) : ValidateCodeTask {
|
||||
|
||||
override suspend fun execute(params: ValidateCodeTask.Params): SuccessResult {
|
||||
return executeRequest {
|
||||
return executeRequest(null) {
|
||||
apiCall = authAPI.validate3Pid(params.url, params.body)
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
|
||||
fun onStateEvent(roomId: String, event: Event) {
|
||||
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_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
|
||||
}
|
||||
@ -155,7 +155,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
|
||||
fun onLiveEvent(roomId: String, event: Event) {
|
||||
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_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
|
||||
}
|
||||
@ -482,7 +482,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||
*/
|
||||
override fun isRoomEncrypted(roomId: String): Boolean {
|
||||
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
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ import im.vector.matrix.android.internal.di.UserId
|
||||
import timber.log.Timber
|
||||
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,
|
||||
private val keysBackup: KeysBackup) {
|
||||
|
||||
|
@ -1339,6 +1339,31 @@ internal class KeysBackup @Inject constructor(
|
||||
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 {
|
||||
// Maximum delay in ms in {@link maybeBackupKeys}
|
||||
private const val KEY_BACKUP_WAITING_TIME_TO_SEND_KEY_BACKUP_MILLIS = 10_000L
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface CreateKeysBackupVersionTask : Task<CreateKeysBackupVersionBody, KeysVersion>
|
||||
|
||||
internal class DefaultCreateKeysBackupVersionTask @Inject constructor(private val roomKeysApi: RoomKeysApi)
|
||||
: CreateKeysBackupVersionTask {
|
||||
internal class DefaultCreateKeysBackupVersionTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : CreateKeysBackupVersionTask {
|
||||
|
||||
override suspend fun execute(params: CreateKeysBackupVersionBody): KeysVersion {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.createKeysBackupVersion(params)
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: DeleteBackupTask {
|
||||
internal class DefaultDeleteBackupTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : DeleteBackupTask {
|
||||
|
||||
override suspend fun execute(params: DeleteBackupTask.Params) {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.deleteBackup(params.version)
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: DeleteRoomSessionDataTask {
|
||||
internal class DefaultDeleteRoomSessionDataTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : DeleteRoomSessionDataTask {
|
||||
|
||||
override suspend fun execute(params: DeleteRoomSessionDataTask.Params) {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.deleteRoomSessionData(
|
||||
params.roomId,
|
||||
params.sessionId,
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: DeleteRoomSessionsDataTask {
|
||||
internal class DefaultDeleteRoomSessionsDataTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : DeleteRoomSessionsDataTask {
|
||||
|
||||
override suspend fun execute(params: DeleteRoomSessionsDataTask.Params) {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.deleteRoomSessionsData(
|
||||
params.roomId,
|
||||
params.version)
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: DeleteSessionsDataTask {
|
||||
internal class DefaultDeleteSessionsDataTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : DeleteSessionsDataTask {
|
||||
|
||||
override suspend fun execute(params: DeleteSessionsDataTask.Params) {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.deleteSessionsData(params.version)
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetKeysBackupLastVersionTask : Task<Unit, KeysVersionResult>
|
||||
|
||||
internal class DefaultGetKeysBackupLastVersionTask @Inject constructor(private val roomKeysApi: RoomKeysApi)
|
||||
: GetKeysBackupLastVersionTask {
|
||||
internal class DefaultGetKeysBackupLastVersionTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : GetKeysBackupLastVersionTask {
|
||||
|
||||
override suspend fun execute(params: Unit): KeysVersionResult {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.getKeysBackupLastVersion()
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetKeysBackupVersionTask : Task<String, KeysVersionResult>
|
||||
|
||||
internal class DefaultGetKeysBackupVersionTask @Inject constructor(private val roomKeysApi: RoomKeysApi)
|
||||
: GetKeysBackupVersionTask {
|
||||
internal class DefaultGetKeysBackupVersionTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : GetKeysBackupVersionTask {
|
||||
|
||||
override suspend fun execute(params: String): KeysVersionResult {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.getKeysBackupVersion(params)
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: GetRoomSessionDataTask {
|
||||
internal class DefaultGetRoomSessionDataTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : GetRoomSessionDataTask {
|
||||
|
||||
override suspend fun execute(params: GetRoomSessionDataTask.Params): KeyBackupData {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.getRoomSessionData(
|
||||
params.roomId,
|
||||
params.sessionId,
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: GetRoomSessionsDataTask {
|
||||
internal class DefaultGetRoomSessionsDataTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : GetRoomSessionsDataTask {
|
||||
|
||||
override suspend fun execute(params: GetRoomSessionsDataTask.Params): RoomKeysBackupData {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.getRoomSessionsData(
|
||||
params.roomId,
|
||||
params.version)
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: GetSessionsDataTask {
|
||||
internal class DefaultGetSessionsDataTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : GetSessionsDataTask {
|
||||
|
||||
override suspend fun execute(params: GetSessionsDataTask.Params): KeysBackupData {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.getSessionsData(params.version)
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: StoreRoomSessionDataTask {
|
||||
internal class DefaultStoreRoomSessionDataTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : StoreRoomSessionDataTask {
|
||||
|
||||
override suspend fun execute(params: StoreRoomSessionDataTask.Params): BackupKeysResult {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.storeRoomSessionData(
|
||||
params.roomId,
|
||||
params.sessionId,
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: StoreRoomSessionsDataTask {
|
||||
internal class DefaultStoreRoomSessionsDataTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : StoreRoomSessionsDataTask {
|
||||
|
||||
override suspend fun execute(params: StoreRoomSessionsDataTask.Params): BackupKeysResult {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.storeRoomSessionsData(
|
||||
params.roomId,
|
||||
params.version,
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: StoreSessionsDataTask {
|
||||
internal class DefaultStoreSessionsDataTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : StoreSessionsDataTask {
|
||||
|
||||
override suspend fun execute(params: StoreSessionsDataTask.Params): BackupKeysResult {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.storeSessionsData(
|
||||
params.version,
|
||||
params.keysBackupData)
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: UpdateKeysBackupVersionTask {
|
||||
internal class DefaultUpdateKeysBackupVersionTask @Inject constructor(
|
||||
private val roomKeysApi: RoomKeysApi,
|
||||
private val eventBus: EventBus
|
||||
) : UpdateKeysBackupVersionTask {
|
||||
|
||||
override suspend fun execute(params: UpdateKeysBackupVersionTask.Params) {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomKeysApi.updateKeysBackupVersion(params.version, params.keysBackupVersionBody)
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -33,13 +34,15 @@ internal interface ClaimOneTimeKeysForUsersDeviceTask : Task<ClaimOneTimeKeysFor
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultClaimOneTimeKeysForUsersDevice @Inject constructor(private val cryptoApi: CryptoApi)
|
||||
: ClaimOneTimeKeysForUsersDeviceTask {
|
||||
internal class DefaultClaimOneTimeKeysForUsersDevice @Inject constructor(
|
||||
private val cryptoApi: CryptoApi,
|
||||
private val eventBus: EventBus
|
||||
) : ClaimOneTimeKeysForUsersDeviceTask {
|
||||
|
||||
override suspend fun execute(params: ClaimOneTimeKeysForUsersDeviceTask.Params): MXUsersDevicesMap<MXKey> {
|
||||
val body = KeysClaimBody(oneTimeKeys = params.usersDevicesKeyTypesMap.map)
|
||||
|
||||
val keysClaimResponse = executeRequest<KeysClaimResponse> {
|
||||
val keysClaimResponse = executeRequest<KeysClaimResponse>(eventBus) {
|
||||
apiCall = cryptoApi.claimOneTimeKeysForUsersDevices(body)
|
||||
}
|
||||
val map = MXUsersDevicesMap<MXKey>()
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: DeleteDeviceTask {
|
||||
internal class DefaultDeleteDeviceTask @Inject constructor(
|
||||
private val cryptoApi: CryptoApi,
|
||||
private val eventBus: EventBus
|
||||
) : DeleteDeviceTask {
|
||||
|
||||
override suspend fun execute(params: DeleteDeviceTask.Params) {
|
||||
try {
|
||||
executeRequest<Unit> {
|
||||
executeRequest<Unit>(eventBus) {
|
||||
apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams())
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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,
|
||||
@UserId private val userId: String)
|
||||
: DeleteDeviceWithUserPasswordTask {
|
||||
internal class DefaultDeleteDeviceWithUserPasswordTask @Inject constructor(
|
||||
private val cryptoApi: CryptoApi,
|
||||
@UserId private val userId: String,
|
||||
private val eventBus: EventBus
|
||||
) : DeleteDeviceWithUserPasswordTask {
|
||||
|
||||
override suspend fun execute(params: DeleteDeviceWithUserPasswordTask.Params) {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams()
|
||||
.apply {
|
||||
deleteDeviceAuth = DeleteDeviceAuth()
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface DownloadKeysForUsersTask : Task<DownloadKeysForUsersTask.Params, KeysQueryResponse> {
|
||||
@ -31,8 +32,10 @@ internal interface DownloadKeysForUsersTask : Task<DownloadKeysForUsersTask.Para
|
||||
val token: String?)
|
||||
}
|
||||
|
||||
internal class DefaultDownloadKeysForUsers @Inject constructor(private val cryptoApi: CryptoApi)
|
||||
: DownloadKeysForUsersTask {
|
||||
internal class DefaultDownloadKeysForUsers @Inject constructor(
|
||||
private val cryptoApi: CryptoApi,
|
||||
private val eventBus: EventBus
|
||||
) : DownloadKeysForUsersTask {
|
||||
|
||||
override suspend fun execute(params: DownloadKeysForUsersTask.Params): KeysQueryResponse {
|
||||
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
|
||||
}
|
||||
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = cryptoApi.downloadKeysForUsers(body)
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetDeviceInfoTask : Task<GetDeviceInfoTask.Params, DeviceInfo> {
|
||||
data class Params(val deviceId: String)
|
||||
}
|
||||
|
||||
internal class DefaultGetDeviceInfoTask @Inject constructor(private val cryptoApi: CryptoApi)
|
||||
: GetDeviceInfoTask {
|
||||
internal class DefaultGetDeviceInfoTask @Inject constructor(
|
||||
private val cryptoApi: CryptoApi,
|
||||
private val eventBus: EventBus
|
||||
) : GetDeviceInfoTask {
|
||||
|
||||
override suspend fun execute(params: GetDeviceInfoTask.Params): DeviceInfo {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = cryptoApi.getDeviceInfo(params.deviceId)
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetDevicesTask : Task<Unit, DevicesListResponse>
|
||||
|
||||
internal class DefaultGetDevicesTask @Inject constructor(private val cryptoApi: CryptoApi)
|
||||
: GetDevicesTask {
|
||||
internal class DefaultGetDevicesTask @Inject constructor(
|
||||
private val cryptoApi: CryptoApi,
|
||||
private val eventBus: EventBus
|
||||
) : GetDevicesTask {
|
||||
|
||||
override suspend fun execute(params: Unit): DevicesListResponse {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = cryptoApi.getDevices()
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: GetKeyChangesTask {
|
||||
internal class DefaultGetKeyChangesTask @Inject constructor(
|
||||
private val cryptoApi: CryptoApi,
|
||||
private val eventBus: EventBus
|
||||
) : GetKeyChangesTask {
|
||||
|
||||
override suspend fun execute(params: GetKeyChangesTask.Params): KeyChangesResponse {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = cryptoApi.getKeyChanges(params.from, params.to)
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
import kotlin.random.Random
|
||||
|
||||
@ -35,14 +36,16 @@ internal interface SendToDeviceTask : Task<SendToDeviceTask.Params, Unit> {
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultSendToDeviceTask @Inject constructor(private val cryptoApi: CryptoApi)
|
||||
: SendToDeviceTask {
|
||||
internal class DefaultSendToDeviceTask @Inject constructor(
|
||||
private val cryptoApi: CryptoApi,
|
||||
private val eventBus: EventBus
|
||||
) : SendToDeviceTask {
|
||||
|
||||
override suspend fun execute(params: SendToDeviceTask.Params) {
|
||||
val sendToDeviceBody = SendToDeviceBody()
|
||||
sendToDeviceBody.messages = params.contentMap.map
|
||||
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = cryptoApi.sendToDevice(
|
||||
params.eventType,
|
||||
params.transactionId ?: Random.nextInt(Integer.MAX_VALUE).toString(),
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: SetDeviceNameTask {
|
||||
internal class DefaultSetDeviceNameTask @Inject constructor(
|
||||
private val cryptoApi: CryptoApi,
|
||||
private val eventBus: EventBus
|
||||
) : SetDeviceNameTask {
|
||||
|
||||
override suspend fun execute(params: SetDeviceNameTask.Params) {
|
||||
val body = UpdateDeviceInfoBody(
|
||||
displayName = params.deviceName
|
||||
)
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = cryptoApi.updateDeviceInfo(params.deviceId, body)
|
||||
}
|
||||
}
|
||||
|
@ -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.task.Task
|
||||
import im.vector.matrix.android.internal.util.convertToUTF8
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface UploadKeysTask : Task<UploadKeysTask.Params, KeysUploadResponse> {
|
||||
@ -36,8 +37,10 @@ internal interface UploadKeysTask : Task<UploadKeysTask.Params, KeysUploadRespon
|
||||
val deviceId: String)
|
||||
}
|
||||
|
||||
internal class DefaultUploadKeysTask @Inject constructor(private val cryptoApi: CryptoApi)
|
||||
: UploadKeysTask {
|
||||
internal class DefaultUploadKeysTask @Inject constructor(
|
||||
private val cryptoApi: CryptoApi,
|
||||
private val eventBus: EventBus
|
||||
) : UploadKeysTask {
|
||||
|
||||
override suspend fun execute(params: UploadKeysTask.Params): KeysUploadResponse {
|
||||
val encodedDeviceId = convertToUTF8(params.deviceId)
|
||||
@ -52,7 +55,7 @@ internal class DefaultUploadKeysTask @Inject constructor(private val cryptoApi:
|
||||
body.oneTimeKeys = params.oneTimeKeys
|
||||
}
|
||||
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = if (encodedDeviceId.isBlank()) {
|
||||
cryptoApi.uploadKeys(body)
|
||||
} else {
|
||||
|
@ -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.internal.crypto.algorithms.olm.OlmDecryptionResult
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import java.util.UUID
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class RoomSummaryMapper @Inject constructor(
|
||||
@ -73,7 +73,8 @@ internal class RoomSummaryMapper @Inject constructor(
|
||||
userDrafts = roomSummaryEntity.userDrafts?.userDrafts?.map { DraftMapper.map(it) } ?: emptyList(),
|
||||
canonicalAlias = roomSummaryEntity.canonicalAlias,
|
||||
aliases = roomSummaryEntity.aliases.toList(),
|
||||
isEncrypted = roomSummaryEntity.isEncrypted
|
||||
isEncrypted = roomSummaryEntity.isEncrypted,
|
||||
typingRoomMemberIds = roomSummaryEntity.typingUserIds.toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||
var aliases: RealmList<String> = RealmList(),
|
||||
// this is required for querying
|
||||
var flatAliases: String = "",
|
||||
var isEncrypted: Boolean = false
|
||||
var isEncrypted: Boolean = false,
|
||||
var typingUserIds: RealmList<String> = RealmList()
|
||||
) : RealmObject() {
|
||||
|
||||
private var membershipStr: String = Membership.NONE.name
|
||||
|
@ -17,13 +17,13 @@
|
||||
package im.vector.matrix.android.internal.network
|
||||
|
||||
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.Response
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class AccessTokenInterceptor @Inject constructor(
|
||||
@UserId private val userId: String,
|
||||
@SessionId private val sessionId: String,
|
||||
private val sessionParamsStore: SessionParamsStore) : Interceptor {
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
@ -40,5 +40,5 @@ internal class AccessTokenInterceptor @Inject constructor(
|
||||
}
|
||||
|
||||
private val accessToken
|
||||
get() = sessionParamsStore.get(userId)?.credentials?.accessToken
|
||||
get() = sessionParamsStore.get(sessionId)?.credentials?.accessToken
|
||||
}
|
||||
|
@ -18,12 +18,14 @@ package im.vector.matrix.android.internal.network
|
||||
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import retrofit2.Call
|
||||
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>
|
||||
|
||||
@ -34,7 +36,7 @@ internal class Request<DATA> {
|
||||
response.body()
|
||||
?: throw IllegalStateException("The request returned a null body")
|
||||
} else {
|
||||
throw response.toFailure()
|
||||
throw response.toFailure(eventBus)
|
||||
}
|
||||
} catch (exception: Throwable) {
|
||||
throw when (exception) {
|
||||
|
@ -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
|
||||
*/
|
||||
internal fun <T> Response<T>.toFailure(): Failure {
|
||||
return toFailure(errorBody(), code())
|
||||
internal fun <T> Response<T>.toFailure(eventBus: EventBus?): Failure {
|
||||
return toFailure(errorBody(), code(), eventBus)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a okhttp3 Response to a Failure, and eventually parse errorBody to convert it to a MatrixError
|
||||
*/
|
||||
internal fun okhttp3.Response.toFailure(): Failure {
|
||||
return toFailure(body, code)
|
||||
internal fun okhttp3.Response.toFailure(eventBus: EventBus?): Failure {
|
||||
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) {
|
||||
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.code == MatrixError.M_CONSENT_NOT_GIVEN && !matrixError.consentUri.isNullOrBlank()) {
|
||||
// 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 */
|
||||
&& matrixError.code == MatrixError.M_UNKNOWN_TOKEN) {
|
||||
// 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)
|
||||
|
@ -17,7 +17,6 @@
|
||||
package im.vector.matrix.android.internal.session
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Looper
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.lifecycle.LiveData
|
||||
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.crypto.DefaultCryptoService
|
||||
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.SyncTokenStore
|
||||
import im.vector.matrix.android.internal.session.sync.job.SyncThread
|
||||
@ -61,8 +61,12 @@ import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
@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 eventBus: EventBus,
|
||||
@SessionId
|
||||
override val sessionId: String,
|
||||
private val liveEntityObservers: Set<@JvmSuppressWildcards LiveEntityObserver>,
|
||||
private val sessionListeners: SessionListeners,
|
||||
private val roomService: Lazy<RoomService>,
|
||||
@ -107,23 +111,22 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||
private var syncThread: SyncThread? = null
|
||||
|
||||
override val isOpenable: Boolean
|
||||
get() = sessionParamsStore.get(myUserId)?.isTokenValid ?: false
|
||||
get() = sessionParamsStore.get(sessionId)?.isTokenValid ?: false
|
||||
|
||||
@MainThread
|
||||
override fun open() {
|
||||
assertMainThread()
|
||||
assert(!isOpen)
|
||||
isOpen = true
|
||||
liveEntityObservers.forEach { it.start() }
|
||||
EventBus.getDefault().register(this)
|
||||
eventBus.register(this)
|
||||
}
|
||||
|
||||
override fun requireBackgroundSync() {
|
||||
SyncWorker.requireBackgroundSync(context, myUserId)
|
||||
SyncWorker.requireBackgroundSync(context, sessionId)
|
||||
}
|
||||
|
||||
override fun startAutomaticBackgroundSync(repeatDelay: Long) {
|
||||
SyncWorker.automaticallyBackgroundSync(context, myUserId, 0, repeatDelay)
|
||||
SyncWorker.automaticallyBackgroundSync(context, sessionId, 0, repeatDelay)
|
||||
}
|
||||
|
||||
override fun stopAnyBackgroundSync() {
|
||||
@ -155,7 +158,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||
liveEntityObservers.forEach { it.dispose() }
|
||||
cryptoService.get().close()
|
||||
isOpen = false
|
||||
EventBus.getDefault().unregister(this)
|
||||
eventBus.unregister(this)
|
||||
syncTaskSequencer.close()
|
||||
}
|
||||
|
||||
@ -186,7 +189,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||
&& globalError.softLogout) {
|
||||
// Mark the token has invalid
|
||||
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) {
|
||||
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!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.HomeServerConnectionConfig
|
||||
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.Session
|
||||
import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService
|
||||
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.SessionRealmConfigurationFactory
|
||||
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 io.realm.RealmConfiguration
|
||||
import okhttp3.OkHttpClient
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import retrofit2.Retrofit
|
||||
import java.io.File
|
||||
|
||||
@ -87,7 +88,7 @@ internal abstract class SessionModule {
|
||||
@SessionId
|
||||
@Provides
|
||||
fun providesSessionId(credentials: Credentials): String {
|
||||
return createSessionId(credentials.userId, credentials.deviceId)
|
||||
return credentials.sessionId()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@ -154,6 +155,13 @@ internal abstract class SessionModule {
|
||||
return retrofitFactory
|
||||
.create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUri.toString())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@SessionScope
|
||||
fun providesEventBus(): EventBus {
|
||||
return EventBus.builder().build()
|
||||
}
|
||||
}
|
||||
|
||||
@Binds
|
||||
|
@ -29,12 +29,14 @@ import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class FileUploader @Inject constructor(@Authenticated
|
||||
private val okHttpClient: OkHttpClient,
|
||||
private val eventBus: EventBus,
|
||||
sessionParams: SessionParams,
|
||||
moshi: Moshi) {
|
||||
|
||||
@ -73,7 +75,7 @@ internal class FileUploader @Inject constructor(@Authenticated
|
||||
|
||||
return okHttpClient.newCall(request).awaitResponse().use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
throw response.toFailure()
|
||||
throw response.toFailure(eventBus)
|
||||
} else {
|
||||
response.body?.source()?.let {
|
||||
responseAdapter.fromJson(it)
|
||||
|
@ -42,7 +42,7 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
override val userId: String,
|
||||
override val sessionId: String,
|
||||
val roomId: String,
|
||||
val event: Event,
|
||||
val attachment: ContentAttachmentData,
|
||||
@ -64,7 +64,7 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
|
||||
return Result.success(inputData)
|
||||
}
|
||||
|
||||
val sessionComponent = getSessionComponent(params.userId) ?: return Result.success()
|
||||
val sessionComponent = getSessionComponent(params.sessionId) ?: return Result.success()
|
||||
sessionComponent.inject(this)
|
||||
|
||||
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")
|
||||
contentUploadStateTracker.setSuccess(params.event.eventId!!)
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -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.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
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 filterRepository: FilterRepository
|
||||
private val filterRepository: FilterRepository,
|
||||
private val eventBus: EventBus
|
||||
) : SaveFilterTask {
|
||||
|
||||
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)
|
||||
if (updated) {
|
||||
val filterResponse = executeRequest<FilterResponse> {
|
||||
val filterResponse = executeRequest<FilterResponse>(eventBus) {
|
||||
// TODO auto retry
|
||||
apiCall = filterAPI.uploadFilter(userId, filterBody)
|
||||
}
|
||||
|
@ -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.GroupUsers
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetGroupDataTask : Task<GetGroupDataTask.Params, Unit> {
|
||||
@ -34,18 +35,19 @@ internal interface GetGroupDataTask : Task<GetGroupDataTask.Params, Unit> {
|
||||
|
||||
internal class DefaultGetGroupDataTask @Inject constructor(
|
||||
private val groupAPI: GroupAPI,
|
||||
private val monarchy: Monarchy
|
||||
private val monarchy: Monarchy,
|
||||
private val eventBus: EventBus
|
||||
) : GetGroupDataTask {
|
||||
|
||||
override suspend fun execute(params: GetGroupDataTask.Params) {
|
||||
val groupId = params.groupId
|
||||
val groupSummary = executeRequest<GroupSummaryResponse> {
|
||||
val groupSummary = executeRequest<GroupSummaryResponse>(eventBus) {
|
||||
apiCall = groupAPI.getSummary(groupId)
|
||||
}
|
||||
val groupRooms = executeRequest<GroupRooms> {
|
||||
val groupRooms = executeRequest<GroupRooms>(eventBus) {
|
||||
apiCall = groupAPI.getRooms(groupId)
|
||||
}
|
||||
val groupUsers = executeRequest<GroupUsers> {
|
||||
val groupUsers = executeRequest<GroupUsers>(eventBus) {
|
||||
apiCall = groupAPI.getUsers(groupId)
|
||||
}
|
||||
insertInDb(groupSummary, groupRooms, groupUsers, groupId)
|
||||
|
@ -29,7 +29,7 @@ internal class GetGroupDataWorker(context: Context, params: WorkerParameters) :
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
override val userId: String,
|
||||
override val sessionId: String,
|
||||
val groupIds: List<String>,
|
||||
override val lastFailureMessage: String? = null
|
||||
) : SessionWorkerParams
|
||||
@ -40,7 +40,7 @@ internal class GetGroupDataWorker(context: Context, params: WorkerParameters) :
|
||||
val params = WorkerParamsFactory.fromData<Params>(inputData)
|
||||
?: return Result.failure()
|
||||
|
||||
val sessionComponent = getSessionComponent(params.userId) ?: return Result.success()
|
||||
val sessionComponent = getSessionComponent(params.sessionId) ?: return Result.success()
|
||||
sessionComponent.inject(this)
|
||||
val results = params.groupIds.map { groupId ->
|
||||
runCatching { fetchGroupData(groupId) }
|
||||
|
@ -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.GroupSummaryEntity
|
||||
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.matrixOneTimeWorkRequestBuilder
|
||||
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"
|
||||
|
||||
internal class GroupSummaryUpdater @Inject constructor(private val context: Context,
|
||||
@UserId private val userId: String,
|
||||
internal class GroupSummaryUpdater @Inject constructor(
|
||||
private val context: Context,
|
||||
@SessionId private val sessionId: String,
|
||||
private val monarchy: Monarchy)
|
||||
: RealmLiveEntityObserver<GroupEntity>(monarchy.realmConfiguration) {
|
||||
|
||||
@ -67,7 +68,7 @@ internal class GroupSummaryUpdater @Inject constructor(private val context: Cont
|
||||
}
|
||||
|
||||
private fun fetchGroupsData(groupIds: List<String>) {
|
||||
val getGroupDataWorkerParams = GetGroupDataWorker.Params(userId, groupIds)
|
||||
val getGroupDataWorkerParams = GetGroupDataWorker.Params(sessionId, groupIds)
|
||||
|
||||
val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams)
|
||||
|
||||
|
@ -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.task.Task
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import java.util.Date
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetHomeServerCapabilitiesTask : Task<Unit, Unit>
|
||||
|
||||
internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||
private val capabilitiesAPI: CapabilitiesAPI,
|
||||
private val monarchy: Monarchy
|
||||
private val monarchy: Monarchy,
|
||||
private val eventBus: EventBus
|
||||
) : GetHomeServerCapabilitiesTask {
|
||||
|
||||
override suspend fun execute(params: Unit) {
|
||||
@ -45,7 +47,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
val uploadCapabilities = executeRequest<GetUploadCapabilitiesResult> {
|
||||
val uploadCapabilities = executeRequest<GetUploadCapabilitiesResult>(eventBus) {
|
||||
apiCall = capabilitiesAPI.getUploadCapabilities()
|
||||
}
|
||||
|
||||
|
@ -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.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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 {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = profileAPI.getProfile(params.userId)
|
||||
}
|
||||
}
|
||||
|
@ -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.network.executeRequest
|
||||
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.getSessionComponent
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class AddHttpPusherWorker(context: Context, params: WorkerParameters)
|
||||
@ -36,18 +38,20 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
override val sessionId: String,
|
||||
val pusher: JsonPusher,
|
||||
val userId: String
|
||||
)
|
||||
override val lastFailureMessage: String? = null
|
||||
) : SessionWorkerParams
|
||||
|
||||
@Inject lateinit var pushersAPI: PushersAPI
|
||||
@Inject lateinit var monarchy: Monarchy
|
||||
@Inject lateinit var eventBus: EventBus
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val params = WorkerParamsFactory.fromData<Params>(inputData)
|
||||
?: return Result.failure()
|
||||
|
||||
val sessionComponent = getSessionComponent(params.userId) ?: return Result.success()
|
||||
val sessionComponent = getSessionComponent(params.sessionId) ?: return Result.success()
|
||||
sessionComponent.inject(this)
|
||||
|
||||
val pusher = params.pusher
|
||||
@ -76,7 +80,7 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters)
|
||||
}
|
||||
|
||||
private suspend fun setPusher(pusher: JsonPusher) {
|
||||
executeRequest<Unit> {
|
||||
executeRequest<Unit>(eventBus) {
|
||||
apiCall = pushersAPI.setPusher(pusher)
|
||||
}
|
||||
monarchy.awaitTransaction { realm ->
|
||||
|
@ -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.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: AddPushRuleTask {
|
||||
internal class DefaultAddPushRuleTask @Inject constructor(
|
||||
private val pushRulesApi: PushRulesApi,
|
||||
private val eventBus: EventBus
|
||||
) : AddPushRuleTask {
|
||||
|
||||
override suspend fun execute(params: AddPushRuleTask.Params) {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = pushRulesApi.addRule(params.kind.value, params.pushRule.ruleId, params.pushRule)
|
||||
}
|
||||
}
|
||||
|
@ -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.model.PusherEntity
|
||||
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.configureWith
|
||||
import im.vector.matrix.android.internal.worker.WorkManagerUtil
|
||||
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
|
||||
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||
import java.util.UUID
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
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,
|
||||
@UserId private val userId: String,
|
||||
@SessionId private val sessionId: String,
|
||||
private val getPusherTask: GetPushersTask,
|
||||
private val removePusherTask: RemovePusherTask,
|
||||
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),
|
||||
append = append)
|
||||
|
||||
val params = AddHttpPusherWorker.Params(pusher, userId)
|
||||
val params = AddHttpPusherWorker.Params(sessionId, pusher)
|
||||
|
||||
val request = matrixOneTimeWorkRequestBuilder<AddHttpPusherWorker>()
|
||||
.setConstraints(WorkManagerUtil.workConstraints)
|
||||
|
@ -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.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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
|
||||
*/
|
||||
internal class DefaultGetPushRulesTask @Inject constructor(private val pushRulesApi: PushRulesApi,
|
||||
private val savePushRulesTask: SavePushRulesTask) : GetPushRulesTask {
|
||||
internal class DefaultGetPushRulesTask @Inject constructor(
|
||||
private val pushRulesApi: PushRulesApi,
|
||||
private val savePushRulesTask: SavePushRulesTask,
|
||||
private val eventBus: EventBus
|
||||
) : GetPushRulesTask {
|
||||
|
||||
override suspend fun execute(params: GetPushRulesTask.Params) {
|
||||
val response = executeRequest<GetPushRulesResponse> {
|
||||
val response = executeRequest<GetPushRulesResponse>(eventBus) {
|
||||
apiCall = pushRulesApi.getAllRules()
|
||||
}
|
||||
|
||||
|
@ -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.task.Task
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetPushersTask : Task<Unit, Unit>
|
||||
|
||||
internal class DefaultGetPushersTask @Inject constructor(private val pushersAPI: PushersAPI,
|
||||
private val monarchy: Monarchy) : GetPushersTask {
|
||||
internal class DefaultGetPushersTask @Inject constructor(
|
||||
private val pushersAPI: PushersAPI,
|
||||
private val monarchy: Monarchy,
|
||||
private val eventBus: EventBus
|
||||
) : GetPushersTask {
|
||||
|
||||
override suspend fun execute(params: Unit) {
|
||||
val response = executeRequest<GetPushersResponse> {
|
||||
val response = executeRequest<GetPushersResponse>(eventBus) {
|
||||
apiCall = pushersAPI.getPushers()
|
||||
}
|
||||
monarchy.awaitTransaction { realm ->
|
||||
|
@ -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.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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)
|
||||
: RemovePushRuleTask {
|
||||
internal class DefaultRemovePushRuleTask @Inject constructor(
|
||||
private val pushRulesApi: PushRulesApi,
|
||||
private val eventBus: EventBus
|
||||
) : RemovePushRuleTask {
|
||||
|
||||
override suspend fun execute(params: RemovePushRuleTask.Params) {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = pushRulesApi.deleteRule(params.kind.value, params.pushRule.ruleId)
|
||||
}
|
||||
}
|
||||
|
@ -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.util.awaitTransaction
|
||||
import io.realm.Realm
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> {
|
||||
@ -34,7 +35,8 @@ internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> {
|
||||
|
||||
internal class DefaultRemovePusherTask @Inject constructor(
|
||||
private val pushersAPI: PushersAPI,
|
||||
private val monarchy: Monarchy
|
||||
private val monarchy: Monarchy,
|
||||
private val eventBus: EventBus
|
||||
) : RemovePusherTask {
|
||||
|
||||
override suspend fun execute(params: RemovePusherTask.Params) {
|
||||
@ -59,7 +61,7 @@ internal class DefaultRemovePusherTask @Inject constructor(
|
||||
data = JsonPusherData(existing.data.url, existing.data.format),
|
||||
append = false
|
||||
)
|
||||
executeRequest<Unit> {
|
||||
executeRequest<Unit>(eventBus) {
|
||||
apiCall = pushersAPI.setPusher(deleteBody)
|
||||
}
|
||||
monarchy.awaitTransaction {
|
||||
|
@ -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.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface UpdatePushRuleEnableStatusTask : Task<UpdatePushRuleEnableStatusTask.Params, Unit> {
|
||||
@ -27,11 +28,13 @@ internal interface UpdatePushRuleEnableStatusTask : Task<UpdatePushRuleEnableSta
|
||||
val enabled: Boolean)
|
||||
}
|
||||
|
||||
internal class DefaultUpdatePushRuleEnableStatusTask @Inject constructor(private val pushRulesApi: PushRulesApi)
|
||||
: UpdatePushRuleEnableStatusTask {
|
||||
internal class DefaultUpdatePushRuleEnableStatusTask @Inject constructor(
|
||||
private val pushRulesApi: PushRulesApi,
|
||||
private val eventBus: EventBus
|
||||
) : UpdatePushRuleEnableStatusTask {
|
||||
|
||||
override suspend fun execute(params: UpdatePushRuleEnableStatusTask.Params) {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = pushRulesApi.updateEnableRuleStatus(params.kind.value, params.pushRule.ruleId, params.enabled)
|
||||
}
|
||||
}
|
||||
|
@ -19,18 +19,20 @@ package im.vector.matrix.android.internal.session.room
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
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.room.Room
|
||||
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.relation.RelationService
|
||||
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.reporting.ReportingService
|
||||
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.state.StateService
|
||||
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.toOptional
|
||||
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 reportingService: ReportingService,
|
||||
private val readService: ReadService,
|
||||
private val typingService: TypingService,
|
||||
private val cryptoService: CryptoService,
|
||||
private val relationService: RelationService,
|
||||
private val roomMembersService: MembershipService,
|
||||
@ -59,6 +62,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
||||
StateService by stateService,
|
||||
ReportingService by reportingService,
|
||||
ReadService by readService,
|
||||
TypingService by typingService,
|
||||
RelationService by relationService,
|
||||
MembershipService by roomMembersService,
|
||||
RoomPushRuleService by roomPushRuleService {
|
||||
@ -91,4 +95,12 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
||||
override fun shouldEncryptForInvitedMembers(): Boolean {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
||||
internal class EventRelationsAggregationUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
|
||||
internal class EventRelationsAggregationUpdater @Inject constructor(
|
||||
@SessionDatabase realmConfiguration: RealmConfiguration,
|
||||
@UserId private val userId: String,
|
||||
private val task: EventRelationsAggregationTask) :
|
||||
RealmLiveEntityObserver<EventEntity>(realmConfiguration) {
|
||||
|
@ -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.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.CreateRoomResponse
|
||||
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.thirdparty.ThirdPartyProtocol
|
||||
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.joining.InviteBody
|
||||
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.timeline.EventContextResponse
|
||||
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.http.*
|
||||
|
||||
@ -268,4 +269,12 @@ internal interface RoomAPI {
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "directory/room/{roomAlias}")
|
||||
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>
|
||||
}
|
||||
|
@ -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.state.DefaultStateService
|
||||
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService
|
||||
import im.vector.matrix.android.internal.session.room.typing.DefaultTypingService
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface RoomFactory {
|
||||
@ -46,6 +47,7 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
|
||||
private val stateServiceFactory: DefaultStateService.Factory,
|
||||
private val reportingServiceFactory: DefaultReportingService.Factory,
|
||||
private val readServiceFactory: DefaultReadService.Factory,
|
||||
private val typingServiceFactory: DefaultTypingService.Factory,
|
||||
private val relationServiceFactory: DefaultRelationService.Factory,
|
||||
private val membershipServiceFactory: DefaultMembershipService.Factory,
|
||||
private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory) :
|
||||
@ -62,6 +64,7 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
|
||||
stateServiceFactory.create(roomId),
|
||||
reportingServiceFactory.create(roomId),
|
||||
readServiceFactory.create(roomId),
|
||||
typingServiceFactory.create(roomId),
|
||||
cryptoService,
|
||||
relationServiceFactory.create(roomId),
|
||||
membershipServiceFactory.create(roomId),
|
||||
|
@ -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.SendStateTask
|
||||
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
|
||||
|
||||
@Module
|
||||
@ -68,74 +70,77 @@ internal abstract class RoomModule {
|
||||
}
|
||||
|
||||
@Binds
|
||||
abstract fun bindRoomFactory(roomFactory: DefaultRoomFactory): RoomFactory
|
||||
abstract fun bindRoomFactory(factory: DefaultRoomFactory): RoomFactory
|
||||
|
||||
@Binds
|
||||
abstract fun bindRoomService(roomService: DefaultRoomService): RoomService
|
||||
abstract fun bindRoomService(service: DefaultRoomService): RoomService
|
||||
|
||||
@Binds
|
||||
abstract fun bindRoomDirectoryService(roomDirectoryService: DefaultRoomDirectoryService): RoomDirectoryService
|
||||
abstract fun bindRoomDirectoryService(service: DefaultRoomDirectoryService): RoomDirectoryService
|
||||
|
||||
@Binds
|
||||
abstract fun bindEventRelationsAggregationTask(eventRelationsAggregationTask: DefaultEventRelationsAggregationTask): EventRelationsAggregationTask
|
||||
abstract fun bindFileService(service: DefaultFileService): FileService
|
||||
|
||||
@Binds
|
||||
abstract fun bindCreateRoomTask(createRoomTask: DefaultCreateRoomTask): CreateRoomTask
|
||||
abstract fun bindEventRelationsAggregationTask(task: DefaultEventRelationsAggregationTask): EventRelationsAggregationTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetPublicRoomTask(getPublicRoomTask: DefaultGetPublicRoomTask): GetPublicRoomTask
|
||||
abstract fun bindCreateRoomTask(task: DefaultCreateRoomTask): CreateRoomTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetThirdPartyProtocolsTask(getThirdPartyProtocolsTask: DefaultGetThirdPartyProtocolsTask): GetThirdPartyProtocolsTask
|
||||
abstract fun bindGetPublicRoomTask(task: DefaultGetPublicRoomTask): GetPublicRoomTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindInviteTask(inviteTask: DefaultInviteTask): InviteTask
|
||||
abstract fun bindGetThirdPartyProtocolsTask(task: DefaultGetThirdPartyProtocolsTask): GetThirdPartyProtocolsTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindJoinRoomTask(joinRoomTask: DefaultJoinRoomTask): JoinRoomTask
|
||||
abstract fun bindInviteTask(task: DefaultInviteTask): InviteTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindLeaveRoomTask(leaveRoomTask: DefaultLeaveRoomTask): LeaveRoomTask
|
||||
abstract fun bindJoinRoomTask(task: DefaultJoinRoomTask): JoinRoomTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindLoadRoomMembersTask(loadRoomMembersTask: DefaultLoadRoomMembersTask): LoadRoomMembersTask
|
||||
abstract fun bindLeaveRoomTask(task: DefaultLeaveRoomTask): LeaveRoomTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindPruneEventTask(pruneEventTask: DefaultPruneEventTask): PruneEventTask
|
||||
abstract fun bindLoadRoomMembersTask(task: DefaultLoadRoomMembersTask): LoadRoomMembersTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindSetReadMarkersTask(setReadMarkersTask: DefaultSetReadMarkersTask): SetReadMarkersTask
|
||||
abstract fun bindPruneEventTask(task: DefaultPruneEventTask): PruneEventTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindMarkAllRoomsReadTask(markAllRoomsReadTask: DefaultMarkAllRoomsReadTask): MarkAllRoomsReadTask
|
||||
abstract fun bindSetReadMarkersTask(task: DefaultSetReadMarkersTask): SetReadMarkersTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindFindReactionEventForUndoTask(findReactionEventForUndoTask: DefaultFindReactionEventForUndoTask): FindReactionEventForUndoTask
|
||||
abstract fun bindMarkAllRoomsReadTask(task: DefaultMarkAllRoomsReadTask): MarkAllRoomsReadTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindUpdateQuickReactionTask(updateQuickReactionTask: DefaultUpdateQuickReactionTask): UpdateQuickReactionTask
|
||||
abstract fun bindFindReactionEventForUndoTask(task: DefaultFindReactionEventForUndoTask): FindReactionEventForUndoTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindSendStateTask(sendStateTask: DefaultSendStateTask): SendStateTask
|
||||
abstract fun bindUpdateQuickReactionTask(task: DefaultUpdateQuickReactionTask): UpdateQuickReactionTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindReportContentTask(reportContentTask: DefaultReportContentTask): ReportContentTask
|
||||
abstract fun bindSendStateTask(task: DefaultSendStateTask): SendStateTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetContextOfEventTask(getContextOfEventTask: DefaultGetContextOfEventTask): GetContextOfEventTask
|
||||
abstract fun bindReportContentTask(task: DefaultReportContentTask): ReportContentTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindClearUnlinkedEventsTask(clearUnlinkedEventsTask: DefaultClearUnlinkedEventsTask): ClearUnlinkedEventsTask
|
||||
abstract fun bindGetContextOfEventTask(task: DefaultGetContextOfEventTask): GetContextOfEventTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindPaginationTask(paginationTask: DefaultPaginationTask): PaginationTask
|
||||
abstract fun bindClearUnlinkedEventsTask(task: DefaultClearUnlinkedEventsTask): ClearUnlinkedEventsTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindFileService(fileService: DefaultFileService): FileService
|
||||
abstract fun bindPaginationTask(task: DefaultPaginationTask): PaginationTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindFetchEditHistoryTask(fetchEditHistoryTask: DefaultFetchEditHistoryTask): FetchEditHistoryTask
|
||||
abstract fun bindFetchEditHistoryTask(task: DefaultFetchEditHistoryTask): FetchEditHistoryTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetRoomIdByAliasTask(getRoomIdByAliasTask: DefaultGetRoomIdByAliasTask): GetRoomIdByAliasTask
|
||||
abstract fun bindGetRoomIdByAliasTask(task: DefaultGetRoomIdByAliasTask): GetRoomIdByAliasTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindSendTypingTask(task: DefaultSendTypingTask): SendTypingTask
|
||||
}
|
||||
|
@ -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.TimelineEventEntity
|
||||
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.session.room.membership.RoomDisplayNameResolver
|
||||
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.RoomSyncUnreadNotifications
|
||||
import io.realm.Realm
|
||||
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 roomAvatarResolver: RoomAvatarResolver,
|
||||
private val monarchy: Monarchy) {
|
||||
@ -57,7 +55,7 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
|
||||
EventType.CALL_HANGUP,
|
||||
EventType.CALL_ANSWER,
|
||||
EventType.ENCRYPTED,
|
||||
EventType.ENCRYPTION,
|
||||
EventType.STATE_ROOM_ENCRYPTION,
|
||||
EventType.STATE_ROOM_THIRD_PARTY_INVITE,
|
||||
EventType.STICKER,
|
||||
EventType.STATE_ROOM_CREATE
|
||||
@ -68,7 +66,8 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
|
||||
membership: Membership? = null,
|
||||
roomSummary: RoomSyncSummary? = null,
|
||||
unreadNotifications: RoomSyncUnreadNotifications? = null,
|
||||
updateMembers: Boolean = false) {
|
||||
updateMembers: Boolean = false,
|
||||
ephemeralResult: RoomSyncHandler.EphemeralResult? = null) {
|
||||
val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId)
|
||||
if (roomSummary != null) {
|
||||
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 lastCanonicalAliasEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_CANONICAL_ALIAS).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
|
||||
// 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.flatAliases = roomAliases.joinToString(separator = "|", prefix = "|")
|
||||
roomSummaryEntity.isEncrypted = encryptionEvent != null
|
||||
roomSummaryEntity.typingUserIds.clear()
|
||||
roomSummaryEntity.typingUserIds.addAll(ephemeralResult?.typingUserIds.orEmpty())
|
||||
|
||||
if (updateMembers) {
|
||||
val otherRoomMembers = RoomMemberHelper(realm, roomId)
|
||||
|
@ -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.task.Task
|
||||
import io.realm.Realm
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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,
|
||||
private val roomAPI: RoomAPI) : GetRoomIdByAliasTask {
|
||||
internal class DefaultGetRoomIdByAliasTask @Inject constructor(
|
||||
private val monarchy: Monarchy,
|
||||
private val roomAPI: RoomAPI,
|
||||
private val eventBus: EventBus
|
||||
) : GetRoomIdByAliasTask {
|
||||
|
||||
override suspend fun execute(params: GetRoomIdByAliasTask.Params): Optional<String> {
|
||||
var roomId = Realm.getInstance(monarchy.realmConfiguration).use {
|
||||
@ -45,7 +49,7 @@ internal class DefaultGetRoomIdByAliasTask @Inject constructor(private val monar
|
||||
} else if (!params.searchOnServer) {
|
||||
Optional.from<String>(null)
|
||||
} else {
|
||||
roomId = executeRequest<RoomAliasDescription> {
|
||||
roomId = executeRequest<RoomAliasDescription>(eventBus) {
|
||||
apiCall = roomAPI.getRoomIdByAlias(params.roomAlias)
|
||||
}.roomId
|
||||
Optional.from(roomId)
|
||||
|
@ -35,21 +35,25 @@ import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import io.realm.RealmConfiguration
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
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 directChatsHelper: DirectChatsHelper,
|
||||
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
|
||||
private val readMarkersTask: SetReadMarkersTask,
|
||||
@SessionDatabase
|
||||
private val realmConfiguration: RealmConfiguration) : CreateRoomTask {
|
||||
private val realmConfiguration: RealmConfiguration,
|
||||
private val eventBus: EventBus
|
||||
) : CreateRoomTask {
|
||||
|
||||
override suspend fun execute(params: CreateRoomParams): String {
|
||||
val createRoomResponse = executeRequest<CreateRoomResponse> {
|
||||
val createRoomResponse = executeRequest<CreateRoomResponse>(eventBus) {
|
||||
apiCall = roomAPI.createRoom(params)
|
||||
}
|
||||
val roomId = createRoomResponse.roomId!!
|
||||
|
@ -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.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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 {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomAPI.publicRooms(params.server, params.publicRoomsParams)
|
||||
}
|
||||
}
|
||||
|
@ -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.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
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> {
|
||||
return executeRequest {
|
||||
return executeRequest(eventBus) {
|
||||
apiCall = roomAPI.thirdPartyProtocols()
|
||||
}
|
||||
}
|
||||
|
@ -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.model.RoomMemberSummaryEntity
|
||||
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.session.room.membership.joining.InviteTask
|
||||
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.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 taskExecutor: TaskExecutor,
|
||||
private val loadRoomMembersTask: LoadRoomMembersTask,
|
||||
private val inviteTask: InviteTask,
|
||||
private val joinTask: JoinRoomTask,
|
||||
private val leaveRoomTask: LeaveRoomTask
|
||||
private val leaveRoomTask: LeaveRoomTask,
|
||||
@UserId
|
||||
private val userId: String
|
||||
) : MembershipService {
|
||||
|
||||
@AssistedInject.Factory
|
||||
@ -91,11 +95,17 @@ internal class DefaultMembershipService @AssistedInject constructor(@Assisted pr
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun roomMembersQuery(realm: Realm, queryParams: RoomMemberQueryParams): RealmQuery<RoomMemberSummaryEntity> {
|
||||
return RoomMemberHelper(realm, roomId).queryRoomMembersEvent()
|
||||
.process(RoomMemberSummaryEntityFields.USER_ID, queryParams.userId)
|
||||
.process(RoomMemberSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
|
||||
.process(RoomMemberSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
|
||||
.apply {
|
||||
if (queryParams.excludeSelf) {
|
||||
notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNumberOfJoinedMembers(): Int {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user