PM-22776: Update logic for determining base domains (#5374)

This commit is contained in:
David Perez 2025-06-18 10:05:24 -05:00 committed by GitHub
parent 6c41c358ac
commit 292a28d155
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 120 additions and 73 deletions

View File

@ -3,7 +3,7 @@ package com.x8bit.bitwarden.data.platform.manager.provider
import com.bitwarden.data.repository.model.Environment
import com.x8bit.bitwarden.data.platform.datasource.disk.FakeEnvironmentDiskSource
import com.x8bit.bitwarden.data.platform.provider.BaseUrlsProviderImpl
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class BaseUrlsProviderTest {
@ -16,8 +16,8 @@ class BaseUrlsProviderTest {
@Test
fun `getBaseApiUrl should return correct api URL when preAuthEnvironmentUrlData is set`() {
fakeEnvironmentDiskSource.preAuthEnvironmentUrlData = Environment.Eu.environmentUrlData
Assertions.assertEquals(
"https://vault.bitwarden.eu/api",
assertEquals(
"https://api.bitwarden.eu",
baseUrlsManager.getBaseApiUrl(),
)
}
@ -25,8 +25,8 @@ class BaseUrlsProviderTest {
@Test
fun `getBaseApiUrl should return default value when preAuthEnvironmentUrlData is null`() {
fakeEnvironmentDiskSource.preAuthEnvironmentUrlData = null
Assertions.assertEquals(
"https://vault.bitwarden.com/api",
assertEquals(
"https://api.bitwarden.com",
baseUrlsManager.getBaseApiUrl(),
)
}
@ -34,8 +34,8 @@ class BaseUrlsProviderTest {
@Test
fun `getBaseIdentityUrl should return correct api URL when preAuthEnvironmentUrlData is set`() {
fakeEnvironmentDiskSource.preAuthEnvironmentUrlData = Environment.Eu.environmentUrlData
Assertions.assertEquals(
"https://vault.bitwarden.eu/identity",
assertEquals(
"https://identity.bitwarden.eu",
baseUrlsManager.getBaseIdentityUrl(),
)
}
@ -43,8 +43,8 @@ class BaseUrlsProviderTest {
@Test
fun `getBaseIdentityUrl should return default value when preAuthEnvironmentUrlData is null`() {
fakeEnvironmentDiskSource.preAuthEnvironmentUrlData = null
Assertions.assertEquals(
"https://vault.bitwarden.com/identity",
assertEquals(
"https://identity.bitwarden.com",
baseUrlsManager.getBaseIdentityUrl(),
)
}
@ -52,8 +52,8 @@ class BaseUrlsProviderTest {
@Test
fun `getBaseEventsUrl should return correct api URL when preAuthEnvironmentUrlData is set`() {
fakeEnvironmentDiskSource.preAuthEnvironmentUrlData = Environment.Eu.environmentUrlData
Assertions.assertEquals(
"https://vault.bitwarden.eu/events",
assertEquals(
"https://events.bitwarden.eu",
baseUrlsManager.getBaseEventsUrl(),
)
}
@ -61,8 +61,8 @@ class BaseUrlsProviderTest {
@Test
fun `getBaseEventsUrl should return default value when preAuthEnvironmentUrlData is null`() {
fakeEnvironmentDiskSource.preAuthEnvironmentUrlData = null
Assertions.assertEquals(
"https://vault.bitwarden.com/events",
assertEquals(
"https://events.bitwarden.com",
baseUrlsManager.getBaseEventsUrl(),
)
}

View File

@ -1159,7 +1159,7 @@ class SearchViewModelTest : BaseViewModelTest() {
every {
ciphers.toViewState(
searchTerm = "",
baseIconUrl = "https://vault.bitwarden.com/icons",
baseIconUrl = "https://icons.bitwarden.net",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
@ -1261,7 +1261,7 @@ class SearchViewModelTest : BaseViewModelTest() {
every {
ciphers.toViewState(
searchTerm = "",
baseIconUrl = "https://vault.bitwarden.com/icons",
baseIconUrl = "https://icons.bitwarden.net",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
@ -1373,7 +1373,7 @@ class SearchViewModelTest : BaseViewModelTest() {
every {
ciphers.toViewState(
searchTerm = "",
baseIconUrl = "https://vault.bitwarden.com/icons",
baseIconUrl = "https://icons.bitwarden.net",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
@ -1488,7 +1488,7 @@ class SearchViewModelTest : BaseViewModelTest() {
every {
ciphers.toViewState(
searchTerm = "",
baseIconUrl = "https://vault.bitwarden.com/icons",
baseIconUrl = "https://icons.bitwarden.net",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
@ -1663,7 +1663,7 @@ class SearchViewModelTest : BaseViewModelTest() {
every {
ciphers.toViewState(
searchTerm = "",
baseIconUrl = "https://vault.bitwarden.com/icons",
baseIconUrl = "https://icons.bitwarden.net",
isIconLoadingDisabled = false,
isAutofill = true,
hasMasterPassword = true,
@ -1697,7 +1697,7 @@ private val DEFAULT_STATE: SearchState = SearchState(
dialogState = null,
vaultFilterData = null,
baseWebSendUrl = "https://send.bitwarden.com/#",
baseIconUrl = "https://vault.bitwarden.com/icons",
baseIconUrl = "https://icons.bitwarden.net",
isIconLoadingDisabled = false,
hasMasterPassword = true,
totpData = null,

View File

@ -1848,7 +1848,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
secondSubtitleTestTag = "PasskeySite",
subtitleTestTag = "PasskeyName",
iconData = IconData.Network(
uri = "https://vault.bitwarden.com/icons/www.mockuri.com/icon.png",
uri = "https://icons.bitwarden.net/www.mockuri.com/icon.png",
fallbackIconRes = R.drawable.ic_bw_passkey,
),
isAutofill = true,
@ -1980,7 +1980,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
secondSubtitleTestTag = "PasskeySite",
subtitleTestTag = "PasskeyName",
iconData = IconData.Network(
uri = "https://vault.bitwarden.com/icons/www.mockuri.com/icon.png",
uri = "https://icons.bitwarden.net/www.mockuri.com/icon.png",
fallbackIconRes = R.drawable.ic_bw_passkey,
),
isCredentialCreation = true,

View File

@ -578,7 +578,7 @@ class VaultItemListingDataExtensionsTest {
secondSubtitleTestTag = "PasskeySite",
subtitleTestTag = "PasskeyName",
iconData = IconData.Network(
uri = "https://vault.bitwarden.com/icons/www.mockuri.com/icon.png",
uri = "https://icons.bitwarden.net/www.mockuri.com/icon.png",
fallbackIconRes = R.drawable.ic_bw_passkey,
),
isAutofill = true,
@ -665,7 +665,7 @@ class VaultItemListingDataExtensionsTest {
secondSubtitleTestTag = "PasskeySite",
subtitleTestTag = "PasskeyName",
iconData = IconData.Network(
uri = "https://vault.bitwarden.com/icons/www.mockuri.com/icon.png",
uri = "https://icons.bitwarden.net/www.mockuri.com/icon.png",
fallbackIconRes = R.drawable.ic_bw_passkey,
),
isAutofill = true,

View File

@ -30,7 +30,7 @@ fun createMockDisplayItemForCipher(
subtitle = subtitle,
subtitleTestTag = "CipherSubTitleLabel",
iconData = IconData.Network(
uri = "https://vault.bitwarden.com/icons/www.mockuri.com/icon.png",
uri = "https://icons.bitwarden.net/www.mockuri.com/icon.png",
fallbackIconRes = R.drawable.ic_globe,
),
extraIconList = persistentListOf(

View File

@ -562,7 +562,7 @@ class VaultDataExtensionsTest {
)
val expected = IconData.Network(
uri = "https://vault.bitwarden.com/icons/www.mockuri1.com/icon.png",
uri = "https://icons.bitwarden.net/www.mockuri1.com/icon.png",
fallbackIconRes = R.drawable.ic_globe,
)
@ -593,7 +593,7 @@ class VaultDataExtensionsTest {
)
val expected = IconData.Network(
uri = "https://vault.bitwarden.com/icons/www.mockuri1.com/icon.png",
uri = "https://icons.bitwarden.net/www.mockuri1.com/icon.png",
fallbackIconRes = R.drawable.ic_bw_passkey,
)
@ -767,7 +767,7 @@ class VaultDataExtensionsTest {
id = "mockId-1",
name = mockCipher.name.asText(),
startIcon = IconData.Network(
uri = "https://vault.bitwarden.com/icons/www.mockuri1.com/icon.png",
uri = "https://icons.bitwarden.net/www.mockuri1.com/icon.png",
fallbackIconRes = R.drawable.ic_globe,
),
startIconTestTag = "LoginCipherIcon",

View File

@ -1,5 +1,6 @@
package com.bitwarden.data.datasource.disk.model
import com.bitwarden.data.repository.model.EnvironmentRegion
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -41,6 +42,16 @@ data class EnvironmentUrlDataJson(
@SerialName("events")
val events: String? = null,
) {
/**
* Returns the [EnvironmentRegion] based on the base domain for the US or EU environments.
*/
val environmentRegion: EnvironmentRegion
get() = when (base) {
DEFAULT_US.base -> EnvironmentRegion.UNITED_STATES
DEFAULT_EU.base -> EnvironmentRegion.EUROPEAN_UNION
else -> EnvironmentRegion.SELF_HOSTED
}
@Suppress("UndocumentedPublicClass")
companion object {
/**

View File

@ -0,0 +1,10 @@
package com.bitwarden.data.repository.model
/**
* Enumeration of the environment regions used within the app.
*/
enum class EnvironmentRegion {
UNITED_STATES,
EUROPEAN_UNION,
SELF_HOSTED,
}

View File

@ -2,38 +2,62 @@ package com.bitwarden.data.repository.util
import com.bitwarden.data.datasource.disk.model.EnvironmentUrlDataJson
import com.bitwarden.data.repository.model.Environment
import com.bitwarden.data.repository.model.EnvironmentRegion
import java.net.URI
private const val DEFAULT_API_URL: String = "https://api.bitwarden.com"
private const val DEFAULT_EVENTS_URL: String = "https://events.bitwarden.com"
private const val DEFAULT_IDENTITY_URL: String = "https://identity.bitwarden.com"
private const val DEFAULT_WEB_VAULT_URL: String = "https://vault.bitwarden.com"
private const val DEFAULT_WEB_SEND_URL: String = "https://send.bitwarden.com/#"
private const val DEFAULT_ICON_URL: String = "https://icons.bitwarden.net"
private const val DEFAULT_US_API_URL: String = "https://api.bitwarden.com"
private const val DEFAULT_EU_API_URL: String = "https://api.bitwarden.eu"
private const val DEFAULT_US_EVENTS_URL: String = "https://events.bitwarden.com"
private const val DEFAULT_EU_EVENTS_URL: String = "https://events.bitwarden.eu"
private const val DEFAULT_US_IDENTITY_URL: String = "https://identity.bitwarden.com"
private const val DEFAULT_EU_IDENTITY_URL: String = "https://identity.bitwarden.eu"
private const val DEFAULT_US_WEB_VAULT_URL: String = "https://vault.bitwarden.com"
private const val DEFAULT_EU_WEB_VAULT_URL: String = "https://vault.bitwarden.eu"
private const val DEFAULT_US_WEB_SEND_URL: String = "https://send.bitwarden.com/#"
private const val DEFAULT_US_ICON_URL: String = "https://icons.bitwarden.net"
private const val DEFAULT_EU_ICON_URL: String = "https://icons.bitwarden.eu"
/**
* Returns the base api URL or the default value if one is not present.
*/
val EnvironmentUrlDataJson.baseApiUrl: String
get() = this.base.sanitizeUrl?.let { "$it/api" }
?: this.api.sanitizeUrl
?: DEFAULT_API_URL
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_API_URL
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_API_URL
EnvironmentRegion.SELF_HOSTED -> {
this.api.sanitizeUrl
?: this.base.sanitizeUrl?.let { "$it/api" }
?: DEFAULT_US_API_URL
}
}
/**
* Returns the base events URL or the default value if one is not present.
*/
val EnvironmentUrlDataJson.baseEventsUrl: String
get() = this.base.sanitizeUrl?.let { "$it/events" }
?: this.events.sanitizeUrl
?: DEFAULT_EVENTS_URL
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_EVENTS_URL
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_EVENTS_URL
EnvironmentRegion.SELF_HOSTED -> {
this.events.sanitizeUrl
?: this.base.sanitizeUrl?.let { "$it/events" }
?: DEFAULT_US_EVENTS_URL
}
}
/**
* Returns the base identity URL or the default value if one is not present.
*/
val EnvironmentUrlDataJson.baseIdentityUrl: String
get() = this.identity.sanitizeUrl
?: this.base.sanitizeUrl?.let { "$it/identity" }
?: DEFAULT_IDENTITY_URL
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_IDENTITY_URL
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_IDENTITY_URL
EnvironmentRegion.SELF_HOSTED -> {
this.identity.sanitizeUrl
?: this.base.sanitizeUrl?.let { "$it/identity" }
?: DEFAULT_US_IDENTITY_URL
}
}
/**
* Returns the base web vault URL. This will check for a custom [EnvironmentUrlDataJson.webVault]
@ -41,8 +65,11 @@ val EnvironmentUrlDataJson.baseIdentityUrl: String
* null or blank.
*/
val EnvironmentUrlDataJson.baseWebVaultUrlOrNull: String?
get() = this.webVault.sanitizeUrl
?: this.base.sanitizeUrl
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_WEB_VAULT_URL
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_WEB_VAULT_URL
EnvironmentRegion.SELF_HOSTED -> this.webVault.sanitizeUrl ?: this.base.sanitizeUrl
}
/**
* Returns the base web vault URL or the default value if one is not present.
@ -50,25 +77,18 @@ val EnvironmentUrlDataJson.baseWebVaultUrlOrNull: String?
* See [baseWebVaultUrlOrNull] for more details.
*/
val EnvironmentUrlDataJson.baseWebVaultUrlOrDefault: String
get() = this.baseWebVaultUrlOrNull ?: DEFAULT_WEB_VAULT_URL
get() = this.baseWebVaultUrlOrNull ?: DEFAULT_US_WEB_VAULT_URL
/**
* Returns the base web send URL or the default value if one is not present.
*/
val EnvironmentUrlDataJson.baseWebSendUrl: String
get() =
this
.baseWebVaultUrlOrNull
?.let {
// Only on US Cloud we should use the default web send URL
// On all other server instances we should use the base web send URL
if (it == DEFAULT_WEB_VAULT_URL) {
DEFAULT_WEB_SEND_URL
} else {
"$it/#/send/"
}
}
?: DEFAULT_WEB_SEND_URL
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_WEB_SEND_URL
EnvironmentRegion.EUROPEAN_UNION,
EnvironmentRegion.SELF_HOSTED,
-> this.baseWebVaultUrlOrNull?.let { "$it/#/send/" } ?: DEFAULT_US_WEB_SEND_URL
}
/**
* Returns the base web vault import URL or the default value if one is not present.
@ -83,9 +103,15 @@ val EnvironmentUrlDataJson.toBaseWebVaultImportUrl: String
* Returns a base icon url based on the environment or the default value if values are missing.
*/
val EnvironmentUrlDataJson.baseIconUrl: String
get() = this.icon.sanitizeUrl
?: this.base.sanitizeUrl?.let { "$it/icons" }
?: DEFAULT_ICON_URL
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_ICON_URL
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_ICON_URL
EnvironmentRegion.SELF_HOSTED -> {
this.icon.sanitizeUrl
?: this.base.sanitizeUrl?.let { "$it/icons" }
?: DEFAULT_US_ICON_URL
}
}
/**
* Returns the appropriate pre-defined labels for environments matching the known US/EU values.

View File

@ -8,18 +8,18 @@ import org.junit.jupiter.api.Test
class EnvironmentUrlsDataJsonExtensionsTest {
@Test
fun `baseApiUrl should return base if it is present`() {
fun `baseApiUrl should return api if it is present`() {
assertEquals(
"base/api",
"api",
DEFAULT_CUSTOM_ENVIRONMENT_URL_DATA.baseApiUrl,
)
}
@Test
fun `baseApiUrl should return api value if base is empty`() {
fun `baseApiUrl should return base value if api is empty`() {
assertEquals(
"api",
DEFAULT_CUSTOM_ENVIRONMENT_URL_DATA.copy(base = "").baseApiUrl,
"base/api",
DEFAULT_CUSTOM_ENVIRONMENT_URL_DATA.copy(api = "").baseApiUrl,
)
}
@ -32,18 +32,18 @@ class EnvironmentUrlsDataJsonExtensionsTest {
}
@Test
fun `baseEventsUrl should return base if it is present`() {
fun `baseEventsUrl should return events if it is present`() {
assertEquals(
"base/events",
"events",
DEFAULT_CUSTOM_ENVIRONMENT_URL_DATA.baseEventsUrl,
)
}
@Test
fun `baseEventsUrl should return events value if base is empty`() {
fun `baseEventsUrl should return base value if events is empty`() {
assertEquals(
"events",
DEFAULT_CUSTOM_ENVIRONMENT_URL_DATA.copy(base = "").baseEventsUrl,
"base/events",
DEFAULT_CUSTOM_ENVIRONMENT_URL_DATA.copy(events = "").baseEventsUrl,
)
}
@ -165,14 +165,14 @@ class EnvironmentUrlsDataJsonExtensionsTest {
}
@Test
fun `baseWebSendUrl should return the default when webvault matches default webvault`() {
fun `baseWebSendUrl should return the modified webvault when not in the US`() {
val result = DEFAULT_CUSTOM_ENVIRONMENT_URL_DATA
.copy(
webVault = "https://vault.bitwarden.com",
base = "",
)
.baseWebSendUrl
assertEquals("https://send.bitwarden.com/#", result)
assertEquals("https://vault.bitwarden.com/#/send/", result)
}
@Test