Skip to content

Commit 1c85645

Browse files
committed
AG-44375 Fix 'prevent-element-src-loading' — TrustedScriptURL is not defined in Firefox. #514
Squashed commit of the following: commit 405af1e Author: Adam Wróblewski <[email protected]> Date: Wed Jul 23 17:29:28 2025 +0200 Re-add support for Trusted Types in `prevent-element-src-loading` scriptlet and tests commit 4fd957b Author: Adam Wróblewski <[email protected]> Date: Tue Jul 22 11:32:11 2025 +0200 Fix `prevent-element-src-loading` scriptlet
1 parent bfcf681 commit 1c85645

File tree

3 files changed

+68
-10
lines changed

3 files changed

+68
-10
lines changed

CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic
1010
<!-- TODO: change `@added unknown` tag due to the actual version -->
1111
<!-- during new scriptlets or redirects releasing -->
1212

13+
## [Unreleased]
14+
15+
### Fixed
16+
17+
- issue with `TrustedScriptURL` in `prevent-element-src-loading` scriptlet [#514].
18+
19+
[Unreleased]: https://github.com/AdguardTeam/Scriptlets/compare/v2.2.8...HEAD
20+
[#514]: https://github.com/AdguardTeam/Scriptlets/issues/514
21+
1322
## [v2.2.8] - 2025-07-08
1423

1524
### Added
@@ -24,7 +33,7 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic
2433

2534
- `trusted-set-cookie-reload` scriptlet infinite page reloading when cookie with time keyword is used [#489].
2635

27-
[v2.2.8]: https://github.com/AdguardTeam/Scriptlets/compare/v2.2.8...HEAD
36+
[v2.2.8]: https://github.com/AdguardTeam/Scriptlets/compare/v2.2.7...v2.2.8
2837
[#489]: https://github.com/AdguardTeam/Scriptlets/issues/489
2938

3039
<!-- v2.2.6 is the same as v2.2.7 -->

src/scriptlets/prevent-element-src-loading.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,20 @@ export function preventElementSrcLoading(source, tagName, match) {
131131
return true;
132132
}
133133

134-
// eslint-disable-next-line no-undef
135-
if (policy && urlValue instanceof TrustedScriptURL) {
136-
const trustedSrc = policy.createScriptURL(urlValue);
137-
origSrcDescriptor.set.call(this, trustedSrc);
138-
hit(source);
139-
return;
134+
let mockData = srcMockData[nodeName];
135+
136+
// If setting value is TrustedScriptURL - we also should set TrustedScriptURL to not violate trusted types
137+
if (
138+
typeof TrustedScriptURL !== 'undefined'
139+
&& policy?.isSupported
140+
// eslint-disable-next-line no-undef
141+
&& urlValue instanceof TrustedScriptURL
142+
) {
143+
mockData = policy.createScriptURL(mockData);
140144
}
145+
141146
setMatchedAttribute(this);
142-
origSrcDescriptor.set.call(this, srcMockData[nodeName]);
147+
origSrcDescriptor.set.call(this, mockData);
143148
hit(source);
144149
},
145150
});

tests/scriptlets/prevent-element-src-loading.test.js

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { runScriptlet, clearGlobalProps } from '../helpers';
44
const { test, module } = QUnit;
55
const name = 'prevent-element-src-loading';
66

7+
const nativeTrustedScriptURL = window.TrustedScriptURL;
8+
79
const beforeEach = () => {
810
window.__debug = () => {
911
window.hit = 'FIRED';
@@ -14,6 +16,7 @@ const afterEach = () => {
1416
if (window.elem) {
1517
window.elem.remove();
1618
}
19+
window.TrustedScriptURL = nativeTrustedScriptURL;
1720
clearGlobalProps('hit', '__debug', 'elem', 'scriptLoaded', 'scriptBlocked');
1821
};
1922

@@ -25,14 +28,21 @@ const ONERROR_PROP = 'onerrorProp';
2528
const ERROR_LISTENER = 'addErrorListener';
2629

2730
// Create tag using combination of different methods
28-
const createTestTag = (assert, nodeName, url, srcMethod, onerrorMethod) => {
31+
const createTestTag = (assert, nodeName, url, srcMethod, onerrorMethod, useTrustedTypes = false) => {
2932
const done = assert.async();
3033
const node = document.createElement(nodeName);
3134

35+
let policy;
36+
if (useTrustedTypes && window.trustedTypes) {
37+
policy = window.trustedTypes.createPolicy('default', {
38+
createScriptURL: (url) => url,
39+
});
40+
}
41+
3242
// Set url with .src or .setAttribute
3343
switch (srcMethod) {
3444
case SET_SRC_PROP: {
35-
node.src = url;
45+
node.src = policy ? policy.createScriptURL(url) : url;
3646
break;
3747
}
3848
case SET_SRC_ATTRIBUTE: {
@@ -424,3 +434,37 @@ test('onerror inline, do not match source', (assert) => {
424434
// and window.hit should not be fired
425435
onErrorTestTag(assert, SOURCE_PATH, testPassed, shouldLoad);
426436
});
437+
438+
test('src prop, matching script element (no TrustedScriptURL)', (assert) => {
439+
window.TrustedScriptURL = undefined; // Simulate no TrustedScriptURL support
440+
const SOURCE_PATH = `${TEST_FILES_DIR}${TEST_SCRIPT01_FILENAME}`;
441+
const scriptletArgs = [SCRIPT_TARGET_NODE, TEST_SCRIPT01_FILENAME];
442+
runScriptlet(name, scriptletArgs);
443+
444+
var elem = createTestTag(
445+
assert,
446+
SCRIPT_TARGET_NODE,
447+
SOURCE_PATH,
448+
SET_SRC_PROP,
449+
ONERROR_PROP,
450+
);
451+
assert.strictEqual(elem.src, srcMockData[SCRIPT_TARGET_NODE], 'src was mocked');
452+
assert.strictEqual(window.hit, 'FIRED', 'hit fired');
453+
});
454+
455+
test('src prop, matching script element TrustedTypes', (assert) => {
456+
const SOURCE_PATH = `${TEST_FILES_DIR}${TEST_SCRIPT01_FILENAME}`;
457+
const scriptletArgs = [SCRIPT_TARGET_NODE, TEST_SCRIPT01_FILENAME];
458+
runScriptlet(name, scriptletArgs);
459+
460+
var elem = createTestTag(
461+
assert,
462+
SCRIPT_TARGET_NODE,
463+
SOURCE_PATH,
464+
SET_SRC_PROP,
465+
ONERROR_PROP,
466+
true,
467+
);
468+
assert.strictEqual(elem.src, srcMockData[SCRIPT_TARGET_NODE], 'src was mocked');
469+
assert.strictEqual(window.hit, 'FIRED', 'hit fired');
470+
});

0 commit comments

Comments
 (0)