Skip to content

Commit 0886544

Browse files
authored
no-document-cookie: Check window.document.cookie (#1833)
1 parent 9ed08ab commit 0886544

5 files changed

+118
-39
lines changed

rules/no-document-cookie.js

+6-22
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,20 @@
11
'use strict';
2-
const {getPropertyName} = require('eslint-utils');
2+
const {GlobalReferenceTracker} = require('./utils/global-reference-tracker.js');
33

44
const MESSAGE_ID = 'no-document-cookie';
55
const messages = {
66
[MESSAGE_ID]: 'Do not use `document.cookie` directly.',
77
};
88

9-
const selector = [
10-
'AssignmentExpression',
11-
'>',
12-
'MemberExpression.left',
13-
'[object.type="Identifier"]',
14-
'[object.name="document"]',
15-
].join('');
16-
17-
/** @param {import('eslint').Rule.RuleContext} context */
18-
const create = context => ({
19-
[selector](node) {
20-
if (getPropertyName(node, context.getScope()) !== 'cookie') {
21-
return;
22-
}
23-
24-
return {
25-
node,
26-
messageId: MESSAGE_ID,
27-
};
28-
},
9+
const tracker = new GlobalReferenceTracker({
10+
object: 'document.cookie',
11+
filter: ({node}) => node.parent.type === 'AssignmentExpression' && node.parent.left === node,
12+
handle: ({node}) => ({node, messageId: MESSAGE_ID}),
2913
});
3014

3115
/** @type {import('eslint').Rule.RuleModule} */
3216
module.exports = {
33-
create,
17+
create: context => tracker.createListeners(context),
3418
meta: {
3519
type: 'problem',
3620
docs: {
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'use strict';
2+
const {ReferenceTracker} = require('eslint-utils');
3+
4+
const createTraceMap = object => {
5+
let map = {[ReferenceTracker.READ]: true};
6+
7+
const path = object.split('.').reverse();
8+
for (const name of path) {
9+
map = {[name]: map};
10+
}
11+
12+
return map;
13+
};
14+
15+
class GlobalReferenceTracker {
16+
#traceMap = {};
17+
#filter;
18+
#handle;
19+
20+
constructor({
21+
object,
22+
objects = [object],
23+
filter,
24+
handle,
25+
}) {
26+
for (const object of objects) {
27+
Object.assign(this.#traceMap, createTraceMap(object));
28+
}
29+
30+
this.#filter = filter;
31+
this.#handle = handle;
32+
}
33+
34+
* track(globalScope) {
35+
const tracker = new ReferenceTracker(globalScope);
36+
37+
for (const reference of tracker.iterateGlobalReferences(this.#traceMap)) {
38+
if (this.#filter && !this.#filter(reference)) {
39+
continue;
40+
}
41+
42+
const problems = this.#handle(reference);
43+
44+
if (!problems) {
45+
continue;
46+
}
47+
48+
if (problems[Symbol.iterator]) {
49+
yield * problems;
50+
} else {
51+
yield problems;
52+
}
53+
}
54+
}
55+
56+
createListeners(context) {
57+
return {
58+
'Program:exit': () => this.track(context.getScope()),
59+
};
60+
}
61+
}
62+
63+
module.exports = {
64+
GlobalReferenceTracker,
65+
};

test/no-document-cookie.mjs

+8-6
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,21 @@ test.snapshot({
1515
'Object.assign(document, {cookie: "foo=bar"})',
1616
'document[CONSTANTS_COOKIE] = "foo=bar"',
1717
'document[cookie] = "foo=bar"',
18-
'var doc = document; doc.cookie = "foo=bar"',
19-
'window.document.cookie = "foo=bar"',
18+
outdent`
19+
const CONSTANTS_COOKIE = "cookie";
20+
document[CONSTANTS_COOKIE] = "foo=bar";
21+
`,
2022
],
2123
invalid: [
2224
'document.cookie = "foo=bar"',
2325
'document.cookie += ";foo=bar"',
2426
'document.cookie = document.cookie + ";foo=bar"',
2527
'document.cookie &&= true',
26-
outdent`
27-
const CONSTANTS_COOKIE = "cookie";
28-
document[CONSTANTS_COOKIE] = "foo=bar";
29-
`,
3028
'document["coo" + "kie"] = "foo=bar"',
3129
'foo = document.cookie = "foo=bar"',
30+
'var doc = document; doc.cookie = "foo=bar"',
31+
'let doc = document; doc.cookie = "foo=bar"',
32+
'const doc = globalThis.document; doc.cookie = "foo=bar"',
33+
'window.document.cookie = "foo=bar"',
3234
],
3335
});

test/snapshots/no-document-cookie.mjs.md

+39-11
Original file line numberDiff line numberDiff line change
@@ -45,33 +45,61 @@ Generated by [AVA](https://avajs.dev).
4545
`
4646

4747
## Invalid #5
48-
1 | const CONSTANTS_COOKIE = "cookie";
49-
2 | document[CONSTANTS_COOKIE] = "foo=bar";
48+
1 | document["coo" + "kie"] = "foo=bar"
5049

5150
> Error 1/1
5251
5352
`␊
54-
1 | const CONSTANTS_COOKIE = "cookie";␊
55-
> 2 | document[CONSTANTS_COOKIE] = "foo=bar";␊
56-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
53+
> 1 | document["coo" + "kie"] = "foo=bar"␊
54+
| ^^^^^^^^^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
5755
`
5856

5957
## Invalid #6
60-
1 | document["coo" + "kie"] = "foo=bar"
58+
1 | foo = document.cookie = "foo=bar"
6159

6260
> Error 1/1
6361
6462
`␊
65-
> 1 | document["coo" + "kie"] = "foo=bar"␊
66-
| ^^^^^^^^^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
63+
> 1 | foo = document.cookie = "foo=bar"␊
64+
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
6765
`
6866

6967
## Invalid #7
70-
1 | foo = document.cookie = "foo=bar"
68+
1 | var doc = document; doc.cookie = "foo=bar"
7169

7270
> Error 1/1
7371
7472
`␊
75-
> 1 | foo = document.cookie = "foo=bar"␊
76-
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
73+
> 1 | var doc = document; doc.cookie = "foo=bar"␊
74+
| ^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
75+
`
76+
77+
## Invalid #8
78+
1 | let doc = document; doc.cookie = "foo=bar"
79+
80+
> Error 1/1
81+
82+
`␊
83+
> 1 | let doc = document; doc.cookie = "foo=bar"␊
84+
| ^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
85+
`
86+
87+
## Invalid #9
88+
1 | const doc = globalThis.document; doc.cookie = "foo=bar"
89+
90+
> Error 1/1
91+
92+
`␊
93+
> 1 | const doc = globalThis.document; doc.cookie = "foo=bar"␊
94+
| ^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
95+
`
96+
97+
## Invalid #10
98+
1 | window.document.cookie = "foo=bar"
99+
100+
> Error 1/1
101+
102+
`␊
103+
> 1 | window.document.cookie = "foo=bar"␊
104+
| ^^^^^^^^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
77105
`
92 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)