12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- /**
- * @fileoverview Forbid target='_blank' attribute
- * @author Kevin Miller
- */
- 'use strict';
- const docsUrl = require('../util/docsUrl');
- // ------------------------------------------------------------------------------
- // Rule Definition
- // ------------------------------------------------------------------------------
- function isTargetBlank(attr) {
- return attr.name.name === 'target' &&
- attr.value.type === 'Literal' &&
- attr.value.value.toLowerCase() === '_blank';
- }
- function hasExternalLink(element) {
- return element.attributes.some(attr => attr.name &&
- attr.name.name === 'href' &&
- attr.value.type === 'Literal' &&
- /^(?:\w+:|\/\/)/.test(attr.value.value));
- }
- function hasDynamicLink(element) {
- return element.attributes.some(attr => attr.name &&
- attr.name.name === 'href' &&
- attr.value.type === 'JSXExpressionContainer');
- }
- function hasSecureRel(element) {
- 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 false;
- });
- }
- module.exports = {
- meta: {
- docs: {
- description: 'Forbid target="_blank" attribute without rel="noopener noreferrer"',
- category: 'Best Practices',
- recommended: true,
- url: docsUrl('jsx-no-target-blank')
- },
- schema: [{
- type: 'object',
- properties: {
- enforceDynamicLinks: {
- enum: ['always', 'never']
- }
- },
- additionalProperties: false
- }]
- },
- create: function(context) {
- const configuration = context.options[0] || {};
- const enforceDynamicLinks = configuration.enforceDynamicLinks || 'always';
- return {
- JSXAttribute: function(node) {
- if (node.parent.name.name !== 'a' || !isTargetBlank(node) || hasSecureRel(node.parent)) {
- return;
- }
- if (hasExternalLink(node.parent) || (enforceDynamicLinks === 'always' && hasDynamicLink(node.parent))) {
- context.report(node, 'Using target="_blank" without rel="noopener noreferrer" ' +
- 'is a security risk: see https://mathiasbynens.github.io/rel-noopener');
- }
- }
- };
- }
- };
|