diff --git a/docs/rules/jsx-no-target-blank.md b/docs/rules/jsx-no-target-blank.md index dd0cdb4c9b..ed724c3607 100644 --- a/docs/rules/jsx-no-target-blank.md +++ b/docs/rules/jsx-no-target-blank.md @@ -20,37 +20,61 @@ This rule aims to prevent user generated links from creating security vulnerabil * enabled: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0. * enforce: optional string, 'always' or 'never' +* Link components can be something other than an ``, see [shared settings](https://github.com/yannickcr/eslint-plugin-react/blob/master/README.md#configuration) for `linkComponents` configuration) + +### `enforceDynamicLinks` + +#### always -### always (default) `{"enforceDynamicLinks": "always"}` enforces the rule if the href is a dynamic link (default) When {"enforceDynamicLinks": "always"} is set, the following patterns are considered errors: ```jsx var Hello = -var Hello = +var Hello = ``` The following patterns are **not** considered errors: ```jsx -var Hello =

-var Hello = -var Hello = -var Hello = +var Hello =

+var Hello = +var Hello = +var Hello = var Hello = ``` -### never +#### never `{"enforceDynamicLinks": "never"}` does not enforce the rule if the href is a dynamic link When {"enforceDynamicLinks": "never"} is set, the following patterns are **not** considered errors: ```jsx -var Hello = +var Hello = +``` + +### Link components + +Link components can be something other than an ``, see [shared settings](https://github.com/yannickcr/eslint-plugin-react/blob/master/README.md#configuration) for `linkComponents` configuration) + +The following patterns are considered errors: + +```jsx +var Hello = +var Hello = +``` + +The following patterns are **not** considered errors: + +```jsx +var Hello = +var Hello = +var Hello = +var Hello = ``` ## When Not To Use It -If you do not have any external links, you can disable this rule \ No newline at end of file +If you do not have any external links, you can disable this rule diff --git a/lib/rules/jsx-no-target-blank.js b/lib/rules/jsx-no-target-blank.js index daee012551..07aae2fa1c 100644 --- a/lib/rules/jsx-no-target-blank.js +++ b/lib/rules/jsx-no-target-blank.js @@ -5,6 +5,7 @@ 'use strict'; const docsUrl = require('../util/docsUrl'); +const linkComponentsUtil = require('../util/linkComponents'); // ------------------------------------------------------------------------------ // Rule Definition @@ -18,16 +19,16 @@ function isTargetBlank(attr) { attr.value.value.toLowerCase() === '_blank'; } -function hasExternalLink(element) { +function hasExternalLink(element, linkAttribute) { return element.attributes.some(attr => attr.name && - attr.name.name === 'href' && + attr.name.name === linkAttribute && attr.value.type === 'Literal' && /^(?:\w+:|\/\/)/.test(attr.value.value)); } -function hasDynamicLink(element) { +function hasDynamicLink(element, linkAttribute) { return element.attributes.some(attr => attr.name && - attr.name.name === 'href' && + attr.name.name === linkAttribute && attr.value.type === 'JSXExpressionContainer'); } @@ -63,14 +64,17 @@ module.exports = { create: function(context) { const configuration = context.options[0] || {}; const enforceDynamicLinks = configuration.enforceDynamicLinks || 'always'; + const components = linkComponentsUtil.getLinkComponents(context); return { JSXAttribute: function(node) { - if (node.parent.name.name !== 'a' || !isTargetBlank(node) || hasSecureRel(node.parent)) { + if (!components.has(node.parent.name.name) || !isTargetBlank(node) || hasSecureRel(node.parent)) { return; } - if (hasExternalLink(node.parent) || (enforceDynamicLinks === 'always' && hasDynamicLink(node.parent))) { + const linkAttribute = components.get(node.parent.name.name); + + if (hasExternalLink(node.parent, linkAttribute) || (enforceDynamicLinks === 'always' && hasDynamicLink(node.parent, linkAttribute))) { context.report(node, 'Using target="_blank" without rel="noopener noreferrer" ' + 'is a security risk: see https://mathiasbynens.github.io/rel-noopener'); } diff --git a/tests/lib/rules/jsx-no-target-blank.js b/tests/lib/rules/jsx-no-target-blank.js index eb90cbd6e3..16ce255c55 100644 --- a/tests/lib/rules/jsx-no-target-blank.js +++ b/tests/lib/rules/jsx-no-target-blank.js @@ -47,6 +47,16 @@ ruleTester.run('jsx-no-target-blank', rule, { { code: '', options: [{enforceDynamicLinks: 'never'}] + }, + { + code: '', + options: [{enforceDynamicLinks: 'never'}], + settings: {linkComponents: ['Link']} + }, + { + code: '', + options: [{enforceDynamicLinks: 'never'}], + settings: {linkComponents: {name: 'Link', linkAttribute: 'to'}} } ], invalid: [{ @@ -83,5 +93,15 @@ ruleTester.run('jsx-no-target-blank', rule, { code: '', options: [{enforceDynamicLinks: 'always'}], errors: defaultErrors + }, { + code: '', + options: [{enforceDynamicLinks: 'always'}], + settings: {linkComponents: ['Link']}, + errors: defaultErrors + }, { + code: '', + options: [{enforceDynamicLinks: 'always'}], + settings: {linkComponents: {name: 'Link', linkAttribute: 'to'}}, + errors: defaultErrors }] });