PM-24089: Remove Mutual TLS feature flag (#5566)

This commit is contained in:
David Perez
2025-07-24 08:33:32 -05:00
committed by GitHub
parent c7df80ff00
commit bb950c8c59
9 changed files with 48 additions and 112 deletions

View File

@@ -25,7 +25,6 @@ sealed class FlagKey<out T : Any> {
ImportLoginsFlow, ImportLoginsFlow,
CredentialExchangeProtocolImport, CredentialExchangeProtocolImport,
CredentialExchangeProtocolExport, CredentialExchangeProtocolExport,
MutualTls,
SingleTapPasskeyCreation, SingleTapPasskeyCreation,
SingleTapPasskeyAuthentication, SingleTapPasskeyAuthentication,
AnonAddySelfHostAlias, AnonAddySelfHostAlias,
@@ -80,14 +79,6 @@ sealed class FlagKey<out T : Any> {
override val defaultValue: Boolean = false override val defaultValue: Boolean = false
} }
/**
* Data object holding the feature flag key for the Mutual TLS feature.
*/
data object MutualTls : FlagKey<Boolean>() {
override val keyName: String = "mutual-tls"
override val defaultValue: Boolean = false
}
/** /**
* Data object holding the feature flag key to enable single tap passkey creation. * Data object holding the feature flag key to enable single tap passkey creation.
*/ */

View File

@@ -323,59 +323,58 @@ fun EnvironmentScreen(
.standardHorizontalMargin(), .standardHorizontalMargin(),
) )
if (state.showMutualTlsOptions) { Spacer(modifier = Modifier.height(height = 16.dp))
Spacer(modifier = Modifier.height(height = 16.dp))
BitwardenListHeaderText( BitwardenListHeaderText(
label = stringResource(id = R.string.client_certificate_mtls), label = stringResource(id = R.string.client_certificate_mtls),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.standardHorizontalMargin() .standardHorizontalMargin()
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
) )
Spacer(modifier = Modifier.height(height = 8.dp)) Spacer(modifier = Modifier.height(height = 8.dp))
BitwardenTextField( BitwardenTextField(
label = stringResource(id = R.string.certificate_alias), label = stringResource(id = R.string.certificate_alias),
value = state.keyAlias, value = state.keyAlias,
supportingText = stringResource( supportingText = stringResource(
id = R.string.certificate_used_for_client_authentication, id = R.string.certificate_used_for_client_authentication,
), ),
onValueChange = {}, onValueChange = {},
readOnly = true, readOnly = true,
cardStyle = CardStyle.Full, cardStyle = CardStyle.Full,
textFieldTestTag = "KeyAliasEntry", textFieldTestTag = "KeyAliasEntry",
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.focusProperties { canFocus = false } .focusProperties { canFocus = false }
.standardHorizontalMargin(), .standardHorizontalMargin(),
) )
Spacer(modifier = Modifier.height(height = 16.dp)) Spacer(modifier = Modifier.height(height = 16.dp))
BitwardenFilledButton( BitwardenFilledButton(
label = stringResource(id = R.string.import_certificate), label = stringResource(id = R.string.import_certificate),
onClick = remember(viewModel) { onClick = remember(viewModel) {
{ viewModel.trySendAction(EnvironmentAction.ImportCertificateClick) } { viewModel.trySendAction(EnvironmentAction.ImportCertificateClick) }
}, },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.standardHorizontalMargin() .standardHorizontalMargin()
.testTag("ImportCertificateButton"), .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.height(height = 16.dp))
Spacer(modifier = Modifier.navigationBarsPadding()) Spacer(modifier = Modifier.navigationBarsPadding())
} }

View File

