Make sure that PerformCreate[ExternalEmail]User can be invoked multiple times without throwing errors
Recover from "Username already taken or not allowed" error when creating new user accounts.
This commit is contained in:
parent
f4b7ecbb67
commit
ff710350f3
|
@ -19,13 +19,14 @@
|
|||
package me.proton.core.auth.domain.usecase.signup
|
||||
|
||||
import me.proton.core.auth.domain.repository.AuthRepository
|
||||
import me.proton.core.auth.domain.usecase.PerformLogin
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.srp.SrpCrypto
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.user.domain.entity.CreateUserType
|
||||
import me.proton.core.user.domain.entity.User
|
||||
import me.proton.core.user.domain.repository.UserRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -33,15 +34,21 @@ class PerformCreateExternalEmailUser @Inject constructor(
|
|||
private val authRepository: AuthRepository,
|
||||
private val userRepository: UserRepository,
|
||||
private val srpCrypto: SrpCrypto,
|
||||
private val keyStoreCrypto: KeyStoreCrypto
|
||||
private val keyStoreCrypto: KeyStoreCrypto,
|
||||
private val performLogin: PerformLogin
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
email: String,
|
||||
password: EncryptedString,
|
||||
referrer: String?
|
||||
): User {
|
||||
): UserId {
|
||||
require(email.isNotBlank()) { "Email must not be empty." }
|
||||
|
||||
if (!userRepository.isUsernameAvailable(email)) {
|
||||
return performLogin.invoke(email, password).userId
|
||||
}
|
||||
|
||||
val modulus = authRepository.randomModulus()
|
||||
|
||||
password.decrypt(keyStoreCrypto).toByteArray().use { decryptedPassword ->
|
||||
|
@ -57,7 +64,7 @@ class PerformCreateExternalEmailUser @Inject constructor(
|
|||
referrer = referrer,
|
||||
type = CreateUserType.Normal,
|
||||
auth = auth
|
||||
)
|
||||
).userId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,14 @@
|
|||
package me.proton.core.auth.domain.usecase.signup
|
||||
|
||||
import me.proton.core.auth.domain.repository.AuthRepository
|
||||
import me.proton.core.auth.domain.usecase.PerformLogin
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.srp.SrpCrypto
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.user.domain.entity.CreateUserType
|
||||
import me.proton.core.user.domain.entity.User
|
||||
import me.proton.core.user.domain.repository.UserRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -33,7 +34,8 @@ class PerformCreateUser @Inject constructor(
|
|||
private val authRepository: AuthRepository,
|
||||
private val userRepository: UserRepository,
|
||||
private val srpCrypto: SrpCrypto,
|
||||
private val keyStoreCrypto: KeyStoreCrypto
|
||||
private val keyStoreCrypto: KeyStoreCrypto,
|
||||
private val performLogin: PerformLogin
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
|
@ -42,13 +44,18 @@ class PerformCreateUser @Inject constructor(
|
|||
recoveryEmail: String?,
|
||||
recoveryPhone: String?,
|
||||
referrer: String?,
|
||||
type: CreateUserType,
|
||||
): User {
|
||||
type: CreateUserType
|
||||
): UserId {
|
||||
require(
|
||||
(recoveryEmail == null && recoveryPhone == null) ||
|
||||
(recoveryEmail == null && recoveryPhone != null) ||
|
||||
(recoveryEmail != null && recoveryPhone == null)
|
||||
recoveryEmail == null && recoveryPhone == null ||
|
||||
recoveryEmail == null && recoveryPhone != null ||
|
||||
recoveryEmail != null && recoveryPhone == null
|
||||
) { "Recovery Email and Phone could not be set together" }
|
||||
|
||||
if (!userRepository.isUsernameAvailable(username)) {
|
||||
return performLogin.invoke(username, password).userId
|
||||
}
|
||||
|
||||
val modulus = authRepository.randomModulus()
|
||||
|
||||
password.decrypt(keyStoreCrypto).toByteArray().use { decryptedPassword ->
|
||||
|
@ -66,7 +73,7 @@ class PerformCreateUser @Inject constructor(
|
|||
referrer = referrer,
|
||||
type = type,
|
||||
auth = auth
|
||||
)
|
||||
).userId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ import kotlinx.coroutines.launch
|
|||
import me.proton.core.account.domain.entity.AccountType
|
||||
import me.proton.core.auth.domain.usecase.signup.PerformCreateExternalEmailUser
|
||||
import me.proton.core.auth.domain.usecase.signup.PerformCreateUser
|
||||
import me.proton.core.auth.domain.usecase.userAlreadyExists
|
||||
import me.proton.core.auth.presentation.LogTag
|
||||
import me.proton.core.auth.presentation.entity.signup.RecoveryMethod
|
||||
import me.proton.core.auth.presentation.entity.signup.RecoveryMethodType
|
||||
import me.proton.core.auth.presentation.entity.signup.SubscriptionDetails
|
||||
|
@ -45,8 +47,6 @@ import me.proton.core.crypto.common.keystore.encrypt
|
|||
import me.proton.core.humanverification.domain.HumanVerificationManager
|
||||
import me.proton.core.humanverification.presentation.HumanVerificationOrchestrator
|
||||
import me.proton.core.humanverification.presentation.onHumanVerificationFailed
|
||||
import me.proton.core.humanverification.presentation.onHumanVerificationNeeded
|
||||
import me.proton.core.humanverification.presentation.onHumanVerificationSucceeded
|
||||
import me.proton.core.network.domain.client.ClientIdProvider
|
||||
import me.proton.core.payment.domain.entity.SubscriptionCycle
|
||||
import me.proton.core.payment.presentation.PaymentsOrchestrator
|
||||
|
@ -55,7 +55,9 @@ import me.proton.core.plan.presentation.PlansOrchestrator
|
|||
import me.proton.core.presentation.savedstate.flowState
|
||||
import me.proton.core.presentation.savedstate.state
|
||||
import me.proton.core.user.domain.entity.createUserType
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
import me.proton.core.util.kotlin.exhaustive
|
||||
import me.proton.core.util.kotlin.retryOnceWhen
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
|
@ -228,7 +230,9 @@ internal class SignupViewModel @Inject constructor(
|
|||
username = username, password = encryptedPassword, recoveryEmail = verification.first,
|
||||
recoveryPhone = verification.second, referrer = null, type = currentAccountType.createUserType()
|
||||
)
|
||||
emit(State.Success(result.userId.id, username, encryptedPassword))
|
||||
emit(State.Success(result.id, username, encryptedPassword))
|
||||
}.retryOnceWhen(Throwable::userAlreadyExists) {
|
||||
CoreLogger.e(LogTag.FLOW_ERROR_RETRY, it, "Retrying to create a user")
|
||||
}.catch { error ->
|
||||
emit(State.Error.Message(error.message))
|
||||
}.onEach {
|
||||
|
@ -239,12 +243,14 @@ internal class SignupViewModel @Inject constructor(
|
|||
val externalEmail = requireNotNull(externalEmail) { "External email is not set." }
|
||||
val encryptedPassword = requireNotNull(_password) { "Password is not set (initialized)." }
|
||||
emit(State.Processing)
|
||||
val user = performCreateExternalEmailUser(
|
||||
val userId = performCreateExternalEmailUser(
|
||||
email = externalEmail,
|
||||
password = encryptedPassword,
|
||||
referrer = null
|
||||
)
|
||||
emit(State.Success(user.userId.id, externalEmail, encryptedPassword))
|
||||
emit(State.Success(userId.id, externalEmail, encryptedPassword))
|
||||
}.retryOnceWhen(Throwable::userAlreadyExists) {
|
||||
CoreLogger.e(LogTag.FLOW_ERROR_RETRY, it, "Retrying to create an external user")
|
||||
}.catch { error ->
|
||||
emit(State.Error.Message(error.message))
|
||||
}.onEach {
|
||||
|
|
Loading…
Reference in New Issue