@nodesecure/js-x-ray 4.4.0 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -39
- package/index.d.ts +33 -123
- package/index.js +2 -40
- package/package.json +7 -6
- package/src/ASTDeps.js +63 -55
- package/src/Analysis.js +140 -152
- package/src/constants.js +0 -12
- package/src/probes/index.js +3 -1
- package/src/probes/isArrayExpression.js +27 -21
- package/src/probes/isAssignmentExpression.js +29 -22
- package/src/probes/isBinaryExpression.js +53 -39
- package/src/probes/isFunctionDeclaration.js +27 -20
- package/src/probes/isImportDeclaration.js +30 -26
- package/src/probes/isLiteral.js +52 -47
- package/src/probes/isLiteralRegex.js +31 -27
- package/src/probes/isObjectExpression.js +29 -23
- package/src/probes/isRegexObject.js +42 -38
- package/src/probes/isRequire.js +159 -160
- package/src/probes/isUnaryExpression.js +26 -18
- package/src/probes/isUnsafeCallee.js +23 -19
- package/src/probes/isVariableDeclaration.js +104 -104
- package/src/probes/isWeakCrypto.js +31 -0
- package/src/utils.js +166 -182
- package/src/warnings.js +70 -0
- package/types/api.d.ts +44 -0
- package/types/astdeps.d.ts +30 -0
- package/types/warnings.d.ts +33 -0
package/src/Analysis.js
CHANGED
|
@@ -1,152 +1,140 @@
|
|
|
1
|
-
// Import Third-party Dependencies
|
|
2
|
-
import { Utils, Literal } from "@nodesecure/sec-literal";
|
|
3
|
-
|
|
4
|
-
// Import Internal Dependencies
|
|
5
|
-
import { rootLocation, toArrayLocation
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this.dependencies.isInTryStmt = false;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return runOnProbes(node, this);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function sum(arr = []) {
|
|
149
|
-
return arr.length === 0 ? 0 : (arr.reduce((prev, curr) => prev + curr, 0) / arr.length);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
Analysis.Warnings = _warnings;
|
|
1
|
+
// Import Third-party Dependencies
|
|
2
|
+
import { Utils, Literal } from "@nodesecure/sec-literal";
|
|
3
|
+
|
|
4
|
+
// Import Internal Dependencies
|
|
5
|
+
import { rootLocation, toArrayLocation } from "./utils.js";
|
|
6
|
+
import { generateWarning } from "./warnings.js";
|
|
7
|
+
import { processMainModuleRequire } from "./constants.js";
|
|
8
|
+
import ASTDeps from "./ASTDeps.js";
|
|
9
|
+
import { isObfuscatedCode, hasTrojanSource } from "./obfuscators/index.js";
|
|
10
|
+
import { runOnProbes } from "./probes/index.js";
|
|
11
|
+
|
|
12
|
+
// CONSTANTS
|
|
13
|
+
const kDictionaryStrParts = [
|
|
14
|
+
"abcdefghijklmnopqrstuvwxyz",
|
|
15
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
16
|
+
"0123456789"
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export default class Analysis {
|
|
20
|
+
hasDictionaryString = false;
|
|
21
|
+
hasPrefixedIdentifiers = false;
|
|
22
|
+
varkinds = { var: 0, let: 0, const: 0 };
|
|
23
|
+
idtypes = { assignExpr: 0, property: 0, variableDeclarator: 0, functionDeclaration: 0 };
|
|
24
|
+
counter = {
|
|
25
|
+
identifiers: 0,
|
|
26
|
+
doubleUnaryArray: 0,
|
|
27
|
+
computedMemberExpr: 0,
|
|
28
|
+
memberExpr: 0,
|
|
29
|
+
deepBinaryExpr: 0,
|
|
30
|
+
encodedArrayValue: 0,
|
|
31
|
+
morseLiteral: 0
|
|
32
|
+
};
|
|
33
|
+
identifiersName = [];
|
|
34
|
+
|
|
35
|
+
constructor() {
|
|
36
|
+
this.dependencies = new ASTDeps();
|
|
37
|
+
|
|
38
|
+
this.identifiers = new Map();
|
|
39
|
+
this.globalParts = new Map();
|
|
40
|
+
this.handledEncodedLiteralValues = new Map();
|
|
41
|
+
|
|
42
|
+
this.requireIdentifiers = new Set(["require", processMainModuleRequire]);
|
|
43
|
+
this.warnings = [];
|
|
44
|
+
this.literalScores = [];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
addWarning(name, value, location = rootLocation()) {
|
|
48
|
+
const isEncodedLiteral = name === "encoded-literal";
|
|
49
|
+
if (isEncodedLiteral && this.handledEncodedLiteralValues.has(value)) {
|
|
50
|
+
const index = this.handledEncodedLiteralValues.get(value);
|
|
51
|
+
this.warnings[index].location.push(toArrayLocation(location));
|
|
52
|
+
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.warnings.push(generateWarning(name, { value, location }));
|
|
57
|
+
if (isEncodedLiteral) {
|
|
58
|
+
this.handledEncodedLiteralValues.set(value, this.warnings.length - 1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
analyzeSourceString(sourceString) {
|
|
63
|
+
if (hasTrojanSource(sourceString)) {
|
|
64
|
+
this.addWarning("obfuscated-code", "trojan-source");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
analyzeString(str) {
|
|
69
|
+
const score = Utils.stringSuspicionScore(str);
|
|
70
|
+
if (score !== 0) {
|
|
71
|
+
this.literalScores.push(score);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!this.hasDictionaryString) {
|
|
75
|
+
const isDictionaryStr = kDictionaryStrParts.every((word) => str.includes(word));
|
|
76
|
+
if (isDictionaryStr) {
|
|
77
|
+
this.hasDictionaryString = true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Searching for morse string like "--.- --.--."
|
|
82
|
+
if (Utils.stringCharDiversity(str, ["\n"]) >= 3 && Utils.isMorse(str)) {
|
|
83
|
+
this.counter.morseLiteral++;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
analyzeLiteral(node, inArrayExpr = false) {
|
|
88
|
+
if (typeof node.value !== "string" || Utils.isSvg(node)) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
this.analyzeString(node.value);
|
|
92
|
+
|
|
93
|
+
const { hasHexadecimalSequence, hasUnicodeSequence, isBase64 } = Literal.defaultAnalysis(node);
|
|
94
|
+
if ((hasHexadecimalSequence || hasUnicodeSequence) && isBase64) {
|
|
95
|
+
if (inArrayExpr) {
|
|
96
|
+
this.counter.encodedArrayValue++;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
this.addWarning("encoded-literal", node.value, node.loc);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
getResult(isMinified) {
|
|
105
|
+
this.counter.identifiers = this.identifiersName.length;
|
|
106
|
+
const [isObfuscated, kind] = isObfuscatedCode(this);
|
|
107
|
+
if (isObfuscated) {
|
|
108
|
+
this.addWarning("obfuscated-code", kind || "unknown");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const identifiersLengthArr = this.identifiersName
|
|
112
|
+
.filter((value) => value.type !== "property" && typeof value.name === "string").map((value) => value.name.length);
|
|
113
|
+
|
|
114
|
+
const [idsLengthAvg, stringScore] = [sum(identifiersLengthArr), sum(this.literalScores)];
|
|
115
|
+
if (!isMinified && identifiersLengthArr.length > 5 && idsLengthAvg <= 1.5) {
|
|
116
|
+
this.addWarning("short-identifiers", idsLengthAvg);
|
|
117
|
+
}
|
|
118
|
+
if (stringScore >= 3) {
|
|
119
|
+
this.addWarning("suspicious-literal", stringScore);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return { idsLengthAvg, stringScore, warnings: this.warnings };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
walk(node) {
|
|
126
|
+
// Detect TryStatement and CatchClause to known which dependency is required in a Try {} clause
|
|
127
|
+
if (node.type === "TryStatement" && typeof node.handler !== "undefined") {
|
|
128
|
+
this.dependencies.isInTryStmt = true;
|
|
129
|
+
}
|
|
130
|
+
else if (node.type === "CatchClause") {
|
|
131
|
+
this.dependencies.isInTryStmt = false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return runOnProbes(node, this);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function sum(arr = []) {
|
|
139
|
+
return arr.length === 0 ? 0 : (arr.reduce((prev, curr) => prev + curr, 0) / arr.length);
|
|
140
|
+
}
|
package/src/constants.js
CHANGED
|
@@ -33,15 +33,3 @@ export const unsafeUnicodeControlCharacters = [
|
|
|
33
33
|
"\u200F",
|
|
34
34
|
"\u061C"
|
|
35
35
|
];
|
|
36
|
-
|
|
37
|
-
export const warnings = Object.freeze({
|
|
38
|
-
parsingError: Symbol("ParsingError"),
|
|
39
|
-
unsafeImport: Symbol("UnsafeImport"),
|
|
40
|
-
unsafeRegex: Symbol("UnsafeRegex"),
|
|
41
|
-
unsafeStmt: Symbol("UnsafeStmt"),
|
|
42
|
-
unsafeAssign: Symbol("UnsafeAssign"),
|
|
43
|
-
encodedLiteral: Symbol("EncodedLiteral"),
|
|
44
|
-
shortIdentifiers: Symbol("ShortIdentifiers"),
|
|
45
|
-
suspiciousLiteral: Symbol("SuspiciousLiteral"),
|
|
46
|
-
obfuscatedCode: Symbol("ObfuscatedCode")
|
|
47
|
-
});
|
package/src/probes/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import isFunctionDeclaration from "./isFunctionDeclaration.js";
|
|
|
13
13
|
import isAssignmentExpression from "./isAssignmentExpression.js";
|
|
14
14
|
import isObjectExpression from "./isObjectExpression.js";
|
|
15
15
|
import isUnaryExpression from "./isUnaryExpression.js";
|
|
16
|
+
import isWeakCrypto from "./isWeakCrypto.js";
|
|
16
17
|
|
|
17
18
|
// CONSTANTS
|
|
18
19
|
const kListOfProbes = [
|
|
@@ -29,7 +30,8 @@ const kListOfProbes = [
|
|
|
29
30
|
isObjectExpression,
|
|
30
31
|
isArrayExpression,
|
|
31
32
|
isFunctionDeclaration,
|
|
32
|
-
isUnaryExpression
|
|
33
|
+
isUnaryExpression,
|
|
34
|
+
isWeakCrypto
|
|
33
35
|
];
|
|
34
36
|
|
|
35
37
|
const kSymBreak = Symbol.for("breakWalk");
|
|
@@ -1,21 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @description Search for ArrayExpression AST Node (Commonly known as JS Arrays)
|
|
3
|
+
*
|
|
4
|
+
* @see https://github.com/estree/estree/blob/master/es5.md#arrayexpression
|
|
5
|
+
* @example
|
|
6
|
+
* ["foo", "bar", 1]
|
|
7
|
+
*/
|
|
8
|
+
function validateNode(node) {
|
|
9
|
+
return [
|
|
10
|
+
node.type === "ArrayExpression"
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function main(node, options) {
|
|
15
|
+
const { analysis } = options;
|
|
16
|
+
|
|
17
|
+
for (const elem of node.elements) {
|
|
18
|
+
if (elem !== null && elem.type === "Literal") {
|
|
19
|
+
analysis.analyzeLiteral(elem, true);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
name: "isArrayExpression",
|
|
26
|
+
validateNode, main, breakOnMatch: false
|
|
27
|
+
};
|
|
@@ -1,22 +1,29 @@
|
|
|
1
|
-
// Import Internal Dependencies
|
|
2
|
-
import { getIdName } from "../utils.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
1
|
+
// Import Internal Dependencies
|
|
2
|
+
import { getIdName } from "../utils.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @description Search for AssignmentExpression (Not to be confused with AssignmentPattern).
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/estree/estree/blob/master/es5.md#assignmentexpression
|
|
8
|
+
* @example
|
|
9
|
+
* (foo = 5)
|
|
10
|
+
*/
|
|
11
|
+
function validateNode(node) {
|
|
12
|
+
return [
|
|
13
|
+
node.type === "AssignmentExpression"
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function main(node, options) {
|
|
18
|
+
const { analysis } = options;
|
|
19
|
+
|
|
20
|
+
analysis.idtypes.assignExpr++;
|
|
21
|
+
for (const name of getIdName(node.left)) {
|
|
22
|
+
analysis.identifiersName.push({ name, type: "assignExpr" });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
name: "isAssignmentExpression",
|
|
28
|
+
validateNode, main, breakOnMatch: false
|
|
29
|
+
};
|
|
@@ -1,39 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @description Search for BinaryExpression AST Node.
|
|
3
|
+
*
|
|
4
|
+
* @see https://github.com/estree/estree/blob/master/es5.md#binaryexpression
|
|
5
|
+
* @example
|
|
6
|
+
* 5 + 5 + 10
|
|
7
|
+
*/
|
|
8
|
+
function validateNode(node) {
|
|
9
|
+
return [
|
|
10
|
+
node.type === "BinaryExpression"
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function main(node, options) {
|
|
15
|
+
const { analysis } = options;
|
|
16
|
+
|
|
17
|
+
const [binaryExprDeepness, hasUnaryExpression] = walkBinaryExpression(node);
|
|
18
|
+
if (binaryExprDeepness >= 3 && hasUnaryExpression) {
|
|
19
|
+
analysis.counter.deepBinaryExpr++;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @description Look for suspicious BinaryExpression (read the Obfuscator.io section of the linked G.Doc)
|
|
25
|
+
* @see https://docs.google.com/document/d/11ZrfW0bDQ-kd7Gr_Ixqyk8p3TGvxckmhFH3Z8dFoPhY/edit?usp=sharing
|
|
26
|
+
* @see https://github.com/estree/estree/blob/master/es5.md#unaryexpression
|
|
27
|
+
* @example
|
|
28
|
+
* 0x1*-0x12df+-0x1fb9*-0x1+0x2*-0x66d
|
|
29
|
+
*/
|
|
30
|
+
function walkBinaryExpression(expr, level = 1) {
|
|
31
|
+
const [lt, rt] = [expr.left.type, expr.right.type];
|
|
32
|
+
let hasUnaryExpression = lt === "UnaryExpression" || rt === "UnaryExpression";
|
|
33
|
+
let currentLevel = lt === "BinaryExpression" || rt === "BinaryExpression" ? level + 1 : level;
|
|
34
|
+
|
|
35
|
+
for (const currExpr of [expr.left, expr.right]) {
|
|
36
|
+
if (currExpr.type === "BinaryExpression") {
|
|
37
|
+
const [deepLevel, deepHasUnaryExpression] = walkBinaryExpression(currExpr, currentLevel);
|
|
38
|
+
if (deepLevel > currentLevel) {
|
|
39
|
+
currentLevel = deepLevel;
|
|
40
|
+
}
|
|
41
|
+
if (!hasUnaryExpression && deepHasUnaryExpression) {
|
|
42
|
+
hasUnaryExpression = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return [currentLevel, hasUnaryExpression];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default {
|
|
51
|
+
name: "isBinaryExpression",
|
|
52
|
+
validateNode, main, breakOnMatch: false
|
|
53
|
+
};
|
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @description Search for FunctionDeclaration AST Node.
|
|
3
|
+
*
|
|
4
|
+
* @see https://github.com/estree/estree/blob/master/es5.md#functiondeclaration
|
|
5
|
+
* @example
|
|
6
|
+
* function foo() {}
|
|
7
|
+
*/
|
|
8
|
+
function validateNode(node) {
|
|
9
|
+
return [
|
|
10
|
+
node.type === "FunctionDeclaration"
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function main(node, options) {
|
|
15
|
+
const { analysis } = options;
|
|
16
|
+
|
|
17
|
+
if (node.id === null || node.id.type !== "Identifier") {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
analysis.idtypes.functionDeclaration++;
|
|
21
|
+
analysis.identifiersName.push({ name: node.id.name, type: "functionDeclaration" });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
name: "isFunctionDeclaration",
|
|
26
|
+
validateNode, main, breakOnMatch: false
|
|
27
|
+
};
|
|
@@ -1,26 +1,30 @@
|
|
|
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
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @description Search for ESM ImportDeclaration
|
|
3
|
+
* @see https://github.com/estree/estree/blob/master/es2015.md#importdeclaration
|
|
4
|
+
* @example
|
|
5
|
+
* import * as foo from "bar";
|
|
6
|
+
* import fs from "fs";
|
|
7
|
+
* import "make-promises-safe";
|
|
8
|
+
*/
|
|
9
|
+
function validateNode(node) {
|
|
10
|
+
return [
|
|
11
|
+
// Note: the source property is the right-side Literal part of the Import
|
|
12
|
+
node.type === "ImportDeclaration" && node.source.type === "Literal"
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function main(node, options) {
|
|
17
|
+
const { analysis } = options;
|
|
18
|
+
|
|
19
|
+
// Searching for dangerous import "data:text/javascript;..." statement.
|
|
20
|
+
// see: https://2ality.com/2019/10/eval-via-import.html
|
|
21
|
+
if (node.source.value.startsWith("data:text/javascript")) {
|
|
22
|
+
analysis.addWarning("unsafe-import", node.source.value, node.loc);
|
|
23
|
+
}
|
|
24
|
+
analysis.dependencies.add(node.source.value, node.loc);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default {
|
|
28
|
+
name: "isImportDeclaration",
|
|
29
|
+
validateNode, main, breakOnMatch: true, breakGroup: "import"
|
|
30
|
+
};
|