diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f62701bbc..4ce04aebe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,12 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ### Fixed * [`no-namespace`]: fix crash on non-string React.createElement name ([#3082] @ljharb) * [`no-namespace`]: avoid crash on non-string createElement values ([#3085] @ljharb) +* [`jsx-no-target-blank`]: improve error messages ([#3088] @cutiful) ### Changed * [Docs] [`jsx-max-props-per-line`]: fix options example ([#3083] @MrRaiter) +[#3088]: https://github.com/yannickcr/eslint-plugin-react/pull/3088 [#3085]: https://github.com/yannickcr/eslint-plugin-react/issue/3085 [#3083]: https://github.com/yannickcr/eslint-plugin-react/pull/3083 [#3082]: https://github.com/yannickcr/eslint-plugin-react/pull/3082 diff --git a/docs/rules/jsx-no-target-blank.md b/docs/rules/jsx-no-target-blank.md index 0f5cfbee92..ea13747d3f 100644 --- a/docs/rules/jsx-no-target-blank.md +++ b/docs/rules/jsx-no-target-blank.md @@ -20,8 +20,8 @@ This rule aims to prevent user generated link hrefs and form actions from creati ... ``` -* `allowReferrer`: optional boolean. If `true` does not require `noreferrer`. Defaults to `false`. -* `enabled`: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0. +* `allowReferrer`: optional boolean. If `true` does not require `noreferrer` (i. e. `noopener` alone is enough, this leaves IE vulnerable). Defaults to `false`. +* `enabled`: for enabling the rule. * `enforceDynamicLinks`: optional string, 'always' or 'never' * `warnOnSpreadAttributes`: optional boolean. Defaults to `false`. * `enforceDynamicLinks` - enforce: optional string, 'always' or 'never' @@ -125,6 +125,8 @@ This rule supports the ability to use custom components for forms. To enable thi For links to a trusted host (e.g. internal links to your own site, or links to a another host you control, where you can be certain this security vulnerability does not exist), you may want to keep the HTTP Referer header for analytics purposes. +If you do not support Internet Explorer (any version), Chrome < 49, Opera < 36, Firefox < 52, desktop Safari < 10.1 or iOS Safari < 10.3, you may set `allowReferrer` to `true`, keep the HTTP Referer header and only add `rel="noopener"` to your links. + ## When Not To Use It If you do not have any external links or forms, you can disable this rule. diff --git a/lib/rules/jsx-no-target-blank.js b/lib/rules/jsx-no-target-blank.js index d73c8e4f9d..18e056575c 100644 --- a/lib/rules/jsx-no-target-blank.js +++ b/lib/rules/jsx-no-target-blank.js @@ -97,7 +97,8 @@ function hasSecureRel(node, allowReferrer, warnOnSpreadAttributes, spreadAttribu } const messages = { - noTargetBlank: 'Using target="_blank" without rel="noreferrer" is a security risk: see https://html.spec.whatwg.org/multipage/links.html#link-type-noopener' + noTargetBlankWithoutNoreferrer: 'Using target="_blank" without rel="noreferrer" (which implies rel="noopener") is a security risk in older browsers: see https://mathiasbynens.github.io/rel-noopener/#recommendations', + noTargetBlankWithoutNoopener: 'Using target="_blank" without rel="noreferrer" or rel="noopener" (the former implies the latter and is preferred due to wider support) is a security risk: see https://mathiasbynens.github.io/rel-noopener/#recommendations' }; module.exports = { @@ -173,7 +174,8 @@ module.exports = { const hasDangerousLink = hasExternalLink(node, linkAttribute, warnOnSpreadAttributes, spreadAttributeIndex) || (enforceDynamicLinks === 'always' && hasDynamicLink(node, linkAttribute)); if (hasDangerousLink && !hasSecureRel(node, allowReferrer, warnOnSpreadAttributes, spreadAttributeIndex)) { - report(context, messages.noTargetBlank, 'noTargetBlank', { + const messageId = allowReferrer ? 'noTargetBlankWithoutNoopener' : 'noTargetBlankWithoutNoreferrer'; + report(context, messages[messageId], messageId, { node, fix(fixer) { // eslint 5 uses `node.attributes`; eslint 6+ uses `node.parent.attributes` @@ -244,7 +246,8 @@ module.exports = { hasExternalLink(node, formAttribute) || (enforceDynamicLinks === 'always' && hasDynamicLink(node, formAttribute)) ) { - report(context, messages.noTargetBlank, 'noTargetBlank', { + const messageId = allowReferrer ? 'noTargetBlankWithoutNoopener' : 'noTargetBlankWithoutNoreferrer'; + report(context, messages[messageId], messageId, { node }); } diff --git a/tests/lib/rules/jsx-no-target-blank.js b/tests/lib/rules/jsx-no-target-blank.js index ce2402325f..38302d6a7d 100644 --- a/tests/lib/rules/jsx-no-target-blank.js +++ b/tests/lib/rules/jsx-no-target-blank.js @@ -25,7 +25,7 @@ const parserOptions = { // ------------------------------------------------------------------------------ const ruleTester = new RuleTester({parserOptions}); -const defaultErrors = [{messageId: 'noTargetBlank'}]; +const defaultErrors = [{messageId: 'noTargetBlankWithoutNoreferrer'}]; ruleTester.run('jsx-no-target-blank', rule, { valid: [ @@ -249,7 +249,7 @@ ruleTester.run('jsx-no-target-blank', rule, { code: '', output: '', options: [{allowReferrer: true}], - errors: defaultErrors + errors: [{messageId: 'noTargetBlankWithoutNoopener'}] }, { code: '',