Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/desktop/extensions/ai-sidebar/sidepanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,10 +320,10 @@ async function togglePit() {
const trust = res && res.trust;
const httpsTip = !trust
? ''
: trust.available && trust.relaunch
? '<code>https://</code> on a pit name: the first visit records its key (when the registry publishes a matching pin), and it loads after the next TronBrowser restart — this engine only takes pins at start.'
: trust.available
? '<code>https://</code> on a pit name is trusted per name on first use, when the registry publishes its pin.'
: trust.available
? '<code>https://</code> on a pit name is trusted per name on first use, when the registry publishes its pin.'
: trust.why === 'flatpak-engine'
? 'This TronBrowser is running the Flatpak Chromium, which ignores per-name trust, so <code>https://</code> on a pit name will warn. Run <code>tron upgrade</code> to get TronBrowser’s own engine, then relaunch.'
: trust.why === 'no-certutil'
? '<code>https://</code> on a pit name will warn until <code>certutil</code> is installed (Debian/Ubuntu: <code>libnss3-tools</code>, Fedora: <code>nss-tools</code>, Arch: <code>nss</code>).'
: '<code>https://</code> on a pit name will warn on this platform; run <code>moshcode dns enable</code> for the certificate.';
Expand Down
35 changes: 8 additions & 27 deletions apps/desktop/launcher/tron-tor-helper
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ BUNDLED_DIR = os.environ.get("TRON_TOR_BIN_DIR", "")
PIDFILE = os.environ.get("TRON_TOR_PIDFILE", "")
# Bumped whenever the helper protocol/behaviour changes; the launcher kills a
# stale helper so the current version always runs.
HELPER_VERSION = "3.4.2"
HELPER_VERSION = "3.4.3"
_lock = threading.Lock()
_proc = None # the running tor subprocess (or None)
_ready = False # True once tor reported Bootstrapped 100%
Expand Down Expand Up @@ -362,13 +362,11 @@ PIT_NSSDB_EXTRA = os.environ.get("TRON_PIT_NSSDB_EXTRA", "")
# What the launcher started: "flatpak" or "native". The Flathub ungoogled-chromium
# ignores NSS user trust (verified on bonita: the leaf sat in the very database
# strace showed it opening, and Chromium still said "No matching issuer found"),
# but it honours --ignore-certificate-errors-spki-list. So every pin this helper
# accepts is also written to PIT_PINS_FILE, and for a Flatpak engine the launcher
# passes those pins on the command line at the next start. A name first trusted
# mid-session therefore needs one relaunch on a Flatpak engine; the sidebar says so.
# so on that engine the import below cannot take effect. Reported to the sidebar,
# which points at `tron upgrade`: the installer fetches TronBrowser's own engine,
# which honours the store.
PIT_ENGINE = os.environ.get("TRON_PIT_ENGINE", "native")
PIT_CERT_DIR = os.environ.get("TRON_PIT_CERT_DIR", os.path.expanduser("~/.tronbrowser/pit-certs"))
PIT_PINS_FILE = os.environ.get("TRON_PIT_PINS_FILE", os.path.join(PIT_CERT_DIR, "pins.txt"))
_trust_lock = threading.Lock()
_trust_seen = {} # name -> (ok, why); retried after a failure only once the pit restarts

Expand Down Expand Up @@ -450,31 +448,15 @@ def _safe_name(name):
return re.sub(r"\.{2,}", ".", re.sub(r"[^a-z0-9.-]", "", name.lower())).strip(".-")


def remember_pin(name, pin):
"""Append `name pin` to the pins file the launcher reads (once per pair)."""
try:
os.makedirs(os.path.dirname(PIT_PINS_FILE), mode=0o700, exist_ok=True)
have = set()
if os.path.exists(PIT_PINS_FILE):
with open(PIT_PINS_FILE) as f:
have = {line.strip() for line in f}
line = "%s %s" % (name, pin)
if line not in have:
with open(PIT_PINS_FILE, "a") as f:
f.write(line + "\n")
except OSError as exc:
log("pit: could not record the pin for %s: %s" % (name, exc))


def trust_available():
"""Can this machine take a per-name import at all? {available, why}.
`relaunch` is true where the engine only honours pins given at start."""
"""Can this machine take a per-name import at all? {available, why, engine}."""
if platform.system() != "Linux":
return {"available": False, "why": "unsupported-platform", "engine": PIT_ENGINE}
if not shutil.which("certutil"):
return {"available": False, "why": "no-certutil", "engine": PIT_ENGINE}
return {"available": True, "why": "certutil", "engine": PIT_ENGINE,
"relaunch": PIT_ENGINE == "flatpak", "nssdbs": pit_nssdbs()}
if PIT_ENGINE == "flatpak":
return {"available": False, "why": "flatpak-engine", "engine": PIT_ENGINE}
return {"available": True, "why": "certutil", "engine": PIT_ENGINE, "nssdbs": pit_nssdbs()}


def _nssdb_groups():
Expand Down Expand Up @@ -574,7 +556,6 @@ def _ensure_leaf_trust(name, ip):
if is_ca:
log("pit: https for %s: certificate is CA:TRUE — refusing to trust a key that could vouch for any name" % name)
return False, "ca-true"
remember_pin(name, pin)
try:
os.makedirs(PIT_CERT_DIR, mode=0o700, exist_ok=True)
cert_file = os.path.join(PIT_CERT_DIR, "moshpit-%s.crt" % name)
Expand Down
38 changes: 15 additions & 23 deletions apps/desktop/launcher/tronbrowser
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@
BROWSER="$TRONBROWSER_BROWSER"
elif [ -x "$DIR/chrome" ]; then
BROWSER="$DIR/chrome" # future: bundled native fork binary
elif [ -x "$DIR/engine/chrome" ] && "$DIR/engine/chrome" --version >/dev/null 2>&1; then
# TronBrowser's own engine: the portable ungoogled-chromium the installer
# fetches next to this shim (install.sh ensure_engine), pinned per release.
# Preferred over anything the distro or Flathub provides because it is the
# one build we have verified end to end — in particular it honours the
# per-user NSS trust store, which the Flathub ungoogled-chromium does not
# (a Moshpit name's certificate sat in the exact database that build opened
# and it still refused it), so https on pit names works here with no flags.
# The --version probe skips it when a shared library is missing, falling
# through to the system candidates rather than failing to start.
BROWSER="$DIR/engine/chrome"
else
# Ungoogled Chromium ONLY. Never regular Chromium/Chrome, never snap (snap
# chromium is regular AND can't be isolated). No fallbacks.
Expand Down Expand Up @@ -116,10 +127,9 @@
if [ -z "$BROWSER" ]; then
cat >&2 <<MSG
TronBrowser runs Ungoogled Chromium ONLY — never regular Chrome/Chromium.
Install Ungoogled Chromium:
Install it:
Linux: curl -fsSL https://tronbrowser.dev/install.sh | sh (fetches TronBrowser's own engine)
Comment thread
ralyodio marked this conversation as resolved.
Dismissed
macOS: brew install --cask ungoogled-chromium
Linux: flatpak install -y flathub io.github.ungoogled_software.ungoogled_chromium
(or just re-run: curl -fsSL https://tronbrowser.dev/install.sh | sh )
Then run 'tron' again. (Advanced override: TRONBROWSER_BROWSER=/path/to/ungoogled-chromium)
MSG
exit 1
Expand Down Expand Up @@ -175,7 +185,7 @@
# running helper isn't this version — otherwise leave a healthy current
# helper alone (don't drop an active Tor session). All backgrounded so the
# kill+settle never holds up the browser launch.
HELPER_VERSION=3.4.2
HELPER_VERSION=3.4.3
(
_pf="$DATA/tor-helper.pid"
_rv="$(curl -fsS --max-time 1 http://127.0.0.1:9061/status 2>/dev/null | sed -n 's/.*"version"[^"]*"\([^"]*\)".*/\1/p')"
Expand Down Expand Up @@ -683,25 +693,7 @@
# bundle one, but the kill switch is not ours to flip on their behalf.
# (Ungoogled keeps MV2, but force it off everywhere to be safe.)
MV2_KEEP="ExtensionManifestV2Disabled,ExtensionManifestV2Unsupported,ExtensionManifestV2DeprecationWarning,ExtensionManifestV2DeprecationUnsupported"
# Flatpak engine only: the Flathub ungoogled-chromium ignores NSS user trust (the
# pit helper's per-name import sat in the very database strace showed it opening,
# and Chromium still answered "No matching issuer found"), but it honours pins
# given on the command line. The helper records every pin it accepted — a key the
# registry vouches for, for that name — in $HOME/.tronbrowser/pit-certs/pins.txt;
# hand them over here. Chromium shows a one-line "unsupported command-line flag"
# bar at start when this switch is present, so it is only passed when there is at
# least one pin, i.e. on a machine that has used https on a pit name. Native
# engines honour NSS and get nothing here.
pit_spki_flag() { # pins_file -> prints the switch, or nothing
[ -s "$1" ] || return 0
_pins="$(awk 'NF >= 2 && $2 !~ /[^A-Za-z0-9+\/=]/ { print $2 }' "$1" | sort -u | paste -sd, -)"
[ -n "$_pins" ] && printf -- '--ignore-certificate-errors-spki-list=%s' "$_pins"
}
PIT_SPKI_FLAG=""
if [ "$BROWSER" = "flatpak" ]; then
PIT_SPKI_FLAG="$(pit_spki_flag "$HOME/.tronbrowser/pit-certs/pins.txt")"
fi
FLAGS="--user-data-dir=$DATA --class=TronBrowser --no-first-run --no-default-browser-check --no-pings --disable-background-networking --disable-breakpad --disable-domain-reliability --disable-sync --disable-features=Translate,OptimizationHints,InterestFeedContentSuggestions,$MV2_KEEP$GPU_OFF_FEATURES --load-extension=$EXT${PIT_SPKI_FLAG:+ $PIT_SPKI_FLAG}"
FLAGS="--user-data-dir=$DATA --class=TronBrowser --no-first-run --no-default-browser-check --no-pings --disable-background-networking --disable-breakpad --disable-domain-reliability --disable-sync --disable-features=Translate,OptimizationHints,InterestFeedContentSuggestions,$MV2_KEEP$GPU_OFF_FEATURES --load-extension=$EXT"

