Skip to content

Commit d4fa5d6

Browse files
committed
Trusted types
1 parent 12a4361 commit d4fa5d6

1 file changed

Lines changed: 139 additions & 47 deletions

File tree

Chrome/utils/inject.js

Lines changed: 139 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,104 @@ class GMAPIRegistry {
218218
window.GM_addStyle = addStyle;
219219
window.GM.addStyle = addStyle;
220220
}
221+
222+
// Always provide Trusted Types helpers for user scripts
223+
this.setupTrustedTypesHelpers();
224+
}
225+
226+
setupTrustedTypesHelpers() {
227+
// Create a comprehensive Trusted Types policy for user scripts
228+
if (window.trustedTypes && window.trustedTypes.createPolicy) {
229+
try {
230+
if (!window.__ctUserScriptPolicy) {
231+
window.__ctUserScriptPolicy = window.trustedTypes.createPolicy("codetweak-userscript", {
232+
createHTML: (input) => {
233+
// Basic sanitization - remove script tags and dangerous attributes
234+
if (typeof input !== 'string') return '';
235+
return input
236+
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
237+
.replace(/on\w+\s*=\s*["'][^"']*["']/gi, '')
238+
.replace(/javascript:/gi, '');
239+
},
240+
createScript: (input) => input,
241+
createScriptURL: (input) => input,
242+
});
243+
}
244+
245+
// Provide helper functions for user scripts
246+
window.GM_setInnerHTML = (element, html) => {
247+
if (!element || typeof html !== 'string') return false;
248+
try {
249+
const trustedHTML = window.__ctUserScriptPolicy.createHTML(html);
250+
element.innerHTML = trustedHTML;
251+
return true;
252+
} catch (error) {
253+
console.warn('CodeTweak: Failed to set innerHTML with Trusted Types:', error);
254+
// Fallback for non-Trusted Types environments
255+
try {
256+
element.innerHTML = html;
257+
return true;
258+
} catch (fallbackError) {
259+
console.error('CodeTweak: innerHTML fallback also failed:', fallbackError);
260+
return false;
261+
}
262+
}
263+
};
264+
265+
window.GM_createHTML = (html) => {
266+
try {
267+
return window.__ctUserScriptPolicy.createHTML(html);
268+
} catch (error) {
269+
console.warn('CodeTweak: Failed to create TrustedHTML:', error);
270+
return html; // Fallback
271+
}
272+
};
273+
274+
// Make these available in GM namespace too
275+
window.GM = window.GM || {};
276+
window.GM.setInnerHTML = window.GM_setInnerHTML;
277+
window.GM.createHTML = window.GM_createHTML;
278+
279+
} catch (error) {
280+
console.warn('CodeTweak: Failed to create Trusted Types policy:', error);
281+
282+
// Provide fallback functions that work without Trusted Types
283+
window.GM_setInnerHTML = (element, html) => {
284+
if (!element || typeof html !== 'string') return false;
285+
try {
286+
element.innerHTML = html;
287+
return true;
288+
} catch (error) {
289+
console.error('CodeTweak: innerHTML assignment failed:', error);
290+
return false;
291+
}
292+
};
293+
294+
window.GM_createHTML = (html) => html;
295+
296+
window.GM = window.GM || {};
297+
window.GM.setInnerHTML = window.GM_setInnerHTML;
298+
window.GM.createHTML = window.GM_createHTML;
299+
}
300+
} else {
301+
// No Trusted Types support - provide basic fallbacks
302+
window.GM_setInnerHTML = (element, html) => {
303+
if (!element || typeof html !== 'string') return false;
304+
try {
305+
element.innerHTML = html;
306+
return true;
307+
} catch (error) {
308+
console.error('CodeTweak: innerHTML assignment failed:', error);
309+
return false;
310+
}
311+
};
312+
313+
window.GM_createHTML = (html) => html;
314+
315+
window.GM = window.GM || {};
316+
window.GM.setInnerHTML = window.GM_setInnerHTML;
317+
window.GM.createHTML = window.GM_createHTML;
318+
}
221319
}
222320

