From a3e705006739bd2d62ca6d347bb188806afc15e7 Mon Sep 17 00:00:00 2001 From: Oleg Semenenko <146032743+oleg-livefront@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:32:50 -0600 Subject: [PATCH] BIT-1699 Fix initial pasword type not checking policy (#954) --- .../feature/generator/GeneratorViewModel.kt | 32 ++++++++++++++++--- .../generator/GeneratorViewModelTest.kt | 25 ++++++++++++++- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModel.kt index f5e85c85cf..36bdceeec8 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModel.kt @@ -57,7 +57,6 @@ import javax.inject.Inject import kotlin.math.max private const val KEY_STATE = "state" -private const val KEY_GENERATOR_MODE = "key_generator_mode" /** * ViewModel responsible for handling user interactions in the generator screen. @@ -100,7 +99,7 @@ class GeneratorViewModel @Inject constructor( init { stateFlow.onEach { savedStateHandle[KEY_STATE] = it }.launchIn(viewModelScope) when (val selectedType = mutableStateFlow.value.selectedType) { - is Passcode -> loadPasscodeOptions(selectedType) + is Passcode -> loadPasscodeOptions(selectedType, usePolicyDefault = true) is Username -> loadUsernameOptions(selectedType) } } @@ -248,14 +247,26 @@ class GeneratorViewModel @Inject constructor( //region Generation Handlers @Suppress("CyclomaticComplexMethod") - private fun loadPasscodeOptions(selectedType: Passcode) { + private fun loadPasscodeOptions(selectedType: Passcode, usePolicyDefault: Boolean) { + val passwordType = if (usePolicyDefault) { + Passcode( + selectedType = generatorRepository + .getPasswordGeneratorPolicy() + ?.defaultType + ?.toSelectedType() + ?: Password(), + ) + } else { + selectedType + } + val options = generatorRepository.getPasscodeGenerationOptions() ?: generatePasscodeDefaultOptions() val policy = policyManager .getActivePolicies() .toStrictestPolicy() - when (selectedType.selectedType) { + when (passwordType.selectedType) { is Passphrase -> { val minNumWords = policy.minNumberWords ?: Passphrase.PASSPHRASE_MIN_NUMBER_OF_WORDS val passphrase = Passphrase( @@ -638,7 +649,10 @@ class GeneratorViewModel @Inject constructor( private fun handleMainTypeOptionSelect(action: GeneratorAction.MainTypeOptionSelect) { when (action.mainTypeOption) { - GeneratorState.MainTypeOption.PASSWORD -> loadPasscodeOptions(Passcode()) + GeneratorState.MainTypeOption.PASSWORD -> { + loadPasscodeOptions(Passcode(), usePolicyDefault = true) + } + GeneratorState.MainTypeOption.USERNAME -> loadUsernameOptions(Username()) } } @@ -653,10 +667,12 @@ class GeneratorViewModel @Inject constructor( when (action.passcodeTypeOption) { PasscodeTypeOption.PASSWORD -> loadPasscodeOptions( selectedType = Passcode(selectedType = Password()), + usePolicyDefault = false, ) PasscodeTypeOption.PASSPHRASE -> loadPasscodeOptions( selectedType = Passcode(selectedType = Passphrase()), + usePolicyDefault = false, ) } } @@ -2340,3 +2356,9 @@ private fun UsernameGenerationOptions.ForwardedEmailServiceType?.toServiceType( else -> null } } + +private fun String?.toSelectedType(): Passcode.PasscodeType = + when (this) { + PolicyInformation.PasswordGenerator.TYPE_PASSPHRASE -> Passphrase() + else -> Password() + } diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModelTest.kt index b07d71daa5..f25c7aa26d 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModelTest.kt @@ -5,10 +5,10 @@ import app.cash.turbine.test import app.cash.turbine.turbineScope 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.UserState import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager -import com.x8bit.bitwarden.data.platform.manager.util.getActivePolicies import com.x8bit.bitwarden.data.platform.repository.model.Environment import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedCatchAllUsernameResult import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedForwardedServiceUsernameResult @@ -201,6 +201,8 @@ class GeneratorViewModelTest : BaseViewModelTest() { @Test fun `RegenerateClick action for passphrase state updates generatedText and saves passphrase generation options on successful passphrase generation`() = runTest { + setupMockPassphraseTypePolicy() + val updatedGeneratedPassphrase = "updatedPassphrase" val viewModel = createViewModel(initialPassphraseState) @@ -242,6 +244,8 @@ class GeneratorViewModelTest : BaseViewModelTest() { @Test fun `RegenerateClick action for passphrase state sends ShowSnackbar event on passphrase generation failure`() = runTest { + setupMockPassphraseTypePolicy() + val viewModel = createViewModel(initialPassphraseState) fakeGeneratorRepository.setMockGeneratePassphraseResult( @@ -1035,6 +1039,7 @@ class GeneratorViewModelTest : BaseViewModelTest() { @BeforeEach fun setup() { + setupMockPassphraseTypePolicy() fakeGeneratorRepository.setMockGeneratePasswordResult( GeneratedPasswordResult.Success("defaultPassphrase"), ) @@ -1900,6 +1905,24 @@ class GeneratorViewModelTest : BaseViewModelTest() { savedStateHandle = SavedStateHandle().apply { set("state", state) }, ) + private fun setupMockPassphraseTypePolicy() { + fakeGeneratorRepository.setMockPasswordGeneratorPolicy( + PolicyInformation.PasswordGenerator( + defaultType = "passphrase", + minLength = null, + useUpper = false, + useLower = false, + useNumbers = false, + useSpecial = false, + minNumbers = null, + minSpecial = null, + minNumberWords = null, + capitalize = false, + includeNumber = false, + ), + ) + } + //endregion Helper Functions }