Skip to content

Commit d8cab63

Browse files
committed
refactor: move ProbeRunner to ASTAnalyser instead of SourceFile
1 parent bc62d3e commit d8cab63

File tree

4 files changed

+66
-66
lines changed

4 files changed

+66
-66
lines changed

.changeset/ten-tires-write.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nodesecure/js-x-ray": minor
3+
---
4+
5+
move ProbeRunner from SourceFile to AstAnalyser class

workspaces/js-x-ray/src/AstAnalyser.ts

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,18 @@ import type { ESTree } from "meriyah";
99
import isMinified from "is-minified-code";
1010

1111
// Import Internal Dependencies
12-
import { generateWarning, type Warning } from "./warnings.js";
12+
import {
13+
generateWarning,
14+
type Warning,
15+
type OptionalWarningName
16+
} from "./warnings.js";
1317
import {
1418
SourceFile,
15-
type ProbesOptions,
1619
type SourceFlags
1720
} from "./SourceFile.js";
1821
import { isOneLineExpressionExport } from "./utils/index.js";
1922
import { JsSourceParser, type SourceParser } from "./JsSourceParser.js";
23+
import { ProbeRunner, type Probe } from "./ProbeRunner.js";
2024

2125
export interface Dependency {
2226
unsafe: boolean;
@@ -63,11 +67,23 @@ export type ReportOnFile = {
6367
warnings: Warning[];
6468
};
6569

66-
export interface AstAnalyserOptions extends ProbesOptions {
70+
export interface AstAnalyserOptions {
6771
/**
6872
* @default JsSourceParser
6973
*/
7074
customParser?: SourceParser;
75+
/**
76+
* @default []
77+
*/
78+
customProbes?: Probe[];
79+
/**
80+
* @default false
81+
*/
82+
skipDefaultProbes?: boolean;
83+
/**
84+
* @default false
85+
*/
86+
optionalWarnings?: boolean | Iterable<OptionalWarningName>;
7187
}
7288

7389
export interface PrepareSourceOptions {
@@ -76,15 +92,40 @@ export interface PrepareSourceOptions {
7692

7793
export class AstAnalyser {
7894
parser: SourceParser;
79-
probesOptions: ProbesOptions;
95+
probes: Probe[];
8096

8197
constructor(options: AstAnalyserOptions = {}) {
98+
const {
99+
customProbes = [],
100+
optionalWarnings = false,
101+
skipDefaultProbes = false
102+
} = options;
103+
82104
this.parser = options.customParser ?? new JsSourceParser();
83-
this.probesOptions = {
84-
customProbes: options.customProbes ?? [],
85-
skipDefaultProbes: options.skipDefaultProbes ?? false,
86-
optionalWarnings: options.optionalWarnings ?? false
87-
};
105+
106+
let probes = ProbeRunner.Defaults;
107+
if (
108+
Array.isArray(customProbes) &&
109+
customProbes.length > 0
110+
) {
111+
probes = skipDefaultProbes === true ?
112+
customProbes :
113+
[...probes, ...customProbes];
114+
}
115+
116+
if (typeof optionalWarnings === "boolean") {
117+
if (optionalWarnings) {
118+
probes = [...probes, ...Object.values(ProbeRunner.Optionals)];
119+
}
120+
}
121+
else {
122+
const optionalProbes = Array.from(optionalWarnings ?? [])
123+
.flatMap((warning) => ProbeRunner.Optionals[warning] ?? []);
124+
125+
probes = [...probes, ...optionalProbes];
126+
}
127+
128+
this.probes = probes;
88129
}
89130

90131
analyse(
@@ -102,7 +143,8 @@ export class AstAnalyser {
102143
const body = this.parser.parse(this.prepareSource(str, { removeHTMLComments }), {
103144
isEcmaScriptModule: Boolean(module)
104145
});
105-
const source = new SourceFile(str, this.probesOptions);
146+
const source = new SourceFile(str);
147+
const runner = new ProbeRunner(source, this.probes);
106148

107149
// TODO: this check should be factorized in a way that we reuse it
108150
// on analyze and anlyseFile
@@ -116,13 +158,14 @@ export class AstAnalyser {
116158
// we walk each AST Nodes, this is a purely synchronous I/O
117159
// @ts-expect-error
118160
walk(body, {
119-
enter(node) {
161+
enter(node: any) {
120162
// Skip the root of the AST.
121163
if (Array.isArray(node)) {
122164
return;
123165
}
124166

125-
const action = source.walk(node as ESTree.Node);
167+
source.walk(node);
168+
const action = runner.walk(node);
126169
if (action === "skip") {
127170
this.skip();
128171
}
@@ -137,7 +180,7 @@ export class AstAnalyser {
137180
}
138181
finalize(source);
139182
}
140-
source.probesRunner.finalize();
183+
runner.finalize();
141184

142185
// Add oneline-require flag if this is a one-line require expression
143186
if (isOneLineExpressionExport(body)) {

workspaces/js-x-ray/src/SourceFile.ts

Lines changed: 3 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ import type { ESTree } from "meriyah";
77
import { rootLocation, toArrayLocation } from "./utils/index.js";
88
import {
99
generateWarning,
10-
type OptionalWarningName,
1110
type Warning
1211
} from "./warnings.js";
1312
import type { Dependency } from "./AstAnalyser.js";
14-
import { ProbeRunner, type Probe } from "./ProbeRunner.js";
1513
import { Deobfuscator } from "./Deobfuscator.js";
1614
import * as trojan from "./obfuscators/trojan-source.js";
1715

@@ -23,24 +21,8 @@ export type SourceFlags =
2321
| "oneline-require"
2422
| "is-minified";
2523

26-
export interface ProbesOptions {
27-
/**
28-
* @default []
29-
*/
30-
customProbes?: Probe[];
31-
/**
32-
* @default false
33-
*/
34-
skipDefaultProbes?: boolean;
35-
/**
36-
* @default false
37-
*/
38-
optionalWarnings?: boolean | Iterable<OptionalWarningName>;
39-
}
40-
4124
export class SourceFile {
42-
tracer: VariableTracer;
43-
probesRunner: ProbeRunner;
25+
tracer = new VariableTracer().enableDefaultTracing();
4426
inTryStatement = false;
4527
dependencyAutoWarning = false;
4628
deobfuscator = new Deobfuscator();
@@ -50,36 +32,8 @@ export class SourceFile {
5032
flags = new Set<SourceFlags>();
5133

5234
constructor(
53-
sourceCodeString: string,
54-
probesOptions: ProbesOptions = {}
35+
sourceCodeString: string
5536
) {
56-
this.tracer = new VariableTracer()
57-
.enableDefaultTracing();
58-
59-
let probes = ProbeRunner.Defaults;
60-
if (
61-
Array.isArray(probesOptions.customProbes) &&
62-
probesOptions.customProbes.length > 0
63-
) {
64-
probes = probesOptions.skipDefaultProbes === true ?
65-
probesOptions.customProbes :
66-
[...probes, ...probesOptions.customProbes];
67-
}
68-
69-
if (typeof probesOptions.optionalWarnings === "boolean") {
70-
if (probesOptions.optionalWarnings) {
71-
probes = [...probes, ...Object.values(ProbeRunner.Optionals)];
72-
}
73-
}
74-
else {
75-
const optionalProbes = Array.from(probesOptions.optionalWarnings ?? [])
76-
.flatMap((warning) => ProbeRunner.Optionals[warning] ?? []);
77-
78-
probes = [...probes, ...optionalProbes];
79-
}
80-
81-
this.probesRunner = new ProbeRunner(this, probes);
82-
8337
if (trojan.verify(sourceCodeString)) {
8438
this.warnings.push(
8539
generateWarning("obfuscated-code", { value: "trojan-source" })
@@ -203,7 +157,7 @@ export class SourceFile {
203157

204158
walk(
205159
node: ESTree.Node
206-
): null | "skip" {
160+
): void {
207161
this.tracer.walk(node);
208162
this.deobfuscator.walk(node);
209163

@@ -214,8 +168,6 @@ export class SourceFile {
214168
else if (node.type === "CatchClause") {
215169
this.inTryStatement = false;
216170
}
217-
218-
return this.probesRunner.walk(node);
219171
}
220172
}
221173

workspaces/js-x-ray/test/AstAnalyser.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import path from "node:path";
99
// Import Internal Dependencies
1010
import { AstAnalyser, JsSourceParser } from "../src/index.js";
1111
import { FakeSourceParser } from "./fixtures/FakeSourceParser.js";
12+
import { ProbeRunner } from "../src/ProbeRunner.js";
1213
import { SourceFile } from "../src/SourceFile.js";
1314
import {
1415
customProbes,
@@ -693,8 +694,7 @@ describe("AstAnalyser", () => {
693694
it("should instantiate with correct default options", () => {
694695
const analyser = new AstAnalyser();
695696
assert.ok(analyser.parser instanceof JsSourceParser);
696-
assert.deepStrictEqual(analyser.probesOptions.customProbes, []);
697-
assert.strictEqual(analyser.probesOptions.skipDefaultProbes, false);
697+
assert.deepStrictEqual(analyser.probes, ProbeRunner.Defaults);
698698
});
699699

700700
it("should properly instanciate default or custom parser (using analyseFile)", async(t) => {

0 commit comments

Comments
 (0)