summaryrefslogtreecommitdiffstats
path: root/config/chroot_local-hooks/10-tbb
blob: 71532516a803988701762c92557b465f76a3853d (plain)
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#!/bin/sh

set -e
set -u

echo "Install the Tor Browser"

# Import the TBB_INSTALL, TBB_PROFILE, TBB_EXT and
# TOR_LAUNCHER_INSTALL variables, which contains the paths we will
# split TBB's actual browser (binaries etc), user data and extension
# into. While this differs from how the TBB organizes the files, the
# end result will be the same, and it's practical since when creating
# a new browser profile we can simply copy the profile directory
# without duplicating all extensions.
. /usr/local/lib/tails-shell-library/tor-browser.sh
# Import install_fake_package
. /usr/local/lib/tails-shell-library/build.sh

download_and_verify_files() {
    local base_url bundles destination apt_proxy
    base_url="${1}"
    bundles="${2}"
    destination="${3}"

    # Use the builder's caching APT proxy, if any
    apt_proxy="$(apt-config --format '%v' dump Acquire::http::Proxy)"
    if [ -n "${apt_proxy}" ]; then
        export HTTP_PROXY="${apt_proxy}"
        export http_proxy="${apt_proxy}"
        export HTTPS_PROXY="${apt_proxy}"
        export https_proxy="${apt_proxy}"
    fi

    echo "${bundles}" | while read expected_sha256 tarball; do
        (
            cd "${destination}"
            echo "Fetching ${base_url}/${tarball} ..."
            curl --retry 20 --remote-name "${base_url}/${tarball}"
        )
        actual_sha256="$(sha256sum "${destination}/${tarball}" | cut -d' ' -f1)"
        if [ "${actual_sha256}" != "${expected_sha256}" ]; then
            echo "SHA256 mismatch for ${tarball}" >&2
            exit 1
        fi
    done
}

