123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- /**
- * @fileoverview Prevent usage of `javascript:` URLs
- * @author Sergei Startsev
- */
- 'use strict';
- const docsUrl = require('../util/docsUrl');
- // ------------------------------------------------------------------------------
- // Rule Definition
- // ------------------------------------------------------------------------------
- // https://github.com/facebook/react/blob/d0ebde77f6d1232cefc0da184d731943d78e86f2/packages/react-dom/src/shared/sanitizeURL.js#L30
- /* eslint-disable-next-line max-len, no-control-regex */
- const isJavaScriptProtocol = /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*:/i;
- function hasJavaScriptProtocol(attr) {
- return attr.value && attr.value.type === 'Literal'
- && isJavaScriptProtocol.test(attr.value.value);
- }
- function shouldVerifyElement(node, config) {
- const name = node.name && node.name.name;
- return name === 'a' || config.find((i) => i.name === name);
- }
- function shouldVerifyProp(node, config) {
- const name = node.name && node.name.name;
- const parentName = node.parent.name && node.parent.name.name;
- if (parentName === 'a' && name === 'href') {
- return true;
- }
- const el = config.find((i) => i.name === parentName);
- if (!el) {
- return false;
- }
- const props = el.props || [];
- return node.name && props.indexOf(name) !== -1;
- }
- module.exports = {
- meta: {
- docs: {
- description: 'Forbid `javascript:` URLs',
- category: 'Best Practices',
- recommended: false,
- url: docsUrl('jsx-no-script-url')
- },
- messages: {
- noScriptURL: 'A future version of React will block javascript: URLs as a security precaution. '
- + 'Use event handlers instead if you can. If you need to generate unsafe HTML, try using dangerouslySetInnerHTML instead.'
- },
- schema: [{
- type: 'array',
- uniqueItems: true,
- items: {
- type: 'object',
- properties: {
- name: {
- type: 'string'
- },
- props: {
- type: 'array',
- items: {
- type: 'string',
- uniqueItems: true
- }
- }
- },
- required: ['name', 'props'],
- additionalProperties: false
- }
- }]
- },
- create(context) {
- const config = context.options[0] || [];
- return {
- JSXAttribute(node) {
- const parent = node.parent;
- if (shouldVerifyElement(parent, config) && shouldVerifyProp(node, config) && hasJavaScriptProtocol(node)) {
- context.report({
- node,
- messageId: 'noScriptURL'
- });
- }
- }
- };
- }
- };
|