mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-26 11:26:01 +03:00
Render security recommendations.
This commit is contained in:
parent
c23a4e4601
commit
58846038ce
5 changed files with 53 additions and 1 deletions
|
@ -30,10 +30,13 @@ import im.vector.app.R
|
|||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.DateProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.resources.toTimestamp
|
||||
import im.vector.app.core.utils.PublishDataSource
|
||||
import im.vector.app.features.auth.ReAuthActivity
|
||||
import im.vector.app.features.login.ReAuthHelper
|
||||
import im.vector.app.features.settings.devices.v2.list.SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS
|
||||
import im.vector.lib.core.utils.flow.throttleFirst
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
@ -52,6 +55,7 @@ import org.matrix.android.sdk.api.auth.UserPasswordAuth
|
|||
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
||||
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||
import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
|
||||
|
@ -67,6 +71,7 @@ import org.matrix.android.sdk.api.util.awaitCallback
|
|||
import org.matrix.android.sdk.api.util.fromBase64
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
|
@ -81,6 +86,8 @@ data class DevicesViewState(
|
|||
val request: Async<Unit> = Uninitialized,
|
||||
val hasAccountCrossSigning: Boolean = false,
|
||||
val accountCrossSigningIsTrusted: Boolean = false,
|
||||
val unverifiedSessionsCount: Int = 0,
|
||||
val inactiveSessionsCount: Int = 0,
|
||||
) : MavericksState
|
||||
|
||||
data class DeviceFullInfo(
|
||||
|
@ -125,6 +132,14 @@ class DevicesViewModel @AssistedInject constructor(
|
|||
session.flow().liveUserCryptoDevices(session.myUserId),
|
||||
session.flow().liveMyDevicesInfo()
|
||||
) { cryptoList, infoList ->
|
||||
val unverifiedSessionsCount = cryptoList.count { !it.trustLevel?.isVerified().orFalse() }
|
||||
val inactiveSessionsCount = infoList.count { isInactiveSession(it.date) }
|
||||
setState {
|
||||
copy(
|
||||
unverifiedSessionsCount = unverifiedSessionsCount,
|
||||
inactiveSessionsCount = inactiveSessionsCount
|
||||
)
|
||||
}
|
||||
infoList
|
||||
.sortedByDescending { it.lastSeenTs }
|
||||
.map { deviceInfo ->
|
||||
|
@ -188,6 +203,14 @@ class DevicesViewModel @AssistedInject constructor(
|
|||
queryRefreshDevicesList()
|
||||
}
|
||||
|
||||
private fun isInactiveSession(lastSeenTs: Long): Boolean {
|
||||
val lastSeenDate = DateProvider.toLocalDateTime(lastSeenTs)
|
||||
val currentDate = DateProvider.currentLocalDateTime()
|
||||
val diffMilliseconds = currentDate.toTimestamp() - lastSeenDate.toTimestamp()
|
||||
val diffDays = TimeUnit.MILLISECONDS.toDays(diffMilliseconds)
|
||||
return diffDays > SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
session.cryptoService().verificationService().removeListener(this)
|
||||
super.onCleared()
|
||||
|
|
|
@ -131,9 +131,11 @@ class VectorSettingsDevicesFragment :
|
|||
}
|
||||
val otherDevices = devices?.filter { it.deviceInfo.deviceId != state.myDeviceId }
|
||||
|
||||
renderSecurityRecommendations(state.inactiveSessionsCount, state.unverifiedSessionsCount)
|
||||
renderCurrentDevice(currentDeviceInfo)
|
||||
renderOtherSessionsView(otherDevices)
|
||||
} else {
|
||||
hideSecurityRecommendations()
|
||||
hideCurrentSessionView()
|
||||
hideOtherSessionsView()
|
||||
}
|
||||
|
@ -141,6 +143,26 @@ class VectorSettingsDevicesFragment :
|
|||
handleRequestStatus(state.request)
|
||||
}
|
||||
|
||||
private fun renderSecurityRecommendations(inactiveSessionsCount: Int, unverifiedSessionsCount: Int) {
|
||||
if (unverifiedSessionsCount == 0 && inactiveSessionsCount == 0) {
|
||||
hideSecurityRecommendations()
|
||||
} else {
|
||||
views.deviceListHeaderSectionSecurityRecommendations.isVisible = true
|
||||
views.deviceListSecurityRecommendationsDivider.isVisible = true
|
||||
views.deviceListUnverifiedSessionsRecommendation.isVisible = unverifiedSessionsCount > 0
|
||||
views.deviceListInactiveSessionsRecommendation.isVisible = inactiveSessionsCount > 0
|
||||
views.deviceListUnverifiedSessionsRecommendation.setCount(unverifiedSessionsCount)
|
||||
views.deviceListInactiveSessionsRecommendation.setCount(inactiveSessionsCount)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideSecurityRecommendations() {
|
||||
views.deviceListHeaderSectionSecurityRecommendations.isVisible = false
|
||||
views.deviceListUnverifiedSessionsRecommendation.isVisible = false
|
||||
views.deviceListInactiveSessionsRecommendation.isVisible = false
|
||||
views.deviceListSecurityRecommendationsDivider.isVisible = false
|
||||
}
|
||||
|
||||
private fun renderOtherSessionsView(otherDevices: List<DeviceFullInfo>?) {
|
||||
if (otherDevices.isNullOrEmpty()) {
|
||||
hideOtherSessionsView()
|
||||
|
@ -169,6 +191,7 @@ class VectorSettingsDevicesFragment :
|
|||
private fun hideCurrentSessionView() {
|
||||
views.deviceListHeaderCurrentSession.isVisible = false
|
||||
views.deviceListCurrentSession.isVisible = false
|
||||
views.deviceListCurrentSessionDivider.isVisible = false
|
||||
}
|
||||
|
||||
private fun handleRequestStatus(unIgnoreRequest: Async<Unit>) {
|
||||
|
|
|
@ -65,4 +65,8 @@ class SecurityRecommendationView @JvmOverloads constructor(
|
|||
views.recommendationShieldImageView.setImageResource(imageResource)
|
||||
views.recommendationShieldImageView.backgroundTintList = ColorStateList.valueOf(backgroundTint)
|
||||
}
|
||||
|
||||
fun setCount(sessionsCount: Int) {
|
||||
views.recommendationViewAllButton.text = context.getString(R.string.device_manager_other_sessions_view_all, sessionsCount)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,3 +17,4 @@
|
|||
package im.vector.app.features.settings.devices.v2.list
|
||||
|
||||
internal const val NUMBER_OF_OTHER_DEVICES_TO_RENDER = 5
|
||||
internal const val SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS = 90
|
||||
|
|
|
@ -32,10 +32,11 @@
|
|||
<TextView
|
||||
android:id="@+id/recommendationDescriptionTextView"
|
||||
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
app:layout_constraintStart_toStartOf="@id/recommendationTitleTextView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/recommendationTitleTextView"
|
||||
tools:text="@string/device_manager_unverified_sessions_description" />
|
||||
|
||||
|
|
Loading…
Reference in a new issue