diff --git a/focus-android/app/src/androidTest/assets/cross-site-cookies.html b/focus-android/app/src/androidTest/assets/cross-site-cookies.html new file mode 100644 index 0000000000000000000000000000000000000000..5cf99f388117f36216df3fae57a9a23f59e41acc --- /dev/null +++ b/focus-android/app/src/androidTest/assets/cross-site-cookies.html @@ -0,0 +1,12 @@ +<!DOCTYPE HTML> +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<html> +<meta name="viewport" content="width=device-width"> +<body> +<h3>known-tracker.englehardt-tracker.com</h3> +<h4>different site, cross-origin iframe, on blocklist</h4> +<iframe width=500 height=600 src="https://known-tracker.englehardt-tracker.com/set_storage_simple.html"></iframe> +</body> +</html> diff --git a/focus-android/app/src/androidTest/assets/same-site-cookies.html b/focus-android/app/src/androidTest/assets/same-site-cookies.html new file mode 100644 index 0000000000000000000000000000000000000000..dd4fa31be78988823e5c4df15477c3bca525f035 --- /dev/null +++ b/focus-android/app/src/androidTest/assets/same-site-cookies.html @@ -0,0 +1,125 @@ +<!DOCTYPE HTML> +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<html lang="en-US" dir="ltr"> +<head> + <meta name="viewport" content="width=device-width"> + <script src="https://cdn.jsdelivr.net/npm/idb-keyval@3/dist/idb-keyval-iife.min.js"></script> +</head> +<body> +<button onclick="setAllStorageLocations();">Rerun Tests</button> +<br> +<h4>cookies</h4> +<pre id="cookie_message"></pre> + +<h4>localStorage</h4> +<pre id="ls_message"></pre> + +<!-- +<h4>sessionStorage</h4> +<pre id="ss_message"></pre> +<h4>Indexed DB</h4> +<pre id="idb_message"></pre> +--> + +<!-- Storage access API --> +<br /> +<h4>Storage Access API</h4> +<button onclick='requestSA()'>requestStorageAccess()</button><br /> +<p>Return value of requestStorageAccess():</p><pre id='request_storage_access'>not yet called</pre><br /> +<button onclick='hasSA()'>hasStorageAccess()</button><br /> +<p>Return value of hasStorageAccess():</p><pre id='has_storage_access'>not yet called</pre><br /> + + +<script> + var newRandVal = Math.random(); + + function outputResult(value, output_id) { + var msg = document.getElementById(output_id); + document.hasStorageAccess().then( + (hasStorageAccess) => { + if (hasStorageAccess === false) { + msg.innerHTML = "BLOCKED"; + } else if (value === "" & hasStorageAccess === true) { + msg.innerHTML = "UNEXPECTED. We have storage access but value is empty..."; + } else if (hasStorageAccess === true) { + msg.innerHTML = "UNRESTRICTED"; + } + }, + (reason) => {msg.innerHTML = 'promise rejected for reason' + reason} + ); + } + + function setCookies() { + var cookies = document.cookie; + if (cookies === "") { + document.cookie = 'foo='+newRandVal+'; SameSite=None; Secure'; + cookies = document.cookie; + } + outputResult(cookies, 'cookie_message'); + } + function setLocalStorage() { + try { + var foo = window.localStorage.getItem('foo'); + if (foo === null) { + window.localStorage.setItem('foo', newRandVal); + foo = window.localStorage.getItem('foo'); + } + } catch (error) { + foo = ""; + } + outputResult(foo, 'ls_message'); + } + function setSessionStorage() { + try { + var foo = window.sessionStorage.getItem('foo'); + if (foo === null) { + window.sessionStorage.setItem('foo', newRandVal); + foo = window.sessionStorage.getItem('foo'); + } + } catch (error) { + foo = ""; + } + outputResult(foo, 'ss_message'); + } + async function setIndexedDB() { + try { + var foo = await idbKeyval.get('foo'); + if (foo === undefined) { + await idbKeyval.set('foo', newRandVal); + foo = await idbKeyval.get('foo'); + } + } catch (error) { + foo = ""; + } + outputResult(foo, 'idb_message'); + } + function setAllStorageLocations() { + setCookies(); + setLocalStorage(); + //setSessionStorage(); + //setIndexedDB(); + } + setAllStorageLocations(); + + // Storage Access API + function requestSA() { + var result = document.getElementById('request_storage_access'); + document.requestStorageAccess().then( + () => {result.innerHTML = 'access granted'}, + () => {result.innerHTML = 'access denied'} + ); + } + + function hasSA() { + var result = document.getElementById('has_storage_access'); + document.hasStorageAccess().then( + (hasAccess) => {result.innerHTML = hasAccess}, + (reason) => {result.innerHTML = 'promise rejected for reason' + reason} + ); + } + hasSA(); + </script> +</body> +</html> diff --git a/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/SettingsPrivacyTest.kt b/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/SettingsPrivacyTest.kt index f37c9095107430586723f999e6ca5aabfff018f4..f313eef0479d40a1f26e9dbc5b5c0dbba16d897f 100644 --- a/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/SettingsPrivacyTest.kt +++ b/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/SettingsPrivacyTest.kt @@ -3,17 +3,22 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.focus.activity -import androidx.core.net.toUri import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner +import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mozilla.focus.activity.robots.homeScreen +import org.mozilla.focus.activity.robots.searchScreen import org.mozilla.focus.helpers.FeatureSettingsHelper import org.mozilla.focus.helpers.MainActivityFirstrunTestRule +import org.mozilla.focus.helpers.MockWebServerHelper import org.mozilla.focus.helpers.RetryTestRule +import org.mozilla.focus.helpers.TestAssetHelper.getStorageTestAsset +import org.mozilla.focus.helpers.TestHelper.exitToTop +import org.mozilla.focus.helpers.TestHelper.progressBar import org.mozilla.focus.helpers.TestHelper.waitingTime import org.mozilla.focus.testAnnotations.SmokeTest @@ -21,6 +26,7 @@ import org.mozilla.focus.testAnnotations.SmokeTest @RunWith(AndroidJUnit4ClassRunner::class) class SettingsPrivacyTest { private val featureSettingsHelper = FeatureSettingsHelper() + private lateinit var webServer: MockWebServer @get: Rule var mActivityTestRule = MainActivityFirstrunTestRule(showFirstRun = false) @@ -32,11 +38,17 @@ class SettingsPrivacyTest { @Before fun setup() { featureSettingsHelper.setCfrForTrackingProtectionEnabled(false) + featureSettingsHelper.setSearchWidgetDialogEnabled(false) + webServer = MockWebServer().apply { + dispatcher = MockWebServerHelper.AndroidAssetDispatcher() + start() + } } @After fun tearDown() { featureSettingsHelper.resetAllFeatureFlags() + webServer.shutdown() } @SmokeTest @@ -55,8 +67,9 @@ class SettingsPrivacyTest { @SmokeTest @Test - fun verifyCookiesEnabledTest() { - val cookiesEnabledURL = "https://www.whatismybrowser.com/detect/are-cookies-enabled" + fun verifyAllCookiesBlockedTest() { + val sameSiteCookiesUrl = getStorageTestAsset(webServer, "same-site-cookies.html").url + val thirdPartyCookiesUrl = getStorageTestAsset(webServer, "cross-site-cookies.html").url homeScreen { }.openMainMenu { @@ -64,30 +77,59 @@ class SettingsPrivacyTest { }.openPrivacySettingsMenu { clickBlockCookies() clickYesPleaseOption() - }.goBackToSettings { - }.goBackToHomeScreen { - }.loadPage(cookiesEnabledURL.toUri().toString()) { + exitToTop() + } + searchScreen { + }.loadPage(sameSiteCookiesUrl) { progressBar.waitUntilGone(waitingTime) - verifyCookiesEnabled("No") + verifyCookiesEnabled("BLOCKED") + }.clearBrowsingData { + }.openSearchBar { + }.loadPage(thirdPartyCookiesUrl) { + progressBar.waitUntilGone(waitingTime) + verifyCookiesEnabled("BLOCKED") } } @SmokeTest @Test - fun verify3rdPartyCookiesEnabledTest() { - val cookiesEnabledURL = "https://www.whatismybrowser.com/detect/are-third-party-cookies-enabled" + fun verify3rdPartyCookiesBlockedTest() { + val sameSiteCookiesUrl = getStorageTestAsset(webServer, "same-site-cookies.html").url + val thirdPartyCookiesURL = getStorageTestAsset(webServer, "cross-site-cookies.html").url homeScreen { }.openMainMenu { }.openSettings { }.openPrivacySettingsMenu { clickBlockCookies() - clickYesPleaseOption() + clickBlockThirdPartyCookiesOnly() }.goBackToSettings { }.goBackToHomeScreen { - }.loadPage(cookiesEnabledURL.toUri().toString()) { + }.loadPage(thirdPartyCookiesURL) { + progressBar.waitUntilGone(waitingTime) + verifyCookiesEnabled("BLOCKED") + }.clearBrowsingData { + }.openSearchBar { + }.loadPage(sameSiteCookiesUrl) { + progressBar.waitUntilGone(waitingTime) + verifyCookiesEnabled("UNRESTRICTED") + } + } + + @Test + fun verifyCrossSiteCookiesBlockedTest() { + val sameSiteCookiesUrl = getStorageTestAsset(webServer, "same-site-cookies.html").url + val crossSiteCookiesURL = getStorageTestAsset(webServer, "cross-site-cookies.html").url + + searchScreen { + }.loadPage(crossSiteCookiesURL) { + progressBar.waitUntilGone(waitingTime) + verifyCookiesEnabled("PARTITIONED") + }.clearBrowsingData { + }.openSearchBar { + }.loadPage(sameSiteCookiesUrl) { progressBar.waitUntilGone(waitingTime) - verifyCookiesEnabled("No") + verifyCookiesEnabled("UNRESTRICTED") } } } diff --git a/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/robots/BrowserRobot.kt b/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/robots/BrowserRobot.kt index 08e4c05bf470294917d66915d3ac4d20dbd522a2..fd58b086f417aa96590751314e792bc08556c3ae 100644 --- a/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/robots/BrowserRobot.kt +++ b/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/robots/BrowserRobot.kt @@ -395,10 +395,26 @@ class BrowserRobot { } fun verifyCookiesEnabled(areCookiesEnabled: String) { - mDevice.findObject(UiSelector().resourceId("detected_value")).waitForExists(waitingTime) - assertTrue( - webPageItemContainingText(areCookiesEnabled).waitForExists(waitingTime), - ) + for (i in 1..RETRY_COUNT) { + try { + assertTrue( + mDevice.findObject( + UiSelector() + .resourceId("cookie_message") + .childSelector( + UiSelector().textContains(areCookiesEnabled), + ), + ).waitForExists(waitingTime), + ) + break + } catch (e: AssertionError) { + if (i == RETRY_COUNT) { + throw e + } else { + refreshPageIfStillLoading(areCookiesEnabled) + } + } + } } fun clickSetCookiesButton() = clickPageObject(webPageItemWithResourceId("setCookies")) diff --git a/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/robots/SettingsPrivacyMenuRobot.kt b/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/robots/SettingsPrivacyMenuRobot.kt index 3e147c8d237f80e5ad68ba53d1d0df8d8c8eb855..7c549c4d36e9da9c9b5ec741993211664e194275 100644 --- a/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/robots/SettingsPrivacyMenuRobot.kt +++ b/focus-android/app/src/androidTest/java/org/mozilla/focus/activity/robots/SettingsPrivacyMenuRobot.kt @@ -217,6 +217,7 @@ class SettingsPrivacyMenuRobot { } fun clickYesPleaseOption() = blockCookiesYesPleaseOption.click() + fun clickBlockThirdPartyCookiesOnly() = block3rdPartyCookiesOnlyOption.click() fun switchSafeBrowsingToggle(): ViewInteraction = safeBrowsingSwitch().perform(click()) @@ -712,7 +713,7 @@ private val blockCookiesYesPleaseOption = private val block3rdPartyCookiesOnlyOption = mDevice.findObject( UiSelector() - .textContains(getStringResource(R.string.preference_privacy_should_block_cookies_yes_option2)), + .textContains(getStringResource(R.string.preference_privacy_should_block_cookies_third_party_only_option)), ) private val block3rdPartyTrackerCookiesOnlyOption =