mirror of
https://github.com/bitwarden/android.git
synced 2026-03-21 13:52:07 -05:00
PM-19645: Remove new device feature flags (#4950)
This commit is contained in:
@@ -1420,34 +1420,28 @@ class AuthRepositoryImpl(
|
||||
}
|
||||
|
||||
override fun checkUserNeedsNewDeviceTwoFactorNotice(): Boolean {
|
||||
return activeUserId?.let { userId ->
|
||||
val temporaryFlag = featureFlagManager.getFeatureFlag(FlagKey.NewDeviceTemporaryDismiss)
|
||||
val permanentFlag = featureFlagManager.getFeatureFlag(FlagKey.NewDevicePermanentDismiss)
|
||||
return activeUserId
|
||||
?.let { userId ->
|
||||
if (!newDeviceNoticePreConditionsValid()) {
|
||||
return false
|
||||
}
|
||||
|
||||
// check if feature flags are disabled
|
||||
if (!temporaryFlag && !permanentFlag) {
|
||||
return false
|
||||
val newDeviceNoticeState = authDiskSource.getNewDeviceNoticeState(userId = userId)
|
||||
return when (newDeviceNoticeState.displayStatus) {
|
||||
// if the user has already attested email access but permanent flag is enabled,
|
||||
// the notice needs to appear again
|
||||
NewDeviceNoticeDisplayStatus.CAN_ACCESS_EMAIL -> true
|
||||
// if the user has already seen but 7 days have already passed,
|
||||
// the notice needs to appear again
|
||||
NewDeviceNoticeDisplayStatus.HAS_SEEN -> {
|
||||
newDeviceNoticeState.shouldDisplayNoticeIfSeen
|
||||
}
|
||||
|
||||
NewDeviceNoticeDisplayStatus.HAS_NOT_SEEN -> true
|
||||
// the user never needs to see the notice again
|
||||
NewDeviceNoticeDisplayStatus.CAN_ACCESS_EMAIL_PERMANENT -> false
|
||||
}
|
||||
}
|
||||
|
||||
if (!newDeviceNoticePreConditionsValid()) {
|
||||
return false
|
||||
}
|
||||
|
||||
val newDeviceNoticeState = authDiskSource.getNewDeviceNoticeState(userId = userId)
|
||||
return when (newDeviceNoticeState.displayStatus) {
|
||||
// if the user has already attested email access but permanent flag is enabled,
|
||||
// the notice needs to appear again
|
||||
NewDeviceNoticeDisplayStatus.CAN_ACCESS_EMAIL -> permanentFlag
|
||||
// if the user has already seen but 7 days have already passed,
|
||||
// the notice needs to appear again
|
||||
NewDeviceNoticeDisplayStatus.HAS_SEEN ->
|
||||
newDeviceNoticeState.shouldDisplayNoticeIfSeen
|
||||
|
||||
NewDeviceNoticeDisplayStatus.HAS_NOT_SEEN -> true
|
||||
// the user never needs to see the notice again
|
||||
NewDeviceNoticeDisplayStatus.CAN_ACCESS_EMAIL_PERMANENT -> false
|
||||
}
|
||||
}
|
||||
?: false
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,6 @@ sealed class FlagKey<out T : Any> {
|
||||
CredentialExchangeProtocolImport,
|
||||
CredentialExchangeProtocolExport,
|
||||
AppReviewPrompt,
|
||||
NewDevicePermanentDismiss,
|
||||
NewDeviceTemporaryDismiss,
|
||||
IgnoreEnvironmentCheck,
|
||||
MutualTls,
|
||||
SingleTapPasskeyCreation,
|
||||
@@ -160,24 +158,6 @@ sealed class FlagKey<out T : Any> {
|
||||
override val isRemotelyConfigured: Boolean = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Data object holding the feature flag key for the New Device Temporary Dismiss feature.
|
||||
*/
|
||||
data object NewDeviceTemporaryDismiss : FlagKey<Boolean>() {
|
||||
override val keyName: String = "new-device-temporary-dismiss"
|
||||
override val defaultValue: Boolean = false
|
||||
override val isRemotelyConfigured: Boolean = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Data object holding the feature flag key for the New Device Permanent Dismiss feature.
|
||||
*/
|
||||
data object NewDevicePermanentDismiss : FlagKey<Boolean>() {
|
||||
override val keyName: String = "new-device-permanent-dismiss"
|
||||
override val defaultValue: Boolean = false
|
||||
override val isRemotelyConfigured: Boolean = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Data object holding the feature flag key to ignore an environment check.
|
||||
*/
|
||||
|
||||
@@ -3,12 +3,9 @@ package com.x8bit.bitwarden.ui.auth.feature.newdevicenotice
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeDisplayStatus.CAN_ACCESS_EMAIL
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeDisplayStatus.CAN_ACCESS_EMAIL_PERMANENT
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeState
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeEmailAccessAction.ContinueClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeEmailAccessAction.EmailAccessToggle
|
||||
@@ -30,7 +27,6 @@ private const val KEY_STATE = "state"
|
||||
class NewDeviceNoticeEmailAccessViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository,
|
||||
private val vaultRepository: VaultRepository,
|
||||
private val featureFlagManager: FeatureFlagManager,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : BaseViewModel<
|
||||
NewDeviceNoticeEmailAccessState,
|
||||
@@ -62,16 +58,9 @@ class NewDeviceNoticeEmailAccessViewModel @Inject constructor(
|
||||
|
||||
private fun handleContinueClick() {
|
||||
if (state.isEmailAccessEnabled) {
|
||||
val displayStatus =
|
||||
if (featureFlagManager.getFeatureFlag(FlagKey.NewDevicePermanentDismiss)) {
|
||||
CAN_ACCESS_EMAIL_PERMANENT
|
||||
} else {
|
||||
CAN_ACCESS_EMAIL
|
||||
}
|
||||
|
||||
authRepository.setNewDeviceNoticeState(
|
||||
NewDeviceNoticeState(
|
||||
displayStatus = displayStatus,
|
||||
displayStatus = CAN_ACCESS_EMAIL_PERMANENT,
|
||||
lastSeenDate = null,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -32,7 +32,6 @@ import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFac
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorAction.ContinueDialogClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorAction.DismissDialogClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorAction.NavigateBackClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorAction.RemindMeLaterClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorAction.TurnOnTwoFactorClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorEvent.NavigateBackToVault
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorEvent.NavigateToChangeAccountEmail
|
||||
@@ -124,10 +123,6 @@ fun NewDeviceNoticeTwoFactorScreen(
|
||||
onChangeAccountEmailClick = {
|
||||
viewModel.trySendAction(ChangeAccountEmailClick)
|
||||
},
|
||||
onRemindMeLaterClick = {
|
||||
viewModel.trySendAction(RemindMeLaterClick)
|
||||
},
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -139,8 +134,6 @@ fun NewDeviceNoticeTwoFactorScreen(
|
||||
private fun NewDeviceNoticeTwoFactorContent(
|
||||
onTurnOnTwoFactorClick: () -> Unit,
|
||||
onChangeAccountEmailClick: () -> Unit,
|
||||
onRemindMeLaterClick: () -> Unit,
|
||||
state: NewDeviceNoticeTwoFactorState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
@@ -156,8 +149,6 @@ private fun NewDeviceNoticeTwoFactorContent(
|
||||
MainContent(
|
||||
onTurnOnTwoFactorClick = onTurnOnTwoFactorClick,
|
||||
onChangeAccountEmailClick = onChangeAccountEmailClick,
|
||||
onRemindMeLaterClick = onRemindMeLaterClick,
|
||||
state = state,
|
||||
)
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
@@ -199,8 +190,6 @@ private fun ColumnScope.HeaderContent() {
|
||||
private fun ColumnScope.MainContent(
|
||||
onTurnOnTwoFactorClick: () -> Unit,
|
||||
onChangeAccountEmailClick: () -> Unit,
|
||||
onRemindMeLaterClick: () -> Unit,
|
||||
state: NewDeviceNoticeTwoFactorState,
|
||||
) {
|
||||
BitwardenFilledButton(
|
||||
label = stringResource(R.string.turn_on_two_step_login),
|
||||
@@ -217,15 +206,6 @@ private fun ColumnScope.MainContent(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
if (state.shouldShowRemindMeLater) {
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
BitwardenOutlinedButton(
|
||||
label = stringResource(R.string.remind_me_later),
|
||||
onClick = onRemindMeLaterClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewScreenSizes
|
||||
@@ -235,10 +215,6 @@ private fun NewDeviceNoticeTwoFactorScreen_preview() {
|
||||
NewDeviceNoticeTwoFactorContent(
|
||||
onTurnOnTwoFactorClick = {},
|
||||
onChangeAccountEmailClick = {},
|
||||
onRemindMeLaterClick = {},
|
||||
state = NewDeviceNoticeTwoFactorState(
|
||||
shouldShowRemindMeLater = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,7 @@ package com.x8bit.bitwarden.ui.auth.feature.newdevicenotice
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeDisplayStatus
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeState
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.baseWebVaultUrlOrDefault
|
||||
@@ -16,7 +12,6 @@ import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFac
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorAction.ContinueDialogClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorAction.DismissDialogClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorAction.NavigateBackClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorAction.RemindMeLaterClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorAction.TurnOnTwoFactorClick
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorDialogState.ChangeAccountEmailDialog
|
||||
import com.x8bit.bitwarden.ui.auth.feature.newdevicenotice.NewDeviceNoticeTwoFactorDialogState.TurnOnTwoFactorDialog
|
||||
@@ -27,8 +22,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.time.Clock
|
||||
import java.time.ZonedDateTime
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
@@ -38,19 +31,15 @@ import javax.inject.Inject
|
||||
class NewDeviceNoticeTwoFactorViewModel @Inject constructor(
|
||||
val authRepository: AuthRepository,
|
||||
val environmentRepository: EnvironmentRepository,
|
||||
val featureFlagManager: FeatureFlagManager,
|
||||
val settingsRepository: SettingsRepository,
|
||||
val vaultRepository: VaultRepository,
|
||||
private val clock: Clock,
|
||||
) : BaseViewModel<
|
||||
NewDeviceNoticeTwoFactorState,
|
||||
NewDeviceNoticeTwoFactorEvent,
|
||||
NewDeviceNoticeTwoFactorAction,
|
||||
>(
|
||||
initialState = NewDeviceNoticeTwoFactorState(
|
||||
shouldShowRemindMeLater = !featureFlagManager.getFeatureFlag(
|
||||
FlagKey.NewDevicePermanentDismiss,
|
||||
),
|
||||
dialogState = null,
|
||||
),
|
||||
) {
|
||||
init {
|
||||
@@ -86,8 +75,6 @@ class NewDeviceNoticeTwoFactorViewModel @Inject constructor(
|
||||
|
||||
TurnOnTwoFactorClick -> updateDialogState(newState = TurnOnTwoFactorDialog)
|
||||
|
||||
RemindMeLaterClick -> handleRemindMeLater()
|
||||
|
||||
DismissDialogClick -> updateDialogState(newState = null)
|
||||
|
||||
ContinueDialogClick -> handleContinueDialog()
|
||||
@@ -96,16 +83,6 @@ class NewDeviceNoticeTwoFactorViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRemindMeLater() {
|
||||
authRepository.setNewDeviceNoticeState(
|
||||
NewDeviceNoticeState(
|
||||
displayStatus = NewDeviceNoticeDisplayStatus.HAS_SEEN,
|
||||
lastSeenDate = ZonedDateTime.now(clock),
|
||||
),
|
||||
)
|
||||
sendEvent(NewDeviceNoticeTwoFactorEvent.NavigateBackToVault)
|
||||
}
|
||||
|
||||
private fun handleContinueDialog() {
|
||||
when (state.dialogState) {
|
||||
is ChangeAccountEmailDialog -> {
|
||||
@@ -178,11 +155,6 @@ sealed class NewDeviceNoticeTwoFactorAction {
|
||||
*/
|
||||
data object ChangeAccountEmailClick : NewDeviceNoticeTwoFactorAction()
|
||||
|
||||
/**
|
||||
* User tapped the remind me later button.
|
||||
*/
|
||||
data object RemindMeLaterClick : NewDeviceNoticeTwoFactorAction()
|
||||
|
||||
/**
|
||||
* User tapped the dismiss dialog button.
|
||||
*/
|
||||
@@ -204,8 +176,7 @@ sealed class NewDeviceNoticeTwoFactorAction {
|
||||
*/
|
||||
@Parcelize
|
||||
data class NewDeviceNoticeTwoFactorState(
|
||||
val dialogState: NewDeviceNoticeTwoFactorDialogState? = null,
|
||||
val shouldShowRemindMeLater: Boolean,
|
||||
val dialogState: NewDeviceNoticeTwoFactorDialogState?,
|
||||
) : Parcelable
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,8 +35,6 @@ fun <T : Any> FlagKey<T>.ListItemContent(
|
||||
FlagKey.CredentialExchangeProtocolExport,
|
||||
FlagKey.AppReviewPrompt,
|
||||
FlagKey.CipherKeyEncryption,
|
||||
FlagKey.NewDevicePermanentDismiss,
|
||||
FlagKey.NewDeviceTemporaryDismiss,
|
||||
FlagKey.IgnoreEnvironmentCheck,
|
||||
FlagKey.MutualTls,
|
||||
FlagKey.SingleTapPasskeyCreation,
|
||||
@@ -97,8 +95,6 @@ private fun <T : Any> FlagKey<T>.getDisplayLabel(): String = when (this) {
|
||||
FlagKey.CredentialExchangeProtocolExport -> stringResource(R.string.cxp_export)
|
||||
FlagKey.AppReviewPrompt -> stringResource(R.string.app_review_prompt)
|
||||
FlagKey.CipherKeyEncryption -> stringResource(R.string.cipher_key_encryption)
|
||||
FlagKey.NewDevicePermanentDismiss -> stringResource(R.string.new_device_permanent_dismiss)
|
||||
FlagKey.NewDeviceTemporaryDismiss -> stringResource(R.string.new_device_temporary_dismiss)
|
||||
FlagKey.IgnoreEnvironmentCheck -> stringResource(R.string.ignore_environment_check)
|
||||
FlagKey.MutualTls -> stringResource(R.string.mutual_tls)
|
||||
FlagKey.SingleTapPasskeyCreation -> stringResource(R.string.single_tap_passkey_creation)
|
||||
|
||||
@@ -966,7 +966,6 @@ Do you want to switch to this account?</string>
|
||||
<string name="your_passkey_will_be_saved_to_your_bitwarden_vault_for_x">Your passkey will be saved to your Bitwarden vault for %1$s</string>
|
||||
<string name="organization_unassigned_items_message_useu_description_long">Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</string>
|
||||
<string name="organization_unassigned_items_message_self_host_041624_description_long">On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</string>
|
||||
<string name="remind_me_later">Remind me later</string>
|
||||
<string name="notice">Notice</string>
|
||||
<string name="passkeys_not_supported_for_this_app">Passkeys not supported for this app</string>
|
||||
<string name="passkey_operation_failed_because_browser_is_not_privileged">Passkey operation failed because browser is not privileged</string>
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
<string name="restart_onboarding_carousel_details">This will force the change to app state which will cause the first time carousel to show. The carousel will continue to show for any \"new\" account until a login is completed. May need to exit debug menu manually.</string>
|
||||
<string name="app_review_prompt">App Review Prompt</string>
|
||||
<string name="cipher_key_encryption">Cipher Key Encryption</string>
|
||||
<string name="new_device_permanent_dismiss">New device notice permanent dismiss</string>
|
||||
<string name="new_device_temporary_dismiss">New device notice temporary dismiss</string>
|
||||
<string name="ignore_environment_check">Ignore environment check</string>">
|
||||
<string name="reset_coach_mark_tour_status">Reset all coach mark tours</string>
|
||||
<string name="anon_addy_self_hosted_aliases">AnonAddy self-hosted aliases</string>
|
||||
|
||||
@@ -253,8 +253,6 @@ class AuthRepositoryTest {
|
||||
}
|
||||
|
||||
private val featureFlagManager: FeatureFlagManager = mockk(relaxed = true) {
|
||||
every { getFeatureFlag(FlagKey.NewDeviceTemporaryDismiss) } returns true
|
||||
every { getFeatureFlag(FlagKey.NewDevicePermanentDismiss) } returns true
|
||||
every { getFeatureFlag(FlagKey.OnboardingFlow) } returns false
|
||||
every { getFeatureFlag(FlagKey.IgnoreEnvironmentCheck) } returns false
|
||||
}
|
||||
@@ -1580,7 +1578,6 @@ class AuthRepositoryTest {
|
||||
coVerify { identityService.preLogin(email = EMAIL) }
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `prelogin fails should return CertificateError when SSLHandshakeException is thrown`() =
|
||||
runTest {
|
||||
@@ -1753,7 +1750,6 @@ class AuthRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `login should return Error result when get token succeeds but unlock vault fails`() =
|
||||
runTest {
|
||||
val successResponse = GET_TOKEN_RESPONSE_SUCCESS
|
||||
@@ -5389,7 +5385,6 @@ class AuthRepositoryTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `getVerifiedOrganizationDomainSsoDetails Success should return Success`() = runTest {
|
||||
val email = "test@gmail.com"
|
||||
@@ -5408,6 +5403,7 @@ class AuthRepositoryTest {
|
||||
assertEquals(
|
||||
VerifiedOrganizationDomainSsoDetailsResult.Success(
|
||||
verifiedOrganizationDomainSsoDetails = listOf(
|
||||
@Suppress("MaxLineLength")
|
||||
VerifiedOrganizationDomainSsoDetailsResponse.VerifiedOrganizationDomainSsoDetail(
|
||||
organizationIdentifier = "Test Identifier",
|
||||
organizationName = "Bitwarden",
|
||||
@@ -6483,7 +6479,6 @@ class AuthRepositoryTest {
|
||||
assertNull(fakeAuthDiskSource.getOnboardingStatus(USER_ID_1))
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on successful login does not set onboarding status if feature flag is off`() =
|
||||
runTest {
|
||||
@@ -6675,28 +6670,6 @@ class AuthRepositoryTest {
|
||||
assertTrue(shouldShowNewDeviceNotice)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `checkUserNeedsNewDeviceTwoFactorNotice NewDeviceTemporaryDismiss and NewDevicePermanentDismiss flags are off returns false`() =
|
||||
runTest {
|
||||
every {
|
||||
featureFlagManager.getFeatureFlag(FlagKey.NewDevicePermanentDismiss)
|
||||
} returns false
|
||||
every {
|
||||
featureFlagManager.getFeatureFlag(FlagKey.NewDeviceTemporaryDismiss)
|
||||
} returns false
|
||||
every {
|
||||
policyManager.getActivePolicies(type = PolicyTypeJson.REQUIRE_SSO)
|
||||
} returns listOf()
|
||||
fakeEnvironmentRepository.environment = Environment.Us
|
||||
|
||||
fakeAuthDiskSource.userState = SINGLE_USER_STATE_1
|
||||
|
||||
val shouldShowNewDeviceNotice = repository.checkUserNeedsNewDeviceTwoFactorNotice()
|
||||
|
||||
assertFalse(shouldShowNewDeviceNotice)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `checkUserNeedsNewDeviceTwoFactorNotice IgnoreEnvironmentCheck flag enabled should not check for a cloud environment and return true`() =
|
||||
@@ -6719,7 +6692,6 @@ class AuthRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `checkUserNeedsNewDeviceTwoFactorNotice if environment is selfhosted return false`() =
|
||||
runTest {
|
||||
every {
|
||||
@@ -6890,7 +6862,7 @@ class AuthRepositoryTest {
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `checkUserNeedsNewDeviceTwoFactorNotice with NewDeviceNoticeDisplayStatus CAN_ACCESS_EMAIL return permanent flag value`() =
|
||||
fun `checkUserNeedsNewDeviceTwoFactorNotice with NewDeviceNoticeDisplayStatus CAN_ACCESS_EMAIL return true`() =
|
||||
runTest {
|
||||
every {
|
||||
policyManager.getActivePolicies(type = PolicyTypeJson.REQUIRE_SSO)
|
||||
@@ -6907,12 +6879,6 @@ class AuthRepositoryTest {
|
||||
)
|
||||
|
||||
assertTrue(repository.checkUserNeedsNewDeviceTwoFactorNotice())
|
||||
|
||||
every {
|
||||
featureFlagManager.getFeatureFlag(FlagKey.NewDevicePermanentDismiss)
|
||||
} returns false
|
||||
|
||||
assertFalse(repository.checkUserNeedsNewDeviceTwoFactorNotice())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -49,14 +49,6 @@ class FlagKeyTest {
|
||||
FlagKey.CipherKeyEncryption.keyName,
|
||||
"cipher-key-encryption",
|
||||
)
|
||||
assertEquals(
|
||||
FlagKey.NewDeviceTemporaryDismiss.keyName,
|
||||
"new-device-temporary-dismiss",
|
||||
)
|
||||
assertEquals(
|
||||
FlagKey.NewDevicePermanentDismiss.keyName,
|
||||
"new-device-permanent-dismiss",
|
||||
)
|
||||
assertEquals(
|
||||
FlagKey.SingleTapPasskeyCreation.keyName,
|
||||
"single-tap-passkey-creation",
|
||||
@@ -104,8 +96,6 @@ class FlagKeyTest {
|
||||
FlagKey.CredentialExchangeProtocolImport,
|
||||
FlagKey.CredentialExchangeProtocolExport,
|
||||
FlagKey.AppReviewPrompt,
|
||||
FlagKey.NewDeviceTemporaryDismiss,
|
||||
FlagKey.NewDevicePermanentDismiss,
|
||||
FlagKey.SingleTapPasskeyCreation,
|
||||
FlagKey.SingleTapPasskeyAuthentication,
|
||||
FlagKey.AnonAddySelfHostAlias,
|
||||
@@ -134,8 +124,6 @@ class FlagKeyTest {
|
||||
FlagKey.CredentialExchangeProtocolExport,
|
||||
FlagKey.AppReviewPrompt,
|
||||
FlagKey.CipherKeyEncryption,
|
||||
FlagKey.NewDeviceTemporaryDismiss,
|
||||
FlagKey.NewDevicePermanentDismiss,
|
||||
FlagKey.SingleTapPasskeyCreation,
|
||||
FlagKey.SingleTapPasskeyAuthentication,
|
||||
FlagKey.MutualTls,
|
||||
|
||||
@@ -5,8 +5,6 @@ import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeDisplayStatus
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeState
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import io.mockk.every
|
||||
@@ -28,11 +26,6 @@ class NewDeviceNoticeEmailAccessViewModelTest : BaseViewModelTest() {
|
||||
every { checkUserNeedsNewDeviceTwoFactorNotice() } returns true
|
||||
}
|
||||
|
||||
private val featureFlagManager = mockk<FeatureFlagManager>(relaxed = true) {
|
||||
every { getFeatureFlag(FlagKey.NewDevicePermanentDismiss) } returns true
|
||||
every { getFeatureFlag(FlagKey.NewDeviceTemporaryDismiss) } returns true
|
||||
}
|
||||
|
||||
private val vaultRepository = mockk<VaultRepository>(relaxed = true)
|
||||
|
||||
@Test
|
||||
@@ -97,33 +90,6 @@ class NewDeviceNoticeEmailAccessViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `ContinueClick should emit NavigateBackToVault if isEmailAccessEnabled and NewDevicePermanentDismiss flag is off`() =
|
||||
runTest {
|
||||
every {
|
||||
featureFlagManager.getFeatureFlag(FlagKey.NewDevicePermanentDismiss)
|
||||
} returns false
|
||||
|
||||
val viewModel = createViewModel()
|
||||
viewModel.trySendAction(NewDeviceNoticeEmailAccessAction.EmailAccessToggle(true))
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(NewDeviceNoticeEmailAccessAction.ContinueClick)
|
||||
assertEquals(
|
||||
NewDeviceNoticeEmailAccessEvent.NavigateBackToVault,
|
||||
awaitItem(),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
authRepository.setNewDeviceNoticeState(
|
||||
NewDeviceNoticeState(
|
||||
displayStatus = NewDeviceNoticeDisplayStatus.CAN_ACCESS_EMAIL,
|
||||
lastSeenDate = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ContinueClick should emit NavigateToTwoFactorOptions if isEmailAccessEnabled is false`() =
|
||||
runTest {
|
||||
@@ -138,14 +104,13 @@ class NewDeviceNoticeEmailAccessViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `LearnMoreClick should emit NavigateToLearnMore`() =
|
||||
runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(NewDeviceNoticeEmailAccessAction.LearnMoreClick)
|
||||
assertEquals(NewDeviceNoticeEmailAccessEvent.NavigateToLearnMore, awaitItem())
|
||||
}
|
||||
fun `LearnMoreClick should emit NavigateToLearnMore`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(NewDeviceNoticeEmailAccessAction.LearnMoreClick)
|
||||
assertEquals(NewDeviceNoticeEmailAccessEvent.NavigateToLearnMore, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createViewModel(
|
||||
savedStateHandle: SavedStateHandle = SavedStateHandle().also {
|
||||
@@ -153,7 +118,6 @@ class NewDeviceNoticeEmailAccessViewModelTest : BaseViewModelTest() {
|
||||
},
|
||||
): NewDeviceNoticeEmailAccessViewModel = NewDeviceNoticeEmailAccessViewModel(
|
||||
authRepository = authRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
vaultRepository = vaultRepository,
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
|
||||
@@ -94,19 +94,6 @@ class NewDeviceNoticeTwoFactorScreenTest : BaseComposeTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Remind me later click should send RemindMeLaterClick action`() {
|
||||
composeTestRule
|
||||
.onNodeWithText("Remind me later")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(
|
||||
NewDeviceNoticeTwoFactorAction.RemindMeLaterClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on NavigateToTurnOnTwoFactor should call launchUri on IntentManager`() {
|
||||
mutableEventFlow.tryEmit(
|
||||
@@ -144,22 +131,6 @@ class NewDeviceNoticeTwoFactorScreenTest : BaseComposeTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `remind me later button visibility should update according to state`() {
|
||||
composeTestRule
|
||||
.onNodeWithText("Remind me later")
|
||||
.performScrollTo()
|
||||
.assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(shouldShowRemindMeLater = false)
|
||||
}
|
||||
composeTestRule
|
||||
.onNodeWithText("Remind me later")
|
||||
.assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `turn on two factor dialog should be shown or hidden according to the state`() {
|
||||
composeTestRule.onNode(isDialog()).assertDoesNotExist()
|
||||
|
||||
@@ -175,9 +146,10 @@ class NewDeviceNoticeTwoFactorScreenTest : BaseComposeTest() {
|
||||
.onNodeWithText("Continue to web app", substring = true, ignoreCase = true)
|
||||
.assert(hasAnyAncestor(isDialog()))
|
||||
.assertIsDisplayed()
|
||||
@Suppress("MaxLineLength")
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
"Make your account more secure by setting up two-step login in the Bitwarden web app.",
|
||||
text = "Make your account more secure by setting up two-step login in the Bitwarden web app.",
|
||||
substring = true,
|
||||
ignoreCase = true,
|
||||
)
|
||||
@@ -251,6 +223,5 @@ class NewDeviceNoticeTwoFactorScreenTest : BaseComposeTest() {
|
||||
|
||||
private val DEFAULT_STATE =
|
||||
NewDeviceNoticeTwoFactorState(
|
||||
shouldShowRemindMeLater = true,
|
||||
dialogState = null,
|
||||
)
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
package com.x8bit.bitwarden.ui.auth.feature.newdevicenotice
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeDisplayStatus
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeState
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
@@ -18,10 +14,6 @@ import io.mockk.verify
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.ZoneOffset
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
class NewDeviceNoticeTwoFactorViewModelTest : BaseViewModelTest() {
|
||||
private val environmentRepository = FakeEnvironmentRepository()
|
||||
@@ -29,35 +21,18 @@ class NewDeviceNoticeTwoFactorViewModelTest : BaseViewModelTest() {
|
||||
every { checkUserNeedsNewDeviceTwoFactorNotice() } returns true
|
||||
}
|
||||
|
||||
private val featureFlagManager = mockk<FeatureFlagManager>(relaxed = true) {
|
||||
every { getFeatureFlag(FlagKey.NewDevicePermanentDismiss) } returns false
|
||||
every { getFeatureFlag(FlagKey.NewDeviceTemporaryDismiss) } returns true
|
||||
}
|
||||
|
||||
private val settingsRepository = mockk<SettingsRepository>(relaxed = true)
|
||||
|
||||
private val vaultRepository = mockk<VaultRepository>(relaxed = true)
|
||||
|
||||
@Test
|
||||
fun `initial state should be correct with NewDevicePermanentDismiss flag false`() = runTest {
|
||||
fun `initial state should be correct`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(DEFAULT_STATE, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `initial state should be correct with NewDevicePermanentDismiss flag true`() = runTest {
|
||||
every { featureFlagManager.getFeatureFlag(FlagKey.NewDevicePermanentDismiss) } returns true
|
||||
val viewModel = createViewModel()
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(shouldShowRemindMeLater = false),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Init should not send events if user needs new device notice`() = runTest {
|
||||
every { authRepository.checkUserNeedsNewDeviceTwoFactorNotice() } returns true
|
||||
@@ -126,26 +101,6 @@ class NewDeviceNoticeTwoFactorViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `RemindMeLaterClick should emit NavigateBackToVault`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(NewDeviceNoticeTwoFactorAction.RemindMeLaterClick)
|
||||
assertEquals(
|
||||
NewDeviceNoticeTwoFactorEvent.NavigateBackToVault,
|
||||
awaitItem(),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
authRepository.setNewDeviceNoticeState(
|
||||
NewDeviceNoticeState(
|
||||
displayStatus = NewDeviceNoticeDisplayStatus.HAS_SEEN,
|
||||
lastSeenDate = ZonedDateTime.now(FIXED_CLOCK),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `NavigateBackClick should send NavigateBack event`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
@@ -207,7 +162,6 @@ class NewDeviceNoticeTwoFactorViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `ContinueDialogClick should return if dialog state is null`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
@@ -223,20 +177,12 @@ class NewDeviceNoticeTwoFactorViewModelTest : BaseViewModelTest() {
|
||||
NewDeviceNoticeTwoFactorViewModel(
|
||||
authRepository = authRepository,
|
||||
environmentRepository = environmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
settingsRepository = settingsRepository,
|
||||
vaultRepository = vaultRepository,
|
||||
clock = FIXED_CLOCK,
|
||||
)
|
||||
}
|
||||
|
||||
private val DEFAULT_STATE =
|
||||
NewDeviceNoticeTwoFactorState(
|
||||
shouldShowRemindMeLater = true,
|
||||
dialogState = null,
|
||||
)
|
||||
|
||||
private val FIXED_CLOCK: Clock = Clock.fixed(
|
||||
Instant.parse("2023-10-27T12:00:00Z"),
|
||||
ZoneOffset.UTC,
|
||||
)
|
||||
|
||||
@@ -129,8 +129,6 @@ private val DEFAULT_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf
|
||||
FlagKey.CredentialExchangeProtocolImport to true,
|
||||
FlagKey.CredentialExchangeProtocolExport to true,
|
||||
FlagKey.AppReviewPrompt to true,
|
||||
FlagKey.NewDeviceTemporaryDismiss to true,
|
||||
FlagKey.NewDevicePermanentDismiss to true,
|
||||
FlagKey.IgnoreEnvironmentCheck to true,
|
||||
FlagKey.MutualTls to true,
|
||||
FlagKey.SingleTapPasskeyCreation to true,
|
||||
@@ -152,8 +150,6 @@ private val UPDATED_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf
|
||||
FlagKey.CredentialExchangeProtocolImport to false,
|
||||
FlagKey.CredentialExchangeProtocolExport to false,
|
||||
FlagKey.AppReviewPrompt to false,
|
||||
FlagKey.NewDeviceTemporaryDismiss to false,
|
||||
FlagKey.NewDevicePermanentDismiss to false,
|
||||
FlagKey.IgnoreEnvironmentCheck to false,
|
||||
FlagKey.MutualTls to false,
|
||||
FlagKey.SingleTapPasskeyCreation to false,
|
||||
|
||||
Reference in New Issue
Block a user