[PM-24411] Extract pending intent management for Credential Manager requests (#5636)

This commit is contained in:
Patrick Honkonen 2025-08-05 10:04:12 -04:00 committed by GitHub
parent 38b92133ff
commit f4c4e06dcc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 229 additions and 245 deletions

View File

@ -12,19 +12,16 @@ import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.vault.CipherListView
import com.x8bit.bitwarden.data.autofill.util.login
import com.x8bit.bitwarden.data.credentials.processor.GET_PASSKEY_INTENT
import com.x8bit.bitwarden.data.credentials.processor.GET_PASSWORD_INTENT
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManager
import com.x8bit.bitwarden.data.credentials.util.setBiometricPromptDataIfSupported
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import kotlin.random.Random
/**
* Primary implementation of [CredentialEntryBuilder].
*/
class CredentialEntryBuilderImpl(
private val context: Context,
private val intentManager: IntentManager,
private val pendingIntentManager: CredentialManagerPendingIntentManager,
private val biometricsEncryptionManager: BiometricsEncryptionManager,
) : CredentialEntryBuilder {
@ -69,15 +66,12 @@ class CredentialEntryBuilderImpl(
context = context,
username = fido2AutofillView.userNameForUi
?: context.getString(BitwardenString.no_username),
pendingIntent = intentManager
.createFido2GetCredentialPendingIntent(
action = GET_PASSKEY_INTENT,
userId = userId,
credentialId = fido2AutofillView.credentialId.toString(),
cipherId = fido2AutofillView.cipherId,
isUserVerified = isUserVerified,
requestCode = Random.nextInt(),
),
pendingIntent = pendingIntentManager.createFido2GetCredentialPendingIntent(
userId = userId,
credentialId = fido2AutofillView.credentialId.toString(),
cipherId = fido2AutofillView.cipherId,
isUserVerified = isUserVerified,
),
beginGetPublicKeyCredentialOption = option,
)
.setIcon(
@ -106,14 +100,11 @@ class CredentialEntryBuilderImpl(
context = context,
username = cipherView.login?.username
?: context.getString(BitwardenString.no_username),
pendingIntent = intentManager
.createPasswordGetCredentialPendingIntent(
action = GET_PASSWORD_INTENT,
userId = userId,
cipherId = cipherView.id,
isUserVerified = isUserVerified,
requestCode = Random.nextInt(),
),
pendingIntent = pendingIntentManager.createPasswordGetCredentialPendingIntent(
userId = userId,
cipherId = cipherView.id,
isUserVerified = isUserVerified,
),
beginGetPasswordOption = option,
)
.setDisplayName(cipherView.name)

View File

@ -12,6 +12,8 @@ import com.x8bit.bitwarden.data.credentials.builder.CredentialEntryBuilderImpl
import com.x8bit.bitwarden.data.credentials.datasource.disk.PrivilegedAppDiskSource
import com.x8bit.bitwarden.data.credentials.manager.BitwardenCredentialManager
import com.x8bit.bitwarden.data.credentials.manager.BitwardenCredentialManagerImpl
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManager
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManagerImpl
import com.x8bit.bitwarden.data.credentials.manager.OriginManager
import com.x8bit.bitwarden.data.credentials.manager.OriginManagerImpl
import com.x8bit.bitwarden.data.credentials.parser.RelyingPartyParser
@ -26,7 +28,6 @@ import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.ciphermatching.CipherMatchingManager
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -51,7 +52,7 @@ object CredentialProviderModule {
authRepository: AuthRepository,
bitwardenCredentialManager: BitwardenCredentialManager,
dispatcherManager: DispatcherManager,
intentManager: IntentManager,
pendingIntentManager: CredentialManagerPendingIntentManager,
biometricsEncryptionManager: BiometricsEncryptionManager,
clock: Clock,
): CredentialProviderProcessor =
@ -59,7 +60,7 @@ object CredentialProviderModule {
context = context,
authRepository = authRepository,
bitwardenCredentialManager = bitwardenCredentialManager,
intentManager = intentManager,
pendingIntentManager = pendingIntentManager,
clock = clock,
biometricsEncryptionManager = biometricsEncryptionManager,
dispatcherManager = dispatcherManager,
@ -105,11 +106,11 @@ object CredentialProviderModule {
@Singleton
fun provideCredentialEntryBuilder(
@ApplicationContext context: Context,
intentManager: IntentManager,
pendingIntentManager: CredentialManagerPendingIntentManager,
biometricsEncryptionManager: BiometricsEncryptionManager,
): CredentialEntryBuilder = CredentialEntryBuilderImpl(
context = context,
intentManager = intentManager,
pendingIntentManager = pendingIntentManager,
biometricsEncryptionManager = biometricsEncryptionManager,
)
@ -132,4 +133,13 @@ object CredentialProviderModule {
fun provideRelyingPartyParser(
json: Json,
): RelyingPartyParser = RelyingPartyParserImpl(json)
@Provides
@Singleton
fun provideCredentialManagerPendingIntentManager(
@ApplicationContext context: Context,
): CredentialManagerPendingIntentManager =
CredentialManagerPendingIntentManagerImpl(
context = context,
)
}

View File

@ -0,0 +1,69 @@
package com.x8bit.bitwarden.data.credentials.manager
import android.app.PendingIntent
/**
* Key for the user id included in Credential provider "create entries".
*
* @see CredentialManagerPendingIntentManager.createFido2CreationPendingIntent
*/
const val EXTRA_KEY_USER_ID: String = "user_id"
/**
* Key for the credential id included in FIDO 2 provider "get entries".
*
* @see CredentialManagerPendingIntentManager.createFido2GetCredentialPendingIntent
*/
const val EXTRA_KEY_CREDENTIAL_ID: String = "credential_id"
/**
* Key for the cipher id included in FIDO 2 provider "get entries".
*
* @see CredentialManagerPendingIntentManager.createFido2GetCredentialPendingIntent
*/
const val EXTRA_KEY_CIPHER_ID: String = "cipher_id"
/**
* Key for the user verification performed during vault unlock while
* processing a Credential request.
*/
const val EXTRA_KEY_UV_PERFORMED_DURING_UNLOCK: String = "uv_performed_during_unlock"
/**
* A manager class for creating pending intents used in credential management operations.
*/
interface CredentialManagerPendingIntentManager {
/**
* Creates a pending intent to use when providing options for FIDO 2 credential creation.
*/
fun createFido2CreationPendingIntent(
userId: String,
): PendingIntent
/**
* Creates a pending intent to use when providing options for FIDO 2 credential filling.
*/
fun createFido2GetCredentialPendingIntent(
userId: String,
credentialId: String,
cipherId: String,
isUserVerified: Boolean,
): PendingIntent
/**
* Creates a pending intent to use when providing unlock options for FIDO 2 credential filling.
*/
fun createFido2UnlockPendingIntent(
userId: String,
): PendingIntent
/**
* Creates a pending intent to use when providing options for Password credential filling.
*/
fun createPasswordGetCredentialPendingIntent(
userId: String,
cipherId: String?,
isUserVerified: Boolean,
): PendingIntent
}

View File

@ -0,0 +1,104 @@
package com.x8bit.bitwarden.data.credentials.manager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import com.bitwarden.annotation.OmitFromCoverage
import com.x8bit.bitwarden.data.autofill.util.toPendingIntentMutabilityFlag
import kotlin.random.Random
/**
* Primary implementation of [CredentialManagerPendingIntentManager].
*/
@OmitFromCoverage
class CredentialManagerPendingIntentManagerImpl(
private val context: Context,
) : CredentialManagerPendingIntentManager {
/**
* Creates a pending intent to use when providing options for FIDO 2 credential creation.
*/
override fun createFido2CreationPendingIntent(
userId: String,
): PendingIntent {
val intent = Intent(CREATE_PASSKEY_ACTION)
.setPackage(context.packageName)
.putExtra(EXTRA_KEY_USER_ID, userId)
return PendingIntent.getActivity(
/* context = */ context,
/* requestCode = */ Random.nextInt(),
/* intent = */ intent,
/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT.toPendingIntentMutabilityFlag(),
)
}
/**
* Creates a pending intent to use when providing options for FIDO 2 credential filling.
*/
override fun createFido2GetCredentialPendingIntent(
userId: String,
credentialId: String,
cipherId: String,
isUserVerified: Boolean,
): PendingIntent {
val intent = Intent(GET_PASSKEY_ACTION)
.setPackage(context.packageName)
.putExtra(EXTRA_KEY_USER_ID, userId)
.putExtra(EXTRA_KEY_CREDENTIAL_ID, credentialId)
.putExtra(EXTRA_KEY_CIPHER_ID, cipherId)
.putExtra(EXTRA_KEY_UV_PERFORMED_DURING_UNLOCK, isUserVerified)
return PendingIntent.getActivity(
/* context = */ context,
/* requestCode = */ Random.nextInt(),
/* intent = */ intent,
/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT.toPendingIntentMutabilityFlag(),
)
}
/**
* Creates a pending intent to use when providing unlock options for FIDO 2 credential filling.
*/
override fun createFido2UnlockPendingIntent(
userId: String,
): PendingIntent {
val intent = Intent(UNLOCK_ACCOUNT_ACTION)
.setPackage(context.packageName)
.putExtra(EXTRA_KEY_USER_ID, userId)
return PendingIntent.getActivity(
/* context = */ context,
/* requestCode = */ Random.nextInt(),
/* intent = */ intent,
/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT.toPendingIntentMutabilityFlag(),
)
}
/**
* Creates a pending intent to use when providing options for Password credential filling.
*/
override fun createPasswordGetCredentialPendingIntent(
userId: String,
cipherId: String?,
isUserVerified: Boolean,
): PendingIntent {
val intent = Intent(GET_PASSWORD_ACTION)
.setPackage(context.packageName)
.putExtra(EXTRA_KEY_USER_ID, userId)
.putExtra(EXTRA_KEY_CIPHER_ID, cipherId)
.putExtra(EXTRA_KEY_UV_PERFORMED_DURING_UNLOCK, isUserVerified)
return PendingIntent.getActivity(
/* context = */ context,
/* requestCode = */ Random.nextInt(),
/* intent = */ intent,
/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT.toPendingIntentMutabilityFlag(),
)
}
}
private const val CREATE_PASSKEY_ACTION = "com.x8bit.bitwarden.credentials.ACTION_CREATE_PASSKEY"
private const val UNLOCK_ACCOUNT_ACTION = "com.x8bit.bitwarden.credentials.ACTION_UNLOCK_ACCOUNT"
private const val GET_PASSKEY_ACTION = "com.x8bit.bitwarden.credentials.ACTION_GET_PASSKEY"
private const val GET_PASSWORD_ACTION = "com.x8bit.bitwarden.credentials.ACTION_GET_PASSWORD"

View File

@ -31,20 +31,14 @@ import com.bitwarden.ui.platform.resource.BitwardenString
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.data.credentials.manager.BitwardenCredentialManager
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManager
import com.x8bit.bitwarden.data.credentials.model.GetCredentialsRequest
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.time.Clock
import java.util.concurrent.atomic.AtomicInteger
import javax.crypto.Cipher
private const val CREATE_PASSKEY_INTENT = "com.x8bit.bitwarden.credentials.ACTION_CREATE_PASSKEY"
const val GET_PASSKEY_INTENT = "com.x8bit.bitwarden.credentials.ACTION_GET_PASSKEY"
const val GET_PASSWORD_INTENT = "com.x8bit.bitwarden.credentials.ACTION_GET_PASSWORD"
const val UNLOCK_ACCOUNT_INTENT = "com.x8bit.bitwarden.credentials.ACTION_UNLOCK_ACCOUNT"
/**
* The default implementation of [CredentialProviderProcessor]. Its purpose is to handle
* [CredentialManager] requests from other applications.
@ -55,13 +49,12 @@ class CredentialProviderProcessorImpl(
private val context: Context,
private val authRepository: AuthRepository,
private val bitwardenCredentialManager: BitwardenCredentialManager,
private val intentManager: IntentManager,
private val pendingIntentManager: CredentialManagerPendingIntentManager,
private val clock: Clock,
private val biometricsEncryptionManager: BiometricsEncryptionManager,
dispatcherManager: DispatcherManager,
) : CredentialProviderProcessor {
private val requestCode = AtomicInteger()
private val ioScope = CoroutineScope(dispatcherManager.io)
override fun processCreateCredentialRequest(
@ -104,10 +97,8 @@ class CredentialProviderProcessorImpl(
if (!userState.activeAccount.isVaultUnlocked) {
val authenticationAction = AuthenticationAction(
title = context.getString(BitwardenString.unlock),
pendingIntent = intentManager.createFido2UnlockPendingIntent(
action = UNLOCK_ACCOUNT_INTENT,
pendingIntent = pendingIntentManager.createFido2UnlockPendingIntent(
userId = userState.activeUserId,
requestCode = requestCode.getAndIncrement(),
),
)
@ -182,10 +173,8 @@ class CredentialProviderProcessorImpl(
val entryBuilder = CreateEntry
.Builder(
accountName = accountName,
pendingIntent = intentManager.createFido2CreationPendingIntent(
action = CREATE_PASSKEY_INTENT,
pendingIntent = pendingIntentManager.createFido2CreationPendingIntent(
userId = userId,
requestCode = requestCode.getAndIncrement(),
),
)
.setDescription(

View File

@ -8,14 +8,14 @@ import androidx.credentials.provider.PendingIntentHandler
import androidx.credentials.provider.ProviderCreateCredentialRequest
import androidx.credentials.provider.ProviderGetCredentialRequest
import com.bitwarden.core.util.isBuildVersionAtLeast
import com.x8bit.bitwarden.data.credentials.manager.EXTRA_KEY_CIPHER_ID
import com.x8bit.bitwarden.data.credentials.manager.EXTRA_KEY_CREDENTIAL_ID
import com.x8bit.bitwarden.data.credentials.manager.EXTRA_KEY_USER_ID
import com.x8bit.bitwarden.data.credentials.manager.EXTRA_KEY_UV_PERFORMED_DURING_UNLOCK
import com.x8bit.bitwarden.data.credentials.model.CreateCredentialRequest
import com.x8bit.bitwarden.data.credentials.model.Fido2CredentialAssertionRequest
import com.x8bit.bitwarden.data.credentials.model.GetCredentialsRequest
import com.x8bit.bitwarden.data.credentials.model.ProviderGetPasswordCredentialRequest
import com.x8bit.bitwarden.ui.platform.manager.intent.EXTRA_KEY_CIPHER_ID
import com.x8bit.bitwarden.ui.platform.manager.intent.EXTRA_KEY_CREDENTIAL_ID
import com.x8bit.bitwarden.ui.platform.manager.intent.EXTRA_KEY_USER_ID
import com.x8bit.bitwarden.ui.platform.manager.intent.EXTRA_KEY_UV_PERFORMED_DURING_UNLOCK
/**
* Checks if this [Intent] contains a [CreateCredentialRequest] related to an ongoing

View File

@ -1,6 +1,5 @@
package com.x8bit.bitwarden.ui.platform.manager.intent
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.net.Uri
@ -9,9 +8,6 @@ import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.result.ActivityResult
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.credentials.provider.AuthenticationAction
import androidx.credentials.provider.CreateEntry
import androidx.credentials.provider.CredentialEntry
import com.x8bit.bitwarden.data.autofill.model.browser.BrowserPackage
import kotlinx.parcelize.Parcelize
@ -106,52 +102,6 @@ interface IntentManager {
*/
fun createDocumentIntent(fileName: String): Intent
/**
* Creates a pending intent to use when providing [CreateEntry]
* instances for FIDO 2 credential creation.
*/
fun createFido2CreationPendingIntent(
action: String,
userId: String,
requestCode: Int,
): PendingIntent
/**
* Creates a pending intent to use when providing
* [CredentialEntry] instances for FIDO 2 credential filling.
*/
@Suppress("LongParameterList")
fun createFido2GetCredentialPendingIntent(
action: String,
userId: String,
credentialId: String,
cipherId: String,
isUserVerified: Boolean,
requestCode: Int,
): PendingIntent
/**
* Creates a pending intent to use when providing
* [AuthenticationAction] instances for FIDO 2 credential filling.
*/
fun createFido2UnlockPendingIntent(
action: String,
userId: String,
requestCode: Int,
): PendingIntent
/**
* Creates a pending intent to use when providing
* [CredentialEntry] instances for Password credential filling.
*/
fun createPasswordGetCredentialPendingIntent(
action: String,
userId: String,
cipherId: String?,
isUserVerified: Boolean,
requestCode: Int,
): PendingIntent
/**
* Open the default email app on device.
*/

View File

@ -1,7 +1,6 @@
package com.x8bit.bitwarden.ui.platform.manager.intent
import android.app.Activity
import android.app.PendingIntent
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
@ -29,7 +28,6 @@ import com.bitwarden.core.util.isBuildVersionAtLeast
import com.bitwarden.ui.platform.resource.BitwardenString
import com.x8bit.bitwarden.BuildConfig
import com.x8bit.bitwarden.data.autofill.model.browser.BrowserPackage
import com.x8bit.bitwarden.data.autofill.util.toPendingIntentMutabilityFlag
import java.io.File
import java.time.Clock
@ -50,33 +48,6 @@ private const val TEMP_CAMERA_IMAGE_NAME: String = "temp_camera_image.jpg"
*/
private const val TEMP_CAMERA_IMAGE_DIR: String = "camera_temp"
/**
* Key for the user id included in Credential provider "create entries".
*
* @see IntentManager.createFido2CreationPendingIntent
*/
const val EXTRA_KEY_USER_ID: String = "user_id"
/**
* Key for the credential id included in FIDO 2 provider "get entries".
*
* @see IntentManager.createFido2GetCredentialPendingIntent
*/
const val EXTRA_KEY_CREDENTIAL_ID: String = "credential_id"
/**
* Key for the cipher id included in FIDO 2 provider "get entries".
*
* @see IntentManager.createFido2GetCredentialPendingIntent
*/
const val EXTRA_KEY_CIPHER_ID: String = "cipher_id"
/**
* Key for the user verification performed during vault unlock while
* processing a Credential request.
*/
const val EXTRA_KEY_UV_PERFORMED_DURING_UNLOCK: String = "uv_performed_during_unlock"
/**
* The default implementation of the [IntentManager] for simplifying the handling of Android
* Intents within a given context.
@ -288,84 +259,6 @@ class IntentManagerImpl(
putExtra(Intent.EXTRA_TITLE, fileName)
}
override fun createFido2CreationPendingIntent(
action: String,
userId: String,
requestCode: Int,
): PendingIntent {
val intent = Intent(action)
.setPackage(context.packageName)
.putExtra(EXTRA_KEY_USER_ID, userId)
return PendingIntent.getActivity(
/* context = */ context,
/* requestCode = */ requestCode,
/* intent = */ intent,
/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT.toPendingIntentMutabilityFlag(),
)
}
override fun createFido2GetCredentialPendingIntent(
action: String,
userId: String,
credentialId: String,
cipherId: String,
isUserVerified: Boolean,
requestCode: Int,
): PendingIntent {
val intent = Intent(action)
.setPackage(context.packageName)
.putExtra(EXTRA_KEY_USER_ID, userId)
.putExtra(EXTRA_KEY_CREDENTIAL_ID, credentialId)
.putExtra(EXTRA_KEY_CIPHER_ID, cipherId)
.putExtra(EXTRA_KEY_UV_PERFORMED_DURING_UNLOCK, isUserVerified)
return PendingIntent.getActivity(
/* context = */ context,
/* requestCode = */ requestCode,
/* intent = */ intent,
/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT.toPendingIntentMutabilityFlag(),
)
}
override fun createFido2UnlockPendingIntent(
action: String,
userId: String,
requestCode: Int,
): PendingIntent {
val intent = Intent(action)
.setPackage(context.packageName)
.putExtra(EXTRA_KEY_USER_ID, userId)
return PendingIntent.getActivity(
/* context = */ context,
/* requestCode = */ requestCode,
/* intent = */ intent,
/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT.toPendingIntentMutabilityFlag(),
)
}
override fun createPasswordGetCredentialPendingIntent(
action: String,
userId: String,
cipherId: String?,
isUserVerified: Boolean,
requestCode: Int,
): PendingIntent {
val intent = Intent(action)
.setPackage(context.packageName)
.putExtra(EXTRA_KEY_USER_ID, userId)
.putExtra(EXTRA_KEY_CIPHER_ID, cipherId)
.putExtra(EXTRA_KEY_UV_PERFORMED_DURING_UNLOCK, isUserVerified)
return PendingIntent.getActivity(
/* context = */ context,
/* requestCode = */ requestCode,
/* intent = */ intent,
/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT.toPendingIntentMutabilityFlag(),
)
}
override fun startDefaultEmailApplication() {
val intent = Intent(Intent.ACTION_MAIN)
intent.addCategory(Intent.CATEGORY_APP_EMAIL)

View File

@ -12,12 +12,12 @@ import com.bitwarden.core.util.isBuildVersionAtLeast
import com.bitwarden.fido.Fido2CredentialAutofillView
import com.bitwarden.vault.CipherListView
import com.bitwarden.vault.CipherListViewType
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManager
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
import com.x8bit.bitwarden.data.util.mockBuilder
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherListView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFido2CredentialAutofillView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockLoginListView
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkConstructor
@ -36,23 +36,19 @@ class CredentialEntryBuilderTest {
private val mockContext = mockk<Context>()
private val mockGetPublicKeyCredentialIntent = mockk<PendingIntent>(relaxed = true)
private val mockGetPasswordCredentialIntent = mockk<PendingIntent>(relaxed = true)
private val mockIntentManager = mockk<IntentManager> {
private val mockPendingIntentManager = mockk<CredentialManagerPendingIntentManager> {
every {
createFido2GetCredentialPendingIntent(
action = any(),
userId = any(),
cipherId = any(),
credentialId = any(),
requestCode = any(),
isUserVerified = any(),
)
} returns mockGetPublicKeyCredentialIntent
every {
createPasswordGetCredentialPendingIntent(
action = any(),
userId = any(),
cipherId = any(),
requestCode = any(),
isUserVerified = any(),
)
} returns mockGetPasswordCredentialIntent
@ -62,7 +58,7 @@ class CredentialEntryBuilderTest {
private val mockBeginGetPasswordOption = mockk<BeginGetPasswordOption>()
private val credentialEntryBuilder = CredentialEntryBuilderImpl(
context = mockContext,
intentManager = mockIntentManager,
pendingIntentManager = mockPendingIntentManager,
biometricsEncryptionManager = mockBiometricsEncryptionManager,
)
private val mockPublicKeyCredentialEntry = mockk<PublicKeyCredentialEntry>(relaxed = true)
@ -155,12 +151,10 @@ class CredentialEntryBuilderTest {
assertTrue(result.isNotEmpty())
verify {
mockIntentManager.createFido2GetCredentialPendingIntent(
action = "com.x8bit.bitwarden.credentials.ACTION_GET_PASSKEY",
mockPendingIntentManager.createFido2GetCredentialPendingIntent(
userId = "userId",
cipherId = "mockCipherId-1",
credentialId = fido2AutofillViews.first().credentialId.toString(),
requestCode = any(),
isUserVerified = false,
)
@ -326,11 +320,9 @@ class CredentialEntryBuilderTest {
assertTrue(result.isNotEmpty())
verify {
mockIntentManager.createPasswordGetCredentialPendingIntent(
action = "com.x8bit.bitwarden.credentials.ACTION_GET_PASSWORD",
mockPendingIntentManager.createPasswordGetCredentialPendingIntent(
userId = "userId",
cipherId = "mockId-1",
requestCode = any(),
isUserVerified = false,
)

View File

@ -31,9 +31,9 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
import com.x8bit.bitwarden.data.credentials.manager.BitwardenCredentialManager
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManager
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import io.mockk.coEvery
import io.mockk.every
import io.mockk.just
@ -69,7 +69,7 @@ class CredentialProviderProcessorTest {
private val bitwardenCredentialManager: BitwardenCredentialManager = mockk {
coEvery { getCredentialEntries(any()) } returns credentialEntries.asSuccess()
}
private val intentManager: IntentManager = mockk()
private val pendingIntentManager: CredentialManagerPendingIntentManager = mockk()
private val dispatcherManager: DispatcherManager = FakeDispatcherManager()
private val biometricsEncryptionManager: BiometricsEncryptionManager = mockk()
private val cancellationSignal: CancellationSignal = mockk()
@ -82,7 +82,7 @@ class CredentialProviderProcessorTest {
context = context,
authRepository = authRepository,
bitwardenCredentialManager = bitwardenCredentialManager,
intentManager = intentManager,
pendingIntentManager = pendingIntentManager,
clock = clock,
biometricsEncryptionManager = biometricsEncryptionManager,
dispatcherManager = dispatcherManager,
@ -220,10 +220,8 @@ class CredentialProviderProcessorTest {
every { context.packageName } returns "com.x8bit.bitwarden"
every { context.getString(any(), any()) } returns "mockDescription"
every {
intentManager.createFido2CreationPendingIntent(
action = any(),
pendingIntentManager.createFido2CreationPendingIntent(
userId = any(),
requestCode = any(),
)
} returns mockIntent
every {
@ -270,10 +268,8 @@ class CredentialProviderProcessorTest {
} returns "{\"mockJsonRequest\":1}"
every { callback.onResult(capture(captureSlot)) } just runs
every {
intentManager.createFido2CreationPendingIntent(
action = any(),
pendingIntentManager.createFido2CreationPendingIntent(
userId = any(),
requestCode = any(),
)
} returns mockIntent
every {
@ -383,10 +379,8 @@ class CredentialProviderProcessorTest {
every { callback.onResult(capture(captureSlot)) } just runs
every { context.getString(any()) } returns "mockTitle"
every {
intentManager.createFido2UnlockPendingIntent(
action = "com.x8bit.bitwarden.credentials.ACTION_UNLOCK_ACCOUNT",
pendingIntentManager.createFido2UnlockPendingIntent(
userId = "mockUserId-1",
requestCode = any(),
)
} returns mockIntent
@ -404,10 +398,8 @@ class CredentialProviderProcessorTest {
verify(exactly = 0) { callback.onError(any()) }
verify(exactly = 1) {
callback.onResult(any())
intentManager.createFido2UnlockPendingIntent(
action = "com.x8bit.bitwarden.credentials.ACTION_UNLOCK_ACCOUNT",
pendingIntentManager.createFido2UnlockPendingIntent(
userId = "mockUserId-1",
requestCode = any(),
)
}

View File

@ -8,10 +8,10 @@ import androidx.credentials.provider.PendingIntentHandler
import androidx.credentials.provider.ProviderCreateCredentialRequest
import androidx.credentials.provider.ProviderGetCredentialRequest
import com.bitwarden.core.util.isBuildVersionAtLeast
import com.x8bit.bitwarden.ui.platform.manager.intent.EXTRA_KEY_CIPHER_ID
import com.x8bit.bitwarden.ui.platform.manager.intent.EXTRA_KEY_CREDENTIAL_ID
import com.x8bit.bitwarden.ui.platform.manager.intent.EXTRA_KEY_USER_ID
import com.x8bit.bitwarden.ui.platform.manager.intent.EXTRA_KEY_UV_PERFORMED_DURING_UNLOCK
import com.x8bit.bitwarden.data.credentials.manager.EXTRA_KEY_CIPHER_ID
import com.x8bit.bitwarden.data.credentials.manager.EXTRA_KEY_CREDENTIAL_ID
import com.x8bit.bitwarden.data.credentials.manager.EXTRA_KEY_USER_ID
import com.x8bit.bitwarden.data.credentials.manager.EXTRA_KEY_UV_PERFORMED_DURING_UNLOCK
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject

View File

@ -11,8 +11,7 @@ import androidx.credentials.provider.PasswordCredentialEntry
import androidx.credentials.provider.PendingIntentHandler
import androidx.credentials.provider.PublicKeyCredentialEntry
import com.bitwarden.ui.util.asText
import com.x8bit.bitwarden.data.credentials.processor.GET_PASSKEY_INTENT
import com.x8bit.bitwarden.data.credentials.processor.GET_PASSWORD_INTENT
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManager
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFido2CredentialAutofillView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockLoginView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockPasswordCredentialAutofillCipherLogin
@ -20,7 +19,6 @@ import com.x8bit.bitwarden.ui.credentials.manager.model.AssertFido2CredentialRes
import com.x8bit.bitwarden.ui.credentials.manager.model.GetCredentialsResult
import com.x8bit.bitwarden.ui.credentials.manager.model.GetPasswordCredentialResult
import com.x8bit.bitwarden.ui.credentials.manager.model.RegisterFido2CredentialResult
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import io.mockk.Called
import io.mockk.MockKVerificationScope
import io.mockk.Ordering
@ -107,7 +105,7 @@ class CredentialProviderCompletionManagerTest {
@Nested
inner class DefaultImplementation {
private val mockIntentManager = mockk<IntentManager>()
private val mockPendingIntentManager = mockk<CredentialManagerPendingIntentManager>()
@BeforeEach
fun setUp() {
@ -274,13 +272,11 @@ class CredentialProviderCompletionManagerTest {
val mockFido2AutofillView = createMockFido2CredentialAutofillView(number = 1)
every {
mockIntentManager.createFido2GetCredentialPendingIntent(
action = GET_PASSKEY_INTENT,
mockPendingIntentManager.createFido2GetCredentialPendingIntent(
userId = "mockUserId",
credentialId = mockFido2AutofillView.credentialId.toString(),
cipherId = mockFido2AutofillView.cipherId,
isUserVerified = false,
requestCode = any(),
)
} returns mockk()
every { mockActivity.getString(any()) } returns "No username"
@ -320,12 +316,10 @@ class CredentialProviderCompletionManagerTest {
val mockPasswordAutofillView = createMockPasswordCredentialAutofillCipherLogin()
every {
mockIntentManager.createPasswordGetCredentialPendingIntent(
action = GET_PASSWORD_INTENT,
mockPendingIntentManager.createPasswordGetCredentialPendingIntent(
userId = "mockUserId",
cipherId = mockPasswordAutofillView.cipherId,
isUserVerified = false,
requestCode = any(),
)
} returns mockk()
every { mockActivity.getString(any()) } returns "No username"