| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 | // Copyright (c) Microsoft Corporation.// Licensed under the MIT License./** * @fileoverview Rule to enforce sandbox attribute on iframe elements */"use strict";// TODO: Follow-up on https://github.com/yannickcr/eslint-plugin-react/issues/2754 and try to merge rule into eslint-plugin-react//------------------------------------------------------------------------------// Rule Definition//------------------------------------------------------------------------------module.exports = {  meta: {    type: "suggestion",    fixable: "code",    schema: [],    docs: {      category: "Security",      description: "The [sandbox](https://www.w3schools.com/tags/att_iframe_sandbox.asp) attribute enables an extra set of restrictions for the content in the iframe and should always be specified.",      url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/react-iframe-missing-sandbox.md"    },    messages: {      attributeMissing: 'An iframe element is missing a sandbox attribute',      invalidValue: 'An iframe element defines a sandbox attribute with invalid value "{{ value }}"',      invalidCombination: 'An iframe element defines a sandbox attribute with both allow-scripts and allow-same-origin which is invalid'    }  },  create(context) {    const ALLOWED_VALUES = [      // From https://www.w3schools.com/tags/att_iframe_sandbox.asp      '',      'allow-forms',      'allow-modals',      'allow-orientation-lock',      'allow-pointer-lock',      'allow-popups',      'allow-popups-to-escape-sandbox',      'allow-presentation',      'allow-same-origin',      'allow-scripts',      'allow-top-navigation',      'allow-top-navigation-by-user-activation'    ];    function validateSandboxAttribute(node, attribute) {      const values = attribute.value.value.split(' ');      let allowScripts = false;      let allowSameOrigin = false;      values.forEach((attributeValue) => {        const trimmedAttributeValue = attributeValue.trim();        if (ALLOWED_VALUES.indexOf(trimmedAttributeValue) === -1) {          context.report({            node,            messageId: 'invalidValue',            data: {              value: trimmedAttributeValue            }          });        }        if (trimmedAttributeValue === 'allow-scripts') {          allowScripts = true;        }        if (trimmedAttributeValue === 'allow-same-origin') {          allowSameOrigin = true;        }      });      if (allowScripts && allowSameOrigin) {        context.report({          node,          messageId: 'invalidCombination'        });      }    }    return {      'JSXOpeningElement[name.name="iframe"]'(node) {        let sandboxAttributeFound = false;        node.attributes.forEach((attribute) => {          if (attribute.type === 'JSXAttribute'            && attribute.name            && attribute.name.type === 'JSXIdentifier'            && attribute.name.name === 'sandbox'          ) {            sandboxAttributeFound = true;            if (              attribute.value              && attribute.value.type === 'Literal'              && attribute.value.value            ) {              // Only string literals are supported for now              validateSandboxAttribute(node, attribute);            }          }        });        if (!sandboxAttributeFound) {          context.report({            node,            messageId: 'attributeMissing'          });        }      }    };  }};
 |