fetch_graph() gains three additive, read-time keys (no schema change,
d3 /social/graph contract untouched):
- by_domain: trackers rolled up under their registrable parent (eTLD+1,
all *.doubleclick.net → doubleclick.net) with tracker_count/hits/sites/vendors
- targets: inverse map — per 1st-party site, the trackers + parent domains
watching it
- history: per-UTC-day timeline (hits/trackers/sites) from social_edges
stats gains total_domains; local _registrable_domain helper (no publicsuffix
dep). Integration-tested (rollup, inversion, history). secubox-toolbox 2.6.17.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
_LEVEL_THEME map drives the banner look per opt-in level: R3 (and the
planned R4) get a neon-tube treatment — dark glass bar, glowing tube
border (layered box-shadow) and neon text-shadow on the title — while R2
keeps the original amber flat bar. _banner_html_dynamic() now takes the
level and themes both the CSP-strict (JS-less) and JS (dismissible)
variants; all inline CSS, no injected <style>/@keyframes, ASCII/NCR-clean.
R4 theme is defined but inert until _client_level() returns 'r4'.
secubox-toolbox 2.6.16.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On a rooted device the app now runs the full silent onboarding on launch
with no taps: a LaunchedEffect auto-starts the root sequence once when
root is detected and this host hasn't been onboarded yet. The root-auto
logic is extracted into a reusable runRootAuto lambda (shared by the
auto-launch and the ⚡ button, which remains for re-runs). An onboarded
flag is persisted per host in SharedPreferences so reopening doesn't redo
it. versionName 0.2.0 / versionCode 2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
install-firefox-linux.sh: one call grabs the ToolBoX .xpi (from a cabine
host, --release, or --local) and launches Firefox with it loaded via
'web-ext run' (temporary, works unsigned — fastest), opening /social/me.
Falls back to opening the .xpi for the install prompt when web-ext/npx
is absent, with the unsigned-install note. Detects firefox/-esr/-bin/flatpak.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Animated hero (gazing eye + floating tracker dots) + one big 'Protège-moi
(R3)' CTA + the auto-detected install panel up front. KPIs, cert-probe,
pitch, R0-R3 levels, charts, architecture, open-source and contact are
folded behind an 'En savoir plus' <details>. Quick-nav trimmed: dropped
the CA iPhone / CA Android / QR profil cards (now inside the per-platform
install panel); kept R3 Install / Mon rapport / Ma carto / Wiki / Cabine.
Count-up animation on the live KPIs. All Jinja vars + live-stats and
cert-probe scripts preserved. secubox-toolbox 2.6.15.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Real cause of the broken extension: api.js and background.js BOTH did
`const ext = …`. In a Firefox event page the background.scripts array
loads them into one shared scope (same via importScripts in a Chromium
SW), and popup.js's `const ext` collided with api.js's in the popup
page realm too — 'redeclaration of const ext' aborts the script. web-ext
lint misses it because it never concatenates/executes the scripts.
Now only api.js declares `const ext`; background.js and popup.js use
`api.ext`.
Also (defensive + Chromium-correct): replace the SVG action/extension
icon with rasterised PNGs (48/128) and keep the SVG out of the package,
so Firefox never renders SVG in chrome UI. Bump to v0.1.1; the
/wg/toolbox.xpi endpoint + fetch helper + docs point at webext-v0.1.1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
README + wiki Browser-Extension: add the direct release download URL,
document make_latest:false / tag-pinned design. TODO/WIP: mark the
webext-v0.1.0 release published (downloadable, verified) and note the
remaining board deploy of secubox-toolbox 2.6.14.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Publishing webext-v* with the default make_latest would steal the
"latest" release pointer from the Android APK release, breaking the
APK endpoint's /releases/latest/download/secubox-toolbox-android.apk
fallback. Publish the webext release with make_latest:false and point
the /wg/toolbox.xpi endpoint + fetch helper at the tag-pinned download
URL instead.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
web-ext lint: 0 errors, 2 benign warnings (AMO data-collection
declaration is submission-time, tied to the signing follow-up;
service_worker-ignored is the intentional cross-browser pattern).
optional_host_permissions needed FF128 and was unused at MVP.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- new wiki page Android-ToolBox.md (install via /wg/toolbox.apk, manual +
root onboarding flows, CI build, endpoints) + sidebar link
- README: document the root-mode silent path + revised constraints
- WIP/TODO/HISTORY: Android client section (#531/#536/#538)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an optional one-tap, zero-interaction onboarding path for rooted
devices. When root is detected the app can:
- install the village3b CA into the SYSTEM trust store (bind-mount over
/system/etc/security/cacerts + conscrypt APEX, SELinux ctx restored),
so every app trusts the cabine CA — not just user-CA opt-in apps;
- bring the WireGuard tunnel up natively via the kernel module
(ip link add … type wireguard + wg set), no WireGuard app needed;
- verify R3 reachability automatically.
Falls back to the existing manual handoff (KeyChain CA prompt + WG app)
when the kernel lacks WireGuard. All root actions are gated behind an
explicit '⚡ Installation automatique (root)' tap — nothing runs as root
without the operator choosing it on their own device.
New: RootShell (su wrapper), RootOnboard (silent sequence + subject_hash_old
in pure Kotlin). MainActivity gains a RootAuto step with a streaming log.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The export/json/recent/ endpoint renamed the IOC field ioc → ioc_value;
the parser still read e.get('ioc') and skipped every entry, ingesting 0
for weeks and starving Phase 13.B DNS-guard of domain IOCs. Now reads
ioc_value or ioc. Verified live on gk2: threatfox 0 → 5000 ingested
(2935 domains + 1613 ips + 32 sha256). changelog 2.6.12.
After the wg-admin tunnel is confirmed working, 'harden' closes the
public SSH brute-force surface:
- sshd drop-in: PasswordAuthentication no + PermitRootLogin
prohibit-password (refuses if no root authorized_keys — no lockout).
- nft SSH-guard: drop tcp/22 from sources outside the LAN (192.168.1.0/24)
+ 10.x tunnels, inserted BEFORE the blanket 'iif eth1 accept' so the
router's port-forwarded public SSH (real public src IP, DNAT no-SNAT)
is dropped while LAN + wg-admin stay reachable. Persisted in
/etc/nftables.conf + applied live without flushing other tables.
Applied + verified on gk2: tunnel SSH (10.98.0.1) key-only works; public
admin.gk2.secubox.in:22 now times out. Tables (blacklist/wg) intact.
The while-read in write_server_conf reused the global pip/ppub names, so
after it ran the caller's $pip (the new peer IP for the client config)
was wiped to empty — the emitted client config showed 'Address = /32'.
The provisioned server state was always correct; only the printed config
was wrong. Loop now uses local _pn/_pip/_pub.
Idempotent provisioner for a dedicated out-of-band admin tunnel,
distinct from wg-toolbox:
- wg-admin UDP 51821, server 10.98.0.1/24, peers 10.98.0.2+/32.
- generates server+peer keys once (0600, never in repo), writes
/etc/wireguard/wg-admin.conf from a peers state file.
- installs /etc/nftables.d/secubox-admin-wg.nft (allow udp/51821,
persistent) — ADDITIVE, does not touch sshd or existing rules.
- 'add <name>' mints a client .conf + QR (split-tunnel, endpoint
admin.gk2.secubox.in:51821).
sshd hardening (key-only + restrict 22) is a deliberate separate step.
Closes the DoH / hardcoded-IP bypass gap on top of 13.A.
- secubox-blacklist-sync: Source 3 resolves threat_intel domain IOCs
(ioc_type='domain') to A/AAAA via getent (2s per-lookup timeout,
2000-domain cap) and pushes the IPs into blacklist_v4/v6 — a device
that resolves a known-bad domain out-of-band (DoH / hardcoded IP) is
still dropped at forward. Writes /run/secubox/blacklist-sync.json.
- secubox-blacklist.nft: doh_detect_v4/v6 sets + count-only doh_watch
chain (priority -11) countering device egress to known DoH/DoT
providers (Cloudflare/Google/Quad9/AdGuard/OpenDNS/CleanBrowsing/
Control-D/NextDNS) on tcp 443/853. Made the drop-in IDEMPOTENT via
the create-or-replace idiom (table{} ; delete table ; table{...}) so
nft -f reloads don't append duplicate rules.
- secubox-blacklist-sync: populates DoH sets each cycle;
SECUBOX_DOH_BLOCK=1 also enforce-drops them (forces devices back
through Vortex DNS). Default off — intrusive, gated per #519 Q1.
- api.py /admin/blacklist: doh_detect counts, doh_hits, resolved_domains,
doh_block flag.
- changelog 2.6.9.
Live on gk2: idempotency verified (enforce=4 / doh_watch=2 rules after
double reload), endpoint shows v4_count 20 + doh_detect 15 v4 / 6 v6,
doh_block false. resolved_domains 0 (threat_intel has no domain IOCs
yet — threatfox feed currently returns 0; path is correct).
First track of the protection enforcement plane (#519). Pure netfilter,
additive drops, DEFAULT-DROP doctrine preserved.
- nftables.d/secubox-blacklist.nft: table inet secubox_blacklist with
blacklist_v4/v6 sets (interval,timeout) + a single forward-hook
chain (priority -10, policy accept) counter-dropping any routed
packet whose saddr OR daddr is blacklisted. One rule set covers
every device egress path (captive/WG/br-lxc/LAN), no per-iface logic.
- sbin/secubox-blacklist-sync: unions CrowdSec ban decisions (cscli)
+ threat-intel C2 IPs (threat_intel ip IOCs) into the sets, 2h
per-element timeout (auto-expire on stale feeds), 50k cap, idempotent
add (no flush race with CrowdSec's own table).
- systemd sync .service + .timer (5min + OnBootSec 90s).
- postinst: install drop-in, reload nft, enable+start timer, first sync.
- api.py GET /admin/blacklist: element counts + drop counters (nft -j).
- debian/rules FIX: moved the whole override_dh_strip body into
execute_after_dh_auto_install. dh_strip is NOT in the binary-indep
sequence for an Architecture: all package, so override_dh_strip
silently never ran — the nft drop-ins / unbound / nginx / perf
drop-ins (and now the blacklist files) had stopped shipping in the
.deb and gk2 was running stale on-disk copies (the live-config-drift
we kept hitting). Now they all ship again.
- changelog 2.6.8.
Live on gk2: table loaded, first sync populated 18 v4 C2 IPs with 2h
timeouts, enforce chain active (4 drop rules, counters wired), timer
enabled, /admin/blacklist returns active:true.
The Clients-tab 🕸️ Carto link 303'd to a relative /social/{token}, but
that route is only served on the kbin vhost — from admin.gk2 it hit the
aggregator's 'missing module' page. admin_client_social() now swaps the
leading admin. host label for kbin. and redirects to the absolute URL.
Live: 303 -> https://kbin.gk2.secubox.in/social/{token} -> 200. changelog 2.6.6.
Anti-bot / 'prove you're human' DETECTION (bypass stays gated behind doctrine):
- social_graph.py detect_antibot(): reCAPTCHA/hCaptcha/Turnstile/Datadome/
PerimeterX-HUMAN/Arkose/Kasada/Akamai-BotManager from URL+cookies+headers.
- social.py: social_host_meta.antibot_vendor + social_antibot per-client
challenge table; fetch_graph/aggregate/wipe_mac carry it.
- social.js: cinnabar severe lens + spinning warning ring + 🤖 label +
'challenged your humanity' alert banner; node-detail vendor.
- operator social tab: anti-bot breakdown card.
Fix the ring-level visibility the user reported missing:
- radial force now DOMINANT (strength 0.9) with weak charge/links, plus
dashed ring guides (inner=sites, outer=trackers); assets cache-busted
?v=264b so the new layout actually loads.
Per-client operator tools in the Clients tab:
- 🕸️ Carto link → GET /admin/clients/{mac}/social mints a token + opens
that client's graph.
- ↺ Reset (RAZ) → POST /admin/clients/{mac}/reset wipes social + events +
consents + reports and zeroes score (store.reset_client + social.wipe_mac).
changelog 2.6.5. Live on gk2: both new tables created, detect_antibot matrix
green, aggregate by_antibot/antibot_clients present, reset endpoint 200, graph
nodes carry antibot_vendor, served assets contain the ring + cache-bust.
First passive track of the #514 anti-human-detection platform.
- social_graph.py: detect_cdn() classifies the edge network fronting
each 3rd-party host from response headers (Cloudflare/Fastly/Akamai/
CloudFront/Google/Vercel/Netlify/BunnyCDN/KeyCDN/Sucuri/Imperva +
generic edge-cache). Host-stable, recorded off-thread. Also deduped
a stray duplicate _ja4_hash left by the 11.C edit.
- social.py: new social_host_meta table; fetch_graph LEFT JOINs
cdn_vendor/cache_status onto nodes; aggregate adds by_cdn.
- social.js: per-client graph re-centred on a Round-Eye hotspot —
device = pulsing eye at centre, sites orbit on inner forceRadial
ring, trackers push to outer ring (densest clusters = hot spots).
Tracker nodes tinted by CDN vendor; node-detail shows CDN/cache.
- social.css: eye halo/sclera/iris/pupil + breathing anim + cinnabar
spokes.
- index.html: operator social tab gains a CDN/edge breakdown card.
- i18n: node_detail_cdn FR/EN. changelog 2.6.4.
Live on gk2: social_host_meta table created, addon loads detect_cdn,
detect_cdn matrix green (CF/Fastly/Akamai/CloudFront/none), end-to-end
read path proven (synthetic Cloudflare record -> graph node cdn_vendor
-> aggregate by_cdn). Populates from live traffic.