Wren Linux

wren-linux / extras / tor-browser.sh

#!/bin/bash
# Tor Browser as its own locked-down user, tor-browser, so a hacked page doesn't reach your
# files. It has no password or login, and its own home (/home/tor-browser), where the browser
# lives and updates itself through Tor.
#  - It opens inside cage, a tiny Wayland compositor shown as one window in your sway, with a
#    private X server: Tor Browser runs on X11 on purpose (less fingerprintable), and on X11 any
#    program can read every window and key. A restricted socket (bin/wayland-restrict) keeps it
#    from your screen.
#  - A firewall rule (data/tor-browser-firewall.nft) keeps it off this computer and your local
#    network. It doesn't force the browser through Tor: browser and Tor are one user, so a
#    hacked browser could go straight out and show your address. Whonix is what stops that.
#  - Nothing crosses by itself. A line of text goes through browser-sandbox clip (Super+Ctrl+b),
#    which shows it to you first; files through ~/Browsers/tor-browser.
#  - Debian's torbrowser-launcher is installed for the AppArmor profiles it brings, which confine
#    the browser and its Tor. The browser itself is the Tor Project's, checked against their key
#    (prep/fetch-tor-browser.sh): contrib is turned on for the launcher, and --remove turns it off
#    again if this script was what turned it on.
#  - Before its first start this writes a user.js into its profile: the Safest security level,
#    JavaScript off, and a bridge if you need one (it asks first, then offers obfs4, webtunnel,
#    Snowflake or meek), so its very first connection goes through it. Firefox applies user.js at
#    every start, so these come back after a restart even if changed in the browser; run this
#    again to change them.
#  - The Safest level is locked by Tor Browser's own policy file (Browser/distribution/
#    policies.json, from data/tor-browser-policies-safest.json): the shield's dialog and
#    about:config can't change it, and the browser's updater leaves the file in place. The lock
#    stops slips and pages, not code running as the tor-browser user. The javascript.* prefs
#    can't be locked that way, so user.js still turns JavaScript off (and sets the same level).
# /usr/bin/torbrowser-launcher, by its full path, still runs as you. A copy you already had there
# is left alone, and --remove asks about it.
# Usage: bash tor-browser.sh [--remove | --manual]
# summary: Tor Browser as its own user, with a bridge if needed
# security: most
# category: web
# status: file:/usr/local/bin/tor-browser apt:wren-tor-browser
# files: lib/browser-sandbox.sh bin/browser-sandbox bin/browser-session data/tor-browser-firewall.nft data/tor-browser-safest.js data/tor-browser-policies-safest.json prep/fetch-tor-browser.sh bin/no-abstract-sockets bin/wren-sandbox bin/wayland-restrict bin/sandbox-net-check
. "$(dirname -- "${BASH_SOURCE[0]}")/../lib.sh"
. "$WREN_DIR/lib/appimage.sh"
. "$WREN_DIR/lib/browser-sandbox.sh"
if [ "${1:-}" = --manual ]; then print_manual; exit; fi
need_user

MARK=/etc/apt/wren-enabled-contrib
CLASSIC=/etc/apt/sources.list

