123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- /**
- * @fileoverview TBD
- */
- 'use strict';
- const docsUrl = require('../util/docsUrl');
- const isCreateElement = require('../util/isCreateElement');
- const report = require('../util/report');
- const 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',
- };
- const ALLOWED_VALUES = [
- // From https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox
- '',
- 'allow-downloads-without-user-activation',
- 'allow-downloads',
- '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-storage-access-by-user-activation',
- 'allow-top-navigation',
- 'allow-top-navigation-by-user-activation',
- ];
- function validateSandboxAttribute(context, node, attribute) {
- if (typeof attribute !== 'string') {
- // Only string literals are supported for now
- return;
- }
- const values = attribute.split(' ');
- let allowScripts = false;
- let allowSameOrigin = false;
- values.forEach((attributeValue) => {
- const trimmedAttributeValue = attributeValue.trim();
- if (ALLOWED_VALUES.indexOf(trimmedAttributeValue) === -1) {
- report(context, messages.invalidValue, 'invalidValue', {
- node,
- data: {
- value: trimmedAttributeValue,
- },
- });
- }
- if (trimmedAttributeValue === 'allow-scripts') {
- allowScripts = true;
- }
- if (trimmedAttributeValue === 'allow-same-origin') {
- allowSameOrigin = true;
- }
- });
- if (allowScripts && allowSameOrigin) {
- report(context, messages.invalidCombination, 'invalidCombination', {
- node,
- });
- }
- }
- function checkAttributes(context, 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
- ) {
- validateSandboxAttribute(context, node, attribute.value.value);
- }
- }
- });
- if (!sandboxAttributeFound) {
- report(context, messages.attributeMissing, 'attributeMissing', {
- node,
- });
- }
- }
- function checkProps(context, node) {
- let sandboxAttributeFound = false;
- if (node.arguments.length > 1) {
- const props = node.arguments[1];
- const sandboxProp = props.properties && props.properties.find((x) => x.type === 'Property' && x.key.name === 'sandbox');
- if (sandboxProp) {
- sandboxAttributeFound = true;
- if (sandboxProp.value && sandboxProp.value.type === 'Literal' && sandboxProp.value.value) {
- validateSandboxAttribute(context, node, sandboxProp.value.value);
- }
- }
- }
- if (!sandboxAttributeFound) {
- report(context, messages.attributeMissing, 'attributeMissing', {
- node,
- });
- }
- }
- module.exports = {
- meta: {
- docs: {
- description: 'Enforce sandbox attribute on iframe elements',
- category: 'Best Practices',
- recommended: false,
- url: docsUrl('iframe-missing-sandbox'),
- },
- schema: [],
- messages,
- },
- create(context) {
- return {
- 'JSXOpeningElement[name.name="iframe"]'(node) {
- checkAttributes(context, node);
- },
- CallExpression(node) {
- if (isCreateElement(node, context) && node.arguments && node.arguments.length > 0) {
- const tag = node.arguments[0];
- if (tag.type === 'Literal' && tag.value === 'iframe') {
- checkProps(context, node);
- }
- }
- },
- };
- },
- };
|