Skip to content

fix(launcher): parse Exec the way the desktop does, single quotes included - #89

Merged
ralyodio merged 1 commit into
mainfrom
fix-pwa-single-quotes
Aug 30, 2026
Merged

fix(launcher): parse Exec the way the desktop does, single quotes included#89
ralyodio merged 1 commit into
mainfrom
fix-pwa-single-quotes

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Two releases of tron-pwa reported "no TronBrowser web apps" on a machine with
eleven of them. They were in the directory it scans, under names #88 taught it
to match, carrying the --app-id and --user-data-dir it looks for. It could
not read them.

The bug

Flatpak's flextop exports every argument single-quoted:

Exec=flatpak 'run' '--command=/app/bin/chromium' 'io.github.…ungoogled_chromium' '--user-data-dir=/home/…/.tronbrowser' '--profile-directory=Default' '--app-id=fpmog…'

The desktop-entry spec defines only double quotes, and the parser followed the
spec. So '--app-id=fpmog…' came out as a single literal token with an
apostrophe on the front, every startswith("--app-id=") test failed, and the
file was classified as not a web app and skipped whole.

GLib's g_shell_parse_argv — which is what actually launches these entries —
honours single quotes. Being stricter than the launcher meant not seeing files
that work perfectly well for everyone else. The parser now follows GLib:
backslash escapes outside quotes, single quotes literal with no escapes, double
quotes as before.

What was actually killing the app

Worth recording, because it explains why routing through the launcher is the fix
and not just tidiness. That flextop command carries
--user-data-dir=~/.tronbrowser but no --filesystem= grant, so the sandbox
cannot read the profile directory. Chromium starts, fails to open the profile,
and exits a few seconds later — which is what the icon looked like from outside.

The launcher runs flatpak run --filesystem="$DATA" --filesystem="$EXTBASE_SRC" ….
That is the difference between the address bar (works) and the icon (dies).

Verification

Tested against the reported file byte-for-byte: found, rewritten to run the
launcher with app id and profile intact and the flatpak run --command=…
wrapper dropped, and reverted back to the original exactly.

4 new cases including that verbatim file; 24 in the file, 113 in the desktop
suite. Typecheck and lint clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SZXtxiVkXd7rFmvrMYV7Ut

…luded

Two releases of tron-pwa reported "no TronBrowser web apps" on a machine with
eleven of them. They were in the directory it scans, under names it now matches,
carrying the --app-id and --user-data-dir it looks for. It could not read them.

Flatpak's flextop exports every argument single-quoted:

  Exec=flatpak 'run' '--command=/app/bin/chromium' '--app-id=abc…'

The desktop-entry spec defines only double quotes, and the parser followed the
spec -- so `'--app-id=abc…'` came out as one literal token with an apostrophe on
the front, every startswith() test failed, and the file was classified as not a
web app and skipped whole. GLib's g_shell_parse_argv, which is what actually
launches these entries, honours single quotes; being stricter than the launcher
meant not seeing files that work fine for everyone else. Parse like GLib:
backslash escapes outside quotes, single quotes literal, double quotes as
before.

That also makes the launch failure legible. The flextop command carries
--user-data-dir=~/.tronbrowser but no --filesystem grant, so the sandbox cannot
read the profile directory: Chromium starts, cannot open the profile, and exits
a few seconds later. The launcher passes --filesystem="$DATA", which is why the
same app opens from the address bar and dies from its icon -- and why routing
the shortcut through the launcher is the fix rather than a tidy-up.

Verified against the reported file byte-for-byte: found, rewritten to run the
launcher with the app id and profile intact and the flatpak wrapper dropped, and
reverted back to the original exactly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SZXtxiVkXd7rFmvrMYV7Ut
@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

49 finding(s)

MEDIUM: 31 | LOW: 18

Severity Rule Location
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:77
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/sidepanel.js:165
MEDIUM sh-remote-script-execution apps/desktop/launcher/tronbrowser:84
MEDIUM sh-remote-script-execution apps/desktop/launcher/tronbrowser:394
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:138
MEDIUM sh-remote-script-execution apps/web/public/install.sh:143
MEDIUM sh-remote-script-execution apps/web/public/install.sh:242
MEDIUM sh-remote-script-execution apps/web/public/install.sh:260
MEDIUM sh-remote-script-execution apps/web/public/install.sh:820
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 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 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
ralyodio merged commit 9d51e80 into main Aug 30, 2026
8 checks passed
@ralyodio
ralyodio deleted the fix-pwa-single-quotes branch August 30, 2026 15:36
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