install_tor_browser() {
    local bundle destination tmp prep torlauncher_xpi_path torlauncher_version
    bundle="${1}"
    destination="${2}"

    tmp="$(mktemp -d)"
    tar -xf "${bundle}" -C "${tmp}"
    if [ -d "${tmp}"/tor-browser_en-US ]; then
        prep="${tmp}"/tor-browser_en-US/Browser
    elif [ -d "${tmp}"/tor-browser ]; then
        # TBB nightly builds
        prep="${tmp}"/tor-browser/Browser
    else
        echo "The main bundle's top level directory is wrong" >&2
        exit 1
    fi

    # Enable our myspell/hunspell dictionaries. TBB only provides the
    # one for en-US, but Debian's seems more comprehensive, so we'll
    # only use Debian's dictionaries.
    rm -f "${prep}"/dictionaries/*
    for f in /usr/share/hunspell/*.aff /usr/share/hunspell/*.dic; do
        ln -s "${f}" "${prep}"/dictionaries/
    done

    # Let's use the libstdc++ that the Tor Browser is intended to be used with,
    # instead of the system one.
    cp "${prep}"/TorBrowser/Tor/libstdc++.so.6 "${prep}"

    # We don't need the Tor binary, the shared libraries Tor needs
    # (but Firefox doesn't) and documentation shipped in the TBB.
    rm -r "${prep}"/TorBrowser/Tor "${prep}"/TorBrowser/Docs

    # We don't want tor-launcher to be part of the regular browser
    # profile but we want to keep it as a standalone application
    # when Tails is started in "bridge mode".
    torlauncher_xpi_path="${prep}/TorBrowser/Data/Browser/profile.default/extensions/tor-launcher@torproject.org.xpi"
    7z x -o"${TOR_LAUNCHER_INSTALL}" "${torlauncher_xpi_path}"
    torlauncher_version="$(sed -n \
        's,^        <em:version>\([0-9\.]\+\)</em:version>,\1,p' \
        "${TOR_LAUNCHER_INSTALL}/install.rdf")"
    SOURCE_DATE_YYYYMMDD=$(date --utc --date="@$SOURCE_DATE_EPOCH" '+%Y%m%d')
    cat > "${TOR_LAUNCHER_INSTALL}/application.ini" << EOF
[App]
Vendor=TorProject
Name=TorLauncher
Version=${torlauncher_version}
BuildID=${SOURCE_DATE_YYYYMMDD}
ID=tor-launcher@torproject.org

[Gecko]
MinVersion=$(get_firefox_version "${prep}/application.ini")
MaxVersion=*.*.*

[Shell]
Icon=icon.png
EOF
    chmod -R a+rX "${TOR_LAUNCHER_INSTALL}"
    rm "${torlauncher_xpi_path}"

    # The Tor Browser will fail, complaining about an incomplete profile,
    # unless there's a readable TorBrowser/Data/Browser/Caches
    # in the directory where the firefox executable is located.
    mkdir -p "${prep}"/TorBrowser/Data/Browser/Caches

    mv "${prep}" "${destination}"

    rm -r "${tmp}"
}

# TBB works around the lack of code signing for its extensions by
# hacking in exceptions. We do the same!
apply_extension_code_signing_hacks () {
    local destination tmp tbb_timestamp
    destination="${1}"

    # For consistency we'll set timestamps of files we modify to the
    # same one used by the Tor Browser instead of SOURCE_DATE_EPOCH.
    tbb_timestamp="$(date --date='2000-01-01 00:00:00' +%s)"

    tmp="$(mktemp -d)"
    (
        cd "${tmp}"
        7z x -tzip "${TBB_INSTALL}/omni.ja"
        patch -p1 <<EOF
diff -Naur a/chrome/toolkit/content/mozapps/extensions/extensions.js b/chrome/toolkit/content/mozapps/extensions/extensions.js
--- a/chrome/toolkit/content/mozapps/extensions/extensions.js 2000-01-01 00:00:00.000000000 +0000
+++ b/chrome/toolkit/content/mozapps/extensions/extensions.js 2000-01-01 00:00:00.000000000 +0000
@@ -282,7 +282,8 @@
   // they aren't the correct type for signing.
   if (aAddon.id == "torbutton@torproject.org" ||
       aAddon.id == "tor-launcher@torproject.org" ||
-      aAddon.id == "https-everywhere-eff@eff.org") {
+      aAddon.id == "https-everywhere-eff@eff.org" ||
+      aAddon.id == "uBlock0@raymondhill.net") {
     return true;
   }
   return aAddon.isCorrectlySigned !== false;
diff -Naur a/modules/addons/XPIProvider.jsm b/modules/addons/XPIProvider.jsm
--- a/modules/addons/XPIProvider.jsm 2000-01-01 00:00:00.000000000 +0000
+++ b/modules/addons/XPIProvider.jsm 2000-01-01 00:00:00.000000000 +0000
@@ -749,7 +749,8 @@
   if (aAddon.id == "torbutton@torproject.org" ||
       aAddon.id == "tor-launcher@torproject.org" ||
       aAddon.id == "https-everywhere-eff@eff.org" ||
-      aAddon.id == "meek-http-helper@bamsoftware.com") {
+      aAddon.id == "meek-http-helper@bamsoftware.com" ||
+      aAddon.id == "uBlock0@raymondhill.net") {
     return true;
   }
 
@@ -3465,6 +3466,7 @@
             addon.id != "tor-launcher@torproject.org" &&
             addon.id != "https-everywhere-eff@eff.org" &&
             addon.id != "meek-http-helper@bamsoftware.com" &&
+            addon.id != "uBlock0@raymondhill.net" &&
             addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) {
           logger.warn("Refusing to install staged add-on " + id + " with signed state " + addon.signedState);
           seenFiles.push(stageDirEntry.leafName);
EOF
        touch --date="@${tbb_timestamp}" modules/addons/XPIProvider.jsm \
              chrome/toolkit/content/mozapps/extensions/extensions.js
        rm "${TBB_INSTALL}/omni.ja"
        7z a -mtc=off -tzip "${TBB_INSTALL}/omni.ja" *
    )
    rm -r "${tmp}"
    tmp="$(mktemp -d)"
    (
        cd "${tmp}"
        7z x -tzip "${TBB_INSTALL}/browser/omni.ja"
        patch -p1 <<EOF
diff -Naur x/components/nsBrowserGlue.js y/components/nsBrowserGlue.js
--- a/components/nsBrowserGlue.js 2000-01-01 00:00:00.000000000 +0000
+++ b/components/nsBrowserGlue.js 2000-01-01 00:00:00.000000000 +0000
@@ -1137,7 +1137,8 @@
           if ((addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) &&
               !(addon.id == "torbutton@torproject.org" ||
                 addon.id == "tor-launcher@torproject.org" ||
-                addon.id == "https-everywhere-eff@eff.org")) {
+                addon.id == "https-everywhere-eff@eff.org" ||
+                addon.id == "uBlock0@raymondhill.net")) {
             this._notifyUnsignedAddonsDisabled();
             break;
           }
EOF
        touch --date="@${tbb_timestamp}" components/nsBrowserGlue.js
        rm "${TBB_INSTALL}/browser/omni.ja"
        7z a -mtc=off -tzip "${TBB_INSTALL}/browser/omni.ja" *
    )
    rm -r "${tmp}"
    for archive in "${TBB_INSTALL}/omni.ja" "${TBB_INSTALL}/browser/omni.ja"; do
        strip_nondeterminism_wrapper --type zip --timestamp "${tbb_timestamp}" \
                                     "${archive}" 2>/dev/null
    done
}

# Modern Firefox doesn't apply browser.search.defaultenginename on
# start, and the other ways to get it to work (e.g. pre-generating
# search.json.mozlz4) seems rather complex. Instead, let's just make
# browser.search.defaultenginename work again by employing some
# Enterprise features to run arbitrary JavaScript with access to the
# Firefox internals. For the details of this feature, see:
# https://developer.mozilla.org/en-US/Firefox/Enterprise_deployment
apply_default_searchengine_hacks () {
    local destination
    destination="${1}"

    cat > "${destination}/defaults/pref/autoconfig.js" <<EOF
// This file must start with a comment
pref("general.config.filename", "mozilla.cfg");
pref("general.config.obscure_value", 0);
EOF

    cat > "${destination}/mozilla.cfg" <<EOF
// This file must start with a comment
var searchService = Components.classes["@mozilla.org/browser/search-service;1"].getService(Components.interfaces.nsIBrowserSearchService);
var engineName = getPref("browser.search.defaultenginename");
if (engineName) {
    var engine = searchService.getEngineByName(engineName);
    if (engine) {
        searchService.currentEngine = engine;
    }
}
EOF
}

install_langpacks_from_bundles() {
    local bundles_dir destination
    bundles_dir="${1}"
    destination="${2}"

    for tarball in "${bundles_dir}"/tor-browser-*.tar.xz; do
        locale="$(echo "${tarball}" | sed "s@^.*/tor-browser-.*_\(.*\)\.tar\.xz@\1@")"
        if [ "${locale}" = en-US ]; then
            continue
        fi
        xpi="tor-browser_${locale}/Browser/TorBrowser/Data/Browser/profile.default/extensions/langpack-${locale}@firefox.mozilla.org.xpi"
        (
            cd "${bundles_dir}"
            tar -xf "${tarball}" "${xpi}"
            mv "${xpi}" "${destination}"
        )
    done
}

