Skip to content

Commit

Permalink
Bug 1797605 - Add API support for ignoring sites for cookie banner ha…
Browse files Browse the repository at this point in the history
…ndling
  • Loading branch information
Amejia481 committed Nov 23, 2022
1 parent 4c569b4 commit c216781
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 0 deletions.
@@ -0,0 +1,86 @@
/* 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/. */

package mozilla.components.browser.engine.gecko.cookiebanners

import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import mozilla.components.browser.engine.gecko.await
import mozilla.components.concept.engine.EngineSession.CookieBannerHandlingMode
import mozilla.components.concept.engine.EngineSession.CookieBannerHandlingMode.DISABLED
import mozilla.components.concept.engine.cookiehandling.CookieBannersStorage
import org.mozilla.geckoview.GeckoRuntime
import org.mozilla.geckoview.StorageController

/**
* A storage to store [CookieBannerHandlingMode] using GeckoView APIs.
*/
class GeckoCookieBannersStorage(
runtime: GeckoRuntime,
) : CookieBannersStorage {

private val geckoStorage: StorageController = runtime.storageController
private val mainScope = CoroutineScope(Dispatchers.Main)

override suspend fun adException(
uri: String,
privateBrowsing: Boolean,
) {
setGeckoException(uri, DISABLED, privateBrowsing)
}

override suspend fun findExceptionFor(
uri: String,
privateBrowsing: Boolean,
): CookieBannerHandlingMode {
return queryExceptionInGecko(uri, privateBrowsing)
}

override suspend fun hasException(uri: String, privateBrowsing: Boolean): Boolean {
return findExceptionFor(uri, privateBrowsing) == DISABLED
}

override suspend fun removeException(uri: String, privateBrowsing: Boolean) {
removeGeckoException(uri, privateBrowsing)
}

@VisibleForTesting
internal fun removeGeckoException(uri: String, privateBrowsing: Boolean) {
geckoStorage.removeCookieBannerModeForDomain(uri, privateBrowsing)
}

@VisibleForTesting
internal fun setGeckoException(
uri: String,
mode: CookieBannerHandlingMode,
privateBrowsing: Boolean,
) {
geckoStorage.setCookieBannerModeForDomain(
uri,
mode.mode,
privateBrowsing,
)
}

@VisibleForTesting
internal suspend fun queryExceptionInGecko(
uri: String,
privateBrowsing: Boolean,
): CookieBannerHandlingMode {
return withContext(mainScope.coroutineContext) {
geckoStorage.getCookieBannerModeForDomain(uri, privateBrowsing).await()
?.toCookieBannerHandlingMode() ?: throw IllegalArgumentException(
"An error happened trying to find cookie banners mode for the " +
"uri $uri and private browsing mode $privateBrowsing",
)
}
}
}

@VisibleForTesting
internal fun Int.toCookieBannerHandlingMode(): CookieBannerHandlingMode {
return CookieBannerHandlingMode.values().first { it.mode == this }
}
@@ -0,0 +1,102 @@
/* 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/. */

package mozilla.components.browser.engine.gecko.cookiebanners

import androidx.test.ext.junit.runners.AndroidJUnit4
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertFalse
import junit.framework.TestCase.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import mozilla.components.concept.engine.EngineSession.CookieBannerHandlingMode.DISABLED
import mozilla.components.concept.engine.EngineSession.CookieBannerHandlingMode.REJECT_OR_ACCEPT_ALL
import mozilla.components.support.test.mock
import mozilla.components.support.test.whenever
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mozilla.geckoview.GeckoRuntime
import org.mozilla.geckoview.StorageController

