TorBrowserFeatures.kt 4.02 KB
Newer Older
Alex Catarineu's avatar
Alex Catarineu committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/* 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/. */

// Copyright (c) 2020, The Tor Project, Inc.

package org.mozilla.fenix.components

import android.content.Context
import mozilla.components.concept.engine.webextension.WebExtension
import mozilla.components.concept.engine.webextension.WebExtensionRuntime
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.ext.settings
import java.io.IOException

object TorBrowserFeatures {
    private val logger = Logger("torbrowser-features")

    private fun installNoScript(
        context: Context,
        runtime: WebExtensionRuntime,
        onSuccess: ((WebExtension) -> Unit),
        onError: ((Throwable) -> Unit)
    ) {
        /**
         * Copy the xpi from assets to cacheDir, we do not care if the file is later deleted.
         */
        val addonPath =
            context.cacheDir.resolve("{73a6fe31-595d-460b-a920-fcc0f8843232}.xpi")
        try {
            context.assets.open("extensions/{73a6fe31-595d-460b-a920-fcc0f8843232}.xpi")
                .use { inStream ->
                    addonPath.outputStream().use { outStream ->
                        inStream.copyTo(outStream)
                    }
                }
        } catch (throwable: IOException) {
            onError(throwable)
            return
        }

        /**
         * Install with a file:// URI pointing to the temp location where the addon was copied to.
         */
        runtime.installWebExtension(
            id = "{73a6fe31-595d-460b-a920-fcc0f8843232}",
            url = addonPath.toURI().toString(),
            onSuccess = { extension ->
                runtime.setAllowedInPrivateBrowsing(
                    extension,
                    true,
                    onSuccess,
                    onError
                )
            },
            onError = { _, throwable -> onError(throwable) })
    }

    private fun installHTTPSEverywhere(
        runtime: WebExtensionRuntime,
        onSuccess: ((WebExtension) -> Unit),
        onError: ((Throwable) -> Unit)
    ) {
        runtime.installWebExtension(
            id = "https-everywhere-eff@eff.org",
            url = "resource://android/assets/extensions/https-everywhere/",
            onSuccess = onSuccess,
            onError = { _, throwable -> onError(throwable) }
        )
    }

    fun install(context: Context, runtime: WebExtensionRuntime) {
        /**
         * Install HTTPS Everywhere as a builtin addon, with a resource://android/ URI.
         * No signatures will be checked/required and there will be no automatic
         * extension updates. It's ok to always try to install, since for builtin extensions it will
         * be checked internally whether it is necessary to install or not: it will only be done
         * if this is the first time or if it's a newer version.
         */
        installHTTPSEverywhere(
            runtime,
            onSuccess = {
                logger.debug("HTTPS Everywhere extension was installed successfully")
            },
            onError = { throwable ->
                logger.error("Could not install HTTPS Everywhere extension", throwable)
            }
        )

        /**
         *  Install NoScript as a user WebExtension if we have not already done so.
         *  AMO signature is checked, and AMO automatic updates will work. The extension should
         *  behave as if the user had installed it manually.
         */
        if (!context.settings().noscriptInstalled) {
            installNoScript(
                context,
                runtime,
                onSuccess = {
                    context.settings().noscriptInstalled = true
                    logger.debug("NoScript extension was installed successfully")
                },
                onError = { throwable ->
                    logger.error("Could not install NoScript extension", throwable)
                }
            )
        }
    }
}