mirror of
https://github.com/bitwarden/android.git
synced 2024-11-21 17:05:44 +03:00
[PM-8137] Refactor FIDO 2 credential registration result object (#3445)
This commit is contained in:
parent
c409132825
commit
9b240ddf5f
15 changed files with 270 additions and 91 deletions
|
@ -2,12 +2,12 @@ package com.x8bit.bitwarden.data.autofill.fido2.manager
|
|||
|
||||
import com.bitwarden.vault.CipherView
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.model.PublicKeyCredentialCreationOptions
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2ValidateOriginResult
|
||||
|
||||
/**
|
||||
* Responsible for managing FIDO 2 credential creation and authentication.
|
||||
* Responsible for managing FIDO 2 credential registration and authentication.
|
||||
*/
|
||||
interface Fido2CredentialManager {
|
||||
|
||||
|
@ -32,5 +32,5 @@ interface Fido2CredentialManager {
|
|||
userId: String,
|
||||
fido2CredentialRequest: Fido2CredentialRequest,
|
||||
selectedCipherView: CipherView,
|
||||
): Fido2CreateCredentialResult
|
||||
): Fido2RegisterCredentialResult
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.x8bit.bitwarden.data.autofill.fido2.manager
|
||||
|
||||
import androidx.credentials.exceptions.CreateCredentialUnknownException
|
||||
import androidx.credentials.provider.CallingAppInfo
|
||||
import com.bitwarden.fido.ClientData
|
||||
import com.bitwarden.sdk.CheckUserResult
|
||||
|
@ -10,8 +9,8 @@ import com.bitwarden.vault.CipherView
|
|||
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.model.DigitalAssetLinkResponseJson
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.model.PublicKeyCredentialCreationOptions
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.service.DigitalAssetLinkService
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2ValidateOriginResult
|
||||
import com.x8bit.bitwarden.data.platform.manager.AssetManager
|
||||
import com.x8bit.bitwarden.data.platform.util.asFailure
|
||||
|
@ -46,15 +45,11 @@ class Fido2CredentialManagerImpl(
|
|||
userId: String,
|
||||
fido2CredentialRequest: Fido2CredentialRequest,
|
||||
selectedCipherView: CipherView,
|
||||
): Fido2CreateCredentialResult {
|
||||
): Fido2RegisterCredentialResult {
|
||||
val clientData = if (fido2CredentialRequest.callingAppInfo.isOriginPopulated()) {
|
||||
fido2CredentialRequest.callingAppInfo.getAppSigningSignatureFingerprint()
|
||||
?.let { ClientData.DefaultWithCustomHash(hash = it) }
|
||||
?: return Fido2CreateCredentialResult.Error(
|
||||
exception = CreateCredentialUnknownException(
|
||||
errorMessage = "Application contains multiple signing certificates.",
|
||||
),
|
||||
)
|
||||
?: return Fido2RegisterCredentialResult.Error
|
||||
} else {
|
||||
ClientData.DefaultWithExtraData(
|
||||
androidPackageName = fido2CredentialRequest
|
||||
|
@ -82,9 +77,9 @@ class Fido2CredentialManagerImpl(
|
|||
.map { it.toAndroidAttestationResponse() }
|
||||
.mapCatching { json.encodeToString(it) }
|
||||
.fold(
|
||||
onSuccess = { Fido2CreateCredentialResult.Success(it) },
|
||||
onSuccess = { Fido2RegisterCredentialResult.Success(it) },
|
||||
onFailure = {
|
||||
Fido2CreateCredentialResult.Error(CreateCredentialUnknownException())
|
||||
Fido2RegisterCredentialResult.Error
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package com.x8bit.bitwarden.data.autofill.fido2.model
|
||||
|
||||
import androidx.credentials.exceptions.CreateCredentialException
|
||||
|
||||
/**
|
||||
* Models the data returned from creating a FIDO 2 credential.
|
||||
*/
|
||||
sealed class Fido2CreateCredentialResult {
|
||||
|
||||
/**
|
||||
* Models a successful response for creating a credential.
|
||||
*/
|
||||
data class Success(
|
||||
val registrationResponse: String,
|
||||
) : Fido2CreateCredentialResult()
|
||||
|
||||
/**
|
||||
* Models an error response for creating a credential.
|
||||
*/
|
||||
data class Error(
|
||||
val exception: CreateCredentialException,
|
||||
) : Fido2CreateCredentialResult()
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.x8bit.bitwarden.data.autofill.fido2.model
|
||||
|
||||
/**
|
||||
* Models the data returned from creating a FIDO 2 credential.
|
||||
*/
|
||||
sealed class Fido2RegisterCredentialResult {
|
||||
|
||||
/**
|
||||
* Indicates the credential has been successfully registered.
|
||||
*/
|
||||
data class Success(
|
||||
val registrationResponse: String,
|
||||
) : Fido2RegisterCredentialResult()
|
||||
|
||||
/**
|
||||
* Indicates there was an error and the credential was not registered.
|
||||
*/
|
||||
data object Error : Fido2RegisterCredentialResult()
|
||||
|
||||
/**
|
||||
* Indicates the user cancelled the request.
|
||||
*/
|
||||
data object Cancelled : Fido2RegisterCredentialResult()
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package com.x8bit.bitwarden.ui.autofill.fido2.manager
|
||||
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||
|
||||
/**
|
||||
* A manager for completing the FIDO 2 creation process.
|
||||
|
@ -8,7 +8,7 @@ import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialResult
|
|||
interface Fido2CompletionManager {
|
||||
|
||||
/**
|
||||
* Completes the FIDO 2 creation process with the provided [result].
|
||||
* Completes the FIDO 2 registration process with the provided [result].
|
||||
*/
|
||||
fun completeFido2Create(result: Fido2CreateCredentialResult)
|
||||
fun completeFido2Registration(result: Fido2RegisterCredentialResult)
|
||||
}
|
||||
|
|
|
@ -5,8 +5,10 @@ import android.content.Intent
|
|||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.credentials.CreatePublicKeyCredentialResponse
|
||||
import androidx.credentials.exceptions.CreateCredentialCancellationException
|
||||
import androidx.credentials.exceptions.CreateCredentialUnknownException
|
||||
import androidx.credentials.provider.PendingIntentHandler
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||
|
||||
/**
|
||||
|
@ -18,19 +20,19 @@ class Fido2CompletionManagerImpl(
|
|||
) : Fido2CompletionManager {
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||
override fun completeFido2Create(result: Fido2CreateCredentialResult) {
|
||||
override fun completeFido2Registration(result: Fido2RegisterCredentialResult) {
|
||||
activity.also {
|
||||
val intent = Intent()
|
||||
when (result) {
|
||||
is Fido2CreateCredentialResult.Error -> {
|
||||
is Fido2RegisterCredentialResult.Error -> {
|
||||
PendingIntentHandler
|
||||
.setCreateCredentialException(
|
||||
intent = intent,
|
||||
exception = result.exception,
|
||||
exception = CreateCredentialUnknownException(),
|
||||
)
|
||||
}
|
||||
|
||||
is Fido2CreateCredentialResult.Success -> {
|
||||
is Fido2RegisterCredentialResult.Success -> {
|
||||
PendingIntentHandler
|
||||
.setCreateCredentialResponse(
|
||||
intent = intent,
|
||||
|
@ -39,6 +41,14 @@ class Fido2CompletionManagerImpl(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
is Fido2RegisterCredentialResult.Cancelled -> {
|
||||
PendingIntentHandler
|
||||
.setCreateCredentialException(
|
||||
intent = intent,
|
||||
exception = CreateCredentialCancellationException(),
|
||||
)
|
||||
}
|
||||
}
|
||||
it.setResult(Activity.RESULT_OK, intent)
|
||||
it.finish()
|
||||
|
|
|
@ -112,8 +112,8 @@ fun VaultAddEditScreen(
|
|||
)
|
||||
}
|
||||
|
||||
is VaultAddEditEvent.CompleteFido2Create -> {
|
||||
fido2CompletionManager.completeFido2Create(event.result)
|
||||
is VaultAddEditEvent.CompleteFido2Registration -> {
|
||||
fido2CompletionManager.completeFido2Registration(event.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.addedit
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.credentials.exceptions.CreateCredentialUnknownException
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.vault.CipherView
|
||||
|
@ -10,8 +9,8 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.BreachCountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.manager.Fido2CredentialManager
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
|
@ -379,14 +378,12 @@ class VaultAddEditViewModel @Inject constructor(
|
|||
?: run {
|
||||
sendAction(
|
||||
VaultAddEditAction.Internal.Fido2RegisterCredentialResultReceive(
|
||||
result = Fido2CreateCredentialResult.Error(
|
||||
exception = CreateCredentialUnknownException(),
|
||||
),
|
||||
result = Fido2RegisterCredentialResult.Error,
|
||||
),
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
val result: Fido2CreateCredentialResult =
|
||||
val result: Fido2RegisterCredentialResult =
|
||||
fido2CredentialManager.registerFido2Credential(
|
||||
userId = activeUserId,
|
||||
fido2CredentialRequest = request,
|
||||
|
@ -1356,15 +1353,19 @@ class VaultAddEditViewModel @Inject constructor(
|
|||
) {
|
||||
clearDialogState()
|
||||
when (action.result) {
|
||||
is Fido2CreateCredentialResult.Error -> {
|
||||
is Fido2RegisterCredentialResult.Error -> {
|
||||
sendEvent(VaultAddEditEvent.ShowToast(R.string.an_error_has_occurred.asText()))
|
||||
}
|
||||
|
||||
is Fido2CreateCredentialResult.Success -> {
|
||||
is Fido2RegisterCredentialResult.Success -> {
|
||||
sendEvent(VaultAddEditEvent.ShowToast(R.string.item_updated.asText()))
|
||||
}
|
||||
|
||||
Fido2RegisterCredentialResult.Cancelled -> {
|
||||
// no-op: The OS will handle re-displaying the system prompt.
|
||||
}
|
||||
}
|
||||
sendEvent(VaultAddEditEvent.CompleteFido2Create(action.result))
|
||||
sendEvent(VaultAddEditEvent.CompleteFido2Registration(action.result))
|
||||
}
|
||||
|
||||
//endregion Internal Type Handlers
|
||||
|
@ -1989,12 +1990,12 @@ sealed class VaultAddEditEvent {
|
|||
) : VaultAddEditEvent()
|
||||
|
||||
/**
|
||||
* Complete the current FIDO 2 credential creation process.
|
||||
* Complete the current FIDO 2 credential registration process.
|
||||
*
|
||||
* @property result the result of FIDO 2 credential creation.
|
||||
*/
|
||||
data class CompleteFido2Create(
|
||||
val result: Fido2CreateCredentialResult,
|
||||
data class CompleteFido2Registration(
|
||||
val result: Fido2RegisterCredentialResult,
|
||||
) : VaultAddEditEvent()
|
||||
}
|
||||
|
||||
|
@ -2484,7 +2485,7 @@ sealed class VaultAddEditAction {
|
|||
* Indicates that the FIDO 2 registration result has been received.
|
||||
*/
|
||||
data class Fido2RegisterCredentialResultReceive(
|
||||
val result: Fido2CreateCredentialResult,
|
||||
val result: Fido2RegisterCredentialResult,
|
||||
) : Internal()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,8 +134,8 @@ fun VaultItemListingScreen(
|
|||
onNavigateToVaultItemListing(VaultItemListingType.Collection(event.collectionId))
|
||||
}
|
||||
|
||||
is VaultItemListingEvent.CompleteFido2Create -> {
|
||||
fido2CompletionManager.completeFido2Create(event.result)
|
||||
is VaultItemListingEvent.CompleteFido2Registration -> {
|
||||
fido2CompletionManager.completeFido2Registration(event.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.itemlisting
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.credentials.exceptions.CreateCredentialUnknownException
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.manager.Fido2CredentialManager
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2ValidateOriginResult
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager
|
||||
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||
|
@ -408,10 +407,8 @@ class VaultItemListingViewModel @Inject constructor(
|
|||
|
||||
private fun handleDismissFido2ErrorDialogClick() {
|
||||
sendEvent(
|
||||
VaultItemListingEvent.CompleteFido2Create(
|
||||
result = Fido2CreateCredentialResult.Error(
|
||||
exception = CreateCredentialUnknownException(),
|
||||
),
|
||||
VaultItemListingEvent.CompleteFido2Registration(
|
||||
result = Fido2RegisterCredentialResult.Error,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -766,15 +763,19 @@ class VaultItemListingViewModel @Inject constructor(
|
|||
) {
|
||||
mutableStateFlow.update { it.copy(dialogState = null) }
|
||||
when (action.result) {
|
||||
is Fido2CreateCredentialResult.Error -> {
|
||||
is Fido2RegisterCredentialResult.Error -> {
|
||||
sendEvent(VaultItemListingEvent.ShowToast(R.string.an_error_has_occurred.asText()))
|
||||
}
|
||||
|
||||
is Fido2CreateCredentialResult.Success -> {
|
||||
is Fido2RegisterCredentialResult.Success -> {
|
||||
sendEvent(VaultItemListingEvent.ShowToast(R.string.item_updated.asText()))
|
||||
}
|
||||
|
||||
Fido2RegisterCredentialResult.Cancelled -> {
|
||||
// no-op: The OS will handle re-displaying the system prompt.
|
||||
}
|
||||
}
|
||||
sendEvent(VaultItemListingEvent.CompleteFido2Create(action.result))
|
||||
sendEvent(VaultItemListingEvent.CompleteFido2Registration(action.result))
|
||||
}
|
||||
|
||||
private fun handleValidateFido2OriginResultReceive(
|
||||
|
@ -1346,8 +1347,8 @@ sealed class VaultItemListingEvent {
|
|||
*
|
||||
* @property result the result of FIDO 2 credential creation.
|
||||
*/
|
||||
data class CompleteFido2Create(
|
||||
val result: Fido2CreateCredentialResult,
|
||||
data class CompleteFido2Registration(
|
||||
val result: Fido2RegisterCredentialResult,
|
||||
) : VaultItemListingEvent()
|
||||
}
|
||||
|
||||
|
@ -1529,7 +1530,7 @@ sealed class VaultItemListingsAction {
|
|||
* Indicates that a result for FIDO 2 credential registration has been received.
|
||||
*/
|
||||
data class Fido2RegisterCredentialResultReceive(
|
||||
val result: Fido2CreateCredentialResult,
|
||||
val result: Fido2RegisterCredentialResult,
|
||||
) : Internal()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.model.DigitalA
|
|||
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.model.PublicKeyCredentialCreationOptions
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.datasource.network.service.DigitalAssetLinkService
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2AttestationResponse
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2ValidateOriginResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.createMockFido2CredentialRequest
|
||||
import com.x8bit.bitwarden.data.platform.manager.AssetManager
|
||||
|
@ -486,7 +486,7 @@ class Fido2CredentialManagerTest {
|
|||
)
|
||||
|
||||
assertTrue(
|
||||
result is Fido2CreateCredentialResult.Error,
|
||||
result is Fido2RegisterCredentialResult.Error,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -530,7 +530,7 @@ class Fido2CredentialManagerTest {
|
|||
)
|
||||
|
||||
assertTrue(
|
||||
result is Fido2CreateCredentialResult.Error,
|
||||
result is Fido2RegisterCredentialResult.Error,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import androidx.compose.ui.test.performTextInput
|
|||
import androidx.compose.ui.test.performTouchInput
|
||||
import androidx.core.net.toUri
|
||||
import com.bitwarden.vault.UriMatchType
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||
import com.x8bit.bitwarden.ui.autofill.fido2.manager.Fido2CompletionManager
|
||||
|
@ -96,7 +96,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
|
|||
every { launchUri(any()) } just runs
|
||||
}
|
||||
private val fido2CompletionManager: Fido2CompletionManager = mockk {
|
||||
every { completeFido2Create(any()) } just runs
|
||||
every { completeFido2Registration(any()) } just runs
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -194,11 +194,11 @@ class VaultAddEditScreenTest : BaseComposeTest() {
|
|||
|
||||
@Test
|
||||
fun `on CompleteFido2Create even should invoke Fido2CompletionManager`() {
|
||||
val result = Fido2CreateCredentialResult.Success(
|
||||
val result = Fido2RegisterCredentialResult.Success(
|
||||
registrationResponse = "mockRegistrationResponse",
|
||||
)
|
||||
mutableEventFlow.tryEmit(VaultAddEditEvent.CompleteFido2Create(result = result))
|
||||
verify { fido2CompletionManager.completeFido2Create(result) }
|
||||
mutableEventFlow.tryEmit(VaultAddEditEvent.CompleteFido2Registration(result = result))
|
||||
verify { fido2CompletionManager.completeFido2Registration(result) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.addedit
|
||||
|
||||
import android.content.pm.SigningInfo
|
||||
import androidx.credentials.exceptions.CreateCredentialUnknownException
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import app.cash.turbine.turbineScope
|
||||
|
@ -17,8 +16,8 @@ import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.manager.Fido2CredentialManager
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CreateCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.model.AutofillSaveItem
|
||||
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
|
@ -725,7 +724,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
|||
vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN),
|
||||
),
|
||||
)
|
||||
val mockCreateResult = Fido2CreateCredentialResult.Success(
|
||||
val mockCreateResult = Fido2RegisterCredentialResult.Success(
|
||||
registrationResponse = "mockRegistrationResponse",
|
||||
)
|
||||
coEvery {
|
||||
|
@ -750,7 +749,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
|||
eventTurbine.awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
VaultAddEditEvent.CompleteFido2Create(result = mockCreateResult),
|
||||
VaultAddEditEvent.CompleteFido2Registration(result = mockCreateResult),
|
||||
eventTurbine.awaitItem(),
|
||||
)
|
||||
assertEquals(stateWithName, stateTurbine.awaitItem())
|
||||
|
@ -767,7 +766,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `in add mode during fido2, SaveClick should show dialog, register credential, show toast on error, and emit ExitApp`() =
|
||||
fun `in add mode during fido2, SaveClick should show dialog, register credential, show toast on error, and emit ExitApp when result is Error`() =
|
||||
runTest {
|
||||
val fido2CredentialRequest = Fido2CredentialRequest(
|
||||
userId = "mockUserId",
|
||||
|
@ -807,9 +806,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
|||
vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN),
|
||||
),
|
||||
)
|
||||
val mockCreateResult = Fido2CreateCredentialResult.Error(
|
||||
exception = CreateCredentialUnknownException(),
|
||||
)
|
||||
val mockCreateResult = Fido2RegisterCredentialResult.Error
|
||||
coEvery {
|
||||
fido2CredentialManager.registerFido2Credential(
|
||||
userId = "mockUserId",
|
||||
|
@ -832,7 +829,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
|||
eventTurbine.awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
VaultAddEditEvent.CompleteFido2Create(result = mockCreateResult),
|
||||
VaultAddEditEvent.CompleteFido2Registration(result = mockCreateResult),
|
||||
eventTurbine.awaitItem(),
|
||||
)
|
||||
assertEquals(stateWithName, stateTurbine.awaitItem())
|
||||
|
@ -847,6 +844,86 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `in add mode during fido2, SaveClick should show saving dialog, register credential, dismiss dialog, show toast on error, and emit ExitApp when activeUserId is null`() =
|
||||
runTest {
|
||||
val fido2CredentialRequest = Fido2CredentialRequest(
|
||||
userId = "mockUserId",
|
||||
requestJson = "mockRequestJson",
|
||||
packageName = "mockPackageName",
|
||||
signingInfo = mockk<SigningInfo>(),
|
||||
origin = null,
|
||||
)
|
||||
specialCircumstanceManager.specialCircumstance =
|
||||
SpecialCircumstance.Fido2Save(
|
||||
fido2CredentialRequest = fido2CredentialRequest,
|
||||
)
|
||||
val stateWithDialog = createVaultAddItemState(
|
||||
vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN),
|
||||
dialogState = VaultAddEditState.DialogState.Loading(
|
||||
R.string.saving.asText(),
|
||||
),
|
||||
commonContentViewState = createCommonContentViewState(
|
||||
name = "mockName-1",
|
||||
),
|
||||
)
|
||||
.copy(shouldExitOnSave = true)
|
||||
|
||||
val stateWithName = createVaultAddItemState(
|
||||
vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN),
|
||||
commonContentViewState = createCommonContentViewState(
|
||||
name = "mockName-1",
|
||||
),
|
||||
)
|
||||
.copy(shouldExitOnSave = true)
|
||||
mutableVaultDataFlow.value = DataState.Loaded(
|
||||
createVaultData(),
|
||||
)
|
||||
val viewModel = createAddVaultItemViewModel(
|
||||
createSavedStateHandleWithState(
|
||||
state = stateWithName,
|
||||
vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN),
|
||||
),
|
||||
)
|
||||
val mockCreateResult = Fido2RegisterCredentialResult.Error
|
||||
coEvery {
|
||||
fido2CredentialManager.registerFido2Credential(
|
||||
userId = "mockUserId",
|
||||
selectedCipherView = any(),
|
||||
fido2CredentialRequest = fido2CredentialRequest,
|
||||
)
|
||||
} returns mockCreateResult
|
||||
every { authRepository.activeUserId } returns null
|
||||
|
||||
turbineScope {
|
||||
val stateTurbine = viewModel.stateFlow.testIn(backgroundScope)
|
||||
val eventTurbine = viewModel.eventFlow.testIn(backgroundScope)
|
||||
|
||||
viewModel.trySendAction(VaultAddEditAction.Common.SaveClick)
|
||||
|
||||
assertEquals(stateWithName, stateTurbine.awaitItem())
|
||||
assertEquals(stateWithDialog, stateTurbine.awaitItem())
|
||||
assertEquals(
|
||||
VaultAddEditEvent.ShowToast(R.string.an_error_has_occurred.asText()),
|
||||
eventTurbine.awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
VaultAddEditEvent.CompleteFido2Registration(result = mockCreateResult),
|
||||
eventTurbine.awaitItem(),
|
||||
)
|
||||
assertEquals(stateWithName, stateTurbine.awaitItem())
|
||||
|
||||
coVerify(exactly = 0) {
|
||||
fido2CredentialManager.registerFido2Credential(
|
||||
userId = "mockUserId",
|
||||
selectedCipherView = any(),
|
||||
fido2CredentialRequest = fido2CredentialRequest,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `in add mode, createCipherInOrganization success should ShowToast and NavigateBack`() =
|
||||
runTest {
|
||||
|
|
|
@ -82,7 +82,7 @@ class VaultItemListingScreenTest : BaseComposeTest() {
|
|||
every { launchUri(any()) } just runs
|
||||
}
|
||||
private val fido2CompletionManager: Fido2CompletionManager = mockk {
|
||||
every { completeFido2Create(any()) } just runs
|
||||
every { completeFido2Registration(any()) } just runs
|
||||
}
|
||||
private val mutableEventFlow = bufferedMutableSharedFlow<VaultItemListingEvent>()
|
||||
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.manager.Fido2CredentialManager
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialRequest
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2ValidateOriginResult
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager
|
||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManagerImpl
|
||||
|
@ -66,6 +67,7 @@ import kotlinx.coroutines.flow.emptyFlow
|
|||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertNull
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.time.Clock
|
||||
|
@ -1736,6 +1738,98 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `Fido2RegisterCredentialResult Error should show toast and emit CompleteFido2Registration result`() =
|
||||
runTest {
|
||||
val mockResult = Fido2RegisterCredentialResult.Error
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.trySendAction(
|
||||
VaultItemListingsAction.Internal.Fido2RegisterCredentialResultReceive(
|
||||
mockResult,
|
||||
),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(
|
||||
VaultItemListingEvent.ShowToast(R.string.an_error_has_occurred.asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
VaultItemListingEvent.CompleteFido2Registration(mockResult),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `Fido2RegisterCredentialResult Success should show toast and emit CompleteFido2Registration result`() =
|
||||
runTest {
|
||||
val mockResult = Fido2RegisterCredentialResult.Success(
|
||||
registrationResponse = "mockResponse",
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.trySendAction(
|
||||
VaultItemListingsAction.Internal.Fido2RegisterCredentialResultReceive(
|
||||
mockResult,
|
||||
),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(
|
||||
VaultItemListingEvent.ShowToast(R.string.item_updated.asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
VaultItemListingEvent.CompleteFido2Registration(mockResult),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `Fido2RegisterCredentialResult Cancelled should emit CompleteFido2Registration result`() =
|
||||
runTest {
|
||||
val mockResult = Fido2RegisterCredentialResult.Cancelled
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.trySendAction(
|
||||
VaultItemListingsAction.Internal.Fido2RegisterCredentialResultReceive(
|
||||
mockResult,
|
||||
),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(
|
||||
VaultItemListingEvent.CompleteFido2Registration(mockResult),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `DismissFido2ErrorDialogClick should clear the dialog state then complete FIDO 2 create`() =
|
||||
runTest {
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.trySendAction(VaultItemListingsAction.DismissFido2CreationErrorDialogClick)
|
||||
viewModel.eventFlow.test {
|
||||
assertNull(viewModel.stateFlow.value.dialogState)
|
||||
assertEquals(
|
||||
VaultItemListingEvent.CompleteFido2Registration(
|
||||
result = Fido2RegisterCredentialResult.Error,
|
||||
),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("CyclomaticComplexMethod")
|
||||
private fun createSavedStateHandleWithVaultItemListingType(
|
||||
vaultItemListingType: VaultItemListingType,
|
||||
|
|
Loading…
Reference in a new issue