Skip to content

Commit

Permalink
Add feature flag for importing passwords via Google Password Manager
Browse files Browse the repository at this point in the history
  • Loading branch information
CDRussell committed Nov 4, 2024
1 parent e69bfc8 commit 73e0f43
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,8 @@ interface AutofillFeature {
*/
@Toggle.DefaultValue(false)
fun showDisableDialogAutofillPrompt(): Toggle

@InternalAlwaysEnabled
@Toggle.DefaultValue(false)
fun canImportFromGooglePasswordManager(): Toggle
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2024 DuckDuckGo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.duckduckgo.autofill.impl.importing.gpm.feature

import com.duckduckgo.autofill.api.AutofillFeature
import com.duckduckgo.common.utils.DispatcherProvider
import com.duckduckgo.di.scopes.AppScope
import com.squareup.anvil.annotations.ContributesBinding
import javax.inject.Inject
import kotlinx.coroutines.withContext

interface AutofillImportPasswordConfigStore {
suspend fun getConfig(): AutofillImportPasswordSettings
}

data class AutofillImportPasswordSettings(
val canImportFromGooglePasswords: Boolean,
val launchUrlGooglePasswords: String,
val javascriptConfigGooglePasswords: String,
)

@ContributesBinding(AppScope::class)
class AutofillImportPasswordConfigStoreImpl @Inject constructor(
private val autofillFeature: AutofillFeature,
private val dispatchers: DispatcherProvider,
) : AutofillImportPasswordConfigStore {

override suspend fun getConfig(): AutofillImportPasswordSettings {
return withContext(dispatchers.io()) {
with(autofillFeature.canImportFromGooglePasswordManager()) {
val config = getConfig()
val launchUrl = config[LAUNCH_URL_KEY] ?: LAUNCH_URL_DEFAULT
val javascriptConfig = config[JAVASCRIPT_CONFIG_KEY] ?: JAVASCRIPT_CONFIG_DEFAULT

AutofillImportPasswordSettings(
canImportFromGooglePasswords = autofillFeature.canImportFromGooglePasswordManager().isEnabled(),
launchUrlGooglePasswords = launchUrl,
javascriptConfigGooglePasswords = javascriptConfig,
)
}
}
}

companion object {
private const val JAVASCRIPT_CONFIG_KEY = "javascriptConfig"
const val JAVASCRIPT_CONFIG_DEFAULT = "{}"

private const val LAUNCH_URL_KEY = "launchUrl"
const val LAUNCH_URL_DEFAULT = "https://passwords.google.com/options?ep=1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.duckduckgo.autofill.impl.importing.gpm.feature

import android.annotation.SuppressLint
import com.duckduckgo.autofill.api.AutofillFeature
import com.duckduckgo.autofill.impl.importing.gpm.feature.AutofillImportPasswordConfigStoreImpl.Companion.JAVASCRIPT_CONFIG_DEFAULT
import com.duckduckgo.autofill.impl.importing.gpm.feature.AutofillImportPasswordConfigStoreImpl.Companion.LAUNCH_URL_DEFAULT
import com.duckduckgo.common.test.CoroutineTestRule
import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory
import com.duckduckgo.feature.toggles.api.Toggle.State
import kotlinx.coroutines.test.runTest
import org.junit.Assert.*
import org.junit.Rule
import org.junit.Test

class AutofillImportPasswordConfigStoreImplTest {

@get:Rule
val coroutineTestRule: CoroutineTestRule = CoroutineTestRule()

private val autofillFeature = FakeFeatureToggleFactory.create(AutofillFeature::class.java)
private val testee = AutofillImportPasswordConfigStoreImpl(
autofillFeature = autofillFeature,
dispatchers = coroutineTestRule.testDispatcherProvider,
)

@Test
fun whenFeatureFlagEnabledThenCanImportGooglePasswordsConfigIsEnabled() = runTest {
configureFeature(true)
assertTrue(testee.getConfig().canImportFromGooglePasswords)
}

@Test
fun whenFeatureFlagEnabledThenCanImportGooglePasswordsConfigIsDisabled() = runTest {
configureFeature(false)
assertFalse(testee.getConfig().canImportFromGooglePasswords)
}

@Test
fun whenLaunchUrlNotSpecifiedInConfigThenDefaultUsed() = runTest {
configureFeature(config = emptyMap())
assertEquals(LAUNCH_URL_DEFAULT, testee.getConfig().launchUrlGooglePasswords)
}

@Test
fun whenLaunchUrlSpecifiedInConfigThenOverridesDefault() = runTest {
configureFeature(config = mapOf("launchUrl" to "https://example.com"))
assertEquals("https://example.com", testee.getConfig().launchUrlGooglePasswords)
}

@Test
fun whenJavascriptConfigNotSpecifiedInConfigThenDefaultUsed() = runTest {
configureFeature(config = emptyMap())
assertEquals(JAVASCRIPT_CONFIG_DEFAULT, testee.getConfig().javascriptConfigGooglePasswords)
}

@Test
fun whenJavascriptConfigSpecifiedInConfigThenOverridesDefault() = runTest {
configureFeature(config = mapOf("javascriptConfig" to """{"key": "value"}"""))
assertEquals("""{"key": "value"}""", testee.getConfig().javascriptConfigGooglePasswords)
}

@SuppressLint("DenyListedApi")
private fun configureFeature(enabled: Boolean = true, config: Map<String, String> = emptyMap()) {
autofillFeature.canImportFromGooglePasswordManager().setRawStoredState(
State(
remoteEnableState = enabled,
config = config,
),
)
}
}

0 comments on commit 73e0f43

Please sign in to comment.