Skip to content

Commit

Permalink
Re-enable autofill in iFrames (#5007)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/72649045549333/1208302312668360/f

### Description
We are adopting new webview interface for injecting JS that supports
iframes.
This PR contains:
- Brings back #4360 (by
reverting #4533)
- adds a guard against usage on WebView < `126.0.6478.40`

### Steps to test this PR (copied from original PR)
This PR covers all of autofill, which includes both autofilling
passwords as well as Email Protection. As such, thorough testing of all
of autofill is required.

### Passwords

#### Saving a login
- [x] visit <https://fill.dev/form/login-simple>
- [x] enter username `abc` and any password (>= 4 characters) and hit
login button
- [x] verify you are prompted to save. 
- [x] Test not saving scenario and saving scenario; verify both work as
you'd expect
- [x] visit overflow → Passwords, and verify the login exists 

#### Updating a password for a saved login
- [x] revisit <https://fill.dev/form/login-simple> and decline any offer
to autofill
- [x] enter username `abc` (same as before)
- [x] enter a different password than last time (still >= 4 characters)
- [x] hit Login button; verify you are prompted to update the saved
password (test both declining and accepting)

#### Autofilling a saved login
- [x] visit <https://fill.dev/form/login-simple>
- [x] verify you are prompted to autofill
- [x] test out autofilling as well as declining; verify both work as
you'd expect
- [x] repeat this test when you have multiple passwords and make sure
the right one is autofilled\

#### Auto-generating a password
- [x] visit <https://fill.dev/form/registration-email>
- [x] verify you see the _generate password_ icon in the password fields
- [x] tap on the password field and verify you are prompted to use a
autogenerated password; test both using it and not
- [x] visit overflow → Passwords, and verify the password exists (it's
auto-saved if you accept generated password)
- [x] tap on email field and add an example address
- [x] tap Register button
- [x] visit overflow → Passwords and verify there is a combined password
saved (with both email + auto-generated password)

### Email Protection

#### Signing in
- [x] visit `Settings` → `Email Protection`
- [x] sign into email protection
- [x] test you can generate aliases (`overflow` → `Generate Duck
Address`)

#### Autofilling email protection
- [x] visit <https://fill.dev/form/registration-email>
- [x] verify dax icon in email field is red
- [x] tap into email field; verify you are prompted to choose an email
address; decline
- [x] tap into email field again; verify this time you are not prompted
but can instead type freely
- [x] tap on the red dax icon in the email field and verify you are
prompted again for the email selection; this time choose the top option
to autofill your personal duck address and verify it works
- [x] tap on the red dax icon in the email field and verify you are
prompted again for the email selection; this time choose the bottom
option to autofill your private duck alias and verify it autofills.
- [x] Also, visit overflow → Passwords and verify it has auto-saved this
as a login using your private duck alias as username (with no password)

####  Signing out
- [x] visit Settings → Email Protection
- [x] sign out
- [x] verify sign out works successfully

#### Email Protection in-context signup
- [x] visit <https://fill.dev/form/registration-email>
- [x] tap on the email field, and verify you are prompted to "Hide Your
Email and Block Trackers"
- [x] tap on "Protect My Email" and sign into your duck address
- [ ] Verify when you're done and have validated with your security
code, you are signed in


### iframes
You can test how autofill now works against iframes, ensuring that
autofill is only offered when the origin of the iframe matches the
stored password (not the top-level page url)
- [x] visit https://gravida.pro/ddg/navigate.html
- [x] enter username (suggestion: `mainframe`), password and hit Login
button. Save when prompted
- [x] refresh the page, and make sure you can successfully autofill into
it when prompted
- [x] hit the `Navigate after 2 seconds` button (and wait 2 seconds...)
- [x] verify you are **not** prompted to autofill (the iframe does not
match the saved password)
- [x] enter username (suggestion: `iframe`), password and hit the red
Login button. Saved when prompted.
- [x] refresh the page. you'll be returned to the first page (with blue
button)
- [x] verify you are prompted to autofill only the `mainframe` password
and not the `iframe` one
- [x] Hit the `Navigate after 2 seconds` button again. 
- [x] when the new page loads (with red button), verify you are only
prompted to autofill the `iframe` one and **not** the main one. Verify
you can autofill the `iframe` one.

### UI changes
| Before  | After |
| ------ | ----- |
!(Upload before screenshot)|(Upload after screenshot)|
  • Loading branch information
cmonfortep authored Sep 30, 2024
1 parent 669d0b4 commit a043931
Show file tree
Hide file tree
Showing 98 changed files with 4,172 additions and 3,606 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/e2e-nightly-autofill.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
name: ${{ github.sha }}
app-file: apk/release.apk
android-api-level: 30
android-api-level: 33
workspace: .maestro
include-tags: autofillNoAuthTests

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ import com.duckduckgo.app.usage.search.SearchCountDao
import com.duckduckgo.app.widget.ui.WidgetCapabilities
import com.duckduckgo.appbuildconfig.api.AppBuildConfig
import com.duckduckgo.autofill.api.AutofillCapabilityChecker
import com.duckduckgo.autofill.api.AutofillWebMessageRequest
import com.duckduckgo.autofill.api.domain.app.LoginCredentials
import com.duckduckgo.autofill.api.email.EmailManager
import com.duckduckgo.autofill.api.passwordgeneration.AutomaticSavedLoginsMonitor
Expand Down Expand Up @@ -3790,59 +3791,22 @@ class BrowserTabViewModelTest {
assertTrue(browserViewState().isEmailSignedIn)
}

