[PM-12695] Add hidden field changes to password history (#4047)

This commit is contained in:
André Bispo 2024-10-08 19:29:50 +01:00 committed by GitHub
parent 5e7dc26837
commit cda4e47414
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 90 additions and 15 deletions

View file

@ -1,3 +1,5 @@
@file:Suppress("TooManyFunctions")
package com.x8bit.bitwarden.ui.vault.feature.vault.util
import com.bitwarden.vault.CardView
@ -118,22 +120,71 @@ private fun VaultAddEditState.ViewState.Content.ItemType.toIdentityView(): Ident
@Suppress("MagicNumber")
private fun VaultAddEditState.ViewState.Content.toPasswordHistory(): List<PasswordHistoryView>? {
val loginCipher = type as? VaultAddEditState.ViewState.Content.ItemType.Login
val oldPassword = common.originalCipher?.login?.password
val timestamp = Instant.now()
return if (oldPassword != null &&
oldPassword != (type as? VaultAddEditState.ViewState.Content.ItemType.Login)?.password
) {
listOf(
PasswordHistoryView(
password = oldPassword,
lastUsedDate = Instant.now(),
),
val newPasswordHistory = getPasswordHistory(
loginCipher,
oldPassword,
timestamp,
)
.plus(common.originalCipher?.passwordHistory.orEmpty())
.take(5)
} else {
common.originalCipher?.passwordHistory
val newHiddenFieldHistory = getHiddenFieldHistory(
timestamp,
common.originalCipher?.fields,
common.customFieldData,
)
return listOf(
common.originalCipher?.passwordHistory.orEmpty(),
newPasswordHistory,
newHiddenFieldHistory,
)
.flatten()
.ifEmpty { null }
?.takeLast(5)
}
private fun getPasswordHistory(
loginCipher: VaultAddEditState.ViewState.Content.ItemType.Login?,
oldPassword: String?,
timestamp: Instant,
): List<PasswordHistoryView> {
return oldPassword
.takeIf {
loginCipher != null && !it.isNullOrEmpty() && it != loginCipher.password
}
?.let {
listOf(PasswordHistoryView(password = it, lastUsedDate = timestamp))
}
?: emptyList()
}
private fun getHiddenFieldHistory(
timestamp: Instant,
oldFields: List<FieldView>?,
newFields: List<VaultAddEditState.Custom>,
): List<PasswordHistoryView> {
return oldFields
?.filter { oldField ->
oldField.type == FieldType.HIDDEN &&
!oldField.value.isNullOrEmpty() &&
!oldField.name.isNullOrEmpty() &&
newFields
.none { newField ->
newField is VaultAddEditState.Custom.HiddenField &&
newField.name == oldField.name &&
newField.value == oldField.value
}
}
?.map { field ->
PasswordHistoryView(
password = "${field.name}: ${field.value}",
lastUsedDate = timestamp,
)
}
.orEmpty()
}
private fun VaultAddEditState.ViewState.Content.ItemType.toLoginView(

View file

@ -207,12 +207,16 @@ class VaultAddItemStateExtensionsTest {
),
),
passwordHistory = listOf(
PasswordHistoryView(
password = "old_password",
lastUsedDate = Instant.MIN,
),
PasswordHistoryView(
password = "password",
lastUsedDate = Instant.MIN,
),
PasswordHistoryView(
password = "old_password",
password = "hidden: value",
lastUsedDate = Instant.MIN,
),
),
@ -297,7 +301,9 @@ class VaultAddItemStateExtensionsTest {
@Test
fun `toCipherView should transform SecureNotes ItemType to CipherView with original cipher`() {
val cipherView = DEFAULT_SECURE_NOTES_CIPHER_VIEW
mockkStatic(Instant::class)
every { Instant.now() } returns Instant.MIN
val cipherView = DEFAULT_SECURE_NOTES_CIPHER_VIEW.copy(passwordHistory = null)
val viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(
originalCipher = cipherView,
@ -325,6 +331,12 @@ class VaultAddItemStateExtensionsTest {
secureNote = SecureNoteView(SecureNoteType.GENERIC),
reprompt = CipherRepromptType.PASSWORD,
fields = emptyList(),
passwordHistory = listOf(
PasswordHistoryView(
password = "hidden: value",
lastUsedDate = Instant.MIN,
),
),
),
result,
)
@ -420,6 +432,8 @@ class VaultAddItemStateExtensionsTest {
@Test
fun `toCipherView should transform Identity ItemType to CipherView with original cipher`() {
mockkStatic(Instant::class)
every { Instant.now() } returns Instant.MIN
val cipherView = DEFAULT_IDENTITY_CIPHER_VIEW
val viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(
@ -527,6 +541,10 @@ class VaultAddItemStateExtensionsTest {
password = "old_password",
lastUsedDate = Instant.MIN,
),
PasswordHistoryView(
password = "hidden: value",
lastUsedDate = Instant.MIN,
),
),
),
result,
@ -599,6 +617,8 @@ class VaultAddItemStateExtensionsTest {
@Test
fun `toCipherView should transform Card ItemType to CipherView with original cipher`() {
mockkStatic(Instant::class)
every { Instant.now() } returns Instant.MIN
val cipherView = DEFAULT_CARD_CIPHER_VIEW
val viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(
@ -672,6 +692,10 @@ class VaultAddItemStateExtensionsTest {
password = "old_password",
lastUsedDate = Instant.MIN,
),
PasswordHistoryView(
password = "hidden: value",
lastUsedDate = Instant.MIN,
),
),
),
result,