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: 8 additions & 0 deletions scripts/assemble-cockpit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
3 changes: 2 additions & 1 deletion scripts/bearbrowser-cockpit-up
Original file line number Diff line number Diff line change
Expand 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.
Expand Down
48 changes: 48 additions & 0 deletions scripts/fetch-geoip.sh
Original file line number Diff line number Diff line change
@@ -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() { # <out-filename> <db-ip-base-name>
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"
84 changes: 84 additions & 0 deletions settings/start/bearstart-autoconfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
"<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none' stroke='context-fill' stroke-width='1.3'>" +
"<circle cx='8' cy='8' r='1.6' fill='context-fill' stroke='none'/>" +
"<circle cx='8' cy='8' r='4'/><circle cx='8' cy='8' r='6.6'/>" +
"<circle cx='13' cy='4' r='1.1' fill='context-fill' stroke='none'/>" +
"</svg>"
);

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.
}
Loading