sanitize-html 1.11.4 → 1.14.1
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/.npmignore +1 -0
- package/README.md +76 -3
- package/index.js +12 -2
- package/package.json +10 -2
- package/test/test.js +37 -0
package/.npmignore
CHANGED
package/README.md
CHANGED
|
@@ -22,6 +22,43 @@ HTML comments are not preserved.
|
|
|
22
22
|
|
|
23
23
|
## How to use
|
|
24
24
|
|
|
25
|
+
### Browser
|
|
26
|
+
|
|
27
|
+
*Think first: why do you want to use it in the browser?* Remember, *servers must never trust browsers.* You can't sanitize HTML for saving on the server anywhere else but on the server.
|
|
28
|
+
|
|
29
|
+
But, perhaps you'd like to display sanitized HTML immediately in the browser for preview. Or ask the browser to do the sanitization work on every page load. You can if you want to!
|
|
30
|
+
|
|
31
|
+
* Clone repository
|
|
32
|
+
* Run npm install and build / minify:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install
|
|
36
|
+
npm run minify
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
You'll find the minified and unminified versions of sanitize-html (with all its dependencies included) in the dist/ directory.
|
|
40
|
+
|
|
41
|
+
Use it in the browser:
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<html>
|
|
45
|
+
<body>
|
|
46
|
+
<script type="text/javascript" src="dist/sanitize-html.js"></script>
|
|
47
|
+
<script type="text/javascript" src="demo.js"></script>
|
|
48
|
+
</body>
|
|
49
|
+
</html>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
var html = "<strong>hello world</strong>";
|
|
54
|
+
console.log(sanitizeHtml(html));
|
|
55
|
+
console.log(sanitizeHtml("<img src=x onerror=alert('img') />"));
|
|
56
|
+
console.log(sanitizeHtml("console.log('hello world')"));
|
|
57
|
+
console.log(sanitizeHtml("<script>alert('hello world')</script>"));
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Node (Recommended)
|
|
61
|
+
|
|
25
62
|
Install module from console:
|
|
26
63
|
|
|
27
64
|
```bash
|
|
@@ -77,7 +114,8 @@ allowedAttributes: {
|
|
|
77
114
|
selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
|
|
78
115
|
// URL schemes we permit
|
|
79
116
|
allowedSchemes: [ 'http', 'https', 'ftp', 'mailto' ],
|
|
80
|
-
allowedSchemesByTag: {}
|
|
117
|
+
allowedSchemesByTag: {},
|
|
118
|
+
allowProtocolRelative: true
|
|
81
119
|
```
|
|
82
120
|
|
|
83
121
|
#### "What if I want to allow all tags or all attributes?"
|
|
@@ -184,6 +222,29 @@ simpleTransform(newTag, newAttributes, shouldMerge)
|
|
|
184
222
|
|
|
185
223
|
The last parameter (`shouldMerge`) is set to `true` by default. When `true`, `simpleTransform` will merge the current attributes with the new ones (`newAttributes`). When `false`, all existing attributes are discarded.
|
|
186
224
|
|
|
225
|
+
You can also add or modify the text contents of a tag:
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
clean = sanitizeHtml(dirty, {
|
|
229
|
+
transformTags: {
|
|
230
|
+
'a': function(tagName, attribs) {
|
|
231
|
+
return {
|
|
232
|
+
tagName: 'a',
|
|
233
|
+
text: 'Some text'
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
For example, you could transform a link element with missing anchor text:
|
|
240
|
+
```js
|
|
241
|
+
<a href="http://somelink.com"></a>
|
|
242
|
+
```
|
|
243
|
+
To a link with anchor text:
|
|
244
|
+
```js
|
|
245
|
+
<a href="http://somelink.com">Some text</a>
|
|
246
|
+
```
|
|
247
|
+
|
|
187
248
|
### Filters
|
|
188
249
|
|
|
189
250
|
You can provide a filter function to remove unwanted tags. Let's suppose we need to remove empty `a` tags like:
|
|
@@ -279,6 +340,12 @@ allowedSchemesByTag: {
|
|
|
279
340
|
}
|
|
280
341
|
```
|
|
281
342
|
|
|
343
|
+
And you can forbid the use of protocol-relative URLs (starting with `//`) to access another site using the current protocol, which is allowed by default:
|
|
344
|
+
|
|
345
|
+
```javascript
|
|
346
|
+
allowProtocolRelative: false
|
|
347
|
+
```
|
|
348
|
+
|
|
282
349
|
### Discarding the entire contents of a disallowed tag
|
|
283
350
|
|
|
284
351
|
Normally, with a few exceptions, if a tag is not allowed, all of the text within it is preserved, and so are any allowed tags within it.
|
|
@@ -299,6 +366,14 @@ The content still gets escaped properly, with the exception of the `script` and
|
|
|
299
366
|
|
|
300
367
|
## Changelog
|
|
301
368
|
|
|
369
|
+
1.14.1: documented `allowProtocolRelative` option. No code changes from 1.14.0, released a few moments ago.
|
|
370
|
+
|
|
371
|
+
1.14.0: the new `allowProtocolRelative` option, which is set to `true` by default, allows you to decline to accept URLs that start with `//` and thus point to a different host using the current protocol. If you do **not** want to permit this, set this option to `false`. This is fully backwards compatible because the default behavior is to allow them. Thanks to Luke Bernard.
|
|
372
|
+
|
|
373
|
+
1.13.0: `transformTags` can now add text to an element that initially had none. Thanks to Dushyant Singh.
|
|
374
|
+
|
|
375
|
+
1.12.0: option to build for browser-side use. Thanks to Michael Blum.
|
|
376
|
+
|
|
302
377
|
1.11.4: fixed crash when `__proto__` is a tag name. Now using a safe check for the existence of properties in all cases. Thanks to Andrew Krasichkov.
|
|
303
378
|
|
|
304
379
|
Fixed XSS attack vector via `textarea` tags (when explicitly allowed). Decided that `script` (obviously) and `style` (due to its own XSS vectors) cannot realistically be afforded any XSS protection if allowed, unless we add a full CSS parser. Thanks again to Andrew Krasichkov.
|
|
@@ -402,5 +477,3 @@ We're rocking our tests and have been working great in production for months, so
|
|
|
402
477
|
Feel free to open issues on [github](http://github.com/punkave/sanitize-html).
|
|
403
478
|
|
|
404
479
|
<a href="http://punkave.com/"><img src="https://raw.github.com/punkave/sanitize-html/master/logos/logo-box-builtby.png" /></a>
|
|
405
|
-
|
|
406
|
-
|
package/index.js
CHANGED
|
@@ -118,6 +118,7 @@ function sanitizeHtml(html, options, _recursing) {
|
|
|
118
118
|
stack.push(frame);
|
|
119
119
|
|
|
120
120
|
var skip = false;
|
|
121
|
+
var hasText = frame.text ? true : false;
|
|
121
122
|
var transformedTag;
|
|
122
123
|
if (has(transformTagsMap, name)) {
|
|
123
124
|
transformedTag = transformTagsMap[name](name, attribs);
|
|
@@ -190,6 +191,9 @@ function sanitizeHtml(html, options, _recursing) {
|
|
|
190
191
|
result += " />";
|
|
191
192
|
} else {
|
|
192
193
|
result += ">";
|
|
194
|
+
if (frame.innerText && !hasText && !options.textFilter) {
|
|
195
|
+
result += frame.innerText;
|
|
196
|
+
}
|
|
193
197
|
}
|
|
194
198
|
},
|
|
195
199
|
ontext: function(text) {
|
|
@@ -292,7 +296,12 @@ function sanitizeHtml(html, options, _recursing) {
|
|
|
292
296
|
// Case insensitive so we don't get faked out by JAVASCRIPT #1
|
|
293
297
|
var matches = href.match(/^([a-zA-Z]+)\:/);
|
|
294
298
|
if (!matches) {
|
|
295
|
-
//
|
|
299
|
+
// Protocol-relative URL: "//some.evil.com/nasty"
|
|
300
|
+
if (href.match(/^\/\//)) {
|
|
301
|
+
return !options.allowProtocolRelative;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// No scheme
|
|
296
305
|
return false;
|
|
297
306
|
}
|
|
298
307
|
var scheme = matches[1].toLowerCase();
|
|
@@ -336,7 +345,8 @@ sanitizeHtml.defaults = {
|
|
|
336
345
|
selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
|
|
337
346
|
// URL schemes we permit
|
|
338
347
|
allowedSchemes: [ 'http', 'https', 'ftp', 'mailto' ],
|
|
339
|
-
allowedSchemesByTag: {}
|
|
348
|
+
allowedSchemesByTag: {},
|
|
349
|
+
allowProtocolRelative: true
|
|
340
350
|
};
|
|
341
351
|
|
|
342
352
|
sanitizeHtml.simpleTransform = function(newTagName, newAttribs, merge) {
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanitize-html",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.1",
|
|
4
4
|
"description": "Clean up user-submitted HTML, preserving whitelisted elements and whitelisted attributes on a per-element basis",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"
|
|
7
|
+
"build": "browserify index.js > dist/sanitize-html.js --standalone 'sanitizeHtml'",
|
|
8
|
+
"minify": "npm run build && uglifyjs dist/sanitize-html.js > dist/sanitize-html.min.js",
|
|
9
|
+
"test": "mocha test/test.js",
|
|
10
|
+
"prebuild": "npm run test && rm -rf dist && mkdir dist"
|
|
8
11
|
},
|
|
9
12
|
"repository": {
|
|
10
13
|
"type": "git",
|
|
@@ -24,5 +27,10 @@
|
|
|
24
27
|
"htmlparser2": "^3.9.0",
|
|
25
28
|
"regexp-quote": "0.0.0",
|
|
26
29
|
"xtend": "^4.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"browserify": "^13.0.1",
|
|
33
|
+
"mocha": "^2.5.3",
|
|
34
|
+
"uglify-js": "^2.6.2"
|
|
27
35
|
}
|
|
28
36
|
}
|
package/test/test.js
CHANGED
|
@@ -144,6 +144,25 @@ describe('sanitizeHtml', function() {
|
|
|
144
144
|
}}), '<a href="http://somelink">some_text_need"to<be>filtered</a>');
|
|
145
145
|
});
|
|
146
146
|
|
|
147
|
+
it('should add new text when not initially set and replace attributes when they are changed by transforming function', function () {
|
|
148
|
+
assert.equal(sanitizeHtml('<a href="http://somelink"></a>', { transformTags: {a: function (tagName, attribs) {
|
|
149
|
+
return {
|
|
150
|
+
tagName: tagName,
|
|
151
|
+
attribs: attribs,
|
|
152
|
+
text: 'some new text'
|
|
153
|
+
}
|
|
154
|
+
}}}), '<a href="http://somelink">some new text</a>');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should preserve text when initially set and replace attributes when they are changed by transforming function', function () {
|
|
158
|
+
assert.equal(sanitizeHtml('<a href="http://somelink">some initial text</a>', { transformTags: {a: function (tagName, attribs) {
|
|
159
|
+
return {
|
|
160
|
+
tagName: tagName,
|
|
161
|
+
attribs: attribs
|
|
162
|
+
}
|
|
163
|
+
}}}), '<a href="http://somelink">some initial text</a>');
|
|
164
|
+
});
|
|
165
|
+
|
|
147
166
|
it('should skip an empty link', function() {
|
|
148
167
|
assert.strictEqual(
|
|
149
168
|
sanitizeHtml('<p>This is <a href="http://www.linux.org"></a><br/>Linux</p>', {
|
|
@@ -495,4 +514,22 @@ describe('sanitizeHtml', function() {
|
|
|
495
514
|
), '!<textarea></textarea><svg/onload=prompt`xs`></textarea>!'
|
|
496
515
|
);
|
|
497
516
|
});
|
|
517
|
+
it('should allow protocol relative links by default', function() {
|
|
518
|
+
assert.equal(
|
|
519
|
+
sanitizeHtml('<a href="//cnn.com/example">test</a>'),
|
|
520
|
+
'<a href="//cnn.com/example">test</a>'
|
|
521
|
+
);
|
|
522
|
+
});
|
|
523
|
+
it('should not allow protocol relative links when allowProtocolRelative is false', function() {
|
|
524
|
+
assert.equal(
|
|
525
|
+
sanitizeHtml('<a href="//cnn.com/example">test</a>', { allowProtocolRelative: false }),
|
|
526
|
+
'<a>test</a>'
|
|
527
|
+
);
|
|
528
|
+
});
|
|
529
|
+
it('should still allow regular relative URLs when allowProtocolRelative is false', function() {
|
|
530
|
+
assert.equal(
|
|
531
|
+
sanitizeHtml('<a href="/welcome">test</a>', { allowProtocolRelative: false }),
|
|
532
|
+
'<a href="/welcome">test</a>'
|
|
533
|
+
);
|
|
534
|
+
});
|
|
498
535
|
});
|