From be0ebb9b3f24b052f2bc5405d95c80d9b176c0e6 Mon Sep 17 00:00:00 2001 From: Patrick Honkonen <1883101+SaintPatrck@users.noreply.github.com> Date: Mon, 21 Oct 2024 09:23:49 -0400 Subject: [PATCH] [PM-13396] Add support for legacy error response model in getToken (#4112) --- .../network/model/GetTokenResponseJson.kt | 22 ++++++++++++- .../auth/repository/AuthRepositoryImpl.kt | 4 +-- .../network/service/IdentityServiceTest.kt | 32 +++++++++++++++++++ .../auth/repository/AuthRepositoryTest.kt | 5 ++- 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/model/GetTokenResponseJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/model/GetTokenResponseJson.kt index 636b9a8a9..ee25582af 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/model/GetTokenResponseJson.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/model/GetTokenResponseJson.kt @@ -96,9 +96,17 @@ sealed class GetTokenResponseJson { @Serializable data class Invalid( @SerialName("ErrorModel") - val errorModel: ErrorModel, + val errorModel: ErrorModel?, + @SerialName("errorModel") + val legacyErrorModel: LegacyErrorModel?, ) : GetTokenResponseJson() { + /** + * The error message returned from the server, or null. + */ + val errorMessage: String? + get() = errorModel?.errorMessage ?: legacyErrorModel?.errorMessage + /** * The error body of an invalid request containing a message. */ @@ -107,6 +115,18 @@ sealed class GetTokenResponseJson { @SerialName("Message") val errorMessage: String, ) + + /** + * The legacy error body of an invalid request containing a message. + * + * This model is used to support older versions of the error response model that used + * lower-case keys. + */ + @Serializable + data class LegacyErrorModel( + @SerialName("message") + val errorMessage: String, + ) } /** diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt index 0b369b6d3..747f60163 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt @@ -45,7 +45,6 @@ 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.DeleteAccountResult import com.x8bit.bitwarden.data.auth.repository.model.EmailTokenResult -import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState import com.x8bit.bitwarden.data.auth.repository.model.KnownDeviceResult import com.x8bit.bitwarden.data.auth.repository.model.LoginResult import com.x8bit.bitwarden.data.auth.repository.model.NewSsoUserResult @@ -99,6 +98,7 @@ import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.PushManager import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager +import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState import com.x8bit.bitwarden.data.platform.manager.model.FlagKey import com.x8bit.bitwarden.data.platform.manager.util.getActivePolicies import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository @@ -1503,7 +1503,7 @@ class AuthRepositoryImpl( ) is GetTokenResponseJson.Invalid -> LoginResult.Error( - errorMessage = loginResponse.errorModel.errorMessage, + errorMessage = loginResponse.errorMessage, ) } }, diff --git a/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/service/IdentityServiceTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/service/IdentityServiceTest.kt index 50d92b082..90d64d205 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/service/IdentityServiceTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/service/IdentityServiceTest.kt @@ -273,6 +273,22 @@ class IdentityServiceTest : BaseServiceTest() { assertEquals(INVALID_LOGIN.asSuccess(), result) } + @Test + fun `getToken when response is a 400 with a legacy error body should return Invalid`() = + runTest { + server.enqueue(MockResponse().setResponseCode(400).setBody(LEGACY_INVALID_LOGIN_JSON)) + val result = identityService.getToken( + email = EMAIL, + authModel = IdentityTokenAuthModel.MasterPassword( + username = EMAIL, + password = PASSWORD_HASH, + ), + captchaToken = null, + uniqueAppId = UNIQUE_APP_ID, + ) + assertEquals(LEGACY_INVALID_LOGIN.asSuccess(), result) + } + @Test fun `prevalidateSso when response is success should return PrevalidateSsoResponseJson`() = runTest { @@ -613,6 +629,14 @@ private const val INVALID_LOGIN_JSON = """ } """ +private const val LEGACY_INVALID_LOGIN_JSON = """ +{ + "errorModel": { + "message": "Legacy-123" + } +} +""" + private const val TOO_MANY_REQUEST_ERROR_JSON = """ { "Object": "error", @@ -645,6 +669,14 @@ private val INVALID_LOGIN = GetTokenResponseJson.Invalid( errorModel = GetTokenResponseJson.Invalid.ErrorModel( errorMessage = "123", ), + legacyErrorModel = null, +) + +private val LEGACY_INVALID_LOGIN = GetTokenResponseJson.Invalid( + errorModel = null, + legacyErrorModel = GetTokenResponseJson.Invalid.LegacyErrorModel( + errorMessage = "Legacy-123", + ), ) private val SEND_VERIFICATION_EMAIL_REQUEST = SendVerificationEmailRequestJson( diff --git a/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt index 162ba1851..12336587b 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt @@ -65,7 +65,6 @@ 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.DeleteAccountResult import com.x8bit.bitwarden.data.auth.repository.model.EmailTokenResult -import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState import com.x8bit.bitwarden.data.auth.repository.model.KnownDeviceResult import com.x8bit.bitwarden.data.auth.repository.model.LoginResult import com.x8bit.bitwarden.data.auth.repository.model.NewSsoUserResult @@ -106,6 +105,7 @@ import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.PushManager import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager +import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState import com.x8bit.bitwarden.data.platform.manager.model.FlagKey import com.x8bit.bitwarden.data.platform.manager.model.NotificationLogoutData import com.x8bit.bitwarden.data.platform.repository.SettingsRepository @@ -1522,6 +1522,7 @@ class AuthRepositoryTest { errorModel = GetTokenResponseJson.Invalid.ErrorModel( errorMessage = "mock_error_message", ), + legacyErrorModel = null, ) .asSuccess() @@ -2314,6 +2315,7 @@ class AuthRepositoryTest { errorModel = GetTokenResponseJson.Invalid.ErrorModel( errorMessage = "mock_error_message", ), + legacyErrorModel = null, ) .asSuccess() @@ -2782,6 +2784,7 @@ class AuthRepositoryTest { errorModel = GetTokenResponseJson.Invalid.ErrorModel( errorMessage = "mock_error_message", ), + legacyErrorModel = null, ) .asSuccess()