Improve Rx chain and cleanup

This commit is contained in:
Benoit Marty 2020-01-31 19:54:04 +01:00
parent 51e0f945a7
commit c3c88c387b
8 changed files with 93 additions and 41 deletions

View File

@ -17,7 +17,6 @@
package im.vector.matrix.rx package im.vector.matrix.rx
import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel
import im.vector.matrix.android.api.extensions.orFalse
import im.vector.matrix.android.api.session.Session 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.Event
import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.api.session.room.Room
@ -31,7 +30,6 @@ import im.vector.matrix.android.api.session.room.send.UserDraft
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.api.util.Optional import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.api.util.toOptional import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.Single import io.reactivex.Single
import io.reactivex.functions.BiFunction import io.reactivex.functions.BiFunction
@ -39,32 +37,50 @@ import io.reactivex.functions.BiFunction
class RxRoom(private val room: Room, private val session: Session) { class RxRoom(private val room: Room, private val session: Session) {
fun liveRoomSummary(): Observable<Optional<RoomSummary>> { fun liveRoomSummary(): Observable<Optional<RoomSummary>> {
val summaryObservable = room.getRoomSummaryLive().asObservable() val summaryObservable = room.getRoomSummaryLive()
.asObservable()
.startWith(room.roomSummary().toOptional()) .startWith(room.roomSummary().toOptional())
val memberChangeObserver = summaryObservable.map { val memberIdsChangeObservable = summaryObservable
it.getOrNull()?.otherMemberIds ?: emptyList() .map {
}.distinctUntilChanged() it.getOrNull()?.let { roomSummary ->
if (roomSummary.isEncrypted) {
val keyObservable = session.getLiveCryptoDeviceInfo().asObservable() // Return the list of other users
roomSummary.otherMemberIds
val subObserver = Observable } else {
.combineLatest<List<String>, List<CryptoDeviceInfo>, RoomEncryptionTrustLevel>( // Return an empty list, the room is not encrypted
memberChangeObserver, emptyList()
keyObservable,
BiFunction { userList, _ ->
session.getCrossSigningService().getTrustLevelForUsers(userList)
} }
) }.orEmpty()
}.distinctUntilChanged()
// Observe the device info of the users in the room
val cryptoDeviceInfoObservable = memberIdsChangeObservable
.switchMap { otherUserIds ->
session.getLiveCryptoDeviceInfo(otherUserIds)
.asObservable()
.map {
// If any key change, emit the userIds list
otherUserIds
}
}
val roomEncryptionTrustLevelObservable = cryptoDeviceInfoObservable
.map { otherUserIds ->
if (otherUserIds.isEmpty()) {
Optional<RoomEncryptionTrustLevel>(null)
} else {
session.getCrossSigningService().getTrustLevelForUsers(otherUserIds).toOptional()
}
}
return Observable return Observable
.combineLatest<Optional<RoomSummary>, RoomEncryptionTrustLevel, Optional<RoomSummary>>( .combineLatest<Optional<RoomSummary>, Optional<RoomEncryptionTrustLevel>, Optional<RoomSummary>>(
summaryObservable, summaryObservable,
subObserver, roomEncryptionTrustLevelObservable,
BiFunction { summary, level -> BiFunction { summary, level ->
summary.getOrNull()?.copy( summary.getOrNull()?.copy(
roomEncryptionTrustLevel = if (summary.getOrNull()?.isEncrypted.orFalse()) level else null roomEncryptionTrustLevel = level.getOrNull()
).toOptional() ).toOptional()
} }
) )

View File

@ -38,22 +38,24 @@ import io.reactivex.functions.BiFunction
class RxSession(private val session: Session) { class RxSession(private val session: Session) {
fun liveRoomSummaries(queryParams: RoomSummaryQueryParams): Observable<List<RoomSummary>> { fun liveRoomSummaries(queryParams: RoomSummaryQueryParams): Observable<List<RoomSummary>> {
val summaryObservable = session.getRoomSummariesLive(queryParams).asObservable() val summariesObservable = session.getRoomSummariesLive(queryParams).asObservable()
.startWith(session.getRoomSummaries(queryParams)) .startWith(session.getRoomSummaries(queryParams))
val keyObservable = session.getLiveCryptoDeviceInfo().asObservable() val cryptoDeviceInfoObservable = session.getLiveCryptoDeviceInfo().asObservable()
return Observable return Observable
.combineLatest<List<RoomSummary>, List<CryptoDeviceInfo>, List<RoomSummary>>( .combineLatest<List<RoomSummary>, List<CryptoDeviceInfo>, List<RoomSummary>>(
summaryObservable, summariesObservable,
keyObservable, cryptoDeviceInfoObservable,
BiFunction { summaries, _ -> BiFunction { summaries, _ ->
summaries.map { summaries.map {
if (it.isEncrypted) it.copy( if (it.isEncrypted) {
roomEncryptionTrustLevel = session.getCrossSigningService().getTrustLevelForUsers( it.copy(
it.otherMemberIds roomEncryptionTrustLevel = session.getCrossSigningService().getTrustLevelForUsers(it.otherMemberIds)
) )
) else it } else {
it
}
} }
} }
) )

View File

@ -120,9 +120,12 @@ interface CryptoService {
fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo> fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo>
fun getLiveCryptoDeviceInfo(userId: String): LiveData<List<CryptoDeviceInfo>>
fun getLiveCryptoDeviceInfo(): LiveData<List<CryptoDeviceInfo>> fun getLiveCryptoDeviceInfo(): LiveData<List<CryptoDeviceInfo>>
fun getLiveCryptoDeviceInfo(userId: String): LiveData<List<CryptoDeviceInfo>>
fun getLiveCryptoDeviceInfo(userIds: List<String>): LiveData<List<CryptoDeviceInfo>>
fun addNewSessionListener(newSessionListener: NewSessionListener) fun addNewSessionListener(newSessionListener: NewSessionListener)
fun removeSessionListener(listener: NewSessionListener) fun removeSessionListener(listener: NewSessionListener)

View File

@ -19,7 +19,6 @@ package im.vector.matrix.android.api.session.crypto.crosssigning
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.util.Optional import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustResult import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustResult
import im.vector.matrix.android.internal.crypto.crosssigning.UserTrustResult import im.vector.matrix.android.internal.crypto.crosssigning.UserTrustResult
@ -65,5 +64,5 @@ interface CrossSigningService {
otherDeviceId: String, otherDeviceId: String,
locallyTrusted: Boolean?): DeviceTrustResult locallyTrusted: Boolean?): DeviceTrustResult
fun getTrustLevelForUsers(userList: List<String>): RoomEncryptionTrustLevel fun getTrustLevelForUsers(userIds: List<String>): RoomEncryptionTrustLevel
} }

View File

@ -403,11 +403,16 @@ internal class DefaultCryptoService @Inject constructor(
return cryptoStore.getUserDevices(userId)?.map { it.value } ?: emptyList() return cryptoStore.getUserDevices(userId)?.map { it.value } ?: emptyList()
} }
override fun getLiveCryptoDeviceInfo(): LiveData<List<CryptoDeviceInfo>> {
return cryptoStore.getLiveDeviceList()
}
override fun getLiveCryptoDeviceInfo(userId: String): LiveData<List<CryptoDeviceInfo>> { override fun getLiveCryptoDeviceInfo(userId: String): LiveData<List<CryptoDeviceInfo>> {
return cryptoStore.getLiveDeviceList(userId) return cryptoStore.getLiveDeviceList(userId)
} }
override fun getLiveCryptoDeviceInfo(): LiveData<List<CryptoDeviceInfo>> {
return cryptoStore.getLiveDeviceList() override fun getLiveCryptoDeviceInfo(userIds: List<String>): LiveData<List<CryptoDeviceInfo>> {
return cryptoStore.getLiveDeviceList(userIds)
} }
/** /**

View File

@ -658,25 +658,33 @@ internal class DefaultCrossSigningService @Inject constructor(
} }
} }
override fun getTrustLevelForUsers(userList: List<String>): RoomEncryptionTrustLevel { override fun getTrustLevelForUsers(userIds: List<String>): RoomEncryptionTrustLevel {
val atLeastOneTrusted = userList val atLeastOneTrusted = userIds
.filter { it != userId } .filter { it != userId }
.map { getUserCrossSigningKeys(it) } .map { getUserCrossSigningKeys(it) }
.any { it?.isTrusted() == true } .any { it?.isTrusted() == true }
if (!atLeastOneTrusted) { return if (!atLeastOneTrusted) {
return RoomEncryptionTrustLevel.Default RoomEncryptionTrustLevel.Default
} else { } else {
// I have verified at least one other user // I have verified at least one other user
val allDevices = userList.mapNotNull { val allDevices = userIds.mapNotNull {
cryptoStore.getUserDeviceList(it) cryptoStore.getUserDeviceList(it)
}.flatten() }.flatten()
if (getMyCrossSigningKeys() != null) { if (getMyCrossSigningKeys() != null) {
val hasWarning = allDevices.any { !it.trustLevel?.crossSigningVerified.orFalse() } val hasWarning = allDevices.any { !it.trustLevel?.crossSigningVerified.orFalse() }
return if (hasWarning) RoomEncryptionTrustLevel.Warning else RoomEncryptionTrustLevel.Trusted if (hasWarning) {
RoomEncryptionTrustLevel.Warning
} else {
RoomEncryptionTrustLevel.Trusted
}
} else { } else {
val hasWarningLegacy = allDevices.any { !it.trustLevel?.crossSigningVerified.orFalse() } val hasWarningLegacy = allDevices.any { !it.isVerified }
return if (hasWarningLegacy) RoomEncryptionTrustLevel.Warning else RoomEncryptionTrustLevel.Trusted if (hasWarningLegacy) {
RoomEncryptionTrustLevel.Warning
} else {
RoomEncryptionTrustLevel.Trusted
}
} }
} }
} }

View File

@ -200,6 +200,9 @@ internal interface IMXCryptoStore {
fun getUserDeviceList(userId: String): List<CryptoDeviceInfo>? fun getUserDeviceList(userId: String): List<CryptoDeviceInfo>?
fun getLiveDeviceList(userId: String): LiveData<List<CryptoDeviceInfo>> fun getLiveDeviceList(userId: String): LiveData<List<CryptoDeviceInfo>>
fun getLiveDeviceList(userIds: List<String>): LiveData<List<CryptoDeviceInfo>>
//TODO temp //TODO temp
fun getLiveDeviceList(): LiveData<List<CryptoDeviceInfo>> fun getLiveDeviceList(): LiveData<List<CryptoDeviceInfo>>
/** /**

View File

@ -398,6 +398,22 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati
} }
} }
override fun getLiveDeviceList(userIds: List<String>): LiveData<List<CryptoDeviceInfo>> {
val liveData = monarchy.findAllMappedWithChanges(
{ realm: Realm ->
realm
.where<UserEntity>()
.`in`(UserEntityFields.USER_ID, userIds.toTypedArray())
},
{ entity ->
entity.devices.map { CryptoMapper.mapToModel(it) }
}
)
return Transformations.map(liveData) {
it.firstOrNull() ?: emptyList()
}
}
override fun getLiveDeviceList(): LiveData<List<CryptoDeviceInfo>> { override fun getLiveDeviceList(): LiveData<List<CryptoDeviceInfo>> {
val liveData = monarchy.findAllMappedWithChanges( val liveData = monarchy.findAllMappedWithChanges(
{ realm: Realm -> { realm: Realm ->