New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

html-janitor

Package Overview
Dependencies
Maintainers
2
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

html-janitor - npm Package Compare versions

Comparing version 2.0.0 to 2.0.1

6

CHANGELOG.md

@@ -5,2 +5,8 @@ # HTML Janitor

## 2.0.1
Adds the ability to configure HTML Janitor with validation functions that determine whether a given element should be allowed programatically.
Thanks [Brad Vogel](https://github.com/bradvogel) for adding this functionality.
## 2.0.0

@@ -7,0 +13,0 @@

6

package.json
{
"name": "html-janitor",
"version": "2.0.0",
"version": "2.0.1",
"main": "src/html-janitor.js",

@@ -8,2 +8,6 @@ "scripts": {

},
"repository": {
"type": "git",
"url": "https://github.com/guardian/html-janitor.git"
},
"devDependencies": {

@@ -10,0 +14,0 @@ "karma": "~0.10.2",

@@ -26,6 +26,36 @@ # html-janitor

#### Blacklisting and whitelisting attributes
#### Blacklisting and whitelisting all attributes
You can set an element to be `true` to allow all attributes on an element and `false` to remove all attributes.
#### Using logic
If you need to apply logic when determining whether to whitelist an element or an attribute, you can pass a function.
Here's an example that removes all `<u>` elements that are empty.
```
u: function(el){
// Remove empty underline tags.
var shouldKeep = el.textContent !== '';
return shouldKeep;
},
```
A function can also be used for attributes, only the attribute's value and the element are passed as the function arguments:
```
img: {
height: function(value){
// Only allow if height is less than 10.
return parseInt(value) < 10;
},
width: function(value, el){
// Only allow if height also specified.
return el.hasAttribute('height');
}
}
```
## Distribution

@@ -32,0 +62,0 @@

50

src/html-janitor.js

@@ -22,3 +22,3 @@ (function (root, factory) {

.map(function(k) { return typeof tagDefinitions[k]; })
.every(function(type) { return type === 'object' || type === 'boolean'; });
.every(function(type) { return type === 'object' || type === 'boolean' || type === 'function'; });

@@ -58,5 +58,2 @@ if(!validConfigValues) {

do {
var nodeName = node.nodeName.toLowerCase();
var allowedAttrs = this.config.tags[nodeName];
// Ignore nodes that have already been sanitized

@@ -97,4 +94,2 @@ if (node._sanitized) {

var isInvalid = isInline && containsBlockElement;
// Block elements should not be nested (e.g. <li><p>...); if

@@ -108,5 +103,11 @@ // they are, we want to unwrap the inner block element.

var nodeName = node.nodeName.toLowerCase();
var allowedAttrs = this.config.tags[nodeName];
var isInvalid = isInline && containsBlockElement;
// Drop tag entirely according to the whitelist *and* if the markup
// is invalid.
if (this.config.tags[nodeName] === undefined || isInvalid || (!this.config.keepNestedBlockElements && isNestedBlockElement)) {
if (isInvalid || shouldRejectNode(node, allowedAttrs)
|| (!this.config.keepNestedBlockElements && isNestedBlockElement)) {
// Do not keep the inner text of SCRIPT/STYLE elements.

@@ -127,9 +128,4 @@ if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) {

var attr = node.attributes[a];
var attrName = attr.name.toLowerCase();
// Allow attribute?
var allowedAttrValue = allowedAttrs[attrName] || allowedAttrs === true;
var notInAttrList = ! allowedAttrValue;
var valueNotAllowed = allowedAttrValue !== true && attr.value !== allowedAttrValue;
if (notInAttrList || valueNotAllowed) {
if (shouldRejectAttr(attr, allowedAttrs, node)) {
node.removeAttribute(attr.name);

@@ -155,4 +151,32 @@ // Shift the array to continue looping.

function shouldRejectNode(node, allowedAttrs){
if (typeof allowedAttrs === 'undefined') {
return true;
} else if (typeof allowedAttrs === 'function'){
return !allowedAttrs(node);
}
return false;
}
function shouldRejectAttr(attr, allowedAttrs, node){
var attrName = attr.name.toLowerCase();
if (allowedAttrs === true){
return false;
} else if (typeof allowedAttrs[attrName] === 'function'){
return !allowedAttrs[attrName](attr.value, node);
} else if (typeof allowedAttrs[attrName] === 'undefined'){
return true;
} else if (allowedAttrs[attrName] === false) {
return true;
} else if (typeof allowedAttrs[attrName] === 'string') {
return (allowedAttrs[attrName] !== attr.value);
}
return false;
}
return HTMLJanitor;
}));

@@ -16,3 +16,2 @@ define([ 'html-janitor' ], function (HTMLJanitor) {

sup: {},
u: {},
strike: {},

@@ -25,3 +24,18 @@

div: {},
figure: false
figure: false,
u: function(el){
// Remove empty underline tags.
var shouldKeepEl = el.innerHTML !== '';
return shouldKeepEl;
},
img: {
height: function(value){
// Only allow if height is less than 10.
return parseInt(value) < 10;
},
width: function(value, el){
// Only allow if height also specified.
return el.hasAttribute('height');
}
}
}

@@ -153,3 +167,3 @@

el.setAttribute('title', 'test');
var outputEl = document.createElement('div');

@@ -166,3 +180,3 @@ outputEl.innerHTML = janitor.clean(el.outerHTML);

expect(attributes.getNamedItem('data-test').value).toBe('true');
expect(attributes.getNamedItem('title').name).toBe('title');

@@ -182,2 +196,25 @@ expect(attributes.getNamedItem('title').value).toBe('test');

it('should handle functions as options', function () {
var html = '<div><u>content</u></div>';
expect(janitor.clean(html)).toBe('<div><u>content</u></div>');
html = '<div><u></u></div>';
expect(janitor.clean(html)).toBe('<div></div>');
});
it('should handle functions as options for attributes', function () {
var html = '<img height="11">';
expect(janitor.clean(html)).toBe('<img>');
html = '<img height="9">';
expect(janitor.clean(html)).toBe('<img height="9">');
});
it('should also handle functions for attributes that take an element', function () {
var html = '<img width="1">';
expect(janitor.clean(html)).toBe('<img>');
html = '<img height="9" width="1">';
expect(janitor.clean(html)).toBe('<img height="9" width="1">');
});
});

@@ -184,0 +221,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc