@deepmetier/xss 0.0.0-stage → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/xss.js ADDED
@@ -0,0 +1,1784 @@
1
+ (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2
+ /**
3
+ * default settings
4
+ *
5
+ * @author Zongmin Lei<leizongmin@gmail.com>
6
+ */
7
+
8
+ var FilterCSS = require("cssfilter").FilterCSS;
9
+ var getDefaultCSSWhiteList = require("cssfilter").getDefaultWhiteList;
10
+ var _ = require("./util");
11
+
12
+ function getDefaultWhiteList() {
13
+ return {
14
+ a: ["target", "href", "title"],
15
+ abbr: ["title"],
16
+ address: [],
17
+ area: ["shape", "coords", "href", "alt"],
18
+ article: [],
19
+ aside: [],
20
+ audio: [
21
+ "autoplay",
22
+ "controls",
23
+ "crossorigin",
24
+ "loop",
25
+ "muted",
26
+ "preload",
27
+ "src",
28
+ ],
29
+ b: [],
30
+ bdi: ["dir"],
31
+ bdo: ["dir"],
32
+ big: [],
33
+ blockquote: ["cite"],
34
+ br: [],
35
+ caption: [],
36
+ center: [],
37
+ cite: [],
38
+ code: [],
39
+ col: ["align", "valign", "span", "width"],
40
+ colgroup: ["align", "valign", "span", "width"],
41
+ dd: [],
42
+ del: ["datetime"],
43
+ details: ["open"],
44
+ div: [],
45
+ dl: [],
46
+ dt: [],
47
+ em: [],
48
+ figcaption: [],
49
+ figure: [],
50
+ font: ["color", "size", "face"],
51
+ footer: [],
52
+ h1: [],
53
+ h2: [],
54
+ h3: [],
55
+ h4: [],
56
+ h5: [],
57
+ h6: [],
58
+ header: [],
59
+ hr: [],
60
+ i: [],
61
+ img: ["src", "alt", "title", "width", "height", "loading"],
62
+ ins: ["datetime"],
63
+ kbd: [],
64
+ li: [],
65
+ mark: [],
66
+ nav: [],
67
+ ol: [],
68
+ p: [],
69
+ pre: [],
70
+ s: [],
71
+ section: [],
72
+ small: [],
73
+ span: [],
74
+ sub: [],
75
+ summary: [],
76
+ sup: [],
77
+ strong: [],
78
+ strike: [],
79
+ table: ["width", "border", "align", "valign"],
80
+ tbody: ["align", "valign"],
81
+ td: ["width", "rowspan", "colspan", "align", "valign"],
82
+ tfoot: ["align", "valign"],
83
+ th: ["width", "rowspan", "colspan", "align", "valign"],
84
+ thead: ["align", "valign"],
85
+ tr: ["rowspan", "align", "valign"],
86
+ tt: [],
87
+ u: [],
88
+ ul: [],
89
+ video: [
90
+ "autoplay",
91
+ "controls",
92
+ "crossorigin",
93
+ "loop",
94
+ "muted",
95
+ "playsinline",
96
+ "poster",
97
+ "preload",
98
+ "src",
99
+ "height",
100
+ "width",
101
+ ],
102
+ };
103
+ }
104
+
105
+ var defaultCSSFilter = new FilterCSS();
106
+
107
+ /**
108
+ * default onTag function
109
+ *
110
+ * @param {String} tag
111
+ * @param {String} html
112
+ * @param {Object} options
113
+ * @return {String}
114
+ */
115
+ function onTag(tag, html, options) {
116
+ // do nothing
117
+ }
118
+
119
+ /**
120
+ * default onIgnoreTag function
121
+ *
122
+ * @param {String} tag
123
+ * @param {String} html
124
+ * @param {Object} options
125
+ * @return {String}
126
+ */
127
+ function onIgnoreTag(tag, html, options) {
128
+ // do nothing
129
+ }
130
+
131
+ /**
132
+ * default onTagAttr function
133
+ *
134
+ * @param {String} tag
135
+ * @param {String} name
136
+ * @param {String} value
137
+ * @return {String}
138
+ */
139
+ function onTagAttr(tag, name, value) {
140
+ // do nothing
141
+ }
142
+
143
+ /**
144
+ * default onIgnoreTagAttr function
145
+ *
146
+ * @param {String} tag
147
+ * @param {String} name
148
+ * @param {String} value
149
+ * @return {String}
150
+ */
151
+ function onIgnoreTagAttr(tag, name, value) {
152
+ // do nothing
153
+ }
154
+
155
+ /**
156
+ * default escapeHtml function
157
+ *
158
+ * @param {String} html
159
+ */
160
+ function escapeHtml(html) {
161
+ return html.replace(REGEXP_LT, "&lt;").replace(REGEXP_GT, "&gt;");
162
+ }
163
+
164
+ /**
165
+ * default safeAttrValue function
166
+ *
167
+ * @param {String} tag
168
+ * @param {String} name
169
+ * @param {String} value
170
+ * @param {Object} cssFilter
171
+ * @return {String}
172
+ */
173
+ function safeAttrValue(tag, name, value, cssFilter) {
174
+ // unescape attribute value firstly
175
+ value = friendlyAttrValue(value);
176
+
177
+ if (name === "href" || name === "src") {
178
+ // filter `href` and `src` attribute
179
+ // only allow the value that starts with `http://` | `https://` | `mailto:` | `/` | `#`
180
+ value = _.trim(value);
181
+ if (value === "#") return "#";
182
+ if (
183
+ !(
184
+ value.substr(0, 7) === "http://" ||
185
+ value.substr(0, 8) === "https://" ||
186
+ value.substr(0, 7) === "mailto:" ||
187
+ value.substr(0, 4) === "tel:" ||
188
+ value.substr(0, 11) === "data:image/" ||
189
+ value.substr(0, 6) === "ftp://" ||
190
+ value.substr(0, 2) === "./" ||
191
+ value.substr(0, 3) === "../" ||
192
+ value[0] === "#" ||
193
+ value[0] === "/"
194
+ )
195
+ ) {
196
+ return "";
197
+ }
198
+ } else if (name === "action" || name === "formaction") {
199
+ // Only allow HTTP(S) or relative form URLs; the href/src data:image/ exception does not apply.
200
+ // A relative URL's first segment cannot contain a colon; colons in queries and fragments are not schemes.
201
+ value = _.trim(value);
202
+ if (!/^https?:\/\//i.test(value) && /^[^/?#]*:/.test(value)) {
203
+ return "";
204
+ }
205
+ } else if (name === "background") {
206
+ // filter `background` attribute (maybe no use)
207
+ // `javascript:`
208
+ REGEXP_DEFAULT_ON_TAG_ATTR_4.lastIndex = 0;
209
+ if (REGEXP_DEFAULT_ON_TAG_ATTR_4.test(value)) {
210
+ return "";
211
+ }
212
+ } else if (name === "style") {
213
+ // `expression()`
214
+ REGEXP_DEFAULT_ON_TAG_ATTR_7.lastIndex = 0;
215
+ if (REGEXP_DEFAULT_ON_TAG_ATTR_7.test(value)) {
216
+ return "";
217
+ }
218
+ // `url()`
219
+ REGEXP_DEFAULT_ON_TAG_ATTR_8.lastIndex = 0;
220
+ if (REGEXP_DEFAULT_ON_TAG_ATTR_8.test(value)) {
221
+ REGEXP_DEFAULT_ON_TAG_ATTR_4.lastIndex = 0;
222
+ if (REGEXP_DEFAULT_ON_TAG_ATTR_4.test(value)) {
223
+ return "";
224
+ }
225
+ }
226
+ if (cssFilter !== false) {
227
+ cssFilter = cssFilter || defaultCSSFilter;
228
+ value = cssFilter.process(value);
229
+ }
230
+ }
231
+
232
+ // escape `<>"` before returns
233
+ value = escapeAttrValue(value);
234
+ return value;
235
+ }
236
+
237
+ // RegExp list
238
+ var REGEXP_LT = /</g;
239
+ var REGEXP_GT = />/g;
240
+ var REGEXP_QUOTE = /"/g;
241
+ var REGEXP_QUOTE_2 = /&quot;/g;
242
+ var REGEXP_ATTR_VALUE_1 = /&#([a-zA-Z0-9]*);?/gim;
243
+ var REGEXP_ATTR_VALUE_COLON = /&colon;?/gim;
244
+ var REGEXP_ATTR_VALUE_NEWLINE = /&newline;?/gim;
245
+ // var REGEXP_DEFAULT_ON_TAG_ATTR_3 = /\/\*|\*\//gm;
246
+ var REGEXP_DEFAULT_ON_TAG_ATTR_4 =
247
+ /((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;
248
+ // var REGEXP_DEFAULT_ON_TAG_ATTR_5 = /^[\s"'`]*(d\s*a\s*t\s*a\s*)\:/gi;
249
+ // var REGEXP_DEFAULT_ON_TAG_ATTR_6 = /^[\s"'`]*(d\s*a\s*t\s*a\s*)\:\s*image\//gi;
250
+ var REGEXP_DEFAULT_ON_TAG_ATTR_7 =
251
+ /e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n\s*\(.*/gi;
252
+ var REGEXP_DEFAULT_ON_TAG_ATTR_8 = /u\s*r\s*l\s*\(.*/gi;
253
+
254
+ /**
255
+ * escape double quote
256
+ *
257
+ * @param {String} str
258
+ * @return {String} str
259
+ */
260
+ function escapeQuote(str) {
261
+ return str.replace(REGEXP_QUOTE, "&quot;");
262
+ }
263
+
264
+ /**
265
+ * unescape double quote
266
+ *
267
+ * @param {String} str
268
+ * @return {String} str
269
+ */
270
+ function unescapeQuote(str) {
271
+ return str.replace(REGEXP_QUOTE_2, '"');
272
+ }
273
+
274
+ /**
275
+ * escape html entities
276
+ *
277
+ * @param {String} str
278
+ * @return {String}
279
+ */
280
+ function escapeHtmlEntities(str) {
281
+ return str.replace(REGEXP_ATTR_VALUE_1, function replaceUnicode(str, code) {
282
+ return code[0] === "x" || code[0] === "X"
283
+ ? String.fromCharCode(parseInt(code.substr(1), 16))
284
+ : String.fromCharCode(parseInt(code, 10));
285
+ });
286
+ }
287
+
288
+ /**
289
+ * escape html5 new danger entities
290
+ *
291
+ * @param {String} str
292
+ * @return {String}
293
+ */
294
+ function escapeDangerHtml5Entities(str) {
295
+ return str
296
+ .replace(REGEXP_ATTR_VALUE_COLON, ":")
297
+ .replace(REGEXP_ATTR_VALUE_NEWLINE, " ");
298
+ }
299
+
300
+ /**
301
+ * clear nonprintable characters
302
+ *
303
+ * @param {String} str
304
+ * @return {String}
305
+ */
306
+ function clearNonPrintableCharacter(str) {
307
+ var str2 = "";
308
+ for (var i = 0, len = str.length; i < len; i++) {
309
+ str2 += str.charCodeAt(i) < 32 ? " " : str.charAt(i);
310
+ }
311
+ return _.trim(str2);
312
+ }
313
+
314
+ /**
315
+ * get friendly attribute value
316
+ *
317
+ * @param {String} str
318
+ * @return {String}
319
+ */
320
+ function friendlyAttrValue(str) {
321
+ str = unescapeQuote(str);
322
+ str = escapeHtmlEntities(str);
323
+ str = escapeDangerHtml5Entities(str);
324
+ str = clearNonPrintableCharacter(str);
325
+ return str;
326
+ }
327
+
328
+ /**
329
+ * unescape attribute value
330
+ *
331
+ * @param {String} str
332
+ * @return {String}
333
+ */
334
+ function escapeAttrValue(str) {
335
+ str = escapeQuote(str);
336
+ str = escapeHtml(str);
337
+ return str;
338
+ }
339
+
340
+ /**
341
+ * `onIgnoreTag` function for removing all the tags that are not in whitelist
342
+ */
343
+ function onIgnoreTagStripAll() {
344
+ return "";
345
+ }
346
+
347
+ /**
348
+ * remove tag body
349
+ * specify a `tags` list, if the tag is not in the `tags` list then process by the specify function (optional)
350
+ *
351
+ * @param {array} tags
352
+ * @param {function} next
353
+ */
354
+ function StripTagBody(tags, next) {
355
+ if (typeof next !== "function") {
356
+ next = function () {};
357
+ }
358
+
359
+ var isRemoveAllTag = !Array.isArray(tags);
360
+ function isRemoveTag(tag) {
361
+ if (isRemoveAllTag) return true;
362
+ return _.indexOf(tags, tag) !== -1;
363
+ }
364
+
365
+ var removeList = [];
366
+ var posStart = false;
367
+
368
+ return {
369
+ onIgnoreTag: function (tag, html, options) {
370
+ if (isRemoveTag(tag)) {
371
+ if (options.isClosing) {
372
+ var ret = "[/removed]";
373
+ var end = options.position + ret.length;
374
+ removeList.push([
375
+ posStart !== false ? posStart : options.position,
376
+ end,
377
+ ]);
378
+ posStart = false;
379
+ return ret;
380
+ } else {
381
+ if (!posStart) {
382
+ posStart = options.position;
383
+ }
384
+ return "[removed]";
385
+ }
386
+ } else {
387
+ return next(tag, html, options);
388
+ }
389
+ },
390
+ remove: function (html) {
391
+ var rethtml = "";
392
+ var lastPos = 0;
393
+ _.forEach(removeList, function (pos) {
394
+ rethtml += html.slice(lastPos, pos[0]);
395
+ lastPos = pos[1];
396
+ });
397
+ rethtml += html.slice(lastPos);
398
+ return rethtml;
399
+ },
400
+ };
401
+ }
402
+
403
+ /**
404
+ * remove html comments
405
+ *
406
+ * @param {String} html
407
+ * @return {String}
408
+ */
409
+ function stripCommentTag(html) {
410
+ var retHtml = "";
411
+ var lastPos = 0;
412
+ while (lastPos < html.length) {
413
+ var i = html.indexOf("<!--", lastPos);
414
+ if (i === -1) {
415
+ retHtml += html.slice(lastPos);
416
+ break;
417
+ }
418
+ retHtml += html.slice(lastPos, i);
419
+ var j = html.indexOf("-->", i);
420
+ if (j === -1) {
421
+ break;
422
+ }
423
+ lastPos = j + 3;
424
+ }
425
+ return retHtml;
426
+ }
427
+
428
+ /**
429
+ * remove invisible characters
430
+ *
431
+ * @param {String} html
432
+ * @return {String}
433
+ */
434
+ function stripBlankChar(html) {
435
+ var chars = html.split("");
436
+ chars = chars.filter(function (char) {
437
+ var c = char.charCodeAt(0);
438
+ if (c === 127) return false;
439
+ if (c <= 31) {
440
+ if (c === 10 || c === 13) return true;
441
+ return false;
442
+ }
443
+ return true;
444
+ });
445
+ return chars.join("");
446
+ }
447
+
448
+ exports.whiteList = getDefaultWhiteList();
449
+ exports.getDefaultWhiteList = getDefaultWhiteList;
450
+ exports.onTag = onTag;
451
+ exports.onIgnoreTag = onIgnoreTag;
452
+ exports.onTagAttr = onTagAttr;
453
+ exports.onIgnoreTagAttr = onIgnoreTagAttr;
454
+ exports.safeAttrValue = safeAttrValue;
455
+ exports.escapeHtml = escapeHtml;
456
+ exports.escapeQuote = escapeQuote;
457
+ exports.unescapeQuote = unescapeQuote;
458
+ exports.escapeHtmlEntities = escapeHtmlEntities;
459
+ exports.escapeDangerHtml5Entities = escapeDangerHtml5Entities;
460
+ exports.clearNonPrintableCharacter = clearNonPrintableCharacter;
461
+ exports.friendlyAttrValue = friendlyAttrValue;
462
+ exports.escapeAttrValue = escapeAttrValue;
463
+ exports.onIgnoreTagStripAll = onIgnoreTagStripAll;
464
+ exports.StripTagBody = StripTagBody;
465
+ exports.stripCommentTag = stripCommentTag;
466
+ exports.stripBlankChar = stripBlankChar;
467
+ exports.attributeWrapSign = '"';
468
+ exports.cssFilter = defaultCSSFilter;
469
+ exports.getDefaultCSSWhiteList = getDefaultCSSWhiteList;
470
+
471
+ },{"./util":4,"cssfilter":8}],2:[function(require,module,exports){
472
+ /**
473
+ * xss
474
+ *
475
+ * @author Zongmin Lei<leizongmin@gmail.com>
476
+ */
477
+
478
+ var DEFAULT = require("./default");
479
+ var parser = require("./parser");
480
+ var FilterXSS = require("./xss");
481
+
482
+ /**
483
+ * filter xss function
484
+ *
485
+ * @param {String} html
486
+ * @param {Object} options { whiteList, onTag, onTagAttr, onIgnoreTag, onIgnoreTagAttr, safeAttrValue, escapeHtml }
487
+ * @return {String}
488
+ */
489
+ function filterXSS(html, options) {
490
+ var xss = new FilterXSS(options);
491
+ return xss.process(html);
492
+ }
493
+
494
+ /**
495
+ * Filter XSS and return both the sanitized HTML and a list of removed elements.
496
+ * Addresses feature request: https://github.com/leizongmin/js-xss/issues/284
497
+ *
498
+ * @param {String} html - dirty HTML string to sanitize
499
+ * @param {Object} options - same options as filterXSS()
500
+ * @return {Object} { html: String, removed: Array }
501
+ *
502
+ * Each item in `removed` is one of:
503
+ * { type: "tag", tag: "script", html: "<script>", isClosing: false }
504
+ * { type: "attr", tag: "a", attr: "onclick", value: "evil()" }
505
+ */
506
+ function filterXSSWithResult(html, options) {
507
+ var removed = [];
508
+
509
+ // Copy options so we don't mutate the caller's object
510
+ var opts = {};
511
+ if (options) {
512
+ for (var key in options) {
513
+ opts[key] = options[key];
514
+ }
515
+ }
516
+
517
+ // Save any hooks the user may have already provided
518
+ var originalOnIgnoreTag = opts.onIgnoreTag;
519
+ var originalOnIgnoreTagAttr = opts.onIgnoreTagAttr;
520
+
521
+ // Override onIgnoreTag to record removed tags
522
+ opts.onIgnoreTag = function (tag, tagHtml, tagOptions) {
523
+ removed.push({
524
+ type: "tag",
525
+ tag: tag,
526
+ html: tagHtml,
527
+ isClosing: !!(tagOptions && tagOptions.isClosing),
528
+ });
529
+ // Still call the user's original hook if they had one
530
+ if (originalOnIgnoreTag) {
531
+ return originalOnIgnoreTag(tag, tagHtml, tagOptions);
532
+ }
533
+ };
534
+
535
+ // Override onIgnoreTagAttr to record removed attributes
536
+ opts.onIgnoreTagAttr = function (tag, name, value, isWhiteAttr) {
537
+ removed.push({
538
+ type: "attr",
539
+ tag: tag,
540
+ attr: name,
541
+ value: value,
542
+ });
543
+ // Still call the user's original hook if they had one
544
+ if (originalOnIgnoreTagAttr) {
545
+ return originalOnIgnoreTagAttr(tag, name, value, isWhiteAttr);
546
+ }
547
+ };
548
+
549
+ var cleanHtml = filterXSS(html, opts);
550
+
551
+ return {
552
+ html: cleanHtml,
553
+ removed: removed,
554
+ };
555
+ }
556
+ exports = module.exports = filterXSS;
557
+ exports.filterXSS = filterXSS;
558
+ exports.filterXSSWithResult = filterXSSWithResult;
559
+ exports.FilterXSS = FilterXSS;
560
+
561
+ (function () {
562
+ for (var i in DEFAULT) {
563
+ if (Object.prototype.hasOwnProperty.call(DEFAULT, i)) {
564
+ exports[i] = DEFAULT[i];
565
+ }
566
+ }
567
+ for (var j in parser) {
568
+ if (Object.prototype.hasOwnProperty.call(parser, j)) {
569
+ exports[j] = parser[j];
570
+ }
571
+ }
572
+ })();
573
+
574
+ // using `xss` on the browser, output `filterXSS` to the globals
575
+ if (typeof window !== "undefined") {
576
+ window.filterXSS = module.exports;
577
+ }
578
+
579
+ // using `xss` on the WebWorker, output `filterXSS` to the globals
580
+ function isWorkerEnv() {
581
+ return (
582
+ typeof self !== "undefined" &&
583
+ typeof DedicatedWorkerGlobalScope !== "undefined" &&
584
+ self instanceof DedicatedWorkerGlobalScope
585
+ );
586
+ }
587
+ if (isWorkerEnv()) {
588
+ self.filterXSS = module.exports;
589
+ }
590
+
591
+ },{"./default":1,"./parser":3,"./xss":5}],3:[function(require,module,exports){
592
+ /**
593
+ * Simple HTML Parser
594
+ *
595
+ * @author Zongmin Lei<leizongmin@gmail.com>
596
+ */
597
+
598
+ var _ = require("./util");
599
+
600
+ /**
601
+ * get tag name
602
+ *
603
+ * @param {String} html e.g. '<a hef="#">'
604
+ * @return {String}
605
+ */
606
+ function getTagName(html) {
607
+ var i = _.spaceIndex(html);
608
+ var tagName;
609
+ if (i === -1) {
610
+ tagName = html.slice(1, -1);
611
+ } else {
612
+ tagName = html.slice(1, i + 1);
613
+ }
614
+ tagName = _.trim(tagName).toLowerCase();
615
+ if (tagName.slice(0, 1) === "/") tagName = tagName.slice(1);
616
+ if (tagName.slice(-1) === "/") tagName = tagName.slice(0, -1);
617
+ return tagName;
618
+ }
619
+
620
+ /**
621
+ * is close tag?
622
+ *
623
+ * @param {String} html 如:'<a hef="#">'
624
+ * @return {Boolean}
625
+ */
626
+ function isClosing(html) {
627
+ return html.slice(0, 2) === "</";
628
+ }
629
+
630
+ /**
631
+ * parse input html and returns processed html
632
+ *
633
+ * @param {String} html
634
+ * @param {Function} onTag e.g. function (sourcePosition, position, tag, html, isClosing)
635
+ * @param {Function} escapeHtml
636
+ * @return {String}
637
+ */
638
+ function parseTag(html, onTag, escapeHtml) {
639
+ "use strict";
640
+
641
+ var rethtml = "";
642
+ var lastPos = 0;
643
+ var tagStart = false;
644
+ var quoteStart = false;
645
+ var currentPos = 0;
646
+ var len = html.length;
647
+ var currentTagName = "";
648
+ var currentHtml = "";
649
+
650
+ chariterator: for (currentPos = 0; currentPos < len; currentPos++) {
651
+ var c = html.charAt(currentPos);
652
+ if (tagStart === false) {
653
+ if (c === "<") {
654
+ tagStart = currentPos;
655
+ continue;
656
+ }
657
+ } else {
658
+ if (quoteStart === false) {
659
+ if (c === "<") {
660
+ rethtml += escapeHtml(html.slice(lastPos, currentPos));
661
+ tagStart = currentPos;
662
+ lastPos = currentPos;
663
+ continue;
664
+ }
665
+ if (c === ">" || currentPos === len - 1) {
666
+ rethtml += escapeHtml(html.slice(lastPos, tagStart));
667
+ currentHtml = html.slice(tagStart, currentPos + 1);
668
+ currentTagName = getTagName(currentHtml);
669
+ rethtml += onTag(
670
+ tagStart,
671
+ rethtml.length,
672
+ currentTagName,
673
+ currentHtml,
674
+ isClosing(currentHtml)
675
+ );
676
+ lastPos = currentPos + 1;
677
+ tagStart = false;
678
+ continue;
679
+ }
680
+ if (c === '"' || c === "'") {
681
+ var i = 1;
682
+ var ic = html.charAt(currentPos - i);
683
+
684
+ while (ic.trim() === "" || ic === "=") {
685
+ if (ic === "=") {
686
+ quoteStart = c;
687
+ continue chariterator;
688
+ }
689
+ ic = html.charAt(currentPos - ++i);
690
+ }
691
+ }
692
+ } else {
693
+ if (c === quoteStart) {
694
+ quoteStart = false;
695
+ continue;
696
+ }
697
+ }
698
+ }
699
+ }
700
+ if (lastPos < len) {
701
+ rethtml += escapeHtml(html.substr(lastPos));
702
+ }
703
+
704
+ return rethtml;
705
+ }
706
+
707
+ var REGEXP_ILLEGAL_ATTR_NAME = /[^a-zA-Z0-9\\_:.-]/gim;
708
+
709
+ /**
710
+ * parse input attributes and returns processed attributes
711
+ *
712
+ * @param {String} html e.g. `href="#" target="_blank"`
713
+ * @param {Function} onAttr e.g. `function (name, value)`
714
+ * @return {String}
715
+ */
716
+ function parseAttr(html, onAttr) {
717
+ "use strict";
718
+
719
+ var lastPos = 0;
720
+ var lastMarkPos = 0;
721
+ var retAttrs = [];
722
+ var tmpName = false;
723
+ var len = html.length;
724
+
725
+ function addAttr(name, value) {
726
+ name = _.trim(name);
727
+ name = name.replace(REGEXP_ILLEGAL_ATTR_NAME, "").toLowerCase();
728
+ if (name.length < 1) return;
729
+ var ret = onAttr(name, value || "");
730
+ if (ret) retAttrs.push(ret);
731
+ }
732
+
733
+ // 逐个分析字符
734
+ for (var i = 0; i < len; i++) {
735
+ var c = html.charAt(i);
736
+ var v, j;
737
+ if (tmpName === false && c === "=") {
738
+ tmpName = html.slice(lastPos, i);
739
+ lastPos = i + 1;
740
+ lastMarkPos = html.charAt(lastPos) === '"' || html.charAt(lastPos) === "'" ? lastPos : findNextQuotationMark(html, i + 1);
741
+ continue;
742
+ }
743
+ if (tmpName !== false) {
744
+ if (
745
+ i === lastMarkPos
746
+ ) {
747
+ j = html.indexOf(c, i + 1);
748
+ if (j === -1) {
749
+ break;
750
+ } else {
751
+ v = _.trim(html.slice(lastMarkPos + 1, j));
752
+ addAttr(tmpName, v);
753
+ tmpName = false;
754
+ i = j;
755
+ lastPos = i + 1;
756
+ continue;
757
+ }
758
+ }
759
+ }
760
+ if (/\s|\n|\t/.test(c)) {
761
+ html = html.replace(/\s|\n|\t/g, " ");
762
+ if (tmpName === false) {
763
+ j = findNextEqual(html, i);
764
+ if (j === -1) {
765
+ v = _.trim(html.slice(lastPos, i));
766
+ addAttr(v);
767
+ tmpName = false;
768
+ lastPos = i + 1;
769
+ continue;
770
+ } else {
771
+ i = j - 1;
772
+ continue;
773
+ }
774
+ } else {
775
+ j = findBeforeEqual(html, i - 1);
776
+ if (j === -1) {
777
+ v = _.trim(html.slice(lastPos, i));
778
+ v = stripQuoteWrap(v);
779
+ addAttr(tmpName, v);
780
+ tmpName = false;
781
+ lastPos = i + 1;
782
+ continue;
783
+ } else {
784
+ continue;
785
+ }
786
+ }
787
+ }
788
+ }
789
+
790
+ if (lastPos < html.length) {
791
+ if (tmpName === false) {
792
+ addAttr(html.slice(lastPos));
793
+ } else {
794
+ addAttr(tmpName, stripQuoteWrap(_.trim(html.slice(lastPos))));
795
+ }
796
+ }
797
+
798
+ return _.trim(retAttrs.join(" "));
799
+ }
800
+
801
+ function findNextEqual(str, i) {
802
+ for (; i < str.length; i++) {
803
+ var c = str[i];
804
+ if (c === " ") continue;
805
+ if (c === "=") return i;
806
+ return -1;
807
+ }
808
+ }
809
+
810
+ function findNextQuotationMark(str, i) {
811
+ for (; i < str.length; i++) {
812
+ var c = str[i];
813
+ if (c === " ") continue;
814
+ if (c === "'" || c === '"') return i;
815
+ return -1;
816
+ }
817
+ }
818
+
819
+ function findBeforeEqual(str, i) {
820
+ for (; i > 0; i--) {
821
+ var c = str[i];
822
+ if (c === " ") continue;
823
+ if (c === "=") return i;
824
+ return -1;
825
+ }
826
+ }
827
+
828
+ function isQuoteWrapString(text) {
829
+ if (
830
+ (text[0] === '"' && text[text.length - 1] === '"') ||
831
+ (text[0] === "'" && text[text.length - 1] === "'")
832
+ ) {
833
+ return true;
834
+ } else {
835
+ return false;
836
+ }
837
+ }
838
+
839
+ function stripQuoteWrap(text) {
840
+ if (isQuoteWrapString(text)) {
841
+ return text.substr(1, text.length - 2);
842
+ } else {
843
+ return text;
844
+ }
845
+ }
846
+
847
+ exports.parseTag = parseTag;
848
+ exports.parseAttr = parseAttr;
849
+
850
+ },{"./util":4}],4:[function(require,module,exports){
851
+ module.exports = {
852
+ indexOf: function (arr, item) {
853
+ var i, j;
854
+ if (Array.prototype.indexOf) {
855
+ return arr.indexOf(item);
856
+ }
857
+ for (i = 0, j = arr.length; i < j; i++) {
858
+ if (arr[i] === item) {
859
+ return i;
860
+ }
861
+ }
862
+ return -1;
863
+ },
864
+ forEach: function (arr, fn, scope) {
865
+ var i, j;
866
+ if (Array.prototype.forEach) {
867
+ return arr.forEach(fn, scope);
868
+ }
869
+ for (i = 0, j = arr.length; i < j; i++) {
870
+ fn.call(scope, arr[i], i, arr);
871
+ }
872
+ },
873
+ trim: function (str) {
874
+ if (String.prototype.trim) {
875
+ return str.trim();
876
+ }
877
+ return str.replace(/(^\s*)|(\s*$)/g, "");
878
+ },
879
+ spaceIndex: function (str) {
880
+ var reg = /\s|\n|\t/;
881
+ var match = reg.exec(str);
882
+ return match ? match.index : -1;
883
+ },
884
+ };
885
+
886
+ },{}],5:[function(require,module,exports){
887
+ /**
888
+ * filter xss
889
+ *
890
+ * @author Zongmin Lei<leizongmin@gmail.com>
891
+ */
892
+
893
+ var FilterCSS = require("cssfilter").FilterCSS;
894
+ var DEFAULT = require("./default");
895
+ var parser = require("./parser");
896
+ var parseTag = parser.parseTag;
897
+ var parseAttr = parser.parseAttr;
898
+ var _ = require("./util");
899
+
900
+ /**
901
+ * returns `true` if the input value is `undefined` or `null`
902
+ *
903
+ * @param {Object} obj
904
+ * @return {Boolean}
905
+ */
906
+ function isNull(obj) {
907
+ return obj === undefined || obj === null;
908
+ }
909
+
910
+ /**
911
+ * get attributes for a tag
912
+ *
913
+ * @param {String} html
914
+ * @return {Object}
915
+ * - {String} html
916
+ * - {Boolean} closing
917
+ */
918
+ function getAttrs(html) {
919
+ var i = _.spaceIndex(html);
920
+ if (i === -1) {
921
+ return {
922
+ html: "",
923
+ closing: html[html.length - 2] === "/",
924
+ };
925
+ }
926
+ html = _.trim(html.slice(i + 1, -1));
927
+ var isClosing = html[html.length - 1] === "/";
928
+ if (isClosing) html = _.trim(html.slice(0, -1));
929
+ return {
930
+ html: html,
931
+ closing: isClosing,
932
+ };
933
+ }
934
+
935
+ /**
936
+ * shallow copy
937
+ *
938
+ * @param {Object} obj
939
+ * @return {Object}
940
+ */
941
+ function shallowCopyObject(obj) {
942
+ var ret = {};
943
+ for (var i in obj) {
944
+ if (Object.prototype.hasOwnProperty.call(obj, i)) {
945
+ ret[i] = obj[i];
946
+ }
947
+ }
948
+ return ret;
949
+ }
950
+
951
+ function keysToLowerCase(obj) {
952
+ var ret = {};
953
+ for (var i in obj) {
954
+ if (Object.prototype.hasOwnProperty.call(obj, i)) {
955
+ if (Array.isArray(obj[i])) {
956
+ ret[i.toLowerCase()] = obj[i].map(function (item) {
957
+ return item.toLowerCase();
958
+ });
959
+ } else {
960
+ ret[i.toLowerCase()] = obj[i];
961
+ }
962
+ }
963
+ }
964
+ return ret;
965
+ }
966
+
967
+ /**
968
+ * FilterXSS class
969
+ *
970
+ * @param {Object} options
971
+ * whiteList (or allowList), onTag, onTagAttr, onIgnoreTag,
972
+ * onIgnoreTagAttr, safeAttrValue, escapeHtml
973
+ * stripIgnoreTagBody, allowCommentTag, stripBlankChar
974
+ * css{whiteList, onAttr, onIgnoreAttr} `css=false` means don't use `cssfilter`
975
+ */
976
+ function FilterXSS(options) {
977
+ options = shallowCopyObject(options || {});
978
+
979
+ if (Object.prototype.hasOwnProperty.call(options, 'stripIgnoreTag') && options.stripIgnoreTag) {
980
+ if (Object.prototype.hasOwnProperty.call(options, 'onIgnoreTag') && options.onIgnoreTag) {
981
+ console.error(
982
+ 'Notes: cannot use these two options "stripIgnoreTag" and "onIgnoreTag" at the same time'
983
+ );
984
+ }
985
+ options.onIgnoreTag = DEFAULT.onIgnoreTagStripAll;
986
+ }
987
+ if (Object.prototype.hasOwnProperty.call(options, 'whiteList') || Object.prototype.hasOwnProperty.call(options, 'allowList')) {
988
+ const wl = Object.prototype.hasOwnProperty.call(options, 'whiteList') ? options.whiteList : options.allowList;
989
+ options.whiteList = keysToLowerCase(wl);
990
+ } else {
991
+ options.whiteList = DEFAULT.whiteList;
992
+ }
993
+
994
+ this.attributeWrapSign = Object.prototype.hasOwnProperty.call(options, 'singleQuotedAttributeValue') && options.singleQuotedAttributeValue === true ? "'" : DEFAULT.attributeWrapSign;
995
+
996
+ options.onTag = Object.prototype.hasOwnProperty.call(options, 'onTag') ? options.onTag : DEFAULT.onTag;
997
+ options.onTagAttr = Object.prototype.hasOwnProperty.call(options, 'onTagAttr') ? options.onTagAttr : DEFAULT.onTagAttr;
998
+ options.onIgnoreTag = Object.prototype.hasOwnProperty.call(options, 'onIgnoreTag') ? options.onIgnoreTag : DEFAULT.onIgnoreTag;
999
+ options.onIgnoreTagAttr = Object.prototype.hasOwnProperty.call(options, 'onIgnoreTagAttr') ? options.onIgnoreTagAttr : DEFAULT.onIgnoreTagAttr;
1000
+ options.safeAttrValue = Object.prototype.hasOwnProperty.call(options, 'safeAttrValue') ? options.safeAttrValue : DEFAULT.safeAttrValue;
1001
+ options.escapeHtml = Object.prototype.hasOwnProperty.call(options, 'escapeHtml') ? options.escapeHtml : DEFAULT.escapeHtml;
1002
+ this.options = options;
1003
+
1004
+ if (Object.prototype.hasOwnProperty.call(options, 'css') && options.css === false) {
1005
+ this.cssFilter = false;
1006
+ } else {
1007
+ options.css = Object.prototype.hasOwnProperty.call(options, 'css') ? options.css : {};
1008
+ this.cssFilter = new FilterCSS(options.css);
1009
+ }
1010
+ }
1011
+
1012
+ /**
1013
+ * start process and returns result
1014
+ *
1015
+ * @param {String} html
1016
+ * @return {String}
1017
+ */
1018
+ FilterXSS.prototype.process = function (html) {
1019
+ // compatible with the input
1020
+ html = html || "";
1021
+ html = html.toString();
1022
+ if (!html) return "";
1023
+
1024
+ var me = this;
1025
+ var options = me.options;
1026
+ var whiteList = options.whiteList;
1027
+ var onTag = options.onTag;
1028
+ var onIgnoreTag = options.onIgnoreTag;
1029
+ var onTagAttr = options.onTagAttr;
1030
+ var onIgnoreTagAttr = options.onIgnoreTagAttr;
1031
+ var safeAttrValue = options.safeAttrValue;
1032
+ var escapeHtml = options.escapeHtml;
1033
+ var attributeWrapSign = me.attributeWrapSign;
1034
+ var cssFilter = me.cssFilter;
1035
+
1036
+ // remove invisible characters
1037
+ if (options.stripBlankChar) {
1038
+ html = DEFAULT.stripBlankChar(html);
1039
+ }
1040
+
1041
+ // remove html comments
1042
+ if (!options.allowCommentTag) {
1043
+ html = DEFAULT.stripCommentTag(html);
1044
+ }
1045
+
1046
+ // if enable stripIgnoreTagBody
1047
+ var stripIgnoreTagBody = false;
1048
+ if (options.stripIgnoreTagBody) {
1049
+ stripIgnoreTagBody = DEFAULT.StripTagBody(
1050
+ options.stripIgnoreTagBody,
1051
+ onIgnoreTag
1052
+ );
1053
+ onIgnoreTag = stripIgnoreTagBody.onIgnoreTag;
1054
+ }
1055
+
1056
+ var retHtml = parseTag(
1057
+ html,
1058
+ function (sourcePosition, position, tag, html, isClosing) {
1059
+ var info = {
1060
+ sourcePosition: sourcePosition,
1061
+ position: position,
1062
+ isClosing: isClosing,
1063
+ isWhite: Object.prototype.hasOwnProperty.call(whiteList, tag),
1064
+ };
1065
+
1066
+ // call `onTag()`
1067
+ var ret = onTag(tag, html, info);
1068
+ if (!isNull(ret)) return ret;
1069
+
1070
+ if (info.isWhite) {
1071
+ if (info.isClosing) {
1072
+ return "</" + tag + ">";
1073
+ }
1074
+
1075
+ var attrs = getAttrs(html);
1076
+ var whiteAttrList = whiteList[tag];
1077
+ var attrsHtml = parseAttr(attrs.html, function (name, value) {
1078
+ // call `onTagAttr()`
1079
+ var isWhiteAttr = _.indexOf(whiteAttrList, name) !== -1;
1080
+ var ret = onTagAttr(tag, name, value, isWhiteAttr);
1081
+ if (!isNull(ret)) return ret;
1082
+
1083
+ if (isWhiteAttr) {
1084
+ // call `safeAttrValue()`
1085
+ value = safeAttrValue(tag, name, value, cssFilter);
1086
+ if (value) {
1087
+ return name + '=' + attributeWrapSign + value + attributeWrapSign;
1088
+ } else {
1089
+ return name;
1090
+ }
1091
+ } else {
1092
+ // call `onIgnoreTagAttr()`
1093
+ ret = onIgnoreTagAttr(tag, name, value, isWhiteAttr);
1094
+ if (!isNull(ret)) return ret;
1095
+ return;
1096
+ }
1097
+ });
1098
+
1099
+ // build new tag html
1100
+ html = "<" + tag;
1101
+ if (attrsHtml) html += " " + attrsHtml;
1102
+ if (attrs.closing) html += " /";
1103
+ html += ">";
1104
+ return html;
1105
+ } else {
1106
+ // call `onIgnoreTag()`
1107
+ ret = onIgnoreTag(tag, html, info);
1108
+ if (!isNull(ret)) return ret;
1109
+ return escapeHtml(html);
1110
+ }
1111
+ },
1112
+ escapeHtml
1113
+ );
1114
+
1115
+ // if enable stripIgnoreTagBody
1116
+ if (stripIgnoreTagBody) {
1117
+ retHtml = stripIgnoreTagBody.remove(retHtml);
1118
+ }
1119
+
1120
+ return retHtml;
1121
+ };
1122
+
1123
+ module.exports = FilterXSS;
1124
+
1125
+ },{"./default":1,"./parser":3,"./util":4,"cssfilter":8}],6:[function(require,module,exports){
1126
+ /**
1127
+ * cssfilter
1128
+ *
1129
+ * @author 老雷<leizongmin@gmail.com>
1130
+ */
1131
+
1132
+ var DEFAULT = require('./default');
1133
+ var parseStyle = require('./parser');
1134
+ var _ = require('./util');
1135
+
1136
+
1137
+ /**
1138
+ * 返回值是否为空
1139
+ *
1140
+ * @param {Object} obj
1141
+ * @return {Boolean}
1142
+ */
1143
+ function isNull (obj) {
1144
+ return (obj === undefined || obj === null);
1145
+ }
1146
+
1147
+ /**
1148
+ * 浅拷贝对象
1149
+ *
1150
+ * @param {Object} obj
1151
+ * @return {Object}
1152
+ */
1153
+ function shallowCopyObject (obj) {
1154
+ var ret = {};
1155
+ for (var i in obj) {
1156
+ ret[i] = obj[i];
1157
+ }
1158
+ return ret;
1159
+ }
1160
+
1161
+ /**
1162
+ * 创建CSS过滤器
1163
+ *
1164
+ * @param {Object} options
1165
+ * - {Object} whiteList
1166
+ * - {Function} onAttr
1167
+ * - {Function} onIgnoreAttr
1168
+ * - {Function} safeAttrValue
1169
+ */
1170
+ function FilterCSS (options) {
1171
+ options = shallowCopyObject(options || {});
1172
+ options.whiteList = options.whiteList || DEFAULT.whiteList;
1173
+ options.onAttr = options.onAttr || DEFAULT.onAttr;
1174
+ options.onIgnoreAttr = options.onIgnoreAttr || DEFAULT.onIgnoreAttr;
1175
+ options.safeAttrValue = options.safeAttrValue || DEFAULT.safeAttrValue;
1176
+ this.options = options;
1177
+ }
1178
+
1179
+ FilterCSS.prototype.process = function (css) {
1180
+ // 兼容各种奇葩输入
1181
+ css = css || '';
1182
+ css = css.toString();
1183
+ if (!css) return '';
1184
+
1185
+ var me = this;
1186
+ var options = me.options;
1187
+ var whiteList = options.whiteList;
1188
+ var onAttr = options.onAttr;
1189
+ var onIgnoreAttr = options.onIgnoreAttr;
1190
+ var safeAttrValue = options.safeAttrValue;
1191
+
1192
+ var retCSS = parseStyle(css, function (sourcePosition, position, name, value, source) {
1193
+
1194
+ var check = whiteList[name];
1195
+ var isWhite = false;
1196
+ if (check === true) isWhite = check;
1197
+ else if (typeof check === 'function') isWhite = check(value);
1198
+ else if (check instanceof RegExp) isWhite = check.test(value);
1199
+ if (isWhite !== true) isWhite = false;
1200
+
1201
+ // 如果过滤后 value 为空则直接忽略
1202
+ value = safeAttrValue(name, value);
1203
+ if (!value) return;
1204
+
1205
+ var opts = {
1206
+ position: position,
1207
+ sourcePosition: sourcePosition,
1208
+ source: source,
1209
+ isWhite: isWhite
1210
+ };
1211
+
1212
+ if (isWhite) {
1213
+
1214
+ var ret = onAttr(name, value, opts);
1215
+ if (isNull(ret)) {
1216
+ return name + ':' + value;
1217
+ } else {
1218
+ return ret;
1219
+ }
1220
+
1221
+ } else {
1222
+
1223
+ var ret = onIgnoreAttr(name, value, opts);
1224
+ if (!isNull(ret)) {
1225
+ return ret;
1226
+ }
1227
+
1228
+ }
1229
+ });
1230
+
1231
+ return retCSS;
1232
+ };
1233
+
1234
+
1235
+ module.exports = FilterCSS;
1236
+
1237
+ },{"./default":7,"./parser":9,"./util":10}],7:[function(require,module,exports){
1238
+ /**
1239
+ * cssfilter
1240
+ *
1241
+ * @author 老雷<leizongmin@gmail.com>
1242
+ */
1243
+
1244
+ function getDefaultWhiteList () {
1245
+ // 白名单值说明:
1246
+ // true: 允许该属性
1247
+ // Function: function (val) { } 返回true表示允许该属性,其他值均表示不允许
1248
+ // RegExp: regexp.test(val) 返回true表示允许该属性,其他值均表示不允许
1249
+ // 除上面列出的值外均表示不允许
1250
+ var whiteList = {};
1251
+
1252
+ whiteList['align-content'] = false; // default: auto
1253
+ whiteList['align-items'] = false; // default: auto
1254
+ whiteList['align-self'] = false; // default: auto
1255
+ whiteList['alignment-adjust'] = false; // default: auto
1256
+ whiteList['alignment-baseline'] = false; // default: baseline
1257
+ whiteList['all'] = false; // default: depending on individual properties
1258
+ whiteList['anchor-point'] = false; // default: none
1259
+ whiteList['animation'] = false; // default: depending on individual properties
1260
+ whiteList['animation-delay'] = false; // default: 0
1261
+ whiteList['animation-direction'] = false; // default: normal
1262
+ whiteList['animation-duration'] = false; // default: 0
1263
+ whiteList['animation-fill-mode'] = false; // default: none
1264
+ whiteList['animation-iteration-count'] = false; // default: 1
1265
+ whiteList['animation-name'] = false; // default: none
1266
+ whiteList['animation-play-state'] = false; // default: running
1267
+ whiteList['animation-timing-function'] = false; // default: ease
1268
+ whiteList['azimuth'] = false; // default: center
1269
+ whiteList['backface-visibility'] = false; // default: visible
1270
+ whiteList['background'] = true; // default: depending on individual properties
1271
+ whiteList['background-attachment'] = true; // default: scroll
1272
+ whiteList['background-clip'] = true; // default: border-box
1273
+ whiteList['background-color'] = true; // default: transparent
1274
+ whiteList['background-image'] = true; // default: none
1275
+ whiteList['background-origin'] = true; // default: padding-box
1276
+ whiteList['background-position'] = true; // default: 0% 0%
1277
+ whiteList['background-repeat'] = true; // default: repeat
1278
+ whiteList['background-size'] = true; // default: auto
1279
+ whiteList['baseline-shift'] = false; // default: baseline
1280
+ whiteList['binding'] = false; // default: none
1281
+ whiteList['bleed'] = false; // default: 6pt
1282
+ whiteList['bookmark-label'] = false; // default: content()
1283
+ whiteList['bookmark-level'] = false; // default: none
1284
+ whiteList['bookmark-state'] = false; // default: open
1285
+ whiteList['border'] = true; // default: depending on individual properties
1286
+ whiteList['border-bottom'] = true; // default: depending on individual properties
1287
+ whiteList['border-bottom-color'] = true; // default: current color
1288
+ whiteList['border-bottom-left-radius'] = true; // default: 0
1289
+ whiteList['border-bottom-right-radius'] = true; // default: 0
1290
+ whiteList['border-bottom-style'] = true; // default: none
1291
+ whiteList['border-bottom-width'] = true; // default: medium
1292
+ whiteList['border-collapse'] = true; // default: separate
1293
+ whiteList['border-color'] = true; // default: depending on individual properties
1294
+ whiteList['border-image'] = true; // default: none
1295
+ whiteList['border-image-outset'] = true; // default: 0
1296
+ whiteList['border-image-repeat'] = true; // default: stretch
1297
+ whiteList['border-image-slice'] = true; // default: 100%
1298
+ whiteList['border-image-source'] = true; // default: none
1299
+ whiteList['border-image-width'] = true; // default: 1
1300
+ whiteList['border-left'] = true; // default: depending on individual properties
1301
+ whiteList['border-left-color'] = true; // default: current color
1302
+ whiteList['border-left-style'] = true; // default: none
1303
+ whiteList['border-left-width'] = true; // default: medium
1304
+ whiteList['border-radius'] = true; // default: 0
1305
+ whiteList['border-right'] = true; // default: depending on individual properties
1306
+ whiteList['border-right-color'] = true; // default: current color
1307
+ whiteList['border-right-style'] = true; // default: none
1308
+ whiteList['border-right-width'] = true; // default: medium
1309
+ whiteList['border-spacing'] = true; // default: 0
1310
+ whiteList['border-style'] = true; // default: depending on individual properties
1311
+ whiteList['border-top'] = true; // default: depending on individual properties
1312
+ whiteList['border-top-color'] = true; // default: current color
1313
+ whiteList['border-top-left-radius'] = true; // default: 0
1314
+ whiteList['border-top-right-radius'] = true; // default: 0
1315
+ whiteList['border-top-style'] = true; // default: none
1316
+ whiteList['border-top-width'] = true; // default: medium
1317
+ whiteList['border-width'] = true; // default: depending on individual properties
1318
+ whiteList['bottom'] = false; // default: auto
1319
+ whiteList['box-decoration-break'] = true; // default: slice
1320
+ whiteList['box-shadow'] = true; // default: none
1321
+ whiteList['box-sizing'] = true; // default: content-box
1322
+ whiteList['box-snap'] = true; // default: none
1323
+ whiteList['box-suppress'] = true; // default: show
1324
+ whiteList['break-after'] = true; // default: auto
1325
+ whiteList['break-before'] = true; // default: auto
1326
+ whiteList['break-inside'] = true; // default: auto
1327
+ whiteList['caption-side'] = false; // default: top
1328
+ whiteList['chains'] = false; // default: none
1329
+ whiteList['clear'] = true; // default: none
1330
+ whiteList['clip'] = false; // default: auto
1331
+ whiteList['clip-path'] = false; // default: none
1332
+ whiteList['clip-rule'] = false; // default: nonzero
1333
+ whiteList['color'] = true; // default: implementation dependent
1334
+ whiteList['color-interpolation-filters'] = true; // default: auto
1335
+ whiteList['column-count'] = false; // default: auto
1336
+ whiteList['column-fill'] = false; // default: balance
1337
+ whiteList['column-gap'] = false; // default: normal
1338
+ whiteList['column-rule'] = false; // default: depending on individual properties
1339
+ whiteList['column-rule-color'] = false; // default: current color
1340
+ whiteList['column-rule-style'] = false; // default: medium
1341
+ whiteList['column-rule-width'] = false; // default: medium
1342
+ whiteList['column-span'] = false; // default: none
1343
+ whiteList['column-width'] = false; // default: auto
1344
+ whiteList['columns'] = false; // default: depending on individual properties
1345
+ whiteList['contain'] = false; // default: none
1346
+ whiteList['content'] = false; // default: normal
1347
+ whiteList['counter-increment'] = false; // default: none
1348
+ whiteList['counter-reset'] = false; // default: none
1349
+ whiteList['counter-set'] = false; // default: none
1350
+ whiteList['crop'] = false; // default: auto
1351
+ whiteList['cue'] = false; // default: depending on individual properties
1352
+ whiteList['cue-after'] = false; // default: none
1353
+ whiteList['cue-before'] = false; // default: none
1354
+ whiteList['cursor'] = false; // default: auto
1355
+ whiteList['direction'] = false; // default: ltr
1356
+ whiteList['display'] = true; // default: depending on individual properties
1357
+ whiteList['display-inside'] = true; // default: auto
1358
+ whiteList['display-list'] = true; // default: none
1359
+ whiteList['display-outside'] = true; // default: inline-level
1360
+ whiteList['dominant-baseline'] = false; // default: auto
1361
+ whiteList['elevation'] = false; // default: level
1362
+ whiteList['empty-cells'] = false; // default: show
1363
+ whiteList['filter'] = false; // default: none
1364
+ whiteList['flex'] = false; // default: depending on individual properties
1365
+ whiteList['flex-basis'] = false; // default: auto
1366
+ whiteList['flex-direction'] = false; // default: row
1367
+ whiteList['flex-flow'] = false; // default: depending on individual properties
1368
+ whiteList['flex-grow'] = false; // default: 0
1369
+ whiteList['flex-shrink'] = false; // default: 1
1370
+ whiteList['flex-wrap'] = false; // default: nowrap
1371
+ whiteList['float'] = false; // default: none
1372
+ whiteList['float-offset'] = false; // default: 0 0
1373
+ whiteList['flood-color'] = false; // default: black
1374
+ whiteList['flood-opacity'] = false; // default: 1
1375
+ whiteList['flow-from'] = false; // default: none
1376
+ whiteList['flow-into'] = false; // default: none
1377
+ whiteList['font'] = true; // default: depending on individual properties
1378
+ whiteList['font-family'] = true; // default: implementation dependent
1379
+ whiteList['font-feature-settings'] = true; // default: normal
1380
+ whiteList['font-kerning'] = true; // default: auto
1381
+ whiteList['font-language-override'] = true; // default: normal
1382
+ whiteList['font-size'] = true; // default: medium
1383
+ whiteList['font-size-adjust'] = true; // default: none
1384
+ whiteList['font-stretch'] = true; // default: normal
1385
+ whiteList['font-style'] = true; // default: normal
1386
+ whiteList['font-synthesis'] = true; // default: weight style
1387
+ whiteList['font-variant'] = true; // default: normal
1388
+ whiteList['font-variant-alternates'] = true; // default: normal
1389
+ whiteList['font-variant-caps'] = true; // default: normal
1390
+ whiteList['font-variant-east-asian'] = true; // default: normal
1391
+ whiteList['font-variant-ligatures'] = true; // default: normal
1392
+ whiteList['font-variant-numeric'] = true; // default: normal
1393
+ whiteList['font-variant-position'] = true; // default: normal
1394
+ whiteList['font-weight'] = true; // default: normal
1395
+ whiteList['grid'] = false; // default: depending on individual properties
1396
+ whiteList['grid-area'] = false; // default: depending on individual properties
1397
+ whiteList['grid-auto-columns'] = false; // default: auto
1398
+ whiteList['grid-auto-flow'] = false; // default: none
1399
+ whiteList['grid-auto-rows'] = false; // default: auto
1400
+ whiteList['grid-column'] = false; // default: depending on individual properties
1401
+ whiteList['grid-column-end'] = false; // default: auto
1402
+ whiteList['grid-column-start'] = false; // default: auto
1403
+ whiteList['grid-row'] = false; // default: depending on individual properties
1404
+ whiteList['grid-row-end'] = false; // default: auto
1405
+ whiteList['grid-row-start'] = false; // default: auto
1406
+ whiteList['grid-template'] = false; // default: depending on individual properties
1407
+ whiteList['grid-template-areas'] = false; // default: none
1408
+ whiteList['grid-template-columns'] = false; // default: none
1409
+ whiteList['grid-template-rows'] = false; // default: none
1410
+ whiteList['hanging-punctuation'] = false; // default: none
1411
+ whiteList['height'] = true; // default: auto
1412
+ whiteList['hyphens'] = false; // default: manual
1413
+ whiteList['icon'] = false; // default: auto
1414
+ whiteList['image-orientation'] = false; // default: auto
1415
+ whiteList['image-resolution'] = false; // default: normal
1416
+ whiteList['ime-mode'] = false; // default: auto
1417
+ whiteList['initial-letters'] = false; // default: normal
1418
+ whiteList['inline-box-align'] = false; // default: last
1419
+ whiteList['justify-content'] = false; // default: auto
1420
+ whiteList['justify-items'] = false; // default: auto
1421
+ whiteList['justify-self'] = false; // default: auto
1422
+ whiteList['left'] = false; // default: auto
1423
+ whiteList['letter-spacing'] = true; // default: normal
1424
+ whiteList['lighting-color'] = true; // default: white
1425
+ whiteList['line-box-contain'] = false; // default: block inline replaced
1426
+ whiteList['line-break'] = false; // default: auto
1427
+ whiteList['line-grid'] = false; // default: match-parent
1428
+ whiteList['line-height'] = false; // default: normal
1429
+ whiteList['line-snap'] = false; // default: none
1430
+ whiteList['line-stacking'] = false; // default: depending on individual properties
1431
+ whiteList['line-stacking-ruby'] = false; // default: exclude-ruby
1432
+ whiteList['line-stacking-shift'] = false; // default: consider-shifts
1433
+ whiteList['line-stacking-strategy'] = false; // default: inline-line-height
1434
+ whiteList['list-style'] = true; // default: depending on individual properties
1435
+ whiteList['list-style-image'] = true; // default: none
1436
+ whiteList['list-style-position'] = true; // default: outside
1437
+ whiteList['list-style-type'] = true; // default: disc
1438
+ whiteList['margin'] = true; // default: depending on individual properties
1439
+ whiteList['margin-bottom'] = true; // default: 0
1440
+ whiteList['margin-left'] = true; // default: 0
1441
+ whiteList['margin-right'] = true; // default: 0
1442
+ whiteList['margin-top'] = true; // default: 0
1443
+ whiteList['marker-offset'] = false; // default: auto
1444
+ whiteList['marker-side'] = false; // default: list-item
1445
+ whiteList['marks'] = false; // default: none
1446
+ whiteList['mask'] = false; // default: border-box
1447
+ whiteList['mask-box'] = false; // default: see individual properties
1448
+ whiteList['mask-box-outset'] = false; // default: 0
1449
+ whiteList['mask-box-repeat'] = false; // default: stretch
1450
+ whiteList['mask-box-slice'] = false; // default: 0 fill
1451
+ whiteList['mask-box-source'] = false; // default: none
1452
+ whiteList['mask-box-width'] = false; // default: auto
1453
+ whiteList['mask-clip'] = false; // default: border-box
1454
+ whiteList['mask-image'] = false; // default: none
1455
+ whiteList['mask-origin'] = false; // default: border-box
1456
+ whiteList['mask-position'] = false; // default: center
1457
+ whiteList['mask-repeat'] = false; // default: no-repeat
1458
+ whiteList['mask-size'] = false; // default: border-box
1459
+ whiteList['mask-source-type'] = false; // default: auto
1460
+ whiteList['mask-type'] = false; // default: luminance
1461
+ whiteList['max-height'] = true; // default: none
1462
+ whiteList['max-lines'] = false; // default: none
1463
+ whiteList['max-width'] = true; // default: none
1464
+ whiteList['min-height'] = true; // default: 0
1465
+ whiteList['min-width'] = true; // default: 0
1466
+ whiteList['move-to'] = false; // default: normal
1467
+ whiteList['nav-down'] = false; // default: auto
1468
+ whiteList['nav-index'] = false; // default: auto
1469
+ whiteList['nav-left'] = false; // default: auto
1470
+ whiteList['nav-right'] = false; // default: auto
1471
+ whiteList['nav-up'] = false; // default: auto
1472
+ whiteList['object-fit'] = false; // default: fill
1473
+ whiteList['object-position'] = false; // default: 50% 50%
1474
+ whiteList['opacity'] = false; // default: 1
1475
+ whiteList['order'] = false; // default: 0
1476
+ whiteList['orphans'] = false; // default: 2
1477
+ whiteList['outline'] = false; // default: depending on individual properties
1478
+ whiteList['outline-color'] = false; // default: invert
1479
+ whiteList['outline-offset'] = false; // default: 0
1480
+ whiteList['outline-style'] = false; // default: none
1481
+ whiteList['outline-width'] = false; // default: medium
1482
+ whiteList['overflow'] = false; // default: depending on individual properties
1483
+ whiteList['overflow-wrap'] = false; // default: normal
1484
+ whiteList['overflow-x'] = false; // default: visible
1485
+ whiteList['overflow-y'] = false; // default: visible
1486
+ whiteList['padding'] = true; // default: depending on individual properties
1487
+ whiteList['padding-bottom'] = true; // default: 0
1488
+ whiteList['padding-left'] = true; // default: 0
1489
+ whiteList['padding-right'] = true; // default: 0
1490
+ whiteList['padding-top'] = true; // default: 0
1491
+ whiteList['page'] = false; // default: auto
1492
+ whiteList['page-break-after'] = false; // default: auto
1493
+ whiteList['page-break-before'] = false; // default: auto
1494
+ whiteList['page-break-inside'] = false; // default: auto
1495
+ whiteList['page-policy'] = false; // default: start
1496
+ whiteList['pause'] = false; // default: implementation dependent
1497
+ whiteList['pause-after'] = false; // default: implementation dependent
1498
+ whiteList['pause-before'] = false; // default: implementation dependent
1499
+ whiteList['perspective'] = false; // default: none
1500
+ whiteList['perspective-origin'] = false; // default: 50% 50%
1501
+ whiteList['pitch'] = false; // default: medium
1502
+ whiteList['pitch-range'] = false; // default: 50
1503
+ whiteList['play-during'] = false; // default: auto
1504
+ whiteList['position'] = false; // default: static
1505
+ whiteList['presentation-level'] = false; // default: 0
1506
+ whiteList['quotes'] = false; // default: text
1507
+ whiteList['region-fragment'] = false; // default: auto
1508
+ whiteList['resize'] = false; // default: none
1509
+ whiteList['rest'] = false; // default: depending on individual properties
1510
+ whiteList['rest-after'] = false; // default: none
1511
+ whiteList['rest-before'] = false; // default: none
1512
+ whiteList['richness'] = false; // default: 50
1513
+ whiteList['right'] = false; // default: auto
1514
+ whiteList['rotation'] = false; // default: 0
1515
+ whiteList['rotation-point'] = false; // default: 50% 50%
1516
+ whiteList['ruby-align'] = false; // default: auto
1517
+ whiteList['ruby-merge'] = false; // default: separate
1518
+ whiteList['ruby-position'] = false; // default: before
1519
+ whiteList['shape-image-threshold'] = false; // default: 0.0
1520
+ whiteList['shape-outside'] = false; // default: none
1521
+ whiteList['shape-margin'] = false; // default: 0
1522
+ whiteList['size'] = false; // default: auto
1523
+ whiteList['speak'] = false; // default: auto
1524
+ whiteList['speak-as'] = false; // default: normal
1525
+ whiteList['speak-header'] = false; // default: once
1526
+ whiteList['speak-numeral'] = false; // default: continuous
1527
+ whiteList['speak-punctuation'] = false; // default: none
1528
+ whiteList['speech-rate'] = false; // default: medium
1529
+ whiteList['stress'] = false; // default: 50
1530
+ whiteList['string-set'] = false; // default: none
1531
+ whiteList['tab-size'] = false; // default: 8
1532
+ whiteList['table-layout'] = false; // default: auto
1533
+ whiteList['text-align'] = true; // default: start
1534
+ whiteList['text-align-last'] = true; // default: auto
1535
+ whiteList['text-combine-upright'] = true; // default: none
1536
+ whiteList['text-decoration'] = true; // default: none
1537
+ whiteList['text-decoration-color'] = true; // default: currentColor
1538
+ whiteList['text-decoration-line'] = true; // default: none
1539
+ whiteList['text-decoration-skip'] = true; // default: objects
1540
+ whiteList['text-decoration-style'] = true; // default: solid
1541
+ whiteList['text-emphasis'] = true; // default: depending on individual properties
1542
+ whiteList['text-emphasis-color'] = true; // default: currentColor
1543
+ whiteList['text-emphasis-position'] = true; // default: over right
1544
+ whiteList['text-emphasis-style'] = true; // default: none
1545
+ whiteList['text-height'] = true; // default: auto
1546
+ whiteList['text-indent'] = true; // default: 0
1547
+ whiteList['text-justify'] = true; // default: auto
1548
+ whiteList['text-orientation'] = true; // default: mixed
1549
+ whiteList['text-overflow'] = true; // default: clip
1550
+ whiteList['text-shadow'] = true; // default: none
1551
+ whiteList['text-space-collapse'] = true; // default: collapse
1552
+ whiteList['text-transform'] = true; // default: none
1553
+ whiteList['text-underline-position'] = true; // default: auto
1554
+ whiteList['text-wrap'] = true; // default: normal
1555
+ whiteList['top'] = false; // default: auto
1556
+ whiteList['transform'] = false; // default: none
1557
+ whiteList['transform-origin'] = false; // default: 50% 50% 0
1558
+ whiteList['transform-style'] = false; // default: flat
1559
+ whiteList['transition'] = false; // default: depending on individual properties
1560
+ whiteList['transition-delay'] = false; // default: 0s
1561
+ whiteList['transition-duration'] = false; // default: 0s
1562
+ whiteList['transition-property'] = false; // default: all
1563
+ whiteList['transition-timing-function'] = false; // default: ease
1564
+ whiteList['unicode-bidi'] = false; // default: normal
1565
+ whiteList['vertical-align'] = false; // default: baseline
1566
+ whiteList['visibility'] = false; // default: visible
1567
+ whiteList['voice-balance'] = false; // default: center
1568
+ whiteList['voice-duration'] = false; // default: auto
1569
+ whiteList['voice-family'] = false; // default: implementation dependent
1570
+ whiteList['voice-pitch'] = false; // default: medium
1571
+ whiteList['voice-range'] = false; // default: medium
1572
+ whiteList['voice-rate'] = false; // default: normal
1573
+ whiteList['voice-stress'] = false; // default: normal
1574
+ whiteList['voice-volume'] = false; // default: medium
1575
+ whiteList['volume'] = false; // default: medium
1576
+ whiteList['white-space'] = false; // default: normal
1577
+ whiteList['widows'] = false; // default: 2
1578
+ whiteList['width'] = true; // default: auto
1579
+ whiteList['will-change'] = false; // default: auto
1580
+ whiteList['word-break'] = true; // default: normal
1581
+ whiteList['word-spacing'] = true; // default: normal
1582
+ whiteList['word-wrap'] = true; // default: normal
1583
+ whiteList['wrap-flow'] = false; // default: auto
1584
+ whiteList['wrap-through'] = false; // default: wrap
1585
+ whiteList['writing-mode'] = false; // default: horizontal-tb
1586
+ whiteList['z-index'] = false; // default: auto
1587
+
1588
+ return whiteList;
1589
+ }
1590
+
1591
+
1592
+ /**
1593
+ * 匹配到白名单上的一个属性时
1594
+ *
1595
+ * @param {String} name
1596
+ * @param {String} value
1597
+ * @param {Object} options
1598
+ * @return {String}
1599
+ */
1600
+ function onAttr (name, value, options) {
1601
+ // do nothing
1602
+ }
1603
+
1604
+ /**
1605
+ * 匹配到不在白名单上的一个属性时
1606
+ *
1607
+ * @param {String} name
1608
+ * @param {String} value
1609
+ * @param {Object} options
1610
+ * @return {String}
1611
+ */
1612
+ function onIgnoreAttr (name, value, options) {
1613
+ // do nothing
1614
+ }
1615
+
1616
+ var REGEXP_URL_JAVASCRIPT = /javascript\s*\:/img;
1617
+
1618
+ /**
1619
+ * 过滤属性值
1620
+ *
1621
+ * @param {String} name
1622
+ * @param {String} value
1623
+ * @return {String}
1624
+ */
1625
+ function safeAttrValue(name, value) {
1626
+ if (REGEXP_URL_JAVASCRIPT.test(value)) return '';
1627
+ return value;
1628
+ }
1629
+
1630
+
1631
+ exports.whiteList = getDefaultWhiteList();
1632
+ exports.getDefaultWhiteList = getDefaultWhiteList;
1633
+ exports.onAttr = onAttr;
1634
+ exports.onIgnoreAttr = onIgnoreAttr;
1635
+ exports.safeAttrValue = safeAttrValue;
1636
+
1637
+ },{}],8:[function(require,module,exports){
1638
+ /**
1639
+ * cssfilter
1640
+ *
1641
+ * @author 老雷<leizongmin@gmail.com>
1642
+ */
1643
+
1644
+ var DEFAULT = require('./default');
1645
+ var FilterCSS = require('./css');
1646
+
1647
+
1648
+ /**
1649
+ * XSS过滤
1650
+ *
1651
+ * @param {String} css 要过滤的CSS代码
1652
+ * @param {Object} options 选项:whiteList, onAttr, onIgnoreAttr
1653
+ * @return {String}
1654
+ */
1655
+ function filterCSS (html, options) {
1656
+ var xss = new FilterCSS(options);
1657
+ return xss.process(html);
1658
+ }
1659
+
1660
+
1661
+ // 输出
1662
+ exports = module.exports = filterCSS;
1663
+ exports.FilterCSS = FilterCSS;
1664
+ for (var i in DEFAULT) exports[i] = DEFAULT[i];
1665
+
1666
+ // 在浏览器端使用
1667
+ if (typeof window !== 'undefined') {
1668
+ window.filterCSS = module.exports;
1669
+ }
1670
+
1671
+ },{"./css":6,"./default":7}],9:[function(require,module,exports){
1672
+ /**
1673
+ * cssfilter
1674
+ *
1675
+ * @author 老雷<leizongmin@gmail.com>
1676
+ */
1677
+
1678
+ var _ = require('./util');
1679
+
1680
+
1681
+ /**
1682
+ * 解析style
1683
+ *
1684
+ * @param {String} css
1685
+ * @param {Function} onAttr 处理属性的函数
1686
+ * 参数格式: function (sourcePosition, position, name, value, source)
1687
+ * @return {String}
1688
+ */
1689
+ function parseStyle (css, onAttr) {
1690
+ css = _.trimRight(css);
1691
+ if (css[css.length - 1] !== ';') css += ';';
1692
+ var cssLength = css.length;
1693
+ var isParenthesisOpen = false;
1694
+ var lastPos = 0;
1695
+ var i = 0;
1696
+ var retCSS = '';
1697
+
1698
+ function addNewAttr () {
1699
+ // 如果没有正常的闭合圆括号,则直接忽略当前属性
1700
+ if (!isParenthesisOpen) {
1701
+ var source = _.trim(css.slice(lastPos, i));
1702
+ var j = source.indexOf(':');
1703
+ if (j !== -1) {
1704
+ var name = _.trim(source.slice(0, j));
1705
+ var value = _.trim(source.slice(j + 1));
1706
+ // 必须有属性名称
1707
+ if (name) {
1708
+ var ret = onAttr(lastPos, retCSS.length, name, value, source);
1709
+ if (ret) retCSS += ret + '; ';
1710
+ }
1711
+ }
1712
+ }
1713
+ lastPos = i + 1;
1714
+ }
1715
+
1716
+ for (; i < cssLength; i++) {
1717
+ var c = css[i];
1718
+ if (c === '/' && css[i + 1] === '*') {
1719
+ // 备注开始
1720
+ var j = css.indexOf('*/', i + 2);
1721
+ // 如果没有正常的备注结束,则后面的部分全部跳过
1722
+ if (j === -1) break;
1723
+ // 直接将当前位置调到备注结尾,并且初始化状态
1724
+ i = j + 1;
1725
+ lastPos = i + 1;
1726
+ isParenthesisOpen = false;
1727
+ } else if (c === '(') {
1728
+ isParenthesisOpen = true;
1729
+ } else if (c === ')') {
1730
+ isParenthesisOpen = false;
1731
+ } else if (c === ';') {
1732
+ if (isParenthesisOpen) {
1733
+ // 在圆括号里面,忽略
1734
+ } else {
1735
+ addNewAttr();
1736
+ }
1737
+ } else if (c === '\n') {
1738
+ addNewAttr();
1739
+ }
1740
+ }
1741
+
1742
+ return _.trim(retCSS);
1743
+ }
1744
+
1745
+ module.exports = parseStyle;
1746
+
1747
+ },{"./util":10}],10:[function(require,module,exports){
1748
+ module.exports = {
1749
+ indexOf: function (arr, item) {
1750
+ var i, j;
1751
+ if (Array.prototype.indexOf) {
1752
+ return arr.indexOf(item);
1753
+ }
1754
+ for (i = 0, j = arr.length; i < j; i++) {
1755
+ if (arr[i] === item) {
1756
+ return i;
1757
+ }
1758
+ }
1759
+ return -1;
1760
+ },
1761
+ forEach: function (arr, fn, scope) {
1762
+ var i, j;
1763
+ if (Array.prototype.forEach) {
1764
+ return arr.forEach(fn, scope);
1765
+ }
1766
+ for (i = 0, j = arr.length; i < j; i++) {
1767
+ fn.call(scope, arr[i], i, arr);
1768
+ }
1769
+ },
1770
+ trim: function (str) {
1771
+ if (String.prototype.trim) {
1772
+ return str.trim();
1773
+ }
1774
+ return str.replace(/(^\s*)|(\s*$)/g, '');
1775
+ },
1776
+ trimRight: function (str) {
1777
+ if (String.prototype.trimRight) {
1778
+ return str.trimRight();
1779
+ }
1780
+ return str.replace(/(\s*$)/g, '');
1781
+ }
1782
+ };
1783
+
1784
+ },{}]},{},[2]);