BIT-2181: Move PreLogin and Register network calls to Identity API (#1285)

This commit is contained in:
Patrick Honkonen 2024-04-19 17:42:42 -04:00 committed by Álison Fernandes
parent 15cb60e3d2
commit 4293c0b9fd
10 changed files with 284 additions and 274 deletions

View file

@ -1,10 +1,6 @@
package com.x8bit.bitwarden.data.auth.datasource.network.api
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson
import retrofit2.http.Body
import retrofit2.http.POST
@ -13,12 +9,6 @@ import retrofit2.http.POST
* Defines raw calls under the /accounts API.
*/
interface AccountsApi {
@POST("/accounts/prelogin")
suspend fun preLogin(@Body body: PreLoginRequestJson): Result<PreLoginResponseJson>
@POST("/accounts/register")
suspend fun register(@Body body: RegisterRequestJson): Result<RegisterResponseJson.Success>
@POST("/accounts/password-hint")
suspend fun passwordHintRequest(
@Body body: PasswordHintRequestJson,

View file

@ -1,9 +1,14 @@
package com.x8bit.bitwarden.data.auth.datasource.network.api
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PrevalidateSsoResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RefreshTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterResponseJson
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET
@ -55,4 +60,10 @@ interface IdentityApi {
@Field(value = "refresh_token") refreshToken: String,
@Field(value = "grant_type") grantType: String,
): Call<RefreshTokenResponseJson>
@POST("/accounts/prelogin")
suspend fun preLogin(@Body body: PreLoginRequestJson): Result<PreLoginResponseJson>
@POST("/accounts/register")
suspend fun register(@Body body: RegisterRequestJson): Result<RegisterResponseJson.Success>
}

View file

@ -1,9 +1,6 @@
package com.x8bit.bitwarden.data.auth.datasource.network.service
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.SetPasswordRequestJson
@ -23,16 +20,6 @@ interface AccountsService {
*/
suspend fun deleteAccount(masterPasswordHash: String): Result<Unit>
/**
* Make pre login request to get KDF params.
*/
suspend fun preLogin(email: String): Result<PreLoginResponseJson>
/**
* Register a new account to Bitwarden.
*/
suspend fun register(body: RegisterRequestJson): Result<RegisterResponseJson>
/**
* Request a one-time passcode that is sent to the user's email.
*/

View file

@ -6,10 +6,6 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.CreateAccountKeysR
import com.x8bit.bitwarden.data.auth.datasource.network.model.DeleteAccountRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.SetPasswordRequestJson
@ -38,27 +34,6 @@ class AccountsServiceImpl(
override suspend fun deleteAccount(masterPasswordHash: String): Result<Unit> =
authenticatedAccountsApi.deleteAccount(DeleteAccountRequestJson(masterPasswordHash))
override suspend fun preLogin(email: String): Result<PreLoginResponseJson> =
accountsApi.preLogin(PreLoginRequestJson(email = email))
@Suppress("MagicNumber")
override suspend fun register(body: RegisterRequestJson): Result<RegisterResponseJson> =
accountsApi
.register(body)
.recoverCatching { throwable ->
val bitwardenError = throwable.toBitwardenError()
bitwardenError.parseErrorBodyOrNull<RegisterResponseJson.CaptchaRequired>(
code = 400,
json = json,
) ?: bitwardenError.parseErrorBodyOrNull<RegisterResponseJson.Invalid>(
codes = listOf(400, 429),
json = json,
) ?: bitwardenError.parseErrorBodyOrNull<RegisterResponseJson.Error>(
code = 429,
json = json,
) ?: throw throwable
}
override suspend fun requestOneTimePasscode(): Result<Unit> =
authenticatedAccountsApi.requestOtp()

View file

@ -2,8 +2,11 @@ package com.x8bit.bitwarden.data.auth.datasource.network.service
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.IdentityTokenAuthModel
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PrevalidateSsoResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RefreshTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorDataModel
/**
@ -11,6 +14,16 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorDataModel
*/
interface IdentityService {
/**
* Make pre login request to get KDF params.
*/
suspend fun preLogin(email: String): Result<PreLoginResponseJson>
/**
* Register a new account to Bitwarden.
*/
suspend fun register(body: RegisterRequestJson): Result<RegisterResponseJson>
/**
* Make request to get an access token.
*

View file

@ -3,8 +3,12 @@ package com.x8bit.bitwarden.data.auth.datasource.network.service
import com.x8bit.bitwarden.data.auth.datasource.network.api.IdentityApi
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.IdentityTokenAuthModel
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PrevalidateSsoResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RefreshTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorDataModel
import com.x8bit.bitwarden.data.platform.datasource.network.model.toBitwardenError
import com.x8bit.bitwarden.data.platform.datasource.network.util.base64UrlEncode
@ -19,6 +23,27 @@ class IdentityServiceImpl(
private val deviceModelProvider: DeviceModelProvider = DeviceModelProvider(),
) : IdentityService {
override suspend fun preLogin(email: String): Result<PreLoginResponseJson> =
api.preLogin(PreLoginRequestJson(email = email))
@Suppress("MagicNumber")
override suspend fun register(body: RegisterRequestJson): Result<RegisterResponseJson> =
api
.register(body)
.recoverCatching { throwable ->
val bitwardenError = throwable.toBitwardenError()
bitwardenError.parseErrorBodyOrNull<RegisterResponseJson.CaptchaRequired>(
code = 400,
json = json,
) ?: bitwardenError.parseErrorBodyOrNull<RegisterResponseJson.Invalid>(
codes = listOf(400, 429),
json = json,
) ?: bitwardenError.parseErrorBodyOrNull<RegisterResponseJson.Error>(
code = 429,
json = json,
) ?: throw throwable
}
@Suppress("MagicNumber")
override suspend fun getToken(
uniqueAppId: String,

View file

@ -453,7 +453,7 @@ class AuthRepositoryImpl(
email: String,
password: String,
captchaToken: String?,
): LoginResult = accountsService
): LoginResult = identityService
.preLogin(email = email)
.flatMap {
authSdkSource.hashPassword(
@ -664,7 +664,7 @@ class AuthRepositoryImpl(
kdf = kdf,
)
.flatMap { registerKeyResponse ->
accountsService.register(
identityService.register(
body = RegisterRequestJson(
email = email,
masterPasswordHash = registerKeyResponse.masterPasswordHash,

View file

@ -2,16 +2,12 @@ package com.x8bit.bitwarden.data.auth.datasource.network.service
import com.x8bit.bitwarden.data.auth.datasource.network.api.AccountsApi
import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedAccountsApi
import com.x8bit.bitwarden.data.auth.datasource.network.model.KdfTypeJson.PBKDF2_SHA256
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.SetPasswordRequestJson
import com.x8bit.bitwarden.data.platform.base.BaseServiceTest
import com.x8bit.bitwarden.data.platform.util.asSuccess
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
import okhttp3.mockwebserver.MockResponse
@ -57,168 +53,6 @@ class AccountsServiceTest : BaseServiceTest() {
assertTrue(service.deleteAccount(masterPasswordHash).isSuccess)
}
@Test
fun `preLogin with unknown kdf type be failure`() = runTest {
val json = """
{
"kdf": 2,
"kdfIterations": 1,
}
"""
val response = MockResponse().setBody(json)
server.enqueue(response)
assertTrue(service.preLogin(EMAIL).isFailure)
}
@Test
fun `preLogin Argon2 without memory property should be failure`() = runTest {
val json = """
{
"kdf": 1,
"kdfIterations": 1,
"kdfParallelism": 1
}
"""
val response = MockResponse().setBody(json)
server.enqueue(response)
assertTrue(service.preLogin(EMAIL).isFailure)
}
@Test
fun `preLogin Argon2 without parallelism property should be failure`() = runTest {
val json = """
{
"kdf": 1,
"kdfIterations": 1,
"kdfMemory": 1
}
"""
val response = MockResponse().setBody(json)
server.enqueue(response)
assertTrue(service.preLogin(EMAIL).isFailure)
}
@Test
fun `preLogin Argon2 should be success`() = runTest {
val json = """
{
"kdf": 1,
"kdfIterations": 1,
"kdfMemory": 1,
"kdfParallelism": 1
}
"""
val expectedResponse = PreLoginResponseJson(
kdfParams = PreLoginResponseJson.KdfParams.Argon2ID(
iterations = 1u,
memory = 1u,
parallelism = 1u,
),
)
val response = MockResponse().setBody(json)
server.enqueue(response)
assertEquals(expectedResponse.asSuccess(), service.preLogin(EMAIL))
}
@Test
fun `preLogin Pbkdf2 should be success`() = runTest {
val json = """
{
"kdf": 0,
"kdfIterations": 1
}
"""
val expectedResponse = PreLoginResponseJson(
kdfParams = PreLoginResponseJson.KdfParams.Pbkdf2(1u),
)
val response = MockResponse().setBody(json)
server.enqueue(response)
assertEquals(expectedResponse.asSuccess(), service.preLogin(EMAIL))
}
@Test
fun `register success json should be Success`() = runTest {
val json = """
{
"captchaBypassToken": "mock_token"
}
"""
val expectedResponse = RegisterResponseJson.Success(
captchaBypassToken = "mock_token",
)
val response = MockResponse().setBody(json)
server.enqueue(response)
assertEquals(expectedResponse.asSuccess(), service.register(registerRequestBody))
}
@Test
fun `register failure with Invalid json should be Invalid`() = runTest {
val json = """
{
"message": "The model state is invalid.",
"validationErrors": {
"": [
"Email '' is already taken."
]
},
"exceptionMessage": null,
"exceptionStackTrace": null,
"innerExceptionMessage": null,
"object": "error"
}
"""
val response = MockResponse().setResponseCode(400).setBody(json)
server.enqueue(response)
val result = service.register(registerRequestBody)
assertEquals(
RegisterResponseJson.Invalid(
message = "The model state is invalid.",
validationErrors = mapOf("" to listOf("Email '' is already taken.")),
),
result.getOrThrow(),
)
}
@Test
fun `register failure with Error json should return Error`() = runTest {
val json = """
{
"Object": "error",
"Message": "Slow down! Too many requests. Try again soon."
}
""".trimIndent()
val response = MockResponse().setResponseCode(429).setBody(json)
server.enqueue(response)
val result = service.register(registerRequestBody)
assertEquals(
RegisterResponseJson.Error(
message = "Slow down! Too many requests. Try again soon.",
),
result.getOrThrow(),
)
}
@Test
fun `register captcha json should be CaptchaRequired`() = runTest {
val json = """
{
"validationErrors": {
"HCaptcha_SiteKey": [
"mock_token"
]
}
}
"""
val expectedResponse = RegisterResponseJson.CaptchaRequired(
validationErrors = RegisterResponseJson.CaptchaRequired.ValidationErrors(
captchaKeys = listOf("mock_token"),
),
)
val response = MockResponse().setResponseCode(400).setBody(json)
server.enqueue(response)
assertEquals(expectedResponse.asSuccess(), service.register(registerRequestBody))
}
@Test
fun `requestOtp success should return Success`() = runTest {
val response = MockResponse().setResponseCode(200)
@ -338,21 +172,4 @@ class AccountsServiceTest : BaseServiceTest() {
)
assertTrue(result.isSuccess)
}
companion object {
private const val EMAIL = "email"
private val registerRequestBody = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = "mockk_masterPasswordHash",
masterPasswordHint = "mockk_masterPasswordHint",
captchaResponse = "mockk_captchaResponse",
key = "mockk_key",
keys = RegisterRequestJson.Keys(
publicKey = "mockk_publicKey",
encryptedPrivateKey = "mockk_encryptedPrivateKey",
),
kdfType = PBKDF2_SHA256,
kdfIterations = 600000U,
)
}
}

View file

@ -6,8 +6,11 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.IdentityTokenAuthM
import com.x8bit.bitwarden.data.auth.datasource.network.model.KdfTypeJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorUserDecryptionOptionsJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.MasterPasswordPolicyOptionsJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PrevalidateSsoResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RefreshTokenResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.TrustedDeviceUserDecryptionOptionsJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorAuthMethod
import com.x8bit.bitwarden.data.auth.datasource.network.model.UserDecryptionOptionsJson
@ -36,10 +39,186 @@ class IdentityServiceTest : BaseServiceTest() {
private val identityService = IdentityServiceImpl(
api = identityApi,
json = Json,
json = Json {
ignoreUnknownKeys = true
},
deviceModelProvider = deviceModelProvider,
)
@Test
fun `preLogin with unknown kdf type be failure`() = runTest {
val json = """
{
"kdf": 2,
"kdfIterations": 1,
}
"""
val response = MockResponse().setBody(json)
server.enqueue(response)
assertTrue(identityService.preLogin(EMAIL).isFailure)
}
@Test
fun `preLogin Argon2 without memory property should be failure`() = runTest {
val json = """
{
"kdf": 1,
"kdfIterations": 1,
"kdfParallelism": 1
}
"""
val response = MockResponse().setBody(json)
server.enqueue(response)
assertTrue(identityService.preLogin(EMAIL).isFailure)
}
@Test
fun `preLogin Argon2 without parallelism property should be failure`() = runTest {
val json = """
{
"kdf": 1,
"kdfIterations": 1,
"kdfMemory": 1
}
"""
val response = MockResponse().setBody(json)
server.enqueue(response)
assertTrue(identityService.preLogin(EMAIL).isFailure)
}
@Test
fun `preLogin Argon2 should be success`() = runTest {
val json = """
{
"kdf": 1,
"kdfIterations": 1,
"kdfMemory": 1,
"kdfParallelism": 1
}
"""
val expectedResponse = PreLoginResponseJson(
kdfParams = PreLoginResponseJson.KdfParams.Argon2ID(
iterations = 1u,
memory = 1u,
parallelism = 1u,
),
)
val response = MockResponse().setBody(json)
server.enqueue(response)
assertEquals(
expectedResponse.asSuccess(),
identityService.preLogin(EMAIL),
)
}
@Test
fun `preLogin Pbkdf2 should be success`() = runTest {
val json = """
{
"kdf": 0,
"kdfIterations": 1
}
"""
val expectedResponse = PreLoginResponseJson(
kdfParams = PreLoginResponseJson.KdfParams.Pbkdf2(1u),
)
val response = MockResponse().setBody(json)
server.enqueue(response)
assertEquals(
expectedResponse.asSuccess(),
identityService.preLogin(EMAIL),
)
}
@Test
fun `register success json should be Success`() = runTest {
val json = """
{
"captchaBypassToken": "mock_token"
}
"""
val expectedResponse = RegisterResponseJson.Success(
captchaBypassToken = "mock_token",
)
val response = MockResponse().setBody(json)
server.enqueue(response)
assertEquals(
expectedResponse.asSuccess(),
identityService.register(registerRequestBody),
)
}
@Test
fun `register failure with Invalid json should be Invalid`() = runTest {
val json = """
{
"message": "The model state is invalid.",
"validationErrors": {
"": [
"Email '' is already taken."
]
},
"exceptionMessage": null,
"exceptionStackTrace": null,
"innerExceptionMessage": null,
"object": "error"
}
"""
val response = MockResponse().setResponseCode(400).setBody(json)
server.enqueue(response)
val result = identityService.register(registerRequestBody)
assertEquals(
RegisterResponseJson.Invalid(
message = "The model state is invalid.",
validationErrors = mapOf("" to listOf("Email '' is already taken.")),
),
result.getOrThrow(),
)
}
@Test
fun `register failure with Error json should return Error`() = runTest {
val json = """
{
"Object": "error",
"Message": "Slow down! Too many requests. Try again soon."
}
""".trimIndent()
val response = MockResponse().setResponseCode(429).setBody(json)
server.enqueue(response)
val result = identityService.register(registerRequestBody)
assertEquals(
RegisterResponseJson.Error(
message = "Slow down! Too many requests. Try again soon.",
),
result.getOrThrow(),
)
}
@Test
fun `register captcha json should be CaptchaRequired`() = runTest {
val json = """
{
"validationErrors": {
"HCaptcha_SiteKey": [
"mock_token"
]
}
}
"""
val expectedResponse = RegisterResponseJson.CaptchaRequired(
validationErrors = RegisterResponseJson.CaptchaRequired.ValidationErrors(
captchaKeys = listOf("mock_token"),
),
)
val response = MockResponse().setResponseCode(400).setBody(json)
server.enqueue(response)
assertEquals(
expectedResponse.asSuccess(),
identityService.register(registerRequestBody),
)
}
@Test
fun `getToken when request response is Success should return Success`() = runTest {
server.enqueue(MockResponse().setBody(LOGIN_SUCCESS_JSON))
@ -153,6 +332,19 @@ class IdentityServiceTest : BaseServiceTest() {
private const val REFRESH_TOKEN = "refreshToken"
private const val EMAIL = "email"
private const val PASSWORD_HASH = "passwordHash"
private val registerRequestBody = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = "mockk_masterPasswordHash",
masterPasswordHint = "mockk_masterPasswordHint",
captchaResponse = "mockk_captchaResponse",
key = "mockk_key",
keys = RegisterRequestJson.Keys(
publicKey = "mockk_publicKey",
encryptedPrivateKey = "mockk_encryptedPrivateKey",
),
kdfType = KdfTypeJson.PBKDF2_SHA256,
kdfIterations = 600000U,
)
}
}

View file

@ -396,7 +396,7 @@ class AuthRepositoryTest {
runTest {
val successResponse = GET_TOKEN_RESPONSE_SUCCESS
coEvery {
accountsService.preLogin(email = EMAIL)
identityService.preLogin(email = EMAIL)
} returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
@ -453,7 +453,7 @@ class AuthRepositoryTest {
// Verify the results.
assertEquals(LoginResult.Success, result)
assertEquals(AuthState.Authenticated(ACCESS_TOKEN), repository.authStateFlow.value)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
fakeAuthDiskSource.assertPrivateKey(
userId = USER_ID_1,
privateKey = "privateKey",
@ -1260,18 +1260,18 @@ class AuthRepositoryTest {
@Test
fun `login when pre login fails should return Error with no message`() = runTest {
coEvery {
accountsService.preLogin(email = EMAIL)
identityService.preLogin(email = EMAIL)
} returns RuntimeException().asFailure()
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
assertEquals(LoginResult.Error(errorMessage = null), result)
assertEquals(AuthState.Unauthenticated, repository.authStateFlow.value)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
}
@Test
fun `login get token fails should return Error with no message`() = runTest {
coEvery {
accountsService.preLogin(email = EMAIL)
identityService.preLogin(email = EMAIL)
} returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
@ -1287,7 +1287,7 @@ class AuthRepositoryTest {
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
assertEquals(LoginResult.Error(errorMessage = null), result)
assertEquals(AuthState.Unauthenticated, repository.authStateFlow.value)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
coVerify {
identityService.getToken(
email = EMAIL,
@ -1304,7 +1304,7 @@ class AuthRepositoryTest {
@Test
fun `login get token returns Invalid should return Error with correct message`() = runTest {
coEvery {
accountsService.preLogin(email = EMAIL)
identityService.preLogin(email = EMAIL)
} returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
@ -1327,7 +1327,7 @@ class AuthRepositoryTest {
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
assertEquals(LoginResult.Error(errorMessage = "mock_error_message"), result)
assertEquals(AuthState.Unauthenticated, repository.authStateFlow.value)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
coVerify {
identityService.getToken(
email = EMAIL,
@ -1347,7 +1347,7 @@ class AuthRepositoryTest {
runTest {
val successResponse = GET_TOKEN_RESPONSE_SUCCESS
coEvery {
accountsService.preLogin(email = EMAIL)
identityService.preLogin(email = EMAIL)
} returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
@ -1381,7 +1381,7 @@ class AuthRepositoryTest {
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
assertEquals(LoginResult.Success, result)
assertEquals(AuthState.Authenticated(ACCESS_TOKEN), repository.authStateFlow.value)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
fakeAuthDiskSource.assertPrivateKey(
userId = USER_ID_1,
privateKey = "privateKey",
@ -1436,7 +1436,7 @@ class AuthRepositoryTest {
),
)
coEvery {
accountsService.preLogin(email = EMAIL)
identityService.preLogin(email = EMAIL)
} returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
@ -1463,7 +1463,7 @@ class AuthRepositoryTest {
)
assertEquals(LoginResult.Success, result)
assertEquals(AuthState.Authenticated(ACCESS_TOKEN), repository.authStateFlow.value)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
fakeAuthDiskSource.assertMasterPasswordHash(
userId = USER_ID_1,
passwordHash = PASSWORD_HASH,
@ -1509,7 +1509,7 @@ class AuthRepositoryTest {
// Set up login for User 1
val successResponse = GET_TOKEN_RESPONSE_SUCCESS
coEvery {
accountsService.preLogin(email = EMAIL)
identityService.preLogin(email = EMAIL)
} returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
@ -1545,7 +1545,7 @@ class AuthRepositoryTest {
assertEquals(LoginResult.Success, result)
assertEquals(AuthState.Authenticated(ACCESS_TOKEN), repository.authStateFlow.value)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
fakeAuthDiskSource.assertPrivateKey(
userId = USER_ID_1,
privateKey = "privateKey",
@ -1585,7 +1585,7 @@ class AuthRepositoryTest {
@Test
fun `login get token returns captcha request should return CaptchaRequired`() = runTest {
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
email = EMAIL,
@ -1600,7 +1600,7 @@ class AuthRepositoryTest {
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
assertEquals(LoginResult.CaptchaRequired(CAPTCHA_KEY), result)
assertEquals(AuthState.Unauthenticated, repository.authStateFlow.value)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
coVerify {
identityService.getToken(
email = EMAIL,
@ -1616,7 +1616,7 @@ class AuthRepositoryTest {
@Test
fun `login get token returns two factor request should return TwoFactorRequired`() = runTest {
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
email = EMAIL,
@ -1641,7 +1641,7 @@ class AuthRepositoryTest {
GetTokenResponseJson.TwoFactorRequired(TWO_FACTOR_AUTH_METHODS_DATA, null, null),
)
assertEquals(AuthState.Unauthenticated, repository.authStateFlow.value)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
coVerify {
identityService.getToken(
email = EMAIL,
@ -1659,7 +1659,7 @@ class AuthRepositoryTest {
fun `login two factor with remember saves two factor auth token`() = runTest {
// Attempt a normal login with a two factor error first, so that the auth
// data will be cached.
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
email = EMAIL,
@ -1679,7 +1679,7 @@ class AuthRepositoryTest {
.asSuccess()
val firstResult = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
assertEquals(LoginResult.TwoFactorRequired, firstResult)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
coVerify {
identityService.getToken(
email = EMAIL,
@ -1750,7 +1750,7 @@ class AuthRepositoryTest {
)
val successResponse = GET_TOKEN_RESPONSE_SUCCESS
coEvery {
accountsService.preLogin(email = EMAIL)
identityService.preLogin(email = EMAIL)
} returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
@ -1785,7 +1785,7 @@ class AuthRepositoryTest {
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
assertEquals(LoginResult.Success, result)
assertEquals(AuthState.Authenticated(ACCESS_TOKEN), repository.authStateFlow.value)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
fakeAuthDiskSource.assertPrivateKey(
userId = USER_ID_1,
privateKey = "privateKey",
@ -2908,7 +2908,7 @@ class AuthRepositoryTest {
haveIBeenPwnedService.hasPasswordBeenBreached(PASSWORD)
} returns Throwable().asFailure()
coEvery {
accountsService.register(
identityService.register(
body = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = PASSWORD_HASH,
@ -2996,7 +2996,7 @@ class AuthRepositoryTest {
haveIBeenPwnedService.hasPasswordBeenBreached(PASSWORD)
} returns false.asSuccess()
coEvery {
accountsService.register(
identityService.register(
body = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = PASSWORD_HASH,
@ -3027,9 +3027,9 @@ class AuthRepositoryTest {
@Test
fun `register Success should return Success`() = runTest {
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
accountsService.register(
identityService.register(
body = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = PASSWORD_HASH,
@ -3060,9 +3060,9 @@ class AuthRepositoryTest {
@Test
fun `register returns CaptchaRequired captchaKeys empty should return Error no message`() =
runTest {
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
accountsService.register(
identityService.register(
body = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = PASSWORD_HASH,
@ -3101,9 +3101,9 @@ class AuthRepositoryTest {
@Test
fun `register returns CaptchaRequired captchaKeys should return CaptchaRequired`() =
runTest {
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
accountsService.register(
identityService.register(
body = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = PASSWORD_HASH,
@ -3141,9 +3141,9 @@ class AuthRepositoryTest {
@Test
fun `register Failure should return Error with no message`() = runTest {
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
accountsService.register(
identityService.register(
body = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = PASSWORD_HASH,
@ -3173,9 +3173,9 @@ class AuthRepositoryTest {
@Test
fun `register returns Invalid should return Error with invalid message`() = runTest {
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
accountsService.register(
identityService.register(
body = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = PASSWORD_HASH,
@ -3205,9 +3205,9 @@ class AuthRepositoryTest {
@Test
fun `register returns Invalid should return Error with first message in map`() = runTest {
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
accountsService.register(
identityService.register(
body = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = PASSWORD_HASH,
@ -3242,9 +3242,9 @@ class AuthRepositoryTest {
@Test
fun `register returns Error body should return Error with message`() = runTest {
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
accountsService.register(
identityService.register(
body = RegisterRequestJson(
email = EMAIL,
masterPasswordHash = PASSWORD_HASH,
@ -4108,7 +4108,7 @@ class AuthRepositoryTest {
fun `resendVerificationCodeEmail uses cached request data to make api call`() = runTest {
// Attempt a normal login with a two factor error first, so that the necessary
// data will be cached.
coEvery { accountsService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
coEvery {
identityService.getToken(
email = EMAIL,
@ -4128,7 +4128,7 @@ class AuthRepositoryTest {
.asSuccess()
val firstResult = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
assertEquals(LoginResult.TwoFactorRequired, firstResult)
coVerify { accountsService.preLogin(email = EMAIL) }
coVerify { identityService.preLogin(email = EMAIL) }
coVerify {
identityService.getToken(
email = EMAIL,