# Make the tab-strip audio indicator a clickable mute/unmute control. Upstream
# media::kEnableTabMuting is DISABLED_BY_DEFAULT and stock Chrome only turns it
Expand Down
67 changes: 67 additions & 0 deletions apps/web/public/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,9 @@
# we install it as part of setup. Skip with TB_NO_BROWSER_INSTALL=1.
ensure_browser() {
[ "${TB_NO_BROWSER_INSTALL:-0}" = "1" ] && return 0
# With TronBrowser's own engine on disk there is nothing to install here.
_eldir="$(find "$APP_DIR" -maxdepth 3 -type f -name tronbrowser 2>/dev/null | head -n1)"
if [ -n "$_eldir" ] && [ -x "$(dirname "$_eldir")/engine/chrome" ]; then return 0; fi

if [ "$(uname -s)" = "Darwin" ]; then
# Where our launcher lives (holds the trust marker for the no-brew path).
Expand Down Expand Up @@ -690,6 +693,67 @@
rm -rf "$tmp"; return 1
}

# TronBrowser's own engine: the portable ungoogled-chromium
# (github.com/ungoogled-software/ungoogled-chromium-portablelinux), the same
# build the Docker image runs. ~170 MB, so it is not in the release tarball;
# the installer fetches the pinned release next to the launcher (engine/), like
# Obscura. The launcher prefers it over any distro or Flathub Chromium: it is
# the one build verified end to end, and unlike the Flathub ungoogled-chromium
# it honours the per-user NSS trust store, which is what makes https on Moshpit
# names work with no flags. Linux only (macOS keeps the Homebrew cask). Skip with
# TB_NO_ENGINE_INSTALL=1, pin another release with TRONBROWSER_ENGINE_VERSION.
ENGINE_VERSION="${TRONBROWSER_ENGINE_VERSION:-152.0.7977.82-1}"

