#!/bin/sh
# The free names' browser for Linux: Mozilla's own Firefox, run apart from any other, with a profile of its own (dns.vm.bd).
#
#   free-names-browser [URL ...]    start it; the first time, for you, it takes Firefox from Mozilla (about a minute)
#   free-names-browser --forget     remove this user's Firefox and profile, and nothing else (apt remove does this for every user)
#
# This is what the package's menu entry and command run. The package puts only this program, the profile it starts from and a menu entry on
# the computer. The first time you start it, and as you, never as root:
#   1. it takes Mozilla's current Firefox for Linux from Mozilla and checks it against the SHA-256 Mozilla publishes beside it;
#   2. it unpacks it into ~/.local/share/free-names-browser/firefox, where it can update itself as Firefox does;
#   3. it makes the profile ~/.local/share/free-names-browser/profile from the one the package carries: the free names' root certificate in
#      the profile's own certificate database, and strict DNS over HTTPS to dns.vm.bd, and no other setting.
# It does NOT touch the system's trusted certificates, any other browser, any other Firefox profile, or your default browser. The root is
# trusted only inside this browser: anyone who holds the root's key could impersonate any site under the top-level domains it covers to
# this browser, until you remove the package. The root's SHA-256 fingerprint is 2D:4A:97:CD:93:CD:32:7C:7E:16:1B:2D:AC:3E:34:83:5C:67:84:42:44:B2:9A:71:6F:2B:17:11:ED:42:5C:95.
set -eu

BASE="${FREE_NAMES_HOME:-$HOME}"
APP="$BASE/.local/share/free-names-browser"
TEMPLATE="${FREE_NAMES_PROFILE:-/usr/share/free-names-browser/profile}"
URL="${FREE_NAMES_FIREFOX_URL:-https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=en-US}"

say() {
    echo "$1" >&2
    if command -v notify-send >/dev/null 2>&1; then notify-send "Free names browser" "$1" >/dev/null 2>&1 || true; fi
}

# A directory is made by this only when it is not there, and is written down so that forgetting takes away what was made and no more.
make_dir() {
    if [ ! -d "$1" ]; then
        make_dir "$(dirname "$1")"
        mkdir "$1"
        echo "$1" >> "$created"
    fi
}

forget() {
    if [ -f "$APP/.created" ]; then
        awk '{a[NR]=$0} END {for (i = NR; i > 0; i--) print a[i]}' "$APP/.created" > "${TMPDIR:-/tmp}/free-names-created.$$"
    fi
    rm -rf "$APP"
    if [ -f "${TMPDIR:-/tmp}/free-names-created.$$" ]; then
        while IFS= read -r directory; do rmdir "$directory" 2>/dev/null || true; done < "${TMPDIR:-/tmp}/free-names-created.$$"
        rm -f "${TMPDIR:-/tmp}/free-names-created.$$"
    fi
    echo "The free names browser and its profile are removed for $BASE."
}

fetch() {
    say "Setting up the free names browser: taking Firefox from Mozilla. This happens once."
    work=$(mktemp -d)
    created="$work/created"
    : > "$created"
    trap 'rm -rf "$work"' EXIT
    # The final address says which release this is, and Mozilla publishes that release's SHA-256 sums beside it.
    final=$(curl -fsSIL -o /dev/null -w '%{url_effective}' "$URL")
    release=${final%/linux-x86_64/*}
    name=${final#"$release"/}
    curl -fsSL -o "$work/firefox.tar.xz" "$final"
    curl -fsSL -o "$work/SHA256SUMS" "$release/SHA256SUMS"
    want=$(grep " $name\$" "$work/SHA256SUMS" | awk '{print $1}')
    got=$(sha256sum "$work/firefox.tar.xz" | awk '{print $1}')
    if [ -z "$want" ] || [ "$want" != "$got" ]; then
        say "The download is not what Mozilla publishes (wanted '$want', got '$got'). Nothing was installed."
        exit 1
    fi
    if [ -e "$APP" ]; then forget >/dev/null; fi
    make_dir "$APP/profile"
    cp "$created" "$APP/.created"
    mkdir "$APP/unpacking"
    tar -xJf "$work/firefox.tar.xz" -C "$APP/unpacking"
    mv "$APP/unpacking/firefox" "$APP/firefox"
    rmdir "$APP/unpacking"
    cp "$TEMPLATE"/cert9.db "$TEMPLATE"/key4.db "$TEMPLATE"/user.js "$APP/profile/"
    chmod 600 "$APP/profile/cert9.db" "$APP/profile/key4.db"
    # Started with `exec` next, which runs no exit trap, so the download is taken away here.
    rm -rf "$work"
    trap - EXIT
}

case "${1:-}" in
    --forget) forget ;;
    *)
        if [ ! -x "$APP/firefox/firefox" ] || [ ! -f "$APP/profile/cert9.db" ]; then fetch; fi
        exec "$APP/firefox/firefox" -profile "$APP/profile" -no-remote "$@"
        ;;
esac
