forked from vuejs/eslint-plugin-vue
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathno-template-target-blank.js
111 lines (99 loc) · 3.04 KB
/
no-template-target-blank.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
* @fileoverview disallow target="_blank" attribute without rel="noopener noreferrer"
* @author Sosukesuzuki
*/
'use strict'
// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------
const utils = require('../utils')
// ------------------------------------------------------------------------------
// Helpers
// ------------------------------------------------------------------------------
function isTargetBlank (node) {
return node.key &&
node.key.name === 'target' &&
node.value &&
node.value.value === '_blank'
}
function hasSecureRel (node, allowReferrer) {
return node.attributes.some(attr => {
if (attr.key && attr.key.name === 'rel') {
const tags = attr.value && attr.value.value.toLowerCase().split(' ')
return tags &&
tags.includes('noopener') &&
(allowReferrer || tags.includes('noreferrer'))
} else {
return false
}
})
}
function hasExternalLink (node) {
return node.attributes.some(attr =>
attr.key &&
attr.key.name === 'href' &&
attr.value && /^(?:\w+:|\/\/)/.test(attr.value.value)
)
}
function hasDynamicLink (node) {
return node.attributes.some(attr =>
attr.key &&
attr.key.type === 'VDirectiveKey' &&
attr.key.name &&
attr.key.name.name === 'bind' &&
attr.key.argument &&
attr.key.argument.name === 'href'
)
}
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
module.exports = {
meta: {
type: 'problem',
docs: {
description:
'disallow target="_blank" attribute without rel="noopener noreferrer"',
categories: undefined,
url: 'https://eslint.vuejs.org/rules/no-template-target-blank.html'
},
schema: [{
type: 'object',
properties: {
allowReferrer: {
type: 'boolean'
},
enforceDynamicLinks: {
enum: ['always', 'never']
}
},
additionalProperties: false
}]
},
/**
* Creates AST event handlers for no-template-target-blank
*
* @param {RuleContext} context - The rule context.
* @returns {Object} AST event handlers.
*/
create (context) {
const configuration = context.options[0] || {}
const allowReferrer = configuration.allowReferrer || false
const enforceDynamicLinks = configuration.enforceDynamicLinks || 'always'
return utils.defineTemplateBodyVisitor(context, {
'VAttribute' (node) {
if (!isTargetBlank(node) || hasSecureRel(node.parent, allowReferrer)) {
return
}
const hasDangerHref = hasExternalLink(node.parent) ||
(enforceDynamicLinks === 'always' && hasDynamicLink(node.parent))
if (hasDangerHref) {
context.report({
node,
message: 'Using target="_blank" without rel="noopener noreferrer" is a security risk.'
})
}
}
})
}
}