BIT-1699 Fix initial pasword type not checking policy (#954)

This commit is contained in:
Oleg Semenenko 2024-02-05 14:32:50 -06:00 committed by Álison Fernandes
parent 23721858b8
commit 28f805418d
2 changed files with 51 additions and 6 deletions

View file

@ -57,7 +57,6 @@ import javax.inject.Inject
import kotlin.math.max import kotlin.math.max
private const val KEY_STATE = "state" 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. * ViewModel responsible for handling user interactions in the generator screen.
@ -100,7 +99,7 @@ class GeneratorViewModel @Inject constructor(
init { init {
stateFlow.onEach { savedStateHandle[KEY_STATE] = it }.launchIn(viewModelScope) stateFlow.onEach { savedStateHandle[KEY_STATE] = it }.launchIn(viewModelScope)
when (val selectedType = mutableStateFlow.value.selectedType) { when (val selectedType = mutableStateFlow.value.selectedType) {
is Passcode -> loadPasscodeOptions(selectedType) is Passcode -> loadPasscodeOptions(selectedType, usePolicyDefault = true)
is Username -> loadUsernameOptions(selectedType) is Username -> loadUsernameOptions(selectedType)
} }
} }
@ -248,14 +247,26 @@ class GeneratorViewModel @Inject constructor(
//region Generation Handlers //region Generation Handlers
@Suppress("CyclomaticComplexMethod") @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() val options = generatorRepository.getPasscodeGenerationOptions()
?: generatePasscodeDefaultOptions() ?: generatePasscodeDefaultOptions()
val policy = policyManager val policy = policyManager
.getActivePolicies<PolicyInformation.PasswordGenerator>() .getActivePolicies<PolicyInformation.PasswordGenerator>()
.toStrictestPolicy() .toStrictestPolicy()
when (selectedType.selectedType) { when (passwordType.selectedType) {
is Passphrase -> { is Passphrase -> {
val minNumWords = policy.minNumberWords ?: Passphrase.PASSPHRASE_MIN_NUMBER_OF_WORDS val minNumWords = policy.minNumberWords ?: Passphrase.PASSPHRASE_MIN_NUMBER_OF_WORDS
val passphrase = Passphrase( val passphrase = Passphrase(
@ -638,7 +649,10 @@ class GeneratorViewModel @Inject constructor(
private fun handleMainTypeOptionSelect(action: GeneratorAction.MainTypeOptionSelect) { private fun handleMainTypeOptionSelect(action: GeneratorAction.MainTypeOptionSelect) {
when (action.mainTypeOption) { when (action.mainTypeOption) {
GeneratorState.MainTypeOption.PASSWORD -> loadPasscodeOptions(Passcode()) GeneratorState.MainTypeOption.PASSWORD -> {
loadPasscodeOptions(Passcode(), usePolicyDefault = true)
}
GeneratorState.MainTypeOption.USERNAME -> loadUsernameOptions(Username()) GeneratorState.MainTypeOption.USERNAME -> loadUsernameOptions(Username())
} }
} }
@ -653,10 +667,12 @@ class GeneratorViewModel @Inject constructor(
when (action.passcodeTypeOption) { when (action.passcodeTypeOption) {
PasscodeTypeOption.PASSWORD -> loadPasscodeOptions( PasscodeTypeOption.PASSWORD -> loadPasscodeOptions(
selectedType = Passcode(selectedType = Password()), selectedType = Passcode(selectedType = Password()),
usePolicyDefault = false,
) )
PasscodeTypeOption.PASSPHRASE -> loadPasscodeOptions( PasscodeTypeOption.PASSPHRASE -> loadPasscodeOptions(
selectedType = Passcode(selectedType = Passphrase()), selectedType = Passcode(selectedType = Passphrase()),
usePolicyDefault = false,
) )
} }
} }
@ -2340,3 +2356,9 @@ private fun UsernameGenerationOptions.ForwardedEmailServiceType?.toServiceType(
else -> null else -> null
} }
} }
private fun String?.toSelectedType(): Passcode.PasscodeType =
when (this) {
PolicyInformation.PasswordGenerator.TYPE_PASSPHRASE -> Passphrase()
else -> Password()
}

View file

@ -5,10 +5,10 @@ import app.cash.turbine.test
import app.cash.turbine.turbineScope import app.cash.turbine.turbineScope
import com.x8bit.bitwarden.R import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.auth.repository.AuthRepository 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.auth.repository.model.UserState
import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager 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.platform.repository.model.Environment
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedCatchAllUsernameResult import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedCatchAllUsernameResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedForwardedServiceUsernameResult import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedForwardedServiceUsernameResult
@ -201,6 +201,8 @@ class GeneratorViewModelTest : BaseViewModelTest() {
@Test @Test
fun `RegenerateClick action for passphrase state updates generatedText and saves passphrase generation options on successful passphrase generation`() = fun `RegenerateClick action for passphrase state updates generatedText and saves passphrase generation options on successful passphrase generation`() =
runTest { runTest {
setupMockPassphraseTypePolicy()
val updatedGeneratedPassphrase = "updatedPassphrase" val updatedGeneratedPassphrase = "updatedPassphrase"
val viewModel = createViewModel(initialPassphraseState) val viewModel = createViewModel(initialPassphraseState)
@ -242,6 +244,8 @@ class GeneratorViewModelTest : BaseViewModelTest() {
@Test @Test
fun `RegenerateClick action for passphrase state sends ShowSnackbar event on passphrase generation failure`() = fun `RegenerateClick action for passphrase state sends ShowSnackbar event on passphrase generation failure`() =
runTest { runTest {
setupMockPassphraseTypePolicy()
val viewModel = createViewModel(initialPassphraseState) val viewModel = createViewModel(initialPassphraseState)
fakeGeneratorRepository.setMockGeneratePassphraseResult( fakeGeneratorRepository.setMockGeneratePassphraseResult(
@ -1035,6 +1039,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
@BeforeEach @BeforeEach
fun setup() { fun setup() {
setupMockPassphraseTypePolicy()
fakeGeneratorRepository.setMockGeneratePasswordResult( fakeGeneratorRepository.setMockGeneratePasswordResult(
GeneratedPasswordResult.Success("defaultPassphrase"), GeneratedPasswordResult.Success("defaultPassphrase"),
) )
@ -1900,6 +1905,24 @@ class GeneratorViewModelTest : BaseViewModelTest() {
savedStateHandle = SavedStateHandle().apply { set("state", state) }, 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 //endregion Helper Functions
} }