BIT-2446: Limit the number of inline autofill items that can be displayed (#3418)

This commit is contained in:
David Perez 2024-07-09 09:38:40 -05:00 committed by GitHub
parent 01b786fcf9
commit adf7916a4c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 110 additions and 2 deletions

View file

@ -10,6 +10,22 @@ import com.x8bit.bitwarden.data.autofill.model.FilledPartition
import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProvider import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProvider
import com.x8bit.bitwarden.data.autofill.util.buildFilledItemOrNull import com.x8bit.bitwarden.data.autofill.util.buildFilledItemOrNull
/**
* The maximum amount of filled partitions the user will see. Viewing the rest will require opening
* the vault.
*
* Note: The vault item is not included in this count.
*/
private const val MAX_FILLED_PARTITIONS_COUNT: Int = 20
/**
* The maximum amount of inline suggestions the user will see. Viewing the rest will require
* opening the vault.
*
* Note: The vault item is not included in this count.
*/
private const val MAX_INLINE_SUGGESTION_COUNT: Int = 5
/** /**
* The default [FilledDataBuilder]. This converts parsed autofill data into filled data that is * The default [FilledDataBuilder]. This converts parsed autofill data into filled data that is
* ready to be loaded into an autofill response. * ready to be loaded into an autofill response.
@ -21,7 +37,9 @@ class FilledDataBuilderImpl(
val isVaultLocked = autofillCipherProvider.isVaultLocked() val isVaultLocked = autofillCipherProvider.isVaultLocked()
// Subtract one to make sure there is space for the vault item. // Subtract one to make sure there is space for the vault item.
val maxCipherInlineSuggestionsCount = autofillRequest.maxInlineSuggestionsCount - 1 val maxCipherInlineSuggestionsCount = (autofillRequest.maxInlineSuggestionsCount - 1)
.coerceAtMost(maximumValue = MAX_INLINE_SUGGESTION_COUNT)
// Track the number of inline suggestions that have been added. // Track the number of inline suggestions that have been added.
var inlineSuggestionsAdded = 0 var inlineSuggestionsAdded = 0
@ -76,7 +94,7 @@ class FilledDataBuilderImpl(
?.getOrLastOrNull(inlineSuggestionsAdded) ?.getOrLastOrNull(inlineSuggestionsAdded)
return FilledData( return FilledData(
filledPartitions = filledPartitions, filledPartitions = filledPartitions.take(n = MAX_FILLED_PARTITIONS_COUNT),
ignoreAutofillIds = autofillRequest.ignoreAutofillIds, ignoreAutofillIds = autofillRequest.ignoreAutofillIds,
originalPartition = autofillRequest.partition, originalPartition = autofillRequest.partition,
uri = autofillRequest.uri, uri = autofillRequest.uri,

View file

@ -361,6 +361,96 @@ class FilledDataBuilderTest {
} }
} }
@Suppress("MaxLineLength")
@Test
fun `build should return filled data with hard-coded max count of inline specs and partitions`() =
runTest {
// Setup
val password = "Password"
val username = "johnDoe"
val autofillCipher = AutofillCipher.Login(
cipherId = null,
isTotpEnabled = false,
name = "Cipher One",
password = password,
username = username,
subtitle = "Subtitle",
)
val filledItemPassword: FilledItem = mockk()
val filledItemUsername: FilledItem = mockk()
val autofillViewPassword: AutofillView.Login.Password = mockk {
every { buildFilledItemOrNull(password) } returns filledItemPassword
}
val autofillViewUsername: AutofillView.Login.Username = mockk {
every { buildFilledItemOrNull(username) } returns filledItemUsername
}
val autofillPartition = AutofillPartition.Login(
views = listOf(autofillViewPassword, autofillViewUsername),
)
val inlinePresentationSpec: InlinePresentationSpec = mockk()
val autofillRequest = AutofillRequest.Fillable(
ignoreAutofillIds = emptyList(),
inlinePresentationSpecs = listOf(inlinePresentationSpec),
maxInlineSuggestionsCount = 10,
packageName = null,
partition = autofillPartition,
uri = URI,
)
val filledPartition = FilledPartition(
autofillCipher = autofillCipher,
filledItems = listOf(filledItemPassword, filledItemUsername),
inlinePresentationSpec = inlinePresentationSpec,
)
val expected = FilledData(
// 5 with inline specs, 20 total
filledPartitions = listOf(
filledPartition,
filledPartition.copy(),
filledPartition.copy(),
filledPartition.copy(),
filledPartition.copy(),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
filledPartition.copy(inlinePresentationSpec = null),
),
ignoreAutofillIds = emptyList(),
originalPartition = autofillPartition,
uri = URI,
vaultItemInlinePresentationSpec = inlinePresentationSpec,
isVaultLocked = false,
)
coEvery {
autofillCipherProvider.getLoginAutofillCiphers(uri = URI)
} returns List(size = 22) { autofillCipher }
// Test
val actual = filledDataBuilder.build(
autofillRequest = autofillRequest,
)
// Verify
assertEquals(expected, actual)
coVerify(exactly = 1) {
autofillCipherProvider.getLoginAutofillCiphers(uri = URI)
}
verify(exactly = 22) {
autofillViewPassword.buildFilledItemOrNull(password)
autofillViewUsername.buildFilledItemOrNull(username)
}
}
companion object { companion object {
private const val URI: String = "androidapp://com.x8bit.bitwarden" private const val URI: String = "androidapp://com.x8bit.bitwarden"
} }