[PM-23278] Add dialog to input password to update KDF settings to minimums

This commit is contained in:
André Bispo committed 2025-09-11 16:37:29 +01:00
1 parent 6300d5d789
commit 98d03614f4
5 files changed
+118

No files matched your search

@@ -59,6 +59,7 @@ import com.bitwarden.ui.platform.manager.IntentManager
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenPlurals
import com.bitwarden.ui.platform.resource.BitwardenString
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenMasterPasswordDialog
import com.x8bit.bitwarden.ui.platform.composition.LocalAppReviewManager
import com.x8bit.bitwarden.ui.platform.composition.LocalExitManager
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
@@ -404,6 +405,7 @@ private fun VaultScreenScaffold(
}
}
@Suppress("LongMethod")
@Composable
private fun VaultDialogs(
dialogState: VaultState.DialogState?,
@@ -462,6 +464,19 @@ private fun VaultDialogs(
)
}
is VaultState.DialogState.VaultLoadKdfUpdateRequired -> {
BitwardenMasterPasswordDialog(
title = dialogState.title(),
message = dialogState.message(),
dismissButtonText = stringResource(BitwardenString.later),
onConfirmClick = {
vaultHandlers.onKdfUpdatePasswordRepromptSubmit(it)
},
onDismissRequest = vaultHandlers.dialogDismiss,
filledButtonStyle = true,
)
}
null -> Unit
}
}
@@ -1464,6 +1464,15 @@ data class VaultState(
val cipherCount: Int,
) : DialogState()
/**
* Represents a dialog indicating that the user needs to update their kdf settings.
*/
@Parcelize
data class VaultLoadKdfUpdateRequired(
val title: Text,
val message: Text,
) : DialogState()
/**
* Represents an error dialog with the given [title] and [message].
*/
@@ -47,6 +47,7 @@ data class VaultHandlers(
val dismissFlightRecorderSnackbar: () -> Unit,
val onShareCipherDecryptionErrorClick: (selectedCipherId: String) -> Unit,
val onShareAllCipherDecryptionErrorsClick: () -> Unit,
val onKdfUpdatePasswordRepromptSubmit: (password: String) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
@@ -139,6 +140,12 @@ data class VaultHandlers(
VaultAction.ShareAllCipherDecryptionErrorsClick,
)
},
onKdfUpdatePasswordRepromptSubmit =
{
viewModel.trySendAction(
VaultAction.KdfUpdatePasswordRepromptSubmit(it),
)
},
)
}
}
@@ -784,6 +784,90 @@ class VaultScreenTest : BitwardenComposeTest() {
}
}
@Test
fun `vault load KDF update required dialog should be shown or hidden according to the state`() {
val dialogTitle = "Master Password Update"
val dialogMessage = "Your master password does not meet the current security requirements."
composeTestRule.assertNoDialogExists()
composeTestRule
.onNodeWithText(dialogTitle)
.assertDoesNotExist()
composeTestRule
.onNodeWithText(dialogMessage)
.assertDoesNotExist()
mutableStateFlow.update {
it.copy(
dialog = VaultState.DialogState.VaultLoadKdfUpdateRequired(
title = dialogTitle.asText(),
message = dialogMessage.asText(),
),
)
}
composeTestRule
.onNodeWithText(dialogTitle)
.assertIsDisplayed()
composeTestRule
.onNodeWithText(dialogMessage)
.assertIsDisplayed()
}
@Suppress("MaxLineLength")
@Test
fun `confirm button click on the VaultLoadKdfUpdateRequired dialog should send KdfUpdatePasswordRepromptSubmit`() {
val dialogTitle = "Master Password Update"
val dialogMessage = "Your master password does not meet the current security requirements."
val testPassword = "test_password"
mutableStateFlow.update {
it.copy(
dialog = VaultState.DialogState.VaultLoadKdfUpdateRequired(
title = dialogTitle.asText(),
message = dialogMessage.asText(),
),
)
}
// Enter password in the input field
composeTestRule
.onNodeWithText("Master password")
.performTextInput(testPassword)
// Click confirm button
composeTestRule
.onNodeWithText("Submit")
.performClick()
verify {
viewModel.trySendAction(
VaultAction.KdfUpdatePasswordRepromptSubmit(testPassword),
)
}
}
@Test
fun `later button click on the VaultLoadKdfUpdateRequired dialog should send DialogDismiss`() {
val dialogTitle = "Master Password Update"
val dialogMessage = "Your master password does not meet the current security requirements."
val laterText = "Later"
mutableStateFlow.update {
it.copy(
dialog = VaultState.DialogState.VaultLoadKdfUpdateRequired(
title = dialogTitle.asText(),
message = dialogMessage.asText(),
),
)
}
composeTestRule
.onNodeWithText(laterText)
.performClick()
verify {
viewModel.trySendAction(VaultAction.DialogDismiss)
}
}
@Test
fun `syncing dialog should be displayed according to state`() {
composeTestRule.assertNoDialogExists()
+3
View File
@@ -1085,4 +1085,7 @@ Do you want to switch to this account?</string>
<string name="default_uri_match_detection_description_advanced_options">URI match detection controls how Bitwarden identifies autofill suggestions.\n<annotation emphasis="bold">Warning:</annotation> “Starts with” is an advanced option with increased risk of exposing credentials.</string>
<string name="advanced_option_with_increased_risk_of_exposing_credentials">“Starts with” is an advanced option with increased risk of exposing credentials.</string>
<string name="advanced_option_increased_risk_exposing_credentials_used_incorrectly">“Regular expression” is an advanced option with increased risk of exposing credentials if used incorrectly.</string>
<string name="later">Later</string>
<string name="update_your_encryption_settings">Update your encryption settings</string>
<string name="the_new_recommended_encryption_settings_will_improve_your_account_security_desc_long">The new recommended encryption settings will improve your account security. Enter your master password to update now.</string>
</resources>