Skip to content

Commit

Permalink
Merge pull request #28 from blockchain-certificates/ahref-data-downlo…
Browse files Browse the repository at this point in the history
…ad-pr

feat(Sanitizer): allow an embedded file to be downloaded from the cert
  • Loading branch information
AnthonyRonning authored Jan 30, 2019
2 parents 8018fe6 + 0fba939 commit e1e7b23
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 3 deletions.
66 changes: 65 additions & 1 deletion sanitizer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function modifyWhiteList () {
Object.keys(whiteList).forEach(el => {
whiteList[el].push('style');
whiteList[el].push('class');
whiteList[el].push('download');
});

return whiteList;
Expand All @@ -39,11 +40,74 @@ function handleTagAttr (tag, name, value, isWhiteAttr) {
}
}

function handleAttrValue (tag, name, value, cssFilter) {
// unescape attribute value firstly
value = xss.friendlyAttrValue(value);

if (name === 'href' || name === 'src') {
// filter `href` and `src` attribute
// only allow the value that starts with `http://` | `https://` | `mailto:` | `data:` | `/` | `#`
value = utilTrim(value);
if (value === '#') return '#';
if (!isWhiteListedHref(value)) {
return '';
}
} else if (name === 'background') {
// filter `background` attribute (maybe no use)
// `javascript:`
REGEXP_DEFAULT_ON_TAG_ATTR_4.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_4.test(value)) {
return '';
}
} else if (name === 'style') {
// `expression()`
REGEXP_DEFAULT_ON_TAG_ATTR_7.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_7.test(value)) {
return '';
}
// `url()`
REGEXP_DEFAULT_ON_TAG_ATTR_8.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_8.test(value)) {
REGEXP_DEFAULT_ON_TAG_ATTR_4.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_4.test(value)) {
return '';
}
}
if (cssFilter !== false) {
cssFilter = cssFilter || xss.getDefaultCSSWhiteList();
value = cssFilter.process(value);
}
}

// escape `<>"` before returns
value = xss.escapeAttrValue(value);
return value;
}

function isWhiteListedHref (value) {
const whiteList = ['http://', 'https://', 'mailto:', 'tel:', 'data:', '#', '/'];
return whiteList.some(item => value.substr(0, item.length) === item);
}

// utility trim from xss
function utilTrim (str) {
if (String.prototype.trim) {
return str.trim();
}
return str.replace(/(^\s*)|(\s*$)/g, '');
}

// RegExp list from xss
var REGEXP_DEFAULT_ON_TAG_ATTR_4 = /((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a):/gi;
var REGEXP_DEFAULT_ON_TAG_ATTR_7 = /e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n\s*\(.*/gi;
var REGEXP_DEFAULT_ON_TAG_ATTR_8 = /u\s*r\s*l\s*\(.*/gi;

const options = {
whiteList: modifyWhiteList(),
css: false,
stripIgnoreTagBody: true,
onTagAttr: handleTagAttr
onTagAttr: handleTagAttr,
safeAttrValue: handleAttrValue
};
const sanitizer = new xss.FilterXSS(options);

Expand Down
66 changes: 65 additions & 1 deletion sanitizer/sanitizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,7 @@ function modifyWhiteList () {
Object.keys(whiteList).forEach(el => {
whiteList[el].push('style');
whiteList[el].push('class');
whiteList[el].push('download');
});

return whiteList;
Expand All @@ -1677,11 +1678,74 @@ function handleTagAttr (tag, name, value, isWhiteAttr) {
}
}

function handleAttrValue (tag, name, value, cssFilter) {
// unescape attribute value firstly
value = lib$1.friendlyAttrValue(value);

if (name === 'href' || name === 'src') {
// filter `href` and `src` attribute
// only allow the value that starts with `http://` | `https://` | `mailto:` | `data:` | `/` | `#`
value = utilTrim(value);
if (value === '#') return '#';
if (!isWhiteListedHref(value)) {
return '';
}
} else if (name === 'background') {
// filter `background` attribute (maybe no use)
// `javascript:`
REGEXP_DEFAULT_ON_TAG_ATTR_4$1.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_4$1.test(value)) {
return '';
}
} else if (name === 'style') {
// `expression()`
REGEXP_DEFAULT_ON_TAG_ATTR_7$1.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_7$1.test(value)) {
return '';
}
// `url()`
REGEXP_DEFAULT_ON_TAG_ATTR_8$1.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_8$1.test(value)) {
REGEXP_DEFAULT_ON_TAG_ATTR_4$1.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_4$1.test(value)) {
return '';
}
}
if (cssFilter !== false) {
cssFilter = cssFilter || lib$1.getDefaultCSSWhiteList();
value = cssFilter.process(value);
}
}

// escape `<>"` before returns
value = lib$1.escapeAttrValue(value);
return value;
}

function isWhiteListedHref (value) {
const whiteList = ['http://', 'https://', 'mailto:', 'tel:', 'data:', '#', '/'];
return whiteList.some(item => value.substr(0, item.length) === item);
}

// utility trim from xss
function utilTrim (str) {
if (String.prototype.trim) {
return str.trim();
}
return str.replace(/(^\s*)|(\s*$)/g, '');
}

// RegExp list from xss
var REGEXP_DEFAULT_ON_TAG_ATTR_4$1 = /((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a):/gi;
var REGEXP_DEFAULT_ON_TAG_ATTR_7$1 = /e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n\s*\(.*/gi;
var REGEXP_DEFAULT_ON_TAG_ATTR_8$1 = /u\s*r\s*l\s*\(.*/gi;

const options = {
whiteList: modifyWhiteList(),
css: false,
stripIgnoreTagBody: true,
onTagAttr: handleTagAttr
onTagAttr: handleTagAttr,
safeAttrValue: handleAttrValue
};
const sanitizer = new lib$1.FilterXSS(options);

Expand Down
Loading

0 comments on commit e1e7b23

Please sign in to comment.