Skip to content

Commit

Permalink
feat(no-target-blank): Configure noreferrer requirement
Browse files Browse the repository at this point in the history
  • Loading branch information
eps1lon committed Oct 30, 2019
1 parent 8093565 commit ef4ef2a
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 4 deletions.
3 changes: 2 additions & 1 deletion docs/rules/jsx-no-target-blank.md
Expand Up @@ -14,10 +14,11 @@ This rule aims to prevent user generated links from creating security vulnerabil
## Rule Options
```json
...
"react/jsx-no-target-blank": [<enabled>, { "enforceDynamicLinks": <enforce> }]
"react/jsx-no-target-blank": [<enabled>, { "allowReferrer": <allow-referrer>, "enforceDynamicLinks": <enforce> }]
...
```

* allow-referrer: 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.
* enforce: optional string, 'always' or 'never'

Expand Down
14 changes: 11 additions & 3 deletions lib/rules/jsx-no-target-blank.js
Expand Up @@ -40,11 +40,11 @@ function hasDynamicLink(element, linkAttribute) {
attr.value.type === 'JSXExpressionContainer');
}

function hasSecureRel(element) {
function hasSecureRel(element, allowReferrer) {
return element.attributes.find((attr) => {
if (attr.type === 'JSXAttribute' && attr.name.name === 'rel') {
const tags = attr.value && attr.value.type === 'Literal' && attr.value.value.toLowerCase().split(' ');
return tags && (tags.indexOf('noopener') >= 0 && tags.indexOf('noreferrer') >= 0);
return tags && (tags.indexOf('noopener') >= 0 && (allowReferrer || tags.indexOf('noreferrer') >= 0));
}
return false;
});
Expand All @@ -61,6 +61,9 @@ module.exports = {
schema: [{
type: 'object',
properties: {
allowReferrer: {
type: 'boolean'
},
enforceDynamicLinks: {
enum: ['always', 'never']
}
Expand All @@ -71,12 +74,17 @@ module.exports = {

create(context) {
const configuration = context.options[0] || {};
const allowReferrer = configuration.allowReferrer || false;
const enforceDynamicLinks = configuration.enforceDynamicLinks || 'always';
const components = linkComponentsUtil.getLinkComponents(context);

return {
JSXAttribute(node) {
if (!components.has(node.parent.name.name) || !isTargetBlank(node) || hasSecureRel(node.parent)) {
if (
!components.has(node.parent.name.name) ||
!isTargetBlank(node) ||
hasSecureRel(node.parent, allowReferrer)
) {
return;
}

Expand Down
4 changes: 4 additions & 0 deletions tests/lib/rules/jsx-no-target-blank.js
Expand Up @@ -68,6 +68,10 @@ ruleTester.run('jsx-no-target-blank', rule, {
code: '<Link target="_blank" to={ dynamicLink }></Link>',
options: [{enforceDynamicLinks: 'never'}],
settings: {linkComponents: {name: 'Link', linkAttribute: 'to'}}
},
{
code: '<a href="foobar" target="_blank" rel="noopener"></a>',
options: [{allowReferrer: true}]
}
],
invalid: [{
Expand Down

0 comments on commit ef4ef2a

Please sign in to comment.