mirror of
https://github.com/bitwarden/android.git
synced 2024-11-26 19:36:18 +03:00
Move auth request logic into its own manager class (#1027)
This commit is contained in:
parent
6b4e367c66
commit
c0f51d049f
20 changed files with 1513 additions and 1471 deletions
|
@ -0,0 +1,50 @@
|
|||
package com.x8bit.bitwarden.data.auth.manager
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.CreateAuthRequestResult
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* A manager class for handling authentication fo logging in with remote device.
|
||||
*/
|
||||
interface AuthRequestManager {
|
||||
/**
|
||||
* Creates a new authentication request and then continues to emit updates over time.
|
||||
*/
|
||||
fun createAuthRequestWithUpdates(email: String): Flow<CreateAuthRequestResult>
|
||||
|
||||
/**
|
||||
* Get an auth request by its [fingerprint] and emits updates for that request.
|
||||
*/
|
||||
fun getAuthRequestByFingerprintFlow(fingerprint: String): Flow<AuthRequestUpdatesResult>
|
||||
|
||||
/**
|
||||
* Get an auth request by its request ID and emits updates for that request.
|
||||
*/
|
||||
fun getAuthRequestByIdFlow(requestId: String): Flow<AuthRequestUpdatesResult>
|
||||
|
||||
/**
|
||||
* Get all auth request and emits updates over time.
|
||||
*/
|
||||
fun getAuthRequestsWithUpdates(): Flow<AuthRequestsUpdatesResult>
|
||||
|
||||
/**
|
||||
* Get a list of the current user's [AuthRequest]s.
|
||||
*/
|
||||
suspend fun getAuthRequests(): AuthRequestsResult
|
||||
|
||||
/**
|
||||
* Approves or declines the request corresponding to this [requestId] based on [publicKey]
|
||||
* according to [isApproved].
|
||||
*/
|
||||
suspend fun updateAuthRequest(
|
||||
requestId: String,
|
||||
masterPasswordHash: String?,
|
||||
publicKey: String,
|
||||
isApproved: Boolean,
|
||||
): AuthRequestResult
|
||||
}
|
|
@ -0,0 +1,372 @@
|
|||
package com.x8bit.bitwarden.data.auth.manager
|
||||
|
||||
import com.bitwarden.core.AuthRequestResponse
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.AuthRequestsService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.NewAuthRequestService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.AuthSdkSource
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.CreateAuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserFingerprintResult
|
||||
import com.x8bit.bitwarden.data.platform.util.flatMap
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.isActive
|
||||
import java.time.Clock
|
||||
import javax.inject.Singleton
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
private const val PASSWORDLESS_NOTIFICATION_TIMEOUT_MILLIS: Long = 15L * 60L * 1_000L
|
||||
private const val PASSWORDLESS_NOTIFICATION_RETRY_INTERVAL_MILLIS: Long = 4L * 1_000L
|
||||
private const val PASSWORDLESS_APPROVER_INTERVAL_MILLIS: Long = 5L * 60L * 1_000L
|
||||
|
||||
/**
|
||||
* Default implementation of [AuthRequestManager].
|
||||
*/
|
||||
@Singleton
|
||||
class AuthRequestManagerImpl(
|
||||
private val clock: Clock,
|
||||
private val authRequestsService: AuthRequestsService,
|
||||
private val newAuthRequestService: NewAuthRequestService,
|
||||
private val authDiskSource: AuthDiskSource,
|
||||
private val authSdkSource: AuthSdkSource,
|
||||
private val vaultSdkSource: VaultSdkSource,
|
||||
) : AuthRequestManager {
|
||||
private val activeUserId: String? get() = authDiskSource.userState?.activeUserId
|
||||
|
||||
override fun getAuthRequestsWithUpdates(): Flow<AuthRequestsUpdatesResult> = flow {
|
||||
while (currentCoroutineContext().isActive) {
|
||||
when (val result = getAuthRequests()) {
|
||||
AuthRequestsResult.Error -> emit(AuthRequestsUpdatesResult.Error)
|
||||
|
||||
is AuthRequestsResult.Success -> {
|
||||
emit(AuthRequestsUpdatesResult.Update(authRequests = result.authRequests))
|
||||
}
|
||||
}
|
||||
delay(timeMillis = PASSWORDLESS_APPROVER_INTERVAL_MILLIS)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
override fun createAuthRequestWithUpdates(
|
||||
email: String,
|
||||
): Flow<CreateAuthRequestResult> = flow {
|
||||
val initialResult = createNewAuthRequest(email).getOrNull() ?: run {
|
||||
emit(CreateAuthRequestResult.Error)
|
||||
return@flow
|
||||
}
|
||||
val authRequestResponse = initialResult.authRequestResponse
|
||||
var authRequest = initialResult.authRequest
|
||||
emit(CreateAuthRequestResult.Update(authRequest))
|
||||
|
||||
var isComplete = false
|
||||
while (currentCoroutineContext().isActive && !isComplete) {
|
||||
delay(timeMillis = PASSWORDLESS_NOTIFICATION_RETRY_INTERVAL_MILLIS)
|
||||
newAuthRequestService
|
||||
.getAuthRequestUpdate(
|
||||
requestId = authRequest.id,
|
||||
accessCode = authRequestResponse.accessCode,
|
||||
)
|
||||
.map { request ->
|
||||
AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = authRequest.fingerprint,
|
||||
)
|
||||
}
|
||||
.fold(
|
||||
onFailure = { emit(CreateAuthRequestResult.Error) },
|
||||
onSuccess = { updateAuthRequest ->
|
||||
when {
|
||||
updateAuthRequest.requestApproved -> {
|
||||
isComplete = true
|
||||
emit(
|
||||
CreateAuthRequestResult.Success(
|
||||
authRequest = updateAuthRequest,
|
||||
authRequestResponse = authRequestResponse,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
!updateAuthRequest.requestApproved &&
|
||||
updateAuthRequest.responseDate != null -> {
|
||||
isComplete = true
|
||||
emit(CreateAuthRequestResult.Declined)
|
||||
}
|
||||
|
||||
updateAuthRequest
|
||||
.creationDate
|
||||
.toInstant()
|
||||
.plusMillis(PASSWORDLESS_NOTIFICATION_TIMEOUT_MILLIS)
|
||||
.isBefore(clock.instant()) -> {
|
||||
isComplete = true
|
||||
emit(CreateAuthRequestResult.Expired)
|
||||
}
|
||||
|
||||
else -> {
|
||||
authRequest = updateAuthRequest
|
||||
emit(CreateAuthRequestResult.Update(authRequest))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAuthRequest(
|
||||
initialRequest: suspend () -> AuthRequestUpdatesResult,
|
||||
): Flow<AuthRequestUpdatesResult> = flow {
|
||||
val result = initialRequest()
|
||||
emit(result)
|
||||
if (result is AuthRequestUpdatesResult.Error) return@flow
|
||||
var isComplete = false
|
||||
while (coroutineContext.isActive && !isComplete) {
|
||||
delay(PASSWORDLESS_APPROVER_INTERVAL_MILLIS)
|
||||
val updateResult = result as AuthRequestUpdatesResult.Update
|
||||
authRequestsService
|
||||
.getAuthRequest(result.authRequest.id)
|
||||
.map { request ->
|
||||
AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = updateResult.authRequest.fingerprint,
|
||||
)
|
||||
}
|
||||
.fold(
|
||||
onFailure = { emit(AuthRequestUpdatesResult.Error) },
|
||||
onSuccess = { updateAuthRequest ->
|
||||
when {
|
||||
updateAuthRequest.requestApproved -> {
|
||||
isComplete = true
|
||||
emit(AuthRequestUpdatesResult.Approved)
|
||||
}
|
||||
|
||||
!updateAuthRequest.requestApproved &&
|
||||
updateAuthRequest.responseDate != null -> {
|
||||
isComplete = true
|
||||
emit(AuthRequestUpdatesResult.Declined)
|
||||
}
|
||||
|
||||
updateAuthRequest
|
||||
.creationDate
|
||||
.toInstant()
|
||||
.plusMillis(PASSWORDLESS_NOTIFICATION_TIMEOUT_MILLIS)
|
||||
.isBefore(clock.instant()) -> {
|
||||
isComplete = true
|
||||
emit(AuthRequestUpdatesResult.Expired)
|
||||
}
|
||||
|
||||
else -> {
|
||||
emit(AuthRequestUpdatesResult.Update(updateAuthRequest))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAuthRequestByFingerprintFlow(
|
||||
fingerprint: String,
|
||||
): Flow<AuthRequestUpdatesResult> = getAuthRequest {
|
||||
when (val authRequestsResult = getAuthRequests()) {
|
||||
AuthRequestsResult.Error -> AuthRequestUpdatesResult.Error
|
||||
is AuthRequestsResult.Success -> {
|
||||
authRequestsResult
|
||||
.authRequests
|
||||
.firstOrNull { it.fingerprint == fingerprint }
|
||||
?.let { AuthRequestUpdatesResult.Update(it) }
|
||||
?: AuthRequestUpdatesResult.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAuthRequestByIdFlow(
|
||||
requestId: String,
|
||||
): Flow<AuthRequestUpdatesResult> = getAuthRequest {
|
||||
authRequestsService
|
||||
.getAuthRequest(requestId)
|
||||
.map { request ->
|
||||
when (val result = getFingerprintPhrase(request.publicKey)) {
|
||||
is UserFingerprintResult.Error -> null
|
||||
is UserFingerprintResult.Success -> AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = result.fingerprint,
|
||||
)
|
||||
}
|
||||
}
|
||||
.fold(
|
||||
onFailure = { AuthRequestUpdatesResult.Error },
|
||||
onSuccess = { authRequest ->
|
||||
authRequest
|
||||
?.let { AuthRequestUpdatesResult.Update(it) }
|
||||
?: AuthRequestUpdatesResult.Error
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getAuthRequests(): AuthRequestsResult =
|
||||
authRequestsService
|
||||
.getAuthRequests()
|
||||
.fold(
|
||||
onFailure = { AuthRequestsResult.Error },
|
||||
onSuccess = { response ->
|
||||
AuthRequestsResult.Success(
|
||||
authRequests = response.authRequests.mapNotNull { request ->
|
||||
when (val result = getFingerprintPhrase(request.publicKey)) {
|
||||
is UserFingerprintResult.Error -> null
|
||||
is UserFingerprintResult.Success -> AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = result.fingerprint,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
override suspend fun updateAuthRequest(
|
||||
requestId: String,
|
||||
masterPasswordHash: String?,
|
||||
publicKey: String,
|
||||
isApproved: Boolean,
|
||||
): AuthRequestResult {
|
||||
val userId = activeUserId ?: return AuthRequestResult.Error
|
||||
return vaultSdkSource
|
||||
.getAuthRequestKey(
|
||||
publicKey = publicKey,
|
||||
userId = userId,
|
||||
)
|
||||
.flatMap {
|
||||
authRequestsService.updateAuthRequest(
|
||||
requestId = requestId,
|
||||
key = it,
|
||||
deviceId = authDiskSource.uniqueAppId,
|
||||
masterPasswordHash = null,
|
||||
isApproved = isApproved,
|
||||
)
|
||||
}
|
||||
.map { request ->
|
||||
AuthRequestResult.Success(
|
||||
authRequest = AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = "",
|
||||
),
|
||||
)
|
||||
}
|
||||
.fold(
|
||||
onFailure = { AuthRequestResult.Error },
|
||||
onSuccess = { it },
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to create a new auth request for the given email and returns a [NewAuthRequestData]
|
||||
* with the [AuthRequest] and [AuthRequestResponse].
|
||||
*/
|
||||
private suspend fun createNewAuthRequest(
|
||||
email: String,
|
||||
): Result<NewAuthRequestData> =
|
||||
authSdkSource
|
||||
.getNewAuthRequest(email)
|
||||
.flatMap { authRequestResponse ->
|
||||
newAuthRequestService
|
||||
.createAuthRequest(
|
||||
email = email,
|
||||
publicKey = authRequestResponse.publicKey,
|
||||
deviceId = authDiskSource.uniqueAppId,
|
||||
accessCode = authRequestResponse.accessCode,
|
||||
fingerprint = authRequestResponse.fingerprint,
|
||||
)
|
||||
.map { request ->
|
||||
AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = authRequestResponse.fingerprint,
|
||||
)
|
||||
}
|
||||
.map { NewAuthRequestData(it, authRequestResponse) }
|
||||
}
|
||||
|
||||
private suspend fun getFingerprintPhrase(
|
||||
publicKey: String,
|
||||
): UserFingerprintResult {
|
||||
val profile = authDiskSource.userState?.activeAccount?.profile
|
||||
?: return UserFingerprintResult.Error
|
||||
|
||||
return authSdkSource
|
||||
.getUserFingerprint(
|
||||
email = profile.email,
|
||||
publicKey = publicKey,
|
||||
)
|
||||
.fold(
|
||||
onFailure = { UserFingerprintResult.Error },
|
||||
onSuccess = { UserFingerprintResult.Success(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for the [AuthRequest] and [AuthRequestResponse] data.
|
||||
*/
|
||||
private data class NewAuthRequestData(
|
||||
val authRequest: AuthRequest,
|
||||
val authRequestResponse: AuthRequestResponse,
|
||||
)
|
|
@ -2,6 +2,11 @@ package com.x8bit.bitwarden.data.auth.manager.di
|
|||
|
||||
import android.content.Context
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.AuthRequestsService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.NewAuthRequestService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.AuthSdkSource
|
||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestManager
|
||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestManagerImpl
|
||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestNotificationManager
|
||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestNotificationManagerImpl
|
||||
import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager
|
||||
|
@ -13,11 +18,13 @@ import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
|||
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.GeneratorDiskSource
|
||||
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.PasswordHistoryDiskSource
|
||||
import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import java.time.Clock
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
|
@ -42,6 +49,25 @@ object AuthManagerModule {
|
|||
dispatchers = dispatchers,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAuthRequestManager(
|
||||
clock: Clock,
|
||||
authRequestsService: AuthRequestsService,
|
||||
newAuthRequestService: NewAuthRequestService,
|
||||
authSdkSource: AuthSdkSource,
|
||||
vaultSdkSource: VaultSdkSource,
|
||||
authDiskSource: AuthDiskSource,
|
||||
): AuthRequestManager =
|
||||
AuthRequestManagerImpl(
|
||||
clock = clock,
|
||||
authRequestsService = authRequestsService,
|
||||
newAuthRequestService = newAuthRequestService,
|
||||
authSdkSource = authSdkSource,
|
||||
vaultSdkSource = vaultSdkSource,
|
||||
authDiskSource = authDiskSource,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUserLogoutManager(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.x8bit.bitwarden.data.auth.repository.model
|
||||
package com.x8bit.bitwarden.data.auth.manager.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
|
@ -1,4 +1,4 @@
|
|||
package com.x8bit.bitwarden.data.auth.repository.model
|
||||
package com.x8bit.bitwarden.data.auth.manager.model
|
||||
|
||||
/**
|
||||
* Models result of creating a new login approval request.
|
|
@ -1,4 +1,4 @@
|
|||
package com.x8bit.bitwarden.data.auth.repository.model
|
||||
package com.x8bit.bitwarden.data.auth.manager.model
|
||||
|
||||
/**
|
||||
* Models result of an authorization approval request.
|
|
@ -1,4 +1,4 @@
|
|||
package com.x8bit.bitwarden.data.auth.repository.model
|
||||
package com.x8bit.bitwarden.data.auth.manager.model
|
||||
|
||||
/**
|
||||
* Models result of getting the list of login approval requests for the current user.
|
|
@ -1,4 +1,4 @@
|
|||
package com.x8bit.bitwarden.data.auth.repository.model
|
||||
package com.x8bit.bitwarden.data.auth.manager.model
|
||||
|
||||
/**
|
||||
* Models result of an authorization approval request.
|
|
@ -1,4 +1,4 @@
|
|||
package com.x8bit.bitwarden.data.auth.repository.model
|
||||
package com.x8bit.bitwarden.data.auth.manager.model
|
||||
|
||||
import com.bitwarden.core.AuthRequestResponse
|
||||
|
|
@ -3,14 +3,9 @@ package com.x8bit.bitwarden.data.auth.repository
|
|||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.ForcePasswordResetReason
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorDataModel
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestsResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestsUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestManager
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthState
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.BreachCountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.CreateAuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.DeleteAccountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.KnownDeviceResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.LoginResult
|
||||
|
@ -36,7 +31,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
* Provides an API for observing an modifying authentication state.
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
interface AuthRepository : AuthenticatorProvider {
|
||||
interface AuthRepository : AuthenticatorProvider, AuthRequestManager {
|
||||
/**
|
||||
* Models the current auth state.
|
||||
*/
|
||||
|
@ -235,42 +230,6 @@ interface AuthRepository : AuthenticatorProvider {
|
|||
*/
|
||||
fun setSsoCallbackResult(result: SsoCallbackResult)
|
||||
|
||||
/**
|
||||
* Creates a new authentication request and then continues to emit updates over time.
|
||||
*/
|
||||
fun createAuthRequestWithUpdates(email: String): Flow<CreateAuthRequestResult>
|
||||
|
||||
/**
|
||||
* Get an auth request by its [fingerprint] and emits updates for that request.
|
||||
*/
|
||||
fun getAuthRequestByFingerprintFlow(fingerprint: String): Flow<AuthRequestUpdatesResult>
|
||||
|
||||
/**
|
||||
* Get an auth request by its request ID and emits updates for that request.
|
||||
*/
|
||||
fun getAuthRequestByIdFlow(requestId: String): Flow<AuthRequestUpdatesResult>
|
||||
|
||||
/**
|
||||
* Get all auth request and emits updates over time.
|
||||
*/
|
||||
fun getAuthRequestsWithUpdates(): Flow<AuthRequestsUpdatesResult>
|
||||
|
||||
/**
|
||||
* Get a list of the current user's [AuthRequest]s.
|
||||
*/
|
||||
suspend fun getAuthRequests(): AuthRequestsResult
|
||||
|
||||
/**
|
||||
* Approves or declines the request corresponding to this [requestId] based on [publicKey]
|
||||
* according to [isApproved].
|
||||
*/
|
||||
suspend fun updateAuthRequest(
|
||||
requestId: String,
|
||||
masterPasswordHash: String?,
|
||||
publicKey: String,
|
||||
isApproved: Boolean,
|
||||
): AuthRequestResult
|
||||
|
||||
/**
|
||||
* Get a [Boolean] indicating whether this is a known device.
|
||||
*/
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.x8bit.bitwarden.data.auth.repository
|
|||
|
||||
import android.os.SystemClock
|
||||
import com.bitwarden.core.AuthRequestMethod
|
||||
import com.bitwarden.core.AuthRequestResponse
|
||||
import com.bitwarden.core.InitUserCryptoMethod
|
||||
import com.bitwarden.crypto.HashPurpose
|
||||
import com.bitwarden.crypto.Kdf
|
||||
|
@ -23,24 +22,17 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordReque
|
|||
import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorAuthMethod
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorDataModel
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.AccountsService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.AuthRequestsService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.DevicesService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.HaveIBeenPwnedService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.IdentityService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.NewAuthRequestService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.OrganizationService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.AuthSdkSource
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.util.toInt
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.util.toKdfTypeJson
|
||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestManager
|
||||
import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestsResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestsUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthState
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.BreachCountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.CreateAuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.DeleteAccountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.KnownDeviceResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.LoginResult
|
||||
|
@ -53,7 +45,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.RegisterResult
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.ResendEmailResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.ResetPasswordResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.SwitchAccountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserFingerprintResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
||||
|
@ -84,8 +75,6 @@ import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
|
@ -93,20 +82,12 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.isActive
|
||||
import java.time.Clock
|
||||
import javax.inject.Singleton
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
private const val PASSWORDLESS_NOTIFICATION_TIMEOUT_MILLIS: Long = 15L * 60L * 1_000L
|
||||
private const val PASSWORDLESS_NOTIFICATION_RETRY_INTERVAL_MILLIS: Long = 4L * 1_000L
|
||||
private const val PASSWORDLESS_APPROVER_INTERVAL_MILLIS: Long = 5L * 60L * 1_000L
|
||||
|
||||
/**
|
||||
* Default implementation of [AuthRepository].
|
||||
|
@ -114,13 +95,10 @@ private const val PASSWORDLESS_APPROVER_INTERVAL_MILLIS: Long = 5L * 60L * 1_000
|
|||
@Suppress("LargeClass", "LongParameterList", "TooManyFunctions")
|
||||
@Singleton
|
||||
class AuthRepositoryImpl(
|
||||
private val clock: Clock,
|
||||
private val accountsService: AccountsService,
|
||||
private val authRequestsService: AuthRequestsService,
|
||||
private val devicesService: DevicesService,
|
||||
private val haveIBeenPwnedService: HaveIBeenPwnedService,
|
||||
private val identityService: IdentityService,
|
||||
private val newAuthRequestService: NewAuthRequestService,
|
||||
private val organizationService: OrganizationService,
|
||||
private val authSdkSource: AuthSdkSource,
|
||||
private val vaultSdkSource: VaultSdkSource,
|
||||
|
@ -128,12 +106,14 @@ class AuthRepositoryImpl(
|
|||
private val environmentRepository: EnvironmentRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val vaultRepository: VaultRepository,
|
||||
private val authRequestManager: AuthRequestManager,
|
||||
private val userLogoutManager: UserLogoutManager,
|
||||
private val pushManager: PushManager,
|
||||
private val policyManager: PolicyManager,
|
||||
pushManager: PushManager,
|
||||
dispatcherManager: DispatcherManager,
|
||||
private val elapsedRealtimeMillisProvider: () -> Long = { SystemClock.elapsedRealtime() },
|
||||
) : AuthRepository {
|
||||
) : AuthRepository,
|
||||
AuthRequestManager by authRequestManager {
|
||||
private val mutableHasPendingAccountAdditionStateFlow = MutableStateFlow(false)
|
||||
private val mutableHasPendingAccountDeletionStateFlow = MutableStateFlow(false)
|
||||
|
||||
|
@ -831,276 +811,6 @@ class AuthRepositoryImpl(
|
|||
mutableSsoCallbackResultFlow.tryEmit(result)
|
||||
}
|
||||
|
||||
override fun getAuthRequestsWithUpdates(): Flow<AuthRequestsUpdatesResult> = flow {
|
||||
while (currentCoroutineContext().isActive) {
|
||||
when (val result = getAuthRequests()) {
|
||||
AuthRequestsResult.Error -> emit(AuthRequestsUpdatesResult.Error)
|
||||
|
||||
is AuthRequestsResult.Success -> {
|
||||
emit(AuthRequestsUpdatesResult.Update(authRequests = result.authRequests))
|
||||
}
|
||||
}
|
||||
delay(timeMillis = PASSWORDLESS_APPROVER_INTERVAL_MILLIS)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
override fun createAuthRequestWithUpdates(
|
||||
email: String,
|
||||
): Flow<CreateAuthRequestResult> = flow {
|
||||
val initialResult = createNewAuthRequest(email)
|
||||
.getOrNull()
|
||||
?: run {
|
||||
emit(CreateAuthRequestResult.Error)
|
||||
return@flow
|
||||
}
|
||||
val authRequestResponse = initialResult.authRequestResponse
|
||||
var authRequest = initialResult.authRequest
|
||||
emit(CreateAuthRequestResult.Update(authRequest))
|
||||
|
||||
var isComplete = false
|
||||
while (currentCoroutineContext().isActive && !isComplete) {
|
||||
delay(timeMillis = PASSWORDLESS_NOTIFICATION_RETRY_INTERVAL_MILLIS)
|
||||
newAuthRequestService
|
||||
.getAuthRequestUpdate(
|
||||
requestId = authRequest.id,
|
||||
accessCode = authRequestResponse.accessCode,
|
||||
)
|
||||
.map { request ->
|
||||
AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = authRequest.fingerprint,
|
||||
)
|
||||
}
|
||||
.fold(
|
||||
onFailure = { emit(CreateAuthRequestResult.Error) },
|
||||
onSuccess = { updateAuthRequest ->
|
||||
when {
|
||||
updateAuthRequest.requestApproved -> {
|
||||
isComplete = true
|
||||
emit(
|
||||
CreateAuthRequestResult.Success(
|
||||
authRequest = updateAuthRequest,
|
||||
authRequestResponse = authRequestResponse,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
!updateAuthRequest.requestApproved &&
|
||||
updateAuthRequest.responseDate != null -> {
|
||||
isComplete = true
|
||||
emit(CreateAuthRequestResult.Declined)
|
||||
}
|
||||
|
||||
updateAuthRequest
|
||||
.creationDate
|
||||
.toInstant()
|
||||
.plusMillis(PASSWORDLESS_NOTIFICATION_TIMEOUT_MILLIS)
|
||||
.isBefore(clock.instant()) -> {
|
||||
isComplete = true
|
||||
emit(CreateAuthRequestResult.Expired)
|
||||
}
|
||||
|
||||
else -> {
|
||||
authRequest = updateAuthRequest
|
||||
emit(CreateAuthRequestResult.Update(authRequest))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAuthRequest(
|
||||
initialRequest: suspend () -> AuthRequestUpdatesResult,
|
||||
): Flow<AuthRequestUpdatesResult> = flow {
|
||||
val result = initialRequest()
|
||||
emit(result)
|
||||
if (result is AuthRequestUpdatesResult.Error) return@flow
|
||||
var isComplete = false
|
||||
while (coroutineContext.isActive && !isComplete) {
|
||||
delay(PASSWORDLESS_APPROVER_INTERVAL_MILLIS)
|
||||
val updateResult = result as AuthRequestUpdatesResult.Update
|
||||
authRequestsService
|
||||
.getAuthRequest(result.authRequest.id)
|
||||
.map { request ->
|
||||
AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = updateResult.authRequest.fingerprint,
|
||||
)
|
||||
}
|
||||
.fold(
|
||||
onFailure = { emit(AuthRequestUpdatesResult.Error) },
|
||||
onSuccess = { updateAuthRequest ->
|
||||
when {
|
||||
updateAuthRequest.requestApproved -> {
|
||||
isComplete = true
|
||||
emit(AuthRequestUpdatesResult.Approved)
|
||||
}
|
||||
|
||||
!updateAuthRequest.requestApproved &&
|
||||
updateAuthRequest.responseDate != null -> {
|
||||
isComplete = true
|
||||
emit(AuthRequestUpdatesResult.Declined)
|
||||
}
|
||||
|
||||
updateAuthRequest
|
||||
.creationDate
|
||||
.toInstant()
|
||||
.plusMillis(PASSWORDLESS_NOTIFICATION_TIMEOUT_MILLIS)
|
||||
.isBefore(clock.instant()) -> {
|
||||
isComplete = true
|
||||
emit(AuthRequestUpdatesResult.Expired)
|
||||
}
|
||||
|
||||
else -> {
|
||||
emit(AuthRequestUpdatesResult.Update(updateAuthRequest))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAuthRequestByFingerprintFlow(
|
||||
fingerprint: String,
|
||||
): Flow<AuthRequestUpdatesResult> = getAuthRequest {
|
||||
when (val authRequestsResult = getAuthRequests()) {
|
||||
AuthRequestsResult.Error -> AuthRequestUpdatesResult.Error
|
||||
is AuthRequestsResult.Success -> {
|
||||
authRequestsResult
|
||||
.authRequests
|
||||
.firstOrNull { it.fingerprint == fingerprint }
|
||||
?.let { AuthRequestUpdatesResult.Update(it) }
|
||||
?: AuthRequestUpdatesResult.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAuthRequestByIdFlow(
|
||||
requestId: String,
|
||||
): Flow<AuthRequestUpdatesResult> = getAuthRequest {
|
||||
authRequestsService
|
||||
.getAuthRequest(requestId)
|
||||
.map { request ->
|
||||
when (val result = getFingerprintPhrase(request.publicKey)) {
|
||||
is UserFingerprintResult.Error -> null
|
||||
is UserFingerprintResult.Success -> AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = result.fingerprint,
|
||||
)
|
||||
}
|
||||
}
|
||||
.fold(
|
||||
onFailure = { AuthRequestUpdatesResult.Error },
|
||||
onSuccess = { authRequest ->
|
||||
authRequest
|
||||
?.let { AuthRequestUpdatesResult.Update(it) }
|
||||
?: AuthRequestUpdatesResult.Error
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getAuthRequests(): AuthRequestsResult =
|
||||
authRequestsService
|
||||
.getAuthRequests()
|
||||
.fold(
|
||||
onFailure = { AuthRequestsResult.Error },
|
||||
onSuccess = { response ->
|
||||
AuthRequestsResult.Success(
|
||||
authRequests = response.authRequests.mapNotNull { request ->
|
||||
when (val result = getFingerprintPhrase(request.publicKey)) {
|
||||
is UserFingerprintResult.Error -> null
|
||||
is UserFingerprintResult.Success -> AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = result.fingerprint,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
override suspend fun updateAuthRequest(
|
||||
requestId: String,
|
||||
masterPasswordHash: String?,
|
||||
publicKey: String,
|
||||
isApproved: Boolean,
|
||||
): AuthRequestResult {
|
||||
val userId = activeUserId ?: return AuthRequestResult.Error
|
||||
return vaultSdkSource
|
||||
.getAuthRequestKey(
|
||||
publicKey = publicKey,
|
||||
userId = userId,
|
||||
)
|
||||
.flatMap {
|
||||
authRequestsService.updateAuthRequest(
|
||||
requestId = requestId,
|
||||
key = it,
|
||||
deviceId = authDiskSource.uniqueAppId,
|
||||
masterPasswordHash = null,
|
||||
isApproved = isApproved,
|
||||
)
|
||||
}
|
||||
.map { request ->
|
||||
AuthRequestResult.Success(
|
||||
authRequest = AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = "",
|
||||
),
|
||||
)
|
||||
}
|
||||
.fold(
|
||||
onFailure = { AuthRequestResult.Error },
|
||||
onSuccess = { it },
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getIsKnownDevice(emailAddress: String): KnownDeviceResult =
|
||||
devicesService
|
||||
.getIsKnownDevice(
|
||||
|
@ -1243,59 +953,6 @@ class AuthRepositoryImpl(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun getFingerprintPhrase(
|
||||
publicKey: String,
|
||||
): UserFingerprintResult {
|
||||
val profile = authDiskSource.userState?.activeAccount?.profile
|
||||
?: return UserFingerprintResult.Error
|
||||
|
||||
return authSdkSource
|
||||
.getUserFingerprint(
|
||||
email = profile.email,
|
||||
publicKey = publicKey,
|
||||
)
|
||||
.fold(
|
||||
onFailure = { UserFingerprintResult.Error },
|
||||
onSuccess = { UserFingerprintResult.Success(it) },
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to create a new auth request for the given email and returns a [NewAuthRequestData]
|
||||
* with the [AuthRequest] and [AuthRequestResponse].
|
||||
*/
|
||||
private suspend fun createNewAuthRequest(
|
||||
email: String,
|
||||
): Result<NewAuthRequestData> =
|
||||
authSdkSource
|
||||
.getNewAuthRequest(email)
|
||||
.flatMap { authRequestResponse ->
|
||||
newAuthRequestService
|
||||
.createAuthRequest(
|
||||
email = email,
|
||||
publicKey = authRequestResponse.publicKey,
|
||||
deviceId = authDiskSource.uniqueAppId,
|
||||
accessCode = authRequestResponse.accessCode,
|
||||
fingerprint = authRequestResponse.fingerprint,
|
||||
)
|
||||
.map { request ->
|
||||
AuthRequest(
|
||||
id = request.id,
|
||||
publicKey = request.publicKey,
|
||||
platform = request.platform,
|
||||
ipAddress = request.ipAddress,
|
||||
key = request.key,
|
||||
masterPasswordHash = request.masterPasswordHash,
|
||||
creationDate = request.creationDate,
|
||||
responseDate = request.responseDate,
|
||||
requestApproved = request.requestApproved ?: false,
|
||||
originUrl = request.originUrl,
|
||||
fingerprint = authRequestResponse.fingerprint,
|
||||
)
|
||||
}
|
||||
.map { NewAuthRequestData(it, authRequestResponse) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remembered two-factor token associated with the user's email, if applicable.
|
||||
*/
|
||||
|
@ -1344,11 +1001,3 @@ class AuthRepositoryImpl(
|
|||
?.copy(accounts = accounts)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for the [AuthRequest] and [AuthRequestResponse] data.
|
||||
*/
|
||||
private data class NewAuthRequestData(
|
||||
val authRequest: AuthRequest,
|
||||
val authRequestResponse: AuthRequestResponse,
|
||||
)
|
||||
|
|
|
@ -2,13 +2,12 @@ package com.x8bit.bitwarden.data.auth.repository.di
|
|||
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.AccountsService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.AuthRequestsService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.DevicesService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.HaveIBeenPwnedService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.IdentityService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.NewAuthRequestService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.OrganizationService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.AuthSdkSource
|
||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestManager
|
||||
import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepositoryImpl
|
||||
|
@ -23,7 +22,6 @@ import dagger.Module
|
|||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import java.time.Clock
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
|
@ -37,13 +35,10 @@ object AuthRepositoryModule {
|
|||
@Singleton
|
||||
@Suppress("LongParameterList")
|
||||
fun providesAuthRepository(
|
||||
clock: Clock,
|
||||
accountsService: AccountsService,
|
||||
authRequestsService: AuthRequestsService,
|
||||
devicesService: DevicesService,
|
||||
identityService: IdentityService,
|
||||
haveIBeenPwnedService: HaveIBeenPwnedService,
|
||||
newAuthRequestService: NewAuthRequestService,
|
||||
organizationService: OrganizationService,
|
||||
authSdkSource: AuthSdkSource,
|
||||
vaultSdkSource: VaultSdkSource,
|
||||
|
@ -52,16 +47,14 @@ object AuthRepositoryModule {
|
|||
environmentRepository: EnvironmentRepository,
|
||||
settingsRepository: SettingsRepository,
|
||||
vaultRepository: VaultRepository,
|
||||
authRequestManager: AuthRequestManager,
|
||||
userLogoutManager: UserLogoutManager,
|
||||
pushManager: PushManager,
|
||||
policyManager: PolicyManager,
|
||||
): AuthRepository = AuthRepositoryImpl(
|
||||
clock = clock,
|
||||
accountsService = accountsService,
|
||||
authRequestsService = authRequestsService,
|
||||
devicesService = devicesService,
|
||||
identityService = identityService,
|
||||
newAuthRequestService = newAuthRequestService,
|
||||
organizationService = organizationService,
|
||||
authSdkSource = authSdkSource,
|
||||
vaultSdkSource = vaultSdkSource,
|
||||
|
@ -71,6 +64,7 @@ object AuthRepositoryModule {
|
|||
environmentRepository = environmentRepository,
|
||||
settingsRepository = settingsRepository,
|
||||
vaultRepository = vaultRepository,
|
||||
authRequestManager = authRequestManager,
|
||||
userLogoutManager = userLogoutManager,
|
||||
pushManager = pushManager,
|
||||
policyManager = policyManager,
|
||||
|
|
|
@ -5,8 +5,8 @@ import android.os.Parcelable
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.CreateAuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.CreateAuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.LoginResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.CaptchaCallbackTokenResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.generateUriForCaptcha
|
||||
|
|
|
@ -4,9 +4,9 @@ import android.os.Parcelable
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestUpdatesResult
|
||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
|
|
|
@ -3,9 +3,9 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.pending
|
|||
import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestsUpdatesResult
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -4,9 +4,9 @@ import androidx.lifecycle.SavedStateHandle
|
|||
import app.cash.turbine.test
|
||||
import com.bitwarden.core.AuthRequestResponse
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.CreateAuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.CreateAuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.LoginResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.CaptchaCallbackTokenResult
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
|
|
|
@ -3,10 +3,10 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.loginap
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.PasswordlessRequestData
|
||||
|
|
|
@ -2,11 +2,11 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.pending
|
|||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsResult
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsUpdatesResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequest
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestsResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.AuthRequestsUpdatesResult
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
|
|
Loading…
Reference in a new issue