@nodesecure/js-x-ray 4.4.0 → 4.5.0
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 +55 -26
- package/index.d.ts +140 -124
- package/index.js +25 -9
- package/package.json +57 -57
- package/src/ASTDeps.js +63 -55
- package/src/Analysis.js +153 -152
- package/src/constants.js +2 -1
- package/src/probes/index.js +68 -66
- 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 +33 -26
- package/src/probes/isLiteral.js +52 -47
- package/src/probes/isLiteralRegex.js +32 -27
- package/src/probes/isObjectExpression.js +29 -23
- package/src/probes/isRegexObject.js +43 -38
- package/src/probes/isUnaryExpression.js +26 -18
- package/src/probes/isUnsafeCallee.js +24 -19
- package/src/probes/isWeakCrypto.js +34 -0
- package/src/utils.js +188 -182
package/src/ASTDeps.js
CHANGED
|
@@ -1,55 +1,63 @@
|
|
|
1
|
-
|
|
2
|
-
export default class ASTDeps {
|
|
3
|
-
#inTry = false;
|
|
4
|
-
dependencies = Object.create(null);
|
|
5
|
-
|
|
6
|
-
get isInTryStmt() {
|
|
7
|
-
return this.#inTry;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
set isInTryStmt(value) {
|
|
11
|
-
if (typeof value !== "boolean") {
|
|
12
|
-
throw new TypeError("value must be a boolean!");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
this.#inTry = value;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
removeByName(name) {
|
|
19
|
-
if (Reflect.has(this.dependencies, name)) {
|
|
20
|
-
delete this.dependencies[name];
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
add(depName, location = null, unsafe = false) {
|
|
25
|
-
if (depName.trim() === "") {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const cleanDepName = depName.charAt(depName.length - 1) === "/" ? depName.slice(0, -1) : depName;
|
|
30
|
-
const dep = {
|
|
31
|
-
unsafe,
|
|
32
|
-
inTry: this.isInTryStmt
|
|
33
|
-
};
|
|
34
|
-
if (location !== null) {
|
|
35
|
-
dep.location = location;
|
|
36
|
-
}
|
|
37
|
-
this.dependencies[cleanDepName] = dep;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
*
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
1
|
+
|
|
2
|
+
export default class ASTDeps {
|
|
3
|
+
#inTry = false;
|
|
4
|
+
dependencies = Object.create(null);
|
|
5
|
+
|
|
6
|
+
get isInTryStmt() {
|
|
7
|
+
return this.#inTry;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
set isInTryStmt(value) {
|
|
11
|
+
if (typeof value !== "boolean") {
|
|
12
|
+
throw new TypeError("value must be a boolean!");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
this.#inTry = value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
removeByName(name) {
|
|
19
|
+
if (Reflect.has(this.dependencies, name)) {
|
|
20
|
+
delete this.dependencies[name];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
add(depName, location = null, unsafe = false) {
|
|
25
|
+
if (depName.trim() === "") {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const cleanDepName = depName.charAt(depName.length - 1) === "/" ? depName.slice(0, -1) : depName;
|
|
30
|
+
const dep = {
|
|
31
|
+
unsafe,
|
|
32
|
+
inTry: this.isInTryStmt
|
|
33
|
+
};
|
|
34
|
+
if (location !== null) {
|
|
35
|
+
dep.location = location;
|
|
36
|
+
}
|
|
37
|
+
this.dependencies[cleanDepName] = dep;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
has(depName) {
|
|
41
|
+
if (depName.trim() === "") {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return Reflect.has(this.dependencies, depName);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get size() {
|
|
49
|
+
return Object.keys(this.dependencies).length;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
* getDependenciesInTryStatement() {
|
|
53
|
+
for (const [depName, props] of Object.entries(this.dependencies)) {
|
|
54
|
+
if (props.inTry === true && props.unsafe === false) {
|
|
55
|
+
yield depName;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
* [Symbol.iterator]() {
|
|
61
|
+
yield* Object.keys(this.dependencies);
|
|
62
|
+
}
|
|
63
|
+
}
|
package/src/Analysis.js
CHANGED
|
@@ -1,152 +1,153 @@
|
|
|
1
|
-
// Import Third-party Dependencies
|
|
2
|
-
import { Utils, Literal } from "@nodesecure/sec-literal";
|
|
3
|
-
|
|
4
|
-
// Import Internal Dependencies
|
|
5
|
-
import { rootLocation, toArrayLocation, generateWarning } from "./utils.js";
|
|
6
|
-
import { warnings as _warnings, processMainModuleRequire } from "./constants.js";
|
|
7
|
-
import ASTDeps from "./ASTDeps.js";
|
|
8
|
-
import { isObfuscatedCode, hasTrojanSource } from "./obfuscators/index.js";
|
|
9
|
-
import { runOnProbes } from "./probes/index.js";
|
|
10
|
-
|
|
11
|
-
// CONSTANTS
|
|
12
|
-
const kDictionaryStrParts = [
|
|
13
|
-
"abcdefghijklmnopqrstuvwxyz",
|
|
14
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
15
|
-
"0123456789"
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
const kWarningsNameStr = Object.freeze({
|
|
19
|
-
[_warnings.parsingError]: "parsing-error",
|
|
20
|
-
[_warnings.unsafeImport]: "unsafe-import",
|
|
21
|
-
[_warnings.unsafeRegex]: "unsafe-regex",
|
|
22
|
-
[_warnings.unsafeStmt]: "unsafe-stmt",
|
|
23
|
-
[_warnings.unsafeAssign]: "unsafe-assign",
|
|
24
|
-
[_warnings.encodedLiteral]: "encoded-literal",
|
|
25
|
-
[_warnings.shortIdentifiers]: "short-identifiers",
|
|
26
|
-
[_warnings.suspiciousLiteral]: "suspicious-literal",
|
|
27
|
-
[_warnings.obfuscatedCode]: "obfuscated-code"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
this.
|
|
55
|
-
this.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
1
|
+
// Import Third-party Dependencies
|
|
2
|
+
import { Utils, Literal } from "@nodesecure/sec-literal";
|
|
3
|
+
|
|
4
|
+
// Import Internal Dependencies
|
|
5
|
+
import { rootLocation, toArrayLocation, generateWarning } from "./utils.js";
|
|
6
|
+
import { warnings as _warnings, processMainModuleRequire } from "./constants.js";
|
|
7
|
+
import ASTDeps from "./ASTDeps.js";
|
|
8
|
+
import { isObfuscatedCode, hasTrojanSource } from "./obfuscators/index.js";
|
|
9
|
+
import { runOnProbes } from "./probes/index.js";
|
|
10
|
+
|
|
11
|
+
// CONSTANTS
|
|
12
|
+
const kDictionaryStrParts = [
|
|
13
|
+
"abcdefghijklmnopqrstuvwxyz",
|
|
14
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
15
|
+
"0123456789"
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const kWarningsNameStr = Object.freeze({
|
|
19
|
+
[_warnings.parsingError]: "parsing-error",
|
|
20
|
+
[_warnings.unsafeImport]: "unsafe-import",
|
|
21
|
+
[_warnings.unsafeRegex]: "unsafe-regex",
|
|
22
|
+
[_warnings.unsafeStmt]: "unsafe-stmt",
|
|
23
|
+
[_warnings.unsafeAssign]: "unsafe-assign",
|
|
24
|
+
[_warnings.encodedLiteral]: "encoded-literal",
|
|
25
|
+
[_warnings.shortIdentifiers]: "short-identifiers",
|
|
26
|
+
[_warnings.suspiciousLiteral]: "suspicious-literal",
|
|
27
|
+
[_warnings.obfuscatedCode]: "obfuscated-code",
|
|
28
|
+
[_warnings.weakCrypto]: "weak-crypto"
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export default class Analysis {
|
|
32
|
+
hasDictionaryString = false;
|
|
33
|
+
hasPrefixedIdentifiers = false;
|
|
34
|
+
varkinds = { var: 0, let: 0, const: 0 };
|
|
35
|
+
idtypes = { assignExpr: 0, property: 0, variableDeclarator: 0, functionDeclaration: 0 };
|
|
36
|
+
counter = {
|
|
37
|
+
identifiers: 0,
|
|
38
|
+
doubleUnaryArray: 0,
|
|
39
|
+
computedMemberExpr: 0,
|
|
40
|
+
memberExpr: 0,
|
|
41
|
+
deepBinaryExpr: 0,
|
|
42
|
+
encodedArrayValue: 0,
|
|
43
|
+
morseLiteral: 0
|
|
44
|
+
};
|
|
45
|
+
identifiersName = [];
|
|
46
|
+
|
|
47
|
+
constructor() {
|
|
48
|
+
this.dependencies = new ASTDeps();
|
|
49
|
+
|
|
50
|
+
this.identifiers = new Map();
|
|
51
|
+
this.globalParts = new Map();
|
|
52
|
+
this.handledEncodedLiteralValues = new Map();
|
|
53
|
+
|
|
54
|
+
this.requireIdentifiers = new Set(["require", processMainModuleRequire]);
|
|
55
|
+
this.warnings = [];
|
|
56
|
+
this.literalScores = [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
addWarning(symbol, value, location = rootLocation()) {
|
|
60
|
+
if (symbol === _warnings.encodedLiteral && this.handledEncodedLiteralValues.has(value)) {
|
|
61
|
+
const index = this.handledEncodedLiteralValues.get(value);
|
|
62
|
+
this.warnings[index].location.push(toArrayLocation(location));
|
|
63
|
+
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const warningName = kWarningsNameStr[symbol];
|
|
67
|
+
this.warnings.push(generateWarning(warningName, { value, location }));
|
|
68
|
+
if (symbol === _warnings.encodedLiteral) {
|
|
69
|
+
this.handledEncodedLiteralValues.set(value, this.warnings.length - 1);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
analyzeSourceString(sourceString) {
|
|
74
|
+
if (hasTrojanSource(sourceString)) {
|
|
75
|
+
this.addWarning(_warnings.obfuscatedCode, "trojan-source");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
analyzeString(str) {
|
|
80
|
+
const score = Utils.stringSuspicionScore(str);
|
|
81
|
+
if (score !== 0) {
|
|
82
|
+
this.literalScores.push(score);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!this.hasDictionaryString) {
|
|
86
|
+
const isDictionaryStr = kDictionaryStrParts.every((word) => str.includes(word));
|
|
87
|
+
if (isDictionaryStr) {
|
|
88
|
+
this.hasDictionaryString = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Searching for morse string like "--.- --.--."
|
|
93
|
+
if (Utils.stringCharDiversity(str, ["\n"]) >= 3 && Utils.isMorse(str)) {
|
|
94
|
+
this.counter.morseLiteral++;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
analyzeLiteral(node, inArrayExpr = false) {
|
|
99
|
+
if (typeof node.value !== "string" || Utils.isSvg(node)) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
this.analyzeString(node.value);
|
|
103
|
+
|
|
104
|
+
const { hasHexadecimalSequence, hasUnicodeSequence, isBase64 } = Literal.defaultAnalysis(node);
|
|
105
|
+
if ((hasHexadecimalSequence || hasUnicodeSequence) && isBase64) {
|
|
106
|
+
if (inArrayExpr) {
|
|
107
|
+
this.counter.encodedArrayValue++;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.addWarning(_warnings.encodedLiteral, node.value, node.loc);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
getResult(isMinified) {
|
|
116
|
+
this.counter.identifiers = this.identifiersName.length;
|
|
117
|
+
const [isObfuscated, kind] = isObfuscatedCode(this);
|
|
118
|
+
if (isObfuscated) {
|
|
119
|
+
this.addWarning(_warnings.obfuscatedCode, kind || "unknown");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const identifiersLengthArr = this.identifiersName
|
|
123
|
+
.filter((value) => value.type !== "property" && typeof value.name === "string").map((value) => value.name.length);
|
|
124
|
+
|
|
125
|
+
const [idsLengthAvg, stringScore] = [sum(identifiersLengthArr), sum(this.literalScores)];
|
|
126
|
+
if (!isMinified && identifiersLengthArr.length > 5 && idsLengthAvg <= 1.5) {
|
|
127
|
+
this.addWarning(_warnings.shortIdentifiers, idsLengthAvg);
|
|
128
|
+
}
|
|
129
|
+
if (stringScore >= 3) {
|
|
130
|
+
this.addWarning(_warnings.suspiciousLiteral, stringScore);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return { idsLengthAvg, stringScore, warnings: this.warnings };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
walk(node) {
|
|
137
|
+
// Detect TryStatement and CatchClause to known which dependency is required in a Try {} clause
|
|
138
|
+
if (node.type === "TryStatement" && typeof node.handler !== "undefined") {
|
|
139
|
+
this.dependencies.isInTryStmt = true;
|
|
140
|
+
}
|
|
141
|
+
else if (node.type === "CatchClause") {
|
|
142
|
+
this.dependencies.isInTryStmt = false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return runOnProbes(node, this);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function sum(arr = []) {
|
|
150
|
+
return arr.length === 0 ? 0 : (arr.reduce((prev, curr) => prev + curr, 0) / arr.length);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
Analysis.Warnings = _warnings;
|
package/src/constants.js
CHANGED
|
@@ -43,5 +43,6 @@ export const warnings = Object.freeze({
|
|
|
43
43
|
encodedLiteral: Symbol("EncodedLiteral"),
|
|
44
44
|
shortIdentifiers: Symbol("ShortIdentifiers"),
|
|
45
45
|
suspiciousLiteral: Symbol("SuspiciousLiteral"),
|
|
46
|
-
obfuscatedCode: Symbol("ObfuscatedCode")
|
|
46
|
+
obfuscatedCode: Symbol("ObfuscatedCode"),
|
|
47
|
+
weakCrypto: Symbol("WeakCrypto")
|
|
47
48
|
});
|
package/src/probes/index.js
CHANGED
|
@@ -1,66 +1,68 @@
|
|
|
1
|
-
// Import all the probes
|
|
2
|
-
import isUnsafeCallee from "./isUnsafeCallee.js";
|
|
3
|
-
import isLiteral from "./isLiteral.js";
|
|
4
|
-
import isLiteralRegex from "./isLiteralRegex.js";
|
|
5
|
-
import isRegexObject from "./isRegexObject.js";
|
|
6
|
-
import isVariableDeclaration from "./isVariableDeclaration.js";
|
|
7
|
-
import isAssignmentExprOrMemberExpr from "./isAssignmentExprOrMemberExpr.js";
|
|
8
|
-
import isRequire from "./isRequire.js";
|
|
9
|
-
import isImportDeclaration from "./isImportDeclaration.js";
|
|
10
|
-
import isMemberExpression from "./isMemberExpression.js";
|
|
11
|
-
import isArrayExpression from "./isArrayExpression.js";
|
|
12
|
-
import isFunctionDeclaration from "./isFunctionDeclaration.js";
|
|
13
|
-
import isAssignmentExpression from "./isAssignmentExpression.js";
|
|
14
|
-
import isObjectExpression from "./isObjectExpression.js";
|
|
15
|
-
import isUnaryExpression from "./isUnaryExpression.js";
|
|
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
|
-
|
|
1
|
+
// Import all the probes
|
|
2
|
+
import isUnsafeCallee from "./isUnsafeCallee.js";
|
|
3
|
+
import isLiteral from "./isLiteral.js";
|
|
4
|
+
import isLiteralRegex from "./isLiteralRegex.js";
|
|
5
|
+
import isRegexObject from "./isRegexObject.js";
|
|
6
|
+
import isVariableDeclaration from "./isVariableDeclaration.js";
|
|
7
|
+
import isAssignmentExprOrMemberExpr from "./isAssignmentExprOrMemberExpr.js";
|
|
8
|
+
import isRequire from "./isRequire.js";
|
|
9
|
+
import isImportDeclaration from "./isImportDeclaration.js";
|
|
10
|
+
import isMemberExpression from "./isMemberExpression.js";
|
|
11
|
+
import isArrayExpression from "./isArrayExpression.js";
|
|
12
|
+
import isFunctionDeclaration from "./isFunctionDeclaration.js";
|
|
13
|
+
import isAssignmentExpression from "./isAssignmentExpression.js";
|
|
14
|
+
import isObjectExpression from "./isObjectExpression.js";
|
|
15
|
+
import isUnaryExpression from "./isUnaryExpression.js";
|
|
16
|
+
import isWeakCrypto from "./isWeakCrypto.js";
|
|
17
|
+
|
|
18
|
+
// CONSTANTS
|
|
19
|
+
const kListOfProbes = [
|
|
20
|
+
isUnsafeCallee,
|
|
21
|
+
isLiteral,
|
|
22
|
+
isLiteralRegex,
|
|
23
|
+
isRegexObject,
|
|
24
|
+
isVariableDeclaration,
|
|
25
|
+
isAssignmentExprOrMemberExpr,
|
|
26
|
+
isRequire,
|
|
27
|
+
isImportDeclaration,
|
|
28
|
+
isMemberExpression,
|
|
29
|
+
isAssignmentExpression,
|
|
30
|
+
isObjectExpression,
|
|
31
|
+
isArrayExpression,
|
|
32
|
+
isFunctionDeclaration,
|
|
33
|
+
isUnaryExpression,
|
|
34
|
+
isWeakCrypto
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const kSymBreak = Symbol.for("breakWalk");
|
|
38
|
+
const kSymSkip = Symbol.for("skipWalk");
|
|
39
|
+
|
|
40
|
+
export function runOnProbes(node, analysis) {
|
|
41
|
+
const breakedGroups = new Set();
|
|
42
|
+
|
|
43
|
+
for (const probe of kListOfProbes) {
|
|
44
|
+
if (breakedGroups.has(probe.breakGroup)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const [isMatching, data = null] = probe.validateNode(node, analysis);
|
|
49
|
+
if (isMatching) {
|
|
50
|
+
const result = probe.main(node, { analysis, data });
|
|
51
|
+
|
|
52
|
+
if (result === kSymSkip) {
|
|
53
|
+
return "skip";
|
|
54
|
+
}
|
|
55
|
+
if (result === kSymBreak || probe.breakOnMatch) {
|
|
56
|
+
const breakGroup = probe.breakGroup || null;
|
|
57
|
+
if (breakGroup === null) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
breakedGroups.add(breakGroup);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
@@ -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
|
+
};
|