@@ -16,8 +16,6 @@ import com.bitwarden.ui.util.asText
import com.x8bit.bitwarden.R import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.platform.datasource.disk.model.MutualTlsKeyHost 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.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.manager.model.ImportPrivateKeyResult
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
import com.x8bit.bitwarden.data.vault.manager.FileManager 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 com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -46,7 +43,6 @@ class EnvironmentViewModel @Inject constructor(
private val environmentRepository: EnvironmentRepository, private val environmentRepository: EnvironmentRepository,
private val fileManager: FileManager, private val fileManager: FileManager,
private val certificateManager: CertificateManager, private val certificateManager: CertificateManager,
private val featureFlagManager: FeatureFlagManager,
private val snackbarRelayManager: SnackbarRelayManager, private val snackbarRelayManager: SnackbarRelayManager,
private val savedStateHandle: SavedStateHandle, private val savedStateHandle: SavedStateHandle,
) : BaseViewModel<EnvironmentState, EnvironmentEvent, EnvironmentAction>( ) : BaseViewModel<EnvironmentState, EnvironmentEvent, EnvironmentAction>(
@@ -70,21 +66,13 @@ class EnvironmentViewModel @Inject constructor(
keyAlias = keyAlias, keyAlias = keyAlias,
keyHost = keyHost, keyHost = keyHost,
dialog = null, dialog = null,
showMutualTlsOptions = featureFlagManager.getFeatureFlag(FlagKey.MutualTls),
) )
}, },
) { ) {
init { init {
stateFlow stateFlow
.onEach { .onEach { savedStateHandle[KEY_STATE] = it }
savedStateHandle[KEY_STATE] = it
}
.launchIn(viewModelScope)
featureFlagManager.getFeatureFlagFlow(FlagKey.MutualTls)
.map { EnvironmentAction.Internal.MutualTlsFeatureFlagUpdate(it) }
.onEach(::handleAction)
.launchIn(viewModelScope) .launchIn(viewModelScope)
} }
@@ -275,10 +263,6 @@ class EnvironmentViewModel @Inject constructor(
is EnvironmentAction.Internal.ImportKeyResultReceive -> { is EnvironmentAction.Internal.ImportKeyResultReceive -> {
handleSaveKeyResultReceive(action) 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() { private fun handleChooseSystemCertificateClickAction() {
mutableStateFlow.update { mutableStateFlow.update {
it.copy( it.copy(
@@ -472,7 +446,6 @@ data class EnvironmentState(
val iconsServerUrl: String, val iconsServerUrl: String,
val keyAlias: String, val keyAlias: String,
val dialog: DialogState?, val dialog: DialogState?,
val showMutualTlsOptions: Boolean,
// internal // internal
private val keyHost: MutualTlsKeyHost?, private val keyHost: MutualTlsKeyHost?,
) : Parcelable { ) : Parcelable {
@@ -692,12 +665,5 @@ sealed class EnvironmentAction {
data class ImportKeyResultReceive( data class ImportKeyResultReceive(
val result: ImportPrivateKeyResult, val result: ImportPrivateKeyResult,
) : Internal() ) : Internal()
/**
* Indicates the mutual TLS feature flag was updated.
*/
data class MutualTlsFeatureFlagUpdate(
val enabled: Boolean,
) : Internal()
} }
} }

View File

@@ -30,7 +30,6 @@ fun <T : Any> FlagKey<T>.ListItemContent(
FlagKey.CredentialExchangeProtocolImport, FlagKey.CredentialExchangeProtocolImport,
FlagKey.CredentialExchangeProtocolExport, FlagKey.CredentialExchangeProtocolExport,
FlagKey.CipherKeyEncryption, FlagKey.CipherKeyEncryption,
FlagKey.MutualTls,
FlagKey.SingleTapPasskeyCreation, FlagKey.SingleTapPasskeyCreation,
FlagKey.SingleTapPasskeyAuthentication, FlagKey.SingleTapPasskeyAuthentication,
FlagKey.AnonAddySelfHostAlias, FlagKey.AnonAddySelfHostAlias,
@@ -85,7 +84,6 @@ private fun <T : Any> FlagKey<T>.getDisplayLabel(): String = when (this) {
FlagKey.CredentialExchangeProtocolImport -> stringResource(R.string.cxp_import) FlagKey.CredentialExchangeProtocolImport -> stringResource(R.string.cxp_import)
FlagKey.CredentialExchangeProtocolExport -> stringResource(R.string.cxp_export) FlagKey.CredentialExchangeProtocolExport -> stringResource(R.string.cxp_export)
FlagKey.CipherKeyEncryption -> stringResource(R.string.cipher_key_encryption) 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.SingleTapPasskeyCreation -> stringResource(R.string.single_tap_passkey_creation)
FlagKey.SingleTapPasskeyAuthentication -> { FlagKey.SingleTapPasskeyAuthentication -> {
stringResource(R.string.single_tap_passkey_authentication) stringResource(R.string.single_tap_passkey_authentication)

View File

@@ -865,7 +865,6 @@ Do you want to switch to this account?</string>
<string name="you_ll_only_need_to_set_up_authenticator_key">Youll 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.</string> <string name="you_ll_only_need_to_set_up_authenticator_key">Youll 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.</string>
<string name="coachmark_3_of_3">3 OF 3</string> <string name="coachmark_3_of_3">3 OF 3</string>
<string name="you_must_add_a_web_address_to_use_autofill_to_access_this_account">You must add a web address to use autofill to access this account.</string> <string name="you_must_add_a_web_address_to_use_autofill_to_access_this_account">You must add a web address to use autofill to access this account.</string>
<string name="mutual_tls">Mutual TLS</string>
<string name="single_tap_passkey_creation">Single tap passkey creation</string> <string name="single_tap_passkey_creation">Single tap passkey creation</string>
<string name="single_tap_passkey_authentication">Single tap passkey sign-on</string> <string name="single_tap_passkey_authentication">Single tap passkey sign-on</string>
<string name="learn_about_new_logins">Learn about new logins</string> <string name="learn_about_new_logins">Learn about new logins</string>

View File

@@ -37,10 +37,6 @@ class FlagKeyTest {
FlagKey.SingleTapPasskeyAuthentication.keyName, FlagKey.SingleTapPasskeyAuthentication.keyName,
"single-tap-passkey-authentication", "single-tap-passkey-authentication",
) )
assertEquals(
FlagKey.MutualTls.keyName,
"mutual-tls",
)
assertEquals( assertEquals(
FlagKey.AnonAddySelfHostAlias.keyName, FlagKey.AnonAddySelfHostAlias.keyName,
"anon-addy-self-host-alias", "anon-addy-self-host-alias",

View File

@@ -437,7 +437,6 @@ class EnvironmentScreenTest : BitwardenComposeTest() {
iconsServerUrl = "", iconsServerUrl = "",
keyHost = null, keyHost = null,
dialog = null, dialog = null,
showMutualTlsOptions = true,
) )
} }
} }

View File

@@ -11,8 +11,6 @@ import com.bitwarden.ui.util.asText
import com.x8bit.bitwarden.R import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.platform.datasource.disk.model.MutualTlsKeyHost 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.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.manager.model.ImportPrivateKeyResult
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
import com.x8bit.bitwarden.data.vault.manager.FileManager import com.x8bit.bitwarden.data.vault.manager.FileManager
@@ -28,7 +26,6 @@ import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.runs import io.mockk.runs
import io.mockk.verify import io.mockk.verify
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@@ -37,11 +34,6 @@ import org.junit.jupiter.api.Test
class EnvironmentViewModelTest : BaseViewModelTest() { class EnvironmentViewModelTest : BaseViewModelTest() {
private val fakeEnvironmentRepository = FakeEnvironmentRepository() private val fakeEnvironmentRepository = FakeEnvironmentRepository()
private val mutableMutualTlsFeatureFlagFlow = MutableStateFlow(true)
private val mockFeatureFlagManager = mockk<FeatureFlagManager> {
every { getFeatureFlag(FlagKey.MutualTls) } returns true
every { getFeatureFlagFlow(FlagKey.MutualTls) } returns mutableMutualTlsFeatureFlagFlow
}
private val mockCertificateManager = mockk<CertificateManager> { private val mockCertificateManager = mockk<CertificateManager> {
every { getMutualTlsKeyAliases() } returns emptyList() every { getMutualTlsKeyAliases() } returns emptyList()
} }
@@ -814,7 +806,6 @@ class EnvironmentViewModelTest : BaseViewModelTest() {
): EnvironmentViewModel = ): EnvironmentViewModel =
EnvironmentViewModel( EnvironmentViewModel(
environmentRepository = fakeEnvironmentRepository, environmentRepository = fakeEnvironmentRepository,
featureFlagManager = mockFeatureFlagManager,
certificateManager = mockCertificateManager, certificateManager = mockCertificateManager,
fileManager = mockFileManager, fileManager = mockFileManager,
snackbarRelayManager = snackbarRelayManager, snackbarRelayManager = snackbarRelayManager,
@@ -833,7 +824,6 @@ class EnvironmentViewModelTest : BaseViewModelTest() {
iconsServerUrl = "", iconsServerUrl = "",
keyHost = null, keyHost = null,
dialog = null, dialog = null,
showMutualTlsOptions = true,
) )
} }
} }

View File

@@ -148,7 +148,6 @@ private val DEFAULT_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf
FlagKey.ImportLoginsFlow to true, FlagKey.ImportLoginsFlow to true,
FlagKey.CredentialExchangeProtocolImport to true, FlagKey.CredentialExchangeProtocolImport to true,
FlagKey.CredentialExchangeProtocolExport to true, FlagKey.CredentialExchangeProtocolExport to true,
FlagKey.MutualTls to true,
FlagKey.SingleTapPasskeyCreation to true, FlagKey.SingleTapPasskeyCreation to true,
FlagKey.SingleTapPasskeyAuthentication to true, FlagKey.SingleTapPasskeyAuthentication to true,
FlagKey.AnonAddySelfHostAlias to true, FlagKey.AnonAddySelfHostAlias to true,
@@ -164,7 +163,6 @@ private val UPDATED_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf
FlagKey.ImportLoginsFlow to false, FlagKey.ImportLoginsFlow to false,
FlagKey.CredentialExchangeProtocolImport to false, FlagKey.CredentialExchangeProtocolImport to false,
FlagKey.CredentialExchangeProtocolExport to false, FlagKey.CredentialExchangeProtocolExport to false,
FlagKey.MutualTls to false,
FlagKey.SingleTapPasskeyCreation to false, FlagKey.SingleTapPasskeyCreation to false,
FlagKey.SingleTapPasskeyAuthentication to false, FlagKey.SingleTapPasskeyAuthentication to false,
FlagKey.AnonAddySelfHostAlias to false, FlagKey.AnonAddySelfHostAlias to false,