engine_asset() { # -> asset name for this arch, or nothing (Linux only)
[ "$(uname -s)" = "Linux" ] || return 1
case "$(uname -m)" in
x86_64|amd64) echo "ungoogled-chromium-${ENGINE_VERSION}-x86_64_linux.tar.xz" ;;
aarch64|arm64) echo "ungoogled-chromium-${ENGINE_VERSION}-arm64_linux.tar.xz" ;;
*) return 1 ;;
esac
}

download_engine() { # dest_dir
dst="$1"
asset="$(engine_asset)" || return 1
url="https://github.com/ungoogled-software/ungoogled-chromium-portablelinux/releases/download/${ENGINE_VERSION}/${asset}"
tmp="$(mktemp -d)"
info "Downloading TronBrowser's engine, ungoogled-chromium ${ENGINE_VERSION} ($asset, ~170 MB)…"
if fetch "$url" "$tmp/engine.tar.xz" 2>/dev/null && mkdir -p "$tmp/engine" \
&& tar -xJf "$tmp/engine.tar.xz" --strip-components=1 -C "$tmp/engine" 2>/dev/null \
&& [ -x "$tmp/engine/chrome" ]; then
# Swap in whole: a half-written engine dir must never be what the launcher finds.
rm -rf "$dst.new"; mv "$tmp/engine" "$dst.new"
echo "$ENGINE_VERSION" > "$dst.new/VERSION"
rm -rf "$dst.old"; [ -d "$dst" ] && mv "$dst" "$dst.old"
mv "$dst.new" "$dst"; rm -rf "$dst.old" "$tmp"
[ -x "$dst/chrome" ] && return 0
fi
rm -rf "$tmp"; return 1
}

