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'
- });
- }
- }
- };
- }
- };
|