no-inner-html.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. // Copyright (c) Microsoft Corporation.
  2. // Licensed under the MIT License.
  3. /**
  4. * @fileoverview Rule to disallow assignment to innerHTML or outerHTML properties
  5. * @author Antonios Katopodis
  6. */
  7. "use strict";
  8. const astUtils = require("../ast-utils");
  9. //------------------------------------------------------------------------------
  10. // Rule Definition
  11. //------------------------------------------------------------------------------
  12. module.exports = {
  13. meta: {
  14. type: "suggestion",
  15. fixable: "code",
  16. schema: [],
  17. docs: {
  18. description: "Assignments to [innerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)/[outerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML) properties or calls to [insertAdjacentHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML) method manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead.",
  19. url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-inner-html.md"
  20. },
  21. messages: {
  22. noInnerHtml: 'Do not write to DOM directly using innerHTML/outerHTML property',
  23. noInsertAdjacentHTML: 'Do not write to DOM using insertAdjacentHTML method'
  24. }
  25. },
  26. create: function (context) {
  27. const fullTypeChecker = astUtils.getFullTypeChecker(context);
  28. function mightBeHTMLElement(node) {
  29. const type = astUtils.getNodeTypeAsString(fullTypeChecker, node, context);
  30. return type.match(/HTML.*Element/) || type === "any";
  31. }
  32. return {
  33. "CallExpression[arguments.length=2] > MemberExpression.callee[property.name='insertAdjacentHTML']"(node) {
  34. // Ignore known false positives
  35. if (
  36. node.parent != undefined
  37. && node.parent.arguments != undefined
  38. && node.parent.arguments.length >= 1
  39. && node.parent.arguments[1] != undefined
  40. // element.insertAdjacentHTML('')
  41. && node.parent.arguments[1].type === 'Literal' && node.parent.arguments[1].value === ''
  42. ) {
  43. return;
  44. }
  45. if (mightBeHTMLElement(node.object)) {
  46. context.report({
  47. node: node,
  48. messageId: "noInsertAdjacentHTML"
  49. });
  50. }
  51. },
  52. "AssignmentExpression[left.type='MemberExpression'][left.property.name=/innerHTML|outerHTML/]"(node) {
  53. // Ignore known false positives
  54. if (
  55. node.right != undefined
  56. // element.innerHTML = ''
  57. && node.right.type === 'Literal' && node.right.value === ''
  58. ) {
  59. return;
  60. }
  61. if (mightBeHTMLElement(node.left.object)) {
  62. context.report({
  63. node: node,
  64. messageId: "noInnerHtml"
  65. });
  66. }
  67. }
  68. };
  69. }
  70. };