ensure_engine() {
[ "${TB_NO_ENGINE_INSTALL:-0}" = "1" ] && return 0
[ "$(uname -s)" = "Linux" ] || return 0
endest="$APP_DIR/engine"
_ldir="$(find "$APP_DIR" -maxdepth 3 -type f -name tronbrowser 2>/dev/null | head -n1)"
[ -n "$_ldir" ] && endest="$(dirname "$_ldir")/engine"
if [ -x "$endest/chrome" ] && [ "$(cat "$endest/VERSION" 2>/dev/null)" = "$ENGINE_VERSION" ]; then return 0; fi
if ! tar --help 2>/dev/null | grep -q -- '-J\|xz'; then
if ! command -v xz >/dev/null 2>&1; then
warn "Couldn't install TronBrowser's engine: 'tar' here cannot read .xz and 'xz' is not installed (Debian/Ubuntu: sudo apt install xz-utils). Falling back to the system or Flatpak Ungoogled Chromium."
return 1
fi
fi
info "Setting up TronBrowser's engine (ungoogled-chromium ${ENGINE_VERSION})…"
if download_engine "$endest"; then
info "Installed the engine to $endest"
return 0
fi
warn "Couldn't install TronBrowser's engine; falling back to the system or Flatpak Ungoogled Chromium (https on Moshpit names may warn there). Retry with: curl -fsSL $INSTALL_URL | sh -s -- ensure-engine"
Comment thread
ralyodio marked this conversation as resolved.
Dismissed
return 1
}

ensure_obscura() {
[ "${TB_NO_OBSCURA_INSTALL:-0}" = "1" ] && return 0
obdest="$APP_DIR/obscura-bin"
Expand Down Expand Up @@ -843,6 +907,7 @@
DESKTOP
command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$apps_dir" 2>/dev/null || true

ensure_engine || true # TronBrowser's own engine; ensure_browser is the fallback
ensure_browser
# `|| true` because this script runs under `set -eu`: both of these return 1
# when they could not install their tool, and a missing nice-to-have must not
Expand Down Expand Up @@ -954,6 +1019,7 @@
[ -n "$latest" ] || err "could not resolve the latest release of $REPO"
if [ "$current" = "$latest" ] && [ "${TB_FORCE:-0}" != "1" ]; then
info "TronBrowser is already up to date ($current)."
ensure_engine || true # and that TronBrowser's own engine is current
ensure_browser # still make sure Ungoogled Chromium is installed
ensure_tor || true # and that Tor is available for the toggle
ensure_certutil || true # and that Moshpit trust can be written
Expand Down Expand Up @@ -1019,6 +1085,7 @@
esac ;;
remove|uninstall) do_remove ;;
ensure-tor) ensure_tor ;;
ensure-engine) ensure_engine ;;
ensure-obscura) ensure_obscura ;;
ensure-certutil) ensure_certutil ;;
version|--version|-v) do_version ;;
Expand Down
28 changes: 15 additions & 13 deletions docs/moshpit-pit-toggle.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 🤘 Pit toggle — Moshpit names for one browser session

**Status:** shipped with the AI-sidebar extension + `tron-tor-helper` 3.4.2
**Status:** shipped with the AI-sidebar extension + `tron-tor-helper` 3.4.3
**Owner:** desktop (`apps/desktop`)
**Scope:** resolve Moshpit names in the running browser with one click. Not a
replacement for `moshcode dns enable`, which does it for the whole machine.
Expand Down Expand Up @@ -93,20 +93,22 @@ Flatpak ungoogled-chromium 152 read `data/pki/nssdb` while `.pki/nssdb`
existed beside it, and Chromium's net log said "No matching issuer found"
until that database held the leaf too.

**Flatpak engines do not honour NSS user trust at all.** Found on bonita with
the Flathub ungoogled-chromium 152: `strace` showed Chromium opening the very
**The Flathub ungoogled-chromium does not honour NSS user trust at all.** Found
on bonita with 152.0.7977.82-1: `strace` showed Chromium opening the very
database that held the leaf (peer and anchor trust both tried), single-process
and no-sandbox made no difference, and its net log still said "No matching
issuer found". What that build does honour is
`--ignore-certificate-errors-spki-list`, Chromium's own per-key allowance. So
the helper also records every pin it accepts in
`~/.tronbrowser/pit-certs/pins.txt`, and for a Flatpak engine the launcher
passes those pins on the command line at start. Two consequences: a name first
trusted mid-session loads over https after one relaunch (the sidebar says so),
and Chromium shows its one-line "unsupported command-line flag" bar at start on
a machine that has such pins. Native engines take the NSS path and get neither.
The clean way out is a Moshpit CA on the registry side, or shipping the
portable ungoogled-chromium as TronBrowser's own engine, which honours NSS.
issuer found". The same 152 release as a portable build accepts the same
database in every variant tried. So TronBrowser now ships its own engine:
`install.sh ensure_engine` fetches the pinned portable ungoogled-chromium into
`<launcher dir>/engine/` next to Tor and Obscura, on install and on
`tron upgrade`, and the launcher prefers `$DIR/engine/chrome` over any system
or Flatpak Chromium (after a `--version` probe, so a machine missing a shared
library falls back rather than failing to start). On that engine the per-name
import above is all that is needed: no flag, no bar, no relaunch. If the pit
is turned on while a Flatpak engine is still running, the sidebar says so and
points at `tron upgrade`. A `--ignore-certificate-errors-spki-list` workaround
was tried and reverted: it works, but Chromium flags it as an unsupported switch
at every start.

Linux only for now (Chromium on macOS reads the keychain, which needs an
interactive prompt), and it needs `certutil` (Debian/Ubuntu `libnss3-tools`,
Expand Down
Loading