88// Rule Definition
99// ------------------------------------------------------------------------------
1010
11+ function isTargetBlank ( attr ) {
12+ return attr . name . name === 'target' &&
13+ attr . value . type === 'Literal' &&
14+ attr . value . value . toLowerCase ( ) === '_blank' ;
15+ }
16+
17+ function hasExternalLink ( element ) {
18+ return element . attributes . find ( function ( attr ) {
19+ return attr . name &&
20+ attr . name . name === 'href' &&
21+ attr . value . type === 'Literal' &&
22+ / ^ (?: \w + : | \/ \/ ) / . test ( attr . value . value ) ;
23+ } ) ;
24+ }
25+
26+ function hasSecureRel ( element ) {
27+ return element . attributes . find ( function ( attr ) {
28+ if ( attr . name . name === 'rel' ) {
29+ var tags = attr . value . type === 'Literal' && attr . value . value . toLowerCase ( ) . split ( ' ' ) ;
30+ return ! tags || ( tags . indexOf ( 'noopener' ) >= 0 && tags . indexOf ( 'noreferrer' ) >= 0 ) ;
31+ }
32+ return false ;
33+ } ) ;
34+ }
35+
1136module . exports = {
1237 meta : {
1338 docs : {
@@ -26,38 +51,12 @@ module.exports = {
2651 }
2752
2853 if (
29- node . name . name === 'target' &&
30- node . value . type === 'Literal' &&
31- node . value . value . toLowerCase ( ) === '_blank'
54+ isTargetBlank ( node ) &&
55+ hasExternalLink ( node . parent ) &&
56+ ! hasSecureRel ( node . parent )
3257 ) {
33- var relFound = false ;
34- var attrs = node . parent . attributes ;
35- for ( var idx in attrs ) {
36- if ( ! Object . prototype . hasOwnProperty . call ( attrs , idx ) ) {
37- continue ;
38- }
39- var attr = attrs [ idx ] ;
40- if ( ! attr . name ) {
41- continue ;
42- }
43- if ( attr . name . name === 'href' ) {
44- if ( attr . value . type === 'Literal' && ! / ^ (?: \w + : | \/ \/ ) / . test ( attr . value . value ) ) {
45- // it's safe because it is not an external link (i.e. doesn't start with a protocol)
46- return ;
47- }
48- }
49- if ( attr . name . name === 'rel' ) {
50- var tags = attr . value . type === 'Literal' && attr . value . value . toLowerCase ( ) . split ( ' ' ) ;
51- if ( ! tags || ( tags . indexOf ( 'noopener' ) >= 0 && tags . indexOf ( 'noreferrer' ) >= 0 ) ) {
52- relFound = true ;
53- break ;
54- }
55- }
56- }
57- if ( ! relFound ) {
58- context . report ( node , 'Using target="_blank" without rel="noopener noreferrer" ' +
59- 'is a security risk: see https://mathiasbynens.github.io/rel-noopener' ) ;
60- }
58+ context . report ( node , 'Using target="_blank" without rel="noopener noreferrer" ' +
59+ 'is a security risk: see https://mathiasbynens.github.io/rel-noopener' ) ;
6160 }
6261 }
6362 } ;
0 commit comments