From 901f01b48b76e1db58cd4f8e2c49f8c8ffade143 Mon Sep 17 00:00:00 2001 From: tchapacan Date: Mon, 11 Mar 2024 18:26:52 +0100 Subject: [PATCH] start refacto options param --- index.js | 6 ++-- src/AstAnalyser.js | 10 +++--- src/SourceFile.js | 13 +++---- test/AstAnalyser.spec.js | 8 ++++- test/issues/221-inject-custom-probes.spec.js | 22 ++++++++++-- test/utils/index.js | 3 +- types/api.d.ts | 38 +++++++++++++++++--- 7 files changed, 75 insertions(+), 25 deletions(-) diff --git a/index.js b/index.js index f6cfbec..0ea9988 100644 --- a/index.js +++ b/index.js @@ -9,10 +9,11 @@ function runASTAnalysis( ) { const { customParser = new JsSourceParser(), + astOptions = { isReplacing: false, customProbe: [] }, ...opts } = options; - const analyser = new AstAnalyser(customParser); + const analyser = new AstAnalyser(customParser, options.astOptions); return analyser.analyse(str, opts); } @@ -23,10 +24,11 @@ async function runASTAnalysisOnFile( ) { const { customParser = new JsSourceParser(), + astOptions = { isReplacing: false, customProbe: [] }, ...opts } = options; - const analyser = new AstAnalyser(customParser); + const analyser = new AstAnalyser(customParser, options.astOptions); return analyser.analyseFile(pathToFile, opts); } diff --git a/src/AstAnalyser.js b/src/AstAnalyser.js index a279b71..9b5b994 100644 --- a/src/AstAnalyser.js +++ b/src/AstAnalyser.js @@ -14,12 +14,12 @@ import { JsSourceParser } from "./JsSourceParser.js"; export class AstAnalyser { /** * @constructor - * @param { SourceParser } [parser] + * @param {SourceParser} [parser] + * @param astOptions */ - constructor(parser = new JsSourceParser(), customProbes = [], mergeMode = "append") { + constructor(parser = new JsSourceParser(), astOptions = { isReplacing: false, customProbe: [] }) { this.parser = parser; - this.customProbes = customProbes; - this.mergeMode = mergeMode; + this.astOptions = astOptions; } analyse(str, options = Object.create(null)) { @@ -33,7 +33,7 @@ export class AstAnalyser { isEcmaScriptModule: Boolean(module) }); - const source = new SourceFile(str, this.customProbes, this.mergeMode); + const source = new SourceFile(str, this.astOptions); // we walk each AST Nodes, this is a purely synchronous I/O walk(body, { diff --git a/src/SourceFile.js b/src/SourceFile.js index 71bd3fb..a680e21 100644 --- a/src/SourceFile.js +++ b/src/SourceFile.js @@ -20,21 +20,18 @@ export class SourceFile { encodedLiterals = new Map(); warnings = []; - constructor(sourceCodeString, customProbes = [], mergeMode = "append") { + constructor(sourceCodeString, astOptions = { isReplacing: false, customProbes: [] }) { this.tracer = new VariableTracer() .enableDefaultTracing() .trace("crypto.createHash", { followConsecutiveAssignment: true, moduleName: "crypto" }); - let mergedProbes; - if (Array.isArray(customProbes) && customProbes.length > 0) { - mergedProbes = mergeMode === "replace" ? customProbes : [...ProbeRunner.Defaults, ...customProbes]; + let probes = ProbeRunner.Defaults; + if (Array.isArray(astOptions.customProbes) && astOptions.customProbes.length > 0) { + probes = astOptions.isReplacing === true ? astOptions.customProbes : [...probes, ...astOptions.customProbes]; } - else { - mergedProbes = ProbeRunner.Defaults; - } - this.probesRunner = new ProbeRunner(this, mergedProbes); + this.probesRunner = new ProbeRunner(this, probes); if (trojan.verify(sourceCodeString)) { this.addWarning("obfuscated-code", "trojan-source"); diff --git a/test/AstAnalyser.spec.js b/test/AstAnalyser.spec.js index 3b792c3..f65c3f5 100644 --- a/test/AstAnalyser.spec.js +++ b/test/AstAnalyser.spec.js @@ -206,7 +206,7 @@ describe("AstAnalyser", (t) => { const preparedSource = getAnalyser().prepareSource(` `, { @@ -236,6 +236,12 @@ describe("AstAnalyser", (t) => { assert.deepEqual([...result.dependencies.keys()], []); }); }); + + it("should instantiate with correct default ASTOptions", () => { + const analyser = new AstAnalyser(); + assert.strictEqual(analyser.astOptions.isReplacing, false); + assert.deepStrictEqual(analyser.astOptions.customProbe, []); + }); }); }); diff --git a/test/issues/221-inject-custom-probes.spec.js b/test/issues/221-inject-custom-probes.spec.js index ce60bac..779ea54 100644 --- a/test/issues/221-inject-custom-probes.spec.js +++ b/test/issues/221-inject-custom-probes.spec.js @@ -6,6 +6,7 @@ import assert from "node:assert"; import { JsSourceParser } from "../../src/JsSourceParser.js"; import { AstAnalyser } from "../../src/AstAnalyser.js"; import { ProbeSignals } from "../../src/ProbeRunner.js"; +import { runASTAnalysis } from "../../index.js"; /** * @see https://github.com/NodeSecure/js-x-ray/issues/221 @@ -37,7 +38,7 @@ const customProbes = [ ]; test("should append to list of probes (default)", () => { - const analyser = new AstAnalyser(new JsSourceParser(), customProbes); + const analyser = new AstAnalyser(new JsSourceParser(), { customProbes }); const result = analyser.analyse(kIncriminedCodeSample); assert.equal(result.warnings[0].kind, kWarningUnsafeDanger); @@ -47,9 +48,26 @@ test("should append to list of probes (default)", () => { }); test("should replace list of probes", () => { - const analyser = new AstAnalyser(new JsSourceParser(), customProbes, "replace"); + const analyser = new AstAnalyser(new JsSourceParser(), { customProbes, isReplacing: true }); const result = analyser.analyse(kIncriminedCodeSample); assert.equal(result.warnings[0].kind, kWarningUnsafeDanger); assert.equal(result.warnings.length, 1); }); + + +test("should append list of probes using runASTAnalysis", () => { + const result = runASTAnalysis(kIncriminedCodeSample, { astOptions: { isReplacing: false, customProbes } }); + + assert.equal(result.warnings[0].kind, kWarningUnsafeDanger); + assert.equal(result.warnings[1].kind, kWarningUnsafeImport); + assert.equal(result.warnings[2].kind, kWarningUnsafeStmt); + assert.equal(result.warnings.length, 3); +}); + +test("should replace list of probes using runASTAnalysis", () => { + const result = runASTAnalysis(kIncriminedCodeSample, { astOptions: { isReplacing: true, customProbes } }); + + assert.equal(result.warnings[0].kind, kWarningUnsafeDanger); + assert.equal(result.warnings.length, 1); +}); diff --git a/test/utils/index.js b/test/utils/index.js index eb0873a..b6a170e 100644 --- a/test/utils/index.js +++ b/test/utils/index.js @@ -38,8 +38,7 @@ export function getSastAnalysis( return this.sourceFile.dependencies; }, execute(body) { - const probes = Array.isArray(probe) ? probe : [probe]; - const probeRunner = new ProbeRunner(this.sourceFile, probes); + const probeRunner = new ProbeRunner(this.sourceFile, [probe]); const self = this; walk(body, { diff --git a/types/api.d.ts b/types/api.d.ts index f81ea66..922e098 100644 --- a/types/api.d.ts +++ b/types/api.d.ts @@ -1,5 +1,6 @@ import { Warning } from "./warnings.js"; import { Statement } from "meriyah/dist/src/estree.js"; +import {validateFunctionName} from "meriyah/dist/src/common"; export { AstAnalyser, @@ -34,6 +35,17 @@ interface Dependency { location?: null | SourceLocation; } +interface RootOptions { + /** + * @default ASTOptions + */ + ASTOptions?: ASTOptions; + /** + * @default RuntimeOptions + */ + RuntimeOptions?: RuntimeOptions; +} + interface RuntimeOptions { /** * @default true @@ -47,10 +59,26 @@ interface RuntimeOptions { * @default false */ removeHTMLComments?: boolean; - + customParser?: SourceParser; } +interface ASTOptions { + /** + * @default false + */ + isReplacing?: boolean; + /** + * @default [] + */ + customParser?: Probe[] | null; +} + +interface Probe { + validate: Function[] | Function; + main: Function[] | Function; +} + interface Report { dependencies: Map; warnings: Warning[]; @@ -74,14 +102,14 @@ type ReportOnFile = { } interface SourceParser { - parse(source: string, options: unknown): Statement[]; + parse(source: string, astOptions: ASTOptions): Statement[]; } declare class AstAnalyser { - constructor(parser?: SourceParser); + constructor(parser?: SourceParser, options?: ASTOptions); analyse: (str: string, options?: Omit) => Report; analyzeFile(pathToFile: string, options?: Omit): Promise; } -declare function runASTAnalysis(str: string, options?: RuntimeOptions): Report; -declare function runASTAnalysisOnFile(pathToFile: string, options?: RuntimeFileOptions): Promise; +declare function runASTAnalysis(str: string, options?: RootOptions): Report; +declare function runASTAnalysisOnFile(pathToFile: string, options?: RootOptions): Promise;