# Debian's own sources: classic lines in sources.list, deb822 stanzas in
# *.sources files that point at debian.org
deb822_files() {
    grep -ls 'debian\.org' /etc/apt/sources.list.d/*.sources 2>/dev/null || true
}

enable_contrib() {
    local changed=false f
    if [ -f "$CLASSIC" ] && grep -Eq '^deb(-src)?[[:space:]].*debian.*[[:space:]]main([[:space:]]|$)' "$CLASSIC" &&
        grep -E '^deb(-src)?[[:space:]].*debian' "$CLASSIC" | grep -vq '[[:space:]]contrib\b'; then
        sudo sed -i -E '/^deb(-src)?[[:space:]].*debian/ { /[[:space:]]contrib([[:space:]]|$)/! s/[[:space:]]main([[:space:]]|$)/ main contrib\1/ }' "$CLASSIC"
        changed=true
    fi
    for f in $(deb822_files); do
        if grep -q '^Components:' "$f" && grep '^Components:' "$f" | grep -vq '\bcontrib\b'; then
            sudo sed -i -E '/^Components:/ { /\bcontrib\b/! s/$/ contrib/ }' "$f"
            changed=true
        fi
    done
    if $changed; then
        sudo touch "$MARK"
        note "Turned on Debian's contrib section."
    else
        note "contrib is already on."
    fi
}

disable_contrib() {
    local f
    [ -e "$MARK" ] || { note "contrib was on before this script; leaving it."; return 0; }
    if [ -f "$CLASSIC" ]; then sudo sed -i -E 's/ main contrib([[:space:]]|$)/ main\1/' "$CLASSIC"; fi
    for f in $(deb822_files); do sudo sed -i -E '/^Components:/ s/ contrib\b//' "$f"; done
    sudo rm -f "$MARK"
    sudo apt-get update >/dev/null
    note "Turned Debian's contrib section off again."
}

NAME=tor-browser
# Where it lives. (Under /home, in the folder the launcher would use: that is where its AppArmor
# profile attaches. It isn't confined anywhere else.)
TB_BASE=/home/$NAME/.local/share/torbrowser/tbb/$(uname -m)
TBB=$TB_BASE/tor-browser
PROFILE=$TBB/Browser/TorBrowser/Data/Browser/profile.default
USERJS=$PROFILE/user.js
# A copy from before it had a user of its own, which ran as you
OLD_USERJS=$HOME/.local/share/torbrowser/tbb/$(uname -m)/tor-browser/Browser/TorBrowser/Data/Browser/profile.default/user.js
POLICIES_SRC=$WREN_DIR/data/tor-browser-policies-safest.json
TB_PREFS_SRC=$WREN_DIR/data/tor-browser-safest.js
TB_LEVEL_NOTES=("Tor Browser starts at the Safest level with JavaScript off. The level is locked:"
    "the shield's dialog and about:config can't change it (Tor Browser's own policy file).")
OFFLINE="$OFFLINE_DIR/torbrowser"

if [ "${1:-}" = --remove ]; then
    browser_remove "$NAME"
    sudo rm -f /usr/local/bin/torbrowser-launcher
    remove_wayland_restrict
    remove_no_abstract
    remove_sandbox_lib
    remove_net_check
    # The AppArmor fixes are shared with tor-browser-unsafe: only undo them if it is gone too
    # (browser_remove above already took this one's command out of /usr/local/bin)
    if ! tor_browser_sibling "$NAME"; then
        unfix_apparmor_browser
        unfix_apparmor_dns
        apt_purge torbrowser-launcher
    else
        note "tor-browser-unsafe is still installed, so Tor Browser's shared pieces stay."
    fi
    disable_contrib
    # The copy from before it had a user of its own
    if [ -d "$HOME/.local/share/torbrowser" ] &&
        ask "Also delete the older Tor Browser that ran as you, and its bookmarks (~/.local/share/torbrowser)?" n; then
        rm -rf "$HOME/.local/share/torbrowser" "$HOME/.cache/torbrowser" "$HOME/.config/torbrowser"
        note "Deleted."
    elif [ -f "$OLD_USERJS" ]; then
        sed -i "\|^$JS_BEGIN\$|,\|^$JS_END\$|d" "$OLD_USERJS"
        note "Took the Wren Linux settings out of $OLD_USERJS; that copy keeps their last values."
    fi
    exit
fi

say "Debian contrib section"
enable_contrib
# A fresh update, so apt sees the contrib packages
unset WREN_APT_UPDATED

say "Installing what it needs"
# torbrowser-launcher: the AppArmor profiles; cage, xwayland: its window and private X server;
# xclip, wl-clipboard: browser-sandbox clip; acl: sharing the socket and the folder; nftables,
# python3: the firewall and its check, wayland-restrict; the pipewire ones: its sound server, and
# pw-cat, the player of yours that reads its one pipe; xz-utils: unpacking it
need_xwayland
apt_install torbrowser-launcher xz-utils cage xclip wl-clipboard acl nftables python3 \
    pipewire-bin pipewire-pulse wireplumber
fix_apparmor_dns

say "The $NAME user"
browser_user "$NAME" "Wren Linux sandboxed Tor Browser"
fix_apparmor_browser
browser_files "$NAME"

say "The commands"
install_bin wayland-restrict
install_no_abstract
install_sandbox_lib
install_net_check
browser_commands "$NAME"
# By the name you may know it from: /usr/local/bin comes first
sudo ln -sfn browser-sandbox /usr/local/bin/torbrowser-launcher
browser_allow "$NAME"

say "Keeping $NAME off this computer and your network"
browser_firewall "$NAME"
browser_clip_key

say "Tor Browser"
install_browser

say "Tor Browser's security level and bridges"
prepare_profile
if [ -d "$HOME/.local/share/torbrowser/tbb" ]; then
    note "You also have a Tor Browser that runs as you, in ~/.local/share/torbrowser: left alone, and no"
    note "longer started by name. To keep its bookmarks, export them to a file there, and import that"
    note "from ~/Browsers/tor-browser."
fi
note "Run it with: tor-browser   (or Super+d)"
note "Text in or out: Super+Ctrl+b, which shows it first. Files: ~/Browsers/tor-browser."