sourcemonkey 0.0.0-stage → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +87 -2
- package/dist/bytes.js +37 -0
- package/dist/channel-placeholder.js +5 -0
- package/dist/collection-scan.js +17 -0
- package/dist/collections.html +353 -0
- package/dist/compare.html +358 -0
- package/dist/composed-source.js +205 -0
- package/dist/connect-prompt.html +47 -0
- package/dist/debug/icons.html +211 -0
- package/dist/debug/storage.html +163 -0
- package/dist/debug-log.js +75 -0
- package/dist/diagnostic-location.js +64 -0
- package/dist/eval-hook.js +308 -0
- package/dist/extension/background.js +5263 -0
- package/dist/extension/channel.js +133 -0
- package/dist/extension/code-links.js +187 -0
- package/dist/extension/code-tabs.js +460 -0
- package/dist/extension/collection-dialog.js +619 -0
- package/dist/extension/collection-display.js +322 -0
- package/dist/extension/collections.js +2905 -0
- package/dist/extension/compare.js +867 -0
- package/dist/extension/concurrency.js +186 -0
- package/dist/extension/connect-grants.js +109 -0
- package/dist/extension/connect-prompt-page.js +70 -0
- package/dist/extension/connect-prompt.js +266 -0
- package/dist/extension/copy-button.js +63 -0
- package/dist/extension/copy-dialog.js +502 -0
- package/dist/extension/copy-preference.js +66 -0
- package/dist/extension/debug/icons.js +203 -0
- package/dist/extension/debug/storage.js +365 -0
- package/dist/extension/deep-link.js +77 -0
- package/dist/extension/delete-dialog.js +432 -0
- package/dist/extension/delete-icon.js +40 -0
- package/dist/extension/details-tooltips.js +66 -0
- package/dist/extension/directories.js +679 -0
- package/dist/extension/export-backup.js +407 -0
- package/dist/extension/export-dialog.js +142 -0
- package/dist/extension/file-access.js +74 -0
- package/dist/extension/file-changes.js +346 -0
- package/dist/extension/frame-info.js +85 -0
- package/dist/extension/github-provider.js +336 -0
- package/dist/extension/glyph.js +84 -0
- package/dist/extension/gm-bindings.js +601 -0
- package/dist/extension/gm-download.js +419 -0
- package/dist/extension/gm-menu.js +228 -0
- package/dist/extension/gm-notification.js +141 -0
- package/dist/extension/gm-originator-map.js +23 -0
- package/dist/extension/gm-tab-data.js +121 -0
- package/dist/extension/gm-tab.js +160 -0
- package/dist/extension/gm-url-change.js +111 -0
- package/dist/extension/gm-url-scheme.js +27 -0
- package/dist/extension/gm-values.js +176 -0
- package/dist/extension/gm-window-control.js +104 -0
- package/dist/extension/gm-xhr-headers.js +333 -0
- package/dist/extension/gm-xhr.js +584 -0
- package/dist/extension/injector.js +3145 -0
- package/dist/extension/install-capture.js +277 -0
- package/dist/extension/line-diff.js +233 -0
- package/dist/extension/local-copy.js +560 -0
- package/dist/extension/local-delete.js +276 -0
- package/dist/extension/location-kinds.js +108 -0
- package/dist/extension/log-format.js +158 -0
- package/dist/extension/managed-changes.js +361 -0
- package/dist/extension/managed-items.js +57 -0
- package/dist/extension/match-index.js +375 -0
- package/dist/extension/missing-scripts.js +66 -0
- package/dist/extension/more-menu.js +109 -0
- package/dist/extension/move-dialog.js +197 -0
- package/dist/extension/offscreen.js +37 -0
- package/dist/extension/options.js +504 -0
- package/dist/extension/page-heading.js +170 -0
- package/dist/extension/page-links.js +199 -0
- package/dist/extension/parse-check-client.js +70 -0
- package/dist/extension/parse-check.js +161 -0
- package/dist/extension/parse-sandbox-host.js +172 -0
- package/dist/extension/parse-sandbox.js +175 -0
- package/dist/extension/popup-commands-open.js +41 -0
- package/dist/extension/popup-view.js +387 -0
- package/dist/extension/popup.js +703 -0
- package/dist/extension/prism-userscript.js +53 -0
- package/dist/extension/refresh-error.js +136 -0
- package/dist/extension/refresh-targets.js +160 -0
- package/dist/extension/related-versions.js +1144 -0
- package/dist/extension/resize-observer-loop.js +19 -0
- package/dist/extension/row-cache.js +387 -0
- package/dist/extension/script-blobs.js +413 -0
- package/dist/extension/script-details.js +658 -0
- package/dist/extension/script-enablement.js +285 -0
- package/dist/extension/script-identity.js +310 -0
- package/dist/extension/script-keys.js +54 -0
- package/dist/extension/script-log-id.js +155 -0
- package/dist/extension/script-log.js +290 -0
- package/dist/extension/script-rejection.js +104 -0
- package/dist/extension/script-sites.js +158 -0
- package/dist/extension/script-store.js +3507 -0
- package/dist/extension/script-updater.js +991 -0
- package/dist/extension/script-url-hash.js +61 -0
- package/dist/extension/select-all.js +37 -0
- package/dist/extension/select-open-guard.js +90 -0
- package/dist/extension/site-icon.js +1261 -0
- package/dist/extension/sm-dev-link.js +302 -0
- package/dist/extension/solo-click.js +58 -0
- package/dist/extension/sticky-numbers.js +188 -0
- package/dist/extension/storage-breakdown.js +253 -0
- package/dist/extension/storage-scan.js +86 -0
- package/dist/extension/storage-usage.js +194 -0
- package/dist/extension/structural-keys.js +29 -0
- package/dist/extension/sw-teardown.js +36 -0
- package/dist/extension/tab-status.js +403 -0
- package/dist/extension/toolbar-summary.js +105 -0
- package/dist/extension/user-scripts-access.js +43 -0
- package/dist/extension/userscript.js +3672 -0
- package/dist/extension/value-store.js +204 -0
- package/dist/extension/version-probe-fetch.js +68 -0
- package/dist/extension/worker-client.js +109 -0
- package/dist/extension/worker-ops.js +171 -0
- package/dist/extension/zip-writer.js +24 -0
- package/dist/external-files.js +878 -0
- package/dist/file-loader.js +436 -0
- package/dist/file-locations.js +439 -0
- package/dist/generated-wrappers.js +5 -0
- package/dist/github-auth.js +148 -0
- package/dist/github-urls.js +46 -0
- package/dist/gm-api-catalog.js +217 -0
- package/dist/gm-connect.js +273 -0
- package/dist/gm-xhr-types.js +5 -0
- package/dist/http-read.js +142 -0
- package/dist/icons/icon-128.png +0 -0
- package/dist/icons/icon-16.png +0 -0
- package/dist/icons/icon-48.png +0 -0
- package/dist/local-file-overrides.js +558 -0
- package/dist/manifest.json +38 -0
- package/dist/markup-response.js +126 -0
- package/dist/match-targets.js +305 -0
- package/dist/menu-captions.js +22 -0
- package/dist/offscreen.html +39 -0
- package/dist/options.html +197 -0
- package/dist/parse-check-protocol.js +51 -0
- package/dist/parse-location.js +171 -0
- package/dist/parse-sandbox.html +56 -0
- package/dist/phase-timing.js +155 -0
- package/dist/popup.html +197 -0
- package/dist/public-suffixes.js +6957 -0
- package/dist/run-context.js +31 -0
- package/dist/runtime-messages.js +34 -0
- package/dist/sandboxed-page.js +35 -0
- package/dist/script-build.js +787 -0
- package/dist/script-display.js +383 -0
- package/dist/script-icon.js +43 -0
- package/dist/script-links.js +204 -0
- package/dist/script-source-url.js +214 -0
- package/dist/script-world.js +65 -0
- package/dist/sm-dev-protocol.js +84 -0
- package/dist/source-map.js +177 -0
- package/dist/stack-link.js +138 -0
- package/dist/styles.css +825 -0
- package/dist/unsafe-window-use.js +229 -0
- package/dist/url-match.js +734 -0
- package/dist/userscript-header.js +248 -0
- package/dist/userscript.html +1165 -0
- package/dist/vendor/fflate.LICENSE +21 -0
- package/dist/vendor/fflate.js +2692 -0
- package/dist/vendor/prism/prism-line-numbers.css +1 -0
- package/dist/vendor/prism/prism-line-numbers.js +1 -0
- package/dist/vendor/prism/prism.css +1 -0
- package/dist/vendor/prism/prism.js +1946 -0
- package/dist/version-compare.js +141 -0
- package/dist/version-probe.js +120 -0
- package/lib/build-info.json +1 -0
- package/lib/bytes.d.ts +3 -0
- package/lib/bytes.js +37 -0
- package/lib/channel-placeholder.d.ts +1 -0
- package/lib/channel-placeholder.js +5 -0
- package/lib/collection-scan.d.ts +8 -0
- package/lib/collection-scan.js +17 -0
- package/lib/composed-source.d.ts +28 -0
- package/lib/composed-source.js +205 -0
- package/lib/debug-log.d.ts +9 -0
- package/lib/debug-log.js +75 -0
- package/lib/diagnostic-location.d.ts +8 -0
- package/lib/diagnostic-location.js +64 -0
- package/lib/eval-hook.d.ts +34 -0
- package/lib/eval-hook.js +308 -0
- package/lib/external-files.d.ts +111 -0
- package/lib/external-files.js +878 -0
- package/lib/file-loader.d.ts +48 -0
- package/lib/file-loader.js +436 -0
- package/lib/file-locations.d.ts +44 -0
- package/lib/file-locations.js +439 -0
- package/lib/generated-wrappers.d.ts +11 -0
- package/lib/generated-wrappers.js +5 -0
- package/lib/github-auth.d.ts +12 -0
- package/lib/github-auth.js +148 -0
- package/lib/github-urls.d.ts +1 -0
- package/lib/github-urls.js +46 -0
- package/lib/gm-api-catalog.d.ts +24 -0
- package/lib/gm-api-catalog.js +217 -0
- package/lib/gm-connect.d.ts +34 -0
- package/lib/gm-connect.js +273 -0
- package/lib/gm-xhr-types.d.ts +68 -0
- package/lib/gm-xhr-types.js +5 -0
- package/lib/harness/browser-extensions.d.ts +73 -0
- package/lib/harness/browser-extensions.js +285 -0
- package/lib/harness/browser-lang.d.ts +20 -0
- package/lib/harness/browser-lang.js +86 -0
- package/lib/harness/browser-launch.d.ts +14 -0
- package/lib/harness/browser-launch.js +184 -0
- package/lib/harness/checks.d.ts +110 -0
- package/lib/harness/checks.js +321 -0
- package/lib/harness/cli.d.ts +2 -0
- package/lib/harness/cli.js +2259 -0
- package/lib/harness/command-args.d.ts +91 -0
- package/lib/harness/command-args.js +369 -0
- package/lib/harness/command-lines.d.ts +80 -0
- package/lib/harness/command-lines.js +180 -0
- package/lib/harness/command-list.d.ts +206 -0
- package/lib/harness/command-list.js +1475 -0
- package/lib/harness/console-commands.d.ts +463 -0
- package/lib/harness/console-commands.js +3216 -0
- package/lib/harness/download-watch.d.ts +21 -0
- package/lib/harness/download-watch.js +156 -0
- package/lib/harness/extension-backend.d.ts +41 -0
- package/lib/harness/extension-backend.js +100 -0
- package/lib/harness/extension-host.d.ts +112 -0
- package/lib/harness/extension-host.js +552 -0
- package/lib/harness/extension-launch.d.ts +67 -0
- package/lib/harness/extension-launch.js +285 -0
- package/lib/harness/extension-link.d.ts +315 -0
- package/lib/harness/extension-link.js +607 -0
- package/lib/harness/external-manager.d.ts +146 -0
- package/lib/harness/external-manager.js +414 -0
- package/lib/harness/fixture.d.ts +165 -0
- package/lib/harness/fixture.js +461 -0
- package/lib/harness/frame-sessions.d.ts +71 -0
- package/lib/harness/frame-sessions.js +248 -0
- package/lib/harness/frames.d.ts +68 -0
- package/lib/harness/frames.js +216 -0
- package/lib/harness/help-format.d.ts +17 -0
- package/lib/harness/help-format.js +127 -0
- package/lib/harness/host.d.ts +352 -0
- package/lib/harness/host.js +423 -0
- package/lib/harness/index.d.ts +8 -0
- package/lib/harness/index.js +10 -0
- package/lib/harness/input-file.d.ts +18 -0
- package/lib/harness/input-file.js +61 -0
- package/lib/harness/json-output.d.ts +565 -0
- package/lib/harness/json-output.js +71 -0
- package/lib/harness/manager-actions.d.ts +21 -0
- package/lib/harness/manager-actions.js +129 -0
- package/lib/harness/manager-commands.d.ts +142 -0
- package/lib/harness/manager-commands.js +1196 -0
- package/lib/harness/manager-fetch.d.ts +33 -0
- package/lib/harness/manager-fetch.js +239 -0
- package/lib/harness/managers.d.ts +24 -0
- package/lib/harness/managers.js +27 -0
- package/lib/harness/output-style.d.ts +125 -0
- package/lib/harness/output-style.js +322 -0
- package/lib/harness/page-commands.d.ts +134 -0
- package/lib/harness/page-commands.js +1141 -0
- package/lib/harness/page-output.d.ts +67 -0
- package/lib/harness/page-output.js +139 -0
- package/lib/harness/page-watch.d.ts +171 -0
- package/lib/harness/page-watch.js +607 -0
- package/lib/harness/parse-check-node.d.ts +3 -0
- package/lib/harness/parse-check-node.js +132 -0
- package/lib/harness/path-args.d.ts +22 -0
- package/lib/harness/path-args.js +148 -0
- package/lib/harness/playwright-chromium.d.ts +16 -0
- package/lib/harness/playwright-chromium.js +86 -0
- package/lib/harness/prepare.d.ts +168 -0
- package/lib/harness/prepare.js +364 -0
- package/lib/harness/prompt-editor.d.ts +17 -0
- package/lib/harness/prompt-editor.js +354 -0
- package/lib/harness/prompt-history.d.ts +13 -0
- package/lib/harness/prompt-history.js +89 -0
- package/lib/harness/rebuild-advice.d.ts +6 -0
- package/lib/harness/rebuild-advice.js +39 -0
- package/lib/harness/run-log.d.ts +47 -0
- package/lib/harness/run-log.js +140 -0
- package/lib/harness/run-logs.d.ts +132 -0
- package/lib/harness/run-logs.js +241 -0
- package/lib/harness/run.d.ts +194 -0
- package/lib/harness/run.js +1973 -0
- package/lib/harness/runs.d.ts +229 -0
- package/lib/harness/runs.js +726 -0
- package/lib/harness/save-html.d.ts +39 -0
- package/lib/harness/save-html.js +89 -0
- package/lib/harness/saved-pages.d.ts +120 -0
- package/lib/harness/saved-pages.js +275 -0
- package/lib/harness/script-mark.d.ts +17 -0
- package/lib/harness/script-mark.js +56 -0
- package/lib/harness/snapshot.d.ts +143 -0
- package/lib/harness/snapshot.js +474 -0
- package/lib/harness/stuck-tabs.d.ts +19 -0
- package/lib/harness/stuck-tabs.js +131 -0
- package/lib/harness/tab-refs.d.ts +20 -0
- package/lib/harness/tab-refs.js +80 -0
- package/lib/harness/tampermonkey.d.ts +71 -0
- package/lib/harness/tampermonkey.js +356 -0
- package/lib/harness/tm-ids.d.ts +18 -0
- package/lib/harness/tm-ids.js +88 -0
- package/lib/harness/violentmonkey.d.ts +34 -0
- package/lib/harness/violentmonkey.js +162 -0
- package/lib/harness/wait.d.ts +77 -0
- package/lib/harness/wait.js +458 -0
- package/lib/http-read.d.ts +30 -0
- package/lib/http-read.js +142 -0
- package/lib/local-file-overrides.d.ts +35 -0
- package/lib/local-file-overrides.js +558 -0
- package/lib/manifest.json +38 -0
- package/lib/markup-response.d.ts +11 -0
- package/lib/markup-response.js +126 -0
- package/lib/match-targets.d.ts +18 -0
- package/lib/match-targets.js +305 -0
- package/lib/menu-captions.d.ts +1 -0
- package/lib/menu-captions.js +22 -0
- package/lib/parse-check-protocol.d.ts +27 -0
- package/lib/parse-check-protocol.js +51 -0
- package/lib/parse-location.d.ts +12 -0
- package/lib/parse-location.js +171 -0
- package/lib/phase-timing.d.ts +12 -0
- package/lib/phase-timing.js +155 -0
- package/lib/public-suffixes.d.ts +1 -0
- package/lib/public-suffixes.js +6957 -0
- package/lib/run-context.d.ts +2 -0
- package/lib/run-context.js +31 -0
- package/lib/runtime-messages.d.ts +10 -0
- package/lib/runtime-messages.js +34 -0
- package/lib/sandboxed-page.d.ts +5 -0
- package/lib/sandboxed-page.js +35 -0
- package/lib/script-build.d.ts +111 -0
- package/lib/script-build.js +787 -0
- package/lib/script-display.d.ts +51 -0
- package/lib/script-display.js +383 -0
- package/lib/script-icon.d.ts +16 -0
- package/lib/script-icon.js +43 -0
- package/lib/script-links.d.ts +24 -0
- package/lib/script-links.js +204 -0
- package/lib/script-source-url.d.ts +8 -0
- package/lib/script-source-url.js +214 -0
- package/lib/script-world.d.ts +6 -0
- package/lib/script-world.js +65 -0
- package/lib/sm-dev-protocol.d.ts +251 -0
- package/lib/sm-dev-protocol.js +84 -0
- package/lib/source-map.d.ts +32 -0
- package/lib/source-map.js +177 -0
- package/lib/stack-link.d.ts +15 -0
- package/lib/stack-link.js +138 -0
- package/lib/unsafe-window-use.d.ts +1 -0
- package/lib/unsafe-window-use.js +229 -0
- package/lib/url-match.d.ts +40 -0
- package/lib/url-match.js +734 -0
- package/lib/userscript-header.d.ts +33 -0
- package/lib/userscript-header.js +248 -0
- package/lib/version-compare.d.ts +6 -0
- package/lib/version-compare.js +141 -0
- package/lib/version-probe.d.ts +17 -0
- package/lib/version-probe.js +120 -0
- package/package.json +55 -3
- package/skills/SourceMonkey-dev/SKILL.md +868 -0
- package/skills/SourceMonkey-dev/references/cdp.md +293 -0
- package/skills/SourceMonkey-dev/references/commands.md +297 -0
- package/skills/SourceMonkey-dev/references/other-managers.md +63 -0
- package/skills/SourceMonkey-dev/references/specs.md +46 -0
- package/skills/SourceMonkey-friction/SKILL.md +103 -0
- package/skills/SourceMonkey-friction/references/template.md +59 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// Does a script's own source reference `unsafeWindow` without granting
|
|
2
|
+
// it?
|
|
3
|
+
//
|
|
4
|
+
// `@grant unsafeWindow` is how a script is *supposed* to ask for the
|
|
5
|
+
// page's window, and it is what gets the script the binding. Plenty of
|
|
6
|
+
// real scripts never declare it: `unsafeWindow` is implicitly available under Tampermonkey and
|
|
7
|
+
// Violentmonkey — neither keys it off a grant line, measured under TM
|
|
8
|
+
// 5.5.0 and VM 2.49.0 by `tests/examples/unsafe-window/ungranted.user.js`
|
|
9
|
+
// — so an author who only ever tested there has no reason to add one.
|
|
10
|
+
//
|
|
11
|
+
// Measured over the GreasyFork top 2000: 112 scripts use `unsafeWindow`
|
|
12
|
+
// with no grant for it. Without the binding, the identifier is a
|
|
13
|
+
// `ReferenceError`, so honoring the reference is what makes those
|
|
14
|
+
// scripts run at all.
|
|
15
|
+
//
|
|
16
|
+
// This is a text scan, not a parse. We have no JS parser in the
|
|
17
|
+
// extension (the install-time check compiles with `new Function` in a
|
|
18
|
+
// sandboxed page and reports only a verdict — see docs/parse-check.md),
|
|
19
|
+
// and the answer is needed on the storage row. So:
|
|
20
|
+
//
|
|
21
|
+
// - Comments and string / template literals are stripped first, so a
|
|
22
|
+
// mention in a comment or a log message gets no binding. That was
|
|
23
|
+
// 13 of the 126 ungranted mentions in the corpus.
|
|
24
|
+
// - A property key, a `#private` member and a `foo.unsafeWindow`
|
|
25
|
+
// access don't count. A false positive only adds an unused
|
|
26
|
+
// `window` alias.
|
|
27
|
+
// - A regex literal is NOT recognized. `/['"]/` therefore opens a
|
|
28
|
+
// string state that runs to the next quote, and a literal ending in
|
|
29
|
+
// `\/\/` reads as a line comment — either can swallow real code.
|
|
30
|
+
// Normally that costs a missed reference, so the script gets no
|
|
31
|
+
// binding. If it swallows a DECLARATION while leaving a use
|
|
32
|
+
// visible, the script gets a binding it shadows anyway, which is
|
|
33
|
+
// harmless. No corpus script hits it.
|
|
34
|
+
// - A script that DECLARES the name — `const unsafeWindow =
|
|
35
|
+
// window.wrappedJSObject || window;`, a real cross-browser idiom —
|
|
36
|
+
// answers false, including in a declarator list or a destructuring
|
|
37
|
+
// pattern. Its references read its own binding, never ours. (Our binding would be
|
|
38
|
+
// harmless beside it: the user program runs in a nested scope, so
|
|
39
|
+
// the script's declaration shadows it. See wrapCombinedEntry in
|
|
40
|
+
// injector.ts.) The check is scope-blind, so a declaration inside a
|
|
41
|
+
// function suppresses the whole script: that direction only costs
|
|
42
|
+
// the feature.
|
|
43
|
+
//
|
|
44
|
+
// Only the script's own body is scanned, not its `@require` bodies: the
|
|
45
|
+
// requires arrive on a later pipeline step (`attachFiles`). See
|
|
46
|
+
// TODO.md.
|
|
47
|
+
const IDENT = /[$\w]/;
|
|
48
|
+
// Strip comments and quoted text, leaving a space in their place so
|
|
49
|
+
// adjacent tokens can't merge into a new identifier.
|
|
50
|
+
//
|
|
51
|
+
// Written to jump between interesting positions rather than walk every
|
|
52
|
+
// character: this runs on every script body that mentions the name, at
|
|
53
|
+
// load time, beside the row's SHA-256. On the corpus's largest body
|
|
54
|
+
// (1.8 MB) the per-character form cost ~200 ms, more than 20x that hash.
|
|
55
|
+
function stripQuotedAndComments(src) {
|
|
56
|
+
// A fresh regex per call — `lastIndex` is state, and this function
|
|
57
|
+
// recurses into template substitutions.
|
|
58
|
+
const delim = /\/\/|\/\*|["'`]/g;
|
|
59
|
+
const parts = [];
|
|
60
|
+
const n = src.length;
|
|
61
|
+
let kept = 0;
|
|
62
|
+
for (let m = delim.exec(src); m !== null; m = delim.exec(src)) {
|
|
63
|
+
const from = m.index;
|
|
64
|
+
let after;
|
|
65
|
+
let replacement = ' ';
|
|
66
|
+
if (m[0] === '//') {
|
|
67
|
+
const nl = src.indexOf('\n', from);
|
|
68
|
+
after = nl === -1 ? n : nl;
|
|
69
|
+
}
|
|
70
|
+
else if (m[0] === '/*') {
|
|
71
|
+
const close = src.indexOf('*/', from + 2);
|
|
72
|
+
after = close === -1 ? n : close + 2;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const quote = m[0];
|
|
76
|
+
// The code found inside this template's `${ ... }` substitutions.
|
|
77
|
+
const inner = [];
|
|
78
|
+
let i = from + 1;
|
|
79
|
+
while (i < n) {
|
|
80
|
+
if (src[i] === '\\') {
|
|
81
|
+
i += 2;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (src[i] === quote) {
|
|
85
|
+
i += 1;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
// A substitution holds real code, so scan it as code rather
|
|
89
|
+
// than as text.
|
|
90
|
+
if (quote === '`' && src[i] === '$' && src[i + 1] === '{') {
|
|
91
|
+
let depth = 1;
|
|
92
|
+
i += 2;
|
|
93
|
+
const innerStart = i;
|
|
94
|
+
while (i < n && depth > 0) {
|
|
95
|
+
if (src[i] === '{')
|
|
96
|
+
depth += 1;
|
|
97
|
+
else if (src[i] === '}')
|
|
98
|
+
depth -= 1;
|
|
99
|
+
i += 1;
|
|
100
|
+
}
|
|
101
|
+
inner.push(stripQuotedAndComments(src.slice(innerStart, i - 1)));
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
i += 1;
|
|
105
|
+
}
|
|
106
|
+
after = i;
|
|
107
|
+
if (inner.length > 0)
|
|
108
|
+
replacement = ` ${inner.join(' ')} `;
|
|
109
|
+
}
|
|
110
|
+
if (from > kept)
|
|
111
|
+
parts.push(src.slice(kept, from));
|
|
112
|
+
parts.push(replacement);
|
|
113
|
+
kept = after;
|
|
114
|
+
delim.lastIndex = after;
|
|
115
|
+
}
|
|
116
|
+
if (n > kept)
|
|
117
|
+
parts.push(src.slice(kept, n));
|
|
118
|
+
return parts.join('');
|
|
119
|
+
}
|
|
120
|
+
// A free `unsafeWindow` — not `foo.unsafeWindow`, not `unsafeWindows`,
|
|
121
|
+
// not a member the source happens to have named that.
|
|
122
|
+
function hasFreeReference(code) {
|
|
123
|
+
let from = 0;
|
|
124
|
+
for (;;) {
|
|
125
|
+
const at = code.indexOf('unsafeWindow', from);
|
|
126
|
+
if (at === -1)
|
|
127
|
+
return false;
|
|
128
|
+
from = at + 'unsafeWindow'.length;
|
|
129
|
+
if (IDENT.test(code[from] ?? ''))
|
|
130
|
+
continue;
|
|
131
|
+
// Immediately preceded by an identifier character → the tail of a
|
|
132
|
+
// longer name (`myunsafeWindow`). Whitespace in between means a
|
|
133
|
+
// separate token, which `typeof unsafeWindow` needs to pass.
|
|
134
|
+
if (IDENT.test(code[at - 1] ?? ''))
|
|
135
|
+
continue;
|
|
136
|
+
// Walk back over whitespace: `foo\n .unsafeWindow` is a property,
|
|
137
|
+
// and `#unsafeWindow` is a private class member.
|
|
138
|
+
let before = at - 1;
|
|
139
|
+
while (before >= 0 && /\s/.test(code[before]))
|
|
140
|
+
before -= 1;
|
|
141
|
+
if (code[before] === '.' || code[before] === '#')
|
|
142
|
+
continue;
|
|
143
|
+
// Followed by `:` → a property key (`{ unsafeWindow: window }`) or a
|
|
144
|
+
// label, which declares a name rather than reading the page's. This
|
|
145
|
+
// also skips `cond ? unsafeWindow : other`, and that is the trade we
|
|
146
|
+
// want: a script using the name in a ternary almost always uses it
|
|
147
|
+
// somewhere else too, while a key is the whole mention.
|
|
148
|
+
let next = from;
|
|
149
|
+
while (next < code.length && /\s/.test(code[next]))
|
|
150
|
+
next += 1;
|
|
151
|
+
if (code[next] === ':')
|
|
152
|
+
continue;
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// `function unsafeWindow(` / `class unsafeWindow`.
|
|
157
|
+
const DECLARES_AS_CALLABLE = /(?:^|[^$\w.])(?:function|class)\s+unsafeWindow(?![$\w])/;
|
|
158
|
+
const KEYWORD = /(?:^|[^$\w.])(?:var|let|const)(?![$\w])/g;
|
|
159
|
+
// How far past a `var` / `let` / `const` to keep looking for the end of
|
|
160
|
+
// its declarator list. A statement without a `;` (ASI) would otherwise
|
|
161
|
+
// run the scan into the rest of the file; over-running only ever
|
|
162
|
+
// over-suppresses, but there is no reason to pay for it.
|
|
163
|
+
const DECLARATOR_SPAN = 2000;
|
|
164
|
+
// Is `unsafeWindow` a NAME BEING BOUND anywhere in this source, rather
|
|
165
|
+
// than a value being read? A script that binds the name reads its own
|
|
166
|
+
// value, so it gets neither our binding nor the move to MAIN world.
|
|
167
|
+
//
|
|
168
|
+
// Walks each `var` / `let` / `const` declarator list, tracking bracket
|
|
169
|
+
// depth and whether the current declarator has passed its `=`:
|
|
170
|
+
//
|
|
171
|
+
// const unsafeWindow = window → bound (before any `=`)
|
|
172
|
+
// let uw = window, unsafeWindow=uw → bound (the `,` starts a declarator)
|
|
173
|
+
// const { unsafeWindow } = window → bound (pattern, before the `=`)
|
|
174
|
+
// const app = unsafeWindow.thing → read (after the `=`) — by far the
|
|
175
|
+
// commonest real use, and the one
|
|
176
|
+
// thing this must not claim
|
|
177
|
+
// const xs = [1, unsafeWindow] → read (bracketed, after the `=`)
|
|
178
|
+
//
|
|
179
|
+
// Scope-blind on purpose: a declaration inside a function suppresses the
|
|
180
|
+
// whole script. That direction only costs the feature.
|
|
181
|
+
function declaresBinding(code) {
|
|
182
|
+
if (DECLARES_AS_CALLABLE.test(code))
|
|
183
|
+
return true;
|
|
184
|
+
KEYWORD.lastIndex = 0;
|
|
185
|
+
for (let m = KEYWORD.exec(code); m !== null; m = KEYWORD.exec(code)) {
|
|
186
|
+
const limit = Math.min(code.length, m.index + DECLARATOR_SPAN);
|
|
187
|
+
let depth = 0;
|
|
188
|
+
let afterEquals = false;
|
|
189
|
+
let i = KEYWORD.lastIndex;
|
|
190
|
+
while (i < limit) {
|
|
191
|
+
const c = code[i];
|
|
192
|
+
if (c === '(' || c === '[' || c === '{')
|
|
193
|
+
depth += 1;
|
|
194
|
+
else if (c === ')' || c === ']' || c === '}') {
|
|
195
|
+
if (depth === 0)
|
|
196
|
+
break;
|
|
197
|
+
depth -= 1;
|
|
198
|
+
}
|
|
199
|
+
else if (c === ';' && depth === 0)
|
|
200
|
+
break;
|
|
201
|
+
else if (c === ',' && depth === 0)
|
|
202
|
+
afterEquals = false;
|
|
203
|
+
else if (c === '=' && code[i + 1] !== '=' && !'=!<>'.includes(code[i - 1] ?? '')) {
|
|
204
|
+
afterEquals = true;
|
|
205
|
+
}
|
|
206
|
+
else if (c === 'u' && code.startsWith('unsafeWindow', i)) {
|
|
207
|
+
const after = code[i + 'unsafeWindow'.length] ?? '';
|
|
208
|
+
const prev = code[i - 1] ?? '';
|
|
209
|
+
if (!IDENT.test(after) && !IDENT.test(prev) && prev !== '.') {
|
|
210
|
+
if (!afterEquals)
|
|
211
|
+
return true;
|
|
212
|
+
i += 'unsafeWindow'.length;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
i += 1;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
export function sourceUsesUnsafeWindow(bodyText) {
|
|
222
|
+
// The overwhelmingly common answer, without paying for the scan.
|
|
223
|
+
if (!bodyText || bodyText.indexOf('unsafeWindow') === -1)
|
|
224
|
+
return false;
|
|
225
|
+
const code = stripQuotedAndComments(bodyText);
|
|
226
|
+
if (declaresBinding(code))
|
|
227
|
+
return false;
|
|
228
|
+
return hasFreeReference(code);
|
|
229
|
+
}
|