index.js 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. const xss = require('xss');
  2. const commonmarkSpec = require('./commonmark-spec');
  3. const REPETITIONS_NUM = 50;
  4. class Xss {
  5. constructor(xssOption) {
  6. xssOption = xssOption || {}; // eslint-disable-line no-param-reassign
  7. const tagWhitelist = xssOption.tagWhitelist || [];
  8. const attrWhitelist = xssOption.attrWhitelist || [];
  9. const whitelistContent = {};
  10. // default
  11. const option = {
  12. stripIgnoreTag: true,
  13. stripIgnoreTagBody: false, // see https://github.com/weseek/growi/pull/505
  14. css: false,
  15. whitelist: whitelistContent,
  16. escapeHtml: (html) => { return html }, // resolve https://github.com/weseek/growi/issues/221
  17. onTag: (tag, html, options) => {
  18. // pass autolink
  19. if (tag.match(commonmarkSpec.uriAutolinkRegexp) || tag.match(commonmarkSpec.emailAutolinkRegexp)) {
  20. return html;
  21. }
  22. },
  23. };
  24. tagWhitelist.forEach((tag) => {
  25. whitelistContent[tag] = attrWhitelist;
  26. });
  27. // create the XSS Filter instance
  28. this.myxss = new xss.FilterXSS(option);
  29. }
  30. process(document) {
  31. let count = 0;
  32. let currDoc = document;
  33. let prevDoc = document;
  34. do {
  35. count += 1;
  36. // stop running infinitely
  37. if (count > REPETITIONS_NUM) {
  38. return '--filtered--';
  39. }
  40. prevDoc = currDoc;
  41. currDoc = this.myxss.process(currDoc);
  42. }
  43. while (currDoc !== prevDoc);
  44. return currDoc;
  45. }
  46. }
  47. module.exports = Xss;