From bb950c8c5926fe8fa39b23ae09be0b4dc51367e6 Mon Sep 17 00:00:00 2001 From: David Perez Date: Thu, 24 Jul 2025 08:33:32 -0500 Subject: [PATCH] PM-24089: Remove Mutual TLS feature flag (#5566) --- .../data/platform/manager/model/FlagKey.kt | 9 -- .../feature/environment/EnvironmentScreen.kt | 95 +++++++++---------- .../environment/EnvironmentViewModel.kt | 36 +------ .../components/FeatureFlagListItems.kt | 2 - app/src/main/res/values/strings.xml | 1 - .../data/platform/manager/FlagKeyTest.kt | 4 - .../environment/EnvironmentScreenTest.kt | 1 - .../environment/EnvironmentViewModelTest.kt | 10 -- .../debugmenu/DebugMenuViewModelTest.kt | 2 - 9 files changed, 48 insertions(+), 112 deletions(-) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/model/FlagKey.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/model/FlagKey.kt index 8c46696792..e3d9ecf981 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/model/FlagKey.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/model/FlagKey.kt @@ -25,7 +25,6 @@ sealed class FlagKey { ImportLoginsFlow, CredentialExchangeProtocolImport, CredentialExchangeProtocolExport, - MutualTls, SingleTapPasskeyCreation, SingleTapPasskeyAuthentication, AnonAddySelfHostAlias, @@ -80,14 +79,6 @@ sealed class FlagKey { override val defaultValue: Boolean = false } - /** - * Data object holding the feature flag key for the Mutual TLS feature. - */ - data object MutualTls : FlagKey() { - override val keyName: String = "mutual-tls" - override val defaultValue: Boolean = false - } - /** * Data object holding the feature flag key to enable single tap passkey creation. */ diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreen.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreen.kt index 7abbcfae75..48215d6adc 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreen.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreen.kt @@ -323,59 +323,58 @@ fun EnvironmentScreen( .standardHorizontalMargin(), ) - if (state.showMutualTlsOptions) { - Spacer(modifier = Modifier.height(height = 16.dp)) + Spacer(modifier = Modifier.height(height = 16.dp)) - BitwardenListHeaderText( - label = stringResource(id = R.string.client_certificate_mtls), - modifier = Modifier - .fillMaxWidth() - .standardHorizontalMargin() - .padding(horizontal = 16.dp), - ) - Spacer(modifier = Modifier.height(height = 8.dp)) + BitwardenListHeaderText( + label = stringResource(id = R.string.client_certificate_mtls), + modifier = Modifier + .fillMaxWidth() + .standardHorizontalMargin() + .padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(height = 8.dp)) - BitwardenTextField( - label = stringResource(id = R.string.certificate_alias), - value = state.keyAlias, - supportingText = stringResource( - id = R.string.certificate_used_for_client_authentication, - ), - onValueChange = {}, - readOnly = true, - cardStyle = CardStyle.Full, - textFieldTestTag = "KeyAliasEntry", - modifier = Modifier - .fillMaxWidth() - .focusProperties { canFocus = false } - .standardHorizontalMargin(), - ) - Spacer(modifier = Modifier.height(height = 16.dp)) + BitwardenTextField( + label = stringResource(id = R.string.certificate_alias), + value = state.keyAlias, + supportingText = stringResource( + id = R.string.certificate_used_for_client_authentication, + ), + onValueChange = {}, + readOnly = true, + cardStyle = CardStyle.Full, + textFieldTestTag = "KeyAliasEntry", + modifier = Modifier + .fillMaxWidth() + .focusProperties { canFocus = false } + .standardHorizontalMargin(), + ) + Spacer(modifier = Modifier.height(height = 16.dp)) - BitwardenFilledButton( - label = stringResource(id = R.string.import_certificate), - onClick = remember(viewModel) { - { viewModel.trySendAction(EnvironmentAction.ImportCertificateClick) } - }, - modifier = Modifier - .fillMaxWidth() - .standardHorizontalMargin() - .testTag("ImportCertificateButton"), - ) + BitwardenFilledButton( + label = stringResource(id = R.string.import_certificate), + onClick = remember(viewModel) { + { viewModel.trySendAction(EnvironmentAction.ImportCertificateClick) } + }, + modifier = Modifier + .fillMaxWidth() + .standardHorizontalMargin() + .testTag("ImportCertificateButton"), + ) - Spacer(modifier = Modifier.height(height = 12.dp)) + Spacer(modifier = Modifier.height(height = 12.dp)) + + BitwardenOutlinedButton( + label = stringResource(id = R.string.choose_system_certificate), + onClick = remember(viewModel) { + { viewModel.trySendAction(EnvironmentAction.ChooseSystemCertificateClick) } + }, + modifier = Modifier + .fillMaxWidth() + .standardHorizontalMargin() + .testTag("ChooseSystemCertificateButton"), + ) - BitwardenOutlinedButton( - label = stringResource(id = R.string.choose_system_certificate), - onClick = remember(viewModel) { - { viewModel.trySendAction(EnvironmentAction.ChooseSystemCertificateClick) } - }, - modifier = Modifier - .fillMaxWidth() - .standardHorizontalMargin() - .testTag("ChooseSystemCertificateButton"), - ) - } Spacer(modifier = Modifier.height(height = 16.dp)) Spacer(modifier = Modifier.navigationBarsPadding()) } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentViewModel.kt index 7f0abd89f3..94aba14aad 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentViewModel.kt @@ -16,8 +16,6 @@ import com.bitwarden.ui.util.asText import com.x8bit.bitwarden.R import com.x8bit.bitwarden.data.platform.datasource.disk.model.MutualTlsKeyHost import com.x8bit.bitwarden.data.platform.manager.CertificateManager -import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager -import com.x8bit.bitwarden.data.platform.manager.model.FlagKey import com.x8bit.bitwarden.data.platform.manager.model.ImportPrivateKeyResult import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository import com.x8bit.bitwarden.data.vault.manager.FileManager @@ -28,7 +26,6 @@ import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelay import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -46,7 +43,6 @@ class EnvironmentViewModel @Inject constructor( private val environmentRepository: EnvironmentRepository, private val fileManager: FileManager, private val certificateManager: CertificateManager, - private val featureFlagManager: FeatureFlagManager, private val snackbarRelayManager: SnackbarRelayManager, private val savedStateHandle: SavedStateHandle, ) : BaseViewModel( @@ -70,21 +66,13 @@ class EnvironmentViewModel @Inject constructor( keyAlias = keyAlias, keyHost = keyHost, dialog = null, - showMutualTlsOptions = featureFlagManager.getFeatureFlag(FlagKey.MutualTls), ) }, ) { init { stateFlow - .onEach { - savedStateHandle[KEY_STATE] = it - } - .launchIn(viewModelScope) - - featureFlagManager.getFeatureFlagFlow(FlagKey.MutualTls) - .map { EnvironmentAction.Internal.MutualTlsFeatureFlagUpdate(it) } - .onEach(::handleAction) + .onEach { savedStateHandle[KEY_STATE] = it } .launchIn(viewModelScope) } @@ -275,10 +263,6 @@ class EnvironmentViewModel @Inject constructor( is EnvironmentAction.Internal.ImportKeyResultReceive -> { handleSaveKeyResultReceive(action) } - - is EnvironmentAction.Internal.MutualTlsFeatureFlagUpdate -> { - handleMutualTlsFeatureFlagUpdate(action) - } } } @@ -361,16 +345,6 @@ class EnvironmentViewModel @Inject constructor( } } - private fun handleMutualTlsFeatureFlagUpdate( - action: EnvironmentAction.Internal.MutualTlsFeatureFlagUpdate, - ) { - mutableStateFlow.update { - it.copy( - showMutualTlsOptions = action.enabled, - ) - } - } - private fun handleChooseSystemCertificateClickAction() { mutableStateFlow.update { it.copy( @@ -472,7 +446,6 @@ data class EnvironmentState( val iconsServerUrl: String, val keyAlias: String, val dialog: DialogState?, - val showMutualTlsOptions: Boolean, // internal private val keyHost: MutualTlsKeyHost?, ) : Parcelable { @@ -692,12 +665,5 @@ sealed class EnvironmentAction { data class ImportKeyResultReceive( val result: ImportPrivateKeyResult, ) : Internal() - - /** - * Indicates the mutual TLS feature flag was updated. - */ - data class MutualTlsFeatureFlagUpdate( - val enabled: Boolean, - ) : Internal() } } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt index 73778a7cf9..be7ede34af 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt @@ -30,7 +30,6 @@ fun FlagKey.ListItemContent( FlagKey.CredentialExchangeProtocolImport, FlagKey.CredentialExchangeProtocolExport, FlagKey.CipherKeyEncryption, - FlagKey.MutualTls, FlagKey.SingleTapPasskeyCreation, FlagKey.SingleTapPasskeyAuthentication, FlagKey.AnonAddySelfHostAlias, @@ -85,7 +84,6 @@ private fun FlagKey.getDisplayLabel(): String = when (this) { FlagKey.CredentialExchangeProtocolImport -> stringResource(R.string.cxp_import) FlagKey.CredentialExchangeProtocolExport -> stringResource(R.string.cxp_export) FlagKey.CipherKeyEncryption -> stringResource(R.string.cipher_key_encryption) - FlagKey.MutualTls -> stringResource(R.string.mutual_tls) FlagKey.SingleTapPasskeyCreation -> stringResource(R.string.single_tap_passkey_creation) FlagKey.SingleTapPasskeyAuthentication -> { stringResource(R.string.single_tap_passkey_authentication) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 45590c89bc..146bcb2aa1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -865,7 +865,6 @@ Do you want to switch to this account? You’ll only need to set up Authenticator Key for logins that require two-factor authentication with a code. The key will continuously generate six-digit codes you can use to log in. 3 OF 3 You must add a web address to use autofill to access this account. - Mutual TLS Single tap passkey creation Single tap passkey sign-on Learn about new logins diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/FlagKeyTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/FlagKeyTest.kt index c11bb48b5b..cdb8803230 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/FlagKeyTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/FlagKeyTest.kt @@ -37,10 +37,6 @@ class FlagKeyTest { FlagKey.SingleTapPasskeyAuthentication.keyName, "single-tap-passkey-authentication", ) - assertEquals( - FlagKey.MutualTls.keyName, - "mutual-tls", - ) assertEquals( FlagKey.AnonAddySelfHostAlias.keyName, "anon-addy-self-host-alias", diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreenTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreenTest.kt index 4e241a4c60..4a9c4790cc 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreenTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreenTest.kt @@ -437,7 +437,6 @@ class EnvironmentScreenTest : BitwardenComposeTest() { iconsServerUrl = "", keyHost = null, dialog = null, - showMutualTlsOptions = true, ) } } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentViewModelTest.kt index bb84a72c5e..ea5d12f072 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentViewModelTest.kt @@ -11,8 +11,6 @@ import com.bitwarden.ui.util.asText import com.x8bit.bitwarden.R import com.x8bit.bitwarden.data.platform.datasource.disk.model.MutualTlsKeyHost import com.x8bit.bitwarden.data.platform.manager.CertificateManager -import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager -import com.x8bit.bitwarden.data.platform.manager.model.FlagKey import com.x8bit.bitwarden.data.platform.manager.model.ImportPrivateKeyResult import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository import com.x8bit.bitwarden.data.vault.manager.FileManager @@ -28,7 +26,6 @@ import io.mockk.just import io.mockk.mockk import io.mockk.runs import io.mockk.verify -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -37,11 +34,6 @@ import org.junit.jupiter.api.Test class EnvironmentViewModelTest : BaseViewModelTest() { private val fakeEnvironmentRepository = FakeEnvironmentRepository() - private val mutableMutualTlsFeatureFlagFlow = MutableStateFlow(true) - private val mockFeatureFlagManager = mockk { - every { getFeatureFlag(FlagKey.MutualTls) } returns true - every { getFeatureFlagFlow(FlagKey.MutualTls) } returns mutableMutualTlsFeatureFlagFlow - } private val mockCertificateManager = mockk { every { getMutualTlsKeyAliases() } returns emptyList() } @@ -814,7 +806,6 @@ class EnvironmentViewModelTest : BaseViewModelTest() { ): EnvironmentViewModel = EnvironmentViewModel( environmentRepository = fakeEnvironmentRepository, - featureFlagManager = mockFeatureFlagManager, certificateManager = mockCertificateManager, fileManager = mockFileManager, snackbarRelayManager = snackbarRelayManager, @@ -833,7 +824,6 @@ class EnvironmentViewModelTest : BaseViewModelTest() { iconsServerUrl = "", keyHost = null, dialog = null, - showMutualTlsOptions = true, ) } } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt index f1eb2cf9cd..0627a43006 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt @@ -148,7 +148,6 @@ private val DEFAULT_MAP_VALUE: ImmutableMap, Any> = persistentMapOf FlagKey.ImportLoginsFlow to true, FlagKey.CredentialExchangeProtocolImport to true, FlagKey.CredentialExchangeProtocolExport to true, - FlagKey.MutualTls to true, FlagKey.SingleTapPasskeyCreation to true, FlagKey.SingleTapPasskeyAuthentication to true, FlagKey.AnonAddySelfHostAlias to true, @@ -164,7 +163,6 @@ private val UPDATED_MAP_VALUE: ImmutableMap, Any> = persistentMapOf FlagKey.ImportLoginsFlow to false, FlagKey.CredentialExchangeProtocolImport to false, FlagKey.CredentialExchangeProtocolExport to false, - FlagKey.MutualTls to false, FlagKey.SingleTapPasskeyCreation to false, FlagKey.SingleTapPasskeyAuthentication to false, FlagKey.AnonAddySelfHostAlias to false,