Skip to content

Commit 59c034b

Browse files
committed
Work on Unsafe Window API
1 parent 1b726c9 commit 59c034b

File tree

3 files changed

+70
-14
lines changed

3 files changed

+70
-14
lines changed

src/GM/gm_core.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,12 @@
173173
if (this.loadedScripts.has(url)) {
174174
return;
175175
}
176-
await this.injectScriptTag(url);
176+
// Auto-upgrade HTTP to HTTPS to prevent mixed content errors
177+
const upgradedUrl = url.replace(/^http:\/\//i, 'https://');
178+
if (upgradedUrl !== url) {
179+
console.info(`CodeTweak: Auto-upgraded ${url} to HTTPS`);
180+
}
181+
await this.injectScriptTag(upgradedUrl);
177182
this.loadedScripts.add(url);
178183
}
179184

@@ -261,10 +266,17 @@
261266
window.addEventListener('error', errorHandler);
262267
window.addEventListener('unhandledrejection', rejectionHandler);
263268

269+
// Ensure unsafeWindow is available globally before loading external scripts
270+
// (jQuery and other libraries may try to attach to it)
271+
if (!window.unsafeWindow) {
272+
window.unsafeWindow = window;
273+
}
274+
264275
try {
265276
await loader.loadScripts(requireUrls);
266277

267-
const wrappedCode = `(async function() {\n'use strict';\n${userCode}\n})();`;
278+
const wrappedCode = `(async function() {\n'use strict';\nconst unsafeWindow = window.unsafeWindow || window;\n${userCode}\n})();`;
279+
console.log('CodeTweak: Wrapped code preview (first 500 chars):', wrappedCode.substring(0, 500));
268280
const blob = new Blob([wrappedCode], { type: "text/javascript" });
269281
const blobUrl = URL.createObjectURL(blob);
270282

src/utils/inject.js

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,25 @@ function createMainWorldExecutor(
2020
requiredUrls,
2121
gmInfo
2222
) {
23-
const MAX_RETRIES = 10;
23+
// Always expose unsafeWindow in MAIN world FIRST (it's just the window object)
24+
if (!window.unsafeWindow) {
25+
try {
26+
Object.defineProperty(window, "unsafeWindow", {
27+
value: window,
28+
writable: false,
29+
configurable: false,
30+
});
31+
console.log('CodeTweak: unsafeWindow exposed via defineProperty');
32+
} catch (e) {
33+
window.unsafeWindow = window;
34+
console.log('CodeTweak: unsafeWindow exposed via direct assignment');
35+
}
36+
} else {
37+
console.log('CodeTweak: unsafeWindow already exists');
38+
}
39+
console.log('CodeTweak: unsafeWindow check:', typeof window.unsafeWindow, window.unsafeWindow === window);
40+
41+
const MAX_RETRIES = 30;
2442
const RETRY_INTERVAL = 100;
2543

2644
function waitForGMBridge(worldType, callback) {
@@ -43,7 +61,14 @@ function createMainWorldExecutor(
4361
setTimeout(check, RETRY_INTERVAL);
4462
} else {
4563
console.error(
46-
`CodeTweak: Timed out waiting for core script to load for script '${scriptId}'${worldType ? ` in ${worldType} world` : ''}.`
64+
`CodeTweak: Timed out waiting for core script to load for script '${scriptId}'${worldType ? ` in ${worldType} world` : ''}.`,
65+
'Missing objects:', {
66+
GMBridge: typeof window.GMBridge,
67+
ResourceManager: typeof window.GMBridge?.ResourceManager,
68+
GMAPIRegistry: typeof window.GMBridge?.GMAPIRegistry,
69+
ExternalScriptLoader: typeof window.GMBridge?.ExternalScriptLoader,
70+
executeUserScriptWithDependencies: typeof window.GMBridge?.executeUserScriptWithDependencies
71+
}
4772
);
4873
}
4974
}
@@ -103,8 +128,6 @@ function createMainWorldExecutor(
103128
waitForGMBridge('MAIN', () => {
104129
if (preventReExecution()) return;
105130

106-
107-
108131
const bridge = new window.GMBridge(scriptId, extensionId, 'MAIN');
109132
const resourceManager = window.GMBridge.ResourceManager.fromScript(script);
110133
const apiRegistry = new window.GMBridge.GMAPIRegistry(bridge, resourceManager);
@@ -133,7 +156,7 @@ function createIsolatedWorldExecutor(
133156
requiredUrls,
134157
gmInfo
135158
) {
136-
const MAX_RETRIES = 10;
159+
const MAX_RETRIES = 30;
137160
const RETRY_INTERVAL = 100;
138161

139162
function waitForGMBridge(worldType, callback) {
@@ -156,7 +179,14 @@ function createIsolatedWorldExecutor(
156179
setTimeout(check, RETRY_INTERVAL);
157180
} else {
158181
console.error(
159-
`CodeTweak: Timed out waiting for core script to load for script '${scriptId}'${worldType ? ` in ${worldType} world` : ''}.`
182+
`CodeTweak: Timed out waiting for core script to load for script '${scriptId}'${worldType ? ` in ${worldType} world` : ''}.`,
183+
'Missing objects:', {
184+
GMBridge: typeof window.GMBridge,
185+
ResourceManager: typeof window.GMBridge?.ResourceManager,
186+
GMAPIRegistry: typeof window.GMBridge?.GMAPIRegistry,
187+
ExternalScriptLoader: typeof window.GMBridge?.ExternalScriptLoader,
188+
executeUserScriptWithDependencies: typeof window.GMBridge?.executeUserScriptWithDependencies
189+
}
160190
);
161191
}
162192
}
@@ -277,7 +307,7 @@ class ScriptInjector {
277307
await chrome.scripting.executeScript({
278308
target: { tabId },
279309
world,
280-
files: ["GM/gm_core.js"],
310+
files: ["GM/gm_core.js", "GM/gm_api_registry.js"],
281311
});
282312
tabCoreScripts.add(world);
283313
}

src/utils/urls.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ export function urlMatchesPattern(url, pattern) {
2727

2828
if (patternHost === "*") {
2929
// Any host
30-
} else if (patternHost.startsWith("*.")) {
31-
const domain = patternHost.slice(2);
30+
} else if (patternHost.startsWith("*.") || patternHost.startsWith(".")) {
31+
const domain = patternHost.startsWith("*.") ? patternHost.slice(2) : patternHost.slice(1);
3232
if (!(urlHost === domain || urlHost.endsWith("." + domain))) return false;
3333
} else if (patternHost.includes("*")) {
3434
const hostRegex = new RegExp(
@@ -46,21 +46,35 @@ export function urlMatchesPattern(url, pattern) {
4646
}
4747

4848
const segments = patternPath.split("/").filter(Boolean);
49+
50+
// If no segments (just /), match any path
51+
if (segments.length === 0) return true;
52+
4953
const regexParts = ["^"];
5054

5155
for (let i = 0; i < segments.length; i++) {
5256
const segment = segments[i];
5357
if (segment === "**") {
54-
regexParts.push("(?:\/.*)?");
58+
regexParts.push("(?:\\/.*)?" );
59+
} else if (segment === "*") {
60+
// Single * as entire segment matches one or more path segments
61+
regexParts.push("(?:\\/[^/]+)+");
5562
} else {
5663
const segmentRegex = segment
5764
.replace(/\*/g, "[^/]*")
5865
.replace(/\./g, "\\.");
59-
regexParts.push("\/" + segmentRegex);
66+
regexParts.push("\\/" + segmentRegex);
6067
}
6168
}
6269

63-
regexParts.push("/?$");
70+
// Allow optional trailing slash and anything after the last segment if it ends with *
71+
const lastSegment = segments[segments.length - 1];
72+
if (lastSegment === "*" || lastSegment.includes("*")) {
73+
regexParts.push("(?:\\/.*)?$");
74+
} else {
75+
regexParts.push("/?$");
76+
}
77+
6478
const pathRegex = new RegExp(regexParts.join(""));
6579
return pathRegex.test(urlPath);
6680
} catch (e) {

0 commit comments

Comments
 (0)