[PM-3553] Support SimpleLogin self hosted servers (#4723)

This commit is contained in:
Patrick Honkonen authored and GitHub committed 2025-02-19 10:20:28 -05:00
1 parent 0ba67f5887
commit 65cc0a0dd8
13 files changed
+344 -6

No files matched your search

@@ -52,6 +52,9 @@ data class UsernameGenerationOptions(
@SerialName("simpleLoginApiKey")
val simpleLoginApiKey: String? = null,
@SerialName("simpleLoginSelfHostServerUrl")
val simpleLoginSelfHostServerUrl: String? = null,
@SerialName("duckDuckGoApiKey")
val duckDuckGoApiKey: String? = null,
@@ -530,6 +530,8 @@ private fun CoachMarkScope<ExploreGeneratorCoachMark>.ScrollContent(
randomWordHandlers = randomWordHandlers,
shouldShowSelfHostServerUrlField =
state.shouldShowAnonAddySelfHostServerUrlField,
shouldShowSimpleLoginSelfHostServerUrlField =
state.shouldShowSimpleLoginSelfHostServerField,
)
}
}
@@ -1104,6 +1106,7 @@ private fun UsernameTypeItems(
catchAllEmailHandlers: CatchAllEmailHandlers,
randomWordHandlers: RandomWordHandlers,
shouldShowSelfHostServerUrlField: Boolean,
shouldShowSimpleLoginSelfHostServerUrlField: Boolean,
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
@@ -1129,6 +1132,8 @@ private fun UsernameTypeItems(
usernameTypeState = selectedType,
forwardedEmailAliasHandlers = forwardedEmailAliasHandlers,
shouldShowSelfHostServerUrlField = shouldShowSelfHostServerUrlField,
shouldShowSimpleLoginSelfHostServerUrlField =
shouldShowSimpleLoginSelfHostServerUrlField,
)
}
@@ -1190,6 +1195,7 @@ private fun ForwardedEmailAliasTypeContent(
usernameTypeState: GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias,
forwardedEmailAliasHandlers: ForwardedEmailAliasHandlers,
shouldShowSelfHostServerUrlField: Boolean,
shouldShowSimpleLoginSelfHostServerUrlField: Boolean,
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
@@ -1329,6 +1335,22 @@ private fun ForwardedEmailAliasTypeContent(
.standardHorizontalMargin()
.fillMaxWidth(),
)
if (shouldShowSimpleLoginSelfHostServerUrlField) {
Spacer(modifier = Modifier.height(8.dp))
BitwardenTextField(
label = stringResource(id = R.string.self_host_server_url),
value = usernameTypeState.selectedServiceType.selfHostServerUrl,
onValueChange =
forwardedEmailAliasHandlers.onSimpleLoginSelfHostServerUrlChange,
textFieldTestTag = "SimpleLoginSelfHostServerUrlEntry",
cardStyle = CardStyle.Full,
modifier = Modifier
.standardHorizontalMargin()
.fillMaxWidth(),
)
}
}
null -> {
@@ -115,6 +115,8 @@ class GeneratorViewModel @Inject constructor(
shouldShowAnonAddySelfHostServerUrlField = featureFlagManager.getFeatureFlag(
FlagKey.AnonAddySelfHostAlias,
),
shouldShowSimpleLoginSelfHostServerField =
featureFlagManager.getFeatureFlag(FlagKey.SimpleLoginSelfHostAlias),
)
},
) {
@@ -152,6 +154,15 @@ class GeneratorViewModel @Inject constructor(
}
.onEach(::sendAction)
.launchIn(viewModelScope)
featureFlagManager.getFeatureFlagFlow(FlagKey.SimpleLoginSelfHostAlias)
.map { shouldShowSimpleLoginSelfHostServerField ->
GeneratorAction.Internal.ShouldShowSimpleLoginSelfHostValueChangeReceive(
shouldShowSelfHostServerField = shouldShowSimpleLoginSelfHostServerField,
)
}
.onEach(::sendAction)
.launchIn(viewModelScope)
}
override fun handleAction(action: GeneratorAction) {
@@ -249,6 +260,10 @@ class GeneratorViewModel @Inject constructor(
is GeneratorAction.MainType.Username.UsernameType.RandomWord -> {
handleRandomWordSpecificAction(action)
}
is GeneratorAction.MainType.Username.UsernameType.ForwardedEmailAlias.SimpleLogin.SelfHostServerUrlChange -> {
handleSimpleLoginSelfHostServerUrlChange(action)
}
}
}
@@ -289,6 +304,10 @@ class GeneratorViewModel @Inject constructor(
is GeneratorAction.Internal.ShouldShowAnonAddySelfHostValueChangeReceive -> {
handleShouldShowAnonAddySelfHostValueChange(action)
}
is GeneratorAction.Internal.ShouldShowSimpleLoginSelfHostValueChangeReceive -> {
handleShouldShowSimpleLoginSelfHostValueChange(action)
}
}
}
@@ -594,6 +613,8 @@ class GeneratorViewModel @Inject constructor(
type = UsernameGenerationOptions.UsernameType.FORWARDED_EMAIL_ALIAS,
serviceType = UsernameGenerationOptions.ForwardedEmailServiceType.SIMPLE_LOGIN,
simpleLoginApiKey = forwardedEmailAlias.selectedServiceType.apiKey,
simpleLoginSelfHostServerUrl =
forwardedEmailAlias.selectedServiceType.selfHostServerUrl,
)
is ForwardEmail -> options.copy(
@@ -643,6 +664,7 @@ class GeneratorViewModel @Inject constructor(
catchAllEmailDomain = "",
firefoxRelayApiAccessToken = "",
simpleLoginApiKey = "",
simpleLoginSelfHostServerUrl = "",
duckDuckGoApiKey = "",
fastMailApiKey = "",
anonAddyApiAccessToken = "",
@@ -813,6 +835,14 @@ class GeneratorViewModel @Inject constructor(
}
}
private fun handleShouldShowSimpleLoginSelfHostValueChange(
action: GeneratorAction.Internal.ShouldShowSimpleLoginSelfHostValueChangeReceive,
) {
mutableStateFlow.update {
it.copy(shouldShowSimpleLoginSelfHostServerField = action.shouldShowSelfHostServerField)
}
}
private fun handlePasswordGeneratorPolicyReceive(
action: GeneratorAction.Internal.PasswordGeneratorPolicyReceive,
) {
@@ -1392,6 +1422,21 @@ class GeneratorViewModel @Inject constructor(
}
}
private fun handleSimpleLoginSelfHostServerUrlChange(
action: GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.SimpleLogin
.SelfHostServerUrlChange,
) {
updateSimpleLoginServiceType { simpleLoginServiceType ->
val newServerUrl = action.url
simpleLoginServiceType.copy(selfHostServerUrl = newServerUrl)
}
}
//endregion SimpleLogin Service Specific Handlers
//region Plus Addressed Email Specific Handlers
@@ -1538,6 +1583,7 @@ class GeneratorViewModel @Inject constructor(
?.toUsernameGeneratorRequest(
website = state.website,
allowAddyIoSelfHostUrl = state.shouldShowAnonAddySelfHostServerUrlField,
allowSimpleLoginSelfHostUrl = state.shouldShowSimpleLoginSelfHostServerField,
)
?: run {
mutableStateFlow.update { it.copy(generatedText = NO_GENERATED_TEXT) }
@@ -1840,6 +1886,7 @@ data class GeneratorState(
var passcodePolicyOverride: PasscodePolicyOverride? = null,
private val shouldShowCoachMarkTour: Boolean,
val shouldShowAnonAddySelfHostServerUrlField: Boolean,
val shouldShowSimpleLoginSelfHostServerField: Boolean,
) : Parcelable {
/**
@@ -2243,9 +2290,15 @@ data class GeneratorState(
@Parcelize
data class SimpleLogin(
val apiKey: String = "",
val selfHostServerUrl: String = "",
) : ServiceType(), Parcelable {
override val displayStringResId: Int
get() = ServiceTypeOption.SIMPLE_LOGIN.labelRes
@Suppress("UndocumentedPublicClass")
companion object {
const val DEFAULT_SIMPLE_LOGIN_URL = "https://app.simplelogin.io"
}
}
}
}
@@ -2586,6 +2639,13 @@ sealed class GeneratorAction {
* @property apiKey The new api key text.
*/
data class ApiKeyTextChange(val apiKey: String) : SimpleLogin()
/**
* Fired when the self host server url input text is changed.
*
* @property url The new self host server url text.
*/
data class SelfHostServerUrlChange(val url: String) : SimpleLogin()
}
}
@@ -2704,6 +2764,13 @@ sealed class GeneratorAction {
data class ShouldShowAnonAddySelfHostValueChangeReceive(
val shouldShowAnonAddySelfHostServerUrlField: Boolean,
) : Internal()
/**
* The value for the shouldShowSimpleLoginSelfHostServerField has changed.
*/
data class ShouldShowSimpleLoginSelfHostValueChangeReceive(
val shouldShowSelfHostServerField: Boolean,
) : Internal()
}
}
@@ -12,7 +12,7 @@ import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorAction.MainType.U
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LongMethod")
data class ForwardedEmailAliasHandlers(
val onServiceChange: (ForwardedEmailAlias.ServiceTypeOption) -> Unit,
val onAddyIoAccessTokenTextChange: (String) -> Unit,
@@ -24,6 +24,7 @@ data class ForwardedEmailAliasHandlers(
val onForwardEmailApiKeyTextChange: (String) -> Unit,
val onForwardEmailDomainNameTextChange: (String) -> Unit,
val onSimpleLoginApiKeyTextChange: (String) -> Unit,
val onSimpleLoginSelfHostServerUrlChange: (String) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
@@ -93,6 +94,13 @@ data class ForwardedEmailAliasHandlers(
ForwardedEmailAliasAction.SimpleLogin.ApiKeyTextChange(apiKey = newApiKey),
)
},
onSimpleLoginSelfHostServerUrlChange = { newServerUrl ->
viewModel.trySendAction(
ForwardedEmailAliasAction.SimpleLogin.SelfHostServerUrlChange(
url = newServerUrl,
),
)
},
)
}
}
@@ -24,7 +24,12 @@ fun UsernameGenerationOptions.ForwardedEmailServiceType?.toServiceType(
}
UsernameGenerationOptions.ForwardedEmailServiceType.SIMPLE_LOGIN -> {
SimpleLogin(apiKey = options.simpleLoginApiKey.orEmpty())
SimpleLogin(
apiKey = options.simpleLoginApiKey.orEmpty(),
selfHostServerUrl = options.simpleLoginSelfHostServerUrl
?.prefixHttpsIfNecessary()
.orEmpty(),
)
}
UsernameGenerationOptions.ForwardedEmailServiceType.DUCK_DUCK_GO -> {
@@ -13,6 +13,7 @@ import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Us
fun ServiceType.toUsernameGeneratorRequest(
website: String?,
allowAddyIoSelfHostUrl: Boolean,
allowSimpleLoginSelfHostUrl: Boolean,
): UsernameGeneratorRequest.Forwarded? {
return when (this) {
is ServiceType.AddyIo -> {
@@ -80,12 +81,17 @@ fun ServiceType.toUsernameGeneratorRequest(
}
is ServiceType.SimpleLogin -> {
val baseUrl = if (allowSimpleLoginSelfHostUrl && selfHostServerUrl.isNotBlank()) {
selfHostServerUrl.prefixHttpsIfNecessary()
} else {
ServiceType.SimpleLogin.DEFAULT_SIMPLE_LOGIN_URL
}
this
.apiKey
.orNullIfBlank()
?.let {
UsernameGeneratorRequest.Forwarded(
service = ForwarderServiceType.SimpleLogin(apiKey = it),
service = ForwarderServiceType.SimpleLogin(apiKey = it, baseUrl = baseUrl),
website = website,
)
}
@@ -53,6 +53,7 @@ class GeneratorDiskSourceTest {
catchAllEmailDomain = "example.com",
firefoxRelayApiAccessToken = "access_token_firefox_relay",
simpleLoginApiKey = "api_key_simple_login",
simpleLoginSelfHostServerUrl = "https://simplelogin.local",
duckDuckGoApiKey = "api_key_duck_duck_go",
fastMailApiKey = "api_key_fast_mail",
anonAddyApiAccessToken = "access_token_anon_addy",
@@ -157,6 +158,7 @@ class GeneratorDiskSourceTest {
catchAllEmailDomain = "example.com",
firefoxRelayApiAccessToken = "access_token_firefox_relay",
simpleLoginApiKey = "api_key_simple_login",
simpleLoginSelfHostServerUrl = "https://simplelogin.local",
duckDuckGoApiKey = "api_key_duck_duck_go",
fastMailApiKey = "api_key_fast_mail",
anonAddyApiAccessToken = "access_token_anon_addy",
@@ -195,6 +197,7 @@ class GeneratorDiskSourceTest {
catchAllEmailDomain = "example.com",
firefoxRelayApiAccessToken = "access_token_firefox_relay",
simpleLoginApiKey = "api_key_simple_login",
simpleLoginSelfHostServerUrl = "https://simplelogin.local",
duckDuckGoApiKey = "api_key_duck_duck_go",
fastMailApiKey = "api_key_fast_mail",
anonAddyApiAccessToken = "access_token_anon_addy",
@@ -645,6 +645,7 @@ class GeneratorRepositoryTest {
catchAllEmailDomain = "example.com",
firefoxRelayApiAccessToken = "access_token_firefox_relay",
simpleLoginApiKey = "api_key_simple_login",
simpleLoginSelfHostServerUrl = "https://simplelogin.local",
duckDuckGoApiKey = "api_key_duck_duck_go",
fastMailApiKey = "api_key_fast_mail",
anonAddyApiAccessToken = "access_token_anon_addy",
@@ -698,6 +699,7 @@ class GeneratorRepositoryTest {
catchAllEmailDomain = "example.com",
firefoxRelayApiAccessToken = "access_token_firefox_relay",
simpleLoginApiKey = "api_key_simple_login",
simpleLoginSelfHostServerUrl = "https://simplelogin.local",
duckDuckGoApiKey = "api_key_duck_duck_go",
fastMailApiKey = "api_key_fast_mail",
anonAddyApiAccessToken = "access_token_anon_addy",
@@ -729,6 +731,7 @@ class GeneratorRepositoryTest {
catchAllEmailDomain = "example.com",
firefoxRelayApiAccessToken = "access_token_firefox_relay",
simpleLoginApiKey = "api_key_simple_login",
simpleLoginSelfHostServerUrl = "https://simplelogin.local",
duckDuckGoApiKey = "api_key_duck_duck_go",
fastMailApiKey = "api_key_fast_mail",
anonAddyApiAccessToken = "access_token_anon_addy",
@@ -1365,6 +1365,93 @@ class GeneratorScreenTest : BaseComposeTest() {
}
}
@Suppress("MaxLineLength")
@Test
fun `in Username_ForwardedEmailAlias_SimpleLogin state, updating self host server url text input should send SelfHostServerUrlChange action`() {
updateState(
DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Username(
GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias(
selectedServiceType = GeneratorState
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ServiceType
.SimpleLogin(),
),
),
),
)
val newSelfHostServerUrl = "https://simplelogin.local"
composeTestRule
.onNodeWithText("Self-host server URL")
.performScrollTo()
.performTextInput(newSelfHostServerUrl)
verify {
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.SimpleLogin
.SelfHostServerUrlChange(url = newSelfHostServerUrl),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in Username_ForwardedEmailAlias_SimpleLogin state, should display self host server url field based on state`() {
updateState(
DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Username(
GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias(
selectedServiceType = GeneratorState
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ServiceType
.SimpleLogin(),
),
),
shouldShowSimpleLoginSelfHostServerField = true,
),
)
composeTestRule
.onNodeWithText("Self-host server URL")
.performScrollTo()
.assertIsDisplayed()
// Simulate disabling the feature flag.
updateState(
DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Username(
GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias(
selectedServiceType = GeneratorState
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ServiceType
.SimpleLogin(),
),
),
shouldShowSimpleLoginSelfHostServerField = false,
),
)
composeTestRule
.onNodeWithText("Self-host server URL")
.assertDoesNotExist()
}
//endregion SimpleLogin Service Type Tests
//region ForwardEmail Service Type Tests
@@ -1853,4 +1940,5 @@ private val DEFAULT_STATE = GeneratorState(
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = false,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
@@ -122,11 +122,16 @@ class GeneratorViewModelTest : BaseViewModelTest() {
every { shouldShowGeneratorCoachMarkFlow } returns mutableShouldShowGeneratorCoachMarkFlow
}
private val mutableAnonAddySelfHostAliasFlow = MutableStateFlow(true)
private val mutableShouldShowSimpleLoginSelfHostFlow = MutableStateFlow(true)
private val featureFlagManager = mockk<FeatureFlagManager> {
every { getFeatureFlag(FlagKey.AnonAddySelfHostAlias) } returns true
every {
getFeatureFlagFlow(FlagKey.AnonAddySelfHostAlias)
} returns mutableAnonAddySelfHostAliasFlow
every { getFeatureFlag(FlagKey.SimpleLoginSelfHostAlias) } returns true
every {
getFeatureFlagFlow(FlagKey.SimpleLoginSelfHostAlias)
} returns mutableShouldShowSimpleLoginSelfHostFlow
}
@Test
@@ -145,6 +150,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
fun `initial state should be correct for username modal`() {
val usernameGenerationOptions = UsernameGenerationOptions(
type = UsernameGenerationOptions.UsernameType.RANDOM_WORD,
simpleLoginSelfHostServerUrl = "",
)
fakeGeneratorRepository.saveUsernameGenerationOptions(usernameGenerationOptions)
val expected = GeneratorState(
@@ -160,6 +166,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
website = "",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
val viewModel = createViewModel(
@@ -195,6 +202,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
val viewModel = createViewModel(
@@ -930,6 +938,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
fakeGeneratorRepository.saveUsernameGenerationOptions(
UsernameGenerationOptions(
type = UsernameGenerationOptions.UsernameType.RANDOM_WORD,
simpleLoginSelfHostServerUrl = "",
),
)
val expectedState = initialState.copy(
@@ -1010,6 +1019,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
fakeGeneratorRepository.saveUsernameGenerationOptions(
UsernameGenerationOptions(
type = UsernameGenerationOptions.UsernameType.RANDOM_WORD,
simpleLoginSelfHostServerUrl = "",
),
)
// When this action is handled there will be another call to `loadOptions()`
@@ -2049,6 +2059,42 @@ class GeneratorViewModelTest : BaseViewModelTest() {
assertEquals(expectedState, viewModel.stateFlow.value)
}
@Test
fun `SelfHostServerUrlChange should update self host server url correctly`() = runTest {
val newSelfHostServerUrl = "https://newSelfHostServerUrl"
val action = GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.SimpleLogin
.SelfHostServerUrlChange(
url = newSelfHostServerUrl,
)
fakeGeneratorRepository.setMockGenerateForwardedServiceResult(
GeneratedForwardedServiceUsernameResult.Success(
generatedEmailAddress = "defaultSimpleLogin",
),
)
viewModel.trySendAction(action)
val expectedState = defaultSimpleLoginState.copy(
generatedText = "-",
selectedType = GeneratorState.MainType.Username(
GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias(
selectedServiceType = ServiceType
.SimpleLogin(
selfHostServerUrl = newSelfHostServerUrl,
),
),
),
)
assertEquals(expectedState, viewModel.stateFlow.value)
}
}
@Nested
@@ -2336,6 +2382,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createPassphraseState(
@@ -2356,6 +2403,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createUsernameModeState(
@@ -2373,6 +2421,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createForwardedEmailAliasState(
@@ -2390,6 +2439,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createAddyIoState(
@@ -2406,6 +2456,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createDuckDuckGoState(
@@ -2422,6 +2473,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createFastMailState(
@@ -2438,6 +2490,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createFirefoxRelayState(
@@ -2454,6 +2507,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createForwardEmailState(
@@ -2470,6 +2524,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createSimpleLoginState(
@@ -2486,6 +2541,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createPlusAddressedEmailState(
@@ -2502,6 +2558,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createCatchAllEmailState(
@@ -2518,6 +2575,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createRandomWordState(
@@ -2536,6 +2594,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
currentEmailAddress = "currentEmail",
shouldShowCoachMarkTour = true,
shouldShowAnonAddySelfHostServerUrlField = true,
shouldShowSimpleLoginSelfHostServerField = true,
)
private fun createSavedStateHandleWithState(state: GeneratorState) =
@@ -18,6 +18,7 @@ class ForwardedEmailServiceTypeExtensionsTest {
catchAllEmailDomain = "example.com",
firefoxRelayApiAccessToken = "access_token_firefox_relay",
simpleLoginApiKey = "api_key_simple_login",
simpleLoginSelfHostServerUrl = "https://simplelogin.local",
duckDuckGoApiKey = "api_key_duck_duck_go",
fastMailApiKey = "api_key_fast_mail",
anonAddyApiAccessToken = "access_token_anon_addy",
@@ -51,6 +52,7 @@ class ForwardedEmailServiceTypeExtensionsTest {
catchAllEmailDomain = null,
firefoxRelayApiAccessToken = null,
simpleLoginApiKey = null,
simpleLoginSelfHostServerUrl = null,
duckDuckGoApiKey = null,
fastMailApiKey = null,
anonAddyApiAccessToken = null,
@@ -101,6 +103,9 @@ class ForwardedEmailServiceTypeExtensionsTest {
apiKey = "api_key_simple_login"
.takeUnless { useEmptyValues }
.orEmpty(),
selfHostServerUrl = "https://simplelogin.local"
.takeUnless { useEmptyValues }
.orEmpty(),
)
}
@@ -18,6 +18,7 @@ internal class ServiceTypeExtensionsTest {
val request = addyIoServiceType.toUsernameGeneratorRequest(
website = null,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertNull(request)
@@ -32,6 +33,7 @@ internal class ServiceTypeExtensionsTest {
val request = addyIoServiceType.toUsernameGeneratorRequest(
website = null,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertNull(request)
@@ -58,6 +60,7 @@ internal class ServiceTypeExtensionsTest {
addyIoServiceType.toUsernameGeneratorRequest(
website = website,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
),
)
@@ -74,6 +77,7 @@ internal class ServiceTypeExtensionsTest {
addyIoServiceType.toUsernameGeneratorRequest(
website = website,
allowAddyIoSelfHostUrl = false,
allowSimpleLoginSelfHostUrl = true,
),
)
}
@@ -89,6 +93,7 @@ internal class ServiceTypeExtensionsTest {
val request = addyIoServiceType.toUsernameGeneratorRequest(
website = website,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertEquals(
@@ -110,6 +115,7 @@ internal class ServiceTypeExtensionsTest {
val request = duckDuckGoServiceType.toUsernameGeneratorRequest(
website = null,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertNull(request)
@@ -122,6 +128,7 @@ internal class ServiceTypeExtensionsTest {
val request = duckDuckGoServiceType.toUsernameGeneratorRequest(
website = website,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertEquals(
@@ -139,6 +146,7 @@ internal class ServiceTypeExtensionsTest {
val request = firefoxRelayServiceType.toUsernameGeneratorRequest(
website = null,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertNull(request)
@@ -151,6 +159,7 @@ internal class ServiceTypeExtensionsTest {
val request = firefoxRelayServiceType.toUsernameGeneratorRequest(
website = website,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertEquals(
@@ -168,6 +177,7 @@ internal class ServiceTypeExtensionsTest {
val request = fastMailServiceType.toUsernameGeneratorRequest(
website = null,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertNull(request)
@@ -182,6 +192,7 @@ internal class ServiceTypeExtensionsTest {
val request = fastMailServiceType.toUsernameGeneratorRequest(
website = website,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertEquals(
@@ -202,6 +213,7 @@ internal class ServiceTypeExtensionsTest {
val request = forwardMailServiceType.toUsernameGeneratorRequest(
website = null,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertNull(request)
@@ -216,6 +228,7 @@ internal class ServiceTypeExtensionsTest {
val request = forwardMailServiceType.toUsernameGeneratorRequest(
website = null,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertNull(request)
@@ -231,6 +244,7 @@ internal class ServiceTypeExtensionsTest {
val request = forwardEmailServiceType.toUsernameGeneratorRequest(
website = website,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertEquals(
@@ -251,23 +265,78 @@ internal class ServiceTypeExtensionsTest {
val request = simpleLoginServiceType.toUsernameGeneratorRequest(
website = null,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertNull(request)
}
@Suppress("MaxLineLength")
@Test
fun `toUsernameGeneratorRequest for SimpleLogin returns correct request`() {
fun `toUsernameGeneratorRequest for SimpleLogin returns correct request when allowSimpleLoginSelfHostServer is false and selfHostServerUrl is blank`() {
val simpleLoginServiceType = ServiceType.SimpleLogin(apiKey = "testKey")
val website = "bitwarden.com"
val request = simpleLoginServiceType.toUsernameGeneratorRequest(
website = website,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertEquals(
UsernameGeneratorRequest.Forwarded(
service = ForwarderServiceType.SimpleLogin(apiKey = "testKey"),
service = ForwarderServiceType.SimpleLogin(
apiKey = "testKey",
ServiceType.SimpleLogin.DEFAULT_SIMPLE_LOGIN_URL,
),
website = website,
),
request,
)
}
@Suppress("MaxLineLength")
@Test
fun `toUsernameGeneratorRequest for SimpleLogin returns correct request when allowSimpleLoginSelfHostServer is true and selfHostServerUrl is blank`() {
val simpleLoginServiceType = ServiceType.SimpleLogin(apiKey = "testKey")
val website = "bitwarden.com"
val request = simpleLoginServiceType.toUsernameGeneratorRequest(
website = website,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertEquals(
UsernameGeneratorRequest.Forwarded(
service = ForwarderServiceType.SimpleLogin(
apiKey = "testKey",
ServiceType.SimpleLogin.DEFAULT_SIMPLE_LOGIN_URL,
),
website = website,
),
request,
)
}
@Suppress("MaxLineLength")
@Test
fun `toUsernameGeneratorRequest for SimpleLogin returns correct request when allowSimpleLoginSelfHostServer is true and selfHostServerUrl is not blank`() {
val simpleLoginServiceType = ServiceType.SimpleLogin(
apiKey = "testKey",
selfHostServerUrl = "https://simplelogin.local",
)
val website = "bitwarden.com"
val request = simpleLoginServiceType.toUsernameGeneratorRequest(
website = website,
allowAddyIoSelfHostUrl = true,
allowSimpleLoginSelfHostUrl = true,
)
assertEquals(
UsernameGeneratorRequest.Forwarded(
service = ForwarderServiceType.SimpleLogin(
apiKey = "testKey",
baseUrl = "https://simplelogin.local",
),
website = website,
),
request,
+1 -1
View File
@@ -26,7 +26,7 @@ androidxSplash = "1.1.0-rc01"
androidXAppCompat = "1.7.0"
androdixAutofill = "1.1.0"
androidxWork = "2.10.0"
bitwardenSdk = "1.0.0-20250203.153811-96"
bitwardenSdk = "1.0.0-20250213.181812-113"
crashlytics = "3.0.2"
detekt = "1.23.7"
firebaseBom = "33.8.0"