mirror of
https://github.com/bitwarden/android.git
synced 2024-11-21 17:05:44 +03:00
[PM-14589] Prevent SSH key item creation (#4251)
This commit is contained in:
parent
a3ed2bc068
commit
2c40a7f105
2 changed files with 25 additions and 133 deletions
|
@ -16,12 +16,10 @@ import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialRequest
|
||||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||||
import com.x8bit.bitwarden.data.autofill.fido2.model.UserVerificationRequirement
|
import com.x8bit.bitwarden.data.autofill.fido2.model.UserVerificationRequirement
|
||||||
import com.x8bit.bitwarden.data.autofill.util.isActiveWithFido2Credentials
|
import com.x8bit.bitwarden.data.autofill.util.isActiveWithFido2Credentials
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
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.event.OrganizationEventManager
|
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
|
import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
|
||||||
import com.x8bit.bitwarden.data.platform.manager.util.toAutofillSaveItemOrNull
|
import com.x8bit.bitwarden.data.platform.manager.util.toAutofillSaveItemOrNull
|
||||||
import com.x8bit.bitwarden.data.platform.manager.util.toAutofillSelectionDataOrNull
|
import com.x8bit.bitwarden.data.platform.manager.util.toAutofillSelectionDataOrNull
|
||||||
|
@ -103,7 +101,6 @@ class VaultAddEditViewModel @Inject constructor(
|
||||||
private val resourceManager: ResourceManager,
|
private val resourceManager: ResourceManager,
|
||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
private val organizationEventManager: OrganizationEventManager,
|
private val organizationEventManager: OrganizationEventManager,
|
||||||
private val featureFlagManager: FeatureFlagManager,
|
|
||||||
) : BaseViewModel<VaultAddEditState, VaultAddEditEvent, VaultAddEditAction>(
|
) : BaseViewModel<VaultAddEditState, VaultAddEditEvent, VaultAddEditAction>(
|
||||||
// We load the state from the savedStateHandle for testing purposes.
|
// We load the state from the savedStateHandle for testing purposes.
|
||||||
initialState = savedStateHandle[KEY_STATE]
|
initialState = savedStateHandle[KEY_STATE]
|
||||||
|
@ -170,11 +167,7 @@ class VaultAddEditViewModel @Inject constructor(
|
||||||
// Set special conditions for autofill and fido2 save
|
// Set special conditions for autofill and fido2 save
|
||||||
shouldShowCloseButton = autofillSaveItem == null && fido2AttestationOptions == null,
|
shouldShowCloseButton = autofillSaveItem == null && fido2AttestationOptions == null,
|
||||||
shouldExitOnSave = shouldExitOnSave,
|
shouldExitOnSave = shouldExitOnSave,
|
||||||
supportedItemTypes = getSupportedItemTypeOptions(
|
supportedItemTypes = getSupportedItemTypeOptions(),
|
||||||
isSshKeyVaultItemSupported = featureFlagManager.getFeatureFlag(
|
|
||||||
key = FlagKey.SshKeyCipherItems,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
@ -216,11 +209,6 @@ class VaultAddEditViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
.onEach(::sendAction)
|
.onEach(::sendAction)
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
featureFlagManager.getFeatureFlagFlow(FlagKey.SshKeyCipherItems)
|
|
||||||
.map { VaultAddEditAction.Internal.SshKeyCipherItemsFeatureFlagReceive(it) }
|
|
||||||
.onEach(::sendAction)
|
|
||||||
.launchIn(viewModelScope)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleAction(action: VaultAddEditAction) {
|
override fun handleAction(action: VaultAddEditAction) {
|
||||||
|
@ -1447,10 +1435,6 @@ class VaultAddEditViewModel @Inject constructor(
|
||||||
is VaultAddEditAction.Internal.ValidateFido2PinResultReceive -> {
|
is VaultAddEditAction.Internal.ValidateFido2PinResultReceive -> {
|
||||||
handleValidateFido2PinResultReceive(action)
|
handleValidateFido2PinResultReceive(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
is VaultAddEditAction.Internal.SshKeyCipherItemsFeatureFlagReceive -> {
|
|
||||||
handleSshKeyCipherItemsFeatureFlagReceive(action)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1785,19 +1769,6 @@ class VaultAddEditViewModel @Inject constructor(
|
||||||
|
|
||||||
getRequestAndRegisterCredential()
|
getRequestAndRegisterCredential()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSshKeyCipherItemsFeatureFlagReceive(
|
|
||||||
action: VaultAddEditAction.Internal.SshKeyCipherItemsFeatureFlagReceive,
|
|
||||||
) {
|
|
||||||
mutableStateFlow.update {
|
|
||||||
it.copy(
|
|
||||||
supportedItemTypes = getSupportedItemTypeOptions(
|
|
||||||
isSshKeyVaultItemSupported = action.enabled,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//endregion Internal Type Handlers
|
//endregion Internal Type Handlers
|
||||||
|
|
||||||
//region Utility Functions
|
//region Utility Functions
|
||||||
|
@ -3112,13 +3083,6 @@ sealed class VaultAddEditAction {
|
||||||
val generatorResult: GeneratorResult,
|
val generatorResult: GeneratorResult,
|
||||||
) : Internal()
|
) : Internal()
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the the SSH key vault item feature flag state has been received.
|
|
||||||
*/
|
|
||||||
data class SshKeyCipherItemsFeatureFlagReceive(
|
|
||||||
val enabled: Boolean,
|
|
||||||
) : Internal()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that the vault item data has been received.
|
* Indicates that the vault item data has been received.
|
||||||
*/
|
*/
|
||||||
|
@ -3173,7 +3137,10 @@ sealed class VaultAddEditAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSupportedItemTypeOptions(
|
/**
|
||||||
isSshKeyVaultItemSupported: Boolean,
|
* Returns a list of item type options that can be selected during item creation.
|
||||||
) = VaultAddEditState.ItemTypeOption.entries
|
*
|
||||||
.filter { isSshKeyVaultItemSupported || it != VaultAddEditState.ItemTypeOption.SSH_KEYS }
|
* TODO: [PM-10413] Allow SSH key creation when the SDK supports it.
|
||||||
|
*/
|
||||||
|
private fun getSupportedItemTypeOptions() = VaultAddEditState.ItemTypeOption.entries
|
||||||
|
.filter { it != VaultAddEditState.ItemTypeOption.SSH_KEYS }
|
||||||
|
|
|
@ -25,14 +25,12 @@ import com.x8bit.bitwarden.data.autofill.fido2.model.createMockFido2CredentialRe
|
||||||
import com.x8bit.bitwarden.data.autofill.model.AutofillSaveItem
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSaveItem
|
||||||
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager
|
import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
|
||||||
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.event.OrganizationEventManager
|
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
|
import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
|
@ -155,15 +153,6 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||||
private val organizationEventManager = mockk<OrganizationEventManager> {
|
private val organizationEventManager = mockk<OrganizationEventManager> {
|
||||||
every { trackEvent(event = any()) } just runs
|
every { trackEvent(event = any()) } just runs
|
||||||
}
|
}
|
||||||
private val mutableSshVaultItemsFeatureFlagFlow = MutableStateFlow<Boolean>(true)
|
|
||||||
private val featureFlagManager = mockk<FeatureFlagManager> {
|
|
||||||
every {
|
|
||||||
getFeatureFlagFlow(key = FlagKey.SshKeyCipherItems)
|
|
||||||
} returns mutableSshVaultItemsFeatureFlagFlow
|
|
||||||
every {
|
|
||||||
getFeatureFlag(key = FlagKey.SshKeyCipherItems)
|
|
||||||
} returns mutableSshVaultItemsFeatureFlagFlow.value
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setup() {
|
fun setup() {
|
||||||
|
@ -180,6 +169,20 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `initial state should be correct when state is null`() = runTest {
|
fun `initial state should be correct when state is null`() = runTest {
|
||||||
|
val expectedState = VaultAddEditState(
|
||||||
|
vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN),
|
||||||
|
viewState = VaultAddEditState.ViewState.Content(
|
||||||
|
common = VaultAddEditState.ViewState.Content.Common(),
|
||||||
|
isIndividualVaultDisabled = false,
|
||||||
|
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
|
||||||
|
),
|
||||||
|
dialog = null,
|
||||||
|
totpData = null,
|
||||||
|
shouldShowCloseButton = true,
|
||||||
|
shouldExitOnSave = false,
|
||||||
|
supportedItemTypes = VaultAddEditState.ItemTypeOption.entries
|
||||||
|
.filter { it != VaultAddEditState.ItemTypeOption.SSH_KEYS },
|
||||||
|
)
|
||||||
val viewModel = createAddVaultItemViewModel(
|
val viewModel = createAddVaultItemViewModel(
|
||||||
savedStateHandle = createSavedStateHandleWithState(
|
savedStateHandle = createSavedStateHandleWithState(
|
||||||
state = null,
|
state = null,
|
||||||
|
@ -188,10 +191,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||||
)
|
)
|
||||||
viewModel.stateFlow.test {
|
viewModel.stateFlow.test {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
createVaultAddItemState(
|
expectedState,
|
||||||
commonContentViewState = VaultAddEditState.ViewState.Content.Common(),
|
|
||||||
typeContentViewState = createLoginTypeContentViewState(),
|
|
||||||
),
|
|
||||||
awaitItem(),
|
awaitItem(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,8 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||||
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
|
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
|
||||||
),
|
),
|
||||||
dialog = null,
|
dialog = null,
|
||||||
supportedItemTypes = VaultAddEditState.ItemTypeOption.entries,
|
supportedItemTypes = VaultAddEditState.ItemTypeOption.entries
|
||||||
|
.filter { it != VaultAddEditState.ItemTypeOption.SSH_KEYS },
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
)
|
)
|
||||||
|
@ -378,56 +379,6 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `initial add state should be correct when SSH key feature flag is enabled`() {
|
|
||||||
mutableSshVaultItemsFeatureFlagFlow.value = true
|
|
||||||
val vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN)
|
|
||||||
val initState = createVaultAddItemState(vaultAddEditType = vaultAddEditType)
|
|
||||||
val viewModel = createAddVaultItemViewModel(
|
|
||||||
savedStateHandle = createSavedStateHandleWithState(
|
|
||||||
state = initState,
|
|
||||||
vaultAddEditType = vaultAddEditType,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
assertEquals(
|
|
||||||
initState,
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `initial add state should be correct when SSH key feature flag is disabled`() {
|
|
||||||
mutableSshVaultItemsFeatureFlagFlow.value = false
|
|
||||||
every {
|
|
||||||
featureFlagManager.getFeatureFlag(key = FlagKey.SshKeyCipherItems)
|
|
||||||
} returns false
|
|
||||||
val vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN)
|
|
||||||
val expectedState = VaultAddEditState(
|
|
||||||
vaultAddEditType = vaultAddEditType,
|
|
||||||
viewState = VaultAddEditState.ViewState.Content(
|
|
||||||
common = VaultAddEditState.ViewState.Content.Common(),
|
|
||||||
isIndividualVaultDisabled = false,
|
|
||||||
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
|
|
||||||
),
|
|
||||||
dialog = null,
|
|
||||||
totpData = null,
|
|
||||||
shouldShowCloseButton = true,
|
|
||||||
shouldExitOnSave = false,
|
|
||||||
supportedItemTypes = VaultAddEditState.ItemTypeOption.entries
|
|
||||||
.filter { it != VaultAddEditState.ItemTypeOption.SSH_KEYS },
|
|
||||||
)
|
|
||||||
val viewModel = createAddVaultItemViewModel(
|
|
||||||
savedStateHandle = createSavedStateHandleWithState(
|
|
||||||
state = null,
|
|
||||||
vaultAddEditType = vaultAddEditType,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
assertEquals(
|
|
||||||
expectedState,
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `initial edit state should be correct`() = runTest {
|
fun `initial edit state should be correct`() = runTest {
|
||||||
val vaultAddEditType = VaultAddEditType.EditItem(DEFAULT_EDIT_ITEM_ID)
|
val vaultAddEditType = VaultAddEditType.EditItem(DEFAULT_EDIT_ITEM_ID)
|
||||||
|
@ -3175,7 +3126,6 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||||
resourceManager = resourceManager,
|
resourceManager = resourceManager,
|
||||||
clock = fixedClock,
|
clock = fixedClock,
|
||||||
organizationEventManager = organizationEventManager,
|
organizationEventManager = organizationEventManager,
|
||||||
featureFlagManager = featureFlagManager,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4271,30 +4221,6 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
|
||||||
@Test
|
|
||||||
fun `SshKeyCipherItemsFeatureFlagReceive should update supportedItemTypes`() = runTest {
|
|
||||||
// Verify SSH keys is supported when feature flag is enabled.
|
|
||||||
viewModel.trySendAction(
|
|
||||||
VaultAddEditAction.Internal.SshKeyCipherItemsFeatureFlagReceive(enabled = true),
|
|
||||||
)
|
|
||||||
assertEquals(
|
|
||||||
VaultAddEditState.ItemTypeOption.entries,
|
|
||||||
viewModel.stateFlow.value.supportedItemTypes,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Verify SSH keys is not supported when feature flag is disabled.
|
|
||||||
viewModel.trySendAction(
|
|
||||||
VaultAddEditAction.Internal.SshKeyCipherItemsFeatureFlagReceive(enabled = false),
|
|
||||||
)
|
|
||||||
assertEquals(
|
|
||||||
VaultAddEditState.ItemTypeOption.entries.filterNot {
|
|
||||||
it == VaultAddEditState.ItemTypeOption.SSH_KEYS
|
|
||||||
},
|
|
||||||
viewModel.stateFlow.value.supportedItemTypes,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//region Helper functions
|
//region Helper functions
|
||||||
|
@ -4429,7 +4355,6 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||||
resourceManager = bitwardenResourceManager,
|
resourceManager = bitwardenResourceManager,
|
||||||
clock = clock,
|
clock = clock,
|
||||||
organizationEventManager = organizationEventManager,
|
organizationEventManager = organizationEventManager,
|
||||||
featureFlagManager = featureFlagManager,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun createVaultData(
|
private fun createVaultData(
|
||||||
|
|
Loading…
Reference in a new issue