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 (mozilla-mobile#139)
  • Loading branch information
Amejia481 committed Nov 23, 2022
1 parent fd46276 commit a2dfa59
Show file tree
Hide file tree
Showing 4 changed files with 239 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 addException(
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,103 @@
/* 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.doNothing
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"

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

geckoStorage.addException(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"

doNothing().`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)

assertFalse(result)

Mockito.reset(geckoStorage)

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

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

assertTrue(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 addException(
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

0 comments on commit a2dfa59

Please sign in to comment.