@Test
fun whenEmailSignOutEventThenEmailSignEventCommandSent() = runTest {
emailStateFlow.emit(true)
emailStateFlow.emit(false)

assertCommandIssuedTimes<Command.EmailSignEvent>(2)
}

@Test
fun whenEmailIsSignedInThenEmailSignEventCommandSent() = runTest {
emailStateFlow.emit(true)

assertCommandIssued<Command.EmailSignEvent>()
}

@Test
fun whenConsumeAliasThenInjectAddressCommandSent() {
whenever(mockEmailManager.getAlias()).thenReturn("alias")

testee.usePrivateDuckAddress("", "alias")

assertCommandIssued<Command.InjectEmailAddress> {
assertEquals("alias", this.duckAddress)
}
}

@Test
fun whenUseAddressThenInjectAddressCommandSent() {
whenever(mockEmailManager.getEmailAddress()).thenReturn("address")

testee.usePersonalDuckAddress("", "address")

assertCommandIssued<Command.InjectEmailAddress> {
assertEquals("address", this.duckAddress)
}
}

@Test
fun whenShowEmailTooltipIfAddressExistsThenShowEmailTooltipCommandSent() {
whenever(mockEmailManager.getEmailAddress()).thenReturn("address")

testee.showEmailProtectionChooseEmailPrompt()
testee.showEmailProtectionChooseEmailPrompt(urlRequest())

assertCommandIssued<Command.ShowEmailProtectionChooseEmailPrompt> {
assertEquals("address", this.address)
assertEquals("address", this.duckAddress)
}
}

@Test
fun whenShowEmailTooltipIfAddressDoesNotExistThenCommandNotSent() {
whenever(mockEmailManager.getEmailAddress()).thenReturn(null)

testee.showEmailProtectionChooseEmailPrompt()
testee.showEmailProtectionChooseEmailPrompt(urlRequest())

assertCommandNotIssued<Command.ShowEmailProtectionChooseEmailPrompt>()
}
Expand Down Expand Up @@ -4443,16 +4407,6 @@ class BrowserTabViewModelTest {
assertShowHistoryCommandSent(expectedStackSize = 10)
}

@Test
fun whenReturnNoCredentialsWithPageThenEmitCancelIncomingAutofillRequestCommand() = runTest {
val url = "originalurl.com"
testee.returnNoCredentialsWithPage(url)

assertCommandIssued<Command.CancelIncomingAutofillRequest> {
assertEquals(url, this.url)
}
}

@Test
fun whenOnAutoconsentResultReceivedThenSiteUpdated() {
updateUrl("http://www.example.com/", "http://twitter.com/explore", true)
Expand Down Expand Up @@ -6039,6 +5993,8 @@ class BrowserTabViewModelTest {
}
}

private fun urlRequest() = AutofillWebMessageRequest("", "", "")

private fun givenLoginDetected(domain: String) = LoginDetected(authLoginDomain = "", forwardedToDomain = domain)

private fun givenCurrentSite(domain: String): Site {
Expand Down Expand Up @@ -6191,10 +6147,6 @@ class BrowserTabViewModelTest {
fun anyUri(): Uri = any()

class FakeCapabilityChecker(var enabled: Boolean) : AutofillCapabilityChecker {
override suspend fun isAutofillEnabledByConfiguration(url: String) = enabled
override suspend fun canInjectCredentialsToWebView(url: String) = enabled
override suspend fun canSaveCredentialsFromWebView(url: String) = enabled
override suspend fun canGeneratePasswordFromWebView(url: String) = enabled
override suspend fun canAccessCredentialManagementScreen() = enabled
override suspend fun canAccessCredentialManagementScreen(): Boolean = enabled
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ import com.duckduckgo.app.pixels.AppPixelName
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.app.statistics.pixels.Pixel.PixelParameter.LOADING_BAR_EXPERIMENT
import com.duckduckgo.autoconsent.api.Autoconsent
import com.duckduckgo.autofill.api.BrowserAutofill
import com.duckduckgo.autofill.api.InternalTestUserChecker
import com.duckduckgo.browser.api.JsInjectorPlugin
import com.duckduckgo.browser.api.WebViewVersionProvider
Expand Down Expand Up @@ -118,7 +117,6 @@ class BrowserWebViewClientTest {
private val trustedCertificateStore: TrustedCertificateStore = mock()
private val webViewHttpAuthStore: WebViewHttpAuthStore = mock()
private val thirdPartyCookieManager: ThirdPartyCookieManager = mock()
private val browserAutofillConfigurator: BrowserAutofill.Configurator = mock()
private val webResourceRequest: WebResourceRequest = mock()
private val webResourceError: WebResourceError = mock()
private val ampLinks: AmpLinks = mock()
Expand Down Expand Up @@ -156,7 +154,6 @@ class BrowserWebViewClientTest {
thirdPartyCookieManager,
TestScope(),
coroutinesTestRule.testDispatcherProvider,
browserAutofillConfigurator,
ampLinks,
printInjector,
internalTestUserChecker,
Expand Down Expand Up @@ -370,13 +367,6 @@ class BrowserWebViewClientTest {
verify(cookieManager).flush()
}

@UiThreadTest
@Test
fun whenOnPageStartedCalledThenInjectEmailAutofillJsCalled() {
testee.onPageStarted(webView, null, null)
verify(browserAutofillConfigurator).configureAutofillForCurrentPage(webView, null)
}

@UiThreadTest
@Test
fun whenShouldOverrideThrowsExceptionThenRecordException() {
Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit a043931

Please sign in to comment.