mirror of
https://github.com/bitwarden/android.git
synced 2026-08-02 02:32:04 -05:00
PM-35112: feat: Add underlying FedRAMP environment (#7138)
This commit is contained in:
+3
@@ -33,6 +33,9 @@ class RestrictionManagerImpl(
|
||||
// If the baseEnvironmentUrl matches the predefined EU environment, assume it is the
|
||||
// default EU environment.
|
||||
Environment.Eu.environmentUrlData.base -> Environment.Eu
|
||||
// If the baseEnvironmentUrl matches the predefined FedRAMP environment, assume it is
|
||||
// the default FedRAMP environment.
|
||||
Environment.FedRamp.environmentUrlData.base -> Environment.FedRamp
|
||||
// Otherwise make a custom self-host environment.
|
||||
else -> Environment.SelfHosted(EnvironmentUrlDataJson(baseEnvironmentUrl))
|
||||
}
|
||||
|
||||
+7
@@ -43,6 +43,13 @@ private fun EnvironmentUrlDataJson.authTabData(
|
||||
)
|
||||
}
|
||||
|
||||
EnvironmentRegion.FED_RAMP -> {
|
||||
AuthTabData.HttpsScheme(
|
||||
host = "bitwarden-gov.com",
|
||||
path = "$kind-callback",
|
||||
)
|
||||
}
|
||||
|
||||
EnvironmentRegion.SELF_HOSTED -> {
|
||||
AuthTabData.CustomScheme(
|
||||
callbackUrl = "bitwarden://$kind-callback",
|
||||
|
||||
+1
@@ -50,6 +50,7 @@ class EnvironmentViewModel @Inject constructor(
|
||||
val environmentUrlData = when (val environment = environmentRepository.environment) {
|
||||
Environment.Us,
|
||||
Environment.Eu,
|
||||
Environment.FedRamp,
|
||||
-> EnvironmentUrlDataJson(base = "")
|
||||
|
||||
is Environment.SelfHosted -> environment.environmentUrlData
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.x8bit.bitwarden.ui.auth.feature.landing
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -274,28 +275,35 @@ private fun LandingScreenContent(
|
||||
|
||||
Spacer(modifier = Modifier.height(height = 24.dp))
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.standardHorizontalMargin()
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
AnimatedVisibility(
|
||||
visible = state.allowCreateAccount,
|
||||
label = "CreateAccountAnimatedVisibility",
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = BitwardenString.new_to_bitwarden),
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
)
|
||||
Column {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.standardHorizontalMargin()
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = BitwardenString.new_to_bitwarden),
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
)
|
||||
|
||||
BitwardenTextButton(
|
||||
label = stringResource(id = BitwardenString.create_an_account),
|
||||
onClick = onCreateAccountClick,
|
||||
modifier = Modifier
|
||||
.testTag("CreateAccountLabel"),
|
||||
)
|
||||
BitwardenTextButton(
|
||||
label = stringResource(id = BitwardenString.create_an_account),
|
||||
onClick = onCreateAccountClick,
|
||||
modifier = Modifier
|
||||
.testTag("CreateAccountLabel"),
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(height = 8.dp))
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(height = 8.dp))
|
||||
BitwardenTextButton(
|
||||
label = stringResource(id = BitwardenString.app_settings),
|
||||
onClick = onAppSettingsClick,
|
||||
|
||||
+35
-2
@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.auth.feature.landing
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.core.data.manager.model.FlagKey
|
||||
import com.bitwarden.data.repository.model.Environment
|
||||
import com.bitwarden.ui.platform.base.BackgroundEvent
|
||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||
@@ -16,6 +17,7 @@ import com.bitwarden.ui.util.asText
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.LogoutReason
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.ui.platform.model.SnackbarRelay
|
||||
@@ -43,6 +45,7 @@ class LandingViewModel @Inject constructor(
|
||||
private val environmentRepository: EnvironmentRepository,
|
||||
snackbarRelayManager: SnackbarRelayManager<SnackbarRelay>,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
featureFlagManager: FeatureFlagManager,
|
||||
) : BaseViewModel<LandingState, LandingEvent, LandingAction>(
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
?: LandingState(
|
||||
@@ -53,12 +56,13 @@ class LandingViewModel @Inject constructor(
|
||||
selectedEnvironmentLabel = environmentRepository.environment.label,
|
||||
dialog = null,
|
||||
accountSummaries = authRepository.userStateFlow.value?.toAccountSummaries().orEmpty(),
|
||||
isFedRampEnabled = featureFlagManager.getFeatureFlag(FlagKey.FedRamp),
|
||||
),
|
||||
) {
|
||||
|
||||
/**
|
||||
* Returns the [AccountSummary] from the current state that matches the current email input and
|
||||
* the the current environment, or `null` if there is no match.
|
||||
* the current environment, or `null` if there is no match.
|
||||
*/
|
||||
private val matchingAccountSummary: AccountSummary?
|
||||
get() {
|
||||
@@ -106,6 +110,12 @@ class LandingViewModel @Inject constructor(
|
||||
.map { LandingAction.Internal.SnackbarDataReceived(it) }
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
featureFlagManager
|
||||
.getFeatureFlagFlow(FlagKey.FedRamp)
|
||||
.map { LandingAction.Internal.FedRampFeatureUpdated(it) }
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun handleAction(action: LandingAction) {
|
||||
@@ -136,6 +146,7 @@ class LandingViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
is LandingAction.Internal.SnackbarDataReceived -> handleSnackbarDataReceived(action)
|
||||
is LandingAction.Internal.FedRampFeatureUpdated -> handleFedRampFeatureUpdated(action)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,6 +242,7 @@ class LandingViewModel @Inject constructor(
|
||||
val environment = when (action.environmentType) {
|
||||
Environment.Type.US -> Environment.Us
|
||||
Environment.Type.EU -> Environment.Eu
|
||||
Environment.Type.FED_RAMP -> Environment.FedRamp
|
||||
Environment.Type.SELF_HOSTED -> {
|
||||
// Launch the self-hosted screen and select the full environment details there.
|
||||
sendEvent(LandingEvent.NavigateToEnvironment)
|
||||
@@ -258,6 +270,10 @@ class LandingViewModel @Inject constructor(
|
||||
sendEvent(LandingEvent.ShowSnackbar(action.data))
|
||||
}
|
||||
|
||||
private fun handleFedRampFeatureUpdated(action: LandingAction.Internal.FedRampFeatureUpdated) {
|
||||
mutableStateFlow.update { it.copy(isFedRampEnabled = action.isEnabled) }
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user state account is changed to an active but not "logged in" account we can
|
||||
* pre-populate the email field with this account.
|
||||
@@ -284,12 +300,22 @@ data class LandingState(
|
||||
val selectedEnvironmentLabel: String,
|
||||
val dialog: DialogState?,
|
||||
val accountSummaries: List<AccountSummary>,
|
||||
val isFedRampEnabled: Boolean,
|
||||
) : Parcelable {
|
||||
/**
|
||||
* The selectable environments.
|
||||
*/
|
||||
val environmentTypeOptions: ImmutableList<Environment.Type>
|
||||
get() = Environment.Type.entries.toImmutableList()
|
||||
get() = Environment.Type
|
||||
.entries
|
||||
.filterNot { it == Environment.Type.FED_RAMP && !isFedRampEnabled }
|
||||
.toImmutableList()
|
||||
|
||||
/**
|
||||
* Determines if the user should be allowed to create a new account.
|
||||
*/
|
||||
val allowCreateAccount: Boolean
|
||||
get() = selectedEnvironmentType != Environment.Type.FED_RAMP
|
||||
|
||||
/**
|
||||
* Determines whether the app bar should be visible based on the presence of account summaries.
|
||||
@@ -453,5 +479,12 @@ sealed class LandingAction {
|
||||
* Internal action to update the email input state from a non-user action
|
||||
*/
|
||||
data class UpdateEmailState(val emailInput: String) : Internal()
|
||||
|
||||
/**
|
||||
* Indicates that FedRamp feature has been enabled or disabled.
|
||||
*/
|
||||
data class FedRampFeatureUpdated(
|
||||
val isEnabled: Boolean,
|
||||
) : Internal()
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -125,6 +125,11 @@ class StartRegistrationViewModel @Inject constructor(
|
||||
sendEvent(StartRegistrationEvent.NavigateToEnvironment)
|
||||
return
|
||||
}
|
||||
|
||||
Environment.Type.FED_RAMP -> {
|
||||
// New account creation is not supported with FedRAMP.
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Update the environment in the repo; the VM state will update accordingly because it is
|
||||
@@ -296,7 +301,10 @@ data class StartRegistrationState(
|
||||
* The selectable environments.
|
||||
*/
|
||||
val environmentTypeOptions: ImmutableList<Environment.Type>
|
||||
get() = Environment.Type.entries.toImmutableList()
|
||||
get() = Environment.Type
|
||||
.entries
|
||||
.filterNot { it == Environment.Type.FED_RAMP }
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,4 +13,5 @@ val Environment.Type.displayLabel: Text
|
||||
Environment.Type.US -> Environment.Us.label.asText()
|
||||
Environment.Type.EU -> Environment.Eu.label.asText()
|
||||
Environment.Type.SELF_HOSTED -> BitwardenString.self_hosted.asText()
|
||||
Environment.Type.FED_RAMP -> Environment.FedRamp.label.asText()
|
||||
}
|
||||
|
||||
+15
@@ -133,6 +133,21 @@ class RestrictionManagerTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `initialize with baseEnvironmentUrl bundle data matching the current FedRAMP environment should set the environment to FedRAMP`() {
|
||||
every {
|
||||
restrictionsManager.applicationRestrictions
|
||||
} returns mockBundle("baseEnvironmentUrl" to "https://vault.bitwarden-gov.com")
|
||||
|
||||
restrictionManager.initialize()
|
||||
|
||||
verify(exactly = 1) {
|
||||
restrictionsManager.applicationRestrictions
|
||||
}
|
||||
assertEquals(Environment.FedRamp, fakeEnvironmentRepository.environment)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `initialize with baseEnvironmentUrl bundle data matching the current self-hosted environment should set the environment to self-hosted`() {
|
||||
|
||||
+21
@@ -23,6 +23,13 @@ class EnvironmentUrlDataJsonExtensionsTest {
|
||||
),
|
||||
EnvironmentUrlDataJson.DEFAULT_EU.duoAuthTabData,
|
||||
)
|
||||
assertEquals(
|
||||
AuthTabData.HttpsScheme(
|
||||
host = "bitwarden-gov.com",
|
||||
path = "duo-callback",
|
||||
),
|
||||
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.duoAuthTabData,
|
||||
)
|
||||
assertEquals(
|
||||
AuthTabData.HttpsScheme(
|
||||
host = "bitwarden.pw",
|
||||
@@ -55,6 +62,13 @@ class EnvironmentUrlDataJsonExtensionsTest {
|
||||
),
|
||||
EnvironmentUrlDataJson.DEFAULT_EU.webAuthnAuthTabData,
|
||||
)
|
||||
assertEquals(
|
||||
AuthTabData.HttpsScheme(
|
||||
host = "bitwarden-gov.com",
|
||||
path = "webauthn-callback",
|
||||
),
|
||||
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.webAuthnAuthTabData,
|
||||
)
|
||||
assertEquals(
|
||||
AuthTabData.HttpsScheme(
|
||||
host = "bitwarden.pw",
|
||||
@@ -87,6 +101,13 @@ class EnvironmentUrlDataJsonExtensionsTest {
|
||||
),
|
||||
EnvironmentUrlDataJson.DEFAULT_EU.ssoAuthTabData,
|
||||
)
|
||||
assertEquals(
|
||||
AuthTabData.HttpsScheme(
|
||||
host = "bitwarden-gov.com",
|
||||
path = "sso-callback",
|
||||
),
|
||||
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.ssoAuthTabData,
|
||||
)
|
||||
assertEquals(
|
||||
AuthTabData.HttpsScheme(
|
||||
host = "bitwarden.pw",
|
||||
|
||||
@@ -342,6 +342,23 @@ class LandingScreenTest : BitwardenComposeTest() {
|
||||
assertTrue(onNavigateToPreAuthSettingsCalled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `allowCreateAccount state should show and hide CreateAccount UI`() {
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Create an account")
|
||||
.performScrollTo()
|
||||
.assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { it.copy(selectedEnvironmentType = Environment.Type.FED_RAMP) }
|
||||
composeTestRule.onNodeWithText(text = "Create an account").assertDoesNotExist()
|
||||
|
||||
mutableStateFlow.update { it.copy(selectedEnvironmentType = Environment.Type.EU) }
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Create an account")
|
||||
.performScrollTo()
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `selecting environment should send EnvironmentOptionSelect action`() {
|
||||
val selectedEnvironment = Environment.Eu
|
||||
@@ -506,4 +523,5 @@ private val DEFAULT_STATE = LandingState(
|
||||
selectedEnvironmentLabel = Environment.Us.label,
|
||||
dialog = null,
|
||||
accountSummaries = emptyList(),
|
||||
isFedRampEnabled = true,
|
||||
)
|
||||
|
||||
+24
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.auth.feature.landing
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.bitwarden.core.data.manager.model.FlagKey
|
||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||
import com.bitwarden.data.repository.model.Environment
|
||||
import com.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
@@ -15,6 +16,7 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.LogoutReason
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
@@ -47,6 +49,13 @@ class LandingViewModelTest : BaseViewModelTest() {
|
||||
getSnackbarDataFlow(SnackbarRelay.ENVIRONMENT_SAVED)
|
||||
} returns mutableSnackbarSharedFlow
|
||||
}
|
||||
private val mutableFedRampFlagStateFlow = MutableStateFlow(true)
|
||||
private val featureFlagManager: FeatureFlagManager = mockk {
|
||||
every { getFeatureFlagFlow(key = FlagKey.FedRamp) } returns mutableFedRampFlagStateFlow
|
||||
every {
|
||||
getFeatureFlag(key = FlagKey.FedRamp)
|
||||
} answers { mutableFedRampFlagStateFlow.value }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `initial state should be correct when there is no remembered email`() = runTest {
|
||||
@@ -124,6 +133,19 @@ class LandingViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `FedRAMP flag changes should update state`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(DEFAULT_STATE, awaitItem())
|
||||
mutableFedRampFlagStateFlow.value = false
|
||||
assertEquals(DEFAULT_STATE.copy(isFedRampEnabled = false), awaitItem())
|
||||
mutableFedRampFlagStateFlow.value = true
|
||||
assertEquals(DEFAULT_STATE.copy(isFedRampEnabled = true), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `LockAccountClick should call lockVault for the given account`() {
|
||||
val accountUserId = "userId"
|
||||
@@ -623,6 +645,7 @@ class LandingViewModelTest : BaseViewModelTest() {
|
||||
vaultRepository = vaultRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
snackbarRelayManager = snackbarRelayManager,
|
||||
featureFlagManager = featureFlagManager,
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
|
||||
@@ -637,4 +660,5 @@ private val DEFAULT_STATE = LandingState(
|
||||
selectedEnvironmentLabel = Environment.Us.label,
|
||||
dialog = null,
|
||||
accountSummaries = emptyList(),
|
||||
isFedRampEnabled = true,
|
||||
)
|
||||
|
||||
+27
-15
@@ -251,22 +251,34 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `EnvironmentTypeSelect should update value of selected region for US or EU`() = runTest {
|
||||
val inputEnvironmentType = Environment.Type.EU
|
||||
val viewModel = createViewModel()
|
||||
viewModel.stateFlow.test {
|
||||
awaitItem()
|
||||
viewModel.trySendAction(
|
||||
EnvironmentTypeSelect(
|
||||
inputEnvironmentType,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(selectedEnvironmentType = Environment.Type.EU),
|
||||
awaitItem(),
|
||||
)
|
||||
fun `EnvironmentTypeSelect should update value of selected region for UE, US, and FedRAMP`() =
|
||||
runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.stateFlow.test {
|
||||
skipItems(count = 1)
|
||||
|
||||
viewModel.trySendAction(
|
||||
EnvironmentTypeSelect(environmentType = Environment.Type.EU),
|
||||
)
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(selectedEnvironmentType = Environment.Type.EU),
|
||||
awaitItem(),
|
||||
)
|
||||
|
||||
viewModel.trySendAction(
|
||||
EnvironmentTypeSelect(environmentType = Environment.Type.US),
|
||||
)
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(selectedEnvironmentType = Environment.Type.US),
|
||||
awaitItem(),
|
||||
)
|
||||
|
||||
viewModel.trySendAction(
|
||||
EnvironmentTypeSelect(environmentType = Environment.Type.FED_RAMP),
|
||||
)
|
||||
expectNoEvents()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `EnvironmentTypeSelect should emit NavigateToEnvironment for self-hosted`() = runTest {
|
||||
|
||||
@@ -23,6 +23,14 @@ class EnvironmentExtensionsTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `displayLabel for FED_RAMP type should return the correct value`() {
|
||||
assertEquals(
|
||||
"bitwarden-gov.com".asText(),
|
||||
Environment.Type.FED_RAMP.displayLabel,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `displayLabel for SELF_HOSTED type should return the correct value`() {
|
||||
assertEquals(
|
||||
|
||||
+7
@@ -49,6 +49,7 @@ data class EnvironmentUrlDataJson(
|
||||
get() = when (base) {
|
||||
DEFAULT_US.base -> EnvironmentRegion.UNITED_STATES
|
||||
DEFAULT_EU.base -> EnvironmentRegion.EUROPEAN_UNION
|
||||
DEFAULT_FED_RAMP.base -> EnvironmentRegion.FED_RAMP
|
||||
else -> {
|
||||
if (base.contains(BITWARDEN_INTERNAL_DOMAIN)) {
|
||||
EnvironmentRegion.INTERNAL
|
||||
@@ -106,5 +107,11 @@ data class EnvironmentUrlDataJson(
|
||||
webVault = "https://vault.bitwarden.eu",
|
||||
events = "https://events.bitwarden.eu",
|
||||
)
|
||||
|
||||
/**
|
||||
* Default [EnvironmentUrlDataJson] for the FedRAMP environment.
|
||||
*/
|
||||
val DEFAULT_FED_RAMP: EnvironmentUrlDataJson =
|
||||
EnvironmentUrlDataJson(base = "https://vault.bitwarden-gov.com")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,17 @@ sealed class Environment {
|
||||
get() = "bitwarden.eu"
|
||||
}
|
||||
|
||||
/**
|
||||
* The default FedRAMP environment.
|
||||
*/
|
||||
data object FedRamp : Environment() {
|
||||
override val type: Type get() = Type.FED_RAMP
|
||||
override val environmentUrlData: EnvironmentUrlDataJson
|
||||
get() = EnvironmentUrlDataJson.DEFAULT_FED_RAMP
|
||||
override val label: String
|
||||
get() = "bitwarden-gov.com"
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom self-hosted environment with a fully configurable [environmentUrlData].
|
||||
*/
|
||||
@@ -63,6 +74,7 @@ sealed class Environment {
|
||||
enum class Type {
|
||||
US,
|
||||
EU,
|
||||
FED_RAMP,
|
||||
SELF_HOSTED,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package com.bitwarden.data.repository.model
|
||||
enum class EnvironmentRegion {
|
||||
UNITED_STATES,
|
||||
EUROPEAN_UNION,
|
||||
FED_RAMP,
|
||||
INTERNAL,
|
||||
SELF_HOSTED,
|
||||
}
|
||||
|
||||
+16
-1
@@ -7,15 +7,21 @@ import java.net.URI
|
||||
|
||||
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_FED_RAMP_API_URL: String = "https://api.bitwarden-gov.com"
|
||||
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_FED_RAMP_EVENTS_URL: String = "https://events.bitwarden-gov.com"
|
||||
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_FED_RAMP_IDENTITY_URL: String = "https://identity.bitwarden-gov.com"
|
||||
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_FED_RAMP_WEB_VAULT_URL: String = "https://vault.bitwarden-gov.com"
|
||||
private const val DEFAULT_US_WEB_SEND_URL: String = "https://send.bitwarden.com/#"
|
||||
private const val DEFAULT_FED_RAMP_WEB_SEND_URL: String = "https://send.bitwarden-gov.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"
|
||||
private const val DEFAULT_FED_RAMP_ICON_URL: String = "https://icons.bitwarden-gov.com"
|
||||
|
||||
/**
|
||||
* Returns the base api URL or the default value if one is not present.
|
||||
@@ -24,6 +30,7 @@ val EnvironmentUrlDataJson.baseApiUrl: String
|
||||
get() = when (this.environmentRegion) {
|
||||
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_API_URL
|
||||
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_API_URL
|
||||
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_API_URL
|
||||
EnvironmentRegion.INTERNAL,
|
||||
EnvironmentRegion.SELF_HOSTED,
|
||||
-> {
|
||||
@@ -40,6 +47,7 @@ val EnvironmentUrlDataJson.appLinksScheme: String
|
||||
get() = when (this.environmentRegion) {
|
||||
EnvironmentRegion.UNITED_STATES,
|
||||
EnvironmentRegion.EUROPEAN_UNION,
|
||||
EnvironmentRegion.FED_RAMP,
|
||||
EnvironmentRegion.INTERNAL,
|
||||
-> "https"
|
||||
|
||||
@@ -53,6 +61,7 @@ val EnvironmentUrlDataJson.baseEventsUrl: String
|
||||
get() = when (this.environmentRegion) {
|
||||
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_EVENTS_URL
|
||||
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_EVENTS_URL
|
||||
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_EVENTS_URL
|
||||
EnvironmentRegion.INTERNAL,
|
||||
EnvironmentRegion.SELF_HOSTED,
|
||||
-> {
|
||||
@@ -69,6 +78,7 @@ val EnvironmentUrlDataJson.baseIdentityUrl: String
|
||||
get() = when (this.environmentRegion) {
|
||||
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_IDENTITY_URL
|
||||
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_IDENTITY_URL
|
||||
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_IDENTITY_URL
|
||||
EnvironmentRegion.INTERNAL,
|
||||
EnvironmentRegion.SELF_HOSTED,
|
||||
-> {
|
||||
@@ -87,6 +97,7 @@ val EnvironmentUrlDataJson.baseWebVaultUrlOrNull: String?
|
||||
get() = when (this.environmentRegion) {
|
||||
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_WEB_VAULT_URL
|
||||
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_WEB_VAULT_URL
|
||||
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_WEB_VAULT_URL
|
||||
EnvironmentRegion.INTERNAL,
|
||||
EnvironmentRegion.SELF_HOSTED,
|
||||
-> this.webVault.sanitizeUrl ?: this.base.sanitizeUrl
|
||||
@@ -106,6 +117,7 @@ val EnvironmentUrlDataJson.baseWebVaultUrlOrDefault: String
|
||||
val EnvironmentUrlDataJson.baseWebSendUrl: String
|
||||
get() = when (this.environmentRegion) {
|
||||
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_WEB_SEND_URL
|
||||
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_WEB_SEND_URL
|
||||
EnvironmentRegion.EUROPEAN_UNION,
|
||||
EnvironmentRegion.INTERNAL,
|
||||
EnvironmentRegion.SELF_HOSTED,
|
||||
@@ -128,6 +140,7 @@ val EnvironmentUrlDataJson.baseIconUrl: String
|
||||
get() = when (this.environmentRegion) {
|
||||
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_ICON_URL
|
||||
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_ICON_URL
|
||||
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_ICON_URL
|
||||
EnvironmentRegion.INTERNAL,
|
||||
EnvironmentRegion.SELF_HOSTED,
|
||||
-> {
|
||||
@@ -139,7 +152,7 @@ val EnvironmentUrlDataJson.baseIconUrl: String
|
||||
|
||||
/**
|
||||
* Returns the appropriate pre-defined labels for environments matching the known US/EU values.
|
||||
* Otherwise returns the host of the custom base URL.
|
||||
* Otherwise, returns the host of the custom base URL.
|
||||
*
|
||||
* @see getSelfHostedUrlOrNull
|
||||
*/
|
||||
@@ -147,6 +160,7 @@ val EnvironmentUrlDataJson.labelOrBaseUrlHost: String
|
||||
get() = when (this) {
|
||||
EnvironmentUrlDataJson.DEFAULT_US -> Environment.Us.label
|
||||
EnvironmentUrlDataJson.DEFAULT_EU -> Environment.Eu.label
|
||||
EnvironmentUrlDataJson.DEFAULT_FED_RAMP -> Environment.FedRamp.label
|
||||
else -> {
|
||||
// Grab the domain
|
||||
// Ex:
|
||||
@@ -189,6 +203,7 @@ fun EnvironmentUrlDataJson.toEnvironmentUrls(): Environment =
|
||||
EnvironmentUrlDataJson.DEFAULT_LEGACY_EU,
|
||||
-> Environment.Eu
|
||||
|
||||
EnvironmentUrlDataJson.DEFAULT_FED_RAMP -> Environment.FedRamp
|
||||
else -> Environment.SelfHosted(environmentUrlData = this)
|
||||
}
|
||||
|
||||
|
||||
+35
@@ -193,6 +193,15 @@ class EnvironmentUrlsDataJsonExtensionsTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `labelOrBaseUrlHost should correctly convert FedRAMP environment to the correct label`() {
|
||||
val environment = EnvironmentUrlDataJson.DEFAULT_FED_RAMP
|
||||
assertEquals(
|
||||
Environment.FedRamp.label,
|
||||
environment.labelOrBaseUrlHost,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `labelOrBaseUrlHost should correctly convert self hosted environment to the correct label`() {
|
||||
@@ -219,6 +228,14 @@ class EnvironmentUrlsDataJsonExtensionsTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toEnvironmentUrls should correctly convert FedRAMP urls to the expected type`() {
|
||||
assertEquals(
|
||||
Environment.FedRamp,
|
||||
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.toEnvironmentUrls(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toEnvironmentUrls should correctly convert custom urls to the expected type`() {
|
||||
assertEquals(
|
||||
@@ -254,6 +271,14 @@ class EnvironmentUrlsDataJsonExtensionsTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toEnvironmentUrlsOrDefault should correctly convert FedRAMP urls to the expected type`() {
|
||||
assertEquals(
|
||||
Environment.FedRamp,
|
||||
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.toEnvironmentUrlsOrDefault(),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `toEnvironmentUrlsOrDefault should correctly convert legacy EU urls to the expected type`() {
|
||||
@@ -357,6 +382,16 @@ class EnvironmentUrlsDataJsonExtensionsTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `appLinksScheme should return the correct scheme for FedRAMP environment`() {
|
||||
val expectedScheme = "https"
|
||||
|
||||
assertEquals(
|
||||
expectedScheme,
|
||||
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.appLinksScheme,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `appLinksScheme should return the correct scheme for internal environment`() {
|
||||
val expectedScheme = "https"
|
||||
|
||||
Reference in New Issue
Block a user