Merge pull request #7247 from vector-im/feature/ons/parse_user_agent
[Device Manager] Parse user agents (PSG-762)
This commit is contained in:
commit
d0dd446af8
|
@ -0,0 +1 @@
|
||||||
|
[Device Manager] Parse user agents
|
|
@ -52,9 +52,17 @@ data class DeviceInfo(
|
||||||
* The last ip address.
|
* The last ip address.
|
||||||
*/
|
*/
|
||||||
@Json(name = "last_seen_ip")
|
@Json(name = "last_seen_ip")
|
||||||
val lastSeenIp: String? = null
|
val lastSeenIp: String? = null,
|
||||||
|
|
||||||
|
@Json(name = "org.matrix.msc3852.last_seen_user_agent")
|
||||||
|
val unstableLastSeenUserAgent: String? = null,
|
||||||
|
|
||||||
|
@Json(name = "last_seen_user_agent")
|
||||||
|
val lastSeenUserAgent: String? = null,
|
||||||
) : DatedObject {
|
) : DatedObject {
|
||||||
|
|
||||||
override val date: Long
|
override val date: Long
|
||||||
get() = lastSeenTs ?: 0
|
get() = lastSeenTs ?: 0
|
||||||
|
|
||||||
|
fun getBestLastSeenUserAgent() = lastSeenUserAgent ?: unstableLastSeenUserAgent
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.app.features.settings.devices.v2
|
||||||
|
|
||||||
|
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||||
|
|
||||||
|
data class DeviceExtendedInfo(
|
||||||
|
/**
|
||||||
|
* One of MOBILE, WEB, DESKTOP or UNKNOWN.
|
||||||
|
*/
|
||||||
|
val deviceType: DeviceType,
|
||||||
|
/**
|
||||||
|
* i.e. Google Pixel 6.
|
||||||
|
*/
|
||||||
|
val deviceModel: String? = null,
|
||||||
|
/**
|
||||||
|
* i.e. Android 11.
|
||||||
|
*/
|
||||||
|
val deviceOperatingSystem: String? = null,
|
||||||
|
/**
|
||||||
|
* i.e. Element Nightly.
|
||||||
|
*/
|
||||||
|
val clientName: String? = null,
|
||||||
|
/**
|
||||||
|
* i.e. 1.5.0.
|
||||||
|
*/
|
||||||
|
val clientVersion: String? = null,
|
||||||
|
)
|
|
@ -26,4 +26,5 @@ data class DeviceFullInfo(
|
||||||
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel,
|
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel,
|
||||||
val isInactive: Boolean,
|
val isInactive: Boolean,
|
||||||
val isCurrentDevice: Boolean,
|
val isCurrentDevice: Boolean,
|
||||||
|
val deviceExtendedInfo: DeviceExtendedInfo,
|
||||||
)
|
)
|
||||||
|
|
|
@ -38,6 +38,7 @@ class GetDeviceFullInfoListUseCase @Inject constructor(
|
||||||
private val getEncryptionTrustLevelForDeviceUseCase: GetEncryptionTrustLevelForDeviceUseCase,
|
private val getEncryptionTrustLevelForDeviceUseCase: GetEncryptionTrustLevelForDeviceUseCase,
|
||||||
private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase,
|
private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase,
|
||||||
private val filterDevicesUseCase: FilterDevicesUseCase,
|
private val filterDevicesUseCase: FilterDevicesUseCase,
|
||||||
|
private val parseDeviceUserAgentUseCase: ParseDeviceUserAgentUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun execute(filterType: DeviceManagerFilterType, excludeCurrentDevice: Boolean = false): Flow<List<DeviceFullInfo>> {
|
fun execute(filterType: DeviceManagerFilterType, excludeCurrentDevice: Boolean = false): Flow<List<DeviceFullInfo>> {
|
||||||
|
@ -72,7 +73,8 @@ class GetDeviceFullInfoListUseCase @Inject constructor(
|
||||||
val roomEncryptionTrustLevel = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo)
|
val roomEncryptionTrustLevel = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo)
|
||||||
val isInactive = checkIfSessionIsInactiveUseCase.execute(deviceInfo.lastSeenTs ?: 0)
|
val isInactive = checkIfSessionIsInactiveUseCase.execute(deviceInfo.lastSeenTs ?: 0)
|
||||||
val isCurrentDevice = currentSessionCrossSigningInfo.deviceId == cryptoDeviceInfo?.deviceId
|
val isCurrentDevice = currentSessionCrossSigningInfo.deviceId == cryptoDeviceInfo?.deviceId
|
||||||
DeviceFullInfo(deviceInfo, cryptoDeviceInfo, roomEncryptionTrustLevel, isInactive, isCurrentDevice)
|
val deviceUserAgent = parseDeviceUserAgentUseCase.execute(deviceInfo.getBestLastSeenUserAgent())
|
||||||
|
DeviceFullInfo(deviceInfo, cryptoDeviceInfo, roomEncryptionTrustLevel, isInactive, isCurrentDevice, deviceUserAgent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.app.features.settings.devices.v2
|
||||||
|
|
||||||
|
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||||
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ParseDeviceUserAgentUseCase @Inject constructor() {
|
||||||
|
|
||||||
|
fun execute(userAgent: String?): DeviceExtendedInfo {
|
||||||
|
if (userAgent == null) return createUnknownUserAgent()
|
||||||
|
|
||||||
|
return when {
|
||||||
|
userAgent.contains(ANDROID_KEYWORD) -> parseAndroidUserAgent(userAgent)
|
||||||
|
userAgent.contains(IOS_KEYWORD) -> parseIosUserAgent(userAgent)
|
||||||
|
userAgent.contains(DESKTOP_KEYWORD) -> parseDesktopUserAgent(userAgent)
|
||||||
|
userAgent.contains(WEB_KEYWORD) -> parseWebUserAgent(userAgent)
|
||||||
|
else -> createUnknownUserAgent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseAndroidUserAgent(userAgent: String): DeviceExtendedInfo {
|
||||||
|
val appName = userAgent.substringBefore("/")
|
||||||
|
val appVersion = userAgent.substringAfter("/").substringBefore(" (")
|
||||||
|
val deviceInfoSegments = userAgent.substringAfter("(").substringBeforeLast(")").split("; ")
|
||||||
|
val deviceModel: String?
|
||||||
|
val deviceOperatingSystem: String?
|
||||||
|
if (deviceInfoSegments.firstOrNull() == "Linux") {
|
||||||
|
val deviceOperatingSystemIndex = deviceInfoSegments.indexOfFirst { it.startsWith("Android") }
|
||||||
|
deviceOperatingSystem = deviceInfoSegments.getOrNull(deviceOperatingSystemIndex)
|
||||||
|
deviceModel = deviceInfoSegments.getOrNull(deviceOperatingSystemIndex + 1)
|
||||||
|
} else {
|
||||||
|
deviceModel = deviceInfoSegments.getOrNull(0)
|
||||||
|
deviceOperatingSystem = deviceInfoSegments.getOrNull(1)
|
||||||
|
}
|
||||||
|
return DeviceExtendedInfo(
|
||||||
|
deviceType = DeviceType.MOBILE,
|
||||||
|
deviceModel = deviceModel,
|
||||||
|
deviceOperatingSystem = deviceOperatingSystem,
|
||||||
|
clientName = appName,
|
||||||
|
clientVersion = appVersion
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseIosUserAgent(userAgent: String): DeviceExtendedInfo {
|
||||||
|
val appName = userAgent.substringBefore("/")
|
||||||
|
val appVersion = userAgent.substringAfter("/").substringBefore(" (")
|
||||||
|
val deviceInfoSegments = userAgent.substringAfter("(").substringBeforeLast(")").split("; ")
|
||||||
|
val deviceModel = deviceInfoSegments.getOrNull(0)
|
||||||
|
val deviceOperatingSystem = deviceInfoSegments.getOrNull(1)
|
||||||
|
return DeviceExtendedInfo(
|
||||||
|
deviceType = DeviceType.MOBILE,
|
||||||
|
deviceModel = deviceModel,
|
||||||
|
deviceOperatingSystem = deviceOperatingSystem,
|
||||||
|
clientName = appName,
|
||||||
|
clientVersion = appVersion
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseDesktopUserAgent(userAgent: String): DeviceExtendedInfo {
|
||||||
|
val browserSegments = userAgent.split(" ")
|
||||||
|
val (browserName, browserVersion) = when {
|
||||||
|
isFirefox(browserSegments) -> {
|
||||||
|
Pair("Firefox", getBrowserVersion(browserSegments, "Firefox"))
|
||||||
|
}
|
||||||
|
isEdge(browserSegments) -> {
|
||||||
|
Pair("Edge", getBrowserVersion(browserSegments, "Edge"))
|
||||||
|
}
|
||||||
|
isMobile(browserSegments) -> {
|
||||||
|
when (val name = getMobileBrowserName(browserSegments)) {
|
||||||
|
null -> {
|
||||||
|
Pair(null, null)
|
||||||
|
}
|
||||||
|
"Safari" -> {
|
||||||
|
Pair(name, getBrowserVersion(browserSegments, "Version"))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Pair(name, getBrowserVersion(browserSegments, name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isSafari(browserSegments) -> {
|
||||||
|
Pair("Safari", getBrowserVersion(browserSegments, "Version"))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
when (val name = getRegularBrowserName(browserSegments)) {
|
||||||
|
null -> {
|
||||||
|
Pair(null, null)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Pair(name, getBrowserVersion(browserSegments, name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val deviceOperatingSystemSegments = userAgent.substringAfter("(").substringBefore(")").split("; ")
|
||||||
|
val deviceOperatingSystem = if (deviceOperatingSystemSegments.getOrNull(1)?.startsWith("Android").orFalse()) {
|
||||||
|
deviceOperatingSystemSegments.getOrNull(1)
|
||||||
|
} else {
|
||||||
|
deviceOperatingSystemSegments.getOrNull(0)
|
||||||
|
}
|
||||||
|
return DeviceExtendedInfo(
|
||||||
|
deviceType = DeviceType.DESKTOP,
|
||||||
|
deviceModel = null,
|
||||||
|
deviceOperatingSystem = deviceOperatingSystem,
|
||||||
|
clientName = browserName,
|
||||||
|
clientVersion = browserVersion,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseWebUserAgent(userAgent: String): DeviceExtendedInfo {
|
||||||
|
return parseDesktopUserAgent(userAgent).copy(
|
||||||
|
deviceType = DeviceType.WEB
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createUnknownUserAgent(): DeviceExtendedInfo {
|
||||||
|
return DeviceExtendedInfo(DeviceType.UNKNOWN)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isFirefox(browserSegments: List<String>): Boolean {
|
||||||
|
return browserSegments.lastOrNull()?.startsWith("Firefox").orFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBrowserVersion(browserSegments: List<String>, browserName: String): String? {
|
||||||
|
// Chrome/104.0.3497.100 -> 104
|
||||||
|
return browserSegments
|
||||||
|
.find { it.startsWith(browserName) }
|
||||||
|
?.split("/")
|
||||||
|
?.getOrNull(1)
|
||||||
|
?.split(".")
|
||||||
|
?.firstOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isEdge(browserSegments: List<String>): Boolean {
|
||||||
|
return browserSegments.lastOrNull()?.startsWith("Edge").orFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isSafari(browserSegments: List<String>): Boolean {
|
||||||
|
return browserSegments.lastOrNull()?.startsWith("Safari").orFalse() &&
|
||||||
|
browserSegments.getOrNull(browserSegments.size - 2)?.startsWith("Version").orFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isMobile(browserSegments: List<String>): Boolean {
|
||||||
|
return browserSegments.getOrNull(browserSegments.size - 2)?.startsWith("Mobile").orFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMobileBrowserName(browserSegments: List<String>): String? {
|
||||||
|
val possibleBrowserName = browserSegments.getOrNull(browserSegments.size - 3)?.split("/")?.firstOrNull()
|
||||||
|
return if (possibleBrowserName == "Version") {
|
||||||
|
"Safari"
|
||||||
|
} else {
|
||||||
|
possibleBrowserName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRegularBrowserName(browserSegments: List<String>): String? {
|
||||||
|
return browserSegments.getOrNull(browserSegments.size - 2)?.split("/")?.firstOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// Element dbg/1.5.0-dev (Xiaomi; Mi 9T; Android 11; RKQ1.200826.002 test-keys; Flavour GooglePlay; MatrixAndroidSdk2 1.5.0)
|
||||||
|
// Legacy : Element/1.0.0 (Linux; U; Android 6.0.1; SM-A510F Build/MMB29; Flavour GPlay; MatrixAndroidSdk2 1.0)
|
||||||
|
private const val ANDROID_KEYWORD = "; MatrixAndroidSdk2"
|
||||||
|
|
||||||
|
// Element/1.8.21 (iPhone XS Max; iOS 15.2; Scale/3.00)
|
||||||
|
private const val IOS_KEYWORD = "; iOS "
|
||||||
|
|
||||||
|
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) ElementNightly/2022091301
|
||||||
|
// Chrome/104.0.5112.102 Electron/20.1.1 Safari/537.36
|
||||||
|
private const val DESKTOP_KEYWORD = " Electron/"
|
||||||
|
|
||||||
|
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
|
||||||
|
private const val WEB_KEYWORD = "Mozilla/"
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2.overview
|
||||||
import androidx.lifecycle.asFlow
|
import androidx.lifecycle.asFlow
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||||
|
import im.vector.app.features.settings.devices.v2.ParseDeviceUserAgentUseCase
|
||||||
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
||||||
import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase
|
import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase
|
||||||
import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase
|
import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase
|
||||||
|
@ -34,6 +35,7 @@ class GetDeviceFullInfoUseCase @Inject constructor(
|
||||||
private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase,
|
private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase,
|
||||||
private val getEncryptionTrustLevelForDeviceUseCase: GetEncryptionTrustLevelForDeviceUseCase,
|
private val getEncryptionTrustLevelForDeviceUseCase: GetEncryptionTrustLevelForDeviceUseCase,
|
||||||
private val checkIfSessionIsInactiveUseCase: CheckIfSessionIsInactiveUseCase,
|
private val checkIfSessionIsInactiveUseCase: CheckIfSessionIsInactiveUseCase,
|
||||||
|
private val parseDeviceUserAgentUseCase: ParseDeviceUserAgentUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun execute(deviceId: String): Flow<DeviceFullInfo> {
|
fun execute(deviceId: String): Flow<DeviceFullInfo> {
|
||||||
|
@ -49,12 +51,14 @@ class GetDeviceFullInfoUseCase @Inject constructor(
|
||||||
val roomEncryptionTrustLevel = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoInfo)
|
val roomEncryptionTrustLevel = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoInfo)
|
||||||
val isInactive = checkIfSessionIsInactiveUseCase.execute(info.lastSeenTs ?: 0)
|
val isInactive = checkIfSessionIsInactiveUseCase.execute(info.lastSeenTs ?: 0)
|
||||||
val isCurrentDevice = currentSessionCrossSigningInfo.deviceId == cryptoInfo.deviceId
|
val isCurrentDevice = currentSessionCrossSigningInfo.deviceId == cryptoInfo.deviceId
|
||||||
|
val deviceUserAgent = parseDeviceUserAgentUseCase.execute(info.getBestLastSeenUserAgent())
|
||||||
DeviceFullInfo(
|
DeviceFullInfo(
|
||||||
deviceInfo = info,
|
deviceInfo = info,
|
||||||
cryptoDeviceInfo = cryptoInfo,
|
cryptoDeviceInfo = cryptoInfo,
|
||||||
roomEncryptionTrustLevel = roomEncryptionTrustLevel,
|
roomEncryptionTrustLevel = roomEncryptionTrustLevel,
|
||||||
isInactive = isInactive,
|
isInactive = isInactive,
|
||||||
isCurrentDevice = isCurrentDevice,
|
isCurrentDevice = isCurrentDevice,
|
||||||
|
deviceExtendedInfo = deviceUserAgent,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.test.MvRxTestRule
|
import com.airbnb.mvrx.test.MvRxTestRule
|
||||||
|
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||||
import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase
|
import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase
|
||||||
import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
|
import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
|
||||||
import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase
|
import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase
|
||||||
|
@ -243,14 +244,16 @@ class DevicesViewModelTest {
|
||||||
cryptoDeviceInfo = verifiedCryptoDeviceInfo,
|
cryptoDeviceInfo = verifiedCryptoDeviceInfo,
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||||
isInactive = false,
|
isInactive = false,
|
||||||
isCurrentDevice = true
|
isCurrentDevice = true,
|
||||||
|
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
)
|
)
|
||||||
val deviceFullInfo2 = DeviceFullInfo(
|
val deviceFullInfo2 = DeviceFullInfo(
|
||||||
deviceInfo = mockk(),
|
deviceInfo = mockk(),
|
||||||
cryptoDeviceInfo = unverifiedCryptoDeviceInfo,
|
cryptoDeviceInfo = unverifiedCryptoDeviceInfo,
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
||||||
isInactive = true,
|
isInactive = true,
|
||||||
isCurrentDevice = false
|
isCurrentDevice = false,
|
||||||
|
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
)
|
)
|
||||||
val deviceFullInfoList = listOf(deviceFullInfo1, deviceFullInfo2)
|
val deviceFullInfoList = listOf(deviceFullInfo1, deviceFullInfo2)
|
||||||
val deviceFullInfoListFlow = flowOf(deviceFullInfoList)
|
val deviceFullInfoListFlow = flowOf(deviceFullInfoList)
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2
|
||||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||||
import im.vector.app.features.settings.devices.v2.filter.FilterDevicesUseCase
|
import im.vector.app.features.settings.devices.v2.filter.FilterDevicesUseCase
|
||||||
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
||||||
|
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||||
import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
|
import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
|
||||||
import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase
|
import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase
|
||||||
import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase
|
import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase
|
||||||
|
@ -53,6 +54,7 @@ class GetDeviceFullInfoListUseCaseTest {
|
||||||
private val getEncryptionTrustLevelForDeviceUseCase = mockk<GetEncryptionTrustLevelForDeviceUseCase>()
|
private val getEncryptionTrustLevelForDeviceUseCase = mockk<GetEncryptionTrustLevelForDeviceUseCase>()
|
||||||
private val getCurrentSessionCrossSigningInfoUseCase = mockk<GetCurrentSessionCrossSigningInfoUseCase>()
|
private val getCurrentSessionCrossSigningInfoUseCase = mockk<GetCurrentSessionCrossSigningInfoUseCase>()
|
||||||
private val filterDevicesUseCase = mockk<FilterDevicesUseCase>()
|
private val filterDevicesUseCase = mockk<FilterDevicesUseCase>()
|
||||||
|
private val parseDeviceUserAgentUseCase = mockk<ParseDeviceUserAgentUseCase>()
|
||||||
|
|
||||||
private val getDeviceFullInfoListUseCase = GetDeviceFullInfoListUseCase(
|
private val getDeviceFullInfoListUseCase = GetDeviceFullInfoListUseCase(
|
||||||
activeSessionHolder = fakeActiveSessionHolder.instance,
|
activeSessionHolder = fakeActiveSessionHolder.instance,
|
||||||
|
@ -60,6 +62,7 @@ class GetDeviceFullInfoListUseCaseTest {
|
||||||
getEncryptionTrustLevelForDeviceUseCase = getEncryptionTrustLevelForDeviceUseCase,
|
getEncryptionTrustLevelForDeviceUseCase = getEncryptionTrustLevelForDeviceUseCase,
|
||||||
getCurrentSessionCrossSigningInfoUseCase = getCurrentSessionCrossSigningInfoUseCase,
|
getCurrentSessionCrossSigningInfoUseCase = getCurrentSessionCrossSigningInfoUseCase,
|
||||||
filterDevicesUseCase = filterDevicesUseCase,
|
filterDevicesUseCase = filterDevicesUseCase,
|
||||||
|
parseDeviceUserAgentUseCase = parseDeviceUserAgentUseCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -87,21 +90,21 @@ class GetDeviceFullInfoListUseCaseTest {
|
||||||
lastSeenTs = A_TIMESTAMP_1,
|
lastSeenTs = A_TIMESTAMP_1,
|
||||||
isInactive = true,
|
isInactive = true,
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||||
cryptoDeviceInfo = cryptoDeviceInfo1
|
cryptoDeviceInfo = cryptoDeviceInfo1,
|
||||||
)
|
)
|
||||||
val deviceInfo2 = givenADevicesInfo(
|
val deviceInfo2 = givenADevicesInfo(
|
||||||
deviceId = A_DEVICE_ID_2,
|
deviceId = A_DEVICE_ID_2,
|
||||||
lastSeenTs = A_TIMESTAMP_2,
|
lastSeenTs = A_TIMESTAMP_2,
|
||||||
isInactive = false,
|
isInactive = false,
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||||
cryptoDeviceInfo = cryptoDeviceInfo2
|
cryptoDeviceInfo = cryptoDeviceInfo2,
|
||||||
)
|
)
|
||||||
val deviceInfo3 = givenADevicesInfo(
|
val deviceInfo3 = givenADevicesInfo(
|
||||||
deviceId = A_DEVICE_ID_3,
|
deviceId = A_DEVICE_ID_3,
|
||||||
lastSeenTs = A_TIMESTAMP_3,
|
lastSeenTs = A_TIMESTAMP_3,
|
||||||
isInactive = false,
|
isInactive = false,
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
||||||
cryptoDeviceInfo = cryptoDeviceInfo3
|
cryptoDeviceInfo = cryptoDeviceInfo3,
|
||||||
)
|
)
|
||||||
val deviceInfoList = listOf(deviceInfo1, deviceInfo2, deviceInfo3)
|
val deviceInfoList = listOf(deviceInfo1, deviceInfo2, deviceInfo3)
|
||||||
every { fakeFlowSession.liveMyDevicesInfo() } returns flowOf(deviceInfoList)
|
every { fakeFlowSession.liveMyDevicesInfo() } returns flowOf(deviceInfoList)
|
||||||
|
@ -110,21 +113,24 @@ class GetDeviceFullInfoListUseCaseTest {
|
||||||
cryptoDeviceInfo = cryptoDeviceInfo1,
|
cryptoDeviceInfo = cryptoDeviceInfo1,
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||||
isInactive = true,
|
isInactive = true,
|
||||||
isCurrentDevice = true
|
isCurrentDevice = true,
|
||||||
|
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
)
|
)
|
||||||
val expectedResult2 = DeviceFullInfo(
|
val expectedResult2 = DeviceFullInfo(
|
||||||
deviceInfo = deviceInfo2,
|
deviceInfo = deviceInfo2,
|
||||||
cryptoDeviceInfo = cryptoDeviceInfo2,
|
cryptoDeviceInfo = cryptoDeviceInfo2,
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||||
isInactive = false,
|
isInactive = false,
|
||||||
isCurrentDevice = false
|
isCurrentDevice = false,
|
||||||
|
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
)
|
)
|
||||||
val expectedResult3 = DeviceFullInfo(
|
val expectedResult3 = DeviceFullInfo(
|
||||||
deviceInfo = deviceInfo3,
|
deviceInfo = deviceInfo3,
|
||||||
cryptoDeviceInfo = cryptoDeviceInfo3,
|
cryptoDeviceInfo = cryptoDeviceInfo3,
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
||||||
isInactive = false,
|
isInactive = false,
|
||||||
isCurrentDevice = false
|
isCurrentDevice = false,
|
||||||
|
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
)
|
)
|
||||||
val expectedResult = listOf(expectedResult3, expectedResult2, expectedResult1)
|
val expectedResult = listOf(expectedResult3, expectedResult2, expectedResult1)
|
||||||
every { filterDevicesUseCase.execute(any(), any()) } returns expectedResult
|
every { filterDevicesUseCase.execute(any(), any()) } returns expectedResult
|
||||||
|
@ -186,8 +192,12 @@ class GetDeviceFullInfoListUseCaseTest {
|
||||||
val deviceInfo = mockk<DeviceInfo>()
|
val deviceInfo = mockk<DeviceInfo>()
|
||||||
every { deviceInfo.deviceId } returns deviceId
|
every { deviceInfo.deviceId } returns deviceId
|
||||||
every { deviceInfo.lastSeenTs } returns lastSeenTs
|
every { deviceInfo.lastSeenTs } returns lastSeenTs
|
||||||
|
every { deviceInfo.getBestLastSeenUserAgent() } returns ""
|
||||||
every { getEncryptionTrustLevelForDeviceUseCase.execute(any(), cryptoDeviceInfo) } returns roomEncryptionTrustLevel
|
every { getEncryptionTrustLevelForDeviceUseCase.execute(any(), cryptoDeviceInfo) } returns roomEncryptionTrustLevel
|
||||||
every { checkIfSessionIsInactiveUseCase.execute(lastSeenTs) } returns isInactive
|
every { checkIfSessionIsInactiveUseCase.execute(lastSeenTs) } returns isInactive
|
||||||
|
every { parseDeviceUserAgentUseCase.execute(any()) } returns DeviceExtendedInfo(
|
||||||
|
DeviceType.MOBILE,
|
||||||
|
)
|
||||||
|
|
||||||
return deviceInfo
|
return deviceInfo
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.app.features.settings.devices.v2
|
||||||
|
|
||||||
|
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||||
|
import org.amshove.kluent.shouldBeEqualTo
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
private val A_USER_AGENT_LIST_FOR_ANDROID = listOf(
|
||||||
|
// New User Agent Implementation
|
||||||
|
"Element dbg/1.5.0-dev (Xiaomi Mi 9T; Android 11; RKQ1.200826.002 test-keys; Flavour GooglePlay; MatrixAndroidSdk2 1.5.2)",
|
||||||
|
"Element/1.5.0 (Samsung SM-G960F; Android 6.0.1; RKQ1.200826.002; Flavour FDroid; MatrixAndroidSdk2 1.5.2)",
|
||||||
|
"Element/1.5.0 (Google Nexus 5; Android 7.0; RKQ1.200826.002 test test; Flavour FDroid; MatrixAndroidSdk2 1.5.2)",
|
||||||
|
"Element/1.5.0 (Google (Nexus) 5; Android 7.0; RKQ1.200826.002 test test; Flavour FDroid; MatrixAndroidSdk2 1.5.2)",
|
||||||
|
"Element/1.5.0 (Google (Nexus) (5); Android 7.0; RKQ1.200826.002 test test; Flavour FDroid; MatrixAndroidSdk2 1.5.2)",
|
||||||
|
// Legacy User Agent Implementation
|
||||||
|
"Element/1.0.0 (Linux; U; Android 6.0.1; SM-A510F Build/MMB29; Flavour GPlay; MatrixAndroidSdk2 1.0)",
|
||||||
|
"Element/1.0.0 (Linux; Android 7.0; SM-G610M Build/NRD90M; Flavour GPlay; MatrixAndroidSdk2 1.0)",
|
||||||
|
)
|
||||||
|
private val AN_EXPECTED_RESULT_LIST_FOR_ANDROID = listOf(
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "Xiaomi Mi 9T", "Android 11", "Element dbg", "1.5.0-dev"),
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "Samsung SM-G960F", "Android 6.0.1", "Element", "1.5.0"),
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "Google Nexus 5", "Android 7.0", "Element", "1.5.0"),
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "Google (Nexus) 5", "Android 7.0", "Element", "1.5.0"),
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "Google (Nexus) (5)", "Android 7.0", "Element", "1.5.0"),
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "SM-A510F Build/MMB29", "Android 6.0.1", "Element", "1.0.0"),
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "SM-G610M Build/NRD90M", "Android 7.0", "Element", "1.0.0"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val A_USER_AGENT_LIST_FOR_IOS = listOf(
|
||||||
|
"Element/1.8.21 (iPhone; iOS 15.2; Scale/3.00)",
|
||||||
|
"Element/1.8.21 (iPhone XS Max; iOS 15.2; Scale/3.00)",
|
||||||
|
"Element/1.8.21 (iPad Pro (11-inch); iOS 15.2; Scale/3.00)",
|
||||||
|
"Element/1.8.21 (iPad Pro (12.9-inch) (3rd generation); iOS 15.2; Scale/3.00)",
|
||||||
|
)
|
||||||
|
private val AN_EXPECTED_RESULT_LIST_FOR_IOS = listOf(
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "iPhone", "iOS 15.2", "Element", "1.8.21"),
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "iPhone XS Max", "iOS 15.2", "Element", "1.8.21"),
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "iPad Pro (11-inch)", "iOS 15.2", "Element", "1.8.21"),
|
||||||
|
DeviceExtendedInfo(DeviceType.MOBILE, "iPad Pro (12.9-inch) (3rd generation)", "iOS 15.2",
|
||||||
|
"Element", "1.8.21"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val A_USER_AGENT_LIST_FOR_DESKTOP = listOf(
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) ElementNightly/2022091301 Chrome/104.0.5112.102" +
|
||||||
|
" Electron/20.1.1 Safari/537.36",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) ElementNightly/2022091301 Chrome/104.0.5112.102 Electron/20.1.1 Safari/537.36",
|
||||||
|
)
|
||||||
|
private val AN_EXPECTED_RESULT_LIST_FOR_DESKTOP = listOf(
|
||||||
|
DeviceExtendedInfo(DeviceType.DESKTOP, null, "Macintosh", "Electron", "20"),
|
||||||
|
DeviceExtendedInfo(DeviceType.DESKTOP, null, "Windows NT 10.0", "Electron", "20"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val A_USER_AGENT_LIST_FOR_WEB = listOf(
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:39.0) Gecko/20100101 Firefox/39.0",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/600.3.18 (KHTML, like Gecko) Version/8.0.3 Safari/600.3.18",
|
||||||
|
"Mozilla/5.0 (Linux; Android 9; SM-G973U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||||
|
"Mozilla/5.0 (iPad; CPU OS 8_4_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H321 Safari/600.1.4",
|
||||||
|
"Mozilla/5.0 (iPhone; CPU iPhone OS 8_4_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H321 Safari/600.1.4",
|
||||||
|
"Mozilla/5.0 (Windows NT 6.0; rv:40.0) Gecko/20100101 Firefox/40.0",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246",
|
||||||
|
)
|
||||||
|
private val AN_EXPECTED_RESULT_LIST_FOR_WEB = listOf(
|
||||||
|
DeviceExtendedInfo(DeviceType.WEB, null, "Macintosh", "Chrome", "104"),
|
||||||
|
DeviceExtendedInfo(DeviceType.WEB, null, "Windows NT 10.0", "Chrome", "104"),
|
||||||
|
DeviceExtendedInfo(DeviceType.WEB, null, "Macintosh", "Firefox", "39"),
|
||||||
|
DeviceExtendedInfo(DeviceType.WEB, null, "Macintosh", "Safari", "8"),
|
||||||
|
DeviceExtendedInfo(DeviceType.WEB, null, "Android 9", "Chrome", "69"),
|
||||||
|
DeviceExtendedInfo(DeviceType.WEB, null, "iPad", "Safari", "8"),
|
||||||
|
DeviceExtendedInfo(DeviceType.WEB, null, "iPhone", "Safari", "8"),
|
||||||
|
DeviceExtendedInfo(DeviceType.WEB, null, "Windows NT 6.0", "Firefox", "40"),
|
||||||
|
DeviceExtendedInfo(DeviceType.WEB, null, "Windows NT 10.0", "Edge", "12"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val AN_UNKNOWN_USER_AGENT_LIST = listOf(
|
||||||
|
"AppleTV11,1/11.1",
|
||||||
|
"Curl Client/1.0",
|
||||||
|
)
|
||||||
|
private val AN_UNKNOWN_USER_AGENT_EXPECTED_RESULT_LIST = listOf(
|
||||||
|
DeviceExtendedInfo(DeviceType.UNKNOWN, null, null, null, null),
|
||||||
|
DeviceExtendedInfo(DeviceType.UNKNOWN, null, null, null, null),
|
||||||
|
)
|
||||||
|
|
||||||
|
class ParseDeviceUserAgentUseCaseTest {
|
||||||
|
|
||||||
|
private val parseDeviceUserAgentUseCase = ParseDeviceUserAgentUseCase()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given an Android user agent then it should be parsed as expected`() {
|
||||||
|
A_USER_AGENT_LIST_FOR_ANDROID.forEachIndexed { index, userAgent ->
|
||||||
|
parseDeviceUserAgentUseCase.execute(userAgent) shouldBeEqualTo AN_EXPECTED_RESULT_LIST_FOR_ANDROID[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given an iOS user agent then it should be parsed as expected`() {
|
||||||
|
A_USER_AGENT_LIST_FOR_IOS.forEachIndexed { index, userAgent ->
|
||||||
|
parseDeviceUserAgentUseCase.execute(userAgent) shouldBeEqualTo AN_EXPECTED_RESULT_LIST_FOR_IOS[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given a Desktop user agent then it should be parsed as expected`() {
|
||||||
|
A_USER_AGENT_LIST_FOR_DESKTOP.forEachIndexed { index, userAgent ->
|
||||||
|
parseDeviceUserAgentUseCase.execute(userAgent) shouldBeEqualTo AN_EXPECTED_RESULT_LIST_FOR_DESKTOP[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given a Web user agent then it should be parsed as expected`() {
|
||||||
|
A_USER_AGENT_LIST_FOR_WEB.forEachIndexed { index, userAgent ->
|
||||||
|
parseDeviceUserAgentUseCase.execute(userAgent) shouldBeEqualTo AN_EXPECTED_RESULT_LIST_FOR_WEB[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given an unknown user agent then it should be parsed as expected`() {
|
||||||
|
AN_UNKNOWN_USER_AGENT_LIST.forEachIndexed { index, userAgent ->
|
||||||
|
parseDeviceUserAgentUseCase.execute(userAgent) shouldBeEqualTo AN_UNKNOWN_USER_AGENT_EXPECTED_RESULT_LIST[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,9 @@
|
||||||
|
|
||||||
package im.vector.app.features.settings.devices.v2.filter
|
package im.vector.app.features.settings.devices.v2.filter
|
||||||
|
|
||||||
|
import im.vector.app.features.settings.devices.v2.DeviceExtendedInfo
|
||||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||||
|
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||||
import org.amshove.kluent.shouldBeEqualTo
|
import org.amshove.kluent.shouldBeEqualTo
|
||||||
import org.amshove.kluent.shouldContainAll
|
import org.amshove.kluent.shouldContainAll
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
@ -34,7 +36,8 @@ private val activeVerifiedDevice = DeviceFullInfo(
|
||||||
),
|
),
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||||
isInactive = false,
|
isInactive = false,
|
||||||
isCurrentDevice = true
|
isCurrentDevice = true,
|
||||||
|
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
)
|
)
|
||||||
private val inactiveVerifiedDevice = DeviceFullInfo(
|
private val inactiveVerifiedDevice = DeviceFullInfo(
|
||||||
deviceInfo = DeviceInfo(deviceId = "INACTIVE_VERIFIED_DEVICE"),
|
deviceInfo = DeviceInfo(deviceId = "INACTIVE_VERIFIED_DEVICE"),
|
||||||
|
@ -45,7 +48,8 @@ private val inactiveVerifiedDevice = DeviceFullInfo(
|
||||||
),
|
),
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||||
isInactive = true,
|
isInactive = true,
|
||||||
isCurrentDevice = false
|
isCurrentDevice = false,
|
||||||
|
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
)
|
)
|
||||||
private val activeUnverifiedDevice = DeviceFullInfo(
|
private val activeUnverifiedDevice = DeviceFullInfo(
|
||||||
deviceInfo = DeviceInfo(deviceId = "ACTIVE_UNVERIFIED_DEVICE"),
|
deviceInfo = DeviceInfo(deviceId = "ACTIVE_UNVERIFIED_DEVICE"),
|
||||||
|
@ -56,7 +60,8 @@ private val activeUnverifiedDevice = DeviceFullInfo(
|
||||||
),
|
),
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
||||||
isInactive = false,
|
isInactive = false,
|
||||||
isCurrentDevice = false
|
isCurrentDevice = false,
|
||||||
|
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
)
|
)
|
||||||
private val inactiveUnverifiedDevice = DeviceFullInfo(
|
private val inactiveUnverifiedDevice = DeviceFullInfo(
|
||||||
deviceInfo = DeviceInfo(deviceId = "INACTIVE_UNVERIFIED_DEVICE"),
|
deviceInfo = DeviceInfo(deviceId = "INACTIVE_UNVERIFIED_DEVICE"),
|
||||||
|
@ -67,7 +72,8 @@ private val inactiveUnverifiedDevice = DeviceFullInfo(
|
||||||
),
|
),
|
||||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
||||||
isInactive = true,
|
isInactive = true,
|
||||||
isCurrentDevice = false
|
isCurrentDevice = false,
|
||||||
|
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val devices = listOf(
|
private val devices = listOf(
|
||||||
|
|
|
@ -18,8 +18,11 @@ package im.vector.app.features.settings.devices.v2.overview
|
||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.asFlow
|
import androidx.lifecycle.asFlow
|
||||||
|
import im.vector.app.features.settings.devices.v2.DeviceExtendedInfo
|
||||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||||
|
import im.vector.app.features.settings.devices.v2.ParseDeviceUserAgentUseCase
|
||||||
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
||||||
|
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||||
import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
|
import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
|
||||||
import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase
|
import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase
|
||||||
import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase
|
import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase
|
||||||
|
@ -53,12 +56,14 @@ class GetDeviceFullInfoUseCaseTest {
|
||||||
private val getEncryptionTrustLevelForDeviceUseCase = mockk<GetEncryptionTrustLevelForDeviceUseCase>()
|
private val getEncryptionTrustLevelForDeviceUseCase = mockk<GetEncryptionTrustLevelForDeviceUseCase>()
|
||||||
private val checkIfSessionIsInactiveUseCase = mockk<CheckIfSessionIsInactiveUseCase>()
|
private val checkIfSessionIsInactiveUseCase = mockk<CheckIfSessionIsInactiveUseCase>()
|
||||||
private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions()
|
private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions()
|
||||||
|
private val parseDeviceUserAgentUseCase = mockk<ParseDeviceUserAgentUseCase>()
|
||||||
|
|
||||||
private val getDeviceFullInfoUseCase = GetDeviceFullInfoUseCase(
|
private val getDeviceFullInfoUseCase = GetDeviceFullInfoUseCase(
|
||||||
activeSessionHolder = fakeActiveSessionHolder.instance,
|
activeSessionHolder = fakeActiveSessionHolder.instance,
|
||||||
getCurrentSessionCrossSigningInfoUseCase = getCurrentSessionCrossSigningInfoUseCase,
|
getCurrentSessionCrossSigningInfoUseCase = getCurrentSessionCrossSigningInfoUseCase,
|
||||||
getEncryptionTrustLevelForDeviceUseCase = getEncryptionTrustLevelForDeviceUseCase,
|
getEncryptionTrustLevelForDeviceUseCase = getEncryptionTrustLevelForDeviceUseCase,
|
||||||
checkIfSessionIsInactiveUseCase = checkIfSessionIsInactiveUseCase,
|
checkIfSessionIsInactiveUseCase = checkIfSessionIsInactiveUseCase,
|
||||||
|
parseDeviceUserAgentUseCase = parseDeviceUserAgentUseCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -76,7 +81,7 @@ class GetDeviceFullInfoUseCaseTest {
|
||||||
// Given
|
// Given
|
||||||
val currentSessionCrossSigningInfo = givenCurrentSessionCrossSigningInfo()
|
val currentSessionCrossSigningInfo = givenCurrentSessionCrossSigningInfo()
|
||||||
val deviceInfo = DeviceInfo(
|
val deviceInfo = DeviceInfo(
|
||||||
lastSeenTs = A_TIMESTAMP
|
lastSeenTs = A_TIMESTAMP,
|
||||||
)
|
)
|
||||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData = MutableLiveData(Optional(deviceInfo))
|
fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData = MutableLiveData(Optional(deviceInfo))
|
||||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData.givenAsFlow()
|
fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData.givenAsFlow()
|
||||||
|
@ -87,6 +92,7 @@ class GetDeviceFullInfoUseCaseTest {
|
||||||
val isInactive = false
|
val isInactive = false
|
||||||
val isCurrentDevice = true
|
val isCurrentDevice = true
|
||||||
every { checkIfSessionIsInactiveUseCase.execute(any()) } returns isInactive
|
every { checkIfSessionIsInactiveUseCase.execute(any()) } returns isInactive
|
||||||
|
every { parseDeviceUserAgentUseCase.execute(any()) } returns DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
|
|
||||||
// When
|
// When
|
||||||
val deviceFullInfo = getDeviceFullInfoUseCase.execute(A_DEVICE_ID).firstOrNull()
|
val deviceFullInfo = getDeviceFullInfoUseCase.execute(A_DEVICE_ID).firstOrNull()
|
||||||
|
@ -97,7 +103,8 @@ class GetDeviceFullInfoUseCaseTest {
|
||||||
cryptoDeviceInfo = cryptoDeviceInfo,
|
cryptoDeviceInfo = cryptoDeviceInfo,
|
||||||
roomEncryptionTrustLevel = trustLevel,
|
roomEncryptionTrustLevel = trustLevel,
|
||||||
isInactive = isInactive,
|
isInactive = isInactive,
|
||||||
isCurrentDevice = isCurrentDevice
|
isCurrentDevice = isCurrentDevice,
|
||||||
|
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||||
)
|
)
|
||||||
verify { fakeActiveSessionHolder.instance.getSafeActiveSession() }
|
verify { fakeActiveSessionHolder.instance.getSafeActiveSession() }
|
||||||
verify { getCurrentSessionCrossSigningInfoUseCase.execute() }
|
verify { getCurrentSessionCrossSigningInfoUseCase.execute() }
|
||||||
|
|
Loading…
Reference in New Issue