From c63f87b61fdc97f28e6706d0ee68d614b4793d55 Mon Sep 17 00:00:00 2001 From: Zongmin Lei Date: Thu, 13 Feb 2014 18:18:43 +0800 Subject: [PATCH] test: stripIgnoreTagBody --- README.md | 40 ++++++++++++++++--------------- lib/default.js | 8 ++++++- lib/old/utils.js | 49 -------------------------------------- lib/xss.js | 21 ++++++++++++++-- test/test_custom_method.js | 40 +++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 71 deletions(-) delete mode 100644 lib/old/utils.js diff --git a/README.md b/README.md index 5083781..8e64fb4 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,8 @@ html = xss('', options); ### 白名单 -通过 `whiteList` 来指定,格式为:`{'标签名': ['属性1', '属性2']}`。不在白名单中 -的标签将被过滤,不在白名单中的属性也会被过滤。以下是示例: +通过 `whiteList` 来指定,格式为:`{'标签名': ['属性1', '属性2']}`。不在白名单上 +的标签将被过滤,不在白名单上的属性也会被过滤。以下是示例: ```JavaScript // 只允许a标签,该标签只允许href, title, target这三个属性 @@ -94,14 +94,14 @@ function onTag (tag, html, options) { // tag是当前的标签名称,比如标签,则tag的值是'a' // html是该标签的HTML,比如标签,则html的值是'' // options是一些附加的信息,具体如下: - // isWhite boolean类型,表示该标签是否在白名单中 + // isWhite boolean类型,表示该标签是否在白名单上 // isClosing boolean类型,表示该标签是否为闭合标签,比如时为true // position integer类型,表示当前标签在输出的结果中的起始位置 // sourcePosition integer类型,表示当前标签在原HTML中的起始位置 // 如果返回一个字符串,则当前标签将被替换为该字符串 // 如果不返回任何值,则使用默认的处理方法: - // 在白名单中: 通过onTagAttr来过滤属性,详见下文 - // 不在白名单中:通过onIgnoreTag指定,详见下文 + // 在白名单上: 通过onTagAttr来过滤属性,详见下文 + // 不在白名单上:通过onIgnoreTag指定,详见下文 } ``` @@ -114,15 +114,15 @@ function onTagAttr (tag, name, value, isWhiteAttr) { // tag是当前的标签名称,比如标签,则tag的值是'a' // name是当前属性的名称,比如href="#",则name的值是'href' // value是当前属性的值,比如href="#",则value的值是'#' - // isWhiteAttr是否为白名单中的属性 + // isWhiteAttr是否为白名单上的属性 // 如果返回一个字符串,则当前属性值将被替换为该字符串 // 如果不返回任何值,则使用默认的处理方法 - // 在白名单中: 输出该属性 - // 不在白名单中:通过onIgnoreTagAttr指定,详见下文 + // 在白名单上: 输出该属性 + // 不在白名单上:通过onIgnoreTagAttr指定,详见下文 } ``` -### 自定义匹配到不在白名单中的标签时的处理方法 +### 自定义匹配到不在白名单上的标签时的处理方法 通过 `onIgnoreTag` 来指定相应的处理函数。以下是详细说明: @@ -134,7 +134,7 @@ function onIgnoreTag (tag, html, options) { } ``` -### 自定义匹配到不在白名单中的属性时的处理方法 +### 自定义匹配到不在白名单上的属性时的处理方法 通过 `onIgnoreTagAttr` 来指定相应的处理函数。以下是详细说明: @@ -169,22 +169,24 @@ function safeAttrValue (tag, name, value) { ### 快捷配置 -#### stripIgnoreTag +#### 去掉不在白名单只的标签 -是否去掉不在白名单只的标签: +通过 `stripIgnoreTag` 来设置: -+ `true`:(默认),去掉不在白名单中的标签 ++ `true`:(默认),去掉不在白名单上的标签 + `false`:使用配置的`escape`函数对该标签进行转义 +#### 去掉不在白名单上的标签及标签体 + +通过 `stripIgnoreTagBody` 来设置: + ++ `false|null|undefined`:(默认),不特殊处理 ++ `'*'|true`:去掉所有不在白名单上的标签 ++ `['tag1', 'tag2']`:仅去掉指定的不在白名单上的标签 + ## 应用实例 -### 去掉<script>标签及标签体内的JS代码 - -```JavaScript -// 待续 -``` - ### 允许标签以data-开头的属性 ```JavaScript diff --git a/lib/default.js b/lib/default.js index fb6c70b..d422f88 100644 --- a/lib/default.js +++ b/lib/default.js @@ -273,12 +273,18 @@ function StripTagBody (tags, next) { next = function () {}; } + var isRemoveAllTag = !Array.isArray(tags); + function isRemoveTag (tag) { + if (isRemoveAllTag) return true; + return tags.indexOf(tag) !== -1; + } + var removeList = []; // 要删除的位置范围列表 var posStart = false; // 当前标签开始位置 return { onIgnoreTag: function (tag, html, options) { - if (tags.indexOf(tag) !== -1) { + if (isRemoveTag(tag)) { if (options.isClosing) { var ret = '[/removed]'; var end = options.position + ret.length; diff --git a/lib/old/utils.js b/lib/old/utils.js deleted file mode 100644 index 5235275..0000000 --- a/lib/old/utils.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * 工具函数 - * - * @author 老雷 - */ - -var utils = module.exports; - -/** - * 过滤代码块 - * - * @param {array} tags 要隐藏的标签列表 - * @param {function} next 对不在列表中的标签的处理函数 - */ -utils.tagFilter = function (tags, next) { - if (typeof(next) !== 'function') { - next = function () {}; - } - var hidden = []; - var posStart = false; - return { - onIgnoreTag: function (tag, html, options) { - if (tags.indexOf(tag) !== -1) { - var ret = '[removed]'; - if (posStart !== false && options.isClosing) { - var end = options.position + ret.length; - hidden.push([posStart, end]); - posStart = false; - } else { - posStart = options.position; - } - return ret; - } else { - return next(tag, html, options); - } - }, - filter: function (html) { - var rethtml = ''; - var lastPos = 0; - hidden.forEach(function (pos) { - rethtml += html.slice(lastPos, pos[0]); - lastPos = pos[1]; - }); - rethtml += html.slice(lastPos); - return rethtml; - } - }; -}; - diff --git a/lib/xss.js b/lib/xss.js index ad3613c..0ed9e4f 100644 --- a/lib/xss.js +++ b/lib/xss.js @@ -48,7 +48,9 @@ function getAttrs (html) { /** * XSS过滤对象 * - * @param {Object} options 选项:whiteList, onTag, onTagAttr, onIgnoreTag, onIgnoreTagAttr, safeAttrValue, escapeHtml + * @param {Object} options 选项:whiteList, onTag, onTagAttr, onIgnoreTag, + * onIgnoreTagAttr, safeAttrValue, escapeHtml + * stripIgnoreTagBody */ function FilterXSS (options) { options = options || {}; @@ -87,7 +89,15 @@ FilterXSS.prototype.process = function (html) { var safeAttrValue = options.safeAttrValue; var escapeHtml = options.escapeHtml - return parseTag(html, function (sourcePosition, position, tag, html, isClosing) { + // 如果开启了stripIgnoreTagBody + if (options.stripIgnoreTagBody) { + var stripIgnoreTagBody = DEFAULT.StripTagBody(options.stripIgnoreTagBody, onIgnoreTag); + onIgnoreTag = stripIgnoreTagBody.onIgnoreTag; + } else { + stripIgnoreTagBody = false; + } + + var retHtml = parseTag(html, function (sourcePosition, position, tag, html, isClosing) { var info = { sourcePosition: sourcePosition, position: position, @@ -148,6 +158,13 @@ FilterXSS.prototype.process = function (html) { } }, escapeHtml); + + // 如果开启了stripIgnoreTagBody,需要对结果再进行处理 + if (stripIgnoreTagBody) { + retHtml = stripIgnoreTagBody.remove(retHtml); + } + + return retHtml; }; diff --git a/test/test_custom_method.js b/test/test_custom_method.js index 526250a..0bf94e8 100644 --- a/test/test_custom_method.js +++ b/test/test_custom_method.js @@ -263,4 +263,44 @@ describe('test custom XSS method', function () { assert.equal(html, 'yybb'); }); + it('#stripTagBody - true', function () { + var source = 'linkhahaabk'; + var html = xss(source, { + stripIgnoreTagBody: true + }); + console.log(html); + assert.equal(html, 'linkbk'); + }); + + it('#stripIgnoreTagBody - *', function () { + var source = 'linkhahaabk'; + var html = xss(source, { + stripIgnoreTagBody: '*' + }); + console.log(html); + assert.equal(html, 'linkbk'); + }); + + it('#stripIgnoreTagBody - [\'x\']', function () { + var source = 'linkhahaabk'; + var html = xss(source, { + stripIgnoreTagBody: ['x'] + }); + console.log(html); + assert.equal(html, 'link<y>a<y></y>b</y>k'); + }); + + it('#stripIgnoreTagBody - [\'x\'] & onIgnoreTag', function () { + var source = 'linkhahaabk'; + var html = xss(source, { + stripIgnoreTagBody: ['x'], + onIgnoreTag: function (tag, html, options) { + return '$' + tag + '$'; + } + }); + console.log(html); + assert.equal(html, 'link$y$a$y$$y$b$y$k'); + }); + + }); \ No newline at end of file