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: '',