Skip to content

w3bs:// on every platform: OS handler registration for macOS, Windows, Linux - #151

Merged
ralyodio merged 3 commits into
mainfrom
feat/w3bs-all-platforms
Oct 20, 2026
Merged

ralyodio merged 3 commits into
mainfrom
feat/w3bs-all-platforms

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Follow-up to #149. A W3BS link from another app, or one typed in the address bar (Chromium hands any scheme it cannot load to the OS), now reaches TronBrowser on every platform and opens through https://w3bs.org/browse?q=.

  • macOS: tron-w3bs-register builds ~/Applications/TronBrowser Links.app, a faceless applet that declares w3bs in CFBundleURLTypes and runs the launcher. It is re-signed ad hoc and registered with LaunchServices, and it becomes the default only if nothing else claims the scheme. Chromium.app can't be the handler because it would hand w3bs:// straight back to the OS.
  • Windows: tron-w3bs.ps1 registers HKCU\Software\Classes\w3bs and opens the URI. cmd.exe never parses a URI that came from a page, and malformed URIs open the resolver without them. tron w3bs://… works too.
  • Linux: the launcher sets the xdg default for installs that never ran install.sh (deb, rpm, AppImage, brew), unless another app already handles w3bs.

The launcher and tronbrowser.cmd register in the background on every start, so every install method works and an upgrade re-points the handler. The launcher now encodes like encodeURIComponent, so the address bar shows q=w3bs%3A%2F%2Fprompt… instead of a byte-by-byte encoding.

New w3bs-scheme.yml proves each OS's real dispatch (xdg-open, open, Start-Process) reaches the engine with the resolver URL. The Linux run passes locally.

Not possible without admin: skipping Chromium's "open this app?" confirmation for typed URIs. That needs the AutoLaunchProtocolsFromOrigins managed policy (root, MDM, or HKLM). After that one click, the URI opens in TronBrowser.

🤖 Generated with Claude Code

…, Linux

A W3BS link from another app, or one typed in the address bar (Chromium hands
any scheme it cannot load to the OS), now reaches TronBrowser everywhere:

- macOS: tron-w3bs-register builds ~/Applications/TronBrowser Links.app, a
  faceless applet declaring CFBundleURLTypes w3bs that runs the launcher
  (re-signed ad hoc, registered with LaunchServices, default only if unclaimed)
- Windows: tron-w3bs.ps1 registers HKCU\Software\Classes\w3bs and opens the
  URI; cmd.exe never parses a URI from a page. `tron w3bs://...` works too
- Linux: the launcher sets the xdg default for installs that never ran
  install.sh (deb/rpm/AppImage/brew), unless another app handles w3bs

The launcher and tronbrowser.cmd register in the background on every start,
so every install method heals after upgrades. The launcher now encodes the URI
like encodeURIComponent, so the address bar stays readable.

w3bs-scheme.yml proves each OS's real dispatch (xdg-open, open, Start-Process)
reaches the engine with the resolver URL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

ThreatCrush Security Scan

48 finding(s)

HIGH/CRITICAL: 2 | MEDIUM: 25 | LOW: 21

Severity Rule Location
HIGH py-ssrf-outbound-request apps/desktop/launcher/tron-tor-helper:303
HIGH py-ssrf-outbound-request apps/desktop/launcher/tron-tor-helper:437
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:246
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/newtab.js:275
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/newtab.js:345
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/options.js:306
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 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:167
MEDIUM sh-remote-script-execution apps/web/public/install.sh:407
MEDIUM sh-remote-script-execution apps/web/public/install.sh:425
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:125
MEDIUM js-dynamic-code-execution packages/sdk/src/page.ts:68
MEDIUM js-dynamic-code-execution packages/sdk/src/page.ts:73
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:28
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:16
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:45
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:57
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:80
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:99
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:62
LOW js-unescaped-html-sink packages/browser-core/src/automation/snapshot-script.test.ts:101
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:261
LOW secret-generic-api-key packages/storage/src/config.ts:51
LOW secret-generic-credential packages/storage/src/config.ts:51
LOW js-dynamic-code-execution services/api/src/store/scanner.test.ts:32
LOW js-hardcoded-crypto-key services/api/src/store/signing.test.ts:24

Snippets are redacted; ThreatCrush never prints matched credential material.

ralyodio and others added 2 commits October 20, 2026 00:55
…h, retry LaunchServices

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ralyodio
ralyodio merged commit a9fcc9d into main Oct 20, 2026
15 checks passed
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.

1 participant