From b1c9eee70bfd81f112756d86e9f58d9a1b0bf08c Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Fri, 24 Jul 2026 15:00:26 -0400 Subject: [PATCH] bearnet: nav-bar button + Tools menu + shortcut, and ship the real GeoIP DBs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Entry points (the answer to 'is there a menu option?' — there wasn't, only the new-tab tile): extends bearstart-autoconfig.js to register, via the same privileged autoconfig, a persistent nav-bar toolbar button (radar glyph, themed), a 'Network Monitor (BearNet)' item at the top of the Tools menu, and a Ctrl/Cmd+Alt+N shortcut — per-window, best-effort, wrapped so it can never break startup. Opens resource:///bearstart/bearnet.html. GeoIP (ship the real asset, not a country-level fake): scripts/fetch-geoip.sh downloads DB-IP City Lite + ASN Lite (CC-BY, month-stamped with last-month fallback); assemble-cockpit stages both into the app's geoip/; cockpit-up launches the capture sidecar with CAPTURE_SIDECAR_GEOIP pointed at them. The 131MB city DB stays out of git (fetched at package time); ASN committed. Verifiable only in a real build (autoconfig UI + sidecar launch need a running app); syntax-checked here. --- scripts/assemble-cockpit.sh | 8 +++ scripts/bearbrowser-cockpit-up | 3 +- scripts/fetch-geoip.sh | 48 +++++++++++++++ settings/start/bearstart-autoconfig.js | 84 ++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 1 deletion(-) create mode 100755 scripts/fetch-geoip.sh diff --git a/scripts/assemble-cockpit.sh b/scripts/assemble-cockpit.sh index f039ca9..08ac76c 100755 --- a/scripts/assemble-cockpit.sh +++ b/scripts/assemble-cockpit.sh @@ -47,6 +47,14 @@ else log "WARNING: cargo not found — skipping capture sidecar (BearNet panel will show offline)" fi +# 2c. GeoIP databases for BearNet's map + who-owns-it view (DB-IP City + ASN, +# CC-BY). Fetched here (the 131MB city DB is too big to commit) and staged into +# the app so geolocation works offline, no per-connection geo-API leak. +log "staging BearNet GeoIP databases …" +mkdir -p "$STAGE/geoip" +bash "$REPO_ROOT/scripts/fetch-geoip.sh" "$STAGE/geoip" || \ + log "WARNING: GeoIP fetch failed — BearNet map dots/ASN will be partial" + # 3. Stage the runtime scripts + the enforcing contract (Lane 4 + Receipts + orchestrator). log "staging runtime scripts + policy contract …" for s in bearbrowser-agent-machine bearbrowser-agent-machine-gate.py agent-control-bridge.py \ diff --git a/scripts/bearbrowser-cockpit-up b/scripts/bearbrowser-cockpit-up index f37d3b3..d2d8b24 100755 --- a/scripts/bearbrowser-cockpit-up +++ b/scripts/bearbrowser-cockpit-up @@ -63,7 +63,8 @@ BEARBROWSER_RECEIPTS_PORT="$RECEIPTS_PORT" python3 "$RECEIPTS" >/tmp/bb-cockpit- # refuses to run if the bridge is missing, so this is safe to launch blindly. if [ -x "$CAPTURE_BIN" ]; then echo "[cockpit-up] capture → :$CAPTURE_PORT" - "$CAPTURE_BIN" --repo-root "$RES" --port "$CAPTURE_PORT" >/tmp/bb-cockpit-capture.log 2>&1 & pids+=($!) + CAPTURE_SIDECAR_GEOIP="$RES/geoip" \ + "$CAPTURE_BIN" --repo-root "$RES" --port "$CAPTURE_PORT" >/tmp/bb-cockpit-capture.log 2>&1 & pids+=($!) fi # 2. Bounded health summary — report, don't hang. diff --git a/scripts/fetch-geoip.sh b/scripts/fetch-geoip.sh new file mode 100755 index 0000000..beaf811 --- /dev/null +++ b/scripts/fetch-geoip.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# fetch-geoip.sh — download the local IP-intelligence databases BearNet uses +# for its map + who-owns-it view: DB-IP City Lite + ASN Lite (MaxMind format, +# CC-BY-4.0). Run at package/assemble time. We ship the REAL city database +# (precise city-level dots), not a country-level stand-in. +# +# The city DB (~131MB uncompressed) is too big to commit, so it's fetched here; +# the ASN DB (~10MB) is committed but re-fetched fine if absent. The sidecar +# loads whatever is present from its geoip dir (CAPTURE_SIDECAR_GEOIP), and +# degrades gracefully if a DB is missing. +# +# Usage: fetch-geoip.sh [DEST_DIR] (default: capture-sidecar/geoip) +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +DIR="${1:-$REPO_ROOT/capture-sidecar/geoip}" +mkdir -p "$DIR" + +# DB-IP publishes month-stamped files; the current month may not exist early on, +# so try this month then fall back to last month. +months() { + date +%Y-%m + if date -v-1m +%Y-%m >/dev/null 2>&1; then date -v-1m +%Y-%m; else date -d 'last month' +%Y-%m; fi +} + +fetch() { # + local out="$DIR/$1" base="$2" + if [ -s "$out" ]; then + echo "[geoip] have $1 ($(du -h "$out" | cut -f1))" + return 0 + fi + local m + for m in $(months); do + local url="https://download.db-ip.com/free/${base}-${m}.mmdb.gz" + if curl -fsSL "$url" 2>/dev/null | gunzip > "$out.tmp" 2>/dev/null && [ -s "$out.tmp" ]; then + mv "$out.tmp" "$out" + echo "[geoip] fetched $1 ($m, $(du -h "$out" | cut -f1))" + return 0 + fi + rm -f "$out.tmp" + done + echo "[geoip] WARNING: could not fetch $1 — BearNet map/ASN will be partial" >&2 + return 1 +} + +fetch dbip-city-lite.mmdb dbip-city-lite # geolocation (lat/lon/city → map dots) +fetch dbip-asn-lite.mmdb dbip-asn-lite # ASN + owning org (who owns the block) +echo "[geoip] ready in $DIR" diff --git a/settings/start/bearstart-autoconfig.js b/settings/start/bearstart-autoconfig.js index f92a5f2..6d97574 100644 --- a/settings/start/bearstart-autoconfig.js +++ b/settings/start/bearstart-autoconfig.js @@ -18,3 +18,87 @@ try { } catch (e) { // Leave stock about:newtab in place rather than risk startup. } + +// ── BearNet entry points ──────────────────────────────────────────────────── +// Make the network monitor reachable from ANYWHERE, not just the new-tab tile: +// a persistent nav-bar button (always visible, cross-platform), a Tools-menu +// item, and a Ctrl/Cmd+Alt+N shortcut. All best-effort — never break startup. +try { + if (!Services.appinfo.inSafeMode) { + const BEARNET_URL = "resource:///bearstart/bearnet.html"; + // Small radar glyph, themed to the toolbar's text color. + const ICON = + "data:image/svg+xml," + + encodeURIComponent( + "" + + "" + + "" + + "" + + "" + ); + + const { CustomizableUI } = ChromeUtils.importESModule( + "resource:///modules/CustomizableUI.sys.mjs" + ); + try { + CustomizableUI.createWidget({ + id: "bearnet-button", + label: "BearNet", + tooltiptext: "BearNet — see and block what this browser is talking to", + defaultArea: CustomizableUI.AREA_NAVBAR, + onCreated(node) { + node.style.listStyleImage = "url('" + ICON + "')"; + node.style.MozContextProperties = "fill"; + }, + onCommand(ev) { + ev.target.ownerGlobal.openTrustedLinkIn(BEARNET_URL, "tab"); + }, + }); + } catch (e) { + // Widget already registered this session — fine. + } + + // Per-window: Tools-menu item + keyboard shortcut. + const decorate = (win) => { + try { + const doc = win.document; + if (doc.documentElement.getAttribute("windowtype") !== "navigator:browser") return; + const tools = doc.getElementById("menu_ToolsPopup"); + if (tools && !doc.getElementById("bearnet-menuitem")) { + const mi = doc.createXULElement("menuitem"); + mi.id = "bearnet-menuitem"; + mi.setAttribute("label", "Network Monitor (BearNet)"); + mi.setAttribute("accesskey", "N"); + mi.addEventListener("command", () => win.openTrustedLinkIn(BEARNET_URL, "tab")); + tools.insertBefore(mi, tools.firstChild); + } + const keyset = doc.getElementById("mainKeyset"); + if (keyset && !doc.getElementById("bearnet-key")) { + const key = doc.createXULElement("key"); + key.id = "bearnet-key"; + key.setAttribute("key", "N"); + key.setAttribute("modifiers", "accel,alt"); + key.setAttribute( + "oncommand", + "openTrustedLinkIn('" + BEARNET_URL + "','tab')" + ); + keyset.appendChild(key); + } + } catch (e) {} + }; + const en = Services.wm.getEnumerator("navigator:browser"); + while (en.hasMoreElements()) decorate(en.getNext()); + Services.wm.addListener({ + onOpenWindow(xw) { + try { + const win = xw.docShell.domWindow; + win.addEventListener("load", () => decorate(win), { once: true }); + } catch (e) {} + }, + onCloseWindow() {}, + onWindowTitleChange() {}, + }); + } +} catch (e) { + // No entry points rather than a broken browser. +}