diff --git a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeScreen.kt b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeScreen.kt index b70c8540b..44bd89118 100644 --- a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeScreen.kt +++ b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeScreen.kt @@ -46,6 +46,9 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import me.proton.core.auth.presentation.compose.R +import me.proton.core.auth.presentation.compose.sso.PasswordFormError.PasswordTooCommon +import me.proton.core.auth.presentation.compose.sso.PasswordFormError.PasswordTooShort +import me.proton.core.auth.presentation.compose.sso.PasswordFormError.PasswordsDoNotMatch import me.proton.core.compose.component.ProtonPasswordOutlinedTextFieldWithError import me.proton.core.compose.component.ProtonSolidButton import me.proton.core.compose.component.appbar.ProtonTopAppBar @@ -97,8 +100,7 @@ public fun BackupPasswordChangeScreen( modifier = modifier, onCloseClicked = onCloseClicked, onContinueClicked = onContinueClicked, - isPasswordTooShort = state.isPasswordTooShort(), - arePasswordsNotMatching = state.arePasswordsNotMatching(), + formError = (state as? BackupPasswordChangeState.FormError)?.cause, isLoading = state is BackupPasswordChangeState.Loading ) } @@ -108,8 +110,7 @@ public fun BackupPasswordChangeScaffold( modifier: Modifier = Modifier, onCloseClicked: () -> Unit = {}, onContinueClicked: (BackupPasswordChangeAction.ChangePassword) -> Unit = {}, - isPasswordTooShort: Boolean = false, - arePasswordsNotMatching: Boolean = false, + formError: PasswordFormError? = null, isLoading: Boolean = false, ) { Scaffold( @@ -138,12 +139,16 @@ public fun BackupPasswordChangeScaffold( .padding(ProtonDimens.DefaultSpacing), ) { - val errorTooShort = stringResource(R.string.backup_password_setup_password_too_short) - val errorNotMatch = stringResource(R.string.backup_password_setup_password_not_matching) + val error = when (formError) { + null -> null + PasswordTooShort -> stringResource(R.string.backup_password_setup_password_too_short) + PasswordTooCommon -> stringResource(R.string.backup_password_setup_password_too_common) + PasswordsDoNotMatch -> stringResource(R.string.backup_password_setup_password_not_matching) + } BackupPasswordChangeForm( - backupPasswordError = errorTooShort.takeIf { isPasswordTooShort }, - backupPasswordRepeatedError = errorNotMatch.takeIf { arePasswordsNotMatching }, + backupPasswordError = error, + backupPasswordRepeatedError = error?.takeIf { formError is PasswordsDoNotMatch }, onContinueClicked = onContinueClicked, isLoading = isLoading, ) diff --git a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeState.kt b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeState.kt index 52fe09fd3..e2945f246 100644 --- a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeState.kt +++ b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeState.kt @@ -29,12 +29,3 @@ public sealed interface BackupPasswordChangeState { public data object Success : BackupPasswordChangeState } - -internal fun BackupPasswordChangeState.formErrorOrNull(): PasswordFormError? = - (this as? BackupPasswordChangeState.FormError)?.cause - -internal fun BackupPasswordChangeState.isPasswordTooShort(): Boolean = - formErrorOrNull() == PasswordFormError.PasswordTooShort - -internal fun BackupPasswordChangeState.arePasswordsNotMatching(): Boolean = - formErrorOrNull() == PasswordFormError.PasswordsDoNotMatch diff --git a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeViewModel.kt b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeViewModel.kt index d47b3a579..ce7abd6d8 100644 --- a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeViewModel.kt +++ b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordChangeViewModel.kt @@ -50,6 +50,7 @@ import me.proton.core.observability.domain.ObservabilityContext import me.proton.core.observability.domain.ObservabilityManager import me.proton.core.observability.domain.metrics.LoginSsoChangePasswordTotal import me.proton.core.presentation.utils.InputValidationResult +import me.proton.core.presentation.utils.InvalidPasswordProvider import me.proton.core.presentation.utils.ValidationType import me.proton.core.presentation.utils.onFailure import me.proton.core.presentation.utils.onSuccess @@ -62,10 +63,15 @@ import javax.inject.Inject public class BackupPasswordChangeViewModel @Inject constructor( savedStateHandle: SavedStateHandle, private val context: CryptoContext, + private val invalidPasswordProvider: InvalidPasswordProvider, private val changeBackupPassword: ChangeBackupPassword, override val observabilityManager: ObservabilityManager ) : ViewModel(), ObservabilityContext { + init { + viewModelScope.launch { invalidPasswordProvider.init() } + } + private val userId: UserId by lazy { savedStateHandle.getUserId() } private val mutableAction = MutableStateFlow(null) @@ -91,12 +97,20 @@ public class BackupPasswordChangeViewModel @Inject constructor( }.onSuccess { InputValidationResult( text = action.backupPassword, - validationType = ValidationType.PasswordMatch, - additionalText = action.repeatBackupPassword + validationType = ValidationType.InvalidPassword, + provider = invalidPasswordProvider ).onFailure { - emit(FormError(PasswordFormError.PasswordsDoNotMatch)) + emit(FormError(PasswordFormError.PasswordTooCommon)) }.onSuccess { - emitAll(onChangeBackupPassword(action.backupPassword)) + InputValidationResult( + text = action.backupPassword, + validationType = ValidationType.PasswordMatch, + additionalText = action.repeatBackupPassword + ).onFailure { + emit(FormError(PasswordFormError.PasswordsDoNotMatch)) + }.onSuccess { + emitAll(onChangeBackupPassword(action.backupPassword)) + } } } } diff --git a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupScreen.kt b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupScreen.kt index a70a7b2e7..2ca761d5c 100644 --- a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupScreen.kt +++ b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupScreen.kt @@ -55,6 +55,9 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.compose.AsyncImage import me.proton.core.auth.presentation.compose.R +import me.proton.core.auth.presentation.compose.sso.PasswordFormError.PasswordTooCommon +import me.proton.core.auth.presentation.compose.sso.PasswordFormError.PasswordTooShort +import me.proton.core.auth.presentation.compose.sso.PasswordFormError.PasswordsDoNotMatch import me.proton.core.compose.component.ProtonPasswordOutlinedTextFieldWithError import me.proton.core.compose.component.ProtonSolidButton import me.proton.core.compose.component.appbar.ProtonTopAppBar @@ -110,8 +113,7 @@ public fun BackupPasswordSetupScreen( organizationAdminEmail = state.data.organizationAdminEmail, organizationIcon = state.data.organizationIcon, organizationName = state.data.organizationName, - isPasswordTooShort = state.isPasswordTooShort(), - arePasswordsNotMatching = state.arePasswordsNotMatching(), + formError = (state as? BackupPasswordSetupState.FormError)?.cause, isLoading = state is BackupPasswordSetupState.Loading ) } @@ -124,8 +126,7 @@ public fun BackupPasswordSetupScaffold( organizationAdminEmail: String? = null, organizationIcon: Any? = null, organizationName: String? = null, - isPasswordTooShort: Boolean = false, - arePasswordsNotMatching: Boolean = false, + formError: PasswordFormError? = null, isLoading: Boolean = false, ) { Scaffold( @@ -163,12 +164,16 @@ public fun BackupPasswordSetupScaffold( color = LocalColors.current.separatorNorm ) - val errorTooShort = stringResource(R.string.backup_password_setup_password_too_short) - val errorNotMatch = stringResource(R.string.backup_password_setup_password_not_matching) + val error = when (formError) { + null -> null + PasswordTooShort -> stringResource(R.string.backup_password_setup_password_too_short) + PasswordTooCommon -> stringResource(R.string.backup_password_setup_password_too_common) + PasswordsDoNotMatch -> stringResource(R.string.backup_password_setup_password_not_matching) + } BackupPasswordSetupForm( - backupPasswordError = errorTooShort.takeIf { isPasswordTooShort }, - backupPasswordRepeatedError = errorNotMatch.takeIf { arePasswordsNotMatching }, + backupPasswordError = error, + backupPasswordRepeatedError = error?.takeIf { formError is PasswordsDoNotMatch }, onContinueClicked = onContinueClicked, isLoading = isLoading, modifier = Modifier @@ -289,7 +294,6 @@ private fun BackupPasswordSetupForm( @Preview @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Preview(device = Devices.TABLET) @Composable private fun BackupPasswordSetupScreenPreview() { ProtonTheme { @@ -303,3 +307,20 @@ private fun BackupPasswordSetupScreenPreview() { ) } } + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun BackupPasswordSetupScreenFormErrorPreview() { + ProtonTheme { + BackupPasswordSetupScreen( + state = BackupPasswordSetupState.FormError( + data = BackupPasswordSetupData( + organizationAdminEmail = "admin@company.test", + organizationName = "The Company", + ), + cause = PasswordsDoNotMatch + ) + ) + } +} diff --git a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupState.kt b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupState.kt index 9cc695478..920273ed4 100644 --- a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupState.kt +++ b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupState.kt @@ -43,12 +43,3 @@ public sealed class BackupPasswordSetupState( override val data: BackupPasswordSetupData ) : BackupPasswordSetupState(data) } - -internal fun BackupPasswordSetupState.formErrorOrNull(): PasswordFormError? = - (this as? BackupPasswordSetupState.FormError)?.cause - -internal fun BackupPasswordSetupState.isPasswordTooShort(): Boolean = - formErrorOrNull() == PasswordFormError.PasswordTooShort - -internal fun BackupPasswordSetupState.arePasswordsNotMatching(): Boolean = - formErrorOrNull() == PasswordFormError.PasswordsDoNotMatch diff --git a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupViewModel.kt b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupViewModel.kt index 815d5f134..4c5787126 100644 --- a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupViewModel.kt +++ b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupViewModel.kt @@ -56,11 +56,11 @@ import me.proton.core.observability.domain.metrics.LoginSsoLoadOrganizationTotal import me.proton.core.observability.domain.metrics.LoginSsoSetupPrimaryKeysTotal import me.proton.core.observability.domain.metrics.LoginSsoVerifyUnprivatizationTotal import me.proton.core.observability.domain.metrics.LoginSsoVerifyUnprivatizationTotal.VerifyStatus -import me.proton.core.observability.domain.metrics.LoginSsoVerifyUnprivatizationTotal.VerifyStatus.failure import me.proton.core.observability.domain.metrics.LoginSsoVerifyUnprivatizationTotal.VerifyStatus.failurePublicAddressKeysError import me.proton.core.observability.domain.metrics.LoginSsoVerifyUnprivatizationTotal.VerifyStatus.failureUnprivatizeStateError import me.proton.core.observability.domain.metrics.LoginSsoVerifyUnprivatizationTotal.VerifyStatus.failureVerificationError import me.proton.core.presentation.utils.InputValidationResult +import me.proton.core.presentation.utils.InvalidPasswordProvider import me.proton.core.presentation.utils.ValidationType import me.proton.core.presentation.utils.onFailure import me.proton.core.presentation.utils.onSuccess @@ -73,6 +73,7 @@ import javax.inject.Inject public class BackupPasswordSetupViewModel @Inject constructor( savedStateHandle: SavedStateHandle, private val context: CryptoContext, + private val invalidPasswordProvider: InvalidPasswordProvider, private val deviceSecretRepository: DeviceSecretRepository, private val verifyUnprivatization: VerifyUnprivatization, private val setupPrimaryKeys: SetupPrimaryKeys, @@ -80,6 +81,10 @@ public class BackupPasswordSetupViewModel @Inject constructor( override val observabilityManager: ObservabilityManager, ) : ViewModel(), ObservabilityContext { + init { + viewModelScope.launch { invalidPasswordProvider.init() } + } + private val userId: UserId by lazy { savedStateHandle.getUserId() } private val mutableAction = MutableStateFlow(Load()) @@ -155,14 +160,22 @@ public class BackupPasswordSetupViewModel @Inject constructor( }.onSuccess { InputValidationResult( text = action.backupPassword, - validationType = ValidationType.PasswordMatch, - additionalText = action.repeatBackupPassword + validationType = ValidationType.InvalidPassword, + provider = invalidPasswordProvider ).onFailure { - emit(FormError(state.value.data, PasswordFormError.PasswordsDoNotMatch)) + emit(FormError(state.value.data, PasswordFormError.PasswordTooCommon)) }.onSuccess { - when (val organizationPublicKey = state.value.data.organizationPublicKey) { - null -> emit(Error(state.value.data, null)) - else -> emitAll(onSetupPrimaryKeys(action.backupPassword, organizationPublicKey)) + InputValidationResult( + text = action.backupPassword, + validationType = ValidationType.PasswordMatch, + additionalText = action.repeatBackupPassword + ).onFailure { + emit(FormError(state.value.data, PasswordFormError.PasswordsDoNotMatch)) + }.onSuccess { + when (val organizationPublicKey = state.value.data.organizationPublicKey) { + null -> emit(Error(state.value.data, null)) + else -> emitAll(onSetupPrimaryKeys(action.backupPassword, organizationPublicKey)) + } } } } diff --git a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/PasswordFormError.kt b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/PasswordFormError.kt index bc4a52fa3..3811266c0 100644 --- a/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/PasswordFormError.kt +++ b/auth/presentation-compose/src/main/kotlin/me/proton/core/auth/presentation/compose/sso/PasswordFormError.kt @@ -2,5 +2,6 @@ package me.proton.core.auth.presentation.compose.sso public sealed interface PasswordFormError { public data object PasswordTooShort : PasswordFormError + public data object PasswordTooCommon : PasswordFormError public data object PasswordsDoNotMatch : PasswordFormError } diff --git a/auth/presentation-compose/src/main/res/values/strings.xml b/auth/presentation-compose/src/main/res/values/strings.xml index 6ee3aa9c6..6597fa09d 100644 --- a/auth/presentation-compose/src/main/res/values/strings.xml +++ b/auth/presentation-compose/src/main/res/values/strings.xml @@ -74,6 +74,8 @@ Repeat backup password Continue Password should be at least 8 characters long. + Password too common. Use a different password. + Passwords do not match. Set backup password diff --git a/auth/presentation-compose/src/test/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupScreenTest.kt b/auth/presentation-compose/src/test/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupScreenTest.kt index 4a84a329c..3aa2e09f4 100644 --- a/auth/presentation-compose/src/test/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupScreenTest.kt +++ b/auth/presentation-compose/src/test/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupScreenTest.kt @@ -80,6 +80,24 @@ class BackupPasswordSetupScreenTest { } } + @Test + fun `passwords too common`() { + paparazzi.snapshot { + ProtonTheme { + BackupPasswordSetupScreen( + state = FormError( + data = BackupPasswordSetupData( + organizationAdminEmail = "admin@example.test", + organizationIcon = null, + organizationName = "Example Organization", + ), + cause = PasswordFormError.PasswordTooCommon + ) + ) + } + } + } + @Test fun `passwords do not match`() { paparazzi.snapshot { diff --git a/auth/presentation-compose/src/test/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupViewModelTest.kt b/auth/presentation-compose/src/test/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupViewModelTest.kt index 7696e4a6a..32f9201a5 100644 --- a/auth/presentation-compose/src/test/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupViewModelTest.kt +++ b/auth/presentation-compose/src/test/kotlin/me/proton/core/auth/presentation/compose/sso/BackupPasswordSetupViewModelTest.kt @@ -21,6 +21,8 @@ package me.proton.core.auth.presentation.compose.sso import androidx.lifecycle.SavedStateHandle import app.cash.turbine.test import io.mockk.MockKAnnotations +import io.mockk.coEvery +import io.mockk.every import io.mockk.impl.annotations.MockK import me.proton.core.auth.domain.repository.DeviceSecretRepository import me.proton.core.auth.domain.usecase.SetupPrimaryKeys @@ -28,6 +30,7 @@ import me.proton.core.auth.domain.usecase.sso.VerifyUnprivatization import me.proton.core.auth.presentation.compose.DeviceSecretRoutes import me.proton.core.crypto.common.context.CryptoContext import me.proton.core.observability.domain.ObservabilityManager +import me.proton.core.presentation.utils.InvalidPasswordProvider import me.proton.core.test.kotlin.CoroutinesTest import me.proton.core.usersettings.domain.repository.OrganizationRepository import kotlin.test.BeforeTest @@ -39,6 +42,9 @@ class BackupPasswordSetupViewModelTest : CoroutinesTest by CoroutinesTest() { @MockK private lateinit var context: CryptoContext + @MockK + private lateinit var invalidPasswordProvider: InvalidPasswordProvider + @MockK private lateinit var observabilityManager: ObservabilityManager @@ -59,9 +65,14 @@ class BackupPasswordSetupViewModelTest : CoroutinesTest by CoroutinesTest() { @BeforeTest fun setUp() { MockKAnnotations.init(this) + + coEvery { invalidPasswordProvider.init() } returns Unit + every { invalidPasswordProvider.isPasswordCommon(any()) } returns false + tested = BackupPasswordSetupViewModel( savedStateHandle = SavedStateHandle(mapOf(DeviceSecretRoutes.Arg.KEY_USER_ID to "user-id")), context = context, + invalidPasswordProvider = invalidPasswordProvider, deviceSecretRepository = deviceSecretRepository, verifyUnprivatization = verifyUnprivatization, setupPrimaryKeys = setupPrimaryKeys, @@ -90,6 +101,28 @@ class BackupPasswordSetupViewModelTest : CoroutinesTest by CoroutinesTest() { } } + @Test + fun `password too common`() = coroutinesTest { + every { invalidPasswordProvider.isPasswordCommon(any()) } returns true + + tested.state.test { + assertEquals(BackupPasswordSetupState.Idle(BackupPasswordSetupData()), awaitItem()) + + // WHEN + tested.submit(BackupPasswordSetupAction.SetPassword("12345678", "12345678")).join() + + // THEN + assertEquals(BackupPasswordSetupState.Loading(BackupPasswordSetupData()), awaitItem()) + assertEquals( + expected = BackupPasswordSetupState.FormError( + data = BackupPasswordSetupData(), + cause = PasswordFormError.PasswordTooCommon + ), + actual = awaitItem() + ) + } + } + @Test fun `passwords not matching`() = coroutinesTest { tested.state.test { diff --git a/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordChangeScreenTest_passwords do not match.png b/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordChangeScreenTest_passwords do not match.png index d03f53b5f..c529d516b 100644 --- a/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordChangeScreenTest_passwords do not match.png +++ b/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordChangeScreenTest_passwords do not match.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e400d8764979a996f762ff8c2829e8a47f50ba0fb5aea5f5f1ab4f2174ae50ed -size 38018 +oid sha256:0c9d4ed4b884d93a155bc51dd76a2adeeafc9169331c0f67eb37fbe2012dd942 +size 40981 diff --git a/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordSetupScreenTest_passwords do not match.png b/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordSetupScreenTest_passwords do not match.png index 5f7eaa83e..21724de2e 100644 --- a/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordSetupScreenTest_passwords do not match.png +++ b/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordSetupScreenTest_passwords do not match.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:163b9f72151331bac4c16025ed05ed14b2af21dcbcfc2f04299742cbcd7dcb5f -size 39101 +oid sha256:6986e400d6a54a65afabacc21bb9e379411f6848d17962fde3d4e84da4397d43 +size 42090 diff --git a/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordSetupScreenTest_passwords too common.png b/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordSetupScreenTest_passwords too common.png new file mode 100644 index 000000000..872fbf42c --- /dev/null +++ b/auth/presentation-compose/src/test/snapshots/images/me.proton.core.auth.presentation.compose.sso_BackupPasswordSetupScreenTest_passwords too common.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d53cfb80b3fbaabb9f680d95075527ca38732d94ad1357b5b89cce366e6f898e +size 41287 diff --git a/presentation/src/main/kotlin/me/proton/core/presentation/utils/InvalidPasswordProvider.kt b/presentation/src/main/kotlin/me/proton/core/presentation/utils/InvalidPasswordProvider.kt index 2f5d5c738..2cb2451d3 100644 --- a/presentation/src/main/kotlin/me/proton/core/presentation/utils/InvalidPasswordProvider.kt +++ b/presentation/src/main/kotlin/me/proton/core/presentation/utils/InvalidPasswordProvider.kt @@ -19,10 +19,16 @@ package me.proton.core.presentation.utils import android.content.Context +import dagger.Reusable +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import javax.inject.Inject -class InvalidPasswordProvider(private val context: Context) { +@Reusable +class InvalidPasswordProvider @Inject constructor( + @ApplicationContext private val context: Context +) { private var commonPasswords: Set? = null