mirror of
https://github.com/bitwarden/android.git
synced 2024-11-22 01:16:02 +03:00
[PM-10282] Default to last active account for passkey creation (#3780)
This commit is contained in:
parent
5f46423638
commit
a15b84a5bf
3 changed files with 28 additions and 3 deletions
|
@ -21,6 +21,7 @@ import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import java.time.Clock
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,6 +42,7 @@ object Fido2ProviderModule {
|
||||||
fido2CredentialManager: Fido2CredentialManager,
|
fido2CredentialManager: Fido2CredentialManager,
|
||||||
dispatcherManager: DispatcherManager,
|
dispatcherManager: DispatcherManager,
|
||||||
intentManager: IntentManager,
|
intentManager: IntentManager,
|
||||||
|
clock: Clock,
|
||||||
): Fido2ProviderProcessor =
|
): Fido2ProviderProcessor =
|
||||||
Fido2ProviderProcessorImpl(
|
Fido2ProviderProcessorImpl(
|
||||||
context,
|
context,
|
||||||
|
@ -49,6 +51,7 @@ object Fido2ProviderModule {
|
||||||
fido2CredentialStore,
|
fido2CredentialStore,
|
||||||
fido2CredentialManager,
|
fido2CredentialManager,
|
||||||
intentManager,
|
intentManager,
|
||||||
|
clock,
|
||||||
dispatcherManager,
|
dispatcherManager,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.DecryptFido2CredentialAut
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.time.Clock
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
private const val CREATE_PASSKEY_INTENT = "com.x8bit.bitwarden.fido2.ACTION_CREATE_PASSKEY"
|
private const val CREATE_PASSKEY_INTENT = "com.x8bit.bitwarden.fido2.ACTION_CREATE_PASSKEY"
|
||||||
|
@ -57,6 +58,7 @@ class Fido2ProviderProcessorImpl(
|
||||||
private val fido2CredentialStore: Fido2CredentialStore,
|
private val fido2CredentialStore: Fido2CredentialStore,
|
||||||
private val fido2CredentialManager: Fido2CredentialManager,
|
private val fido2CredentialManager: Fido2CredentialManager,
|
||||||
private val intentManager: IntentManager,
|
private val intentManager: IntentManager,
|
||||||
|
private val clock: Clock,
|
||||||
dispatcherManager: DispatcherManager,
|
dispatcherManager: DispatcherManager,
|
||||||
) : Fido2ProviderProcessor {
|
) : Fido2ProviderProcessor {
|
||||||
|
|
||||||
|
@ -111,13 +113,14 @@ class Fido2ProviderProcessorImpl(
|
||||||
val userState = authRepository.userStateFlow.value ?: return null
|
val userState = authRepository.userStateFlow.value ?: return null
|
||||||
|
|
||||||
return BeginCreateCredentialResponse.Builder()
|
return BeginCreateCredentialResponse.Builder()
|
||||||
.setCreateEntries(userState.accounts.toCreateEntries())
|
.setCreateEntries(userState.accounts.toCreateEntries(userState.activeUserId))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<UserState.Account>.toCreateEntries() = map { it.toCreateEntry() }
|
private fun List<UserState.Account>.toCreateEntries(activeUserId: String) =
|
||||||
|
map { it.toCreateEntry(isActive = activeUserId == it.userId) }
|
||||||
|
|
||||||
private fun UserState.Account.toCreateEntry(): CreateEntry {
|
private fun UserState.Account.toCreateEntry(isActive: Boolean): CreateEntry {
|
||||||
val accountName = name ?: email
|
val accountName = name ?: email
|
||||||
return CreateEntry
|
return CreateEntry
|
||||||
.Builder(
|
.Builder(
|
||||||
|
@ -134,6 +137,9 @@ class Fido2ProviderProcessorImpl(
|
||||||
accountName,
|
accountName,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
// Set the last used time to "now" so the active account is the default option in the
|
||||||
|
// system prompt.
|
||||||
|
.setLastUsedTime(if (isActive) clock.instant() else null)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,9 @@ import kotlinx.serialization.encodeToString
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import java.time.Clock
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.ZoneOffset
|
||||||
|
|
||||||
class Fido2ProviderProcessorTest {
|
class Fido2ProviderProcessorTest {
|
||||||
|
|
||||||
|
@ -80,6 +83,7 @@ class Fido2ProviderProcessorTest {
|
||||||
private val cancellationSignal: CancellationSignal = mockk()
|
private val cancellationSignal: CancellationSignal = mockk()
|
||||||
|
|
||||||
private val json = PlatformNetworkModule.providesJson()
|
private val json = PlatformNetworkModule.providesJson()
|
||||||
|
private val clock = FIXED_CLOCK
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
|
@ -90,6 +94,7 @@ class Fido2ProviderProcessorTest {
|
||||||
fido2CredentialStore,
|
fido2CredentialStore,
|
||||||
fido2CredentialManager,
|
fido2CredentialManager,
|
||||||
intentManager,
|
intentManager,
|
||||||
|
clock,
|
||||||
dispatcherManager,
|
dispatcherManager,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -244,6 +249,12 @@ class Fido2ProviderProcessorTest {
|
||||||
verify(exactly = 0) { callback.onError(any()) }
|
verify(exactly = 0) { callback.onError(any()) }
|
||||||
|
|
||||||
assertEquals(DEFAULT_USER_STATE.accounts.size, captureSlot.captured.createEntries.size)
|
assertEquals(DEFAULT_USER_STATE.accounts.size, captureSlot.captured.createEntries.size)
|
||||||
|
|
||||||
|
// Verify only the active account entry has a lastUsedTime
|
||||||
|
assertEquals(
|
||||||
|
1,
|
||||||
|
captureSlot.captured.createEntries.filter { it.lastUsedTime != null }.size,
|
||||||
|
)
|
||||||
DEFAULT_USER_STATE.accounts.forEachIndexed { index, mockAccount ->
|
DEFAULT_USER_STATE.accounts.forEachIndexed { index, mockAccount ->
|
||||||
assertEquals(mockAccount.email, captureSlot.captured.createEntries[index].accountName)
|
assertEquals(mockAccount.email, captureSlot.captured.createEntries[index].accountName)
|
||||||
}
|
}
|
||||||
|
@ -495,6 +506,11 @@ private val DEFAULT_USER_STATE = UserState(
|
||||||
accounts = createMockAccounts(2),
|
accounts = createMockAccounts(2),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val FIXED_CLOCK: Clock = Clock.fixed(
|
||||||
|
Instant.parse("2023-10-27T12:00:00Z"),
|
||||||
|
ZoneOffset.UTC,
|
||||||
|
)
|
||||||
|
|
||||||
private fun createMockAccounts(number: Int): List<UserState.Account> {
|
private fun createMockAccounts(number: Int): List<UserState.Account> {
|
||||||
val accounts = mutableListOf<UserState.Account>()
|
val accounts = mutableListOf<UserState.Account>()
|
||||||
repeat(number) {
|
repeat(number) {
|
||||||
|
|
Loading…
Reference in a new issue