Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
For issue #3264 Add api for interacting with the tracking protection
Browse files Browse the repository at this point in the history
exceptions.
  • Loading branch information
Amejia481 committed Sep 26, 2019
1 parent 639f5c3 commit bb6b9c6
Show file tree
Hide file tree
Showing 16 changed files with 1,176 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import mozilla.components.concept.engine.EngineSessionState
import mozilla.components.concept.engine.EngineView
import mozilla.components.concept.engine.Settings
import mozilla.components.concept.engine.content.blocking.TrackerLog
import mozilla.components.concept.engine.content.blocking.TrackingProtectionExceptionStorage
import mozilla.components.concept.engine.history.HistoryTrackingDelegate
import mozilla.components.concept.engine.mediaquery.PreferredColorScheme
import mozilla.components.concept.engine.utils.EngineVersion
Expand All @@ -40,7 +41,9 @@ class GeckoEngine(
context: Context,
private val defaultSettings: Settings? = null,
private val runtime: GeckoRuntime = GeckoRuntime.getDefault(context),
executorProvider: () -> GeckoWebExecutor = { GeckoWebExecutor(runtime) }
executorProvider: () -> GeckoWebExecutor = { GeckoWebExecutor(runtime) },
override val trackingProtectionExceptionStore: TrackingProtectionExceptionStorage =
TrackingProtectionExceptionFileStorage(context, runtime)
) : Engine {
private val executor by lazy { executorProvider.invoke() }

Expand All @@ -56,6 +59,7 @@ class GeckoEngine(
@Suppress("TooGenericExceptionThrown")
throw RuntimeException("GeckoRuntime is shutting down")
}
trackingProtectionExceptionStore.restore()
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/* 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

import android.content.Context
import android.util.AtomicFile
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.content.blocking.TrackingProtectionExceptionStorage
import mozilla.components.support.ktx.util.readAndDeserialize
import mozilla.components.support.ktx.util.writeString
import org.mozilla.geckoview.GeckoRuntime
import java.io.File

private const val STORE_FILE_NAME_FORMAT =
"mozilla_components_tracking_protection_storage_gecko.json"

/**
* A [TrackingProtectionExceptionStorage] implementation to store tracking protection exceptions.
*/
internal class TrackingProtectionExceptionFileStorage(
private val context: Context,
private val runtime: GeckoRuntime
) : TrackingProtectionExceptionStorage {
private val fileLock = Any()
internal var scope = CoroutineScope(Dispatchers.IO)

/**
* Restore all exceptions from the [STORE_FILE_NAME_FORMAT] file,
* and provides them to the gecko [runtime].
*/
override fun restore() {
scope.launch {
synchronized(fileLock) {
getFile(context).readAndDeserialize { json ->
if (json.isNotEmpty()) {
val exceptionList = runtime.contentBlockingController.ExceptionList(json)
runtime.contentBlockingController.restoreExceptionList(exceptionList)
}
}
}
}
}

override fun contains(session: EngineSession, onFinish: (Boolean) -> Unit) {
val geckoSession = (session as GeckoEngineSession).geckoSession
runtime.contentBlockingController.checkException(geckoSession).accept {
if (it != null) {
onFinish(it)
} else {
onFinish(false)
}
}
}

override fun fetchAll(onFinish: (List<String>) -> Unit) {
runtime.contentBlockingController.saveExceptionList().accept { exceptionList ->
val exceptions = if (exceptionList != null) {
val uris = exceptionList.uris.map { uri ->
uri
}
uris
} else {
emptyList()
}
onFinish(exceptions)
}
}

override fun add(session: EngineSession) {
val geckoSession = (session as GeckoEngineSession).geckoSession
runtime.contentBlockingController.addException(geckoSession)
persist()
}

override fun remove(session: EngineSession) {
val geckoSession = (session as GeckoEngineSession).geckoSession
runtime.contentBlockingController.removeException(geckoSession)
persist()
}

override fun removeAll() {
runtime.contentBlockingController.clearExceptionList()
removeFileFromDisk(context)
}

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun getFile(context: Context): AtomicFile {
return AtomicFile(
File(
context.filesDir,
STORE_FILE_NAME_FORMAT
)
)
}

/**
* Take all the exception from the gecko [runtime] and saves them into the
* [STORE_FILE_NAME_FORMAT] file.
*/
private fun persist() {
runtime.contentBlockingController.saveExceptionList().accept { exceptionList ->
if (exceptionList != null) {
scope.launch {
synchronized(fileLock) {
getFile(context).writeString {
exceptionList.toJson().toString()
}
}
}
} else {
removeFileFromDisk(context)
}
}
}

private fun removeFileFromDisk(context: Context) {
scope.launch {
synchronized(fileLock) {
getFile(context)
.delete()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import mozilla.components.concept.engine.EngineSession.SafeBrowsingPolicy
import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.CookiePolicy
import mozilla.components.concept.engine.UnsupportedSettingException
import mozilla.components.concept.engine.content.blocking.TrackerLog
import mozilla.components.concept.engine.content.blocking.TrackingProtectionExceptionStorage
import mozilla.components.concept.engine.mediaquery.PreferredColorScheme
import mozilla.components.support.test.any
import mozilla.components.support.test.argumentCaptor
Expand Down Expand Up @@ -585,6 +586,15 @@ class GeckoEngineTest {
assertTrue(version.isAtLeast(69, 0, 0))
}

@Test
fun `after init is called the trackingProtectionExceptionStore must be restored`() {
val mockStore: TrackingProtectionExceptionStorage = mock()
val runtime: GeckoRuntime = mock()
GeckoEngine(context, runtime = runtime, trackingProtectionExceptionStore = mockStore)

verify(mockStore).restore()
}

private fun createDummyLogEntryList(): List<ContentBlockingController.LogEntry> {
val addLogEntry = object : ContentBlockingController.LogEntry() {}

Expand Down
Loading

0 comments on commit bb6b9c6

Please sign in to comment.