sanitize-html
Advanced tools
Comparing version 1.27.1 to 2.0.0-beta
## Changelog | ||
2.0.0-beta: | ||
- Moves the `index.js` file to the project root and removes all build steps within the package. Going forward, it is up to the developer to include sanitize-html in their project builds as-needed. This removes major points of conflict with project code and frees this module to not worry about myriad build-related questions. | ||
- Replaces lodash with utility packages: klona, is-plain-object, deepmerge, escape-string-regexp. | ||
- Makes custom tag transformations less error-prone by escaping frame `innerText`. Thanks to [Mike Samuel](https://github.com/mikesamuel) for the contribution. | ||
Prior to this patch, tag transformations which turned an attribute | ||
value into a text node could be vulnerable to code execution. | ||
- Updates code to use modern features including `const`/`let` variable assignment. | ||
- ESLint clean up. | ||
- Updates `is-plain-object` to the 4.x major version. | ||
- Updates `srcset` to the 3.x major version. | ||
Thanks to [Bogdan Chadkin](https://github.com/TrySound) for contributions to this major version update. | ||
1.27.1 (2020-07-15): | ||
@@ -4,0 +17,0 @@ - Removes the unused chalk dependency. |
{ | ||
"name": "sanitize-html", | ||
"version": "1.27.1", | ||
"version": "2.0.0-beta", | ||
"description": "Clean up user-submitted HTML, preserving whitelisted elements and whitelisted attributes on a per-element basis", | ||
"sideEffects": false, | ||
"main": "dist/sanitize-html.js", | ||
"files": [ | ||
"dist/" | ||
], | ||
"main": "index.js", | ||
"scripts": { | ||
"build": "mkdir -p dist && browserify src/index.js > dist/sanitize-html-es2015.js --standalone 'sanitizeHtml' && babel dist/sanitize-html-es2015.js --out-file dist/sanitize-html.js --presets=@babel/preset-env", | ||
"minify": "npm run build && uglifyjs dist/sanitize-html.js > dist/sanitize-html.min.js", | ||
"prepublishOnly": "npm run minify", | ||
"test": "npx eslint . && npm run prepublishOnly && mocha test/test.js" | ||
"test": "npx eslint . && mocha test/test.js" | ||
}, | ||
@@ -23,4 +17,3 @@ "repository": { | ||
"parser", | ||
"sanitizer", | ||
"apostrophecms" | ||
"sanitizer" | ||
], | ||
@@ -30,24 +23,21 @@ "author": "Apostrophe Technologies, Inc.", | ||
"dependencies": { | ||
"deepmerge": "^4.2.2", | ||
"escape-string-regexp": "^4.0.0", | ||
"htmlparser2": "^4.1.0", | ||
"lodash": "^4.17.15", | ||
"is-plain-object": "^4.1.1", | ||
"klona": "^1.1.2", | ||
"postcss": "^7.0.27", | ||
"srcset": "^2.0.1" | ||
"srcset": "^3.0.0" | ||
}, | ||
"devDependencies": { | ||
"@babel/cli": "^7.8.4", | ||
"@babel/core": "^7.8.4", | ||
"@babel/preset-env": "^7.8.4", | ||
"babelify": "^10.0.0", | ||
"browserify": "^16.2.3", | ||
"eslint": "^4.0.0", | ||
"eslint-config-apostrophe": "^3.1.0", | ||
"eslint-config-standard": "^11.0.0", | ||
"eslint-plugin-import": "^2.13.0", | ||
"eslint-plugin-node": "^6.0.1", | ||
"eslint-plugin-promise": "^3.8.0", | ||
"eslint-plugin-standard": "^3.1.0", | ||
"eslint": "^7.3.1", | ||
"eslint-config-apostrophe": "^3.2.0", | ||
"eslint-config-standard": "^14.1.1", | ||
"eslint-plugin-import": "^2.21.2", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-promise": "^4.2.1", | ||
"eslint-plugin-standard": "^4.0.1", | ||
"mocha": "^5.2.0", | ||
"sinon": "^9.0.2", | ||
"uglify-js": "^3.8.0" | ||
"sinon": "^9.0.2" | ||
} | ||
} | ||
} |
211
README.md
# sanitize-html | ||
[![CircleCI](https://circleci.com/gh/apostrophecms/sanitize-html/tree/master.svg?style=svg)](https://circleci.com/gh/apostrophecms/sanitize-html/tree/master) | ||
[![CircleCI](https://circleci.com/gh/apostrophecms/sanitize-html/tree/main.svg?style=svg)](https://circleci.com/gh/apostrophecms/sanitize-html/tree/main) | ||
@@ -37,25 +37,17 @@ <a href="https://apostrophecms.com/"><img src="https://raw.github.com/apostrophecms/sanitize-html/master/logos/logo-box-madefor.png" align="right" /></a> | ||
* Clone repository | ||
* Run npm install and build / minify: | ||
* Clone repository and install via npm | ||
* Run npm install and : | ||
```bash | ||
npm install | ||
npm run minify | ||
npm install sanitize-html # yarn install sanitize-html | ||
``` | ||
You'll find the minified and unminified versions of sanitize-html (with all its dependencies included) in the dist/ directory. | ||
The primary change in the 2.x version of sanitize-html is that it no longer includes a build that is ready for browser use. Developers are expected to include sanitize-html in their project builds (e.g., webpack) as they would any other dependency. So while sanitize-html is no longer ready to link to directly in HTML, developers can now more easily process it according to their needs. | ||
Use it in the browser: | ||
Once built and linked in the browser with other project Javascript it can be used to sanitize HTML strings in front end code: | ||
```html | ||
<html> | ||
<body> | ||
<script type="text/javascript" src="dist/sanitize-html.js"></script> | ||
<script type="text/javascript" src="demo.js"></script> | ||
</body> | ||
</html> | ||
``` | ||
```javascript | ||
import sanitizeHtml from 'sanitize-html'; | ||
```javascript | ||
var html = "<strong>hello world</strong>"; | ||
const html = "<strong>hello world</strong>"; | ||
console.log(sanitizeHtml(html)); | ||
@@ -78,13 +70,13 @@ console.log(sanitizeHtml("<img src=x onerror=alert('img') />")); | ||
```js | ||
var sanitizeHtml = require('sanitize-html'); | ||
const sanitizeHtml = require('sanitize-html'); | ||
var dirty = 'some really tacky HTML'; | ||
var clean = sanitizeHtml(dirty); | ||
const dirty = 'some really tacky HTML'; | ||
const clean = sanitizeHtml(dirty); | ||
``` | ||
That will allow our default list of allowed tags and attributes through. It's a nice set, but probably not quite what you want. So: | ||
That will allow our [default list of allowed tags and attributes](#default-options) through. It's a nice set, but probably not quite what you want. So: | ||
```js | ||
// Allow only a super restricted set of tags and attributes | ||
clean = sanitizeHtml(dirty, { | ||
const clean = sanitizeHtml(dirty, { | ||
allowedTags: [ 'b', 'i', 'em', 'strong', 'a' ], | ||
@@ -100,15 +92,5 @@ allowedAttributes: { | ||
#### "I like your set but I want to add one more tag. Is there a convenient way?" Sure: | ||
### Default options | ||
```js | ||
clean = sanitizeHtml(dirty, { | ||
allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'img' ]) | ||
}); | ||
``` | ||
If you do not specify `allowedTags` or `allowedAttributes` our default list is applied. So if you really want an empty list, specify one. | ||
#### "What are the default options?" | ||
```js | ||
allowedTags: [ 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', | ||
@@ -135,2 +117,14 @@ 'nl', 'li', 'b', 'i', 'strong', 'em', 'strike', 'abbr', 'code', 'hr', 'br', 'div', | ||
### Common use cases | ||
#### "I like your set but I want to add one more tag. Is there a convenient way?" Sure: | ||
```js | ||
const clean = sanitizeHtml(dirty, { | ||
allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'img' ]) | ||
}); | ||
``` | ||
If you do not specify `allowedTags` or `allowedAttributes` our default list is applied. So if you really want an empty list, specify one. | ||
#### "What if I want to allow all tags or all attributes?" | ||
@@ -155,3 +149,3 @@ | ||
### "What if I want disallowed tags to be escaped rather than discarded?" | ||
#### "What if I want disallowed tags to be escaped rather than discarded?" | ||
@@ -164,3 +158,3 @@ If you set `disallowedTagsMode` to `discard` (the default), disallowed tags are discarded. Any text content or subtags is still included, depending on whether the individual subtags are allowed. | ||
### "What if I want to allow only specific values on some attributes?" | ||
#### "What if I want to allow only specific values on some attributes?" | ||
@@ -170,10 +164,10 @@ When configuring the attribute in `allowedAttributes` simply use an object with attribute `name` and an allowed `values` array. In the following example `sandbox="allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-scripts"` would become `sandbox="allow-popups allow-scripts"`: | ||
```js | ||
allowedAttributes: { | ||
iframe: [ | ||
{ | ||
name: 'sandbox', | ||
multiple: true, | ||
values: ['allow-popups', 'allow-same-origin', 'allow-scripts'] | ||
} | ||
] | ||
allowedAttributes: { | ||
iframe: [ | ||
{ | ||
name: 'sandbox', | ||
multiple: true, | ||
values: ['allow-popups', 'allow-same-origin', 'allow-scripts'] | ||
} | ||
] | ||
``` | ||
@@ -200,2 +194,52 @@ | ||
``` | ||
## Additional options | ||
### Allowed CSS Classes | ||
If you wish to allow specific CSS classes on a particular element, you can do so with the `allowedClasses` option. Any other CSS classes are discarded. | ||
This implies that the `class` attribute is allowed on that element. | ||
```javascript | ||
// Allow only a restricted set of CSS classes and only on the p tag | ||
const clean = sanitizeHtml(dirty, { | ||
allowedTags: [ 'p', 'em', 'strong' ], | ||
allowedClasses: { | ||
'p': [ 'fancy', 'simple' ] | ||
} | ||
}); | ||
``` | ||
### Allowed CSS Styles | ||
If you wish to allow specific CSS _styles_ on a particular element, you can do that with the `allowedStyles` option. Simply declare your desired attributes as regular expression options within an array for the given attribute. Specific elements will inherit whitelisted attributes from the global (\*) attribute. Any other CSS classes are discarded. | ||
**You must also use `allowedAttributes`** to activate the `style` attribute for the relevant elements. Otherwise this feature will never come into play. | ||
**When constructing regular expressions, don't forget `^` and `$`.** It's not enough to say "the string should contain this." It must also say "and only this." | ||
**URLs in inline styles are NOT filtered by any mechanism other than your regular expression.** | ||
```javascript | ||
const clean = sanitizeHtml(dirty, { | ||
allowedTags: ['p'], | ||
allowedAttributes: { | ||
'p': ["style"], | ||
}, | ||
allowedStyles: { | ||
'*': { | ||
// Match HEX and RGB | ||
'color': [/^#(0x)?[0-9a-f]+$/i, /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/], | ||
'text-align': [/^left$/, /^right$/, /^center$/], | ||
// Match any number with px, em, or % | ||
'font-size': [/^\d+(?:px|em|%)$/] | ||
}, | ||
'p': { | ||
'font-size': [/^\d+rem$/] | ||
} | ||
} | ||
}); | ||
``` | ||
### Discarding text outside of ```<html></html>``` tags | ||
@@ -216,3 +260,3 @@ | ||
```javascript | ||
clean = sanitizeHtml(dirty, { | ||
const clean = sanitizeHtml(dirty, { | ||
allowedTags: ['a'], | ||
@@ -233,3 +277,3 @@ parser: { | ||
```js | ||
clean = sanitizeHtml(dirty, { | ||
const clean = sanitizeHtml(dirty, { | ||
transformTags: { | ||
@@ -244,7 +288,6 @@ 'ol': 'ul', | ||
```js | ||
clean = sanitizeHtml(dirty, { | ||
const clean = sanitizeHtml(dirty, { | ||
transformTags: { | ||
'ol': function(tagName, attribs) { | ||
// My own custom magic goes here | ||
return { | ||
@@ -266,3 +309,3 @@ tagName: 'ul', | ||
```js | ||
clean = sanitizeHtml(dirty, { | ||
const clean = sanitizeHtml(dirty, { | ||
transformTags: { | ||
@@ -285,3 +328,3 @@ 'ol': sanitizeHtml.simpleTransform('ul', {class: 'foo'}), | ||
```js | ||
clean = sanitizeHtml(dirty, { | ||
const clean = sanitizeHtml(dirty, { | ||
transformTags: { | ||
@@ -384,3 +427,3 @@ 'a': function(tagName, attribs) { | ||
```javascript | ||
clean = sanitizeHtml('<p><iframe src="https://www.youtube.com/embed/nykIhs12345"></iframe><p>', { | ||
const clean = sanitizeHtml('<p><iframe src="https://www.youtube.com/embed/nykIhs12345"></iframe><p>', { | ||
allowedTags: [ 'p', 'em', 'strong', 'iframe' ], | ||
@@ -400,3 +443,3 @@ allowedClasses: { | ||
```javascript | ||
clean = sanitizeHtml('<p><iframe src="https://www.youtube.net/embed/nykIhs12345"></iframe><p>', { | ||
const clean = sanitizeHtml('<p><iframe src="https://www.youtube.net/embed/nykIhs12345"></iframe><p>', { | ||
allowedTags: [ 'p', 'em', 'strong', 'iframe' ], | ||
@@ -416,3 +459,3 @@ allowedClasses: { | ||
```javascript | ||
clean = sanitizeHtml('<p><iframe src="https://www.vimeo/video/12345"></iframe><p>', { | ||
const clean = sanitizeHtml('<p><iframe src="https://www.vimeo/video/12345"></iframe><p>', { | ||
allowedTags: [ 'p', 'em', 'strong', 'iframe' ], | ||
@@ -434,3 +477,4 @@ allowedClasses: { | ||
```javascript | ||
clean = sanitizeHtml('<p><iframe src="https://us02web.zoom.us/embed/12345"></iframe><p>', { | ||
// This iframe markup will pass through as safe. | ||
const clean = sanitizeHtml('<p><iframe src="https://us02web.zoom.us/embed/12345"></iframe><p>', { | ||
allowedTags: [ 'p', 'em', 'strong', 'iframe' ], | ||
@@ -448,51 +492,2 @@ allowedClasses: { | ||
will pass through as safe. | ||
### Allowed CSS Classes | ||
If you wish to allow specific CSS classes on a particular element, you can do so with the `allowedClasses` option. Any other CSS classes are discarded. | ||
This implies that the `class` attribute is allowed on that element. | ||
```javascript | ||
// Allow only a restricted set of CSS classes and only on the p tag | ||
clean = sanitizeHtml(dirty, { | ||
allowedTags: [ 'p', 'em', 'strong' ], | ||
allowedClasses: { | ||
'p': [ 'fancy', 'simple' ] | ||
} | ||
}); | ||
``` | ||
### Allowed CSS Styles | ||
If you wish to allow specific CSS _styles_ on a particular element, you can do that with the `allowedStyles` option. Simply declare your desired attributes as regular expression options within an array for the given attribute. Specific elements will inherit whitelisted attributes from the global (\*) attribute. Any other CSS classes are discarded. | ||
**You must also use `allowedAttributes`** to activate the `style` attribute for the relevant elements. Otherwise this feature will never come into play. | ||
**When constructing regular expressions, don't forget `^` and `$`.** It's not enough to say "the string should contain this." It must also say "and only this." | ||
**URLs in inline styles are NOT filtered by any mechanism other than your regular expression.** | ||
```javascript | ||
clean = sanitizeHtml(dirty, { | ||
allowedTags: ['p'], | ||
allowedAttributes: { | ||
'p': ["style"], | ||
}, | ||
allowedStyles: { | ||
'*': { | ||
// Match HEX and RGB | ||
'color': [/^#(0x)?[0-9a-f]+$/i, /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/], | ||
'text-align': [/^left$/, /^right$/, /^center$/], | ||
// Match any number with px, em, or % | ||
'font-size': [/^\d+(?:px|em|%)$/] | ||
}, | ||
'p': { | ||
'font-size': [/^\d+rem$/] | ||
} | ||
} | ||
}); | ||
``` | ||
### Allowed URL schemes | ||
@@ -569,14 +564,8 @@ | ||
## About P'unk Avenue and Apostrophe | ||
## About ApostropheCMS | ||
`sanitize-html` was created at [P'unk Avenue](http://punkave.com) for use in ApostropheCMS, an open-source content management system built on node.js. If you like `sanitize-html` you should definitely [check out apostrophecms.org](http://apostrophecms.org). | ||
`sanitize-html` was created at [P'unk Avenue](https://punkave.com) for use in [ApostropheCMS](https://apostrophecms.com), an open-source content management system built on Node.js. If you like `sanitize-html` you should definitely check out ApostropheCMS. | ||
## Changelog | ||
[The changelog is now in a separate file for readability.](https://github.com/apostrophecms/sanitize-html/blob/master/CHANGELOG.md) | ||
## Support | ||
Feel free to open issues on [github](http://github.com/apostrophecms/sanitize-html). | ||
<a href="http://apostrophecms.com/"><img src="https://raw.github.com/apostrophecms/sanitize-html/master/logos/logo-box-builtby.png" /></a> | ||
Feel free to open issues on [github](https://github.com/apostrophecms/sanitize-html). |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
9
12
0
1
114996
7
1777
553
+ Addeddeepmerge@^4.2.2
+ Addedescape-string-regexp@^4.0.0
+ Addedis-plain-object@^4.1.1
+ Addedklona@^1.1.2
+ Addeddeepmerge@4.3.1(transitive)
+ Addedescape-string-regexp@4.0.0(transitive)
+ Addedis-plain-object@4.1.1(transitive)
+ Addedklona@1.1.2(transitive)
+ Addedsrcset@3.0.1(transitive)
- Removedlodash@^4.17.15
- Removedlodash@4.17.21(transitive)
- Removedsrcset@2.0.1(transitive)
Updatedsrcset@^3.0.0