Skip to content

Add a 🤘 Pit toggle: resolve Moshpit names for the session, like the Tor toggle - #102

Merged
ralyodio merged 1 commit into
mainfrom
worktree-pit-toggle
Sep 16, 2026
Merged

ralyodio merged 1 commit into
mainfrom
worktree-pit-toggle

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

What

A 🤘 Pit button in the AI sidebar, next to 🧅 Tor, that turns Moshpit name resolution on and off for the running browser session. Asked for as "just a button like the tor one", and built the same way.

How it works

piece change
launcher/tron-tor-helper (→ 3.3.0) new /pit/start, /pit/stop, /pit/status. /pit/start binds a loopback SOCKS5 resolver on 127.0.0.1:9081 that answers names through the Moshpit DoH resolver (https://dns.moshcode.sh/dns-query, RFC 8484, TTL-cached) and relays the connection; it probes mosh.eggs so the toggle can report that names really resolve. Nothing listens or is contacted until the toggle asks.
extensions/ai-sidebar/pit-proxy.js the PAC. FindProxyForURL calls dnsResolve(host): anything the system resolver can answer goes DIRECT, untouched; only a host it has no answer for goes to the pit. That is the house policy (clearnet wins, pit as fallback) with no ending list to fetch — real TLDs like .io/.dev are claimed as Moshpit endings too, so a list could not decide. Not mandatory, so a broken PAC degrades to DIRECT.
background.js pit-set / pit-status messages, PIT badge, session-scoped state (off on every fresh launch, like Tor). Tor and the pit are exclusive: the PAC asks the system resolver about every host, which under Tor would leak lookups, so turning Tor on takes the pit down and enabling the pit under Tor is refused with a reason.
sidepanel.* the button (acid green when ON) and plain-language status/error copy; the status strip functions are renamed showNetStatus/hideNetStatus since both toggles share it.
options.html the Name-resolution hint now describes both routes: moshcode dns enable for the whole machine, 🤘 Pit for this session.
launcher/tronbrowser HELPER_VERSION bumped to 3.3.0 so a running 3.2.8 helper is replaced on next launch.
docs/moshpit-pit-toggle.md design, limits, hand-test recipe.

Whole-machine resolution is still moshcode dns enable; this is the no-root, this-browser-only alternative the pit's own DNS page promises.

Fix found while testing

Closing a listening socket from another thread does not wake a blocked accept(), so the first cut of /pit/stop replied {"stopped": true} while the port stayed bound. The listener now polls a stop flag with a short accept timeout and stop() joins before replying.

Verified

  • pnpm test in apps/desktop: 136 tests pass across 11 files, including 6 new PAC tests (unresolvable host → SOCKS5, resolvable → DIRECT, loopback/intranet/IP literals → DIRECT, case + trailing dot, bad port).
  • pnpm lint clean; sh -n on the launcher; bash -n on build-release.sh.
  • Helper live on scratch ports: /pit/start → probe mosh.eggs → 67.205.189.229; curl --socks5-hostname … http://mosh.eggs/ → 302 to pit.moshcode.sh/n/mosh.eggs; clearnet http and https relay through the same port; unknown host → SOCKS reply 04; /pit/stop closes the port; start again works; SIGTERM closes it.

Not in this PR

  • https:// on a pit name without the Moshpit CA still warns (the pit page documents why); moshcode dns enable installs the CA and the launcher already mirrors it into Chromium's trust store, so the two compose.
  • "Moshpit wins" mode, persisting the toggle across launches, and Windows (the .cmd shim starts no helper) — see the doc.

Ship notes

Needs a v* tag for the helper and extension to reach users (tron upgrade pulls the tagged tarball). Not browser-tested in a live TronBrowser session yet: the PAC's dnsResolve path and the badge are the parts to click through.

🤖 Generated with Claude Code

…or toggle

The AI sidebar gets a Pit button next to Tor. The launcher's helper (now 3.3.0) serves /pit/start, /pit/stop and /pit/status: a loopback SOCKS5 resolver on 127.0.0.1:9081 that answers through the Moshpit DNS-over-HTTPS resolver and relays the connection. The extension installs a PAC that sends only hosts the system resolver has no answer for to it, so clearnet names are never touched, nothing on the machine changes and no root is needed. Session-scoped and exclusive with Tor (the PAC asks the system resolver, which under Tor would leak lookups). Whole-machine resolution is still moshcode dns enable; the settings copy now says both.

Fix along the way: closing a listening socket from another thread does not wake accept(), so /pit/stop left the port bound; the listener now polls a stop flag and stop() joins before replying.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment thread apps/desktop/launcher/tron-tor-helper Dismissed
Comment thread apps/desktop/extensions/ai-sidebar/pit-proxy.test.js Dismissed
@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

53 finding(s)

HIGH/CRITICAL: 1 | MEDIUM: 32 | LOW: 20

Severity Rule Location
HIGH py-ssrf-outbound-request apps/desktop/launcher/tron-tor-helper:298
MEDIUM js-open-redirect apps/desktop/extensions/ai-sidebar/install-helper.js:156
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/media.js:34
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/media.js:57
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/newtab.js:237
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/newtab.js:266
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/newtab.js:336
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/options.js:305
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/sidepanel.js:78
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/sidepanel.js:166
MEDIUM sh-remote-script-execution apps/desktop/launcher/tronbrowser:122
MEDIUM sh-remote-script-execution apps/desktop/launcher/tronbrowser:433
MEDIUM js-unescaped-html-sink apps/extensions/public/store.js:77
MEDIUM js-unescaped-html-sink apps/extensions/public/store.js:227
MEDIUM js-unescaped-html-sink apps/extensions/public/store.js:569
MEDIUM js-unescaped-html-sink apps/web/public/app.js:29
MEDIUM js-unescaped-html-sink apps/web/public/dns.js:54
MEDIUM sh-remote-script-execution apps/web/public/install.sh:161
MEDIUM sh-remote-script-execution apps/web/public/install.sh:166
MEDIUM sh-remote-script-execution apps/web/public/install.sh:279
MEDIUM sh-remote-script-execution apps/web/public/install.sh:297
MEDIUM sh-remote-script-execution apps/web/public/install.sh:704
MEDIUM sh-remote-script-execution apps/web/public/install.sh:985
MEDIUM js-unescaped-html-sink apps/web/public/settings.js:96
MEDIUM js-unescaped-html-sink apps/web/public/settings.js:168
MEDIUM js-dynamic-code-execution packages/sdk/src/mcp/tools.ts:80
MEDIUM js-dynamic-code-execution packages/sdk/src/mcp/tools.ts:92
MEDIUM js-dynamic-code-execution packages/sdk/src/mcp/tools.ts:103
MEDIUM js-dynamic-code-execution packages/sdk/src/page.ts:65
MEDIUM js-dynamic-code-execution packages/sdk/src/page.ts:70
MEDIUM sql-template-interpolation services/api/src/store/db.ts:116
MEDIUM js-dynamic-code-execution services/api/src/store/scanner.ts:44
MEDIUM sh-predictable-temp-path start.sh:25
LOW js-dynamic-code-execution apps/desktop/extensions/ai-sidebar/pit-proxy.test.js:8
LOW js-dynamic-code-execution packages/agent-runtime/src/analyze/form-script.test.ts:6
LOW js-unescaped-html-sink packages/agent-runtime/src/analyze/form-script.test.ts:26
LOW js-unescaped-html-sink packages/agent-runtime/src/analyze/form-script.test.ts:49
LOW js-dynamic-code-execution packages/browser-core/src/automation/extract-script.test.ts:6
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:35
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:47
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:70
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:89
LOW js-dynamic-code-execution packages/browser-core/src/automation/snapshot-script.test.ts:11
LOW js-unescaped-html-sink packages/browser-core/src/automation/snapshot-script.test.ts:24
LOW js-unescaped-html-sink packages/browser-core/src/automation/snapshot-script.test.ts:63
LOW js-unescaped-html-sink packages/provenance/src/scan.test.ts:47
LOW js-unescaped-html-sink packages/provenance/src/scan.test.ts:170
LOW js-unescaped-html-sink packages/provenance/src/scan.test.ts:216
LOW js-dynamic-code-execution packages/sdk/src/mcp/automate.test.ts:258
LOW secret-generic-api-key packages/storage/src/config.ts:51

…and 3 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio marked this pull request as ready for review September 16, 2026 09:08
@ralyodio
ralyodio merged commit e183791 into main Sep 16, 2026
7 of 8 checks passed
@ralyodio
ralyodio deleted the worktree-pit-toggle branch September 17, 2026 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants