10-tbb 13.3 KB
Newer Older
1
2
#!/bin/sh

3
4
set -e
set -u
5
6
7

echo "Install the Tor Browser"

8
9
10
11
12
13
14
# 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.
15
. /usr/local/lib/tails-shell-library/tor-browser.sh
16
17
# Import install_fake_package
. /usr/local/lib/tails-shell-library/build.sh
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

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} ..."
38
            curl --retry 20 --remote-name "${base_url}/${tarball}"
39
40
41
42
43
44
45
46
47
        )
        actual_sha256="$(sha256sum "${destination}/${tarball}" | cut -d' ' -f1)"
        if [ "${actual_sha256}" != "${expected_sha256}" ]; then
            echo "SHA256 mismatch for ${tarball}" >&2
            exit 1
        fi
    done
}

48
install_tor_browser() {
49
    local bundle destination tmp prep torlauncher_xpi_path torlauncher_version
50
51
52
53
    bundle="${1}"
    destination="${2}"

    tmp="$(mktemp -d)"
54
55
56
57
58
59
60
61
62
63
    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
64
65
66
67

    # 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.
68
    rm -f "${prep}"/dictionaries/*
69
    for f in /usr/share/hunspell/*.aff /usr/share/hunspell/*.dic; do
Tails developers's avatar
Tails developers committed
70
        ln -s "${f}" "${prep}"/dictionaries/
71
72
    done

intrigeri's avatar
intrigeri committed
73
74
    # Let's use the libstdc++ that the Tor Browser is intended to be used with,
    # instead of the system one.
75
76
77
78
    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.
79
80
    rm -r "${prep}"/TorBrowser/Tor "${prep}"/TorBrowser/Docs

81
    # We don't want tor-launcher to be part of the regular browser
82
83
84
    # 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"
85
    7z x -o"${TOR_LAUNCHER_INSTALL}" "${torlauncher_xpi_path}"
86
87
    torlauncher_version="$(sed -n \
        's,^        <em:version>\([0-9\.]\+\)</em:version>,\1,p' \
88
        "${TOR_LAUNCHER_INSTALL}/install.rdf")"
89
    SOURCE_DATE_YYYYMMDD=$(date --utc --date="@$SOURCE_DATE_EPOCH" '+%Y%m%d')
90
    cat > "${TOR_LAUNCHER_INSTALL}/application.ini" << EOF
91
92
93
94
[App]
Vendor=TorProject
Name=TorLauncher
Version=${torlauncher_version}
95
BuildID=${SOURCE_DATE_YYYYMMDD}
96
97
98
99
100
101
102
103
104
ID=tor-launcher@torproject.org

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

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

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

    mv "${prep}" "${destination}"
114
115
116
117

    rm -r "${tmp}"
}

intrigeri's avatar
intrigeri committed
118
# TBB works around the lack of code signing for its extensions by
119
120
# hacking in exceptions. We do the same!
apply_extension_code_signing_hacks () {
121
    local destination tmp tbb_timestamp
122
123
    destination="${1}"

124
125
126
127
    # 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)"

128
129
130
    tmp="$(mktemp -d)"
    (
        cd "${tmp}"
131
        7z x -tzip "${TBB_INSTALL}/omni.ja"
132
133
134
135
        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
136
@@ -282,7 +282,8 @@
137
138
139
140
141
142
143
144
145
146
147
148
   // 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
149
@@ -749,7 +749,8 @@
150
151
152
153
154
155
156
157
   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;
   }
158
159
160
161
162
163
164
165
166
 
@@ -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);
167
EOF
168
169
        touch --date="@${tbb_timestamp}" modules/addons/XPIProvider.jsm \
              chrome/toolkit/content/mozapps/extensions/extensions.js
170
171
172
173
174
175
176
177
        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"
178
179
180
181
        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
182
@@ -1137,7 +1137,8 @@
183
184
185
186
187
188
189
190
191
192
           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
193
        touch --date="@${tbb_timestamp}" components/nsBrowserGlue.js
194
195
        rm "${TBB_INSTALL}/browser/omni.ja"
        7z a -mtc=off -tzip "${TBB_INSTALL}/browser/omni.ja" *
196
    )
197
    rm -r "${tmp}"
198
199
}

200
201
202
203
# 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
anonym's avatar
anonym committed
204
# Enterprise features to run arbitrary JavaScript with access to the
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# 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");
221
222
223
224
225
226
if (engineName) {
    var engine = searchService.getEngineByName(engineName);
    if (engine) {
        searchService.currentEngine = engine;
    }
}
227
228
229
EOF
}

230
231
232
233
234
235
236
237
238
strip_nondeterminism () {
    local tbb_install
    tbb_install="${1}"
    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
}

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
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
}

258
259
260
261
262
263
264
265
get_firefox_version() {
    # The application.ini file
    local appini
    appini="${1}"
    sed -n 's/^Version=\(.*\)$/\1/p' "${appini}"
}

install_debian_extensions() {
266
267
    local destination
    destination="${1}"
268
    shift
269
    apt-get install --yes "${@}"
spriver's avatar
spriver committed
270
271
    ln -s /usr/share/xul-ext/ublock-origin/ \
          "${destination}"/'uBlock0@raymondhill.net'
272
273
}

274
create_default_profile() {
275
276
277
    local tbb_profile extensions_dir destination
    tbb_profile="${1}"
    tbb_extensions_dir="${2}"
278
279
280
    destination="${3}"

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

283
284
285
    # 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
286
287

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

Tails developers's avatar
Tails developers committed
293
TBB_SHA256SUMS_FILE=/usr/share/tails/tbb-sha256sums.txt
294
TBB_TARBALLS="$(grep "\<tor-browser-linux64-.*\.tar.xz$" "${TBB_SHA256SUMS_FILE}")"
295

Tails developers's avatar
Tails developers committed
296
297
# We'll use the en-US bundle as our basis; only langpacks will be
# installed from the other bundles.
298
299
300
301
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
intrigeri's avatar
intrigeri committed
302
    # containing all langpacks
303
304
305
    MAIN_TARBALL='tor-browser-linux64-tbb-nightly_ALL.tar.xz'
    NIGHTLY_BUILD=yes
fi
Tails developers's avatar
Tails developers committed
306
TBB_DIST_URL_FILE=/usr/share/tails/tbb-dist-url.txt
307
TBB_TARBALLS_BASE_URL="$(cat "${TBB_DIST_URL_FILE}")"
308

309
310
# The Debian Iceweasel extensions we want to install and make
# available in the Tor Browser.
spriver's avatar
spriver committed
311
DEBIAN_EXT_PKGS="xul-ext-ublock-origin"
312

313
TMP="$(mktemp -d)"
Tails developers's avatar
Tails developers committed
314
download_and_verify_files "${TBB_TARBALLS_BASE_URL}" "${TBB_TARBALLS}" "${TMP}"
315

Tails developers's avatar
Tails developers committed
316
install_tor_browser "${TMP}/${MAIN_TARBALL}" "${TBB_INSTALL}"
317
apply_extension_code_signing_hacks "${TBB_INSTALL}"
318
apply_default_searchengine_hacks "${TBB_INSTALL}"
319
strip_nondeterminism "${TBB_INSTALL}"
320

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

326
327
rm -r "${TMP}"

Tails developers's avatar
Tails developers committed
328
# Let's put all the extensions from TBB in the global extensions
329
# directory...
330
331
mv "${TBB_INSTALL}"/TorBrowser/Data/Browser/profile.default/extensions/* "${TBB_EXT}"
rmdir "${TBB_INSTALL}"/TorBrowser/Data/Browser/profile.default/extensions
332

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

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

343
344
345
346
# 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"

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

Tails developers's avatar
Tails developers committed
350
# Make the Tor Browser into the system's default web browser
351
352
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
353
sed 's/\<firefox-esr\.desktop\>/tor-browser.desktop/' \
354
355
356
    /usr/share/applications/gnome-mimeapps.list \
    > /etc/xdg/gnome-mimeapps.list
chmod 644 /etc/xdg/gnome-mimeapps.list