mirror of
https://github.com/bitwarden/android.git
synced 2026-08-25 17:09:55 -05:00
PM-33893: bug: Crash caused by empty credential password (#6693)
This commit is contained in:
+2
-2
@@ -131,8 +131,8 @@ class CredentialProviderCompletionManagerImpl(
|
||||
intent = intent,
|
||||
response = GetCredentialResponse(
|
||||
credential = PasswordCredential(
|
||||
id = result.credential.username ?: "",
|
||||
password = result.credential.password ?: "",
|
||||
id = result.username.orEmpty(),
|
||||
password = result.password,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
+5
-3
@@ -1,7 +1,6 @@
|
||||
package com.x8bit.bitwarden.ui.credentials.manager.model
|
||||
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.vault.LoginView
|
||||
|
||||
/**
|
||||
* Represents the result of Password authentication.
|
||||
@@ -10,10 +9,13 @@ sealed class GetPasswordCredentialResult {
|
||||
/**
|
||||
* Represents a successful authentication of Password credentials.
|
||||
*/
|
||||
data class Success(val credential: LoginView) : GetPasswordCredentialResult()
|
||||
data class Success(
|
||||
val username: String?,
|
||||
val password: String,
|
||||
) : GetPasswordCredentialResult()
|
||||
|
||||
/**
|
||||
* Indicates the user cancelled authentication.
|
||||
* Indicates the user canceled authentication.
|
||||
*/
|
||||
data object Cancelled : GetPasswordCredentialResult()
|
||||
|
||||
|
||||
+21
-4
@@ -2549,11 +2549,28 @@ class VaultItemListingViewModel @Inject constructor(
|
||||
bitwardenCredentialManager.isUserVerified = false
|
||||
clearDialogState()
|
||||
|
||||
val event = selectedCipher.login
|
||||
val event = selectedCipher
|
||||
.login
|
||||
?.let { credential ->
|
||||
VaultItemListingEvent.CompleteProviderGetPasswordCredentialRequest(
|
||||
GetPasswordCredentialResult.Success(credential = credential),
|
||||
)
|
||||
credential
|
||||
.password
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?.let { password ->
|
||||
VaultItemListingEvent.CompleteProviderGetPasswordCredentialRequest(
|
||||
GetPasswordCredentialResult.Success(
|
||||
username = credential.username,
|
||||
password = password,
|
||||
),
|
||||
)
|
||||
}
|
||||
?: VaultItemListingEvent.CompleteProviderGetPasswordCredentialRequest(
|
||||
@Suppress("MaxLineLength")
|
||||
GetPasswordCredentialResult.Error(
|
||||
message = BitwardenString
|
||||
.password_operation_failed_because_the_selected_item_does_not_have_a_valid_password
|
||||
.asText(),
|
||||
),
|
||||
)
|
||||
}
|
||||
?: VaultItemListingEvent.CompleteProviderGetPasswordCredentialRequest(
|
||||
GetPasswordCredentialResult.Error(
|
||||
|
||||
+6
-3
@@ -14,7 +14,6 @@ import androidx.credentials.provider.PublicKeyCredentialEntry
|
||||
import com.bitwarden.ui.util.asText
|
||||
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
|
||||
import com.x8bit.bitwarden.ui.credentials.manager.model.AssertFido2CredentialResult
|
||||
import com.x8bit.bitwarden.ui.credentials.manager.model.CreateCredentialResult
|
||||
@@ -228,8 +227,12 @@ class CredentialProviderCompletionManagerTest {
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `completePasswordGet should set GetCredentialResponse, set activity result, then finish activity when result is Success`() {
|
||||
credentialProviderCompletionManager
|
||||
.completePasswordGet(GetPasswordCredentialResult.Success(createMockLoginView(1)))
|
||||
credentialProviderCompletionManager.completePasswordGet(
|
||||
GetPasswordCredentialResult.Success(
|
||||
username = "mockUsername-1",
|
||||
password = "mockPassword-1",
|
||||
),
|
||||
)
|
||||
|
||||
verifyActivityResultIsSetAndFinishedAfter {
|
||||
PendingIntentHandler.setGetCredentialResponse(any(), any())
|
||||
|
||||
+4
-2
@@ -50,7 +50,6 @@ import com.bitwarden.ui.util.performYesDialogButtonClick
|
||||
import com.bitwarden.vault.CipherType
|
||||
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockLoginView
|
||||
import com.x8bit.bitwarden.ui.credentials.manager.CredentialProviderCompletionManager
|
||||
import com.x8bit.bitwarden.ui.credentials.manager.model.AssertFido2CredentialResult
|
||||
import com.x8bit.bitwarden.ui.credentials.manager.model.CreateCredentialResult
|
||||
@@ -2056,7 +2055,10 @@ class VaultItemListingScreenTest : BitwardenComposeTest() {
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `GetPasswordCredentialResult event should call CredentialProviderCompletionManager with result`() {
|
||||
val result = GetPasswordCredentialResult.Success(createMockLoginView(1))
|
||||
val result = GetPasswordCredentialResult.Success(
|
||||
username = "mockUsername-1",
|
||||
password = "mockPassword-1",
|
||||
)
|
||||
mutableEventFlow.tryEmit(
|
||||
VaultItemListingEvent.CompleteProviderGetPasswordCredentialRequest(result),
|
||||
)
|
||||
|
||||
+64
-11
@@ -92,7 +92,6 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionV
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockDecryptCipherListResult
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFolderView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockLoginListView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockLoginView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSdkFido2CredentialList
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSendView
|
||||
import com.x8bit.bitwarden.data.vault.manager.model.GetCipherResult
|
||||
@@ -5531,15 +5530,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
number = 1,
|
||||
totp = "mockTotp-1",
|
||||
)
|
||||
val mockLoginView = createMockLoginView(
|
||||
number = 1,
|
||||
totp = "mockTotp-1",
|
||||
clock = clock,
|
||||
password = "mockPassword-1",
|
||||
fido2Credentials = null,
|
||||
)
|
||||
val mockGetPasswordRequest = createMockProviderGetPasswordCredentialRequest(1)
|
||||
.copy(cipherId = "mockId-1")
|
||||
val mockGetPasswordRequest = createMockProviderGetPasswordCredentialRequest(number = 1)
|
||||
specialCircumstanceManager.specialCircumstance =
|
||||
SpecialCircumstance.ProviderGetPasswordRequest(
|
||||
passwordGetRequest = mockGetPasswordRequest,
|
||||
@@ -5578,7 +5569,69 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(
|
||||
VaultItemListingEvent.CompleteProviderGetPasswordCredentialRequest(
|
||||
result = GetPasswordCredentialResult.Success(mockLoginView),
|
||||
result = GetPasswordCredentialResult.Success(
|
||||
username = "mockUsername-1",
|
||||
password = "mockPassword-1",
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
)
|
||||
assertNull(viewModel.stateFlow.value.dialogState)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `UserVerificationSuccess should set isUserVerified to true, and emit CompleteGetPassword with error result`() =
|
||||
runTest {
|
||||
val mockLoginListView = createMockLoginListView(
|
||||
number = 1,
|
||||
totp = "mockTotp-1",
|
||||
)
|
||||
val mockGetPasswordRequest = createMockProviderGetPasswordCredentialRequest(number = 1)
|
||||
specialCircumstanceManager.specialCircumstance =
|
||||
SpecialCircumstance.ProviderGetPasswordRequest(
|
||||
passwordGetRequest = mockGetPasswordRequest,
|
||||
)
|
||||
every {
|
||||
ProviderGetCredentialRequest.fromBundle(any())
|
||||
} returns mockk(relaxed = true) {
|
||||
every {
|
||||
credentialOptions
|
||||
} returns listOf(
|
||||
mockk<GetPasswordOption>(relaxed = true),
|
||||
)
|
||||
}
|
||||
every {
|
||||
vaultRepository
|
||||
.decryptCipherListResultStateFlow
|
||||
.value
|
||||
.data
|
||||
} returns createMockDecryptCipherListResult(
|
||||
number = 1,
|
||||
successes = listOf(
|
||||
createMockCipherListView(
|
||||
number = 1,
|
||||
type = CipherListViewType.Login(mockLoginListView),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.trySendAction(
|
||||
VaultItemListingsAction.UserVerificationSuccess(
|
||||
selectedCipherView = createMockCipherView(number = 1, password = ""),
|
||||
),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(
|
||||
VaultItemListingEvent.CompleteProviderGetPasswordCredentialRequest(
|
||||
result = GetPasswordCredentialResult.Error(
|
||||
message = BitwardenString
|
||||
.password_operation_failed_because_the_selected_item_does_not_have_a_valid_password
|
||||
.asText(),
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
)
|
||||
|
||||
@@ -941,6 +941,7 @@ Do you want to switch to this account?</string>
|
||||
<string name="passkey_operation_failed_because_no_item_was_selected">Passkey operation failed because no item was selected.</string>
|
||||
<string name="passkey_operation_failed_because_the_request_is_unsupported">Passkey operation failed because the request is unsupported.</string>
|
||||
<string name="password_operation_failed_because_the_selected_item_does_not_exist">Password operation failed because the selected item does not exist.</string>
|
||||
<string name="password_operation_failed_because_the_selected_item_does_not_have_a_valid_password">Password operation failed because the selected item does not have a valid password.</string>
|
||||
<string name="password_operation_failed_because_no_item_was_selected">Password operation failed because no item was selected.</string>
|
||||
<string name="credential_operation_failed_because_the_request_is_invalid">Credential operation failed because the request is invalid.</string>
|
||||
<string name="credential_operation_failed_because_the_request_is_unsupported">Credential operation failed because the request is unsupported.</string>
|
||||
|
||||
Reference in New Issue
Block a user