Skip to content

Commit

Permalink
Merge branch 'main' into pm-18451/exempt-from-policies
Browse files Browse the repository at this point in the history
# Conflicts:
#	app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt
  • Loading branch information
andrebispo5 committed Feb 26, 2025
2 parents 09cb26e + 64da29f commit 924427b
Show file tree
Hide file tree
Showing 112 changed files with 993 additions and 439 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.x8bit.bitwarden.data.auth.datasource.network.model

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames
import kotlinx.serialization.json.JsonObject

/**
Expand Down Expand Up @@ -92,20 +94,21 @@ sealed class GetTokenResponseJson {

/**
* Models json body of an invalid request.
*
* This model supports older versions of the error response model that used lower-case keys.
*/
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class Invalid(
@JsonNames("errorModel")
@SerialName("ErrorModel")
val errorModel: ErrorModel?,
@SerialName("errorModel")
val legacyErrorModel: LegacyErrorModel?,
private val errorModel: ErrorModel?,
) : GetTokenResponseJson() {

/**
* The error message returned from the server, or null.
*/
val errorMessage: String?
get() = errorModel?.errorMessage ?: legacyErrorModel?.errorMessage
val errorMessage: String? get() = errorModel?.errorMessage

/**
* The type of invalid responses that can be received.
Expand All @@ -131,24 +134,16 @@ sealed class GetTokenResponseJson {

/**
* The error body of an invalid request containing a message.
*
* This model supports older versions of the error response model that used lower-case
* keys.
*/
@Serializable
data class ErrorModel(
@JsonNames("message")
@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,
)
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.x8bit.bitwarden.data.auth.datasource.network.model

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames

/**
* Models response bodies for the register request.
Expand Down Expand Up @@ -50,20 +52,24 @@ sealed class RegisterResponseJson {
* The values in the array should be used for display to the user, since the keys tend to come
* back as nonsense. (eg: empty string key)
*/
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class Invalid(
@SerialName("message")
private val invalidMessage: String? = null,

@JsonNames("message")
@SerialName("Message")
private val errorMessage: String? = null,
private val invalidMessage: String? = null,

@SerialName("validationErrors")
val validationErrors: Map<String, List<String>>?,
private val validationErrors: Map<String, List<String>>?,
) : RegisterResponseJson() {
/**
* A generic error message.
*/
val message: String? get() = invalidMessage ?: errorMessage
val message: String?
get() = validationErrors
?.values
?.firstOrNull()
?.firstOrNull()
?: invalidMessage
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.SetPasswordRequest
import com.x8bit.bitwarden.data.auth.datasource.network.model.VerifyOtpRequestJson
import com.x8bit.bitwarden.data.platform.datasource.network.model.toBitwardenError
import com.x8bit.bitwarden.data.platform.datasource.network.util.HEADER_VALUE_BEARER_PREFIX
import com.x8bit.bitwarden.data.platform.datasource.network.util.NetworkErrorCode
import com.x8bit.bitwarden.data.platform.datasource.network.util.parseErrorBodyOrNull
import com.x8bit.bitwarden.data.platform.datasource.network.util.toResult
import kotlinx.serialization.json.Json
Expand Down Expand Up @@ -73,7 +74,7 @@ class AccountsServiceImpl(
throwable
.toBitwardenError()
.parseErrorBodyOrNull<DeleteAccountResponseJson.Invalid>(
code = 400,
code = NetworkErrorCode.BAD_REQUEST,
json = json,
)
?: throw throwable
Expand Down Expand Up @@ -104,7 +105,7 @@ class AccountsServiceImpl(
throwable
.toBitwardenError()
.parseErrorBodyOrNull<PasswordHintResponseJson.Error>(
code = 429,
code = NetworkErrorCode.TOO_MANY_REQUESTS,
json = json,
)
?: throw throwable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.TwoFactorDataModel
import com.x8bit.bitwarden.data.auth.datasource.network.model.VerifyEmailTokenRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.VerifyEmailTokenResponseJson
import com.x8bit.bitwarden.data.platform.datasource.network.model.toBitwardenError
import com.x8bit.bitwarden.data.platform.datasource.network.util.NetworkErrorCode
import com.x8bit.bitwarden.data.platform.datasource.network.util.base64UrlEncode
import com.x8bit.bitwarden.data.platform.datasource.network.util.executeForNetworkResult
import com.x8bit.bitwarden.data.platform.datasource.network.util.parseErrorBodyOrNull
Expand All @@ -34,7 +35,6 @@ class IdentityServiceImpl(
.preLogin(PreLoginRequestJson(email = email))
.toResult()

@Suppress("MagicNumber")
override suspend fun register(body: RegisterRequestJson): Result<RegisterResponseJson> =
unauthenticatedIdentityApi
.register(body)
Expand All @@ -43,17 +43,19 @@ class IdentityServiceImpl(
val bitwardenError = throwable.toBitwardenError()
bitwardenError
.parseErrorBodyOrNull<RegisterResponseJson.CaptchaRequired>(
code = 400,
code = NetworkErrorCode.BAD_REQUEST,
json = json,
)
?: bitwardenError.parseErrorBodyOrNull<RegisterResponseJson.Invalid>(
codes = listOf(400, 429),
codes = listOf(
NetworkErrorCode.BAD_REQUEST,
NetworkErrorCode.TOO_MANY_REQUESTS,
),
json = json,
)
?: throw throwable
}

@Suppress("MagicNumber")
override suspend fun getToken(
uniqueAppId: String,
email: String,
Expand Down Expand Up @@ -87,21 +89,20 @@ class IdentityServiceImpl(
val bitwardenError = throwable.toBitwardenError()
bitwardenError
.parseErrorBodyOrNull<GetTokenResponseJson.CaptchaRequired>(
code = 400,
code = NetworkErrorCode.BAD_REQUEST,
json = json,
)
?: bitwardenError.parseErrorBodyOrNull<GetTokenResponseJson.TwoFactorRequired>(
code = 400,
code = NetworkErrorCode.BAD_REQUEST,
json = json,
)
?: bitwardenError.parseErrorBodyOrNull<GetTokenResponseJson.Invalid>(
code = 400,
code = NetworkErrorCode.BAD_REQUEST,
json = json,
)
?: throw throwable
}

@Suppress("MagicNumber")
override suspend fun prevalidateSso(
organizationIdentifier: String,
): Result<PrevalidateSsoResponseJson> = unauthenticatedIdentityApi
Expand All @@ -113,7 +114,7 @@ class IdentityServiceImpl(
val bitwardenError = throwable.toBitwardenError()
bitwardenError
.parseErrorBodyOrNull<PrevalidateSsoResponseJson.Error>(
code = 400,
code = NetworkErrorCode.BAD_REQUEST,
json = json,
)
?: throw throwable
Expand All @@ -130,7 +131,6 @@ class IdentityServiceImpl(
.executeForNetworkResult()
.toResult()

@Suppress("MagicNumber")
override suspend fun registerFinish(
body: RegisterFinishRequestJson,
): Result<RegisterResponseJson> =
Expand All @@ -141,13 +141,15 @@ class IdentityServiceImpl(
val bitwardenError = throwable.toBitwardenError()
bitwardenError
.parseErrorBodyOrNull<RegisterResponseJson.Invalid>(
codes = listOf(400, 429),
codes = listOf(
NetworkErrorCode.BAD_REQUEST,
NetworkErrorCode.TOO_MANY_REQUESTS,
),
json = json,
)
?: throw throwable
}

@Suppress("MagicNumber")
override suspend fun sendVerificationEmail(
body: SendVerificationEmailRequestJson,
): Result<SendVerificationEmailResponseJson> {
Expand All @@ -159,14 +161,13 @@ class IdentityServiceImpl(
throwable
.toBitwardenError()
.parseErrorBodyOrNull<SendVerificationEmailResponseJson.Invalid>(
code = 400,
code = NetworkErrorCode.BAD_REQUEST,
json = json,
)
?: throw throwable
}
}

@Suppress("MagicNumber")
override suspend fun verifyEmailRegistrationToken(
body: VerifyEmailTokenRequestJson,
): Result<VerifyEmailTokenResponseJson> = unauthenticatedIdentityApi
Expand All @@ -179,7 +180,7 @@ class IdentityServiceImpl(
val bitwardenError = throwable.toBitwardenError()
bitwardenError
.parseErrorBodyOrNull<VerifyEmailTokenResponseJson.Invalid>(
code = 400,
code = NetworkErrorCode.BAD_REQUEST,
json = json,
)
?.checkForExpiredMessage()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -910,14 +910,7 @@ class AuthRepositoryImpl(
}

is RegisterResponseJson.Invalid -> {
RegisterResult.Error(
errorMessage = it
.validationErrors
?.values
?.firstOrNull()
?.firstOrNull()
?: it.message,
)
RegisterResult.Error(errorMessage = it.message)
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
* @property name The name of the organization (if applicable).
* @property shouldManageResetPassword Indicates that this user has the permission to manage their
* own password.
* @property shouldManagePolicies Indicates that this user has the permission to manage policies.
* @property shouldUseKeyConnector Indicates that the organization uses a key connector.
* @property role The user's role in the organization.
*/
data class Organization(
val id: String,
val name: String?,
val shouldManageResetPassword: Boolean,
val shouldManagePolicies: Boolean,
val shouldUseKeyConnector: Boolean,
val role: OrganizationType,
)
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fun SyncResponseJson.Profile.Organization.toOrganization(): Organization =
shouldUseKeyConnector = this.shouldUseKeyConnector,
role = this.type,
shouldManageResetPassword = this.permissions.shouldManageResetPassword,
shouldManagePolicies = this.permissions.shouldManagePolicies,
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ import retrofit2.HttpException
* will be attempted to be parsed.
* @param json [Json] serializer to use.
*/
inline fun <reified T> BitwardenError.parseErrorBodyOrNull(codes: List<Int>, json: Json): T? =
inline fun <reified T> BitwardenError.parseErrorBodyOrNull(
codes: List<NetworkErrorCode>,
json: Json,
): T? =
(this as? BitwardenError.Http)
?.takeIf { codes.any { it == this.code } }
?.takeIf { codes.any { it.code == this.code } }
?.responseBodyString
?.let { responseBody ->
json.decodeFromStringOrNull(responseBody)
Expand All @@ -28,5 +31,7 @@ inline fun <reified T> BitwardenError.parseErrorBodyOrNull(codes: List<Int>, jso
/**
* Helper for calling [parseErrorBodyOrNull] with a single code.
*/
inline fun <reified T> BitwardenError.parseErrorBodyOrNull(code: Int, json: Json): T? =
parseErrorBodyOrNull(listOf(code), json)
inline fun <reified T> BitwardenError.parseErrorBodyOrNull(
code: NetworkErrorCode,
json: Json,
): T? = parseErrorBodyOrNull(codes = listOf(code), json = json)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.x8bit.bitwarden.data.platform.datasource.network.util

/**
* An enum that represents HTTP error codes that we may need to parse for specific responses.
*/
enum class NetworkErrorCode(
val code: Int,
) {
BAD_REQUEST(code = 400),
TOO_MANY_REQUESTS(code = 429),
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ sealed class FlagKey<out T : Any> {
OnboardingFlow,
OnboardingCarousel,
ImportLoginsFlow,
SshKeyCipherItems,
VerifiedSsoDomainEndpoint,
CredentialExchangeProtocolImport,
CredentialExchangeProtocolExport,
Expand Down Expand Up @@ -94,15 +93,6 @@ sealed class FlagKey<out T : Any> {
override val isRemotelyConfigured: Boolean = true
}

/**
* Data object holding the feature flag key for the SSH key cipher items feature.
*/
data object SshKeyCipherItems : FlagKey<Boolean>() {
override val keyName: String = "ssh-key-vault-item"
override val defaultValue: Boolean = false
override val isRemotelyConfigured: Boolean = true
}

/**
* Data object holding the feature flag key for the new verified SSO domain endpoint feature.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.vault.datasource.network.service
import androidx.core.net.toUri
import com.bitwarden.vault.Attachment
import com.x8bit.bitwarden.data.platform.datasource.network.model.toBitwardenError
import com.x8bit.bitwarden.data.platform.datasource.network.util.NetworkErrorCode
import com.x8bit.bitwarden.data.platform.datasource.network.util.parseErrorBodyOrNull
import com.x8bit.bitwarden.data.platform.datasource.network.util.toResult
import com.x8bit.bitwarden.data.platform.util.asFailure
Expand Down Expand Up @@ -110,7 +111,7 @@ class CiphersServiceImpl(
throwable
.toBitwardenError()
.parseErrorBodyOrNull<UpdateCipherResponseJson.Invalid>(
code = 400,
code = NetworkErrorCode.BAD_REQUEST,
json = json,
)
?: throw throwable
Expand Down Expand Up @@ -229,7 +230,7 @@ class CiphersServiceImpl(
throwable
.toBitwardenError()
.parseErrorBodyOrNull<ImportCiphersResponseJson.Invalid>(
code = 400,
code = NetworkErrorCode.BAD_REQUEST,
json = json,
)
?: throw throwable
Expand Down
Loading

0 comments on commit 924427b

Please sign in to comment.