Skip to content

Commit 72a2388

Browse files
authored
Merge commit from fork
Match JavaScript URIs case insensitively, such as JAVASCRIPT or JavaScript. Match <*:script> elements that are explicitly namespaced/prefixed with the SVG namespace or XHTML namespace. We leave intact any other namespace like a custom <filmmaker:script> script which isn't executable.
1 parent bbab162 commit 72a2388

6 files changed

Lines changed: 135 additions & 4 deletions

File tree

lib/svgo/tools.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ const hasScripts = (node) => {
162162
([attrKey, attrValue]) =>
163163
(attrKey === 'href' || attrKey.endsWith(':href')) &&
164164
attrValue != null &&
165-
attrValue.trimStart().startsWith('javascript:'),
165+
attrValue.trimStart().toLowerCase().startsWith('javascript:'),
166166
);
167167

168168
if (hasJsLinks) {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"packageManager": "yarn@2.4.3",
33
"name": "svgo",
4-
"version": "3.3.3",
4+
"version": "3.3.4",
55
"description": "Nodejs-based tool for optimizing SVG vector graphics files",
66
"license": "MIT",
77
"keywords": [

plugins/removeScriptElement.js

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,37 @@ const eventAttrs = [
1515
...attrsGroups.graphicalEvent,
1616
];
1717

18+
/** Namespaces that support executable <script> elements. */
19+
const SCRIPT_NAMESPACES = [
20+
'http://www.w3.org/2000/svg',
21+
'http://www.w3.org/1999/xhtml',
22+
];
23+
24+
/**
25+
* @param {string} elem
26+
* @param {string} targetElem
27+
* @param {ReadonlyMap<string, string[]>} prefixes
28+
* @param {string[]} targetNamespaces
29+
* @returns {boolean}
30+
*/
31+
function isNamespaceAwareElem(elem, targetElem, prefixes, targetNamespaces) {
32+
if (elem === targetElem) {
33+
return true;
34+
}
35+
36+
if (elem.includes(':')) {
37+
const [prefix, effectiveTag] = elem.split(':', 2);
38+
39+
if (targetElem === effectiveTag) {
40+
const namespaces = /** @type {string[]} */ (prefixes.get(prefix));
41+
const namespace = namespaces[namespaces.length - 1];
42+
return targetNamespaces.includes(namespace);
43+
}
44+
}
45+
46+
return false;
47+
}
48+
1849
/**
1950
* Remove scripts.
2051
*
@@ -24,10 +55,34 @@ const eventAttrs = [
2455
* @type {import('./plugins-types').Plugin<'removeScriptElement'>}
2556
*/
2657
exports.fn = () => {
58+
/**
59+
* Map of XML namespace prefixes to the XML namespace. Each value is a stack
60+
* as XML namespaces can be pushed to in children elements and revert back
61+
* previous namespace when we exit that node.
62+
*
63+
* @type {Map<string, string[]>} */
64+
const prefixes = new Map();
65+
2766
return {
2867
element: {
2968
enter: (node, parentNode) => {
30-
if (node.name === 'script') {
69+
for (const [k, v] of Object.entries(node.attributes)) {
70+
if (!k.startsWith('xmlns:')) {
71+
continue;
72+
}
73+
74+
const prefix = k.slice(6);
75+
76+
if (!prefixes.has(prefix)) {
77+
prefixes.set(prefix, [v]);
78+
} else {
79+
/** @type {string[]} */ (prefixes.get(prefix)).push(v);
80+
}
81+
}
82+
83+
if (
84+
isNamespaceAwareElem(node.name, 'script', prefixes, SCRIPT_NAMESPACES)
85+
) {
3186
detachNodeFromParent(node, parentNode);
3287
return;
3388
}
@@ -39,6 +94,15 @@ exports.fn = () => {
3994
}
4095
},
4196
exit: (node, parentNode) => {
97+
for (const k of Object.keys(node.attributes)) {
98+
if (!k.startsWith('xmlns:')) {
99+
continue;
100+
}
101+
102+
const prefix = k.slice(6);
103+
/** @type {string[]} */ (prefixes.get(prefix)).pop();
104+
}
105+
42106
if (node.name !== 'a') {
43107
return;
44108
}
@@ -47,7 +111,10 @@ exports.fn = () => {
47111
if (attr === 'href' || attr.endsWith(':href')) {
48112
if (
49113
node.attributes[attr] == null ||
50-
!node.attributes[attr].trimStart().startsWith('javascript:')
114+
!node.attributes[attr]
115+
.trimStart()
116+
.toLowerCase()
117+
.startsWith('javascript:')
51118
) {
52119
continue;
53120
}
Lines changed: 20 additions & 0 deletions
Loading
Lines changed: 24 additions & 0 deletions
Loading
Lines changed: 20 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)