From be18c62e52a8f19d36c4b2d48fe590080e4d23d7 Mon Sep 17 00:00:00 2001 From: adon Date: Fri, 10 Jul 2015 14:52:37 +0800 Subject: [PATCH] release as v1.2.4 --- Gruntfile.js | 2 +- bower.json | 2 +- dist/xss-filters.1.2.4.min.js | 5 + dist/xss-filters.js | 1097 +++++++++++++++++++++++++- dist/xss-filters.min-browserified.js | 5 + dist/xss-filters.min.js | 4 +- package.json | 2 +- src/xss-filters.js | 208 +++-- 8 files changed, 1209 insertions(+), 116 deletions(-) create mode 100644 dist/xss-filters.1.2.4.min.js create mode 100644 dist/xss-filters.min-browserified.js diff --git a/Gruntfile.js b/Gruntfile.js index ac713b6..eee303d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -50,7 +50,7 @@ module.exports = function(grunt) { }, buildBrowserified: { src: 'dist/<%= pkg.name %>.js', - dest: 'dist/<%= pkg.name %>.js' + dest: 'dist/<%= pkg.name %>.min-browserified.js' }, buildMin: { options: { diff --git a/bower.json b/bower.json index 0126731..17a0e53 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "xss-filters", - "version": "1.2.3", + "version": "1.2.4", "homepage": "https://github.com/yahoo/xss-filters", "authors": [ "Nera Liu ", diff --git a/dist/xss-filters.1.2.4.min.js b/dist/xss-filters.1.2.4.min.js new file mode 100644 index 0000000..1b6efa1 --- /dev/null +++ b/dist/xss-filters.1.2.4.min.js @@ -0,0 +1,5 @@ +/** + * xss-filters - v1.2.4 + * Yahoo! Inc. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. + */ +!function(a,b){function c(a,b,c){return d.yubl(b((c||d.yufull)(a)))}b.xssFilters=a,a._getPrivFilters=function(){function a(a){return a=a.split(w,2),2===a.length&&a[0]?a[0]:null}function b(a,b,c,d){function e(a,c,e,g){return c?(c=Number(c[0]<="9"?c:"0"+c),d?A(c):128===c?"€":130===c?"‚":131===c?"ƒ":132===c?"„":133===c?"…":134===c?"†":135===c?"‡":136===c?"ˆ":137===c?"‰":138===c?"Š":139===c?"‹":140===c?"Œ":142===c?"Ž":145===c?"‘":146===c?"’":147===c?"“":148===c?"”":149===c?"•":150===c?"–":151===c?"—":152===c?"˜":153===c?"™":154===c?"š":155===c?"›":156===c?"œ":158===c?"ž":159===c?"Ÿ":c>=55296&&57343>=c||13===c?"�":f.frCoPt(c)):b[e||g]||a}return b=b||p,c=c||o,void 0===a?"undefined":null===a?"null":a.toString().replace(k,"�").replace(c,e)}function c(a){return"\\"+a.charCodeAt(0).toString(16).toLowerCase()+" "}function d(a,d){return b(a).replace(d,c)}function e(d,e){d=f.yufull(b(d));var g=a(d);return g&&v[g.toLowerCase()]&&(d="##"+d),e?d.replace(e,c):d}var f,g=/])/g,m=/[&<>"'`]/g,n=/(?:\x00|^-*!?>|--!?>|--?!?$|\]>|\]$)/g,o=/&(?:#([xX][0-9A-Fa-f]+|\d+);?|(Tab|NewLine|colon|semi|lpar|rpar|apos|sol|comma|excl|ast|midast|ensp|emsp|thinsp);|(nbsp|amp|AMP|lt|LT|gt|GT|quot|QUOT);?)/g,p={Tab:" ",NewLine:"\n",colon:":",semi:";",lpar:"(",rpar:")",apos:"'",sol:"/",comma:",",excl:"!",ast:"*",midast:"*",ensp:" ",emsp:" ",thinsp:" ",nbsp:" ",amp:"&",lt:"<",gt:">",quot:'"',QUOT:'"'},q=/[^%#+\-\w\.]/g,r=/[\x01-\x1F\x7F\\"]/g,s=/[\x01-\x1F\x7F\\']/g,t=/['\(\)]/g,u=/\/\/%5[Bb]([A-Fa-f0-9:]+)%5[Dd]/,v={javascript:1,data:1,vbscript:1,mhtml:1},w=/(?::|&#[xX]0*3[aA];?|�*58;?|:)/,x=/(?:^[\x00-\x20]+|[\t\n\r\x00]+)/g,y={Tab:" ",NewLine:"\n"},z=function(a,b,c){return void 0===a?"undefined":null===a?"null":a.toString().replace(b,c)},A=String.fromCodePoint||function(a){return 0===arguments.length?"":65535>=a?String.fromCharCode(a):(a-=65536,String.fromCharCode((a>>10)+55296,a%1024+56320))};return f={frCoPt:function(a){return void 0===a||null===a?"":!isFinite(a=Number(a))||0>=a||a>1114111||a>=1&&8>=a||a>=14&&31>=a||a>=127&&159>=a||a>=64976&&65007>=a||11===a||65535===(65535&a)||65534===(65535&a)?"�":A(a)},d:b,yup:function(c){return c=a(c.replace(k,"")),c?b(c,y,null,!0).replace(x,"").toLowerCase():null},y:function(a){return z(a,m,function(a){return"&"===a?"&":"<"===a?"<":">"===a?">":'"'===a?""":"'"===a?"'":"`"})},ya:function(a){return z(a,j,"&")},yd:function(a){return z(a,g,"<")},yc:function(a){return z(a,n,function(a){return"\x00"===a?"�":"--!"===a||"--"===a||"-"===a||"]"===a?a+" ":a.slice(0,-1)+" >"})},yavd:function(a){return z(a,h,""")},yavs:function(a){return z(a,i,"'")},yavu:function(a){return z(a,l,function(a){return" "===a?" ":"\n"===a?" ":" "===a?" ":"\f"===a?" ":"\r"===a?" ":" "===a?" ":"="===a?"=":"<"===a?"<":">"===a?">":'"'===a?""":"'"===a?"'":"`"===a?"`":"�"})},yu:encodeURI,yuc:encodeURIComponent,yubl:function(a){return v[f.yup(a)]?"x-"+a:a},yufull:function(a){return f.yu(a).replace(u,function(a,b){return"//["+b+"]"})},yublf:function(a){return f.yubl(f.yufull(a))},yceu:function(a){return d(a,q)},yced:function(a){return d(a,r)},yces:function(a){return d(a,s)},yceuu:function(a){return e(a,t)},yceud:function(a){return e(a)},yceus:function(a){return e(a,i)}}};var d=a._privFilters=a._getPrivFilters();a.inHTMLData=d.yd,a.inHTMLComment=d.yc,a.inSingleQuotedAttr=d.yavs,a.inDoubleQuotedAttr=d.yavd,a.inUnQuotedAttr=d.yavu,a.uriInSingleQuotedAttr=function(a){return c(a,d.yavs)},a.uriInDoubleQuotedAttr=function(a){return c(a,d.yavd)},a.uriInUnQuotedAttr=function(a){return c(a,d.yavu)},a.uriInHTMLData=d.yufull,a.uriInHTMLComment=function(a){return d.yc(d.yufull(a))},a.uriPathInSingleQuotedAttr=function(a){return c(a,d.yavs,d.yu)},a.uriPathInDoubleQuotedAttr=function(a){return c(a,d.yavd,d.yu)},a.uriPathInUnQuotedAttr=function(a){return c(a,d.yavu,d.yu)},a.uriPathInHTMLData=d.yu,a.uriPathInHTMLComment=function(a){return d.yc(d.yu(a))},a.uriQueryInSingleQuotedAttr=a.uriPathInSingleQuotedAttr,a.uriQueryInDoubleQuotedAttr=a.uriPathInDoubleQuotedAttr,a.uriQueryInUnQuotedAttr=a.uriPathInUnQuotedAttr,a.uriQueryInHTMLData=a.uriPathInHTMLData,a.uriQueryInHTMLComment=a.uriPathInHTMLComment,a.uriComponentInSingleQuotedAttr=function(a){return d.yavs(d.yuc(a))},a.uriComponentInDoubleQuotedAttr=function(a){return d.yavd(d.yuc(a))},a.uriComponentInUnQuotedAttr=function(a){return d.yavu(d.yuc(a))},a.uriComponentInHTMLData=d.yuc,a.uriComponentInHTMLComment=function(a){return d.yc(d.yuc(a))},a.uriFragmentInSingleQuotedAttr=function(a){return d.yubl(d.yavs(d.yuc(a)))},a.uriFragmentInDoubleQuotedAttr=function(a){return d.yubl(d.yavd(d.yuc(a)))},a.uriFragmentInUnQuotedAttr=function(a){return d.yubl(d.yavu(d.yuc(a)))},a.uriFragmentInHTMLData=a.uriComponentInHTMLData,a.uriFragmentInHTMLComment=a.uriComponentInHTMLComment}({},function(){return this}()); \ No newline at end of file diff --git a/dist/xss-filters.js b/dist/xss-filters.js index b726a56..3fdc675 100644 --- a/dist/xss-filters.js +++ b/dist/xss-filters.js @@ -1,5 +1,1094 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.xssFilters = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o + Adonis Fung + Albert Yu +*/ +/*jshint node: true */ + +exports._getPrivFilters = function () { + + var LT = /])/g, + SPECIAL_HTML_CHARS = /[&<>"'`]/g, + SPECIAL_COMMENT_CHARS = /(?:\x00|^-*!?>|--!?>|--?!?$|\]>|\]$)/g; + + // CSS sensitive chars: ()"'/,!*@{}:; + // By CSS: (Tab|NewLine|colon|semi|lpar|rpar|apos|sol|comma|excl|ast|midast);|(quot|QUOT) + // By URI_PROTOCOL: (Tab|NewLine); + var SENSITIVE_HTML_ENTITIES = /&(?:#([xX][0-9A-Fa-f]+|\d+);?|(Tab|NewLine|colon|semi|lpar|rpar|apos|sol|comma|excl|ast|midast|ensp|emsp|thinsp);|(nbsp|amp|AMP|lt|LT|gt|GT|quot|QUOT);?)/g, + SENSITIVE_NAMED_REF_MAP = {Tab: '\t', NewLine: '\n', colon: ':', semi: ';', lpar: '(', rpar: ')', apos: '\'', sol: '/', comma: ',', excl: '!', ast: '*', midast: '*', ensp: '\u2002', emsp: '\u2003', thinsp: '\u2009', nbsp: '\xA0', amp: '&', lt: '<', gt: '>', quot: '"', QUOT: '"'}; + + // TODO: CSS_DANGEROUS_FUNCTION_NAME = /(url\(|expression\()/ig; + var CSS_UNQUOTED_CHARS = /[^%#+\-\w\.]/g, + // \x7F and \x01-\x1F less \x09 are for Safari 5.0 + CSS_DOUBLE_QUOTED_CHARS = /[\x01-\x1F\x7F\\"]/g, + CSS_SINGLE_QUOTED_CHARS = /[\x01-\x1F\x7F\\']/g, + // this assumes encodeURI() and encodeURIComponent() has escaped 1-32, 41, 127 for IE8 + CSS_UNQUOTED_URL = /['\(\)]/g; // " \ treated by encodeURI() + + // Given a full URI, need to support "[" ( IPv6address ) "]" in URI as per RFC3986 + // Reference: https://tools.ietf.org/html/rfc3986 + var URL_IPV6 = /\/\/%5[Bb]([A-Fa-f0-9:]+)%5[Dd]/; + + + // Reference: http://shazzer.co.uk/database/All/characters-allowd-in-html-entities + // Reference: http://shazzer.co.uk/vector/Characters-allowed-after-ampersand-in-named-character-references + // Reference: http://shazzer.co.uk/database/All/Characters-before-javascript-uri + // Reference: http://shazzer.co.uk/database/All/Characters-after-javascript-uri + // Reference: https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference + // Reference for named characters: https://html.spec.whatwg.org/multipage/entities.json + var URI_BLACKLIST_PROTOCOLS = {'javascript':1, 'data':1, 'vbscript':1, 'mhtml':1}, + URI_PROTOCOL_COLON = /(?::|&#[xX]0*3[aA];?|�*58;?|:)/, + URI_PROTOCOL_WHITESPACES = /(?:^[\x00-\x20]+|[\t\n\r\x00]+)/g, + URI_PROTOCOL_NAMED_REF_MAP = {Tab: '\t', NewLine: '\n'}; + + var x, + strReplace = function (s, regexp, callback) { + return s === undefined ? 'undefined' + : s === null ? 'null' + : s.toString().replace(regexp, callback); + }, + fromCodePoint = String.fromCodePoint || function(codePoint) { + if (arguments.length === 0) { + return ''; + } + if (codePoint <= 0xFFFF) { // BMP code point + return String.fromCharCode(codePoint); + } + + // Astral code point; split in surrogate halves + // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + codePoint -= 0x10000; + return String.fromCharCode((codePoint >> 10) + 0xD800, (codePoint % 0x400) + 0xDC00); + }; + + + function getProtocol(s) { + s = s.split(URI_PROTOCOL_COLON, 2); + return (s.length === 2 && s[0]) ? s[0] : null; + } + + function htmlDecode(s, namedRefMap, reNamedRef, skipReplacement) { + + namedRefMap = namedRefMap || SENSITIVE_NAMED_REF_MAP; + reNamedRef = reNamedRef || SENSITIVE_HTML_ENTITIES; + + function regExpFunction(m, num, named, named1) { + if (num) { + num = Number(num[0] <= '9' ? num : '0' + num); + // switch(num) { + // case 0x80: return '\u20AC'; // EURO SIGN (€) + // case 0x82: return '\u201A'; // SINGLE LOW-9 QUOTATION MARK (‚) + // case 0x83: return '\u0192'; // LATIN SMALL LETTER F WITH HOOK (ƒ) + // case 0x84: return '\u201E'; // DOUBLE LOW-9 QUOTATION MARK („) + // case 0x85: return '\u2026'; // HORIZONTAL ELLIPSIS (…) + // case 0x86: return '\u2020'; // DAGGER (†) + // case 0x87: return '\u2021'; // DOUBLE DAGGER (‡) + // case 0x88: return '\u02C6'; // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ) + // case 0x89: return '\u2030'; // PER MILLE SIGN (‰) + // case 0x8A: return '\u0160'; // LATIN CAPITAL LETTER S WITH CARON (Š) + // case 0x8B: return '\u2039'; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹) + // case 0x8C: return '\u0152'; // LATIN CAPITAL LIGATURE OE (Œ) + // case 0x8E: return '\u017D'; // LATIN CAPITAL LETTER Z WITH CARON (Ž) + // case 0x91: return '\u2018'; // LEFT SINGLE QUOTATION MARK (‘) + // case 0x92: return '\u2019'; // RIGHT SINGLE QUOTATION MARK (’) + // case 0x93: return '\u201C'; // LEFT DOUBLE QUOTATION MARK (“) + // case 0x94: return '\u201D'; // RIGHT DOUBLE QUOTATION MARK (”) + // case 0x95: return '\u2022'; // BULLET (•) + // case 0x96: return '\u2013'; // EN DASH (–) + // case 0x97: return '\u2014'; // EM DASH (—) + // case 0x98: return '\u02DC'; // SMALL TILDE (˜) + // case 0x99: return '\u2122'; // TRADE MARK SIGN (™) + // case 0x9A: return '\u0161'; // LATIN SMALL LETTER S WITH CARON (š) + // case 0x9B: return '\u203A'; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›) + // case 0x9C: return '\u0153'; // LATIN SMALL LIGATURE OE (œ) + // case 0x9E: return '\u017E'; // LATIN SMALL LETTER Z WITH CARON (ž) + // case 0x9F: return '\u0178'; // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ) + // } + // // num >= 0xD800 && num <= 0xDFFF, and 0x0D is separately handled, as it doesn't fall into the range of x.pec() + // return (num >= 0xD800 && num <= 0xDFFF) || num === 0x0D ? '\uFFFD' : x.frCoPt(num); + + return skipReplacement ? fromCodePoint(num) + : num === 0x80 ? '\u20AC' // EURO SIGN (€) + : num === 0x82 ? '\u201A' // SINGLE LOW-9 QUOTATION MARK (‚) + : num === 0x83 ? '\u0192' // LATIN SMALL LETTER F WITH HOOK (ƒ) + : num === 0x84 ? '\u201E' // DOUBLE LOW-9 QUOTATION MARK („) + : num === 0x85 ? '\u2026' // HORIZONTAL ELLIPSIS (…) + : num === 0x86 ? '\u2020' // DAGGER (†) + : num === 0x87 ? '\u2021' // DOUBLE DAGGER (‡) + : num === 0x88 ? '\u02C6' // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ) + : num === 0x89 ? '\u2030' // PER MILLE SIGN (‰) + : num === 0x8A ? '\u0160' // LATIN CAPITAL LETTER S WITH CARON (Š) + : num === 0x8B ? '\u2039' // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹) + : num === 0x8C ? '\u0152' // LATIN CAPITAL LIGATURE OE (Œ) + : num === 0x8E ? '\u017D' // LATIN CAPITAL LETTER Z WITH CARON (Ž) + : num === 0x91 ? '\u2018' // LEFT SINGLE QUOTATION MARK (‘) + : num === 0x92 ? '\u2019' // RIGHT SINGLE QUOTATION MARK (’) + : num === 0x93 ? '\u201C' // LEFT DOUBLE QUOTATION MARK (“) + : num === 0x94 ? '\u201D' // RIGHT DOUBLE QUOTATION MARK (”) + : num === 0x95 ? '\u2022' // BULLET (•) + : num === 0x96 ? '\u2013' // EN DASH (–) + : num === 0x97 ? '\u2014' // EM DASH (—) + : num === 0x98 ? '\u02DC' // SMALL TILDE (˜) + : num === 0x99 ? '\u2122' // TRADE MARK SIGN (™) + : num === 0x9A ? '\u0161' // LATIN SMALL LETTER S WITH CARON (š) + : num === 0x9B ? '\u203A' // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›) + : num === 0x9C ? '\u0153' // LATIN SMALL LIGATURE OE (œ) + : num === 0x9E ? '\u017E' // LATIN SMALL LETTER Z WITH CARON (ž) + : num === 0x9F ? '\u0178' // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ) + : (num >= 0xD800 && num <= 0xDFFF) || num === 0x0D ? '\uFFFD' + : x.frCoPt(num); + } + return namedRefMap[named || named1] || m; + } + + return s === undefined ? 'undefined' + : s === null ? 'null' + : s.toString().replace(NULL, '\uFFFD').replace(reNamedRef, regExpFunction); + } + + function cssEncode(chr) { + // space after \\HEX is needed by spec + return '\\' + chr.charCodeAt(0).toString(16).toLowerCase() + ' '; + } + function css(s, reSensitiveChars) { + return htmlDecode(s).replace(reSensitiveChars, cssEncode); + } + function cssUrl(s, reSensitiveChars) { + // encodeURI() in yufull() will throw error for use of the CSS_UNSUPPORTED_CODE_POINT (i.e., [\uD800-\uDFFF]) + s = x.yufull(htmlDecode(s)); + var protocol = getProtocol(s); + + // prefix ## for blacklisted protocols + if (protocol && URI_BLACKLIST_PROTOCOLS[protocol.toLowerCase()]) { + s = '##' + s; + } + + return reSensitiveChars ? s.replace(reSensitiveChars, cssEncode) : s; + } + + return (x = { + // turn invalid codePoints and that of non-characters to \uFFFD, and then fromCodePoint() + frCoPt: function(num) { + return num === undefined || num === null ? '' : + !isFinite(num = Number(num)) || // `NaN`, `+Infinity`, or `-Infinity` + num <= 0 || // not a valid Unicode code point + num > 0x10FFFF || // not a valid Unicode code point + // Math.floor(num) != num || + + (num >= 0x01 && num <= 0x08) || + (num >= 0x0E && num <= 0x1F) || + (num >= 0x7F && num <= 0x9F) || + (num >= 0xFDD0 && num <= 0xFDEF) || + + num === 0x0B || + (num & 0xFFFF) === 0xFFFF || + (num & 0xFFFF) === 0xFFFE ? '\uFFFD' : fromCodePoint(num); + }, + d: htmlDecode, + /* + * @param {string} s - An untrusted uri input + * @returns {string} s - null if relative url, otherwise the protocol with whitespaces stripped and lower-cased + */ + yup: function(s) { + s = getProtocol(s.replace(NULL, '')); + // URI_PROTOCOL_WHITESPACES is required for left trim and remove interim whitespaces + return s ? htmlDecode(s, URI_PROTOCOL_NAMED_REF_MAP, null, true).replace(URI_PROTOCOL_WHITESPACES, '').toLowerCase() : null; + }, + + /* + * @deprecated + * @param {string} s - An untrusted user input + * @returns {string} s - The original user input with & < > " ' ` encoded respectively as & < > " ' and `. + * + */ + y: function(s) { + return strReplace(s, SPECIAL_HTML_CHARS, function (m) { + return m === '&' ? '&' + : m === '<' ? '<' + : m === '>' ? '>' + : m === '"' ? '"' + : m === "'" ? ''' + : /*m === '`'*/ '`'; // in hex: 60 + }); + }, + + // This filter is meant to introduce double-encoding, and should be used with extra care. + ya: function(s) { + return strReplace(s, AMP, '&'); + }, + + // FOR DETAILS, refer to inHTMLData() + // Reference: https://html.spec.whatwg.org/multipage/syntax.html#data-state + yd: function (s) { + return strReplace(s, LT, '<'); + }, + + // FOR DETAILS, refer to inHTMLComment() + // All NULL characters in s are first replaced with \uFFFD. + // If s contains -->, --!>, or starts with -*>, insert a space right before > to stop state breaking at + // If s ends with --!, --, or -, append a space to stop collaborative state breaking at {{{yc s}}}>, {{{yc s}}}!>, {{{yc s}}}-!>, {{{yc s}}}-> + // Reference: https://html.spec.whatwg.org/multipage/syntax.html#comment-state + // Reference: http://shazzer.co.uk/vector/Characters-that-close-a-HTML-comment-3 + // Reference: http://shazzer.co.uk/vector/Characters-that-close-a-HTML-comment + // Reference: http://shazzer.co.uk/vector/Characters-that-close-a-HTML-comment-0021 + // If s contains ]> or ends with ], append a space after ] is verified in IE to stop IE conditional comments. + // Reference: http://msdn.microsoft.com/en-us/library/ms537512%28v=vs.85%29.aspx + // We do not care --\s>, which can possibly be intepreted as a valid close comment tag in very old browsers (e.g., firefox 3.6), as specified in the html4 spec + // Reference: http://www.w3.org/TR/html401/intro/sgmltut.html#h-3.2.4 + yc: function (s) { + return strReplace(s, SPECIAL_COMMENT_CHARS, function(m){ + return m === '\x00' ? '\uFFFD' + : m === '--!' || m === '--' || m === '-' || m === ']' ? m + ' ' + :/* + : m === ']>' ? '] >' + : m === '-->' ? '-- >' + : m === '--!>' ? '--! >' + : /-*!?>/.test(m) ? */ m.slice(0, -1) + ' >'; + }); + }, + + // FOR DETAILS, refer to inDoubleQuotedAttr() + // Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(double-quoted)-state + yavd: function (s) { + return strReplace(s, QUOT, '"'); + }, + + // FOR DETAILS, refer to inSingleQuotedAttr() + // Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(single-quoted)-state + yavs: function (s) { + return strReplace(s, SQUOT, '''); + }, + + // FOR DETAILS, refer to inUnQuotedAttr() + // PART A. + // if s contains any state breaking chars (\t, \n, \v, \f, \r, space, and >), + // they are escaped and encoded into their equivalent HTML entity representations. + // Reference: http://shazzer.co.uk/database/All/Characters-which-break-attributes-without-quotes + // Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(unquoted)-state + // + // PART B. + // if s starts with ', " or `, encode it resp. as ', ", or ` to + // enforce the attr value (unquoted) state + // Reference: https://html.spec.whatwg.org/multipage/syntax.html#before-attribute-value-state + // Reference: http://shazzer.co.uk/vector/Characters-allowed-attribute-quote + // + // PART C. + // Inject a \uFFFD character if an empty or all null string is encountered in + // unquoted attribute value state. + // + // Rationale 1: our belief is that developers wouldn't expect an + // empty string would result in ' name="passwd"' rendered as + // attribute value, even though this is how HTML5 is specified. + // Rationale 2: an empty or all null string (for IE) can + // effectively alter its immediate subsequent state, we choose + // \uFFFD to end the unquoted attr + // state, which therefore will not mess up later contexts. + // Rationale 3: Since IE 6, it is verified that NULL chars are stripped. + // Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(unquoted)-state + // + // Example: + // + yavu: function (s) { + return strReplace(s, SPECIAL_ATTR_VALUE_UNQUOTED_CHARS, function (m) { + return m === '\t' ? ' ' // in hex: 09 + : m === '\n' ? ' ' // in hex: 0A + : m === '\x0B' ? ' ' // in hex: 0B for IE. IE<9 \v equals v, so use \x0B instead + : m === '\f' ? ' ' // in hex: 0C + : m === '\r' ? ' ' // in hex: 0D + : m === ' ' ? ' ' // in hex: 20 + : m === '=' ? '=' // in hex: 3D + : m === '<' ? '<' + : m === '>' ? '>' + : m === '"' ? '"' + : m === "'" ? ''' + : m === '`' ? '`' + : /*empty or null*/ '\uFFFD'; + }); + }, + + yu: encodeURI, + yuc: encodeURIComponent, + + // Notice that yubl MUST BE APPLIED LAST, and will not be used independently (expected output from encodeURI/encodeURIComponent and yavd/yavs/yavu) + // This is used to disable JS execution capabilities by prefixing x- to ^javascript:, ^vbscript: or ^data: that possibly could trigger script execution in URI attribute context + yubl: function (s) { + return URI_BLACKLIST_PROTOCOLS[x.yup(s)] ? 'x-' + s : s; + }, + + // This is NOT a security-critical filter. + // Reference: https://tools.ietf.org/html/rfc3986 + yufull: function (s) { + return x.yu(s).replace(URL_IPV6, function(m, p) { + return '//[' + p + ']'; + }); + }, + + // chain yufull() with yubl() + yublf: function (s) { + return x.yubl(x.yufull(s)); + }, + + // The design principle of the CSS filter MUST meet the following goal(s). + // (1) The input cannot break out of the context (expr) and this is to fulfill the just sufficient encoding principle. + // (2) The input cannot introduce CSS parsing error and this is to address the concern of UI redressing. + // + // term + // : unary_operator? + // [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* | + // TIME S* | FREQ S* ] + // | STRING S* | IDENT S* | URI S* | hexcolor | function + // + // Reference: + // * http://www.w3.org/TR/CSS21/grammar.html + // * http://www.w3.org/TR/css-syntax-3/ + // + // NOTE: delimitar in CSS - \ _ : ; ( ) " ' / , % # ! * @ . { } + + // CSS_UNQUOTED_CHARS = /[^%#+\-\w\.]/g, + yceu: function(s) { + return css(s, CSS_UNQUOTED_CHARS); + }, + + // string1 = \"([^\n\r\f\\"]|\\{nl}|\\[^\n\r\f0-9a-f]|\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?)*\" + // CSS_DOUBLE_QUOTED_CHARS = /[\x01-\x1F\x7F\\"]/g, + yced: function(s) { + return css(s, CSS_DOUBLE_QUOTED_CHARS); + }, + + // string2 = \'([^\n\r\f\\']|\\{nl}|\\[^\n\r\f0-9a-f]|\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?)*\' + // CSS_SINGLE_QUOTED_CHARS = /[\x01-\x1F\x7F\\']/g, + yces: function(s) { + return css(s, CSS_SINGLE_QUOTED_CHARS); + }, + + // for url({{{yceuu url}}} + // unquoted_url = ([!#$%&*-~]|\\{h}{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])* (CSS 2.1 definition) + // unquoted_url = ([^"'()\\ \t\n\r\f\v\u0000\u0008\u000b\u000e-\u001f\u007f]|\\{h}{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])* (CSS 3.0 definition) + // The state machine in CSS 3.0 is more well defined - http://www.w3.org/TR/css-syntax-3/#consume-a-url-token0 + // CSS_UNQUOTED_URL = /['\(\)]/g; // " \ treated by encodeURI() + yceuu: function(s) { + return cssUrl(s, CSS_UNQUOTED_URL); + }, + + // for url("{{{yceud url}}} + // CSS_DOUBLE_QUOTED_URL has nothing else to escape (optimized version by chaining with yufull) + yceud: function(s) { + return cssUrl(s); + }, + + // for url('{{{yceus url}}} + // CSS_SINGLE_QUOTED_URL = /'/g; (optimized version by chaining with yufull) + yceus: function(s) { + return cssUrl(s, SQUOT); + } + }); +}; + +// exposing privFilters +// this is an undocumented feature, and please use it with extra care +var privFilters = exports._privFilters = exports._getPrivFilters(); + + +/* chaining filters */ + +// uriInAttr and literally uriPathInAttr +// yubl is always used +// Rationale: given pattern like this: +// developer may expect s is always prefixed with ? or /, but an attacker can abuse it with 'javascript:alert(1)' +function uriInAttr (s, yav, yu) { + return privFilters.yubl(yav((yu || privFilters.yufull)(s))); +} + +/** +* Yahoo Secure XSS Filters - just sufficient output filtering to prevent XSS! +* @module xss-filters +*/ + /** - * xss-filters - v1.2.3 - * Yahoo! Inc. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. - */ -!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.xssFilters=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g=55296&&57343>=b||13===b?"�":g.frCoPt(b)):c[d||e]||a}),e?e.apply(h,i):h})}function d(a){return"\\"+a.charCodeAt(0).toString(16).toLowerCase()+" "}function e(a,b){return c(a,null,null,function(){return this.replace(b,d)})}function f(b,e){return c(b,null,null,function(){var b=g.yufull(this),c=a(b);return b=c&&w[c.toLowerCase()]?"##"+b:b,e?b.replace(e,d):b})}var g,h=/])/g,n=/[&<>"'`]/g,o=/(?:\x00|^-*!?>|--!?>|--?!?$|\]>|\]$)/g,p=/&(?:#([xX][0-9A-Fa-f]+|\d+);?|(Tab|NewLine|colon|semi|lpar|rpar|apos|sol|comma|excl|ast|midast|ensp|emsp|thinsp);|(nbsp|amp|AMP|lt|LT|gt|GT|quot|QUOT);?)/g,q={Tab:" ",NewLine:"\n",colon:":",semi:";",lpar:"(",rpar:")",apos:"'",sol:"/",comma:",",excl:"!",ast:"*",midast:"*",ensp:" ",emsp:" ",thinsp:" ",nbsp:" ",amp:"&",lt:"<",gt:">",quot:'"',QUOT:'"'},r=/[^%#+\-\w\.]/g,s=/[\x01-\x1F\x7F\\"]/g,t=/[\x01-\x1F\x7F\\']/g,u=/['\(\)]/g,v=/\/\/%5[Bb]([A-Fa-f0-9:]+)%5[Dd]/,w={javascript:1,data:1,vbscript:1,mhtml:1},x=/(?::|&#[xX]0*3[aA];?|�*58;?|:)/,y=/(?:^[\x00-\x20]+|[\t\n\r\x00]+)/g,z={Tab:" ",NewLine:"\n"},A=String.prototype.replace,B=String.fromCodePoint||function(a){return 0===arguments.length?"":65535>=a?String.fromCharCode(a):(a-=65536,String.fromCharCode((a>>10)+55296,a%1024+56320))};return g={frCoPt:function(a){return void 0===a||null===a?"":!isFinite(a=Number(a))||0>=a||a>1114111||a>=1&&8>=a||a>=14&&31>=a||a>=127&&159>=a||a>=64976&&65007>=a||11===a||65535===(65535&a)||65534===(65535&a)?"�":B(a)},d:c,yup:function(b){return b=a(b.replace(l,"")),b?c(b,z,null,function(){return this.replace(y,"").toLowerCase()},!0):null},y:function(a){return b(a,A,n,function(a){return"&"===a?"&":"<"===a?"<":">"===a?">":'"'===a?""":"'"===a?"'":"`"})},ya:function(a){return b(a,A,k,"&")},yd:function(a){return b(a,A,h,"<")},yc:function(a){return b(a,A,o,function(a){return"\x00"===a?"�":"--!"===a||"--"===a||"-"===a||"]"===a?a+" ":a.slice(0,-1)+" >"})},yavd:function(a){return b(a,A,i,""")},yavs:function(a){return b(a,A,j,"'")},yavu:function(a){return b(a,A,m,function(a){return" "===a?" ":"\n"===a?" ":" "===a?" ":"\f"===a?" ":"\r"===a?" ":" "===a?" ":"="===a?"=":"<"===a?"<":">"===a?">":'"'===a?""":"'"===a?"'":"`"===a?"`":"�"})},yu:encodeURI,yuc:encodeURIComponent,yubl:function(a){return w[g.yup(a)]?"x-"+a:a},yufull:function(a){return g.yu(a).replace(v,function(a,b){return"//["+b+"]"})},yublf:function(a){return g.yubl(g.yufull(a))},yceu:function(a){return e(a,r)},yced:function(a){return e(a,s)},yces:function(a){return e(a,t)},yceuu:function(a){return f(a,u)},yceud:function(a){return f(a)},yceus:function(a){return f(a,j)}}};var e=c._privFilters=c._getPrivFilters();c.inHTMLData=e.yd,c.inHTMLComment=e.yc,c.inSingleQuotedAttr=e.yavs,c.inDoubleQuotedAttr=e.yavd,c.inUnQuotedAttr=e.yavu,c.uriInSingleQuotedAttr=function(a){return d(a,e.yavs)},c.uriInDoubleQuotedAttr=function(a){return d(a,e.yavd)},c.uriInUnQuotedAttr=function(a){return d(a,e.yavu)},c.uriInHTMLData=e.yufull,c.uriInHTMLComment=function(a){return e.yc(e.yufull(a))},c.uriPathInSingleQuotedAttr=function(a){return d(a,e.yavs,e.yu)},c.uriPathInDoubleQuotedAttr=function(a){return d(a,e.yavd,e.yu)},c.uriPathInUnQuotedAttr=function(a){return d(a,e.yavu,e.yu)},c.uriPathInHTMLData=e.yu,c.uriPathInHTMLComment=function(a){return e.yc(e.yu(a))},c.uriQueryInSingleQuotedAttr=c.uriPathInSingleQuotedAttr,c.uriQueryInDoubleQuotedAttr=c.uriPathInDoubleQuotedAttr,c.uriQueryInUnQuotedAttr=c.uriPathInUnQuotedAttr,c.uriQueryInHTMLData=c.uriPathInHTMLData,c.uriQueryInHTMLComment=c.uriPathInHTMLComment,c.uriComponentInSingleQuotedAttr=function(a){return e.yavs(e.yuc(a))},c.uriComponentInDoubleQuotedAttr=function(a){return e.yavd(e.yuc(a))},c.uriComponentInUnQuotedAttr=function(a){return e.yavu(e.yuc(a))},c.uriComponentInHTMLData=e.yuc,c.uriComponentInHTMLComment=function(a){return e.yc(e.yuc(a))},c.uriFragmentInSingleQuotedAttr=function(a){return e.yubl(e.yavs(e.yuc(a)))},c.uriFragmentInDoubleQuotedAttr=function(a){return e.yubl(e.yavd(e.yuc(a)))},c.uriFragmentInUnQuotedAttr=function(a){return e.yubl(e.yavu(e.yuc(a)))},c.uriFragmentInHTMLData=c.uriComponentInHTMLData,c.uriFragmentInHTMLComment=c.uriComponentInHTMLComment},{}]},{},[1])(1)}); \ No newline at end of file +* @function module:xss-filters#inHTMLData +* +* @param {string} s - An untrusted user input +* @returns {string} The string s with '<' encoded as '&lt;' +* +* @description +* This filter is to be placed in HTML Data context to encode all '<' characters into '&lt;' +* +* +* @example +* // output context to be applied by this filter. +*
{{{inHTMLData htmlData}}}
+* +*/ +exports.inHTMLData = privFilters.yd; + +/** +* @function module:xss-filters#inHTMLComment +* +* @param {string} s - An untrusted user input +* @returns {string} All NULL characters in s are first replaced with \uFFFD. If s contains -->, --!>, or starts with -*>, insert a space right before > to stop state breaking at . If s ends with --!, --, or -, append a space to stop collaborative state breaking at {{{yc s}}}>, {{{yc s}}}!>, {{{yc s}}}-!>, {{{yc s}}}->. If s contains ]> or ends with ], append a space after ] is verified in IE to stop IE conditional comments. +* +* @description +* This filter is to be placed in HTML Comment context +* +* +* @example +* // output context to be applied by this filter. +* +* +*/ +exports.inHTMLComment = privFilters.yc; + +/** +* @function module:xss-filters#inSingleQuotedAttr +* +* @param {string} s - An untrusted user input +* @returns {string} The string s with any single-quote characters encoded into '&''. +* +* @description +*

Warning: This is NOT designed for any onX (e.g., onclick) attributes!

+*

Warning: If you're working on URI/components, use the more specific uri___InSingleQuotedAttr filter

+* This filter is to be placed in HTML Attribute Value (single-quoted) state to encode all single-quote characters into '&'' +* +* +* +* @example +* // output context to be applied by this filter. +* +* +*/ +exports.inSingleQuotedAttr = privFilters.yavs; + +/** +* @function module:xss-filters#inDoubleQuotedAttr +* +* @param {string} s - An untrusted user input +* @returns {string} The string s with any single-quote characters encoded into '&"'. +* +* @description +*

Warning: This is NOT designed for any onX (e.g., onclick) attributes!

+*

Warning: If you're working on URI/components, use the more specific uri___InDoubleQuotedAttr filter

+* This filter is to be placed in HTML Attribute Value (double-quoted) state to encode all single-quote characters into '&"' +* +* +* +* @example +* // output context to be applied by this filter. +* +* +*/ +exports.inDoubleQuotedAttr = privFilters.yavd; + +/** +* @function module:xss-filters#inUnQuotedAttr +* +* @param {string} s - An untrusted user input +* @returns {string} If s contains any state breaking chars (\t, \n, \v, \f, \r, space, null, ', ", `, <, >, and =), they are escaped and encoded into their equivalent HTML entity representations. If the string is empty, inject a \uFFFD character. +* +* @description +*

Warning: This is NOT designed for any onX (e.g., onclick) attributes!

+*

Warning: If you're working on URI/components, use the more specific uri___InUnQuotedAttr filter

+*

Regarding \uFFFD injection, given ,
+* Rationale 1: our belief is that developers wouldn't expect when id equals an +* empty string would result in ' name="passwd"' rendered as +* attribute value, even though this is how HTML5 is specified.
+* Rationale 2: an empty or all null string (for IE) can +* effectively alter its immediate subsequent state, we choose +* \uFFFD to end the unquoted attr +* state, which therefore will not mess up later contexts.
+* Rationale 3: Since IE 6, it is verified that NULL chars are stripped.
+* Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(unquoted)-state

+* +* +* @example +* // output context to be applied by this filter. +* +* +*/ +exports.inUnQuotedAttr = privFilters.yavu; + + +/** +* @function module:xss-filters#uriInSingleQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly an absolute URI +* @returns {string} The string s encoded first by window.encodeURI(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* @description +* This filter is to be placed in HTML Attribute Value (single-quoted) state for an absolute URI.
+* The correct order of encoders is thus: first window.encodeURI(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +*

Notice: This filter is IPv6 friendly by not encoding '[' and ']'.

+* +* +* +* @example +* // output context to be applied by this filter. +* link +* +*/ +exports.uriInSingleQuotedAttr = function (s) { + return uriInAttr(s, privFilters.yavs); +}; + +/** +* @function module:xss-filters#uriInDoubleQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly an absolute URI +* @returns {string} The string s encoded first by window.encodeURI(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* @description +* This filter is to be placed in HTML Attribute Value (double-quoted) state for an absolute URI.
+* The correct order of encoders is thus: first window.encodeURI(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +*

Notice: This filter is IPv6 friendly by not encoding '[' and ']'.

+* +* +* +* @example +* // output context to be applied by this filter. +* link +* +*/ +exports.uriInDoubleQuotedAttr = function (s) { + return uriInAttr(s, privFilters.yavd); +}; + + +/** +* @function module:xss-filters#uriInUnQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly an absolute URI +* @returns {string} The string s encoded first by window.encodeURI(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* @description +* This filter is to be placed in HTML Attribute Value (unquoted) state for an absolute URI.
+* The correct order of encoders is thus: first the built-in encodeURI(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +*

Notice: This filter is IPv6 friendly by not encoding '[' and ']'.

+* +* +* +* @example +* // output context to be applied by this filter. +* link +* +*/ +exports.uriInUnQuotedAttr = function (s) { + return uriInAttr(s, privFilters.yavu); +}; + +/** +* @function module:xss-filters#uriInHTMLData +* +* @param {string} s - An untrusted user input, supposedly an absolute URI +* @returns {string} The string s encoded by window.encodeURI() and then inHTMLData() +* +* @description +* This filter is to be placed in HTML Data state for an absolute URI. +* +*

Notice: The actual implementation skips inHTMLData(), since '<' is already encoded as '%3C' by encodeURI().

+*

Notice: This filter is IPv6 friendly by not encoding '[' and ']'.

+* +* +* +* @example +* // output context to be applied by this filter. +* {{{uriInHTMLData full_uri}}} +* +*/ +exports.uriInHTMLData = privFilters.yufull; + + +/** +* @function module:xss-filters#uriInHTMLComment +* +* @param {string} s - An untrusted user input, supposedly an absolute URI +* @returns {string} The string s encoded by window.encodeURI(), and finally inHTMLComment() +* +* @description +* This filter is to be placed in HTML Comment state for an absolute URI. +* +*

Notice: This filter is IPv6 friendly by not encoding '[' and ']'.

+* +* +* +* @example +* // output context to be applied by this filter. +* +* +*/ +exports.uriInHTMLComment = function (s) { + return privFilters.yc(privFilters.yufull(s)); +}; + + + + +/** +* @function module:xss-filters#uriPathInSingleQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly a URI Path/Query or relative URI +* @returns {string} The string s encoded first by window.encodeURI(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* @description +* This filter is to be placed in HTML Attribute Value (single-quoted) state for a URI Path/Query or relative URI.
+* The correct order of encoders is thus: first window.encodeURI(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* +* +* @example +* // output context to be applied by this filter. +* link +* link +* +*/ +exports.uriPathInSingleQuotedAttr = function (s) { + return uriInAttr(s, privFilters.yavs, privFilters.yu); +}; + +/** +* @function module:xss-filters#uriPathInDoubleQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly a URI Path/Query or relative URI +* @returns {string} The string s encoded first by window.encodeURI(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* @description +* This filter is to be placed in HTML Attribute Value (double-quoted) state for a URI Path/Query or relative URI.
+* The correct order of encoders is thus: first window.encodeURI(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* +* +* @example +* // output context to be applied by this filter. +* link +* link +* +*/ +exports.uriPathInDoubleQuotedAttr = function (s) { + return uriInAttr(s, privFilters.yavd, privFilters.yu); +}; + + +/** +* @function module:xss-filters#uriPathInUnQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly a URI Path/Query or relative URI +* @returns {string} The string s encoded first by window.encodeURI(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* @description +* This filter is to be placed in HTML Attribute Value (unquoted) state for a URI Path/Query or relative URI.
+* The correct order of encoders is thus: first the built-in encodeURI(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* +* +* @example +* // output context to be applied by this filter. +* link +* link +* +*/ +exports.uriPathInUnQuotedAttr = function (s) { + return uriInAttr(s, privFilters.yavu, privFilters.yu); +}; + +/** +* @function module:xss-filters#uriPathInHTMLData +* +* @param {string} s - An untrusted user input, supposedly a URI Path/Query or relative URI +* @returns {string} The string s encoded by window.encodeURI() and then inHTMLData() +* +* @description +* This filter is to be placed in HTML Data state for a URI Path/Query or relative URI. +* +*

Notice: The actual implementation skips inHTMLData(), since '<' is already encoded as '%3C' by encodeURI().

+* +* +* +* @example +* // output context to be applied by this filter. +* http://example.com/{{{uriPathInHTMLData uri_path}}} +* http://example.com/?{{{uriQueryInHTMLData uri_query}}} +* +*/ +exports.uriPathInHTMLData = privFilters.yu; + + +/** +* @function module:xss-filters#uriPathInHTMLComment +* +* @param {string} s - An untrusted user input, supposedly a URI Path/Query or relative URI +* @returns {string} The string s encoded by window.encodeURI(), and finally inHTMLComment() +* +* @description +* This filter is to be placed in HTML Comment state for a URI Path/Query or relative URI. +* +* +* +* @example +* // output context to be applied by this filter. +* +* +*/ +exports.uriPathInHTMLComment = function (s) { + return privFilters.yc(privFilters.yu(s)); +}; + + +/** +* @function module:xss-filters#uriQueryInSingleQuotedAttr +* @description This is an alias of {@link module:xss-filters#uriPathInSingleQuotedAttr} +* +* @alias module:xss-filters#uriPathInSingleQuotedAttr +*/ +exports.uriQueryInSingleQuotedAttr = exports.uriPathInSingleQuotedAttr; + +/** +* @function module:xss-filters#uriQueryInDoubleQuotedAttr +* @description This is an alias of {@link module:xss-filters#uriPathInDoubleQuotedAttr} +* +* @alias module:xss-filters#uriPathInDoubleQuotedAttr +*/ +exports.uriQueryInDoubleQuotedAttr = exports.uriPathInDoubleQuotedAttr; + +/** +* @function module:xss-filters#uriQueryInUnQuotedAttr +* @description This is an alias of {@link module:xss-filters#uriPathInUnQuotedAttr} +* +* @alias module:xss-filters#uriPathInUnQuotedAttr +*/ +exports.uriQueryInUnQuotedAttr = exports.uriPathInUnQuotedAttr; + +/** +* @function module:xss-filters#uriQueryInHTMLData +* @description This is an alias of {@link module:xss-filters#uriPathInHTMLData} +* +* @alias module:xss-filters#uriPathInHTMLData +*/ +exports.uriQueryInHTMLData = exports.uriPathInHTMLData; + +/** +* @function module:xss-filters#uriQueryInHTMLComment +* @description This is an alias of {@link module:xss-filters#uriPathInHTMLComment} +* +* @alias module:xss-filters#uriPathInHTMLComment +*/ +exports.uriQueryInHTMLComment = exports.uriPathInHTMLComment; + + + +/** +* @function module:xss-filters#uriComponentInSingleQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly a URI Component +* @returns {string} The string s encoded first by window.encodeURIComponent(), then inSingleQuotedAttr() +* +* @description +* This filter is to be placed in HTML Attribute Value (single-quoted) state for a URI Component.
+* The correct order of encoders is thus: first window.encodeURIComponent(), then inSingleQuotedAttr() +* +* +* +* +* @example +* // output context to be applied by this filter. +* link +* +*/ +exports.uriComponentInSingleQuotedAttr = function (s) { + return privFilters.yavs(privFilters.yuc(s)); +}; + +/** +* @function module:xss-filters#uriComponentInDoubleQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly a URI Component +* @returns {string} The string s encoded first by window.encodeURIComponent(), then inDoubleQuotedAttr() +* +* @description +* This filter is to be placed in HTML Attribute Value (double-quoted) state for a URI Component.
+* The correct order of encoders is thus: first window.encodeURIComponent(), then inDoubleQuotedAttr() +* +* +* +* +* @example +* // output context to be applied by this filter. +* link +* +*/ +exports.uriComponentInDoubleQuotedAttr = function (s) { + return privFilters.yavd(privFilters.yuc(s)); +}; + + +/** +* @function module:xss-filters#uriComponentInUnQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly a URI Component +* @returns {string} The string s encoded first by window.encodeURIComponent(), then inUnQuotedAttr() +* +* @description +* This filter is to be placed in HTML Attribute Value (unquoted) state for a URI Component.
+* The correct order of encoders is thus: first the built-in encodeURIComponent(), then inUnQuotedAttr() +* +* +* +* +* @example +* // output context to be applied by this filter. +* link +* +*/ +exports.uriComponentInUnQuotedAttr = function (s) { + return privFilters.yavu(privFilters.yuc(s)); +}; + +/** +* @function module:xss-filters#uriComponentInHTMLData +* +* @param {string} s - An untrusted user input, supposedly a URI Component +* @returns {string} The string s encoded by window.encodeURIComponent() and then inHTMLData() +* +* @description +* This filter is to be placed in HTML Data state for a URI Component. +* +*

Notice: The actual implementation skips inHTMLData(), since '<' is already encoded as '%3C' by encodeURIComponent().

+* +* +* +* @example +* // output context to be applied by this filter. +* http://example.com/?q={{{uriComponentInHTMLData uri_component}}} +* http://example.com/#{{{uriComponentInHTMLData uri_fragment}}} +* +*/ +exports.uriComponentInHTMLData = privFilters.yuc; + + +/** +* @function module:xss-filters#uriComponentInHTMLComment +* +* @param {string} s - An untrusted user input, supposedly a URI Component +* @returns {string} The string s encoded by window.encodeURIComponent(), and finally inHTMLComment() +* +* @description +* This filter is to be placed in HTML Comment state for a URI Component. +* +* +* +* @example +* // output context to be applied by this filter. +* +* +*/ +exports.uriComponentInHTMLComment = function (s) { + return privFilters.yc(privFilters.yuc(s)); +}; + + +// uriFragmentInSingleQuotedAttr +// added yubl on top of uriComponentInAttr +// Rationale: given pattern like this: +// developer may expect s is always prefixed with #, but an attacker can abuse it with 'javascript:alert(1)' + +/** +* @function module:xss-filters#uriFragmentInSingleQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly a URI Fragment +* @returns {string} The string s encoded first by window.encodeURIComponent(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* @description +* This filter is to be placed in HTML Attribute Value (single-quoted) state for a URI Fragment.
+* The correct order of encoders is thus: first window.encodeURIComponent(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* +*
+* +* @example +* // output context to be applied by this filter. +* link +* +*/ +exports.uriFragmentInSingleQuotedAttr = function (s) { + return privFilters.yubl(privFilters.yavs(privFilters.yuc(s))); +}; + +// uriFragmentInDoubleQuotedAttr +// added yubl on top of uriComponentInAttr +// Rationale: given pattern like this: +// developer may expect s is always prefixed with #, but an attacker can abuse it with 'javascript:alert(1)' + +/** +* @function module:xss-filters#uriFragmentInDoubleQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly a URI Fragment +* @returns {string} The string s encoded first by window.encodeURIComponent(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* @description +* This filter is to be placed in HTML Attribute Value (double-quoted) state for a URI Fragment.
+* The correct order of encoders is thus: first window.encodeURIComponent(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* +*
+* +* @example +* // output context to be applied by this filter. +* link +* +*/ +exports.uriFragmentInDoubleQuotedAttr = function (s) { + return privFilters.yubl(privFilters.yavd(privFilters.yuc(s))); +}; + +// uriFragmentInUnQuotedAttr +// added yubl on top of uriComponentInAttr +// Rationale: given pattern like this: +// developer may expect s is always prefixed with #, but an attacker can abuse it with 'javascript:alert(1)' + +/** +* @function module:xss-filters#uriFragmentInUnQuotedAttr +* +* @param {string} s - An untrusted user input, supposedly a URI Fragment +* @returns {string} The string s encoded first by window.encodeURIComponent(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +* @description +* This filter is to be placed in HTML Attribute Value (unquoted) state for a URI Fragment.
+* The correct order of encoders is thus: first the built-in encodeURIComponent(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution +* +*
+* +* @example +* // output context to be applied by this filter. +* link +* +*/ +exports.uriFragmentInUnQuotedAttr = function (s) { + return privFilters.yubl(privFilters.yavu(privFilters.yuc(s))); +}; + + +/** +* @function module:xss-filters#uriFragmentInHTMLData +* @description This is an alias of {@link module:xss-filters#uriComponentInHTMLData} +* +* @alias module:xss-filters#uriComponentInHTMLData +*/ +exports.uriFragmentInHTMLData = exports.uriComponentInHTMLData; + +/** +* @function module:xss-filters#uriFragmentInHTMLComment +* @description This is an alias of {@link module:xss-filters#uriComponentInHTMLComment} +* +* @alias module:xss-filters#uriComponentInHTMLComment +*/ +exports.uriFragmentInHTMLComment = exports.uriComponentInHTMLComment; + +},{}]},{},[1])(1) +}); \ No newline at end of file diff --git a/dist/xss-filters.min-browserified.js b/dist/xss-filters.min-browserified.js new file mode 100644 index 0000000..da1d263 --- /dev/null +++ b/dist/xss-filters.min-browserified.js @@ -0,0 +1,5 @@ +/** + * xss-filters - v1.2.4 + * Yahoo! Inc. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. + */ +!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.xssFilters=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g=55296&&57343>=c||13===c?"�":f.frCoPt(c)):b[e||g]||a}return b=b||p,c=c||o,void 0===a?"undefined":null===a?"null":a.toString().replace(k,"�").replace(c,e)}function c(a){return"\\"+a.charCodeAt(0).toString(16).toLowerCase()+" "}function d(a,d){return b(a).replace(d,c)}function e(d,e){d=f.yufull(b(d));var g=a(d);return g&&v[g.toLowerCase()]&&(d="##"+d),e?d.replace(e,c):d}var f,g=/])/g,m=/[&<>"'`]/g,n=/(?:\x00|^-*!?>|--!?>|--?!?$|\]>|\]$)/g,o=/&(?:#([xX][0-9A-Fa-f]+|\d+);?|(Tab|NewLine|colon|semi|lpar|rpar|apos|sol|comma|excl|ast|midast|ensp|emsp|thinsp);|(nbsp|amp|AMP|lt|LT|gt|GT|quot|QUOT);?)/g,p={Tab:" ",NewLine:"\n",colon:":",semi:";",lpar:"(",rpar:")",apos:"'",sol:"/",comma:",",excl:"!",ast:"*",midast:"*",ensp:" ",emsp:" ",thinsp:" ",nbsp:" ",amp:"&",lt:"<",gt:">",quot:'"',QUOT:'"'},q=/[^%#+\-\w\.]/g,r=/[\x01-\x1F\x7F\\"]/g,s=/[\x01-\x1F\x7F\\']/g,t=/['\(\)]/g,u=/\/\/%5[Bb]([A-Fa-f0-9:]+)%5[Dd]/,v={javascript:1,data:1,vbscript:1,mhtml:1},w=/(?::|&#[xX]0*3[aA];?|�*58;?|:)/,x=/(?:^[\x00-\x20]+|[\t\n\r\x00]+)/g,y={Tab:" ",NewLine:"\n"},z=function(a,b,c){return void 0===a?"undefined":null===a?"null":a.toString().replace(b,c)},A=String.fromCodePoint||function(a){return 0===arguments.length?"":65535>=a?String.fromCharCode(a):(a-=65536,String.fromCharCode((a>>10)+55296,a%1024+56320))};return f={frCoPt:function(a){return void 0===a||null===a?"":!isFinite(a=Number(a))||0>=a||a>1114111||a>=1&&8>=a||a>=14&&31>=a||a>=127&&159>=a||a>=64976&&65007>=a||11===a||65535===(65535&a)||65534===(65535&a)?"�":A(a)},d:b,yup:function(c){return c=a(c.replace(k,"")),c?b(c,y,null,!0).replace(x,"").toLowerCase():null},y:function(a){return z(a,m,function(a){return"&"===a?"&":"<"===a?"<":">"===a?">":'"'===a?""":"'"===a?"'":"`"})},ya:function(a){return z(a,j,"&")},yd:function(a){return z(a,g,"<")},yc:function(a){return z(a,n,function(a){return"\x00"===a?"�":"--!"===a||"--"===a||"-"===a||"]"===a?a+" ":a.slice(0,-1)+" >"})},yavd:function(a){return z(a,h,""")},yavs:function(a){return z(a,i,"'")},yavu:function(a){return z(a,l,function(a){return" "===a?" ":"\n"===a?" ":" "===a?" ":"\f"===a?" ":"\r"===a?" ":" "===a?" ":"="===a?"=":"<"===a?"<":">"===a?">":'"'===a?""":"'"===a?"'":"`"===a?"`":"�"})},yu:encodeURI,yuc:encodeURIComponent,yubl:function(a){return v[f.yup(a)]?"x-"+a:a},yufull:function(a){return f.yu(a).replace(u,function(a,b){return"//["+b+"]"})},yublf:function(a){return f.yubl(f.yufull(a))},yceu:function(a){return d(a,q)},yced:function(a){return d(a,r)},yces:function(a){return d(a,s)},yceuu:function(a){return e(a,t)},yceud:function(a){return e(a)},yceus:function(a){return e(a,i)}}};var e=c._privFilters=c._getPrivFilters();c.inHTMLData=e.yd,c.inHTMLComment=e.yc,c.inSingleQuotedAttr=e.yavs,c.inDoubleQuotedAttr=e.yavd,c.inUnQuotedAttr=e.yavu,c.uriInSingleQuotedAttr=function(a){return d(a,e.yavs)},c.uriInDoubleQuotedAttr=function(a){return d(a,e.yavd)},c.uriInUnQuotedAttr=function(a){return d(a,e.yavu)},c.uriInHTMLData=e.yufull,c.uriInHTMLComment=function(a){return e.yc(e.yufull(a))},c.uriPathInSingleQuotedAttr=function(a){return d(a,e.yavs,e.yu)},c.uriPathInDoubleQuotedAttr=function(a){return d(a,e.yavd,e.yu)},c.uriPathInUnQuotedAttr=function(a){return d(a,e.yavu,e.yu)},c.uriPathInHTMLData=e.yu,c.uriPathInHTMLComment=function(a){return e.yc(e.yu(a))},c.uriQueryInSingleQuotedAttr=c.uriPathInSingleQuotedAttr,c.uriQueryInDoubleQuotedAttr=c.uriPathInDoubleQuotedAttr,c.uriQueryInUnQuotedAttr=c.uriPathInUnQuotedAttr,c.uriQueryInHTMLData=c.uriPathInHTMLData,c.uriQueryInHTMLComment=c.uriPathInHTMLComment,c.uriComponentInSingleQuotedAttr=function(a){return e.yavs(e.yuc(a))},c.uriComponentInDoubleQuotedAttr=function(a){return e.yavd(e.yuc(a))},c.uriComponentInUnQuotedAttr=function(a){return e.yavu(e.yuc(a))},c.uriComponentInHTMLData=e.yuc,c.uriComponentInHTMLComment=function(a){return e.yc(e.yuc(a))},c.uriFragmentInSingleQuotedAttr=function(a){return e.yubl(e.yavs(e.yuc(a)))},c.uriFragmentInDoubleQuotedAttr=function(a){return e.yubl(e.yavd(e.yuc(a)))},c.uriFragmentInUnQuotedAttr=function(a){return e.yubl(e.yavu(e.yuc(a)))},c.uriFragmentInHTMLData=c.uriComponentInHTMLData,c.uriFragmentInHTMLComment=c.uriComponentInHTMLComment},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/dist/xss-filters.min.js b/dist/xss-filters.min.js index 7d31f1e..1b6efa1 100644 --- a/dist/xss-filters.min.js +++ b/dist/xss-filters.min.js @@ -1,5 +1,5 @@ /** - * xss-filters - v1.2.3 + * xss-filters - v1.2.4 * Yahoo! Inc. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. */ -!function(a,b){function c(a,b,c){return d.yubl(b((c||d.yufull)(a)))}b.xssFilters=a,a._getPrivFilters=function(){function a(a){return a=a.split(x,2),2===a.length&&a[0]?a[0]:null}function b(a,b){return"undefined"==typeof a?"undefined":null===a?"null":b.apply(a.toString(),[].splice.call(arguments,2))}function c(a,c,d,e,f){c=c||q,d=d||p;var h,i=[].splice.call(arguments,4);return b(a,function(){return h=this.replace(l,"�").replace(d,function(a,b,d,e){return b?(b=Number(b[0]<="9"?b:"0"+b),f?B(b):128===b?"€":130===b?"‚":131===b?"ƒ":132===b?"„":133===b?"…":134===b?"†":135===b?"‡":136===b?"ˆ":137===b?"‰":138===b?"Š":139===b?"‹":140===b?"Œ":142===b?"Ž":145===b?"‘":146===b?"’":147===b?"“":148===b?"”":149===b?"•":150===b?"–":151===b?"—":152===b?"˜":153===b?"™":154===b?"š":155===b?"›":156===b?"œ":158===b?"ž":159===b?"Ÿ":b>=55296&&57343>=b||13===b?"�":g.frCoPt(b)):c[d||e]||a}),e?e.apply(h,i):h})}function d(a){return"\\"+a.charCodeAt(0).toString(16).toLowerCase()+" "}function e(a,b){return c(a,null,null,function(){return this.replace(b,d)})}function f(b,e){return c(b,null,null,function(){var b=g.yufull(this),c=a(b);return b=c&&w[c.toLowerCase()]?"##"+b:b,e?b.replace(e,d):b})}var g,h=/])/g,n=/[&<>"'`]/g,o=/(?:\x00|^-*!?>|--!?>|--?!?$|\]>|\]$)/g,p=/&(?:#([xX][0-9A-Fa-f]+|\d+);?|(Tab|NewLine|colon|semi|lpar|rpar|apos|sol|comma|excl|ast|midast|ensp|emsp|thinsp);|(nbsp|amp|AMP|lt|LT|gt|GT|quot|QUOT);?)/g,q={Tab:" ",NewLine:"\n",colon:":",semi:";",lpar:"(",rpar:")",apos:"'",sol:"/",comma:",",excl:"!",ast:"*",midast:"*",ensp:" ",emsp:" ",thinsp:" ",nbsp:" ",amp:"&",lt:"<",gt:">",quot:'"',QUOT:'"'},r=/[^%#+\-\w\.]/g,s=/[\x01-\x1F\x7F\\"]/g,t=/[\x01-\x1F\x7F\\']/g,u=/['\(\)]/g,v=/\/\/%5[Bb]([A-Fa-f0-9:]+)%5[Dd]/,w={javascript:1,data:1,vbscript:1,mhtml:1},x=/(?::|&#[xX]0*3[aA];?|�*58;?|:)/,y=/(?:^[\x00-\x20]+|[\t\n\r\x00]+)/g,z={Tab:" ",NewLine:"\n"},A=String.prototype.replace,B=String.fromCodePoint||function(a){return 0===arguments.length?"":65535>=a?String.fromCharCode(a):(a-=65536,String.fromCharCode((a>>10)+55296,a%1024+56320))};return g={frCoPt:function(a){return void 0===a||null===a?"":!isFinite(a=Number(a))||0>=a||a>1114111||a>=1&&8>=a||a>=14&&31>=a||a>=127&&159>=a||a>=64976&&65007>=a||11===a||65535===(65535&a)||65534===(65535&a)?"�":B(a)},d:c,yup:function(b){return b=a(b.replace(l,"")),b?c(b,z,null,function(){return this.replace(y,"").toLowerCase()},!0):null},y:function(a){return b(a,A,n,function(a){return"&"===a?"&":"<"===a?"<":">"===a?">":'"'===a?""":"'"===a?"'":"`"})},ya:function(a){return b(a,A,k,"&")},yd:function(a){return b(a,A,h,"<")},yc:function(a){return b(a,A,o,function(a){return"\x00"===a?"�":"--!"===a||"--"===a||"-"===a||"]"===a?a+" ":a.slice(0,-1)+" >"})},yavd:function(a){return b(a,A,i,""")},yavs:function(a){return b(a,A,j,"'")},yavu:function(a){return b(a,A,m,function(a){return" "===a?" ":"\n"===a?" ":" "===a?" ":"\f"===a?" ":"\r"===a?" ":" "===a?" ":"="===a?"=":"<"===a?"<":">"===a?">":'"'===a?""":"'"===a?"'":"`"===a?"`":"�"})},yu:encodeURI,yuc:encodeURIComponent,yubl:function(a){return w[g.yup(a)]?"x-"+a:a},yufull:function(a){return g.yu(a).replace(v,function(a,b){return"//["+b+"]"})},yublf:function(a){return g.yubl(g.yufull(a))},yceu:function(a){return e(a,r)},yced:function(a){return e(a,s)},yces:function(a){return e(a,t)},yceuu:function(a){return f(a,u)},yceud:function(a){return f(a)},yceus:function(a){return f(a,j)}}};var d=a._privFilters=a._getPrivFilters();a.inHTMLData=d.yd,a.inHTMLComment=d.yc,a.inSingleQuotedAttr=d.yavs,a.inDoubleQuotedAttr=d.yavd,a.inUnQuotedAttr=d.yavu,a.uriInSingleQuotedAttr=function(a){return c(a,d.yavs)},a.uriInDoubleQuotedAttr=function(a){return c(a,d.yavd)},a.uriInUnQuotedAttr=function(a){return c(a,d.yavu)},a.uriInHTMLData=d.yufull,a.uriInHTMLComment=function(a){return d.yc(d.yufull(a))},a.uriPathInSingleQuotedAttr=function(a){return c(a,d.yavs,d.yu)},a.uriPathInDoubleQuotedAttr=function(a){return c(a,d.yavd,d.yu)},a.uriPathInUnQuotedAttr=function(a){return c(a,d.yavu,d.yu)},a.uriPathInHTMLData=d.yu,a.uriPathInHTMLComment=function(a){return d.yc(d.yu(a))},a.uriQueryInSingleQuotedAttr=a.uriPathInSingleQuotedAttr,a.uriQueryInDoubleQuotedAttr=a.uriPathInDoubleQuotedAttr,a.uriQueryInUnQuotedAttr=a.uriPathInUnQuotedAttr,a.uriQueryInHTMLData=a.uriPathInHTMLData,a.uriQueryInHTMLComment=a.uriPathInHTMLComment,a.uriComponentInSingleQuotedAttr=function(a){return d.yavs(d.yuc(a))},a.uriComponentInDoubleQuotedAttr=function(a){return d.yavd(d.yuc(a))},a.uriComponentInUnQuotedAttr=function(a){return d.yavu(d.yuc(a))},a.uriComponentInHTMLData=d.yuc,a.uriComponentInHTMLComment=function(a){return d.yc(d.yuc(a))},a.uriFragmentInSingleQuotedAttr=function(a){return d.yubl(d.yavs(d.yuc(a)))},a.uriFragmentInDoubleQuotedAttr=function(a){return d.yubl(d.yavd(d.yuc(a)))},a.uriFragmentInUnQuotedAttr=function(a){return d.yubl(d.yavu(d.yuc(a)))},a.uriFragmentInHTMLData=a.uriComponentInHTMLData,a.uriFragmentInHTMLComment=a.uriComponentInHTMLComment}({},function(){return this}()); \ No newline at end of file +!function(a,b){function c(a,b,c){return d.yubl(b((c||d.yufull)(a)))}b.xssFilters=a,a._getPrivFilters=function(){function a(a){return a=a.split(w,2),2===a.length&&a[0]?a[0]:null}function b(a,b,c,d){function e(a,c,e,g){return c?(c=Number(c[0]<="9"?c:"0"+c),d?A(c):128===c?"€":130===c?"‚":131===c?"ƒ":132===c?"„":133===c?"…":134===c?"†":135===c?"‡":136===c?"ˆ":137===c?"‰":138===c?"Š":139===c?"‹":140===c?"Œ":142===c?"Ž":145===c?"‘":146===c?"’":147===c?"“":148===c?"”":149===c?"•":150===c?"–":151===c?"—":152===c?"˜":153===c?"™":154===c?"š":155===c?"›":156===c?"œ":158===c?"ž":159===c?"Ÿ":c>=55296&&57343>=c||13===c?"�":f.frCoPt(c)):b[e||g]||a}return b=b||p,c=c||o,void 0===a?"undefined":null===a?"null":a.toString().replace(k,"�").replace(c,e)}function c(a){return"\\"+a.charCodeAt(0).toString(16).toLowerCase()+" "}function d(a,d){return b(a).replace(d,c)}function e(d,e){d=f.yufull(b(d));var g=a(d);return g&&v[g.toLowerCase()]&&(d="##"+d),e?d.replace(e,c):d}var f,g=/])/g,m=/[&<>"'`]/g,n=/(?:\x00|^-*!?>|--!?>|--?!?$|\]>|\]$)/g,o=/&(?:#([xX][0-9A-Fa-f]+|\d+);?|(Tab|NewLine|colon|semi|lpar|rpar|apos|sol|comma|excl|ast|midast|ensp|emsp|thinsp);|(nbsp|amp|AMP|lt|LT|gt|GT|quot|QUOT);?)/g,p={Tab:" ",NewLine:"\n",colon:":",semi:";",lpar:"(",rpar:")",apos:"'",sol:"/",comma:",",excl:"!",ast:"*",midast:"*",ensp:" ",emsp:" ",thinsp:" ",nbsp:" ",amp:"&",lt:"<",gt:">",quot:'"',QUOT:'"'},q=/[^%#+\-\w\.]/g,r=/[\x01-\x1F\x7F\\"]/g,s=/[\x01-\x1F\x7F\\']/g,t=/['\(\)]/g,u=/\/\/%5[Bb]([A-Fa-f0-9:]+)%5[Dd]/,v={javascript:1,data:1,vbscript:1,mhtml:1},w=/(?::|&#[xX]0*3[aA];?|�*58;?|:)/,x=/(?:^[\x00-\x20]+|[\t\n\r\x00]+)/g,y={Tab:" ",NewLine:"\n"},z=function(a,b,c){return void 0===a?"undefined":null===a?"null":a.toString().replace(b,c)},A=String.fromCodePoint||function(a){return 0===arguments.length?"":65535>=a?String.fromCharCode(a):(a-=65536,String.fromCharCode((a>>10)+55296,a%1024+56320))};return f={frCoPt:function(a){return void 0===a||null===a?"":!isFinite(a=Number(a))||0>=a||a>1114111||a>=1&&8>=a||a>=14&&31>=a||a>=127&&159>=a||a>=64976&&65007>=a||11===a||65535===(65535&a)||65534===(65535&a)?"�":A(a)},d:b,yup:function(c){return c=a(c.replace(k,"")),c?b(c,y,null,!0).replace(x,"").toLowerCase():null},y:function(a){return z(a,m,function(a){return"&"===a?"&":"<"===a?"<":">"===a?">":'"'===a?""":"'"===a?"'":"`"})},ya:function(a){return z(a,j,"&")},yd:function(a){return z(a,g,"<")},yc:function(a){return z(a,n,function(a){return"\x00"===a?"�":"--!"===a||"--"===a||"-"===a||"]"===a?a+" ":a.slice(0,-1)+" >"})},yavd:function(a){return z(a,h,""")},yavs:function(a){return z(a,i,"'")},yavu:function(a){return z(a,l,function(a){return" "===a?" ":"\n"===a?" ":" "===a?" ":"\f"===a?" ":"\r"===a?" ":" "===a?" ":"="===a?"=":"<"===a?"<":">"===a?">":'"'===a?""":"'"===a?"'":"`"===a?"`":"�"})},yu:encodeURI,yuc:encodeURIComponent,yubl:function(a){return v[f.yup(a)]?"x-"+a:a},yufull:function(a){return f.yu(a).replace(u,function(a,b){return"//["+b+"]"})},yublf:function(a){return f.yubl(f.yufull(a))},yceu:function(a){return d(a,q)},yced:function(a){return d(a,r)},yces:function(a){return d(a,s)},yceuu:function(a){return e(a,t)},yceud:function(a){return e(a)},yceus:function(a){return e(a,i)}}};var d=a._privFilters=a._getPrivFilters();a.inHTMLData=d.yd,a.inHTMLComment=d.yc,a.inSingleQuotedAttr=d.yavs,a.inDoubleQuotedAttr=d.yavd,a.inUnQuotedAttr=d.yavu,a.uriInSingleQuotedAttr=function(a){return c(a,d.yavs)},a.uriInDoubleQuotedAttr=function(a){return c(a,d.yavd)},a.uriInUnQuotedAttr=function(a){return c(a,d.yavu)},a.uriInHTMLData=d.yufull,a.uriInHTMLComment=function(a){return d.yc(d.yufull(a))},a.uriPathInSingleQuotedAttr=function(a){return c(a,d.yavs,d.yu)},a.uriPathInDoubleQuotedAttr=function(a){return c(a,d.yavd,d.yu)},a.uriPathInUnQuotedAttr=function(a){return c(a,d.yavu,d.yu)},a.uriPathInHTMLData=d.yu,a.uriPathInHTMLComment=function(a){return d.yc(d.yu(a))},a.uriQueryInSingleQuotedAttr=a.uriPathInSingleQuotedAttr,a.uriQueryInDoubleQuotedAttr=a.uriPathInDoubleQuotedAttr,a.uriQueryInUnQuotedAttr=a.uriPathInUnQuotedAttr,a.uriQueryInHTMLData=a.uriPathInHTMLData,a.uriQueryInHTMLComment=a.uriPathInHTMLComment,a.uriComponentInSingleQuotedAttr=function(a){return d.yavs(d.yuc(a))},a.uriComponentInDoubleQuotedAttr=function(a){return d.yavd(d.yuc(a))},a.uriComponentInUnQuotedAttr=function(a){return d.yavu(d.yuc(a))},a.uriComponentInHTMLData=d.yuc,a.uriComponentInHTMLComment=function(a){return d.yc(d.yuc(a))},a.uriFragmentInSingleQuotedAttr=function(a){return d.yubl(d.yavs(d.yuc(a)))},a.uriFragmentInDoubleQuotedAttr=function(a){return d.yubl(d.yavd(d.yuc(a)))},a.uriFragmentInUnQuotedAttr=function(a){return d.yubl(d.yavu(d.yuc(a)))},a.uriFragmentInHTMLData=a.uriComponentInHTMLData,a.uriFragmentInHTMLComment=a.uriComponentInHTMLComment}({},function(){return this}()); \ No newline at end of file diff --git a/package.json b/package.json index 949758d..a49a219 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xss-filters", - "version": "1.2.3", + "version": "1.2.4", "licenses": [ { "type": "BSD", diff --git a/src/xss-filters.js b/src/xss-filters.js index 57c7992..4f490d9 100644 --- a/src/xss-filters.js +++ b/src/xss-filters.js @@ -51,7 +51,11 @@ exports._getPrivFilters = function () { URI_PROTOCOL_NAMED_REF_MAP = {Tab: '\t', NewLine: '\n'}; var x, - strReplace = String.prototype.replace, + strReplace = function (s, regexp, callback) { + return s === undefined ? 'undefined' + : s === null ? 'null' + : s.toString().replace(regexp, callback); + }, fromCodePoint = String.fromCodePoint || function(codePoint) { if (arguments.length === 0) { return ''; @@ -72,90 +76,83 @@ exports._getPrivFilters = function () { return (s.length === 2 && s[0]) ? s[0] : null; } - function stringify(s, callback) { - return typeof s === 'undefined' ? 'undefined' - : s === null ? 'null' - : callback.apply(s.toString(), [].splice.call(arguments, 2)); - } - - - function htmlDecode(s, namedRefMap, reNamedRef, callback, skipReplacement) { + function htmlDecode(s, namedRefMap, reNamedRef, skipReplacement) { + namedRefMap = namedRefMap || SENSITIVE_NAMED_REF_MAP; reNamedRef = reNamedRef || SENSITIVE_HTML_ENTITIES; - var decodedStr, args = [].splice.call(arguments, 4); - - return stringify(s, function() { - decodedStr = this.replace(NULL, '\uFFFD').replace(reNamedRef, function(m, num, named, named1) { - if (num) { - num = Number(num[0] <= '9' ? num : '0' + num); - // switch(num) { - // case 0x80: return '\u20AC'; // EURO SIGN (€) - // case 0x82: return '\u201A'; // SINGLE LOW-9 QUOTATION MARK (‚) - // case 0x83: return '\u0192'; // LATIN SMALL LETTER F WITH HOOK (ƒ) - // case 0x84: return '\u201E'; // DOUBLE LOW-9 QUOTATION MARK („) - // case 0x85: return '\u2026'; // HORIZONTAL ELLIPSIS (…) - // case 0x86: return '\u2020'; // DAGGER (†) - // case 0x87: return '\u2021'; // DOUBLE DAGGER (‡) - // case 0x88: return '\u02C6'; // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ) - // case 0x89: return '\u2030'; // PER MILLE SIGN (‰) - // case 0x8A: return '\u0160'; // LATIN CAPITAL LETTER S WITH CARON (Š) - // case 0x8B: return '\u2039'; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹) - // case 0x8C: return '\u0152'; // LATIN CAPITAL LIGATURE OE (Œ) - // case 0x8E: return '\u017D'; // LATIN CAPITAL LETTER Z WITH CARON (Ž) - // case 0x91: return '\u2018'; // LEFT SINGLE QUOTATION MARK (‘) - // case 0x92: return '\u2019'; // RIGHT SINGLE QUOTATION MARK (’) - // case 0x93: return '\u201C'; // LEFT DOUBLE QUOTATION MARK (“) - // case 0x94: return '\u201D'; // RIGHT DOUBLE QUOTATION MARK (”) - // case 0x95: return '\u2022'; // BULLET (•) - // case 0x96: return '\u2013'; // EN DASH (–) - // case 0x97: return '\u2014'; // EM DASH (—) - // case 0x98: return '\u02DC'; // SMALL TILDE (˜) - // case 0x99: return '\u2122'; // TRADE MARK SIGN (™) - // case 0x9A: return '\u0161'; // LATIN SMALL LETTER S WITH CARON (š) - // case 0x9B: return '\u203A'; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›) - // case 0x9C: return '\u0153'; // LATIN SMALL LIGATURE OE (œ) - // case 0x9E: return '\u017E'; // LATIN SMALL LETTER Z WITH CARON (ž) - // case 0x9F: return '\u0178'; // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ) - // } - // // num >= 0xD800 && num <= 0xDFFF, and 0x0D is separately handled, as it doesn't fall into the range of x.pec() - // return (num >= 0xD800 && num <= 0xDFFF) || num === 0x0D ? '\uFFFD' : x.frCoPt(num); - - return skipReplacement ? fromCodePoint(num) - : num === 0x80 ? '\u20AC' // EURO SIGN (€) - : num === 0x82 ? '\u201A' // SINGLE LOW-9 QUOTATION MARK (‚) - : num === 0x83 ? '\u0192' // LATIN SMALL LETTER F WITH HOOK (ƒ) - : num === 0x84 ? '\u201E' // DOUBLE LOW-9 QUOTATION MARK („) - : num === 0x85 ? '\u2026' // HORIZONTAL ELLIPSIS (…) - : num === 0x86 ? '\u2020' // DAGGER (†) - : num === 0x87 ? '\u2021' // DOUBLE DAGGER (‡) - : num === 0x88 ? '\u02C6' // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ) - : num === 0x89 ? '\u2030' // PER MILLE SIGN (‰) - : num === 0x8A ? '\u0160' // LATIN CAPITAL LETTER S WITH CARON (Š) - : num === 0x8B ? '\u2039' // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹) - : num === 0x8C ? '\u0152' // LATIN CAPITAL LIGATURE OE (Œ) - : num === 0x8E ? '\u017D' // LATIN CAPITAL LETTER Z WITH CARON (Ž) - : num === 0x91 ? '\u2018' // LEFT SINGLE QUOTATION MARK (‘) - : num === 0x92 ? '\u2019' // RIGHT SINGLE QUOTATION MARK (’) - : num === 0x93 ? '\u201C' // LEFT DOUBLE QUOTATION MARK (“) - : num === 0x94 ? '\u201D' // RIGHT DOUBLE QUOTATION MARK (”) - : num === 0x95 ? '\u2022' // BULLET (•) - : num === 0x96 ? '\u2013' // EN DASH (–) - : num === 0x97 ? '\u2014' // EM DASH (—) - : num === 0x98 ? '\u02DC' // SMALL TILDE (˜) - : num === 0x99 ? '\u2122' // TRADE MARK SIGN (™) - : num === 0x9A ? '\u0161' // LATIN SMALL LETTER S WITH CARON (š) - : num === 0x9B ? '\u203A' // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›) - : num === 0x9C ? '\u0153' // LATIN SMALL LIGATURE OE (œ) - : num === 0x9E ? '\u017E' // LATIN SMALL LETTER Z WITH CARON (ž) - : num === 0x9F ? '\u0178' // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ) - : (num >= 0xD800 && num <= 0xDFFF) || num === 0x0D ? '\uFFFD' - : x.frCoPt(num); - } - return namedRefMap[named || named1] || m; - }); - return callback ? callback.apply(decodedStr, args) : decodedStr; - }); + function regExpFunction(m, num, named, named1) { + if (num) { + num = Number(num[0] <= '9' ? num : '0' + num); + // switch(num) { + // case 0x80: return '\u20AC'; // EURO SIGN (€) + // case 0x82: return '\u201A'; // SINGLE LOW-9 QUOTATION MARK (‚) + // case 0x83: return '\u0192'; // LATIN SMALL LETTER F WITH HOOK (ƒ) + // case 0x84: return '\u201E'; // DOUBLE LOW-9 QUOTATION MARK („) + // case 0x85: return '\u2026'; // HORIZONTAL ELLIPSIS (…) + // case 0x86: return '\u2020'; // DAGGER (†) + // case 0x87: return '\u2021'; // DOUBLE DAGGER (‡) + // case 0x88: return '\u02C6'; // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ) + // case 0x89: return '\u2030'; // PER MILLE SIGN (‰) + // case 0x8A: return '\u0160'; // LATIN CAPITAL LETTER S WITH CARON (Š) + // case 0x8B: return '\u2039'; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹) + // case 0x8C: return '\u0152'; // LATIN CAPITAL LIGATURE OE (Œ) + // case 0x8E: return '\u017D'; // LATIN CAPITAL LETTER Z WITH CARON (Ž) + // case 0x91: return '\u2018'; // LEFT SINGLE QUOTATION MARK (‘) + // case 0x92: return '\u2019'; // RIGHT SINGLE QUOTATION MARK (’) + // case 0x93: return '\u201C'; // LEFT DOUBLE QUOTATION MARK (“) + // case 0x94: return '\u201D'; // RIGHT DOUBLE QUOTATION MARK (”) + // case 0x95: return '\u2022'; // BULLET (•) + // case 0x96: return '\u2013'; // EN DASH (–) + // case 0x97: return '\u2014'; // EM DASH (—) + // case 0x98: return '\u02DC'; // SMALL TILDE (˜) + // case 0x99: return '\u2122'; // TRADE MARK SIGN (™) + // case 0x9A: return '\u0161'; // LATIN SMALL LETTER S WITH CARON (š) + // case 0x9B: return '\u203A'; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›) + // case 0x9C: return '\u0153'; // LATIN SMALL LIGATURE OE (œ) + // case 0x9E: return '\u017E'; // LATIN SMALL LETTER Z WITH CARON (ž) + // case 0x9F: return '\u0178'; // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ) + // } + // // num >= 0xD800 && num <= 0xDFFF, and 0x0D is separately handled, as it doesn't fall into the range of x.pec() + // return (num >= 0xD800 && num <= 0xDFFF) || num === 0x0D ? '\uFFFD' : x.frCoPt(num); + + return skipReplacement ? fromCodePoint(num) + : num === 0x80 ? '\u20AC' // EURO SIGN (€) + : num === 0x82 ? '\u201A' // SINGLE LOW-9 QUOTATION MARK (‚) + : num === 0x83 ? '\u0192' // LATIN SMALL LETTER F WITH HOOK (ƒ) + : num === 0x84 ? '\u201E' // DOUBLE LOW-9 QUOTATION MARK („) + : num === 0x85 ? '\u2026' // HORIZONTAL ELLIPSIS (…) + : num === 0x86 ? '\u2020' // DAGGER (†) + : num === 0x87 ? '\u2021' // DOUBLE DAGGER (‡) + : num === 0x88 ? '\u02C6' // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ) + : num === 0x89 ? '\u2030' // PER MILLE SIGN (‰) + : num === 0x8A ? '\u0160' // LATIN CAPITAL LETTER S WITH CARON (Š) + : num === 0x8B ? '\u2039' // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹) + : num === 0x8C ? '\u0152' // LATIN CAPITAL LIGATURE OE (Œ) + : num === 0x8E ? '\u017D' // LATIN CAPITAL LETTER Z WITH CARON (Ž) + : num === 0x91 ? '\u2018' // LEFT SINGLE QUOTATION MARK (‘) + : num === 0x92 ? '\u2019' // RIGHT SINGLE QUOTATION MARK (’) + : num === 0x93 ? '\u201C' // LEFT DOUBLE QUOTATION MARK (“) + : num === 0x94 ? '\u201D' // RIGHT DOUBLE QUOTATION MARK (”) + : num === 0x95 ? '\u2022' // BULLET (•) + : num === 0x96 ? '\u2013' // EN DASH (–) + : num === 0x97 ? '\u2014' // EM DASH (—) + : num === 0x98 ? '\u02DC' // SMALL TILDE (˜) + : num === 0x99 ? '\u2122' // TRADE MARK SIGN (™) + : num === 0x9A ? '\u0161' // LATIN SMALL LETTER S WITH CARON (š) + : num === 0x9B ? '\u203A' // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›) + : num === 0x9C ? '\u0153' // LATIN SMALL LIGATURE OE (œ) + : num === 0x9E ? '\u017E' // LATIN SMALL LETTER Z WITH CARON (ž) + : num === 0x9F ? '\u0178' // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ) + : (num >= 0xD800 && num <= 0xDFFF) || num === 0x0D ? '\uFFFD' + : x.frCoPt(num); + } + return namedRefMap[named || named1] || m; + } + + return s === undefined ? 'undefined' + : s === null ? 'null' + : s.toString().replace(NULL, '\uFFFD').replace(reNamedRef, regExpFunction); } function cssEncode(chr) { @@ -163,19 +160,19 @@ exports._getPrivFilters = function () { return '\\' + chr.charCodeAt(0).toString(16).toLowerCase() + ' '; } function css(s, reSensitiveChars) { - return htmlDecode(s, null, null, function() { - return this.replace(reSensitiveChars, cssEncode); - }); + return htmlDecode(s).replace(reSensitiveChars, cssEncode); } function cssUrl(s, reSensitiveChars) { - return htmlDecode(s, null, null, function() { - // encodeURI() will throw error for use of the CSS_UNSUPPORTED_CODE_POINT (i.e., [\uD800-\uDFFF]) - var s = x.yufull(this), protocol = getProtocol(s); - // prefix ## for blacklisted protocols - s = protocol && URI_BLACKLIST_PROTOCOLS[protocol.toLowerCase()] ? '##' + s : s; - - return reSensitiveChars ? s.replace(reSensitiveChars, cssEncode) : s; - }); + // encodeURI() in yufull() will throw error for use of the CSS_UNSUPPORTED_CODE_POINT (i.e., [\uD800-\uDFFF]) + s = x.yufull(htmlDecode(s)); + var protocol = getProtocol(s); + + // prefix ## for blacklisted protocols + if (protocol && URI_BLACKLIST_PROTOCOLS[protocol.toLowerCase()]) { + s = '##' + s; + } + + return reSensitiveChars ? s.replace(reSensitiveChars, cssEncode) : s; } return (x = { @@ -204,9 +201,7 @@ exports._getPrivFilters = function () { yup: function(s) { s = getProtocol(s.replace(NULL, '')); // URI_PROTOCOL_WHITESPACES is required for left trim and remove interim whitespaces - return s ? htmlDecode(s, URI_PROTOCOL_NAMED_REF_MAP, null, function() { - return this.replace(URI_PROTOCOL_WHITESPACES, '').toLowerCase(); - }, true): null; + return s ? htmlDecode(s, URI_PROTOCOL_NAMED_REF_MAP, null, true).replace(URI_PROTOCOL_WHITESPACES, '').toLowerCase() : null; }, /* @@ -216,7 +211,7 @@ exports._getPrivFilters = function () { * */ y: function(s) { - return stringify(s, strReplace, SPECIAL_HTML_CHARS, function (m) { + return strReplace(s, SPECIAL_HTML_CHARS, function (m) { return m === '&' ? '&' : m === '<' ? '<' : m === '>' ? '>' @@ -228,13 +223,13 @@ exports._getPrivFilters = function () { // This filter is meant to introduce double-encoding, and should be used with extra care. ya: function(s) { - return stringify(s, strReplace, AMP, '&'); + return strReplace(s, AMP, '&'); }, // FOR DETAILS, refer to inHTMLData() // Reference: https://html.spec.whatwg.org/multipage/syntax.html#data-state yd: function (s) { - return stringify(s, strReplace, LT, '<'); + return strReplace(s, LT, '<'); }, // FOR DETAILS, refer to inHTMLComment() @@ -250,7 +245,7 @@ exports._getPrivFilters = function () { // We do not care --\s>, which can possibly be intepreted as a valid close comment tag in very old browsers (e.g., firefox 3.6), as specified in the html4 spec // Reference: http://www.w3.org/TR/html401/intro/sgmltut.html#h-3.2.4 yc: function (s) { - return stringify(s, strReplace, SPECIAL_COMMENT_CHARS, function(m){ + return strReplace(s, SPECIAL_COMMENT_CHARS, function(m){ return m === '\x00' ? '\uFFFD' : m === '--!' || m === '--' || m === '-' || m === ']' ? m + ' ' :/* @@ -264,13 +259,13 @@ exports._getPrivFilters = function () { // FOR DETAILS, refer to inDoubleQuotedAttr() // Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(double-quoted)-state yavd: function (s) { - return stringify(s, strReplace, QUOT, '"'); + return strReplace(s, QUOT, '"'); }, // FOR DETAILS, refer to inSingleQuotedAttr() // Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(single-quoted)-state yavs: function (s) { - return stringify(s, strReplace, SQUOT, '''); + return strReplace(s, SQUOT, '''); }, // FOR DETAILS, refer to inUnQuotedAttr() @@ -303,7 +298,7 @@ exports._getPrivFilters = function () { // Example: // yavu: function (s) { - return stringify(s, strReplace, SPECIAL_ATTR_VALUE_UNQUOTED_CHARS, function (m) { + return strReplace(s, SPECIAL_ATTR_VALUE_UNQUOTED_CHARS, function (m) { return m === '\t' ? ' ' // in hex: 09 : m === '\n' ? ' ' // in hex: 0A : m === '\x0B' ? ' ' // in hex: 0B for IE. IE<9 \v equals v, so use \x0B instead @@ -332,10 +327,9 @@ exports._getPrivFilters = function () { // This is NOT a security-critical filter. // Reference: https://tools.ietf.org/html/rfc3986 yufull: function (s) { - return x.yu(s) - .replace(URL_IPV6, function(m, p) { - return '//[' + p + ']'; - }); + return x.yu(s).replace(URL_IPV6, function(m, p) { + return '//[' + p + ']'; + }); }, // chain yufull() with yubl()