UNPKG

2.58 kBJavaScriptView Raw
1/**
2 * @fileoverview Prevent usage of `javascript:` URLs
3 * @author Sergei Startsev
4 */
5
6'use strict';
7
8const docsUrl = require('../util/docsUrl');
9
10// ------------------------------------------------------------------------------
11// Rule Definition
12// ------------------------------------------------------------------------------
13
14// https://github.com/facebook/react/blob/d0ebde77f6d1232cefc0da184d731943d78e86f2/packages/react-dom/src/shared/sanitizeURL.js#L30
15/* eslint-disable-next-line max-len, no-control-regex */
16const 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;
17
18function hasJavaScriptProtocol(attr) {
19 return attr.value.type === 'Literal'
20 && isJavaScriptProtocol.test(attr.value.value);
21}
22
23function shouldVerifyElement(node, config) {
24 const name = node.name && node.name.name;
25 return name === 'a' || config.find((i) => i.name === name);
26}
27
28function shouldVerifyProp(node, config) {
29 const name = node.name && node.name.name;
30 const parentName = node.parent.name && node.parent.name.name;
31
32 if (parentName === 'a' && name === 'href') {
33 return true;
34 }
35
36 const el = config.find((i) => i.name === parentName);
37 if (!el) {
38 return false;
39 }
40
41 const props = el.props || [];
42 return node.name && props.indexOf(name) !== -1;
43}
44
45module.exports = {
46 meta: {
47 docs: {
48 description: 'Forbid `javascript:` URLs',
49 category: 'Best Practices',
50 recommended: false,
51 url: docsUrl('jsx-no-script-url')
52 },
53 schema: [{
54 type: 'array',
55 uniqueItems: true,
56 items: {
57 type: 'object',
58 properties: {
59 name: {
60 type: 'string'
61 },
62 props: {
63 type: 'array',
64 items: {
65 type: 'string',
66 uniqueItems: true
67 }
68 }
69 },
70 required: ['name', 'props'],
71 additionalProperties: false
72 }
73 }]
74 },
75
76 create(context) {
77 const config = context.options[0] || [];
78 return {
79 JSXAttribute(node) {
80 const parent = node.parent;
81 if (shouldVerifyElement(parent, config) && shouldVerifyProp(node, config) && hasJavaScriptProtocol(node)) {
82 context.report({
83 node,
84 message: 'A future version of React will block javascript: URLs as a security precaution. '
85 + 'Use event handlers instead if you can. If you need to generate unsafe HTML, try using dangerouslySetInnerHTML instead.'
86 });
87 }
88 }
89 };
90 }
91};