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,148 @@
|
|
|
1
|
+
// GitHub personal access token storage + helper for attaching the
|
|
2
|
+
// `Authorization: Bearer <token>` header onto requests that target a
|
|
3
|
+
// GitHub host (so we can fetch private repos and lift the
|
|
4
|
+
// unauthenticated 60/hour rate limit to 5000/hour).
|
|
5
|
+
//
|
|
6
|
+
// Mirrors `debug-log.ts`'s shape: one chrome.storage.local key, a
|
|
7
|
+
// cached in-memory copy, a `load…` for boot-time hydration, and an
|
|
8
|
+
// `install…Listener` for live updates without an SW restart.
|
|
9
|
+
//
|
|
10
|
+
// Hosts we attach the header to:
|
|
11
|
+
// - api.github.com (Contents API, repo metadata)
|
|
12
|
+
// - raw.githubusercontent.com (raw bytes for blob URLs we rewrite to)
|
|
13
|
+
// Any other URL passes through untouched. Sending the header to
|
|
14
|
+
// non-GitHub hosts would leak the token, so the gate is strict.
|
|
15
|
+
//
|
|
16
|
+
// Notable omission: `github.com/<o>/<r>/raw/<ref>/<path>` (the "Raw"
|
|
17
|
+
// button URL). GitHub serves a 302 to raw.githubusercontent.com on
|
|
18
|
+
// that route, and the Fetch spec strips the `Authorization` header
|
|
19
|
+
// on cross-origin redirects — so the auth header would never reach
|
|
20
|
+
// raw, and the github.com hop itself doesn't honour our PAT for the
|
|
21
|
+
// bytes either. `normalizeGithubInput` rewrites `/blob/` and bare-
|
|
22
|
+
// repo URLs to the raw form at add time; users with a `/raw/` URL
|
|
23
|
+
// in hand can paste either the `/blob/` form (auto-rewritten) or the
|
|
24
|
+
// `raw.githubusercontent.com` form directly.
|
|
25
|
+
export const GITHUB_AUTH_TOKEN_KEY = 'githubAuthToken';
|
|
26
|
+
let cachedToken = '';
|
|
27
|
+
export function getGithubAuthToken() {
|
|
28
|
+
return cachedToken;
|
|
29
|
+
}
|
|
30
|
+
// Test/debug hook. Production callers should toggle the storage key
|
|
31
|
+
// instead so the change persists and is observed via onChanged.
|
|
32
|
+
export function _setGithubAuthTokenForTests(value) {
|
|
33
|
+
cachedToken = value;
|
|
34
|
+
}
|
|
35
|
+
export async function loadGithubAuthToken() {
|
|
36
|
+
try {
|
|
37
|
+
const got = await chrome.storage.local.get(GITHUB_AUTH_TOKEN_KEY);
|
|
38
|
+
const raw = got[GITHUB_AUTH_TOKEN_KEY];
|
|
39
|
+
cachedToken = typeof raw === 'string' ? raw : '';
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
cachedToken = '';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// The load, memoized. A service worker that woke up to answer a fetch
|
|
46
|
+
// request has a startup read in flight; a caller that needs the token
|
|
47
|
+
// to be *there* awaits this instead of racing it. Subsequent changes
|
|
48
|
+
// arrive through the onChanged listener below, so one load is enough.
|
|
49
|
+
let loadOnce = null;
|
|
50
|
+
export function ensureGithubAuthTokenLoaded() {
|
|
51
|
+
if (!loadOnce)
|
|
52
|
+
loadOnce = loadGithubAuthToken();
|
|
53
|
+
return loadOnce;
|
|
54
|
+
}
|
|
55
|
+
// The worker's `writeSetting` publishes the token at once, so a refresh
|
|
56
|
+
// it runs next doesn't wait for the change event.
|
|
57
|
+
export function setGithubAuthToken(token) {
|
|
58
|
+
cachedToken = token;
|
|
59
|
+
}
|
|
60
|
+
export function installGithubAuthListener() {
|
|
61
|
+
chrome.storage.onChanged.addListener((changes, areaName) => {
|
|
62
|
+
if (areaName !== 'local')
|
|
63
|
+
return;
|
|
64
|
+
const change = changes[GITHUB_AUTH_TOKEN_KEY];
|
|
65
|
+
if (!change)
|
|
66
|
+
return;
|
|
67
|
+
cachedToken = typeof change.newValue === 'string' ? change.newValue : '';
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
// True if the URL targets a GitHub-controlled host we'd want to
|
|
71
|
+
// authenticate against. Pure function — exported for unit tests.
|
|
72
|
+
export function isGithubAuthUrl(url) {
|
|
73
|
+
let parsed;
|
|
74
|
+
try {
|
|
75
|
+
parsed = new URL(url);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const host = parsed.hostname.toLowerCase();
|
|
81
|
+
if (host === 'api.github.com')
|
|
82
|
+
return true;
|
|
83
|
+
if (host === 'raw.githubusercontent.com')
|
|
84
|
+
return true;
|
|
85
|
+
// `github.com` itself is intentionally NOT in the gate — the only
|
|
86
|
+
// bytes-serving route on that host (`/<o>/<r>/raw/...`) 302s to
|
|
87
|
+
// raw.githubusercontent.com, and the Fetch spec strips
|
|
88
|
+
// `Authorization` on cross-origin redirects. See the module header.
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
// Return the `Authorization` header (and the `X-GitHub-Api-Version`
|
|
92
|
+
// pinning header) for a GitHub URL when a token is set; an empty
|
|
93
|
+
// object otherwise. Safe to spread into a `headers` object that may
|
|
94
|
+
// already carry an `Accept`. Callers should ALWAYS go through this
|
|
95
|
+
// helper rather than reading `cachedToken` directly so the host gate
|
|
96
|
+
// can't be accidentally skipped.
|
|
97
|
+
export function githubAuthHeaders(url) {
|
|
98
|
+
if (!cachedToken)
|
|
99
|
+
return {};
|
|
100
|
+
if (!isGithubAuthUrl(url))
|
|
101
|
+
return {};
|
|
102
|
+
return {
|
|
103
|
+
Authorization: `Bearer ${cachedToken}`,
|
|
104
|
+
// Pin the REST API version. Optional for the endpoints we hit
|
|
105
|
+
// today, but cheap insurance against a future shape change.
|
|
106
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// True when a request to this URL would actually carry the GitHub
|
|
110
|
+
// auth header (URL is GitHub-eligible AND a token is configured).
|
|
111
|
+
// Same predicate `githubAuthHeaders` uses; exposed so log/UI callers
|
|
112
|
+
// can mirror its decision without re-running the header build.
|
|
113
|
+
export function isGithubAuthInUse(url) {
|
|
114
|
+
if (!cachedToken)
|
|
115
|
+
return false;
|
|
116
|
+
return isGithubAuthUrl(url);
|
|
117
|
+
}
|
|
118
|
+
// True when a *collection URL* (the stored collectionPath, not a
|
|
119
|
+
// per-fetch URL) describes content SourceMonkey reaches through GitHub
|
|
120
|
+
// — covers the github-dir case where `collectionPath` is a
|
|
121
|
+
// `github.com/<o>/<r>/tree/...` page URL but the actual scan + per-
|
|
122
|
+
// script fetches go to api.github.com + raw.githubusercontent.com.
|
|
123
|
+
// Returns true iff a token is configured AND the collection URL is
|
|
124
|
+
// recognisably GitHub. Used by the collection-refresh log line.
|
|
125
|
+
export function isGithubAuthInUseForCollection(collectionPath) {
|
|
126
|
+
if (!cachedToken)
|
|
127
|
+
return false;
|
|
128
|
+
if (isGithubAuthUrl(collectionPath))
|
|
129
|
+
return true;
|
|
130
|
+
// github.com page URLs (`/blob/`, `/tree/`, bare repo) aren't
|
|
131
|
+
// fetched directly — but a github-dir collection resolves to authed
|
|
132
|
+
// api.github.com + raw.githubusercontent.com calls. Recognise the
|
|
133
|
+
// github.com host so those collections get the suffix too.
|
|
134
|
+
try {
|
|
135
|
+
const host = new URL(collectionPath).hostname.toLowerCase();
|
|
136
|
+
return host === 'github.com';
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Log-line suffix used by the updater so the SW console makes it
|
|
143
|
+
// obvious when a collection refresh / per-script check is going out
|
|
144
|
+
// authenticated. Empty string when no token would apply, so callers
|
|
145
|
+
// can unconditionally `${label}${githubTokenLogSuffix(url)}`.
|
|
146
|
+
export function githubTokenLogSuffix(url) {
|
|
147
|
+
return isGithubAuthInUseForCollection(url) ? ' (with GitHub token)' : '';
|
|
148
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// A GitHub raw URL's page on github.com. Its own module so code that
|
|
2
|
+
// only shows links (match-targets.ts) needn't load the GitHub provider.
|
|
3
|
+
// Reverse of `githubFileUrlToRaw` (github-provider.ts): take a
|
|
4
|
+
// raw-content GitHub URL and return its
|
|
5
|
+
// `github.com/<o>/<r>/blob/<ref>/<path>` counterpart — the
|
|
6
|
+
// page a human would open in a browser. Used wherever the UI surfaces
|
|
7
|
+
// a github URL for clicking (collections-page bubble, viewer Location
|
|
8
|
+
// row): the raw URL is what we fetch from, but the blob URL is what
|
|
9
|
+
// the user wants to see.
|
|
10
|
+
//
|
|
11
|
+
// "Raw" here covers both hosts GitHub serves raw bytes from:
|
|
12
|
+
// - `raw.githubusercontent.com/<o>/<r>/[refs/<type>/]<ref>/<path>`
|
|
13
|
+
// - `github.com/<o>/<r>/raw/[refs/<type>/]<ref>/<path>` (the form
|
|
14
|
+
// produced by github.com's own "Raw" button — it 302s to the
|
|
15
|
+
// `raw.githubusercontent.com` host but we may store the URL in
|
|
16
|
+
// this form when the user pastes it directly, or when a manifest
|
|
17
|
+
// entry resolves to a URL in this shape).
|
|
18
|
+
//
|
|
19
|
+
// The optional `/refs/<type>/` segment is the new-style raw URL.
|
|
20
|
+
// `<type>` is typically `heads` (branch) but can also be `tags` or
|
|
21
|
+
// `pull` — we accept any single segment there so tag URLs map
|
|
22
|
+
// correctly to `blob/<tag>/<path>`. Both stripped shapes resolve to
|
|
23
|
+
// the same content.
|
|
24
|
+
//
|
|
25
|
+
// Limitation shared with github-provider.ts: branch names
|
|
26
|
+
// containing `/` (e.g. `feature/foo`) are not supported — the
|
|
27
|
+
// first ref segment is taken and the rest folded into the path.
|
|
28
|
+
//
|
|
29
|
+
// Returns null for any URL that isn't a recognised raw URL — callers
|
|
30
|
+
// fall back to the original URL.
|
|
31
|
+
//
|
|
32
|
+
// Query strings + fragments get stripped — they don't carry over to
|
|
33
|
+
// the github.com page (a `?token=…` is raw-only; an `#L42` fragment
|
|
34
|
+
// would point at the wrong viewer anchor).
|
|
35
|
+
export function githubRawToBlobUrl(rawUrl) {
|
|
36
|
+
// Two regexes (rather than one with alternation) because owner/repo
|
|
37
|
+
// sit at different positions in the two shapes.
|
|
38
|
+
let m = /^https?:\/\/raw\.githubusercontent\.com\/([^\/]+)\/([^\/]+)\/(?:refs\/[^\/]+\/)?([^\/]+)\/([^?#]+)/i.exec(rawUrl);
|
|
39
|
+
if (!m) {
|
|
40
|
+
m = /^https?:\/\/github\.com\/([^\/]+)\/([^\/]+)\/raw\/(?:refs\/[^\/]+\/)?([^\/]+)\/([^?#]+)/i.exec(rawUrl);
|
|
41
|
+
}
|
|
42
|
+
if (!m)
|
|
43
|
+
return null;
|
|
44
|
+
const [, owner, repo, ref, path] = m;
|
|
45
|
+
return `https://github.com/${owner}/${repo}/blob/${ref}/${path}`;
|
|
46
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
// Catalog of GM_* / GM.* APIs that SourceMonkey supports (or has slots
|
|
2
|
+
// for). This is the single source of truth that:
|
|
3
|
+
//
|
|
4
|
+
// - The injector consults to decide which GM_* function definitions
|
|
5
|
+
// to compile into a given script's wrapper, based on its @grant
|
|
6
|
+
// lines. This is where @grant is actually enforced: an ungranted
|
|
7
|
+
// API is simply never bound into the script's scope.
|
|
8
|
+
// - The permission-test e2e spec consults to assert that ungranted
|
|
9
|
+
// APIs are not bound in the script's scope.
|
|
10
|
+
//
|
|
11
|
+
// NOTE: the SW-side async handlers do NOT re-validate @grant against
|
|
12
|
+
// this catalog. Enforcement is binding-time only (above). Re-checking
|
|
13
|
+
// in the SW would add no security: the per-message `scriptId` is
|
|
14
|
+
// wrapper-supplied and spoofable, so a script that wanted to bypass
|
|
15
|
+
// the grant would just claim the id of a script that has it. See the
|
|
16
|
+
// "trust caveat" notes in docs/GM-APIs.md.
|
|
17
|
+
//
|
|
18
|
+
// Each API entry says:
|
|
19
|
+
// - The canonical `GM_x` name and the GM4-style `GM.x` alias (if
|
|
20
|
+
// any). Scripts can @grant either form and we honor both.
|
|
21
|
+
// - Whether the call resolves in-page (`sync`) — runs in
|
|
22
|
+
// USER_SCRIPT world via the shared GM runtime — or makes a
|
|
23
|
+
// SW round-trip (`async`).
|
|
24
|
+
// - The subsystem the body delegates to. Drives both the wrapper-side
|
|
25
|
+
// stub and the SW-side message routing.
|
|
26
|
+
//
|
|
27
|
+
// Adding a new API: append an entry, then either (a) implement the
|
|
28
|
+
// sync body in src/wrapper-gm-runtime.js if `kind === 'sync'` or (b)
|
|
29
|
+
// add an SW-side handler if `kind === 'async'`.
|
|
30
|
+
import { getValues } from './userscript-header.js';
|
|
31
|
+
// What a request that reads or writes a script's stored values has to
|
|
32
|
+
// have granted: any storage API, or a value-change listener (its
|
|
33
|
+
// snapshot seeds the listener's remote-change detection). Used by the
|
|
34
|
+
// bridge gate in background.ts.
|
|
35
|
+
export const STORAGE_SUBSYSTEMS = ['storage', 'storage-listener'];
|
|
36
|
+
// The refusal a bridge-relayed request gets when the page may not act
|
|
37
|
+
// for the script it names. Shared by the same two gates.
|
|
38
|
+
export const BRIDGE_DENIED = 'This page is not allowed to act for that userscript';
|
|
39
|
+
// IMPORTANT: when adding entries here keep the order stable — emit
|
|
40
|
+
// order in the wrapper isn't load-bearing but stable order makes
|
|
41
|
+
// stack traces and diffed wrapper bodies easier to compare across
|
|
42
|
+
// runs.
|
|
43
|
+
export const GM_APIS = Object.freeze([
|
|
44
|
+
// ----- Compile-time / in-page constants -----
|
|
45
|
+
{ name: 'GM_info', gmDotName: 'info', kind: 'sync', subsystem: 'info' },
|
|
46
|
+
{ name: 'unsafeWindow', kind: 'sync', subsystem: 'unsafe-window' },
|
|
47
|
+
// ----- Non-GM_* window features (TM's `@grant window.x` family) -----
|
|
48
|
+
// `window.onurlchange` is not a callable and not a valid JS
|
|
49
|
+
// identifier, so it emits no `const` binding at all. What the grant
|
|
50
|
+
// buys is an eager `__smReg.gm.urlchange.enable(scriptId)` call that
|
|
51
|
+
// installs the `urlchange` event surface on the world's `window`.
|
|
52
|
+
// See docs/GM-APIs.md#windowonurlchange.
|
|
53
|
+
{ name: 'window.onurlchange', kind: 'sync', subsystem: 'url-change' },
|
|
54
|
+
// `window.close` / `window.focus` are callables, but `window.close`
|
|
55
|
+
// is not a legal binding name either — so, like the grant above,
|
|
56
|
+
// they emit no `GM_*`-style binding. The grant's effect is an eager
|
|
57
|
+
// `__smReg.gm.windowControl` call that REPLACES the method the script
|
|
58
|
+
// sees (on its sandbox `window` in the page's world, on the world's
|
|
59
|
+
// `window` when isolated) with one that routes through the SW (`chrome.tabs.remove` / `chrome.windows.update`),
|
|
60
|
+
// which is what lets it work where the page's own call is a no-op.
|
|
61
|
+
// `async` for that SW round-trip; the script still sees the void,
|
|
62
|
+
// synchronous return TM gives it. See docs/GM-APIs.md#windowclose--windowfocus.
|
|
63
|
+
{ name: 'window.close', kind: 'async', subsystem: 'window-control' },
|
|
64
|
+
{ name: 'window.focus', kind: 'async', subsystem: 'window-control' },
|
|
65
|
+
// ----- Logging -----
|
|
66
|
+
{ name: 'GM_log', gmDotName: 'log', kind: 'sync', subsystem: 'log' },
|
|
67
|
+
// ----- Storage (sync return; GM. form returns Promise per GM4) -----
|
|
68
|
+
{ name: 'GM_setValue', gmDotName: 'setValue', gmDotPromised: true, kind: 'sync', subsystem: 'storage' },
|
|
69
|
+
{ name: 'GM_getValue', gmDotName: 'getValue', gmDotPromised: true, kind: 'sync', subsystem: 'storage' },
|
|
70
|
+
{ name: 'GM_deleteValue', gmDotName: 'deleteValue', gmDotPromised: true, kind: 'sync', subsystem: 'storage' },
|
|
71
|
+
{ name: 'GM_listValues', gmDotName: 'listValues', gmDotPromised: true, kind: 'sync', subsystem: 'storage' },
|
|
72
|
+
// ----- Value-change listeners (sync register/unregister) -----
|
|
73
|
+
{ name: 'GM_addValueChangeListener', gmDotName: 'addValueChangeListener', kind: 'sync', subsystem: 'storage-listener' },
|
|
74
|
+
{ name: 'GM_removeValueChangeListener', gmDotName: 'removeValueChangeListener', kind: 'sync', subsystem: 'storage-listener' },
|
|
75
|
+
// ----- DOM injection -----
|
|
76
|
+
{ name: 'GM_addStyle', gmDotName: 'addStyle', kind: 'sync', subsystem: 'dom' },
|
|
77
|
+
{ name: 'GM_addElement', gmDotName: 'addElement', kind: 'sync', subsystem: 'dom' },
|
|
78
|
+
// ----- @resource lookups (require @resource header support) -----
|
|
79
|
+
// GM4 spelling is `GM.getResourceUrl` (lowercase 'u') — keep the
|
|
80
|
+
// casing mismatch with GM_getResourceURL, it's deliberate.
|
|
81
|
+
{ name: 'GM_getResourceText', gmDotName: 'getResourceText', kind: 'sync', subsystem: 'resource', requires: ['resource'] },
|
|
82
|
+
{ name: 'GM_getResourceURL', gmDotName: 'getResourceUrl', kind: 'sync', subsystem: 'resource', requires: ['resource'] },
|
|
83
|
+
// ----- Menu commands (stub: register/unregister) -----
|
|
84
|
+
{ name: 'GM_registerMenuCommand', gmDotName: 'registerMenuCommand', kind: 'sync', subsystem: 'menu' },
|
|
85
|
+
{ name: 'GM_unregisterMenuCommand', gmDotName: 'unregisterMenuCommand', kind: 'sync', subsystem: 'menu' },
|
|
86
|
+
// ----- Async APIs (cross-world, SW round-trip) -----
|
|
87
|
+
// Note: GM_xmlhttpRequest returns a sync control object, but the
|
|
88
|
+
// request itself is async. We classify by SW round-trip — `async` —
|
|
89
|
+
// because the wrapper has to message the SW to start the request.
|
|
90
|
+
{ name: 'GM_xmlhttpRequest', gmDotName: 'xmlHttpRequest', kind: 'async', subsystem: 'xhr', requires: ['connect'] },
|
|
91
|
+
// GM_setClipboard is handled in-page via navigator.clipboard.writeText
|
|
92
|
+
// — no SW round-trip — so it's classified `sync` even though the
|
|
93
|
+
// underlying browser call is async (returns Promise<void>). Page-
|
|
94
|
+
// handled vs SW-handled is what `kind` actually means in this
|
|
95
|
+
// catalog. TM/VM use an offscreen document via execCommand('copy');
|
|
96
|
+
// we may revisit later if real users hit "navigator.clipboard
|
|
97
|
+
// requires focus" failures.
|
|
98
|
+
{ name: 'GM_setClipboard', gmDotName: 'setClipboard', kind: 'sync', subsystem: 'clipboard' },
|
|
99
|
+
{ name: 'GM_notification', gmDotName: 'notification', kind: 'async', subsystem: 'notification' },
|
|
100
|
+
{ name: 'GM_openInTab', gmDotName: 'openInTab', kind: 'async', subsystem: 'tab' },
|
|
101
|
+
// Per-tab objects kept by the SW while the tab is open. Each takes an
|
|
102
|
+
// optional callback, as in TM, and returns a Promise when given none,
|
|
103
|
+
// which is what the `GM.` form passes through.
|
|
104
|
+
{ name: 'GM_getTab', gmDotName: 'getTab', kind: 'async', subsystem: 'tab-data' },
|
|
105
|
+
{ name: 'GM_saveTab', gmDotName: 'saveTab', kind: 'async', subsystem: 'tab-data' },
|
|
106
|
+
{ name: 'GM_getTabs', gmDotName: 'getTabs', kind: 'async', subsystem: 'tab-data' },
|
|
107
|
+
// Like GM_xmlhttpRequest, GM_download hands back a sync `{abort}`
|
|
108
|
+
// control object while the transfer itself runs in the SW — `async`
|
|
109
|
+
// classifies the SW round-trip, not the return value. It is NOT
|
|
110
|
+
// `requires: ['connect']`: download URLs are runtime-discovered CDN
|
|
111
|
+
// hosts that scripts can't enumerate in a header, and the bytes go
|
|
112
|
+
// to disk rather than back to the script, so the exfiltration risk
|
|
113
|
+
// `@connect` guards doesn't apply. See docs/GM-APIs.md.
|
|
114
|
+
{ name: 'GM_download', gmDotName: 'download', kind: 'async', subsystem: 'download' },
|
|
115
|
+
]);
|
|
116
|
+
// Quick lookup. Built lazily so unit tests that only import types or
|
|
117
|
+
// constants don't pay the Map cost; callers that hit this in a hot
|
|
118
|
+
// loop should cache the result of `findApi` themselves.
|
|
119
|
+
let byName = null;
|
|
120
|
+
function ensureIndex() {
|
|
121
|
+
if (byName !== null)
|
|
122
|
+
return byName;
|
|
123
|
+
const m = new Map();
|
|
124
|
+
for (const a of GM_APIS) {
|
|
125
|
+
m.set(a.name, a);
|
|
126
|
+
if (a.gmDotName)
|
|
127
|
+
m.set(`GM.${a.gmDotName}`, a);
|
|
128
|
+
}
|
|
129
|
+
byName = m;
|
|
130
|
+
return m;
|
|
131
|
+
}
|
|
132
|
+
// Look up an API spec by either its `GM_x` name OR its `GM.x` form.
|
|
133
|
+
// Returns undefined for unknown names (e.g. APIs we don't support
|
|
134
|
+
// yet — `GM_webRequest`, `GM_audio`, etc.).
|
|
135
|
+
export function findApi(name) {
|
|
136
|
+
return ensureIndex().get(name);
|
|
137
|
+
}
|
|
138
|
+
// Normalize a single `@grant` line to its canonical `GM_x` name.
|
|
139
|
+
//
|
|
140
|
+
// Cases:
|
|
141
|
+
// - `GM_setValue` → `'GM_setValue'`
|
|
142
|
+
// - `GM.setValue` → `'GM_setValue'` (canonicalized to the legacy form)
|
|
143
|
+
// - unknown / blank → `null`
|
|
144
|
+
//
|
|
145
|
+
// Does NOT handle the `none` sentinel — that's a per-script policy,
|
|
146
|
+
// not a per-name canonicalization. `resolveGrants` is where `none`
|
|
147
|
+
// gets recognized and propagated.
|
|
148
|
+
export function canonicalizeGrant(raw) {
|
|
149
|
+
const trimmed = raw.trim();
|
|
150
|
+
if (trimmed === '')
|
|
151
|
+
return null;
|
|
152
|
+
if (trimmed.toLowerCase() === 'none')
|
|
153
|
+
return null;
|
|
154
|
+
const spec = findApi(trimmed);
|
|
155
|
+
return spec ? spec.name : null;
|
|
156
|
+
}
|
|
157
|
+
// Resolve the set of granted GM_* names for a script, given its raw
|
|
158
|
+
// @grant lines.
|
|
159
|
+
//
|
|
160
|
+
// Rules:
|
|
161
|
+
// - A `none` line anywhere wins — the script is treated as ungranted.
|
|
162
|
+
// Matches TM/VM behavior: a script with `@grant none` and `@grant
|
|
163
|
+
// GM_setValue` is treated as `@grant none`. The granted set is
|
|
164
|
+
// returned empty in this case; `unknown` is still populated so the
|
|
165
|
+
// caller can warn.
|
|
166
|
+
// - Unknown names are dropped from `granted` and surfaced in
|
|
167
|
+
// `unknown`. The wrapper simply won't emit a binding for them, and
|
|
168
|
+
// the script gets a natural ReferenceError at call time.
|
|
169
|
+
// - Duplicate names collapse to one (Set semantics).
|
|
170
|
+
export function resolveGrants(rawGrants) {
|
|
171
|
+
const granted = new Set();
|
|
172
|
+
let hasNone = false;
|
|
173
|
+
const unknown = [];
|
|
174
|
+
for (const raw of rawGrants) {
|
|
175
|
+
const trimmed = raw.trim();
|
|
176
|
+
if (trimmed === '')
|
|
177
|
+
continue;
|
|
178
|
+
if (trimmed.toLowerCase() === 'none') {
|
|
179
|
+
hasNone = true;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const canonical = canonicalizeGrant(trimmed);
|
|
183
|
+
if (canonical === null) {
|
|
184
|
+
unknown.push(trimmed);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
granted.add(canonical);
|
|
188
|
+
}
|
|
189
|
+
// @grant none wins — even if other granted lines were also present.
|
|
190
|
+
if (hasNone)
|
|
191
|
+
granted.clear();
|
|
192
|
+
return { granted, hasNone, unknown };
|
|
193
|
+
}
|
|
194
|
+
// True iff the named API is part of the supported surface. Used by the
|
|
195
|
+
// SW-side message router to reject unknown method calls (a misbehaving
|
|
196
|
+
// or stale wrapper that asks for `GM_audio.play` shouldn't be able to
|
|
197
|
+
// drive any handler).
|
|
198
|
+
export function isSupportedApi(name) {
|
|
199
|
+
return findApi(name) !== undefined;
|
|
200
|
+
}
|
|
201
|
+
// The catalog subsystems the script's `@grant` lines reach — the set the
|
|
202
|
+
// SW's bridge gate (`bridgeMayActAs` in background.ts) checks a relayed
|
|
203
|
+
// request against, so a page can only act for a script through APIs
|
|
204
|
+
// that script actually has. `@grant none` and unknown names contribute
|
|
205
|
+
// nothing.
|
|
206
|
+
export function grantedSubsystems(header) {
|
|
207
|
+
const out = new Set();
|
|
208
|
+
if (!header)
|
|
209
|
+
return out;
|
|
210
|
+
const { granted } = resolveGrants(getValues(header, 'grant'));
|
|
211
|
+
for (const name of granted) {
|
|
212
|
+
const spec = findApi(name);
|
|
213
|
+
if (spec)
|
|
214
|
+
out.add(spec.subsystem);
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|