Skip to content

Commit

Permalink
[Feature Toggle, Autofill.js] Pass through a js feature toggle for au…
Browse files Browse the repository at this point in the history
…tofill (#4955)

Task/Issue URL:
https://app.asana.com/0/1205996472158114/1208150709359290/f

### Description
This PR passes through remote config so that it can be accessed in
`autofill.js`, no other business logic is added on the Android side.
It's a simple pass-through.

Remote config was already merged:
duckduckgo/privacy-configuration#2265

Autofill.js PR was already merged with the feature toggle: 
duckduckgo/duckduckgo-autofill#619

### Steps to test this PR
Fixes bugs like:
https://app.asana.com/0/1200930669568058/1206749141089966/f
(With the latest remote config, already merged)
1. Run the android app,
2. Go to https://dplinfo.ssb-ag.de/WebComm/default.aspx?TestingCookie=1
3. Save a password there and reload page,
4. The username should have the key icon, and autofill should work
(won't autofill password automatically, that's okay).

Counter test - do the same steps with an older config, with
the`canCategorizeUnknownUsername` feature `disabled`. You won't see the
key icon.

E.g with https://jsonblob.com/api/1278747279446892544

### UI changes
Autofill.js changes only, which were tested already in
duckduckgo/duckduckgo-autofill#619
  • Loading branch information
dbajpeyi authored Aug 30, 2024
1 parent 3f2d47c commit 43773a1
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ interface AutofillFeature {
@Toggle.DefaultValue(false)
fun canAccessCredentialManagement(): Toggle

/**
* @return `true` when the remote config has the global "canCategorizeUnknownUsername" autofill sub-feature flag enabled
* If the remote feature is not present defaults to `false`
*/
@Toggle.DefaultValue(false)
fun canCategorizeUnknownUsername(): Toggle

/**
* @return `true` when the remote config has the global "onByDefault" autofill sub-feature flag enabled
* If the remote feature is not present defaults to `false`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.duckduckgo.autofill.impl.configuration

import com.duckduckgo.autofill.api.AutofillCapabilityChecker
import com.duckduckgo.autofill.api.AutofillFeature
import com.duckduckgo.autofill.api.domain.app.LoginCredentials
import com.duckduckgo.autofill.api.email.EmailManager
import com.duckduckgo.autofill.impl.email.incontext.availability.EmailProtectionInContextAvailabilityRules
Expand All @@ -42,6 +43,7 @@ class RealAutofillRuntimeConfigProvider @Inject constructor(
private val autofillStore: InternalAutofillStore,
private val runtimeConfigurationWriter: RuntimeConfigurationWriter,
private val autofillCapabilityChecker: AutofillCapabilityChecker,
private val autofillFeature: AutofillFeature,
private val shareableCredentials: ShareableCredentials,
private val emailProtectionInContextAvailabilityRules: EmailProtectionInContextAvailabilityRules,
private val neverSavedSiteRepository: NeverSavedSiteRepository,
Expand All @@ -60,6 +62,7 @@ class RealAutofillRuntimeConfigProvider @Inject constructor(
passwordGeneration = canGeneratePasswords(url),
showInlineKeyIcon = true,
showInContextEmailProtectionSignup = canShowInContextEmailProtectionSignup(url),
unknownUsernameCategorization = canCategorizeUnknownUsername(),
)
val availableInputTypes = generateAvailableInputTypes(url)

Expand Down Expand Up @@ -126,6 +129,10 @@ class RealAutofillRuntimeConfigProvider @Inject constructor(
return !neverSavedSiteRepository.isInNeverSaveList(url)
}

private fun canCategorizeUnknownUsername(): Boolean {
return autofillFeature.canCategorizeUnknownUsername().isEnabled()
}

private suspend fun canShowInContextEmailProtectionSignup(url: String?): Boolean {
if (url == null) return false
return emailProtectionInContextAvailabilityRules.permittedToShow(url)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ interface RuntimeConfigurationWriter {
passwordGeneration: Boolean,
showInlineKeyIcon: Boolean,
showInContextEmailProtectionSignup: Boolean,
unknownUsernameCategorization: Boolean,
): String
}

Expand Down Expand Up @@ -86,6 +87,7 @@ class RealRuntimeConfigurationWriter @Inject constructor(val moshi: Moshi) : Run
passwordGeneration: Boolean,
showInlineKeyIcon: Boolean,
showInContextEmailProtectionSignup: Boolean,
unknownUsernameCategorization: Boolean,
): String {
return """
userPreferences = {
Expand All @@ -104,7 +106,8 @@ class RealRuntimeConfigurationWriter @Inject constructor(val moshi: Moshi) : Run
"password_generation": $passwordGeneration,
"credentials_saving": $credentialSaving,
"inlineIcon_credentials": $showInlineKeyIcon,
"emailProtection_incontext_signup": $showInContextEmailProtectionSignup
"emailProtection_incontext_signup": $showInContextEmailProtectionSignup,
"unknown_username_categorization": $unknownUsernameCategorization,
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.duckduckgo.autofill.impl.jsbridge.response.AvailableInputTypeCredenti
import com.duckduckgo.autofill.impl.sharedcreds.ShareableCredentials
import com.duckduckgo.autofill.impl.store.InternalAutofillStore
import com.duckduckgo.autofill.impl.store.NeverSavedSiteRepository
import com.duckduckgo.feature.toggles.api.toggle.AutofillTestFeature
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
Expand All @@ -40,6 +41,7 @@ class RealAutofillRuntimeConfigProviderTest {

private val emailManager: EmailManager = mock()
private val autofillStore: InternalAutofillStore = mock()
private val autofillFeature: AutofillTestFeature = AutofillTestFeature()
private val runtimeConfigurationWriter: RuntimeConfigurationWriter = mock()
private val shareableCredentials: ShareableCredentials = mock()
private val autofillCapabilityChecker: AutofillCapabilityChecker = mock()
Expand All @@ -54,6 +56,7 @@ class RealAutofillRuntimeConfigProviderTest {
autofillStore,
runtimeConfigurationWriter,
autofillCapabilityChecker = autofillCapabilityChecker,
autofillFeature = autofillFeature,
shareableCredentials = shareableCredentials,
emailProtectionInContextAvailabilityRules = emailProtectionInContextAvailabilityRules,
neverSavedSiteRepository = neverSavedSiteRepository,
Expand All @@ -64,6 +67,7 @@ class RealAutofillRuntimeConfigProviderTest {
whenever(neverSavedSiteRepository.isInNeverSaveList(any())).thenReturn(false)
}

autofillFeature.canCategorizeUnknownUsername = true
whenever(runtimeConfigurationWriter.generateContentScope()).thenReturn("")
whenever(runtimeConfigurationWriter.generateResponseGetAvailableInputTypes(any(), any())).thenReturn("")
whenever(runtimeConfigurationWriter.generateUserUnprotectedDomains()).thenReturn("")
Expand All @@ -74,6 +78,7 @@ class RealAutofillRuntimeConfigProviderTest {
passwordGeneration = any(),
showInlineKeyIcon = any(),
showInContextEmailProtectionSignup = any(),
unknownUsernameCategorization = any(),
),
).thenReturn("")
}
Expand Down Expand Up @@ -383,6 +388,7 @@ class RealAutofillRuntimeConfigProviderTest {
passwordGeneration = any(),
showInlineKeyIcon = any(),
showInContextEmailProtectionSignup = any(),
unknownUsernameCategorization = any(),
)
}

Expand All @@ -393,6 +399,7 @@ class RealAutofillRuntimeConfigProviderTest {
passwordGeneration = any(),
showInlineKeyIcon = any(),
showInContextEmailProtectionSignup = any(),
unknownUsernameCategorization = any(),
)
}

Expand All @@ -407,6 +414,7 @@ class RealAutofillRuntimeConfigProviderTest {
passwordGeneration = any(),
showInlineKeyIcon = eq(true),
showInContextEmailProtectionSignup = any(),
unknownUsernameCategorization = any(),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ class RealRuntimeConfigurationWriterTest {
"password_generation": true,
"credentials_saving": true,
"inlineIcon_credentials": true,
"emailProtection_incontext_signup": true
"emailProtection_incontext_signup": true,
"unknown_username_categorization": false,
}
}
}
Expand All @@ -107,6 +108,7 @@ class RealRuntimeConfigurationWriterTest {
passwordGeneration = true,
showInlineKeyIcon = true,
showInContextEmailProtectionSignup = true,
unknownUsernameCategorization = false,
),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ class AutofillTestFeature : AutofillFeature {
var canIntegrateWithWebView: Boolean = false
var onForExistingUsers: Boolean = false
var showDisableDialogAutofillPrompt: Boolean = false
var canCategorizeUnknownUsername: Boolean = false

override fun self(): Toggle = TestToggle(topLevelFeatureEnabled)
override fun canInjectCredentials(): Toggle = TestToggle(canInjectCredentials)
override fun canIntegrateAutofillInWebView() = TestToggle(canIntegrateWithWebView)
override fun canSaveCredentials(): Toggle = TestToggle(canSaveCredentials)
override fun canGeneratePasswords(): Toggle = TestToggle(canGeneratePassword)
override fun canAccessCredentialManagement(): Toggle = TestToggle(canAccessCredentialManagement)
override fun canCategorizeUnknownUsername(): Toggle = TestToggle(canCategorizeUnknownUsername)
override fun onByDefault(): Toggle = TestToggle(onByDefault)
override fun onForExistingUsers(): Toggle = TestToggle(onForExistingUsers)
override fun showDisableDialogAutofillPrompt(): Toggle = TestToggle(showDisableDialogAutofillPrompt)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class AutofillInternalSettingsActivity : DuckDuckGoActivity() {
val canInjectCredentials = autofillFeature.canInjectCredentials()
val canGeneratePasswords = autofillFeature.canGeneratePasswords()
val canAccessCredentialManagement = autofillFeature.canAccessCredentialManagement()
val canCategorizeUnknownUsername = autofillFeature.canCategorizeUnknownUsername()

withContext(dispatchers.main()) {
binding.autofillTopLevelFeature.setSecondaryText(autofillEnabled.description())
Expand All @@ -132,6 +133,7 @@ class AutofillInternalSettingsActivity : DuckDuckGoActivity() {
binding.canInjectCredentialsFeature.setSecondaryText(canInjectCredentials.description())
binding.canGeneratePasswordsFeature.setSecondaryText(canGeneratePasswords.description())
binding.canAccessCredentialManagementFeature.setSecondaryText(canAccessCredentialManagement.description())
binding.autofillTopLevelFeature.setSecondaryText(canCategorizeUnknownUsername.description())
}
}
}
Expand Down

0 comments on commit 43773a1

Please sign in to comment.