@webex/helper-html 3.0.0-beta.8 → 3.0.0-bnr.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/browsers.js +2 -2
- package/dist/html-base.js +6 -14
- package/dist/html-base.js.map +1 -1
- package/dist/html.js +1 -13
- package/dist/html.js.map +1 -1
- package/dist/html.shim.js +22 -74
- package/dist/html.shim.js.map +1 -1
- package/dist/index.js +0 -8
- package/dist/index.js.map +1 -1
- package/dist/types/html-base.d.ts +12 -0
- package/dist/types/html.d.ts +5 -0
- package/dist/types/html.shim.d.ts +33 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +4 -4
- package/src/html.shim.js +21 -27
- package/test/unit/spec/html.js +71 -57
package/browsers.js
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
module.exports = function(browsers) {
|
|
9
|
+
module.exports = function (browsers) {
|
|
10
10
|
// For reasons as-yet unexplained, the html filter test suite hangs when run
|
|
11
11
|
// on Safari/Sauce Labs
|
|
12
|
-
Object.keys(browsers).forEach(function(key) {
|
|
12
|
+
Object.keys(browsers).forEach(function (key) {
|
|
13
13
|
if (key.indexOf('safari') !== -1) {
|
|
14
14
|
delete browsers[key];
|
|
15
15
|
}
|
package/dist/html-base.js
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
4
|
-
|
|
5
4
|
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
6
|
-
|
|
7
5
|
_Object$defineProperty(exports, "__esModule", {
|
|
8
6
|
value: true
|
|
9
7
|
});
|
|
10
|
-
|
|
11
8
|
exports.escape = escape;
|
|
12
9
|
exports.escapeSync = escapeSync;
|
|
13
|
-
|
|
14
10
|
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
15
|
-
|
|
16
11
|
/*!
|
|
17
12
|
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
18
13
|
*/
|
|
19
|
-
|
|
14
|
+
|
|
15
|
+
var escapeMe = /(<|>|&)/g;
|
|
16
|
+
|
|
17
|
+
// escape and escapeSync probably don't both need to exist, but it seemed like a
|
|
20
18
|
// good idea in case we ever want to for the future.
|
|
21
19
|
|
|
22
20
|
/**
|
|
@@ -24,40 +22,34 @@ var escapeMe = /(<|>|&)/g; // escape and escapeSync probably don't both need to
|
|
|
24
22
|
* @param {[type]} html
|
|
25
23
|
* @returns {[type]}
|
|
26
24
|
*/
|
|
27
|
-
|
|
28
25
|
function escape(html) {
|
|
29
26
|
return new _promise.default(function (resolve) {
|
|
30
27
|
return resolve(escapeSync(html));
|
|
31
28
|
});
|
|
32
29
|
}
|
|
30
|
+
|
|
33
31
|
/**
|
|
34
32
|
* Synchronously escape HTML
|
|
35
33
|
* @param {[type]} html
|
|
36
34
|
* @returns {[type]}
|
|
37
35
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
36
|
function escapeSync(html) {
|
|
41
37
|
return html.replace(escapeMe, entityReplacer);
|
|
42
38
|
}
|
|
39
|
+
|
|
43
40
|
/**
|
|
44
41
|
* @param {string} char
|
|
45
42
|
* @private
|
|
46
43
|
* @returns {string}
|
|
47
44
|
*/
|
|
48
|
-
|
|
49
|
-
|
|
50
45
|
function entityReplacer(char) {
|
|
51
46
|
switch (char) {
|
|
52
47
|
case '<':
|
|
53
48
|
return '<';
|
|
54
|
-
|
|
55
49
|
case '>':
|
|
56
50
|
return '>';
|
|
57
|
-
|
|
58
51
|
case '&':
|
|
59
52
|
return '&';
|
|
60
|
-
|
|
61
53
|
default:
|
|
62
54
|
return char;
|
|
63
55
|
}
|
package/dist/html-base.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["escapeMe","escape","html","resolve","escapeSync","replace","entityReplacer","char"],"sources":["html-base.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nconst escapeMe = /(<|>|&)/g;\n\n// escape and escapeSync probably don't both need to exist, but it seemed like a\n// good idea in case we ever want to for the future.\n\n/**\n * Escapes HTML\n * @param {[type]} html\n * @returns {[type]}\n */\nexport function escape(html) {\n return new Promise((resolve) => resolve(escapeSync(html)));\n}\n\n/**\n * Synchronously escape HTML\n * @param {[type]} html\n * @returns {[type]}\n */\nexport function escapeSync(html) {\n return html.replace(escapeMe, entityReplacer);\n}\n\n/**\n * @param {string} char\n * @private\n * @returns {string}\n */\nfunction entityReplacer(char) {\n switch (char) {\n case '<':\n return '<';\n case '>':\n return '>';\n case '&':\n return '&';\n default:\n return char;\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"names":["escapeMe","escape","html","resolve","escapeSync","replace","entityReplacer","char"],"sources":["html-base.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nconst escapeMe = /(<|>|&)/g;\n\n// escape and escapeSync probably don't both need to exist, but it seemed like a\n// good idea in case we ever want to for the future.\n\n/**\n * Escapes HTML\n * @param {[type]} html\n * @returns {[type]}\n */\nexport function escape(html) {\n return new Promise((resolve) => resolve(escapeSync(html)));\n}\n\n/**\n * Synchronously escape HTML\n * @param {[type]} html\n * @returns {[type]}\n */\nexport function escapeSync(html) {\n return html.replace(escapeMe, entityReplacer);\n}\n\n/**\n * @param {string} char\n * @private\n * @returns {string}\n */\nfunction entityReplacer(char) {\n switch (char) {\n case '<':\n return '<';\n case '>':\n return '>';\n case '&':\n return '&';\n default:\n return char;\n }\n}\n"],"mappings":";;;;;;;;;;AAAA;AACA;AACA;;AAEA,IAAMA,QAAQ,GAAG,UAAU;;AAE3B;AACA;;AAEA;AACA;AACA;AACA;AACA;AACO,SAASC,MAAM,CAACC,IAAI,EAAE;EAC3B,OAAO,qBAAY,UAACC,OAAO;IAAA,OAAKA,OAAO,CAACC,UAAU,CAACF,IAAI,CAAC,CAAC;EAAA,EAAC;AAC5D;;AAEA;AACA;AACA;AACA;AACA;AACO,SAASE,UAAU,CAACF,IAAI,EAAE;EAC/B,OAAOA,IAAI,CAACG,OAAO,CAACL,QAAQ,EAAEM,cAAc,CAAC;AAC/C;;AAEA;AACA;AACA;AACA;AACA;AACA,SAASA,cAAc,CAACC,IAAI,EAAE;EAC5B,QAAQA,IAAI;IACV,KAAK,GAAG;MACN,OAAO,MAAM;IACf,KAAK,GAAG;MACN,OAAO,MAAM;IACf,KAAK,GAAG;MACN,OAAO,OAAO;IAChB;MACE,OAAOA,IAAI;EAAC;AAElB"}
|
package/dist/html.js
CHANGED
|
@@ -1,35 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
4
|
-
|
|
5
4
|
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
6
|
-
|
|
7
5
|
_Object$defineProperty(exports, "__esModule", {
|
|
8
6
|
value: true
|
|
9
7
|
});
|
|
10
|
-
|
|
11
8
|
_Object$defineProperty(exports, "escape", {
|
|
12
9
|
enumerable: true,
|
|
13
10
|
get: function get() {
|
|
14
11
|
return _htmlBase.escape;
|
|
15
12
|
}
|
|
16
13
|
});
|
|
17
|
-
|
|
18
14
|
_Object$defineProperty(exports, "escapeSync", {
|
|
19
15
|
enumerable: true,
|
|
20
16
|
get: function get() {
|
|
21
17
|
return _htmlBase.escapeSync;
|
|
22
18
|
}
|
|
23
19
|
});
|
|
24
|
-
|
|
25
20
|
exports.filterSync = exports.filterEscapeSync = exports.filterEscape = exports.filter = void 0;
|
|
26
|
-
|
|
27
21
|
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
28
|
-
|
|
29
22
|
var _curry2 = _interopRequireDefault(require("lodash/curry"));
|
|
30
|
-
|
|
31
23
|
var _htmlBase = require("./html-base");
|
|
32
|
-
|
|
33
24
|
/**
|
|
34
25
|
* @param {Object} allowedTags
|
|
35
26
|
* @param {Array<string>} allowedStyles
|
|
@@ -41,11 +32,11 @@ function noop() {
|
|
|
41
32
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
42
33
|
args[_key] = arguments[_key];
|
|
43
34
|
}
|
|
44
|
-
|
|
45
35
|
return new _promise.default(function (resolve) {
|
|
46
36
|
resolve(noopSync.apply(void 0, args));
|
|
47
37
|
});
|
|
48
38
|
}
|
|
39
|
+
|
|
49
40
|
/**
|
|
50
41
|
* @param {function} processCallback callback function to do additional
|
|
51
42
|
* processing on node. of the form process(node)
|
|
@@ -55,12 +46,9 @@ function noop() {
|
|
|
55
46
|
* @private
|
|
56
47
|
* @returns {string}
|
|
57
48
|
*/
|
|
58
|
-
|
|
59
|
-
|
|
60
49
|
function noopSync(processCallback, allowedTags, allowedStyles, html) {
|
|
61
50
|
return html;
|
|
62
51
|
}
|
|
63
|
-
|
|
64
52
|
var filter = (0, _curry2.default)(noop, 4);
|
|
65
53
|
exports.filter = filter;
|
|
66
54
|
var filterSync = (0, _curry2.default)(noopSync, 4);
|
package/dist/html.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["noop","args","resolve","noopSync","processCallback","allowedTags","allowedStyles","html","filter","filterSync","filterEscape","filterEscapeSync"],"sources":["html.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport {curry} from 'lodash';\n\nexport {escape, escapeSync} from './html-base';\n\n/**\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @private\n * @returns {string}\n */\nfunction noop(...args) {\n return new Promise((resolve) => {\n resolve(noopSync(...args));\n });\n}\n\n/**\n * @param {function} processCallback callback function to do additional\n * processing on node. of the form process(node)\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @private\n * @returns {string}\n */\nfunction noopSync(processCallback, allowedTags, allowedStyles, html) {\n return html;\n}\n\nexport const filter = curry(noop, 4);\nexport const filterSync = curry(noopSync, 4);\nexport const filterEscape = curry(noop, 4);\nexport const filterEscapeSync = curry(noopSync, 4);\n"],"mappings":"
|
|
1
|
+
{"version":3,"names":["noop","args","resolve","noopSync","processCallback","allowedTags","allowedStyles","html","filter","filterSync","filterEscape","filterEscapeSync"],"sources":["html.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport {curry} from 'lodash';\n\nexport {escape, escapeSync} from './html-base';\n\n/**\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @private\n * @returns {string}\n */\nfunction noop(...args) {\n return new Promise((resolve) => {\n resolve(noopSync(...args));\n });\n}\n\n/**\n * @param {function} processCallback callback function to do additional\n * processing on node. of the form process(node)\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @private\n * @returns {string}\n */\nfunction noopSync(processCallback, allowedTags, allowedStyles, html) {\n return html;\n}\n\nexport const filter = curry(noop, 4);\nexport const filterSync = curry(noopSync, 4);\nexport const filterEscape = curry(noop, 4);\nexport const filterEscapeSync = curry(noopSync, 4);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAMA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,IAAI,GAAU;EAAA,kCAANC,IAAI;IAAJA,IAAI;EAAA;EACnB,OAAO,qBAAY,UAACC,OAAO,EAAK;IAC9BA,OAAO,CAACC,QAAQ,eAAIF,IAAI,CAAC,CAAC;EAC5B,CAAC,CAAC;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASE,QAAQ,CAACC,eAAe,EAAEC,WAAW,EAAEC,aAAa,EAAEC,IAAI,EAAE;EACnE,OAAOA,IAAI;AACb;AAEO,IAAMC,MAAM,GAAG,qBAAMR,IAAI,EAAE,CAAC,CAAC;AAAC;AAC9B,IAAMS,UAAU,GAAG,qBAAMN,QAAQ,EAAE,CAAC,CAAC;AAAC;AACtC,IAAMO,YAAY,GAAG,qBAAMV,IAAI,EAAE,CAAC,CAAC;AAAC;AACpC,IAAMW,gBAAgB,GAAG,qBAAMR,QAAQ,EAAE,CAAC,CAAC;AAAC"}
|
package/dist/html.shim.js
CHANGED
|
@@ -1,43 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
4
|
-
|
|
5
4
|
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
6
|
-
|
|
7
5
|
_Object$defineProperty(exports, "__esModule", {
|
|
8
6
|
value: true
|
|
9
7
|
});
|
|
10
|
-
|
|
11
8
|
_Object$defineProperty(exports, "escape", {
|
|
12
9
|
enumerable: true,
|
|
13
10
|
get: function get() {
|
|
14
11
|
return _htmlBase.escape;
|
|
15
12
|
}
|
|
16
13
|
});
|
|
17
|
-
|
|
18
14
|
_Object$defineProperty(exports, "escapeSync", {
|
|
19
15
|
enumerable: true,
|
|
20
16
|
get: function get() {
|
|
21
17
|
return _htmlBase.escapeSync;
|
|
22
18
|
}
|
|
23
19
|
});
|
|
24
|
-
|
|
25
20
|
exports.filterSync = exports.filterEscapeSync = exports.filterEscape = exports.filter = void 0;
|
|
26
|
-
|
|
27
21
|
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
28
|
-
|
|
29
22
|
var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
|
|
30
|
-
|
|
31
23
|
var _reduce2 = _interopRequireDefault(require("lodash/reduce"));
|
|
32
|
-
|
|
33
24
|
var _includes2 = _interopRequireDefault(require("lodash/includes"));
|
|
34
|
-
|
|
35
25
|
var _forEach2 = _interopRequireDefault(require("lodash/forEach"));
|
|
36
|
-
|
|
37
26
|
var _curry2 = _interopRequireDefault(require("lodash/curry"));
|
|
38
|
-
|
|
39
27
|
var _htmlBase = require("./html-base");
|
|
40
|
-
|
|
41
28
|
/**
|
|
42
29
|
* Some browsers don't implement {@link Element#remove()} or
|
|
43
30
|
* {@link NodeList#remove()} or {@link HTMLCollection#remove()}. This wrapper
|
|
@@ -51,22 +38,19 @@ function removeNode(node) {
|
|
|
51
38
|
node.remove();
|
|
52
39
|
return;
|
|
53
40
|
}
|
|
54
|
-
|
|
55
41
|
if (node.parentElement) {
|
|
56
42
|
node.parentElement.removeChild(node);
|
|
57
43
|
return;
|
|
58
44
|
}
|
|
59
|
-
|
|
60
45
|
if ('length' in node) {
|
|
61
46
|
for (var i = node.length - 1; i >= 0; i -= 1) {
|
|
62
47
|
removeNode(node[i]);
|
|
63
48
|
}
|
|
64
|
-
|
|
65
49
|
return;
|
|
66
50
|
}
|
|
67
|
-
|
|
68
51
|
throw new Error('Could not find a way to remove node');
|
|
69
52
|
}
|
|
53
|
+
|
|
70
54
|
/**
|
|
71
55
|
* @param {Object} allowedTags
|
|
72
56
|
* @param {Array<string>} allowedStyles
|
|
@@ -74,17 +58,15 @@ function removeNode(node) {
|
|
|
74
58
|
* @private
|
|
75
59
|
* @returns {string}
|
|
76
60
|
*/
|
|
77
|
-
|
|
78
|
-
|
|
79
61
|
function _filter() {
|
|
80
62
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
81
63
|
args[_key] = arguments[_key];
|
|
82
64
|
}
|
|
83
|
-
|
|
84
65
|
return new _promise.default(function (resolve) {
|
|
85
66
|
resolve(_filterSync.apply(void 0, args));
|
|
86
67
|
});
|
|
87
68
|
}
|
|
69
|
+
|
|
88
70
|
/**
|
|
89
71
|
* Curried async HTML filter.
|
|
90
72
|
* @param {Object} allowedTags Map of tagName -> array of allowed attributes
|
|
@@ -92,9 +74,8 @@ function _filter() {
|
|
|
92
74
|
* @param {string} html html to filter
|
|
93
75
|
* @returns {string}
|
|
94
76
|
*/
|
|
95
|
-
|
|
96
|
-
|
|
97
77
|
var filter = (0, _curry2.default)(_filter, 4);
|
|
78
|
+
|
|
98
79
|
/**
|
|
99
80
|
* @param {function} processCallback callback function to do additional
|
|
100
81
|
* processing on node. of the form process(node)
|
|
@@ -104,63 +85,54 @@ var filter = (0, _curry2.default)(_filter, 4);
|
|
|
104
85
|
* @private
|
|
105
86
|
* @returns {string}
|
|
106
87
|
*/
|
|
107
|
-
|
|
108
88
|
exports.filter = filter;
|
|
109
|
-
|
|
110
89
|
function _filterSync(processCallback, allowedTags, allowedStyles, html) {
|
|
111
90
|
if (!html || !allowedStyles || !allowedTags) {
|
|
112
91
|
if (html.length === 0) {
|
|
113
92
|
return html;
|
|
114
93
|
}
|
|
115
|
-
|
|
116
94
|
throw new Error('`allowedTags`, `allowedStyles`, and `html` must be provided');
|
|
117
95
|
}
|
|
118
|
-
|
|
119
96
|
var doc = new DOMParser().parseFromString(html, 'text/html');
|
|
120
97
|
depthFirstForEach(doc.body.childNodes, filterNode);
|
|
121
98
|
processCallback(doc.body);
|
|
122
|
-
|
|
123
99
|
if (html.indexOf('body') === 1) {
|
|
124
100
|
return "<body>".concat(doc.body.innerHTML, "</body>");
|
|
125
101
|
}
|
|
126
|
-
|
|
127
102
|
return doc.body.innerHTML;
|
|
103
|
+
|
|
128
104
|
/**
|
|
129
105
|
* @param {Node} node
|
|
130
106
|
* @private
|
|
131
107
|
* @returns {undefined}
|
|
132
108
|
*/
|
|
133
|
-
|
|
134
109
|
function filterNode(node) {
|
|
135
110
|
if (!isElement(node)) {
|
|
136
111
|
return;
|
|
137
112
|
}
|
|
138
|
-
|
|
139
113
|
var nodeName = node.nodeName.toLowerCase();
|
|
140
114
|
var allowedTagNames = (0, _keys.default)(allowedTags);
|
|
141
115
|
depthFirstForEach(node.childNodes, filterNode);
|
|
142
|
-
|
|
143
116
|
if ((0, _includes2.default)(allowedTagNames, nodeName)) {
|
|
144
117
|
var allowedAttributes = allowedTags[nodeName];
|
|
145
118
|
(0, _forEach2.default)(listAttributeNames(node.attributes), function (attrName) {
|
|
146
119
|
if (!(0, _includes2.default)(allowedAttributes, attrName)) {
|
|
147
120
|
node.removeAttribute(attrName);
|
|
148
121
|
} else if (attrName === 'href' || attrName === 'src') {
|
|
149
|
-
var attrValue = node.attributes.getNamedItem(attrName).value.trim().toLowerCase();
|
|
122
|
+
var attrValue = node.attributes.getNamedItem(attrName).value.trim().toLowerCase();
|
|
123
|
+
|
|
124
|
+
// We're doing at runtime what the no-script-url rule does at compile
|
|
150
125
|
// time
|
|
151
126
|
// eslint-disable-next-line no-script-url
|
|
152
|
-
|
|
153
127
|
if (attrValue.indexOf('javascript:') === 0 || attrValue.indexOf('vbscript:') === 0) {
|
|
154
128
|
reparent(node);
|
|
155
129
|
}
|
|
156
130
|
} else if (attrName === 'style') {
|
|
157
131
|
var styles = node.attributes.getNamedItem('style').value.split(';').map(function (style) {
|
|
158
132
|
var styleName = trim(style.split(':')[0]);
|
|
159
|
-
|
|
160
133
|
if ((0, _includes2.default)(allowedStyles, styleName)) {
|
|
161
134
|
return style;
|
|
162
135
|
}
|
|
163
|
-
|
|
164
136
|
return null;
|
|
165
137
|
}).filter(function (style) {
|
|
166
138
|
return Boolean(style);
|
|
@@ -173,6 +145,7 @@ function _filterSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
173
145
|
}
|
|
174
146
|
}
|
|
175
147
|
}
|
|
148
|
+
|
|
176
149
|
/**
|
|
177
150
|
* Same as _filter, but escapes rather than removes disallowed values
|
|
178
151
|
* @param {Function} processCallback
|
|
@@ -181,17 +154,15 @@ function _filterSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
181
154
|
* @param {string} html
|
|
182
155
|
* @returns {Promise<string>}
|
|
183
156
|
*/
|
|
184
|
-
|
|
185
|
-
|
|
186
157
|
function _filterEscape() {
|
|
187
158
|
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
188
159
|
args[_key2] = arguments[_key2];
|
|
189
160
|
}
|
|
190
|
-
|
|
191
161
|
return new _promise.default(function (resolve) {
|
|
192
162
|
resolve(_filterEscapeSync.apply(void 0, args));
|
|
193
163
|
});
|
|
194
164
|
}
|
|
165
|
+
|
|
195
166
|
/**
|
|
196
167
|
* Same as _filterSync, but escapes rather than removes disallowed values
|
|
197
168
|
* @param {Function} processCallback
|
|
@@ -200,62 +171,53 @@ function _filterEscape() {
|
|
|
200
171
|
* @param {string} html
|
|
201
172
|
* @returns {string}
|
|
202
173
|
*/
|
|
203
|
-
|
|
204
|
-
|
|
205
174
|
function _filterEscapeSync(processCallback, allowedTags, allowedStyles, html) {
|
|
206
175
|
if (!html || !allowedStyles || !allowedTags) {
|
|
207
176
|
if (html.length === 0) {
|
|
208
177
|
return html;
|
|
209
178
|
}
|
|
210
|
-
|
|
211
179
|
throw new Error('`allowedTags`, `allowedStyles`, and `html` must be provided');
|
|
212
180
|
}
|
|
213
|
-
|
|
214
181
|
var doc = new DOMParser().parseFromString(html, 'text/html');
|
|
215
182
|
depthFirstForEach(doc.body.childNodes, filterNode);
|
|
216
183
|
processCallback(doc.body);
|
|
217
|
-
|
|
218
184
|
if (html.indexOf('body') === 1) {
|
|
219
185
|
return "<body>".concat(doc.body.innerHTML, "</body>");
|
|
220
186
|
}
|
|
221
|
-
|
|
222
187
|
return doc.body.innerHTML;
|
|
188
|
+
|
|
223
189
|
/**
|
|
224
190
|
* @param {Node} node
|
|
225
191
|
* @private
|
|
226
192
|
* @returns {undefined}
|
|
227
193
|
*/
|
|
228
|
-
|
|
229
194
|
function filterNode(node) {
|
|
230
195
|
if (!isElement(node)) {
|
|
231
196
|
return;
|
|
232
197
|
}
|
|
233
|
-
|
|
234
198
|
depthFirstForEach(node.childNodes, filterNode);
|
|
235
199
|
var nodeName = node.nodeName.toLowerCase();
|
|
236
200
|
var allowedTagNames = (0, _keys.default)(allowedTags);
|
|
237
|
-
|
|
238
201
|
if ((0, _includes2.default)(allowedTagNames, nodeName)) {
|
|
239
202
|
var allowedAttributes = allowedTags[nodeName];
|
|
240
203
|
(0, _forEach2.default)(listAttributeNames(node.attributes), function (attrName) {
|
|
241
204
|
if (!(0, _includes2.default)(allowedAttributes, attrName)) {
|
|
242
205
|
node.removeAttribute(attrName);
|
|
243
206
|
} else if (attrName === 'href' || attrName === 'src') {
|
|
244
|
-
var attrValue = node.attributes.getNamedItem(attrName).value.toLowerCase();
|
|
207
|
+
var attrValue = node.attributes.getNamedItem(attrName).value.toLowerCase();
|
|
208
|
+
|
|
209
|
+
// We're doing at runtime what the no-script-url rule does at compile
|
|
245
210
|
// time
|
|
246
211
|
// eslint-disable-next-line no-script-url
|
|
247
|
-
|
|
248
212
|
if (attrValue.indexOf('javascript:') === 0 || attrValue.indexOf('vbscript:') === 0) {
|
|
249
213
|
reparent(node);
|
|
250
214
|
}
|
|
251
215
|
} else if (attrName === 'style') {
|
|
252
216
|
var styles = node.attributes.getNamedItem('style').value.split(';').map(function (style) {
|
|
253
217
|
var styleName = trim(style.split(':')[0]);
|
|
254
|
-
|
|
255
218
|
if ((0, _includes2.default)(allowedStyles, styleName)) {
|
|
256
219
|
return style;
|
|
257
220
|
}
|
|
258
|
-
|
|
259
221
|
return null;
|
|
260
222
|
}).filter(function (style) {
|
|
261
223
|
return Boolean(style);
|
|
@@ -268,101 +230,89 @@ function _filterEscapeSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
268
230
|
}
|
|
269
231
|
}
|
|
270
232
|
}
|
|
233
|
+
|
|
271
234
|
/**
|
|
272
235
|
* Escapes a given html node
|
|
273
236
|
* @param {Node} node
|
|
274
237
|
* @returns {undefined}
|
|
275
238
|
*/
|
|
276
|
-
|
|
277
|
-
|
|
278
239
|
function escapeNode(node) {
|
|
279
240
|
var before = document.createTextNode("<".concat(node.nodeName.toLowerCase(), ">"));
|
|
280
241
|
var after = document.createTextNode("</".concat(node.nodeName.toLowerCase(), ">"));
|
|
281
242
|
node.parentNode.insertBefore(before, node);
|
|
282
|
-
|
|
283
243
|
while (node.childNodes.length > 0) {
|
|
284
244
|
node.parentNode.insertBefore(node.childNodes[0], node);
|
|
285
245
|
}
|
|
286
|
-
|
|
287
246
|
node.parentNode.insertBefore(after, node);
|
|
288
247
|
removeNode(node);
|
|
289
248
|
}
|
|
290
|
-
|
|
291
249
|
var trimPattern = /^\s|\s$/g;
|
|
250
|
+
|
|
292
251
|
/**
|
|
293
252
|
* @param {string} str
|
|
294
253
|
* @returns {string}
|
|
295
254
|
*/
|
|
296
|
-
|
|
297
255
|
function trim(str) {
|
|
298
256
|
return str.replace(trimPattern, '');
|
|
299
257
|
}
|
|
258
|
+
|
|
300
259
|
/**
|
|
301
260
|
* @param {Node} node
|
|
302
261
|
* @private
|
|
303
262
|
* @returns {undefined}
|
|
304
263
|
*/
|
|
305
|
-
|
|
306
|
-
|
|
307
264
|
function reparent(node) {
|
|
308
265
|
while (node.childNodes.length > 0) {
|
|
309
266
|
node.parentNode.insertBefore(node.childNodes[0], node);
|
|
310
267
|
}
|
|
311
|
-
|
|
312
268
|
removeNode(node);
|
|
313
269
|
}
|
|
270
|
+
|
|
314
271
|
/**
|
|
315
272
|
* @param {NamedNodeMap} attributes
|
|
316
273
|
* @private
|
|
317
274
|
* @returns {Array<string>}
|
|
318
275
|
*/
|
|
319
|
-
|
|
320
|
-
|
|
321
276
|
function listAttributeNames(attributes) {
|
|
322
277
|
return (0, _reduce2.default)(attributes, function (attrNames, attr) {
|
|
323
278
|
attrNames.push(attr.name);
|
|
324
279
|
return attrNames;
|
|
325
280
|
}, []);
|
|
326
281
|
}
|
|
282
|
+
|
|
327
283
|
/**
|
|
328
284
|
* @param {Array} list
|
|
329
285
|
* @param {Function} fn
|
|
330
286
|
* @private
|
|
331
287
|
* @returns {undefined}
|
|
332
288
|
*/
|
|
333
|
-
|
|
334
|
-
|
|
335
289
|
function depthFirstForEach(list, fn) {
|
|
336
290
|
for (var i = list.length; i >= 0; i -= 1) {
|
|
337
291
|
fn(list[i]);
|
|
338
292
|
}
|
|
339
293
|
}
|
|
294
|
+
|
|
340
295
|
/**
|
|
341
296
|
* @param {Node} o
|
|
342
297
|
* @private
|
|
343
298
|
* @returns {Boolean}
|
|
344
299
|
*/
|
|
345
|
-
|
|
346
|
-
|
|
347
300
|
function isElement(o) {
|
|
348
301
|
if (!o) {
|
|
349
302
|
return false;
|
|
350
303
|
}
|
|
351
|
-
|
|
352
304
|
if (o.ownerDocument === undefined) {
|
|
353
305
|
return false;
|
|
354
306
|
}
|
|
355
|
-
|
|
356
307
|
if (o.nodeType !== 1) {
|
|
357
308
|
return false;
|
|
358
309
|
}
|
|
359
|
-
|
|
360
310
|
if (typeof o.nodeName !== 'string') {
|
|
361
311
|
return false;
|
|
362
312
|
}
|
|
363
|
-
|
|
364
313
|
return true;
|
|
365
314
|
}
|
|
315
|
+
|
|
366
316
|
/**
|
|
367
317
|
* Curried HTML filter.
|
|
368
318
|
* @param {Object} allowedTags Map of tagName -> array of allowed attributes
|
|
@@ -370,9 +320,8 @@ function isElement(o) {
|
|
|
370
320
|
* @param {string} html html to filter
|
|
371
321
|
* @returns {string}
|
|
372
322
|
*/
|
|
373
|
-
|
|
374
|
-
|
|
375
323
|
var filterSync = (0, _curry2.default)(_filterSync, 4);
|
|
324
|
+
|
|
376
325
|
/**
|
|
377
326
|
* Curried HTML filter that escapes rather than removes disallowed tags
|
|
378
327
|
* @param {Object} allowedTags Map of tagName -> array of allowed attributes
|
|
@@ -380,9 +329,9 @@ var filterSync = (0, _curry2.default)(_filterSync, 4);
|
|
|
380
329
|
* @param {string} html html to filter
|
|
381
330
|
* @returns {Promise<string>}
|
|
382
331
|
*/
|
|
383
|
-
|
|
384
332
|
exports.filterSync = filterSync;
|
|
385
333
|
var filterEscape = (0, _curry2.default)(_filterEscape, 4);
|
|
334
|
+
|
|
386
335
|
/**
|
|
387
336
|
* Curried HTML filter that escapes rather than removes disallowed tags
|
|
388
337
|
* @param {Object} allowedTags Map of tagName -> array of allowed attributes
|
|
@@ -390,7 +339,6 @@ var filterEscape = (0, _curry2.default)(_filterEscape, 4);
|
|
|
390
339
|
* @param {string} html html to filter
|
|
391
340
|
* @returns {string}
|
|
392
341
|
*/
|
|
393
|
-
|
|
394
342
|
exports.filterEscape = filterEscape;
|
|
395
343
|
var filterEscapeSync = (0, _curry2.default)(_filterEscapeSync, 4);
|
|
396
344
|
exports.filterEscapeSync = filterEscapeSync;
|
package/dist/html.shim.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["removeNode","node","remove","parentElement","removeChild","i","length","Error","_filter","args","resolve","_filterSync","filter","processCallback","allowedTags","allowedStyles","html","doc","DOMParser","parseFromString","depthFirstForEach","body","childNodes","filterNode","indexOf","innerHTML","isElement","nodeName","toLowerCase","allowedTagNames","allowedAttributes","listAttributeNames","attributes","attrName","removeAttribute","attrValue","getNamedItem","value","trim","reparent","styles","split","map","style","styleName","Boolean","join","setAttribute","_filterEscape","_filterEscapeSync","escapeNode","before","document","createTextNode","after","parentNode","insertBefore","trimPattern","str","replace","attrNames","attr","push","name","list","fn","o","ownerDocument","undefined","nodeType","filterSync","filterEscape","filterEscapeSync"],"sources":["html.shim.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/* eslint-env browser */\n\nimport {curry, forEach, includes, reduce} from 'lodash';\n\nexport {escape, escapeSync} from './html-base';\n\n/**\n * Some browsers don't implement {@link Element#remove()} or\n * {@link NodeList#remove()} or {@link HTMLCollection#remove()}. This wrapper\n * calls the appropriate `#remove()` method if available, or falls back to a\n * non-global-polluting polyfill.\n * @param {Element|NodeList|HTMLCollection} node\n * @returns {undefined}\n */\nfunction removeNode(node) {\n if (node.remove) {\n node.remove();\n\n return;\n }\n\n if (node.parentElement) {\n node.parentElement.removeChild(node);\n\n return;\n }\n\n if ('length' in node) {\n for (let i = node.length - 1; i >= 0; i -= 1) {\n removeNode(node[i]);\n }\n\n return;\n }\n\n throw new Error('Could not find a way to remove node');\n}\n\n/**\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @private\n * @returns {string}\n */\nfunction _filter(...args) {\n return new Promise((resolve) => {\n resolve(_filterSync(...args));\n });\n}\n\n/**\n * Curried async HTML filter.\n * @param {Object} allowedTags Map of tagName -> array of allowed attributes\n * @param {Array<string>} allowedStyles Array of allowed styles\n * @param {string} html html to filter\n * @returns {string}\n */\nexport const filter = curry(_filter, 4);\n\n/**\n * @param {function} processCallback callback function to do additional\n * processing on node. of the form process(node)\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @private\n * @returns {string}\n */\nfunction _filterSync(processCallback, allowedTags, allowedStyles, html) {\n if (!html || !allowedStyles || !allowedTags) {\n if (html.length === 0) {\n return html;\n }\n\n throw new Error('`allowedTags`, `allowedStyles`, and `html` must be provided');\n }\n\n const doc = (new DOMParser()).parseFromString(html, 'text/html');\n\n depthFirstForEach(doc.body.childNodes, filterNode);\n processCallback(doc.body);\n\n if (html.indexOf('body') === 1) {\n return `<body>${doc.body.innerHTML}</body>`;\n }\n\n return doc.body.innerHTML;\n\n /**\n * @param {Node} node\n * @private\n * @returns {undefined}\n */\n function filterNode(node) {\n if (!isElement(node)) {\n return;\n }\n\n const nodeName = node.nodeName.toLowerCase();\n const allowedTagNames = Object.keys(allowedTags);\n\n depthFirstForEach(node.childNodes, filterNode);\n\n if (includes(allowedTagNames, nodeName)) {\n const allowedAttributes = allowedTags[nodeName];\n\n forEach(listAttributeNames(node.attributes), (attrName) => {\n if (!includes(allowedAttributes, attrName)) {\n node.removeAttribute(attrName);\n }\n else if (attrName === 'href' || attrName === 'src') {\n const attrValue = node.attributes.getNamedItem(attrName).value.trim().toLowerCase();\n\n // We're doing at runtime what the no-script-url rule does at compile\n // time\n // eslint-disable-next-line no-script-url\n if (attrValue.indexOf('javascript:') === 0 || attrValue.indexOf('vbscript:') === 0) {\n reparent(node);\n }\n }\n else if (attrName === 'style') {\n const styles = node\n .attributes\n .getNamedItem('style')\n .value\n .split(';')\n .map((style) => {\n const styleName = trim(style.split(':')[0]);\n\n if (includes(allowedStyles, styleName)) {\n return style;\n }\n\n return null;\n })\n .filter((style) => Boolean(style))\n .join(';');\n\n node.setAttribute('style', styles);\n }\n });\n }\n else {\n reparent(node);\n }\n }\n}\n\n/**\n * Same as _filter, but escapes rather than removes disallowed values\n * @param {Function} processCallback\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @returns {Promise<string>}\n */\nfunction _filterEscape(...args) {\n return new Promise((resolve) => {\n resolve(_filterEscapeSync(...args));\n });\n}\n\n/**\n * Same as _filterSync, but escapes rather than removes disallowed values\n * @param {Function} processCallback\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @returns {string}\n */\nfunction _filterEscapeSync(processCallback, allowedTags, allowedStyles, html) {\n if (!html || !allowedStyles || !allowedTags) {\n if (html.length === 0) {\n return html;\n }\n\n throw new Error('`allowedTags`, `allowedStyles`, and `html` must be provided');\n }\n\n const doc = (new DOMParser()).parseFromString(html, 'text/html');\n\n depthFirstForEach(doc.body.childNodes, filterNode);\n processCallback(doc.body);\n\n if (html.indexOf('body') === 1) {\n return `<body>${doc.body.innerHTML}</body>`;\n }\n\n return doc.body.innerHTML;\n\n /**\n * @param {Node} node\n * @private\n * @returns {undefined}\n */\n function filterNode(node) {\n if (!isElement(node)) {\n return;\n }\n\n depthFirstForEach(node.childNodes, filterNode);\n\n const nodeName = node.nodeName.toLowerCase();\n const allowedTagNames = Object.keys(allowedTags);\n\n if (includes(allowedTagNames, nodeName)) {\n const allowedAttributes = allowedTags[nodeName];\n\n forEach(listAttributeNames(node.attributes), (attrName) => {\n if (!includes(allowedAttributes, attrName)) {\n node.removeAttribute(attrName);\n }\n else if (attrName === 'href' || attrName === 'src') {\n const attrValue = node.attributes.getNamedItem(attrName).value.toLowerCase();\n\n // We're doing at runtime what the no-script-url rule does at compile\n // time\n // eslint-disable-next-line no-script-url\n if (attrValue.indexOf('javascript:') === 0 || attrValue.indexOf('vbscript:') === 0) {\n reparent(node);\n }\n }\n else if (attrName === 'style') {\n const styles = node\n .attributes\n .getNamedItem('style')\n .value\n .split(';')\n .map((style) => {\n const styleName = trim(style.split(':')[0]);\n\n if (includes(allowedStyles, styleName)) {\n return style;\n }\n\n return null;\n })\n .filter((style) => Boolean(style))\n .join(';');\n\n node.setAttribute('style', styles);\n }\n });\n }\n else {\n escapeNode(node);\n }\n }\n}\n\n/**\n * Escapes a given html node\n * @param {Node} node\n * @returns {undefined}\n */\nfunction escapeNode(node) {\n const before = document.createTextNode(`<${node.nodeName.toLowerCase()}>`);\n const after = document.createTextNode(`</${node.nodeName.toLowerCase()}>`);\n\n node.parentNode.insertBefore(before, node);\n while (node.childNodes.length > 0) {\n node.parentNode.insertBefore(node.childNodes[0], node);\n }\n node.parentNode.insertBefore(after, node);\n\n removeNode(node);\n}\n\nconst trimPattern = /^\\s|\\s$/g;\n\n/**\n * @param {string} str\n * @returns {string}\n */\nfunction trim(str) {\n return str.replace(trimPattern, '');\n}\n\n/**\n * @param {Node} node\n * @private\n * @returns {undefined}\n */\nfunction reparent(node) {\n while (node.childNodes.length > 0) {\n node.parentNode.insertBefore(node.childNodes[0], node);\n }\n removeNode(node);\n}\n\n/**\n * @param {NamedNodeMap} attributes\n * @private\n * @returns {Array<string>}\n */\nfunction listAttributeNames(attributes) {\n return reduce(attributes, (attrNames, attr) => {\n attrNames.push(attr.name);\n\n return attrNames;\n }, []);\n}\n\n/**\n * @param {Array} list\n * @param {Function} fn\n * @private\n * @returns {undefined}\n */\nfunction depthFirstForEach(list, fn) {\n for (let i = list.length; i >= 0; i -= 1) {\n fn(list[i]);\n }\n}\n\n/**\n * @param {Node} o\n * @private\n * @returns {Boolean}\n */\nfunction isElement(o) {\n if (!o) {\n return false;\n }\n\n if (o.ownerDocument === undefined) {\n return false;\n }\n\n if (o.nodeType !== 1) {\n return false;\n }\n\n if (typeof o.nodeName !== 'string') {\n return false;\n }\n\n return true;\n}\n\n/**\n * Curried HTML filter.\n * @param {Object} allowedTags Map of tagName -> array of allowed attributes\n * @param {Array<string>} allowedStyles Array of allowed styles\n * @param {string} html html to filter\n * @returns {string}\n */\nexport const filterSync = curry(_filterSync, 4);\n\n/**\n * Curried HTML filter that escapes rather than removes disallowed tags\n * @param {Object} allowedTags Map of tagName -> array of allowed attributes\n * @param {Array<string>} allowedStyles Array of allowed styles\n * @param {string} html html to filter\n * @returns {Promise<string>}\n */\nexport const filterEscape = curry(_filterEscape, 4);\n\n/**\n * Curried HTML filter that escapes rather than removes disallowed tags\n * @param {Object} allowedTags Map of tagName -> array of allowed attributes\n * @param {Array<string>} allowedStyles Array of allowed styles\n * @param {string} html html to filter\n * @returns {string}\n */\nexport const filterEscapeSync = curry(_filterEscapeSync, 4);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["removeNode","node","remove","parentElement","removeChild","i","length","Error","_filter","args","resolve","_filterSync","filter","processCallback","allowedTags","allowedStyles","html","doc","DOMParser","parseFromString","depthFirstForEach","body","childNodes","filterNode","indexOf","innerHTML","isElement","nodeName","toLowerCase","allowedTagNames","allowedAttributes","listAttributeNames","attributes","attrName","removeAttribute","attrValue","getNamedItem","value","trim","reparent","styles","split","map","style","styleName","Boolean","join","setAttribute","_filterEscape","_filterEscapeSync","escapeNode","before","document","createTextNode","after","parentNode","insertBefore","trimPattern","str","replace","attrNames","attr","push","name","list","fn","o","ownerDocument","undefined","nodeType","filterSync","filterEscape","filterEscapeSync"],"sources":["html.shim.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/* eslint-env browser */\n\nimport {curry, forEach, includes, reduce} from 'lodash';\n\nexport {escape, escapeSync} from './html-base';\n\n/**\n * Some browsers don't implement {@link Element#remove()} or\n * {@link NodeList#remove()} or {@link HTMLCollection#remove()}. This wrapper\n * calls the appropriate `#remove()` method if available, or falls back to a\n * non-global-polluting polyfill.\n * @param {Element|NodeList|HTMLCollection} node\n * @returns {undefined}\n */\nfunction removeNode(node) {\n if (node.remove) {\n node.remove();\n\n return;\n }\n\n if (node.parentElement) {\n node.parentElement.removeChild(node);\n\n return;\n }\n\n if ('length' in node) {\n for (let i = node.length - 1; i >= 0; i -= 1) {\n removeNode(node[i]);\n }\n\n return;\n }\n\n throw new Error('Could not find a way to remove node');\n}\n\n/**\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @private\n * @returns {string}\n */\nfunction _filter(...args) {\n return new Promise((resolve) => {\n resolve(_filterSync(...args));\n });\n}\n\n/**\n * Curried async HTML filter.\n * @param {Object} allowedTags Map of tagName -> array of allowed attributes\n * @param {Array<string>} allowedStyles Array of allowed styles\n * @param {string} html html to filter\n * @returns {string}\n */\nexport const filter = curry(_filter, 4);\n\n/**\n * @param {function} processCallback callback function to do additional\n * processing on node. of the form process(node)\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @private\n * @returns {string}\n */\nfunction _filterSync(processCallback, allowedTags, allowedStyles, html) {\n if (!html || !allowedStyles || !allowedTags) {\n if (html.length === 0) {\n return html;\n }\n\n throw new Error('`allowedTags`, `allowedStyles`, and `html` must be provided');\n }\n\n const doc = new DOMParser().parseFromString(html, 'text/html');\n\n depthFirstForEach(doc.body.childNodes, filterNode);\n processCallback(doc.body);\n\n if (html.indexOf('body') === 1) {\n return `<body>${doc.body.innerHTML}</body>`;\n }\n\n return doc.body.innerHTML;\n\n /**\n * @param {Node} node\n * @private\n * @returns {undefined}\n */\n function filterNode(node) {\n if (!isElement(node)) {\n return;\n }\n\n const nodeName = node.nodeName.toLowerCase();\n const allowedTagNames = Object.keys(allowedTags);\n\n depthFirstForEach(node.childNodes, filterNode);\n\n if (includes(allowedTagNames, nodeName)) {\n const allowedAttributes = allowedTags[nodeName];\n\n forEach(listAttributeNames(node.attributes), (attrName) => {\n if (!includes(allowedAttributes, attrName)) {\n node.removeAttribute(attrName);\n } else if (attrName === 'href' || attrName === 'src') {\n const attrValue = node.attributes.getNamedItem(attrName).value.trim().toLowerCase();\n\n // We're doing at runtime what the no-script-url rule does at compile\n // time\n // eslint-disable-next-line no-script-url\n if (attrValue.indexOf('javascript:') === 0 || attrValue.indexOf('vbscript:') === 0) {\n reparent(node);\n }\n } else if (attrName === 'style') {\n const styles = node.attributes\n .getNamedItem('style')\n .value.split(';')\n .map((style) => {\n const styleName = trim(style.split(':')[0]);\n\n if (includes(allowedStyles, styleName)) {\n return style;\n }\n\n return null;\n })\n .filter((style) => Boolean(style))\n .join(';');\n\n node.setAttribute('style', styles);\n }\n });\n } else {\n reparent(node);\n }\n }\n}\n\n/**\n * Same as _filter, but escapes rather than removes disallowed values\n * @param {Function} processCallback\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @returns {Promise<string>}\n */\nfunction _filterEscape(...args) {\n return new Promise((resolve) => {\n resolve(_filterEscapeSync(...args));\n });\n}\n\n/**\n * Same as _filterSync, but escapes rather than removes disallowed values\n * @param {Function} processCallback\n * @param {Object} allowedTags\n * @param {Array<string>} allowedStyles\n * @param {string} html\n * @returns {string}\n */\nfunction _filterEscapeSync(processCallback, allowedTags, allowedStyles, html) {\n if (!html || !allowedStyles || !allowedTags) {\n if (html.length === 0) {\n return html;\n }\n\n throw new Error('`allowedTags`, `allowedStyles`, and `html` must be provided');\n }\n\n const doc = new DOMParser().parseFromString(html, 'text/html');\n\n depthFirstForEach(doc.body.childNodes, filterNode);\n processCallback(doc.body);\n\n if (html.indexOf('body') === 1) {\n return `<body>${doc.body.innerHTML}</body>`;\n }\n\n return doc.body.innerHTML;\n\n /**\n * @param {Node} node\n * @private\n * @returns {undefined}\n */\n function filterNode(node) {\n if (!isElement(node)) {\n return;\n }\n\n depthFirstForEach(node.childNodes, filterNode);\n\n const nodeName = node.nodeName.toLowerCase();\n const allowedTagNames = Object.keys(allowedTags);\n\n if (includes(allowedTagNames, nodeName)) {\n const allowedAttributes = allowedTags[nodeName];\n\n forEach(listAttributeNames(node.attributes), (attrName) => {\n if (!includes(allowedAttributes, attrName)) {\n node.removeAttribute(attrName);\n } else if (attrName === 'href' || attrName === 'src') {\n const attrValue = node.attributes.getNamedItem(attrName).value.toLowerCase();\n\n // We're doing at runtime what the no-script-url rule does at compile\n // time\n // eslint-disable-next-line no-script-url\n if (attrValue.indexOf('javascript:') === 0 || attrValue.indexOf('vbscript:') === 0) {\n reparent(node);\n }\n } else if (attrName === 'style') {\n const styles = node.attributes\n .getNamedItem('style')\n .value.split(';')\n .map((style) => {\n const styleName = trim(style.split(':')[0]);\n\n if (includes(allowedStyles, styleName)) {\n return style;\n }\n\n return null;\n })\n .filter((style) => Boolean(style))\n .join(';');\n\n node.setAttribute('style', styles);\n }\n });\n } else {\n escapeNode(node);\n }\n }\n}\n\n/**\n * Escapes a given html node\n * @param {Node} node\n * @returns {undefined}\n */\nfunction escapeNode(node) {\n const before = document.createTextNode(`<${node.nodeName.toLowerCase()}>`);\n const after = document.createTextNode(`</${node.nodeName.toLowerCase()}>`);\n\n node.parentNode.insertBefore(before, node);\n while (node.childNodes.length > 0) {\n node.parentNode.insertBefore(node.childNodes[0], node);\n }\n node.parentNode.insertBefore(after, node);\n\n removeNode(node);\n}\n\nconst trimPattern = /^\\s|\\s$/g;\n\n/**\n * @param {string} str\n * @returns {string}\n */\nfunction trim(str) {\n return str.replace(trimPattern, '');\n}\n\n/**\n * @param {Node} node\n * @private\n * @returns {undefined}\n */\nfunction reparent(node) {\n while (node.childNodes.length > 0) {\n node.parentNode.insertBefore(node.childNodes[0], node);\n }\n removeNode(node);\n}\n\n/**\n * @param {NamedNodeMap} attributes\n * @private\n * @returns {Array<string>}\n */\nfunction listAttributeNames(attributes) {\n return reduce(\n attributes,\n (attrNames, attr) => {\n attrNames.push(attr.name);\n\n return attrNames;\n },\n []\n );\n}\n\n/**\n * @param {Array} list\n * @param {Function} fn\n * @private\n * @returns {undefined}\n */\nfunction depthFirstForEach(list, fn) {\n for (let i = list.length; i >= 0; i -= 1) {\n fn(list[i]);\n }\n}\n\n/**\n * @param {Node} o\n * @private\n * @returns {Boolean}\n */\nfunction isElement(o) {\n if (!o) {\n return false;\n }\n\n if (o.ownerDocument === undefined) {\n return false;\n }\n\n if (o.nodeType !== 1) {\n return false;\n }\n\n if (typeof o.nodeName !== 'string') {\n return false;\n }\n\n return true;\n}\n\n/**\n * Curried HTML filter.\n * @param {Object} allowedTags Map of tagName -> array of allowed attributes\n * @param {Array<string>} allowedStyles Array of allowed styles\n * @param {string} html html to filter\n * @returns {string}\n */\nexport const filterSync = curry(_filterSync, 4);\n\n/**\n * Curried HTML filter that escapes rather than removes disallowed tags\n * @param {Object} allowedTags Map of tagName -> array of allowed attributes\n * @param {Array<string>} allowedStyles Array of allowed styles\n * @param {string} html html to filter\n * @returns {Promise<string>}\n */\nexport const filterEscape = curry(_filterEscape, 4);\n\n/**\n * Curried HTML filter that escapes rather than removes disallowed tags\n * @param {Object} allowedTags Map of tagName -> array of allowed attributes\n * @param {Array<string>} allowedStyles Array of allowed styles\n * @param {string} html html to filter\n * @returns {string}\n */\nexport const filterEscapeSync = curry(_filterEscapeSync, 4);\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,52 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
4
|
-
|
|
5
4
|
_Object$defineProperty(exports, "__esModule", {
|
|
6
5
|
value: true
|
|
7
6
|
});
|
|
8
|
-
|
|
9
7
|
_Object$defineProperty(exports, "escape", {
|
|
10
8
|
enumerable: true,
|
|
11
9
|
get: function get() {
|
|
12
10
|
return _html.escape;
|
|
13
11
|
}
|
|
14
12
|
});
|
|
15
|
-
|
|
16
13
|
_Object$defineProperty(exports, "escapeSync", {
|
|
17
14
|
enumerable: true,
|
|
18
15
|
get: function get() {
|
|
19
16
|
return _html.escapeSync;
|
|
20
17
|
}
|
|
21
18
|
});
|
|
22
|
-
|
|
23
19
|
_Object$defineProperty(exports, "filter", {
|
|
24
20
|
enumerable: true,
|
|
25
21
|
get: function get() {
|
|
26
22
|
return _html.filter;
|
|
27
23
|
}
|
|
28
24
|
});
|
|
29
|
-
|
|
30
25
|
_Object$defineProperty(exports, "filterEscape", {
|
|
31
26
|
enumerable: true,
|
|
32
27
|
get: function get() {
|
|
33
28
|
return _html.filterEscape;
|
|
34
29
|
}
|
|
35
30
|
});
|
|
36
|
-
|
|
37
31
|
_Object$defineProperty(exports, "filterEscapeSync", {
|
|
38
32
|
enumerable: true,
|
|
39
33
|
get: function get() {
|
|
40
34
|
return _html.filterEscapeSync;
|
|
41
35
|
}
|
|
42
36
|
});
|
|
43
|
-
|
|
44
37
|
_Object$defineProperty(exports, "filterSync", {
|
|
45
38
|
enumerable: true,
|
|
46
39
|
get: function get() {
|
|
47
40
|
return _html.filterSync;
|
|
48
41
|
}
|
|
49
42
|
});
|
|
50
|
-
|
|
51
43
|
var _html = require("./html");
|
|
52
44
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["index.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nexport {escape, escapeSync, filter, filterSync, filterEscape, filterEscapeSync} from './html';\n"],"mappings":"
|
|
1
|
+
{"version":3,"names":[],"sources":["index.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nexport {escape, escapeSync, filter, filterSync, filterEscape, filterEscapeSync} from './html';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escapes HTML
|
|
3
|
+
* @param {[type]} html
|
|
4
|
+
* @returns {[type]}
|
|
5
|
+
*/
|
|
6
|
+
export function escape(html: [type]): [type];
|
|
7
|
+
/**
|
|
8
|
+
* Synchronously escape HTML
|
|
9
|
+
* @param {[type]} html
|
|
10
|
+
* @returns {[type]}
|
|
11
|
+
*/
|
|
12
|
+
export function escapeSync(html: [type]): [type];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const filter: import("lodash").CurriedFunction1<any, string>;
|
|
2
|
+
export const filterSync: import("lodash").CurriedFunction4<Function, any, string[], string, string>;
|
|
3
|
+
export const filterEscape: import("lodash").CurriedFunction1<any, string>;
|
|
4
|
+
export const filterEscapeSync: import("lodash").CurriedFunction4<Function, any, string[], string, string>;
|
|
5
|
+
export { escape, escapeSync } from "./html-base";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curried async HTML filter.
|
|
3
|
+
* @param {Object} allowedTags Map of tagName -> array of allowed attributes
|
|
4
|
+
* @param {Array<string>} allowedStyles Array of allowed styles
|
|
5
|
+
* @param {string} html html to filter
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
8
|
+
export const filter: import("lodash").CurriedFunction1<any, string>;
|
|
9
|
+
/**
|
|
10
|
+
* Curried HTML filter.
|
|
11
|
+
* @param {Object} allowedTags Map of tagName -> array of allowed attributes
|
|
12
|
+
* @param {Array<string>} allowedStyles Array of allowed styles
|
|
13
|
+
* @param {string} html html to filter
|
|
14
|
+
* @returns {string}
|
|
15
|
+
*/
|
|
16
|
+
export const filterSync: import("lodash").CurriedFunction4<Function, any, string[], string, string>;
|
|
17
|
+
/**
|
|
18
|
+
* Curried HTML filter that escapes rather than removes disallowed tags
|
|
19
|
+
* @param {Object} allowedTags Map of tagName -> array of allowed attributes
|
|
20
|
+
* @param {Array<string>} allowedStyles Array of allowed styles
|
|
21
|
+
* @param {string} html html to filter
|
|
22
|
+
* @returns {Promise<string>}
|
|
23
|
+
*/
|
|
24
|
+
export const filterEscape: import("lodash").CurriedFunction1<any, Promise<string>>;
|
|
25
|
+
/**
|
|
26
|
+
* Curried HTML filter that escapes rather than removes disallowed tags
|
|
27
|
+
* @param {Object} allowedTags Map of tagName -> array of allowed attributes
|
|
28
|
+
* @param {Array<string>} allowedStyles Array of allowed styles
|
|
29
|
+
* @param {string} html html to filter
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
export const filterEscapeSync: import("lodash").CurriedFunction4<Function, any, string[], string, string>;
|
|
33
|
+
export { escape, escapeSync } from "./html-base";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { escape, escapeSync, filter, filterSync, filterEscape, filterEscapeSync } from "./html";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webex/helper-html",
|
|
3
|
-
"version": "3.0.0-
|
|
3
|
+
"version": "3.0.0-bnr.0",
|
|
4
4
|
"description": "HTML Utiltities",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
]
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@webex/test-helper-chai": "3.0.0-
|
|
28
|
-
"@webex/test-helper-mocha": "3.0.0-
|
|
27
|
+
"@webex/test-helper-chai": "3.0.0-bnr.0",
|
|
28
|
+
"@webex/test-helper-mocha": "3.0.0-bnr.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@webex/helper-html": "3.0.0-
|
|
31
|
+
"@webex/helper-html": "3.0.0-bnr.0",
|
|
32
32
|
"lodash": "^4.17.21"
|
|
33
33
|
}
|
|
34
34
|
}
|
package/src/html.shim.js
CHANGED
|
@@ -80,7 +80,7 @@ function _filterSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
80
80
|
throw new Error('`allowedTags`, `allowedStyles`, and `html` must be provided');
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
const doc =
|
|
83
|
+
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
84
84
|
|
|
85
85
|
depthFirstForEach(doc.body.childNodes, filterNode);
|
|
86
86
|
processCallback(doc.body);
|
|
@@ -112,8 +112,7 @@ function _filterSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
112
112
|
forEach(listAttributeNames(node.attributes), (attrName) => {
|
|
113
113
|
if (!includes(allowedAttributes, attrName)) {
|
|
114
114
|
node.removeAttribute(attrName);
|
|
115
|
-
}
|
|
116
|
-
else if (attrName === 'href' || attrName === 'src') {
|
|
115
|
+
} else if (attrName === 'href' || attrName === 'src') {
|
|
117
116
|
const attrValue = node.attributes.getNamedItem(attrName).value.trim().toLowerCase();
|
|
118
117
|
|
|
119
118
|
// We're doing at runtime what the no-script-url rule does at compile
|
|
@@ -122,13 +121,10 @@ function _filterSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
122
121
|
if (attrValue.indexOf('javascript:') === 0 || attrValue.indexOf('vbscript:') === 0) {
|
|
123
122
|
reparent(node);
|
|
124
123
|
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const styles = node
|
|
128
|
-
.attributes
|
|
124
|
+
} else if (attrName === 'style') {
|
|
125
|
+
const styles = node.attributes
|
|
129
126
|
.getNamedItem('style')
|
|
130
|
-
.value
|
|
131
|
-
.split(';')
|
|
127
|
+
.value.split(';')
|
|
132
128
|
.map((style) => {
|
|
133
129
|
const styleName = trim(style.split(':')[0]);
|
|
134
130
|
|
|
@@ -144,8 +140,7 @@ function _filterSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
144
140
|
node.setAttribute('style', styles);
|
|
145
141
|
}
|
|
146
142
|
});
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
143
|
+
} else {
|
|
149
144
|
reparent(node);
|
|
150
145
|
}
|
|
151
146
|
}
|
|
@@ -182,7 +177,7 @@ function _filterEscapeSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
182
177
|
throw new Error('`allowedTags`, `allowedStyles`, and `html` must be provided');
|
|
183
178
|
}
|
|
184
179
|
|
|
185
|
-
const doc =
|
|
180
|
+
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
186
181
|
|
|
187
182
|
depthFirstForEach(doc.body.childNodes, filterNode);
|
|
188
183
|
processCallback(doc.body);
|
|
@@ -214,8 +209,7 @@ function _filterEscapeSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
214
209
|
forEach(listAttributeNames(node.attributes), (attrName) => {
|
|
215
210
|
if (!includes(allowedAttributes, attrName)) {
|
|
216
211
|
node.removeAttribute(attrName);
|
|
217
|
-
}
|
|
218
|
-
else if (attrName === 'href' || attrName === 'src') {
|
|
212
|
+
} else if (attrName === 'href' || attrName === 'src') {
|
|
219
213
|
const attrValue = node.attributes.getNamedItem(attrName).value.toLowerCase();
|
|
220
214
|
|
|
221
215
|
// We're doing at runtime what the no-script-url rule does at compile
|
|
@@ -224,13 +218,10 @@ function _filterEscapeSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
224
218
|
if (attrValue.indexOf('javascript:') === 0 || attrValue.indexOf('vbscript:') === 0) {
|
|
225
219
|
reparent(node);
|
|
226
220
|
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const styles = node
|
|
230
|
-
.attributes
|
|
221
|
+
} else if (attrName === 'style') {
|
|
222
|
+
const styles = node.attributes
|
|
231
223
|
.getNamedItem('style')
|
|
232
|
-
.value
|
|
233
|
-
.split(';')
|
|
224
|
+
.value.split(';')
|
|
234
225
|
.map((style) => {
|
|
235
226
|
const styleName = trim(style.split(':')[0]);
|
|
236
227
|
|
|
@@ -246,8 +237,7 @@ function _filterEscapeSync(processCallback, allowedTags, allowedStyles, html) {
|
|
|
246
237
|
node.setAttribute('style', styles);
|
|
247
238
|
}
|
|
248
239
|
});
|
|
249
|
-
}
|
|
250
|
-
else {
|
|
240
|
+
} else {
|
|
251
241
|
escapeNode(node);
|
|
252
242
|
}
|
|
253
243
|
}
|
|
@@ -299,11 +289,15 @@ function reparent(node) {
|
|
|
299
289
|
* @returns {Array<string>}
|
|
300
290
|
*/
|
|
301
291
|
function listAttributeNames(attributes) {
|
|
302
|
-
return reduce(
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
292
|
+
return reduce(
|
|
293
|
+
attributes,
|
|
294
|
+
(attrNames, attr) => {
|
|
295
|
+
attrNames.push(attr.name);
|
|
296
|
+
|
|
297
|
+
return attrNames;
|
|
298
|
+
},
|
|
299
|
+
[]
|
|
300
|
+
);
|
|
307
301
|
}
|
|
308
302
|
|
|
309
303
|
/**
|
package/test/unit/spec/html.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
filter,
|
|
10
10
|
filterSync,
|
|
11
11
|
filterEscape,
|
|
12
|
-
filterEscapeSync
|
|
12
|
+
filterEscapeSync,
|
|
13
13
|
} from '@webex/helper-html';
|
|
14
14
|
import {skipInNode} from '@webex/test-helper-mocha';
|
|
15
15
|
|
|
@@ -29,7 +29,7 @@ skipInNode(describe)('html', () => {
|
|
|
29
29
|
span: ['style'],
|
|
30
30
|
ul: ['style'],
|
|
31
31
|
body: ['style', 'xmlns', 'xml:lang'],
|
|
32
|
-
'webex-mention': ['data-object-id', 'data-object-type']
|
|
32
|
+
'webex-mention': ['data-object-id', 'data-object-type'],
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
const allowedStyles = [
|
|
@@ -42,7 +42,7 @@ skipInNode(describe)('html', () => {
|
|
|
42
42
|
'margin-left',
|
|
43
43
|
'margin-right',
|
|
44
44
|
'text-align',
|
|
45
|
-
'text-decoration'
|
|
45
|
+
'text-decoration',
|
|
46
46
|
];
|
|
47
47
|
|
|
48
48
|
/**
|
|
@@ -58,12 +58,15 @@ skipInNode(describe)('html', () => {
|
|
|
58
58
|
const cfilterEscapeSync = filterEscapeSync(noop, allowedTags, allowedStyles);
|
|
59
59
|
|
|
60
60
|
describe('#filter()', () => {
|
|
61
|
-
it('sanitizes trivial html', () =>
|
|
62
|
-
|
|
61
|
+
it('sanitizes trivial html', () =>
|
|
62
|
+
cfilter('<p data-test="5"><em>foo</em></p>').then((result) =>
|
|
63
|
+
assert.deepEqual(result, '<p><em>foo</em></p>')
|
|
64
|
+
));
|
|
63
65
|
});
|
|
64
66
|
|
|
65
67
|
describe('#filterSync()', () => {
|
|
66
|
-
it('sanitizes trivial html', () =>
|
|
68
|
+
it('sanitizes trivial html', () =>
|
|
69
|
+
assert.deepEqual(cfilterSync('<p data-test="5"><em>foo</em></p>'), '<p><em>foo</em></p>'));
|
|
67
70
|
});
|
|
68
71
|
|
|
69
72
|
[
|
|
@@ -72,147 +75,154 @@ skipInNode(describe)('html', () => {
|
|
|
72
75
|
// emptry string
|
|
73
76
|
it: 'accepts blank strings',
|
|
74
77
|
input: '',
|
|
75
|
-
output: ''
|
|
78
|
+
output: '',
|
|
76
79
|
},
|
|
77
80
|
{
|
|
78
81
|
it: 'allows custom tags',
|
|
79
|
-
input:
|
|
80
|
-
|
|
82
|
+
input:
|
|
83
|
+
'<webex-mention data-object-id="88888888-4444-4444-4444-AAAAAAAAAAAA">John Doe</webex-mention>',
|
|
84
|
+
output:
|
|
85
|
+
'<webex-mention data-object-id="88888888-4444-4444-4444-AAAAAAAAAAAA">John Doe</webex-mention>',
|
|
81
86
|
},
|
|
82
87
|
{
|
|
83
88
|
it: 'filters tags',
|
|
84
|
-
input:
|
|
85
|
-
|
|
89
|
+
input:
|
|
90
|
+
'<p><remove-me><bar>text1<em>text2</em>text3</bar>text4</remove-me><strong>text5</strong>text6</p>',
|
|
91
|
+
output: '<p>text1<em>text2</em>text3text4<strong>text5</strong>text6</p>',
|
|
86
92
|
},
|
|
87
93
|
{
|
|
88
94
|
it: 'filters attributes',
|
|
89
95
|
input: '<p remove="me" style="font-size:large"><em>foo</em></p>',
|
|
90
|
-
output: /<p style="font-size:\s?large;?"><em>foo<\/em><\/p
|
|
96
|
+
output: /<p style="font-size:\s?large;?"><em>foo<\/em><\/p>/,
|
|
91
97
|
},
|
|
92
98
|
{
|
|
93
99
|
it: 'filters styles',
|
|
94
100
|
input: '<p style="color:red;remove:me;font-size:large"><em>foo</em></p>',
|
|
95
|
-
output: /<p style="color:\s?red;\s?font-size:\s?large;?"><em>foo<\/em><\/p
|
|
101
|
+
output: /<p style="color:\s?red;\s?font-size:\s?large;?"><em>foo<\/em><\/p>/,
|
|
96
102
|
},
|
|
97
103
|
{
|
|
98
104
|
it: 'filters child attributes',
|
|
99
105
|
input: '<body><span bcd="abc" style="font-size:large"><p><em>foo</em></p></span></body>',
|
|
100
|
-
output: /<body><span style="font-size:\s?large;?"><p><em>foo<\/em><\/p><\/span><\/body
|
|
106
|
+
output: /<body><span style="font-size:\s?large;?"><p><em>foo<\/em><\/p><\/span><\/body>/,
|
|
101
107
|
},
|
|
102
108
|
{
|
|
103
109
|
it: 'filters disallowed attributes from allowed tags',
|
|
104
110
|
input: '<strong style="font-size:large"><span>text</span></strong>',
|
|
105
|
-
output: '<strong><span>text</span></strong>'
|
|
111
|
+
output: '<strong><span>text</span></strong>',
|
|
106
112
|
},
|
|
107
113
|
{
|
|
108
114
|
it: 'filters javascript: from a href',
|
|
109
115
|
input: '<p><a href="javascript:window.close(); return false">click here</a></p>',
|
|
110
|
-
output: '<p>click here</p>'
|
|
116
|
+
output: '<p>click here</p>',
|
|
111
117
|
},
|
|
112
118
|
{
|
|
113
119
|
it: 'filters javascript: from a href (mixed case)',
|
|
114
120
|
input: '<p><a href="JavaScript:window.close(); return false">click here</a></p>',
|
|
115
|
-
output: '<p>click here</p>'
|
|
121
|
+
output: '<p>click here</p>',
|
|
116
122
|
},
|
|
117
123
|
{
|
|
118
124
|
it: 'filters vbscript: from a href',
|
|
119
125
|
input: '<p><a href="vbscript:window.close(); return false">click here</a></p>',
|
|
120
|
-
output: '<p>click here</p>'
|
|
126
|
+
output: '<p>click here</p>',
|
|
121
127
|
},
|
|
122
128
|
{
|
|
123
129
|
it: 'filters vbscript: from a href (mixed case)',
|
|
124
130
|
input: '<p><a href="VBScript:window.close(); return false">click here</a></p>',
|
|
125
|
-
output: '<p>click here</p>'
|
|
131
|
+
output: '<p>click here</p>',
|
|
126
132
|
},
|
|
127
133
|
{
|
|
128
134
|
it: 'does not filter arbitrary strings from a href',
|
|
129
135
|
input: '<p><a href="window.close(); return false">click here</a></p>',
|
|
130
|
-
output: '<p><a href="window.close(); return false">click here</a></p>'
|
|
136
|
+
output: '<p><a href="window.close(); return false">click here</a></p>',
|
|
131
137
|
},
|
|
132
138
|
{
|
|
133
139
|
it: 'filters javascript: from img src',
|
|
134
140
|
input: '<p><img src="javascript:window.close(); return false">foo</img>bar</p>',
|
|
135
|
-
output: '<p>foobar</p>'
|
|
141
|
+
output: '<p>foobar</p>',
|
|
136
142
|
},
|
|
137
143
|
{
|
|
138
144
|
it: 'filters javascript: from img src (mixed case)',
|
|
139
145
|
input: '<p><img src="javaScript:window.close(); return false">foo</img>bar</p>',
|
|
140
|
-
output: '<p>foobar</p>'
|
|
146
|
+
output: '<p>foobar</p>',
|
|
141
147
|
},
|
|
142
148
|
{
|
|
143
149
|
it: 'filters vbscript: from img src',
|
|
144
150
|
input: '<p><img src="vbscript:window.close(); return false">foo</img>bar</p>',
|
|
145
|
-
output: '<p>foobar</p>'
|
|
151
|
+
output: '<p>foobar</p>',
|
|
146
152
|
},
|
|
147
153
|
{
|
|
148
154
|
it: 'filters vbscript: from img src (mixed case)',
|
|
149
155
|
input: '<p><img src="VBScript:window.close(); return false">foo</img>bar</p>',
|
|
150
|
-
output: '<p>foobar</p>'
|
|
156
|
+
output: '<p>foobar</p>',
|
|
151
157
|
},
|
|
152
158
|
{
|
|
153
159
|
it: 'does not filter arbitrary strings from img src',
|
|
154
160
|
input: '<p><img src="window.close(); return false">foo</img></p>',
|
|
155
|
-
output: '<p><img src="window.close(); return false">foo</p>'
|
|
161
|
+
output: '<p><img src="window.close(); return false">foo</p>',
|
|
156
162
|
},
|
|
157
163
|
{
|
|
158
164
|
it: 'correctly cleans nested a/img tags with javscript: href/src',
|
|
159
|
-
input:
|
|
160
|
-
|
|
165
|
+
input:
|
|
166
|
+
'<p><a href="javascript:window.close()">Click here<img src="http://example.com/img">bar</img></a> for something with <a href="http://www.cisco.com/">MORE<img src="javascript:window.location=`http://www.cisco.com`">of my</img>MOJO</a></p>',
|
|
167
|
+
output:
|
|
168
|
+
'<p>Click here<img src="http://example.com/img">bar for something with <a href="http://www.cisco.com/">MOREof myMOJO</a></p>',
|
|
161
169
|
},
|
|
162
170
|
{
|
|
163
171
|
it: 'correctly cleans nested a/img tags with javscript: href/src, even cleverly obfuscated with whitespace',
|
|
164
|
-
input:
|
|
165
|
-
|
|
172
|
+
input:
|
|
173
|
+
'<p><a href=" javascript:window.close()">Click here<img src="http://example.com/img">bar</img></a> for something with <a href="http://www.cisco.com/">MORE<img src=" javascript:window.location=`http://www.cisco.com`">of my</img>MOJO</a></p>',
|
|
174
|
+
output:
|
|
175
|
+
'<p>Click here<img src="http://example.com/img">bar for something with <a href="http://www.cisco.com/">MOREof myMOJO</a></p>',
|
|
166
176
|
},
|
|
167
177
|
{
|
|
168
178
|
it: 'handles weirder nesting',
|
|
169
|
-
input:
|
|
170
|
-
|
|
179
|
+
input:
|
|
180
|
+
'<p>text</p><div><p>text0</p><div style="font-size: large;"><span>text1</span><span>text2</span><script></script></div></div>',
|
|
181
|
+
output: '<p>text</p><p>text0</p><span>text1</span><span>text2</span>',
|
|
171
182
|
},
|
|
172
183
|
{
|
|
173
184
|
it: 'filters bad html from unwrapped strings',
|
|
174
185
|
input: 'Hi <script></script><em style="font-size:large;">Steve</em>',
|
|
175
|
-
output: 'Hi <em>Steve</em>'
|
|
186
|
+
output: 'Hi <em>Steve</em>',
|
|
176
187
|
},
|
|
177
188
|
{
|
|
178
189
|
it: 'filters disallowed attributes from a href',
|
|
179
190
|
input: '<a remove="me" href="http://www.jabber.org/"><p><em>foo</em></p></a>',
|
|
180
|
-
output: '<a href="http://www.jabber.org/"><p><em>foo</em></p></a>'
|
|
191
|
+
output: '<a href="http://www.jabber.org/"><p><em>foo</em></p></a>',
|
|
181
192
|
},
|
|
182
193
|
{
|
|
183
194
|
it: 'filters disallowed attributes from a style',
|
|
184
195
|
input: '<a remove="me" style="font-size:large"><p><em>foo</em></p></a>',
|
|
185
|
-
output: /<a style="font-size:\s?large;?"><p><em>foo<\/em><\/p><\/a
|
|
196
|
+
output: /<a style="font-size:\s?large;?"><p><em>foo<\/em><\/p><\/a>/,
|
|
186
197
|
},
|
|
187
198
|
{
|
|
188
199
|
it: 'filters disallowed attributes from a type',
|
|
189
200
|
input: '<a remove="me" type="stuff"><p><em>foo</em></p></a>',
|
|
190
|
-
output: '<a type="stuff"><p><em>foo</em></p></a>'
|
|
201
|
+
output: '<a type="stuff"><p><em>foo</em></p></a>',
|
|
191
202
|
},
|
|
192
203
|
{
|
|
193
204
|
it: 'filters disallowed attributes from img src',
|
|
194
205
|
input: '<img remove="me" src="http://www.xmpp.org/images/psa-license.jpg">bar</img>',
|
|
195
|
-
output: '<img src="http://www.xmpp.org/images/psa-license.jpg">bar'
|
|
206
|
+
output: '<img src="http://www.xmpp.org/images/psa-license.jpg">bar',
|
|
196
207
|
},
|
|
197
208
|
{
|
|
198
209
|
it: 'filters disallowed attributes from img alt',
|
|
199
210
|
input: '<img remove="me" alt="A License to Jabber">bar</img>',
|
|
200
|
-
output: '<img alt="A License to Jabber">bar'
|
|
211
|
+
output: '<img alt="A License to Jabber">bar',
|
|
201
212
|
},
|
|
202
213
|
{
|
|
203
214
|
it: 'filters disallowed attributes from img height',
|
|
204
215
|
input: '<img remove="me" height="261">bar</img>',
|
|
205
|
-
output: '<img height="261">bar'
|
|
216
|
+
output: '<img height="261">bar',
|
|
206
217
|
},
|
|
207
218
|
{
|
|
208
219
|
it: 'filters disallowed attributes from img width',
|
|
209
220
|
input: '<img remove="me" width="537">bar</img>',
|
|
210
|
-
output: '<img width="537">bar'
|
|
211
|
-
}
|
|
221
|
+
output: '<img width="537">bar',
|
|
222
|
+
},
|
|
212
223
|
].forEach((def) => {
|
|
213
224
|
describe('#filter()', () => {
|
|
214
|
-
it(def.it, () => cfilter(def.input)
|
|
215
|
-
.then((out) => assert.match(out, def.output)));
|
|
225
|
+
it(def.it, () => cfilter(def.input).then((out) => assert.match(out, def.output)));
|
|
216
226
|
});
|
|
217
227
|
|
|
218
228
|
describe('#filterSync()', () => {
|
|
@@ -222,14 +232,15 @@ skipInNode(describe)('html', () => {
|
|
|
222
232
|
});
|
|
223
233
|
});
|
|
224
234
|
|
|
225
|
-
[
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
235
|
+
[
|
|
236
|
+
{
|
|
237
|
+
it: 'escapes html',
|
|
238
|
+
input: 'This is an <b>invalid</b> tag',
|
|
239
|
+
output: 'This is an <b>invalid</b> tag',
|
|
240
|
+
},
|
|
241
|
+
].forEach((def) => {
|
|
230
242
|
describe('#escape()', () => {
|
|
231
|
-
it(def.it, () => escape(def.input)
|
|
232
|
-
.then((result) => assert.deepEqual(result, def.output)));
|
|
243
|
+
it(def.it, () => escape(def.input).then((result) => assert.deepEqual(result, def.output)));
|
|
233
244
|
});
|
|
234
245
|
|
|
235
246
|
describe('#escapeSync()', () => {
|
|
@@ -243,24 +254,27 @@ skipInNode(describe)('html', () => {
|
|
|
243
254
|
{
|
|
244
255
|
it: 'escapes invalid tags',
|
|
245
256
|
input: '<bar>text1<em>text2</em>text3</bar>',
|
|
246
|
-
output: '<bar>text1<em>text2</em>text3</bar>'
|
|
257
|
+
output: '<bar>text1<em>text2</em>text3</bar>',
|
|
247
258
|
},
|
|
248
259
|
{
|
|
249
260
|
it: 'escapes deeply nested invalid tags',
|
|
250
|
-
input:
|
|
251
|
-
|
|
261
|
+
input:
|
|
262
|
+
'<p><remove-me><bar>text1<em>text2</em>text3</bar>text4</remove-me><strong>text5</strong>text6</p>',
|
|
263
|
+
output:
|
|
264
|
+
'<p><remove-me><bar>text1<em>text2</em>text3</bar>text4</remove-me><strong>text5</strong>text6</p>',
|
|
252
265
|
},
|
|
253
266
|
{
|
|
254
267
|
it: 'esapes special characters',
|
|
255
268
|
input: '<b>&<</b>',
|
|
256
|
-
output: '<b>&<</b>'
|
|
257
|
-
}
|
|
269
|
+
output: '<b>&<</b>',
|
|
270
|
+
},
|
|
258
271
|
].forEach((def) => {
|
|
259
272
|
describe('#filterEscape()', () => {
|
|
260
|
-
it(def.it, () =>
|
|
261
|
-
.then((out) => {
|
|
273
|
+
it(def.it, () =>
|
|
274
|
+
cfilterEscape(def.input).then((out) => {
|
|
262
275
|
assert.match(out, def.output);
|
|
263
|
-
})
|
|
276
|
+
})
|
|
277
|
+
);
|
|
264
278
|
});
|
|
265
279
|
|
|
266
280
|
describe('#filterEscapeSync()', () => {
|