223321
registerResourceAPIs(enabledApis) {
@@ -303,7 +401,26 @@ class GMAPIRegistry {
303401
if (typeof css !== "string") return null;
304402

305403
const style = document.createElement("style");
306-
style.textContent = css;
404+
405+
// Handle Trusted Types for textContent
406+
let trustedCSS = css;
407+
if (window.trustedTypes && window.trustedTypes.createPolicy) {
408+
try {
409+
if (!window.__ctTrustedHTMLPolicy) {
410+
window.__ctTrustedHTMLPolicy = window.trustedTypes.createPolicy("codetweak-html", {
411+
createHTML: (input) => input,
412+
createScript: (input) => input,
413+
createScriptURL: (input) => input,
414+
});
415+
}
416+
// For CSS, we can use textContent directly, but let's be safe
417+
trustedCSS = css; // textContent doesn't require TrustedHTML
418+
} catch (e) {
419+
console.warn("CodeTweak: Failed to create trusted types policy for CSS:", e);
420+
}
421+
}
422+
423+
style.textContent = trustedCSS;
307424

308425
const target = document.head || document.documentElement || document.body;
309426
if (target) {
@@ -599,55 +716,30 @@ async function executeUserScriptWithDependencies(
599716
// Load external dependencies first
600717
await scriptLoader.loadScripts(requiredUrls);
601718

602-
// Execute user script using a CSP-compliant blob URL instead of Function()
603-
const blob = new Blob([userCode], { type: "text/javascript" });
604-
const blobUrl = URL.createObjectURL(blob);
605-
606-
await new Promise((resolve, reject) => {
607-
const scriptEl = document.createElement("script");
608-
609-
// Trusted Types compliance for blob URL
610-
let trustedSrc = blobUrl;
611-
if (window.trustedTypes && window.trustedTypes.createPolicy) {
719+
// Execute user script directly without blob URLs to avoid CSP violations
720+
// Use Function constructor with proper error handling
721+
try {
722+
// Create a wrapper function that provides better error context
723+
const wrappedCode = `
612724
try {
613-
if (!window.__ctTrustedScriptURLPolicy) {
614-
window.__ctTrustedScriptURLPolicy =
615-
window.trustedTypes.createPolicy("codetweak", {
616-
createScriptURL: (input) => input,
617-
});
618-
}
619-
trustedSrc =
620-
window.__ctTrustedScriptURLPolicy.createScriptURL(blobUrl);
621-
} catch (_e) {
622-
console.error("Failed to create trusted script URL:", _e);
623-
console.warn("Falling back to raw URL.");
624-
// ignore, fall back to raw URL
625-
trustedSrc = blobUrl;
725+
${userCode}
726+
} catch (error) {
727+
console.error('CodeTweak: User script execution error in ${scriptId}:', error);
728+
throw error;
626729
}
627-
}
628-
629-
scriptEl.src = trustedSrc;
630-
scriptEl.async = false; // Preserve execution order
631-
scriptEl.onload = () => {
632-
URL.revokeObjectURL(blobUrl);
633-
resolve();
634-
};
635-
scriptEl.onerror = (event) => {
636-
URL.revokeObjectURL(blobUrl);
637-
reject(
638-
new Error(
639-
`Failed to execute user script ${scriptId}: ${
640-
event?.message || "unknown error"
641-
}`
642-
)
643-
);
644-
};
645-
(document.head || document.documentElement || document.body).appendChild(
646-
scriptEl
647-
);
648-
});
730+
`;
731+
732+
// Execute directly using Function constructor (CSP-compliant)
733+
const userFunction = new Function(wrappedCode);
734+
userFunction();
735+
736+
console.log(`CodeTweak: Successfully executed script ${scriptId}`);
737+
} catch (error) {
738+
console.error(`CodeTweak: Error executing user script ${scriptId}:`, error);
739+
throw error;
740+
}
649741
} catch (error) {
650-
console.error(`CodeTweak: Error executing user script ${scriptId}:`, error);
742+
console.error(`CodeTweak: Error in executeUserScriptWithDependencies for ${scriptId}:`, error);
651743
}
652744
}
653745

0 commit comments

Comments
 (0)