mirror of
https://github.com/bitwarden/android.git
synced 2026-07-29 23:28:08 -05:00
Use Google's Digital Asset Links API to verify digital asset links (#5101)
This commit is contained in:
@@ -24,11 +24,9 @@ import com.x8bit.bitwarden.data.auth.util.getPasswordlessRequestDataIntentOrNull
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilitySelectionManager
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilitySelectionManagerImpl
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.manager.Fido2CredentialManager
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.manager.Fido2OriginManager
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialAssertionRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2GetCredentialsRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2ValidateOriginResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.createMockFido2CreateCredentialRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.createMockFido2CredentialAssertionRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.createMockFido2GetCredentialsRequest
|
||||
@@ -136,9 +134,6 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||
every { isUserVerified } returns true
|
||||
every { isUserVerified = any() } just runs
|
||||
}
|
||||
private val fido2OriginManager = mockk<Fido2OriginManager> {
|
||||
coEvery { validateOrigin(any(), any()) } returns Fido2ValidateOriginResult.Success(null)
|
||||
}
|
||||
private val savedStateHandle = SavedStateHandle()
|
||||
|
||||
private val appResumeManager: AppResumeManager = mockk {
|
||||
@@ -749,12 +744,6 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||
val mockIntent = createMockIntent(
|
||||
mockFido2CreateCredentialRequest = fido2CreateCredentialRequest,
|
||||
)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = any(),
|
||||
relyingPartyId = any(),
|
||||
)
|
||||
} returns Fido2ValidateOriginResult.Success(null)
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveFirstIntent(
|
||||
@@ -780,12 +769,6 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||
val mockIntent = createMockIntent(
|
||||
mockFido2CreateCredentialRequest = fido2CreateCredentialRequest,
|
||||
)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = any(),
|
||||
relyingPartyId = any(),
|
||||
)
|
||||
} returns Fido2ValidateOriginResult.Success(null)
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveFirstIntent(
|
||||
|
||||
-19
@@ -454,25 +454,6 @@ class Fido2CredentialManagerTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `registerFido2Credential should return InvalidAppSignature when calling app is not privileged and signature is invalid`() =
|
||||
runTest {
|
||||
every { mockCallingAppInfo.isOriginPopulated() } returns false
|
||||
every { mockSigningInfo.hasMultipleSigners() } returns true
|
||||
val result = fido2CredentialManager.registerFido2Credential(
|
||||
userId = "mockUserId",
|
||||
callingAppInfo = mockCallingAppInfo,
|
||||
createPublicKeyCredentialRequest = mockCreatePublicKeyCredentialRequest,
|
||||
selectedCipherView = createMockCipherView(number = 1),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
Fido2RegisterCredentialResult.Error.InvalidAppSignature,
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `registerFido2Credential should return MissingHostUrl when calling app if privileged and origin is missing`() =
|
||||
|
||||
+28
-87
@@ -5,7 +5,7 @@ import android.util.Base64
|
||||
import androidx.credentials.provider.CallingAppInfo
|
||||
import com.bitwarden.core.data.util.asFailure
|
||||
import com.bitwarden.core.data.util.asSuccess
|
||||
import com.bitwarden.network.model.DigitalAssetLinkResponseJson
|
||||
import com.bitwarden.network.model.DigitalAssetLinkCheckResponseJson
|
||||
import com.bitwarden.network.service.DigitalAssetLinkService
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2ValidateOriginResult
|
||||
import com.x8bit.bitwarden.data.platform.manager.AssetManager
|
||||
@@ -76,7 +76,6 @@ class Fido2OriginManagerTest {
|
||||
|
||||
val result = fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = mockPrivilegedAppInfo,
|
||||
relyingPartyId = "relyingPartyId",
|
||||
)
|
||||
coVerify(exactly = 1) {
|
||||
mockAssetManager.readAsset(GOOGLE_ALLOW_LIST_FILENAME)
|
||||
@@ -100,7 +99,6 @@ class Fido2OriginManagerTest {
|
||||
|
||||
val result = fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = mockPrivilegedAppInfo,
|
||||
relyingPartyId = "relyingPartyId",
|
||||
)
|
||||
coVerify(exactly = 1) {
|
||||
mockAssetManager.readAsset(GOOGLE_ALLOW_LIST_FILENAME)
|
||||
@@ -125,7 +123,6 @@ class Fido2OriginManagerTest {
|
||||
|
||||
val result = fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = mockPrivilegedAppInfo,
|
||||
relyingPartyId = "relyingPartyId",
|
||||
)
|
||||
|
||||
coVerify(exactly = 1) {
|
||||
@@ -143,12 +140,15 @@ class Fido2OriginManagerTest {
|
||||
fun `validateOrigin should return Success when calling app is NonPrivileged and has a valid asset link entry`() =
|
||||
runTest {
|
||||
coEvery {
|
||||
mockDigitalAssetLinkService.getDigitalAssetLinkForRp(relyingParty = DEFAULT_RP_ID)
|
||||
} returns listOf(DEFAULT_STATEMENT).asSuccess()
|
||||
mockDigitalAssetLinkService.checkDigitalAssetLinksRelations(
|
||||
packageName = DEFAULT_PACKAGE_NAME,
|
||||
certificateFingerprint = DEFAULT_CERT_FINGERPRINT,
|
||||
relation = "delegate_permission/common.handle_all_urls",
|
||||
)
|
||||
} returns DEFAULT_ASSET_LINKS_CHECK_RESPONSE.asSuccess()
|
||||
|
||||
val result = fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = mockNonPrivilegedAppInfo,
|
||||
relyingPartyId = DEFAULT_RP_ID,
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
@@ -159,49 +159,21 @@ class Fido2OriginManagerTest {
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `validateOrigin should return ApplicationFingerprintNotVerified when calling app is NonPrivileged but signature does not match asset link entry`() =
|
||||
fun `validateOrigin should return PasskeysNotSupportedForApp when calling app is NonPrivileged but signature does not match asset link entry`() =
|
||||
runTest {
|
||||
coEvery {
|
||||
mockDigitalAssetLinkService.getDigitalAssetLinkForRp(relyingParty = DEFAULT_RP_ID)
|
||||
} returns listOf(
|
||||
DEFAULT_STATEMENT.copy(
|
||||
target = DEFAULT_STATEMENT.target.copy(
|
||||
sha256CertFingerprints = listOf("invalid_fingerprint"),
|
||||
),
|
||||
),
|
||||
)
|
||||
mockDigitalAssetLinkService.checkDigitalAssetLinksRelations(
|
||||
packageName = DEFAULT_PACKAGE_NAME,
|
||||
certificateFingerprint = DEFAULT_CERT_FINGERPRINT,
|
||||
relation = "delegate_permission/common.handle_all_urls",
|
||||
)
|
||||
} returns DEFAULT_ASSET_LINKS_CHECK_RESPONSE
|
||||
.copy(linked = false)
|
||||
.asSuccess()
|
||||
|
||||
assertEquals(
|
||||
Fido2ValidateOriginResult.Error.ApplicationFingerprintNotVerified,
|
||||
fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = mockNonPrivilegedAppInfo,
|
||||
relyingPartyId = DEFAULT_RP_ID,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `validateOrigin should return ApplicationNotFound when calling app is NonPrivileged and packageName has no asset link entry`() =
|
||||
runTest {
|
||||
coEvery {
|
||||
mockDigitalAssetLinkService.getDigitalAssetLinkForRp(relyingParty = DEFAULT_RP_ID)
|
||||
} returns listOf(
|
||||
DEFAULT_STATEMENT.copy(
|
||||
target = DEFAULT_STATEMENT.target.copy(
|
||||
packageName = "invalid_package_name",
|
||||
),
|
||||
),
|
||||
)
|
||||
.asSuccess()
|
||||
|
||||
assertEquals(
|
||||
Fido2ValidateOriginResult.Error.ApplicationNotFound,
|
||||
fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = mockNonPrivilegedAppInfo,
|
||||
relyingPartyId = DEFAULT_RP_ID,
|
||||
),
|
||||
Fido2ValidateOriginResult.Error.PasskeyNotSupportedForApp,
|
||||
fido2OriginManager.validateOrigin(callingAppInfo = mockNonPrivilegedAppInfo),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -210,35 +182,16 @@ class Fido2OriginManagerTest {
|
||||
fun `validateOrigin should return AssetLinkNotFound when calling app is NonPrivileged and asset link does not exist`() =
|
||||
runTest {
|
||||
coEvery {
|
||||
mockDigitalAssetLinkService.getDigitalAssetLinkForRp(relyingParty = DEFAULT_RP_ID)
|
||||
mockDigitalAssetLinkService.checkDigitalAssetLinksRelations(
|
||||
packageName = DEFAULT_PACKAGE_NAME,
|
||||
certificateFingerprint = DEFAULT_CERT_FINGERPRINT,
|
||||
relation = "delegate_permission/common.handle_all_urls",
|
||||
)
|
||||
} returns RuntimeException().asFailure()
|
||||
|
||||
assertEquals(
|
||||
Fido2ValidateOriginResult.Error.AssetLinkNotFound,
|
||||
fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = mockNonPrivilegedAppInfo,
|
||||
relyingPartyId = DEFAULT_RP_ID,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `validateOrigin should return Unknown error when calling app is NonPrivileged and exception is caught while filtering asset links`() =
|
||||
runTest {
|
||||
coEvery {
|
||||
mockDigitalAssetLinkService.getDigitalAssetLinkForRp(relyingParty = DEFAULT_RP_ID)
|
||||
} returns listOf(DEFAULT_STATEMENT).asSuccess()
|
||||
every {
|
||||
mockNonPrivilegedAppInfo.packageName
|
||||
} throws IllegalStateException()
|
||||
|
||||
assertEquals(
|
||||
Fido2ValidateOriginResult.Error.Unknown,
|
||||
fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = mockNonPrivilegedAppInfo,
|
||||
relyingPartyId = DEFAULT_RP_ID,
|
||||
),
|
||||
fido2OriginManager.validateOrigin(callingAppInfo = mockNonPrivilegedAppInfo),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -246,9 +199,6 @@ class Fido2OriginManagerTest {
|
||||
@Test
|
||||
fun `validateOrigin should return Unknown error when calling app is Privileged and allow list file read fails`() =
|
||||
runTest {
|
||||
coEvery {
|
||||
mockDigitalAssetLinkService.getDigitalAssetLinkForRp(relyingParty = DEFAULT_RP_ID)
|
||||
} returns listOf(DEFAULT_STATEMENT).asSuccess()
|
||||
coEvery {
|
||||
mockAssetManager.readAsset(GOOGLE_ALLOW_LIST_FILENAME)
|
||||
} returns IllegalStateException().asFailure()
|
||||
@@ -260,7 +210,6 @@ class Fido2OriginManagerTest {
|
||||
Fido2ValidateOriginResult.Error.Unknown,
|
||||
fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = mockPrivilegedAppInfo,
|
||||
relyingPartyId = DEFAULT_RP_ID,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -269,7 +218,6 @@ class Fido2OriginManagerTest {
|
||||
private const val DEFAULT_PACKAGE_NAME = "com.x8bit.bitwarden"
|
||||
private const val DEFAULT_APP_SIGNATURE = "0987654321ABCDEF"
|
||||
private const val DEFAULT_CERT_FINGERPRINT = "30:39:38:37:36:35:34:33:32:31:41:42:43:44:45:46"
|
||||
private const val DEFAULT_RP_ID = "bitwarden.com"
|
||||
private const val DEFAULT_ORIGIN = "bitwarden.com"
|
||||
private const val GOOGLE_ALLOW_LIST_FILENAME = "fido2_privileged_google.json"
|
||||
private const val COMMUNITY_ALLOW_LIST_FILENAME = "fido2_privileged_community.json"
|
||||
@@ -317,16 +265,9 @@ private const val FAIL_ALLOW_LIST = """
|
||||
]
|
||||
}
|
||||
"""
|
||||
private val DEFAULT_STATEMENT = DigitalAssetLinkResponseJson(
|
||||
relation = listOf(
|
||||
"delegate_permission/common.get_login_creds",
|
||||
"delegate_permission/common.handle_all_urls",
|
||||
),
|
||||
target = DigitalAssetLinkResponseJson.Target(
|
||||
namespace = "android_app",
|
||||
packageName = DEFAULT_PACKAGE_NAME,
|
||||
sha256CertFingerprints = listOf(
|
||||
DEFAULT_CERT_FINGERPRINT,
|
||||
),
|
||||
),
|
||||
private val DEFAULT_ASSET_LINKS_CHECK_RESPONSE =
|
||||
DigitalAssetLinkCheckResponseJson(
|
||||
linked = true,
|
||||
maxAge = "30s",
|
||||
debugString = null,
|
||||
)
|
||||
|
||||
+14
-149
@@ -198,7 +198,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
} returns UserVerificationRequirement.PREFERRED
|
||||
}
|
||||
private val fido2OriginManager: Fido2OriginManager = mockk {
|
||||
coEvery { validateOrigin(any(), any()) } returns Fido2ValidateOriginResult.Success(null)
|
||||
coEvery { validateOrigin(any()) } returns Fido2ValidateOriginResult.Success(null)
|
||||
}
|
||||
|
||||
private val organizationEventManager = mockk<OrganizationEventManager> {
|
||||
@@ -289,7 +289,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
fido2CredentialManager.getPasskeyAttestationOptionsOrNull(any())
|
||||
} returns createMockPasskeyAttestationOptions(number = 1)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
fido2OriginManager.validateOrigin(any())
|
||||
} returns Fido2ValidateOriginResult.Success(null)
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
@@ -1871,7 +1871,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
)
|
||||
} returns DecryptFido2CredentialAutofillViewResult.Success(emptyList())
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
fido2OriginManager.validateOrigin(any())
|
||||
} returns Fido2ValidateOriginResult.Success("")
|
||||
|
||||
mockFilteredCiphers = listOf(cipherView1)
|
||||
@@ -1925,7 +1925,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
vaultRepository.getDecryptedFido2CredentialAutofillViews(
|
||||
cipherViewList = listOf(cipherView1, cipherView2),
|
||||
)
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
fido2OriginManager.validateOrigin(any())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2594,16 +2594,13 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
fido2CredentialManager.getPasskeyAttestationOptionsOrNull(any())
|
||||
} returns mockk(relaxed = true)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = any(),
|
||||
relyingPartyId = any(),
|
||||
)
|
||||
fido2OriginManager.validateOrigin(callingAppInfo = any())
|
||||
} returns Fido2ValidateOriginResult.Success("mockOrigin")
|
||||
|
||||
createVaultItemListingViewModel()
|
||||
|
||||
coVerify(ordering = Ordering.ORDERED) {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
fido2OriginManager.validateOrigin(any())
|
||||
vaultRepository.vaultDataStateFlow
|
||||
}
|
||||
}
|
||||
@@ -2631,7 +2628,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
fido2CredentialManager.getPasskeyAttestationOptionsOrNull(any())
|
||||
} returns mockk(relaxed = true)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
fido2OriginManager.validateOrigin(any())
|
||||
} returns Fido2ValidateOriginResult.Error.Unknown
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
@@ -2670,7 +2667,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
fido2CredentialManager.getPasskeyAttestationOptionsOrNull(any())
|
||||
} returns mockk(relaxed = true)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
fido2OriginManager.validateOrigin(any())
|
||||
} returns Fido2ValidateOriginResult.Error.PrivilegedAppNotAllowed
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
@@ -2709,7 +2706,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
fido2CredentialManager.getPasskeyAttestationOptionsOrNull(any())
|
||||
} returns mockk(relaxed = true)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
fido2OriginManager.validateOrigin(any())
|
||||
} returns Fido2ValidateOriginResult.Error.PrivilegedAppSignatureNotFound
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
@@ -2748,7 +2745,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
fido2CredentialManager.getPasskeyAttestationOptionsOrNull(any())
|
||||
} returns mockk(relaxed = true)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
fido2OriginManager.validateOrigin(any())
|
||||
} returns Fido2ValidateOriginResult.Error.PasskeyNotSupportedForApp
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
@@ -2762,45 +2759,6 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `Fido2ValidateOriginResult should update dialog state on ApplicationNotFound error`() =
|
||||
runTest {
|
||||
val fido2CreateCredentialRequest = Fido2CreateCredentialRequest(
|
||||
userId = "mockUserId",
|
||||
isUserPreVerified = false,
|
||||
requestData = bundleOf(),
|
||||
)
|
||||
|
||||
specialCircumstanceManager.specialCircumstance = SpecialCircumstance.Fido2Save(
|
||||
fido2CreateCredentialRequest = fido2CreateCredentialRequest,
|
||||
)
|
||||
|
||||
every {
|
||||
ProviderCreateCredentialRequest.fromBundle(any())
|
||||
} returns mockk(relaxed = true) {
|
||||
every {
|
||||
callingRequest
|
||||
} returns mockk<CreatePublicKeyCredentialRequest>(relaxed = true)
|
||||
}
|
||||
every {
|
||||
fido2CredentialManager.getPasskeyAttestationOptionsOrNull(any())
|
||||
} returns mockk(relaxed = true)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
} returns Fido2ValidateOriginResult.Error.ApplicationNotFound
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
VaultItemListingState.DialogState.Fido2OperationFail(
|
||||
R.string.an_error_has_occurred.asText(),
|
||||
R.string.passkey_operation_failed_because_app_not_found_in_asset_links.asText(),
|
||||
),
|
||||
viewModel.stateFlow.value.dialogState,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `Fido2ValidateOriginResult should update dialog state on AssetLinkNotFound error`() =
|
||||
@@ -2826,7 +2784,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
fido2CredentialManager.getPasskeyAttestationOptionsOrNull(any())
|
||||
} returns mockk(relaxed = true)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
fido2OriginManager.validateOrigin(any())
|
||||
} returns Fido2ValidateOriginResult.Error.AssetLinkNotFound
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
@@ -2840,45 +2798,6 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `Fido2ValidateOriginResult should update dialog state on ApplicationNotVerified error`() =
|
||||
runTest {
|
||||
val fido2CreateCredentialRequest = Fido2CreateCredentialRequest(
|
||||
userId = "mockUserId",
|
||||
isUserPreVerified = false,
|
||||
requestData = bundleOf(),
|
||||
)
|
||||
|
||||
specialCircumstanceManager.specialCircumstance = SpecialCircumstance.Fido2Save(
|
||||
fido2CreateCredentialRequest = fido2CreateCredentialRequest,
|
||||
)
|
||||
|
||||
every {
|
||||
ProviderCreateCredentialRequest.fromBundle(any())
|
||||
} returns mockk(relaxed = true) {
|
||||
every {
|
||||
callingRequest
|
||||
} returns mockk<CreatePublicKeyCredentialRequest>(relaxed = true)
|
||||
}
|
||||
every {
|
||||
fido2CredentialManager.getPasskeyAttestationOptionsOrNull(any())
|
||||
} returns mockk(relaxed = true)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
} returns Fido2ValidateOriginResult.Error.ApplicationFingerprintNotVerified
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
VaultItemListingState.DialogState.Fido2OperationFail(
|
||||
R.string.an_error_has_occurred.asText(),
|
||||
R.string.passkey_operation_failed_because_app_could_not_be_verified.asText(),
|
||||
),
|
||||
viewModel.stateFlow.value.dialogState,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `Fido2RegisterCredentialResult Error should show toast and emit CompleteFido2Registration result`() =
|
||||
@@ -3038,10 +2957,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
fido2CredentialManager.getPasskeyAssertionOptionsOrNull(any())
|
||||
} returns mockk(relaxed = true)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = any(),
|
||||
relyingPartyId = any(),
|
||||
)
|
||||
fido2OriginManager.validateOrigin(callingAppInfo = any())
|
||||
} returns Fido2ValidateOriginResult.Success("mockOrigin")
|
||||
every {
|
||||
vaultRepository
|
||||
@@ -3247,10 +3163,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
fido2CredentialManager.getPasskeyAssertionOptionsOrNull(any())
|
||||
} returns mockk(relaxed = true)
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(
|
||||
callingAppInfo = any(),
|
||||
relyingPartyId = any(),
|
||||
)
|
||||
fido2OriginManager.validateOrigin(callingAppInfo = any())
|
||||
} returns Fido2ValidateOriginResult.Error.Unknown
|
||||
|
||||
val dataState = DataState.Loaded(
|
||||
@@ -3463,54 +3376,6 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Fido2AssertionRequest should show error dialog when relyingPartyId is null`() = runTest {
|
||||
setupMockUri()
|
||||
val mockAssertionRequest = createMockFido2CredentialAssertionRequest(number = 1)
|
||||
.copy(cipherId = "mockId-1")
|
||||
val mockFido2CredentialList = createMockSdkFido2CredentialList(number = 1)
|
||||
val mockCipherView = createMockCipherView(
|
||||
number = 1,
|
||||
fido2Credentials = mockFido2CredentialList,
|
||||
)
|
||||
specialCircumstanceManager.specialCircumstance = SpecialCircumstance.Fido2Assertion(
|
||||
mockAssertionRequest,
|
||||
)
|
||||
every {
|
||||
vaultRepository
|
||||
.ciphersStateFlow
|
||||
.value
|
||||
.data
|
||||
} returns listOf(mockCipherView)
|
||||
every { fido2CredentialManager.isUserVerified } returns true
|
||||
every {
|
||||
fido2CredentialManager.getPasskeyAssertionOptionsOrNull(any())
|
||||
} returns createMockPasskeyAssertionOptions(
|
||||
number = 1,
|
||||
userVerificationRequirement = UserVerificationRequirement.DISCOURAGED,
|
||||
relyingPartyId = null,
|
||||
)
|
||||
|
||||
val dataState = DataState.Loaded(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(mockCipherView),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
collectionViewList = listOf(createMockCollectionView(number = 1)),
|
||||
sendViewList = listOf(createMockSendView(number = 1)),
|
||||
),
|
||||
)
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
mutableVaultDataStateFlow.value = dataState
|
||||
|
||||
assertEquals(
|
||||
VaultItemListingState.DialogState.Fido2OperationFail(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
message = R.string.passkey_operation_failed_because_the_request_is_invalid.asText(),
|
||||
),
|
||||
viewModel.stateFlow.value.dialogState,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Fido2AssertionRequest should show error dialog when validateOrigin is not Success`() =
|
||||
runTest {
|
||||
@@ -3540,7 +3405,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
fido2CredentialManager.getPasskeyAssertionOptionsOrNull(any())
|
||||
} returns mockAssertionOptions
|
||||
coEvery {
|
||||
fido2OriginManager.validateOrigin(any(), any())
|
||||
fido2OriginManager.validateOrigin(any())
|
||||
} returns Fido2ValidateOriginResult.Error.Unknown
|
||||
|
||||
val dataState = DataState.Loaded(
|
||||
|
||||
Reference in New Issue
Block a user