@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
class GeckoCookieBannersStorageTest {
private lateinit var runtime: GeckoRuntime
private lateinit var geckoStorage: GeckoCookieBannersStorage
private lateinit var storageController: StorageController

@Before
fun setup() {
storageController = mock()
runtime = mock()

whenever(runtime.storageController).thenReturn(storageController)

geckoStorage = spy(GeckoCookieBannersStorage(runtime))
}

@Test
fun `GIVEN a cookie banner mode WHEN adding an exception THEN add an exception for the given uri and browsing mode`() =
runTest {
val uri = "https://www.mozilla.org"

doReturn(Unit).`when`(geckoStorage)
.setGeckoException(uri = uri, mode = DISABLED, privateBrowsing = false)

geckoStorage.adException(uri = uri, privateBrowsing = false)

verify(geckoStorage).setGeckoException(uri, DISABLED, false)
}

@Test
fun `GIVEN uri and browsing mode WHEN removing an exception THEN remove the exception`() =
runTest {
val uri = "https://www.mozilla.org"

doReturn(Unit).`when`(geckoStorage).removeGeckoException(uri, false)

geckoStorage.removeException(uri = uri, privateBrowsing = false)

verify(geckoStorage).removeGeckoException(uri, false)
}

@Test
fun `GIVEN uri and browsing mode WHEN querying an exception THEN return the matching exception`() =
runTest {
val uri = "https://www.mozilla.org"

doReturn(REJECT_OR_ACCEPT_ALL).`when`(geckoStorage)
.queryExceptionInGecko(uri = uri, privateBrowsing = false)

val result = geckoStorage.findExceptionFor(uri = uri, privateBrowsing = false)
assertEquals(REJECT_OR_ACCEPT_ALL, result)
}

@Test
fun `GIVEN uri and browsing mode WHEN checking for an exception THEN indicate if it has exceptions`() =
runTest {
val uri = "https://www.mozilla.org"

doReturn(REJECT_OR_ACCEPT_ALL).`when`(geckoStorage)
.queryExceptionInGecko(uri = uri, privateBrowsing = false)

var result = geckoStorage.hasException(uri = uri, privateBrowsing = false)

assertTrue(result)

Mockito.reset(geckoStorage)

doReturn(DISABLED).`when`(geckoStorage)
.queryExceptionInGecko(uri = uri, privateBrowsing = false)

result = geckoStorage.hasException(uri = uri, privateBrowsing = false)

assertFalse(result)
}
}
@@ -0,0 +1,47 @@
/* 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/. */

package mozilla.components.concept.engine.cookiehandling

import mozilla.components.concept.engine.EngineSession.CookieBannerHandlingMode

/**
* Represents a storage to manage [CookieBannerHandlingMode] exceptions.
*/
interface CookieBannersStorage {
/**
* Set the [CookieBannerHandlingMode.DISABLED] mode for the given [uri] and [privateBrowsing].
* @param uri the [uri] for the site to be updated.
* @param privateBrowsing Indicates if given [uri] should be in private browsing or not.
*/
suspend fun adException(
uri: String,
privateBrowsing: Boolean,
)

/**
* Find a [CookieBannerHandlingMode] that matches the given [uri] and browsing mode.
* @param uri the [uri] to be used as filter in the search.
* @param privateBrowsing Indicates if given [uri] should be in private browsing or not.
* @return the [CookieBannerHandlingMode] for the provided [uri] and browsing mode.
*/
suspend fun findExceptionFor(uri: String, privateBrowsing: Boolean): CookieBannerHandlingMode

/**
* Indicates if the given [uri] and browsing mode has the [CookieBannerHandlingMode.DISABLED] mode.
* @param uri the [uri] to be used as filter in the search.
* @param privateBrowsing Indicates if given [uri] should be in private browsing or not.
* @return A [Boolean] indicating if the [CookieBannerHandlingMode] has been updated, from the
* default value.
*/
suspend fun hasException(uri: String, privateBrowsing: Boolean): Boolean

/**
* Remove any [CookieBannerHandlingMode] exception that has been applied to the given [uri] and
* browsing mode.
* @param uri the [uri] to be used as filter in the search.
* @param privateBrowsing Indicates if given [uri] should be in private browsing or not.
*/
suspend fun removeException(uri: String, privateBrowsing: Boolean)
}
3 changes: 3 additions & 0 deletions docs/changelog.md
Expand Up @@ -25,6 +25,9 @@ permalink: /changelog/
* **support-ktx**:
* Added `String.toShortUrl` extension that allows making URLs more user friendly [#1796379](https://bugzilla.mozilla.org/show_bug.cgi?id=1796379)

* **browser-engine-gecko**
* 🆕 Added `GeckoCookieBannersStorage.kt` to manage cookie banner exceptions [bug #1797605](https://bugzilla.mozilla.org/show_bug.cgi?id=1797605).

# 108.0.0
* [Commits](https://github.com/mozilla-mobile/firefox-android/compare/v107.0.0...v108.0.0)
* [Dependencies](https://github.com/mozilla-mobile/firefox-android/blob/v108.0.0/android-components/buildSrc/src/main/java/Dependencies.kt)
Expand Down

2 comments on commit c216781

@firefoxci-taskcluster
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh oh! Looks like an error! Details

Failed to fetch task artifact public/github/customCheckRunText.md for GitHub integration.
Make sure the artifact exists on the worker or other location.

@firefoxci-taskcluster
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh oh! Looks like an error! Details

Failed to fetch task artifact public/github/customCheckRunText.md for GitHub integration.
Make sure the artifact exists on the worker or other location.

Please sign in to comment.