Skip to content

Commit d3b5d71

Browse files
eps1lonljharb
authored andcommitted
[New] jsx-no-target-blank: add allowReferrer option
1 parent 83ac4c0 commit d3b5d71

File tree

3 files changed

+17
-4
lines changed

3 files changed

+17
-4
lines changed

docs/rules/jsx-no-target-blank.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ This rule aims to prevent user generated links from creating security vulnerabil
1414
## Rule Options
1515
```json
1616
...
17-
"react/jsx-no-target-blank": [<enabled>, { "enforceDynamicLinks": <enforce> }]
17+
"react/jsx-no-target-blank": [<enabled>, { "allowReferrer": <allow-referrer>, "enforceDynamicLinks": <enforce> }]
1818
...
1919
```
2020

21+
* allow-referrer: optional boolean. If `true` does not require `noreferrer`. Defaults to `false`.
2122
* enabled: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0.
2223
* enforce: optional string, 'always' or 'never'
2324

lib/rules/jsx-no-target-blank.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ function hasDynamicLink(element, linkAttribute) {
4040
attr.value.type === 'JSXExpressionContainer');
4141
}
4242

43-
function hasSecureRel(element) {
43+
function hasSecureRel(element, allowReferrer) {
4444
return element.attributes.find((attr) => {
4545
if (attr.type === 'JSXAttribute' && attr.name.name === 'rel') {
4646
const tags = attr.value && attr.value.type === 'Literal' && attr.value.value.toLowerCase().split(' ');
47-
return tags && (tags.indexOf('noopener') >= 0 && tags.indexOf('noreferrer') >= 0);
47+
return tags && (tags.indexOf('noopener') >= 0 && (allowReferrer || tags.indexOf('noreferrer') >= 0));
4848
}
4949
return false;
5050
});
@@ -61,6 +61,9 @@ module.exports = {
6161
schema: [{
6262
type: 'object',
6363
properties: {
64+
allowReferrer: {
65+
type: 'boolean'
66+
},
6467
enforceDynamicLinks: {
6568
enum: ['always', 'never']
6669
}
@@ -71,12 +74,17 @@ module.exports = {
7174

7275
create(context) {
7376
const configuration = context.options[0] || {};
77+
const allowReferrer = configuration.allowReferrer || false;
7478
const enforceDynamicLinks = configuration.enforceDynamicLinks || 'always';
7579
const components = linkComponentsUtil.getLinkComponents(context);
7680

7781
return {
7882
JSXAttribute(node) {
79-
if (!components.has(node.parent.name.name) || !isTargetBlank(node) || hasSecureRel(node.parent)) {
83+
if (
84+
!components.has(node.parent.name.name) ||
85+
!isTargetBlank(node) ||
86+
hasSecureRel(node.parent, allowReferrer)
87+
) {
8088
return;
8189
}
8290

tests/lib/rules/jsx-no-target-blank.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ ruleTester.run('jsx-no-target-blank', rule, {
6868
code: '<Link target="_blank" to={ dynamicLink }></Link>',
6969
options: [{enforceDynamicLinks: 'never'}],
7070
settings: {linkComponents: {name: 'Link', linkAttribute: 'to'}}
71+
},
72+
{
73+
code: '<a href="foobar" target="_blank" rel="noopener"></a>',
74+
options: [{allowReferrer: true}]
7175
}
7276
],
7377
invalid: [{

0 commit comments

Comments
 (0)