mirror of
https://github.com/bitwarden/android.git
synced 2026-06-05 12:16:32 -05:00
BIT-785: Vault timeout policy (#924)
This commit is contained in:
committed by
Álison Fernandes
parent
c7f063a306
commit
89dd552908
@@ -98,4 +98,16 @@ sealed class PolicyInformation {
|
||||
const val TYPE_PASSPHRASE: String = "passphrase"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a policy enforcing rules on the user's vault timeout settings.
|
||||
*/
|
||||
@Serializable
|
||||
data class VaultTimeout(
|
||||
@SerialName("minutes")
|
||||
val minutes: Int?,
|
||||
|
||||
@SerialName("action")
|
||||
val action: String?,
|
||||
) : PolicyInformation()
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.auth.repository.util
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation
|
||||
import com.x8bit.bitwarden.data.platform.util.decodeFromStringOrNull
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import kotlinx.serialization.json.Json
|
||||
@@ -29,10 +30,15 @@ val SyncResponseJson.Policy.policyInformation: PolicyInformation?
|
||||
get() = data?.toString()?.let {
|
||||
when (type) {
|
||||
PolicyTypeJson.MASTER_PASSWORD -> {
|
||||
Json.decodeFromString<PolicyInformation.MasterPassword>(it)
|
||||
Json.decodeFromStringOrNull<PolicyInformation.MasterPassword>(it)
|
||||
}
|
||||
|
||||
PolicyTypeJson.PASSWORD_GENERATOR -> {
|
||||
Json.decodeFromString<PolicyInformation.PasswordGenerator>(it)
|
||||
Json.decodeFromStringOrNull<PolicyInformation.PasswordGenerator>(it)
|
||||
}
|
||||
|
||||
PolicyTypeJson.MAXIMUM_VAULT_TIMEOUT -> {
|
||||
Json.decodeFromStringOrNull<PolicyInformation.VaultTimeout>(it)
|
||||
}
|
||||
|
||||
else -> null
|
||||
|
||||
@@ -3,16 +3,21 @@ package com.x8bit.bitwarden.data.platform.repository
|
||||
import android.view.autofill.AutofillManager
|
||||
import com.x8bit.bitwarden.BuildConfig
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserFingerprintResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.policyInformation
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillEnabledManager
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.BiometricsKeyResult
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.ClearClipboardFrequency
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
@@ -24,7 +29,9 @@ import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.Instant
|
||||
@@ -42,6 +49,7 @@ class SettingsRepositoryImpl(
|
||||
private val settingsDiskSource: SettingsDiskSource,
|
||||
private val vaultSdkSource: VaultSdkSource,
|
||||
private val biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||
private val policyManager: PolicyManager,
|
||||
private val dispatcherManager: DispatcherManager,
|
||||
) : SettingsRepository {
|
||||
private val activeUserId: String? get() = authDiskSource.userState?.activeUserId
|
||||
@@ -286,6 +294,13 @@ class SettingsRepositoryImpl(
|
||||
?: DEFAULT_IS_SCREEN_CAPTURE_ALLOWED,
|
||||
)
|
||||
|
||||
init {
|
||||
policyManager
|
||||
.getActivePoliciesFlow(type = PolicyTypeJson.MAXIMUM_VAULT_TIMEOUT)
|
||||
.onEach { updateVaultUnlockSettingsIfNecessary(it) }
|
||||
.launchIn(unconfinedScope)
|
||||
}
|
||||
|
||||
override fun disableAutofill() {
|
||||
autofillManager.disableAutofillServices()
|
||||
|
||||
@@ -451,6 +466,36 @@ class SettingsRepositoryImpl(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the parameters of the vault unlock policy against the user's
|
||||
* settings to determine whether to update the user's settings.
|
||||
*/
|
||||
private fun updateVaultUnlockSettingsIfNecessary(
|
||||
policies: List<SyncResponseJson.Policy>,
|
||||
) {
|
||||
// The vault timeout policy can only be implemented in organizations that have
|
||||
// the single organization policy, meaning that if this is enabled, the user is
|
||||
// only in one organization and hence there is only one result in the list.
|
||||
val vaultUnlockPolicy = policies
|
||||
.firstOrNull()
|
||||
?.policyInformation as? PolicyInformation.VaultTimeout
|
||||
?: return
|
||||
|
||||
// Adjust the user's timeout or method if necessary to meet the policy requirements.
|
||||
vaultUnlockPolicy.minutes?.let { maxMinutes ->
|
||||
if ((vaultTimeout.vaultTimeoutInMinutes ?: Int.MAX_VALUE) > maxMinutes) {
|
||||
vaultTimeout = VaultTimeout.Custom(maxMinutes)
|
||||
}
|
||||
}
|
||||
vaultUnlockPolicy.action?.let {
|
||||
vaultTimeoutAction = if (it == "lock") {
|
||||
VaultTimeoutAction.LOCK
|
||||
} else {
|
||||
VaultTimeoutAction.LOGOUT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,8 +5,8 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillEnabledManager
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.EnvironmentDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepositoryImpl
|
||||
@@ -44,12 +44,12 @@ object PlatformRepositoryModule {
|
||||
fun provideSettingsRepository(
|
||||
autofillManager: AutofillManager,
|
||||
autofillEnabledManager: AutofillEnabledManager,
|
||||
appForegroundManager: AppForegroundManager,
|
||||
authDiskSource: AuthDiskSource,
|
||||
settingsDiskSource: SettingsDiskSource,
|
||||
vaultSdkSource: VaultSdkSource,
|
||||
encryptionManager: BiometricsEncryptionManager,
|
||||
dispatcherManager: DispatcherManager,
|
||||
policyManager: PolicyManager,
|
||||
): SettingsRepository =
|
||||
SettingsRepositoryImpl(
|
||||
autofillManager = autofillManager,
|
||||
@@ -59,5 +59,6 @@ object PlatformRepositoryModule {
|
||||
vaultSdkSource = vaultSdkSource,
|
||||
biometricsEncryptionManager = encryptionManager,
|
||||
dispatcherManager = dispatcherManager,
|
||||
policyManager = policyManager,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -37,10 +37,14 @@ import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenExternalLinkRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenListHeaderText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenLogoutConfirmationDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenPolicyWarningText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenSelectionDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenSelectionRow
|
||||
@@ -60,6 +64,7 @@ import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialColors
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialTypography
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalPermissionsManager
|
||||
import com.x8bit.bitwarden.ui.platform.util.displayLabel
|
||||
import com.x8bit.bitwarden.ui.platform.util.minutes
|
||||
import com.x8bit.bitwarden.ui.platform.util.toFormattedPattern
|
||||
import java.time.LocalTime
|
||||
|
||||
@@ -210,7 +215,15 @@ fun AccountSecurityScreen(
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
SessionTimeoutPolicyRow(
|
||||
vaultTimeoutPolicyMinutes = state.vaultTimeoutPolicyMinutes,
|
||||
vaultTimeoutPolicyAction = state.vaultTimeoutPolicyAction,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
SessionTimeoutRow(
|
||||
vaultTimeoutPolicyMinutes = state.vaultTimeoutPolicyMinutes,
|
||||
selectedVaultTimeoutType = state.vaultTimeout.type,
|
||||
onVaultTimeoutTypeSelect = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AccountSecurityAction.VaultTimeoutTypeSelect(it)) }
|
||||
@@ -219,6 +232,7 @@ fun AccountSecurityScreen(
|
||||
)
|
||||
(state.vaultTimeout as? VaultTimeout.Custom)?.let { customTimeout ->
|
||||
SessionCustomTimeoutRow(
|
||||
vaultTimeoutPolicyMinutes = state.vaultTimeoutPolicyMinutes,
|
||||
customVaultTimeout = customTimeout,
|
||||
onCustomVaultTimeoutSelect = remember(viewModel) {
|
||||
{
|
||||
@@ -231,6 +245,7 @@ fun AccountSecurityScreen(
|
||||
)
|
||||
}
|
||||
SessionTimeoutActionRow(
|
||||
vaultTimeoutPolicyAction = state.vaultTimeoutPolicyAction,
|
||||
selectedVaultTimeoutAction = state.vaultTimeoutAction,
|
||||
onVaultTimeoutActionSelect = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AccountSecurityAction.VaultTimeoutActionSelect(it)) }
|
||||
@@ -468,9 +483,44 @@ private fun UnlockWithPinRow(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SessionTimeoutPolicyRow(
|
||||
vaultTimeoutPolicyMinutes: Int?,
|
||||
vaultTimeoutPolicyAction: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
// Show the policy warning if applicable.
|
||||
if (vaultTimeoutPolicyMinutes != null || !vaultTimeoutPolicyAction.isNullOrBlank()) {
|
||||
// Calculate the hours and minutes to show in the policy label.
|
||||
val hours = vaultTimeoutPolicyMinutes?.floorDiv(MINUTES_PER_HOUR)
|
||||
val minutes = vaultTimeoutPolicyMinutes?.mod(MINUTES_PER_HOUR)
|
||||
|
||||
// Get the localized version of the action.
|
||||
val action = if (vaultTimeoutPolicyAction == "lock") {
|
||||
R.string.lock.asText()
|
||||
} else {
|
||||
R.string.log_out.asText()
|
||||
}
|
||||
|
||||
val policyText = if (hours == null || minutes == null) {
|
||||
R.string.vault_timeout_action_policy_in_effect.asText(action)
|
||||
} else if (vaultTimeoutPolicyAction.isNullOrBlank()) {
|
||||
R.string.vault_timeout_policy_in_effect.asText(hours, minutes)
|
||||
} else {
|
||||
R.string.vault_timeout_policy_with_action_in_effect.asText(hours, minutes, action)
|
||||
}
|
||||
|
||||
BitwardenPolicyWarningText(
|
||||
text = policyText(),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun SessionTimeoutRow(
|
||||
vaultTimeoutPolicyMinutes: Int?,
|
||||
selectedVaultTimeoutType: VaultTimeout.Type,
|
||||
onVaultTimeoutTypeSelect: (VaultTimeout.Type) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
@@ -492,6 +542,10 @@ private fun SessionTimeoutRow(
|
||||
when {
|
||||
shouldShowSelectionDialog -> {
|
||||
val vaultTimeoutOptions = VaultTimeout.Type.entries
|
||||
.filter {
|
||||
it.minutes <= (vaultTimeoutPolicyMinutes ?: Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
BitwardenSelectionDialog(
|
||||
title = stringResource(id = R.string.session_timeout),
|
||||
onDismissRequest = { shouldShowSelectionDialog = false },
|
||||
@@ -535,11 +589,13 @@ private fun SessionTimeoutRow(
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun SessionCustomTimeoutRow(
|
||||
vaultTimeoutPolicyMinutes: Int?,
|
||||
customVaultTimeout: VaultTimeout.Custom,
|
||||
onCustomVaultTimeoutSelect: (VaultTimeout.Custom) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var shouldShowTimePickerDialog by rememberSaveable { mutableStateOf(false) }
|
||||
var shouldShowViolatesPoliciesDialog by remember { mutableStateOf(false) }
|
||||
val vaultTimeoutInMinutes = customVaultTimeout.vaultTimeoutInMinutes
|
||||
BitwardenTextRow(
|
||||
text = stringResource(id = R.string.custom),
|
||||
@@ -564,21 +620,49 @@ private fun SessionCustomTimeoutRow(
|
||||
initialMinute = vaultTimeoutInMinutes.mod(MINUTES_PER_HOUR),
|
||||
onTimeSelect = { hour, minute ->
|
||||
shouldShowTimePickerDialog = false
|
||||
onCustomVaultTimeoutSelect(
|
||||
VaultTimeout.Custom(
|
||||
vaultTimeoutInMinutes = hour * MINUTES_PER_HOUR + minute,
|
||||
),
|
||||
)
|
||||
|
||||
val totalMinutes = (hour * MINUTES_PER_HOUR) + minute
|
||||
if (vaultTimeoutPolicyMinutes != null &&
|
||||
totalMinutes > vaultTimeoutPolicyMinutes
|
||||
) {
|
||||
shouldShowViolatesPoliciesDialog = true
|
||||
} else {
|
||||
onCustomVaultTimeoutSelect(
|
||||
VaultTimeout.Custom(
|
||||
vaultTimeoutInMinutes = totalMinutes,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
onDismissRequest = { shouldShowTimePickerDialog = false },
|
||||
is24Hour = true,
|
||||
)
|
||||
}
|
||||
|
||||
if (shouldShowViolatesPoliciesDialog) {
|
||||
BitwardenBasicDialog(
|
||||
visibilityState = BasicDialogState.Shown(
|
||||
title = R.string.warning.asText(),
|
||||
message = R.string.vault_timeout_to_large.asText(),
|
||||
),
|
||||
onDismissRequest = {
|
||||
shouldShowViolatesPoliciesDialog = false
|
||||
vaultTimeoutPolicyMinutes?.let {
|
||||
onCustomVaultTimeoutSelect(
|
||||
VaultTimeout.Custom(
|
||||
vaultTimeoutInMinutes = it,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun SessionTimeoutActionRow(
|
||||
vaultTimeoutPolicyAction: String?,
|
||||
selectedVaultTimeoutAction: VaultTimeoutAction,
|
||||
onVaultTimeoutActionSelect: (VaultTimeoutAction) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
@@ -587,7 +671,11 @@ private fun SessionTimeoutActionRow(
|
||||
var shouldShowLogoutActionConfirmationDialog by rememberSaveable { mutableStateOf(false) }
|
||||
BitwardenTextRow(
|
||||
text = stringResource(id = R.string.session_timeout_action),
|
||||
onClick = { shouldShowSelectionDialog = true },
|
||||
onClick = {
|
||||
// The option is not selectable if there's a policy in place.
|
||||
if (vaultTimeoutPolicyAction != null) return@BitwardenTextRow
|
||||
shouldShowSelectionDialog = true
|
||||
},
|
||||
modifier = modifier,
|
||||
) {
|
||||
Text(
|
||||
|
||||
@@ -5,19 +5,24 @@ import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserFingerprintResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.policyInformation
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.BiometricsKeyResult
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.baseWebVaultUrlOrDefault
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -36,6 +41,7 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
private val vaultRepository: VaultRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val environmentRepository: EnvironmentRepository,
|
||||
private val policyManager: PolicyManager,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : BaseViewModel<AccountSecurityState, AccountSecurityEvent, AccountSecurityAction>(
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
@@ -47,6 +53,8 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
isUnlockWithPinEnabled = settingsRepository.isUnlockWithPinEnabled,
|
||||
vaultTimeout = settingsRepository.vaultTimeout,
|
||||
vaultTimeoutAction = settingsRepository.vaultTimeoutAction,
|
||||
vaultTimeoutPolicyMinutes = null,
|
||||
vaultTimeoutPolicyAction = null,
|
||||
),
|
||||
) {
|
||||
private val webSettingsUrl: String
|
||||
@@ -63,6 +71,18 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
.onEach { savedStateHandle[KEY_STATE] = it }
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
policyManager
|
||||
.getActivePoliciesFlow(type = PolicyTypeJson.MAXIMUM_VAULT_TIMEOUT)
|
||||
.map { policies ->
|
||||
AccountSecurityAction.Internal.PolicyUpdateReceive(
|
||||
vaultTimeoutPolicies = policies.mapNotNull {
|
||||
it.policyInformation as? PolicyInformation.VaultTimeout
|
||||
},
|
||||
)
|
||||
}
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
viewModelScope.launch {
|
||||
trySendAction(
|
||||
AccountSecurityAction.Internal.FingerprintResultReceive(
|
||||
@@ -268,6 +288,10 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
is AccountSecurityAction.Internal.FingerprintResultReceive -> {
|
||||
handleFingerprintResultReceived(action)
|
||||
}
|
||||
|
||||
is AccountSecurityAction.Internal.PolicyUpdateReceive -> {
|
||||
handlePolicyUpdateReceive(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,6 +332,20 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePolicyUpdateReceive(
|
||||
action: AccountSecurityAction.Internal.PolicyUpdateReceive,
|
||||
) {
|
||||
// The vault timeout policy can only be implemented in organizations that have
|
||||
// the single organization policy, meaning that if this is enabled, the user is
|
||||
// only in one organization and hence there is only one result in the list.
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
vaultTimeoutPolicyMinutes = action.vaultTimeoutPolicies?.firstOrNull()?.minutes,
|
||||
vaultTimeoutPolicyAction = action.vaultTimeoutPolicies?.firstOrNull()?.action,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,6 +360,8 @@ data class AccountSecurityState(
|
||||
val isUnlockWithPinEnabled: Boolean,
|
||||
val vaultTimeout: VaultTimeout,
|
||||
val vaultTimeoutAction: VaultTimeoutAction,
|
||||
val vaultTimeoutPolicyMinutes: Int?,
|
||||
val vaultTimeoutPolicyAction: String?,
|
||||
) : Parcelable
|
||||
|
||||
/**
|
||||
@@ -349,14 +389,6 @@ sealed class AccountSecurityDialog : Parcelable {
|
||||
) : AccountSecurityDialog()
|
||||
}
|
||||
|
||||
/**
|
||||
* A representation of the Session timeout action.
|
||||
*/
|
||||
enum class SessionTimeoutAction(val text: Text) {
|
||||
LOCK(text = R.string.lock.asText()),
|
||||
LOG_OUT(text = R.string.log_out.asText()),
|
||||
}
|
||||
|
||||
/**
|
||||
* Models events for the account security screen.
|
||||
*/
|
||||
@@ -569,5 +601,12 @@ sealed class AccountSecurityAction {
|
||||
data class FingerprintResultReceive(
|
||||
val fingerprintResult: UserFingerprintResult,
|
||||
) : Internal()
|
||||
|
||||
/**
|
||||
* A policy update has been received.
|
||||
*/
|
||||
data class PolicyUpdateReceive(
|
||||
val vaultTimeoutPolicies: List<PolicyInformation.VaultTimeout>?,
|
||||
) : Internal()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,3 +22,25 @@ val VaultTimeout.Type.displayLabel: Text
|
||||
VaultTimeout.Type.CUSTOM -> R.string.custom
|
||||
}
|
||||
.asText()
|
||||
|
||||
/**
|
||||
* The value in minutes for the given [VaultTimeout.Type], used as a comparison
|
||||
* against the maximum timeout allowed by the organization's policy.
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
val VaultTimeout.Type.minutes: Int
|
||||
get() = when (this) {
|
||||
VaultTimeout.Type.IMMEDIATELY -> 0
|
||||
VaultTimeout.Type.ONE_MINUTE -> 1
|
||||
VaultTimeout.Type.FIVE_MINUTES -> 5
|
||||
VaultTimeout.Type.FIFTEEN_MINUTES -> 15
|
||||
VaultTimeout.Type.THIRTY_MINUTES -> 30
|
||||
VaultTimeout.Type.ONE_HOUR -> 60
|
||||
VaultTimeout.Type.FOUR_HOURS -> 240
|
||||
|
||||
VaultTimeout.Type.ON_APP_RESTART,
|
||||
VaultTimeout.Type.NEVER,
|
||||
-> Int.MAX_VALUE
|
||||
|
||||
VaultTimeout.Type.CUSTOM -> 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user