BIT-2201: Handle URI checksum validation (#1231)

This commit is contained in:
David Perez 2024-04-04 22:19:51 -05:00 committed by Álison Fernandes
parent 1a12a91a74
commit 04eba5828b
19 changed files with 104 additions and 37 deletions

View file

@ -753,6 +753,9 @@ data class SyncResponseJson(
@SerialName("uri")
val uri: String?,
@SerialName("uriChecksum")
val uriChecksum: String?,
)
}

View file

@ -184,6 +184,7 @@ private fun LoginUri.toEncryptedNetworkUri(): SyncResponseJson.Cipher.Login.Uri
SyncResponseJson.Cipher.Login.Uri(
uriMatchType = match?.toNetworkMatchType(),
uri = uri,
uriChecksum = uriChecksum,
)
private fun UriMatchType.toNetworkMatchType(): UriMatchTypeJson =
@ -432,7 +433,7 @@ fun SyncResponseJson.Cipher.Login.Uri.toSdkLoginUri(): LoginUri =
LoginUri(
uri = uri,
match = uriMatchType?.toSdkMatchType(),
uriChecksum = null,
uriChecksum = uriChecksum,
)
/**

View file

@ -126,6 +126,7 @@ class VaultAddEditViewModel @Inject constructor(
type = vaultAddEditType.vaultItemCipherType.toItemType(),
)
}
is VaultAddEditType.EditItem -> VaultAddEditState.ViewState.Loading
is VaultAddEditType.CloneItem -> VaultAddEditState.ViewState.Loading
},
@ -718,6 +719,7 @@ class VaultAddEditViewModel @Inject constructor(
id = UUID.randomUUID().toString(),
uri = "",
match = null,
checksum = null,
),
)
}
@ -1571,7 +1573,12 @@ data class VaultAddEditState(
val totp: String? = null,
val canViewPassword: Boolean = true,
val uriList: List<UriItem> = listOf(
UriItem(id = UUID.randomUUID().toString(), uri = "", match = null),
UriItem(
id = UUID.randomUUID().toString(),
uri = "",
match = null,
checksum = null,
),
),
val fido2CredentialCreationDateTime: Text? = null,
) : ItemType() {

View file

@ -12,4 +12,5 @@ data class UriItem(
val id: String,
val uri: String?,
val match: UriMatchType?,
val checksum: String?,
) : Parcelable

View file

@ -47,6 +47,7 @@ fun AutofillSaveItem.toDefaultAddTypeContent(
id = UUID.randomUUID().toString(),
uri = uri,
match = null,
checksum = null,
),
),
),

View file

@ -27,6 +27,7 @@ fun AutofillSelectionData.toDefaultAddTypeContent(
id = UUID.randomUUID().toString(),
uri = uri,
match = null,
checksum = null,
),
),
)

View file

@ -272,6 +272,7 @@ private fun List<LoginUriView>?.toUriItems(): List<UriItem> =
id = UUID.randomUUID().toString(),
uri = "",
match = null,
checksum = null,
),
)
} else {
@ -280,6 +281,7 @@ private fun List<LoginUriView>?.toUriItems(): List<UriItem> =
id = UUID.randomUUID().toString(),
uri = loginUriView.uri,
match = loginUriView.match,
checksum = loginUriView.uriChecksum,
)
}
}

View file

@ -329,7 +329,8 @@ private const val CIPHER_JSON = """
"uris": [
{
"match": 1,
"uri": "mockUri-1"
"uri": "mockUri-1",
"uriChecksum": "mockUriChecksum-1"
}
],
"totp": "mockTotp-1",

View file

@ -154,4 +154,5 @@ fun createMockUri(number: Int): SyncResponseJson.Cipher.Login.Uri =
SyncResponseJson.Cipher.Login.Uri(
uri = "mockUri-$number",
uriMatchType = UriMatchTypeJson.HOST,
uriChecksum = "mockUriChecksum-$number",
)

View file

@ -306,7 +306,8 @@ private const val CREATE_ATTACHMENT_SUCCESS_JSON = """
"uris": [
{
"match": 1,
"uri": "mockUri-1"
"uri": "mockUri-1",
"uriChecksum": "mockUriChecksum-1"
}
],
"totp": "mockTotp-1",
@ -416,7 +417,8 @@ private const val CREATE_UPDATE_CIPHER_SUCCESS_JSON = """
"uris": [
{
"match": 1,
"uri": "mockUri-1"
"uri": "mockUri-1",
"uriChecksum": "mockUriChecksum-1"
}
],
"totp": "mockTotp-1",

View file

@ -222,7 +222,8 @@ private const val SYNC_SUCCESS_JSON = """
"uris": [
{
"match": 1,
"uri": "mockUri-1"
"uri": "mockUri-1",
"uriChecksum": "mockUriChecksum-1"
}
],
"totp": "mockTotp-1",

View file

@ -130,7 +130,7 @@ fun createMockUriView(number: Int): LoginUriView =
LoginUriView(
uri = "www.mockuri$number.com",
match = UriMatchType.HOST,
uriChecksum = null,
uriChecksum = "mockUriChecksum-$number",
)
/**

View file

@ -159,5 +159,5 @@ fun createMockSdkUri(number: Int): LoginUri =
LoginUri(
uri = "mockUri-$number",
match = UriMatchType.HOST,
uriChecksum = null,
uriChecksum = "mockUriChecksum-$number",
)

View file

@ -808,7 +808,11 @@ class VaultAddEditScreenTest : BaseComposeTest() {
fun `in ItemType_Login state changing URI text field should trigger UriValueChange`() {
mutableStateFlow.update { currentState ->
updateLoginType(currentState) {
copy(uriList = listOf(UriItem("TestId", "URI", null)))
copy(
uriList = listOf(
UriItem(id = "TestId", uri = "URI", match = null, checksum = null),
),
)
}
}
@ -819,7 +823,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddEditAction.ItemType.LoginType.UriValueChange(
UriItem("TestId", "TestURI", null),
UriItem(id = "TestId", uri = "TestURI", match = null, checksum = null),
),
)
}
@ -833,7 +837,11 @@ class VaultAddEditScreenTest : BaseComposeTest() {
mutableStateFlow.update { currentState ->
updateLoginType(currentState) {
copy(uriList = listOf(UriItem("TestId", "NewURI", null)))
copy(
uriList = listOf(
UriItem(id = "TestId", uri = "NewURI", match = null, checksum = null),
),
)
}
}
@ -863,7 +871,11 @@ class VaultAddEditScreenTest : BaseComposeTest() {
fun `in ItemType_Login Uri settings dialog should send RemoveUriClick action if remove is clicked`() {
mutableStateFlow.update { currentState ->
updateLoginType(currentState) {
copy(uriList = listOf(UriItem("TestId", null, null)))
copy(
uriList = listOf(
UriItem(id = "TestId", uri = null, match = null, checksum = null),
),
)
}
}
@ -883,11 +895,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddEditAction.ItemType.LoginType.RemoveUriClick(
UriItem(
"TestId",
null,
null,
),
UriItem(id = "TestId", uri = null, match = null, checksum = null),
),
)
}
@ -948,7 +956,11 @@ class VaultAddEditScreenTest : BaseComposeTest() {
fun `in ItemType_Login on URI settings click and on match detection click and option click should emit UriValueChange action`() {
mutableStateFlow.update { currentState ->
updateLoginType(currentState) {
copy(uriList = listOf(UriItem("TestId", null, null)))
copy(
uriList = listOf(
UriItem(id = "TestId", uri = null, match = null, checksum = null),
),
)
}
}
@ -978,11 +990,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
verify {
viewModel.trySendAction(
VaultAddEditAction.ItemType.LoginType.UriValueChange(
UriItem(
"TestId",
null,
UriMatchType.EXACT,
),
UriItem(id = "TestId", uri = null, match = UriMatchType.EXACT, checksum = null),
),
)
}
@ -993,7 +1001,11 @@ class VaultAddEditScreenTest : BaseComposeTest() {
fun `in ItemType_Login on URI settings click and on match detection click and cancel click should dismiss the dialog`() {
mutableStateFlow.update { currentState ->
updateLoginType(currentState) {
copy(uriList = listOf(UriItem("TestId", null, null)))
copy(
uriList = listOf(
UriItem(id = "TestId", uri = null, match = null, checksum = null),
),
)
}
}

View file

@ -482,7 +482,14 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
typeContentViewState = createLoginTypeContentViewState(
username = "mockUsername-1",
password = "mockPassword-1",
uri = listOf(UriItem("testId", "www.mockuri1.com", UriMatchType.HOST)),
uri = listOf(
UriItem(
id = "testId",
uri = "www.mockuri1.com",
match = UriMatchType.HOST,
checksum = "mockUriChecksum-1",
),
),
totpCode = "mockTotp-1",
canViewPassword = true,
fido2CredentialCreationDateTime = R.string.created_xy.asText(
@ -1354,14 +1361,15 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
}
}
@Suppress("MaxLineLength")
@Test
fun `UriValueChange should update URI value in state`() = runTest {
val viewModel = createAddVaultItemViewModel(
savedStateHandle = createSavedStateHandleWithState(
state = createVaultAddItemState(
typeContentViewState = createLoginTypeContentViewState(
uri = listOf(UriItem("testID", null, null)),
uri = listOf(
UriItem(id = "testID", uri = null, match = null, checksum = null),
),
),
),
vaultAddEditType = VaultAddEditType.EditItem(DEFAULT_EDIT_ITEM_ID),
@ -1372,28 +1380,31 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
common = createCommonContentViewState(),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(
uri = listOf(UriItem("testID", "Test", null)),
uri = listOf(
UriItem(id = "testID", uri = "Test", match = null, checksum = null),
),
),
),
)
viewModel.trySendAction(
VaultAddEditAction.ItemType.LoginType.UriValueChange(
uriItem = UriItem("testID", "Test", null),
uriItem = UriItem(id = "testID", uri = "Test", match = null, checksum = null),
),
)
assertEquals(expectedState, viewModel.stateFlow.value)
}
@Suppress("MaxLineLength")
@Test
fun `RemoveUriClick should remove URI value in state`() = runTest {
val viewModel = createAddVaultItemViewModel(
savedStateHandle = createSavedStateHandleWithState(
state = createVaultAddItemState(
typeContentViewState = createLoginTypeContentViewState(
uri = listOf(UriItem("testID", null, null)),
uri = listOf(
UriItem(id = "testID", uri = null, match = null, checksum = null),
),
),
),
vaultAddEditType = VaultAddEditType.EditItem(DEFAULT_EDIT_ITEM_ID),
@ -1412,7 +1423,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
viewModel.trySendAction(
VaultAddEditAction.ItemType.LoginType.RemoveUriClick(
uriItem = UriItem("testID", null, null),
uriItem = UriItem(id = "testID", uri = null, match = null, checksum = null),
),
)
@ -1428,7 +1439,10 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val expectedState = createVaultAddItemState(
typeContentViewState = createLoginTypeContentViewState().copy(
uriList = listOf(UriItem("testId", "", null), UriItem("testId2", "", null)),
uriList = listOf(
UriItem(id = "testId", uri = "", match = null, checksum = null),
UriItem(id = "testId2", uri = "", match = null, checksum = null),
),
),
)
@ -2391,7 +2405,9 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
private fun createLoginTypeContentViewState(
username: String = "",
password: String = "",
uri: List<UriItem> = listOf(UriItem("testId", "", null)),
uri: List<UriItem> = listOf(
UriItem(id = "testId", uri = "", match = null, checksum = null),
),
totpCode: String? = null,
canViewPassword: Boolean = true,
fido2CredentialCreationDateTime: Text? = null,

View file

@ -63,6 +63,7 @@ class AutofillSaveItemExtensionsTest {
id = "uuid",
uri = "https://www.test.com",
match = null,
checksum = null,
),
),
),

View file

@ -53,6 +53,7 @@ class AutofillSelectionDataExtensionsTest {
id = "uuid",
uri = "https://www.test.com",
match = null,
checksum = null,
),
),
),

View file

@ -192,7 +192,14 @@ class CipherViewExtensionsTest {
type = VaultAddEditState.ViewState.Content.ItemType.Login(
username = "username",
password = "password",
uriList = listOf(UriItem(TEST_ID, "www.example.com", null)),
uriList = listOf(
UriItem(
id = TEST_ID,
uri = "www.example.com",
match = null,
checksum = null,
),
),
totp = "otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example",
canViewPassword = false,
fido2CredentialCreationDateTime = R.string.created_xy.asText(

View file

@ -55,7 +55,14 @@ class VaultAddItemStateExtensionsTest {
type = VaultAddEditState.ViewState.Content.ItemType.Login(
username = "mockUsername-1",
password = "mockPassword-1",
uriList = listOf(UriItem("testId", "mockUri-1", UriMatchType.DOMAIN)),
uriList = listOf(
UriItem(
id = "testId",
uri = "mockUri-1",
match = UriMatchType.DOMAIN,
checksum = null,
),
),
totp = "otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example",
fido2CredentialCreationDateTime = null,
),
@ -138,7 +145,9 @@ class VaultAddItemStateExtensionsTest {
type = VaultAddEditState.ViewState.Content.ItemType.Login(
username = "mockUsername-1",
password = "mockPassword-1",
uriList = listOf(UriItem("TestId", "mockUri-1", null)),
uriList = listOf(
UriItem(id = "TestId", uri = "mockUri-1", match = null, checksum = null),
),
totp = "otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example",
),
)