PM-8953: Require 4 digits for pin entry (#4914)

This commit is contained in:
David Perez
2025-03-25 16:20:15 -05:00
committed by GitHub
parent 22376bfe4b
commit b4b4f753ca
4 changed files with 15 additions and 26 deletions

View File

@@ -38,6 +38,8 @@ import com.x8bit.bitwarden.ui.platform.components.model.CardStyle
import com.x8bit.bitwarden.ui.platform.components.util.maxDialogHeight import com.x8bit.bitwarden.ui.platform.components.util.maxDialogHeight
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
private const val MINIMUM_PIN_LENGTH: Int = 4
/** /**
* A dialog for setting a user's PIN. * A dialog for setting a user's PIN.
* *
@@ -138,6 +140,7 @@ fun PinInputDialog(
BitwardenFilledButton( BitwardenFilledButton(
label = stringResource(id = R.string.submit), label = stringResource(id = R.string.submit),
isEnabled = !isPinCreation || pin.length >= MINIMUM_PIN_LENGTH,
onClick = { onSubmitClick(pin) }, onClick = { onSubmitClick(pin) },
modifier = Modifier.testTag(tag = "AcceptAlertButton"), modifier = Modifier.testTag(tag = "AcceptAlertButton"),
) )

View File

@@ -480,7 +480,7 @@ Scanning will happen automatically.</string>
<string name="unlock">Unlock</string> <string name="unlock">Unlock</string>
<string name="unlock_vault">Unlock vault</string> <string name="unlock_vault">Unlock vault</string>
<string name="thirty_minutes">30 minutes</string> <string name="thirty_minutes">30 minutes</string>
<string name="set_pin_description">Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application.</string> <string name="set_pin_description">Your PIN must be at least 4 characters. Your PIN settings will be reset if you ever fully log out of the application.</string>
<string name="logged_in_as_on">Logged in as %1$s on %2$s.</string> <string name="logged_in_as_on">Logged in as %1$s on %2$s.</string>
<string name="vault_locked_master_password">Your vault is locked. Verify your master password to continue.</string> <string name="vault_locked_master_password">Your vault is locked. Verify your master password to continue.</string>
<string name="vault_locked_pin">Your vault is locked. Verify your PIN code to continue.</string> <string name="vault_locked_pin">Your vault is locked. Verify your PIN code to continue.</string>

View File

@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.auth.feature.accountsetup
import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.assertIsOff import androidx.compose.ui.test.assertIsOff
import androidx.compose.ui.test.assertIsOn import androidx.compose.ui.test.assertIsOn
import androidx.compose.ui.test.filterToOne import androidx.compose.ui.test.filterToOne
@@ -257,8 +258,8 @@ class SetupUnlockScreenTest : BaseComposeTest() {
.assertIsDisplayed() .assertIsDisplayed()
composeTestRule composeTestRule
.onAllNodesWithText( .onAllNodesWithText(
text = "Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if " + text = "Your PIN must be at least 4 characters. Your PIN settings will be reset " +
"you ever fully log out of the application.", "if you ever fully log out of the application.",
) )
.filterToOne(hasAnyAncestor(isDialog())) .filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed() .assertIsDisplayed()
@@ -306,9 +307,8 @@ class SetupUnlockScreenTest : BaseComposeTest() {
composeTestRule.assertNoDialogExists() composeTestRule.assertNoDialogExists()
} }
@Suppress("MaxLineLength")
@Test @Test
fun `PIN input dialog Submit click with empty pin should clear the dialog and send UnlockWithPinToggle Disabled`() { fun `PIN input dialog with empty pin should disable submit button`() {
mutableStateFlow.update { mutableStateFlow.update {
it.copy(isUnlockWithPinEnabled = false) it.copy(isUnlockWithPinEnabled = false)
} }
@@ -320,14 +320,7 @@ class SetupUnlockScreenTest : BaseComposeTest() {
composeTestRule composeTestRule
.onAllNodesWithText(text = "Submit") .onAllNodesWithText(text = "Submit")
.filterToOne(hasAnyAncestor(isDialog())) .filterToOne(hasAnyAncestor(isDialog()))
.performClick() .assertIsNotEnabled()
verify {
viewModel.trySendAction(
SetupUnlockAction.UnlockWithPinToggle(UnlockWithPinState.Disabled),
)
}
composeTestRule.assertNoDialogExists()
} }
@Suppress("MaxLineLength") @Suppress("MaxLineLength")

View File

@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity
import androidx.compose.ui.test.assert import androidx.compose.ui.test.assert
import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsFocused import androidx.compose.ui.test.assertIsFocused
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.assertIsOff import androidx.compose.ui.test.assertIsOff
import androidx.compose.ui.test.assertIsOn import androidx.compose.ui.test.assertIsOn
import androidx.compose.ui.test.filterToOne import androidx.compose.ui.test.filterToOne
@@ -352,8 +353,8 @@ class AccountSecurityScreenTest : BaseComposeTest() {
.assertIsDisplayed() .assertIsDisplayed()
composeTestRule composeTestRule
.onAllNodesWithText( .onAllNodesWithText(
"Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if " + text = "Your PIN must be at least 4 characters. Your PIN settings will be reset " +
"you ever fully log out of the application.", "if you ever fully log out of the application.",
) )
.filterToOne(hasAnyAncestor(isDialog())) .filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed() .assertIsDisplayed()
@@ -402,9 +403,8 @@ class AccountSecurityScreenTest : BaseComposeTest() {
composeTestRule.assertNoDialogExists() composeTestRule.assertNoDialogExists()
} }
@Suppress("MaxLineLength")
@Test @Test
fun `PIN input dialog Submit click with empty pin should clear the dialog and send UnlockWithPinToggle Disabled`() { fun `PIN input dialog with empty pin should disable the Submit button`() {
mutableStateFlow.update { mutableStateFlow.update {
it.copy(isUnlockWithPinEnabled = false) it.copy(isUnlockWithPinEnabled = false)
} }
@@ -414,16 +414,9 @@ class AccountSecurityScreenTest : BaseComposeTest() {
.performClick() .performClick()
composeTestRule composeTestRule
.onAllNodesWithText("Submit") .onAllNodesWithText(text = "Submit")
.filterToOne(hasAnyAncestor(isDialog())) .filterToOne(hasAnyAncestor(isDialog()))
.performClick() .assertIsNotEnabled()
verify {
viewModel.trySendAction(
AccountSecurityAction.UnlockWithPinToggle(UnlockWithPinState.Disabled),
)
}
composeTestRule.assertNoDialogExists()
} }
@Suppress("MaxLineLength") @Suppress("MaxLineLength")