get_firefox_version() {
    # The application.ini file
    local appini
    appini="${1}"
    sed -n 's/^Version=\(.*\)$/\1/p' "${appini}"
}

install_debian_extensions() {
    local destination
    destination="${1}"
    shift
    apt-get install --yes "${@}"
    ln -s /usr/share/xul-ext/ublock-origin/ \
          "${destination}"/'uBlock0@raymondhill.net'
}

create_default_profile() {
    local tbb_profile extensions_dir destination
    tbb_profile="${1}"
    tbb_extensions_dir="${2}"
    destination="${3}"

    rsync -a --exclude bookmarks.html --exclude extensions \
          "${tbb_profile}"/ "${destination}"/

    # Remove TBB's Tor Launcher settings since we don't enable it in
    # our Tor Browser.
    sed -i '/extensions\.torlauncher\./d' "${destination}"/preferences/extension-overrides.js

    mkdir -p "${destination}"/extensions
    for ext in "${tbb_extensions_dir}"/*; do
        ln -s "${ext}" "${destination}"/extensions/
    done
}

TBB_SHA256SUMS_FILE=/usr/share/tails/tbb-sha256sums.txt
TBB_TARBALLS="$(grep "\<tor-browser-linux64-.*\.tar.xz$" "${TBB_SHA256SUMS_FILE}")"

# We'll use the en-US bundle as our basis; only langpacks will be
# installed from the other bundles.
MAIN_TARBALL="$(echo "${TBB_TARBALLS}" | grep -o "tor-browser-linux64-.*_en-US.tar.xz" || :)"
NIGHTLY_BUILD=
if [ -z "${MAIN_TARBALL}" ] && [ "$(echo $TBB_TARBALLS | awk '{ print $2 }')" = 'tor-browser-linux64-tbb-nightly_ALL.tar.xz' ]; then
    # Except for TBB nightly builds; then there is only one bundle
    # containing all langpacks
    MAIN_TARBALL='tor-browser-linux64-tbb-nightly_ALL.tar.xz'
    NIGHTLY_BUILD=yes
fi
TBB_DIST_URL_FILE=/usr/share/tails/tbb-dist-url.txt
TBB_TARBALLS_BASE_URL="$(cat "${TBB_DIST_URL_FILE}")"

# The Debian Iceweasel extensions we want to install and make
# available in the Tor Browser.
DEBIAN_EXT_PKGS="xul-ext-ublock-origin"

TMP="$(mktemp -d)"
download_and_verify_files "${TBB_TARBALLS_BASE_URL}" "${TBB_TARBALLS}" "${TMP}"

install_tor_browser "${TMP}/${MAIN_TARBALL}" "${TBB_INSTALL}"
apply_extension_code_signing_hacks "${TBB_INSTALL}"
apply_default_searchengine_hacks "${TBB_INSTALL}"

mkdir -p "${TBB_EXT}"
if [ "${NIGHTLY_BUILD}" != yes ]; then
    install_langpacks_from_bundles "${TMP}" "${TBB_EXT}"
fi

rm -r "${TMP}"

# Let's put all the extensions from TBB in the global extensions
# directory...
mv "${TBB_INSTALL}"/TorBrowser/Data/Browser/profile.default/extensions/* "${TBB_EXT}"
rmdir "${TBB_INSTALL}"/TorBrowser/Data/Browser/profile.default/extensions

# ... and then install a few Iceweasel extension by using a fake
# Iceweasel equivs package to satisfy the dependencies.
FIREFOX_VERSION=$(get_firefox_version "${TBB_INSTALL}"/application.ini)
FAKE_ICEWEASEL_VERSION=${FIREFOX_VERSION}+fake1
install_fake_package iceweasel "${FAKE_ICEWEASEL_VERSION}" web
install_debian_extensions "${TBB_EXT}" ${DEBIAN_EXT_PKGS}

mkdir -p "${TBB_PROFILE}"
create_default_profile "${TBB_INSTALL}"/TorBrowser/Data/Browser/profile.default "${TBB_EXT}" "${TBB_PROFILE}"

# Create a copy of the Firefox binary, for use e.g. by Tor Launcher.
# It won't be subject to AppArmor confinement.
cp -a "${TBB_INSTALL}/firefox" "${TBB_INSTALL}/firefox-unconfined"

chown -R root:root "${TBB_INSTALL}" "${TBB_PROFILE}" "${TBB_EXT}"
chmod -R a+rX "${TBB_INSTALL}" "${TBB_PROFILE}" "${TBB_EXT}"

# Make the Tor Browser into the system's default web browser
update-alternatives --install /usr/bin/x-www-browser x-www-browser /usr/local/bin/tor-browser 99
update-alternatives --install /usr/bin/gnome-www-browser gnome-www-browser /usr/local/bin/tor-browser 99
sed 's/\<firefox-esr\.desktop\>/tor-browser.desktop/' \
    /usr/share/applications/gnome-mimeapps.list \
    > /etc/xdg/gnome-mimeapps.list
chmod 644 /etc/xdg/gnome-mimeapps.list