mirror of
https://github.com/bitwarden/android.git
synced 2024-11-24 10:25:57 +03:00
[PM-12695] Add hidden field changes to password history (#4047)
This commit is contained in:
parent
5e7dc26837
commit
cda4e47414
2 changed files with 90 additions and 15 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
@file:Suppress("TooManyFunctions")
|
||||||
|
|
||||||
package com.x8bit.bitwarden.ui.vault.feature.vault.util
|
package com.x8bit.bitwarden.ui.vault.feature.vault.util
|
||||||
|
|
||||||
import com.bitwarden.vault.CardView
|
import com.bitwarden.vault.CardView
|
||||||
|
@ -118,22 +120,71 @@ private fun VaultAddEditState.ViewState.Content.ItemType.toIdentityView(): Ident
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
private fun VaultAddEditState.ViewState.Content.toPasswordHistory(): List<PasswordHistoryView>? {
|
private fun VaultAddEditState.ViewState.Content.toPasswordHistory(): List<PasswordHistoryView>? {
|
||||||
|
val loginCipher = type as? VaultAddEditState.ViewState.Content.ItemType.Login
|
||||||
val oldPassword = common.originalCipher?.login?.password
|
val oldPassword = common.originalCipher?.login?.password
|
||||||
|
val timestamp = Instant.now()
|
||||||
|
|
||||||
return if (oldPassword != null &&
|
val newPasswordHistory = getPasswordHistory(
|
||||||
oldPassword != (type as? VaultAddEditState.ViewState.Content.ItemType.Login)?.password
|
loginCipher,
|
||||||
) {
|
oldPassword,
|
||||||
listOf(
|
timestamp,
|
||||||
PasswordHistoryView(
|
|
||||||
password = oldPassword,
|
|
||||||
lastUsedDate = Instant.now(),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.plus(common.originalCipher?.passwordHistory.orEmpty())
|
|
||||||
.take(5)
|
val newHiddenFieldHistory = getHiddenFieldHistory(
|
||||||
} else {
|
timestamp,
|
||||||
common.originalCipher?.passwordHistory
|
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(
|
private fun VaultAddEditState.ViewState.Content.ItemType.toLoginView(
|
||||||
|
|
|
@ -207,12 +207,16 @@ class VaultAddItemStateExtensionsTest {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
passwordHistory = listOf(
|
passwordHistory = listOf(
|
||||||
|
PasswordHistoryView(
|
||||||
|
password = "old_password",
|
||||||
|
lastUsedDate = Instant.MIN,
|
||||||
|
),
|
||||||
PasswordHistoryView(
|
PasswordHistoryView(
|
||||||
password = "password",
|
password = "password",
|
||||||
lastUsedDate = Instant.MIN,
|
lastUsedDate = Instant.MIN,
|
||||||
),
|
),
|
||||||
PasswordHistoryView(
|
PasswordHistoryView(
|
||||||
password = "old_password",
|
password = "hidden: value",
|
||||||
lastUsedDate = Instant.MIN,
|
lastUsedDate = Instant.MIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -297,7 +301,9 @@ class VaultAddItemStateExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toCipherView should transform SecureNotes ItemType to CipherView with original cipher`() {
|
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(
|
val viewState = VaultAddEditState.ViewState.Content(
|
||||||
common = VaultAddEditState.ViewState.Content.Common(
|
common = VaultAddEditState.ViewState.Content.Common(
|
||||||
originalCipher = cipherView,
|
originalCipher = cipherView,
|
||||||
|
@ -325,6 +331,12 @@ class VaultAddItemStateExtensionsTest {
|
||||||
secureNote = SecureNoteView(SecureNoteType.GENERIC),
|
secureNote = SecureNoteView(SecureNoteType.GENERIC),
|
||||||
reprompt = CipherRepromptType.PASSWORD,
|
reprompt = CipherRepromptType.PASSWORD,
|
||||||
fields = emptyList(),
|
fields = emptyList(),
|
||||||
|
passwordHistory = listOf(
|
||||||
|
PasswordHistoryView(
|
||||||
|
password = "hidden: value",
|
||||||
|
lastUsedDate = Instant.MIN,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
|
@ -420,6 +432,8 @@ class VaultAddItemStateExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toCipherView should transform Identity ItemType to CipherView with original cipher`() {
|
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 cipherView = DEFAULT_IDENTITY_CIPHER_VIEW
|
||||||
val viewState = VaultAddEditState.ViewState.Content(
|
val viewState = VaultAddEditState.ViewState.Content(
|
||||||
common = VaultAddEditState.ViewState.Content.Common(
|
common = VaultAddEditState.ViewState.Content.Common(
|
||||||
|
@ -527,6 +541,10 @@ class VaultAddItemStateExtensionsTest {
|
||||||
password = "old_password",
|
password = "old_password",
|
||||||
lastUsedDate = Instant.MIN,
|
lastUsedDate = Instant.MIN,
|
||||||
),
|
),
|
||||||
|
PasswordHistoryView(
|
||||||
|
password = "hidden: value",
|
||||||
|
lastUsedDate = Instant.MIN,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
result,
|
result,
|
||||||
|
@ -599,6 +617,8 @@ class VaultAddItemStateExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toCipherView should transform Card ItemType to CipherView with original cipher`() {
|
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 cipherView = DEFAULT_CARD_CIPHER_VIEW
|
||||||
val viewState = VaultAddEditState.ViewState.Content(
|
val viewState = VaultAddEditState.ViewState.Content(
|
||||||
common = VaultAddEditState.ViewState.Content.Common(
|
common = VaultAddEditState.ViewState.Content.Common(
|
||||||
|
@ -672,6 +692,10 @@ class VaultAddItemStateExtensionsTest {
|
||||||
password = "old_password",
|
password = "old_password",
|
||||||
lastUsedDate = Instant.MIN,
|
lastUsedDate = Instant.MIN,
|
||||||
),
|
),
|
||||||
|
PasswordHistoryView(
|
||||||
|
password = "hidden: value",
|
||||||
|
lastUsedDate = Instant.MIN,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
result,
|
result,
|
||||||
|
|
Loading…
Reference in a new issue