@nodesecure/js-x-ray 4.3.0 → 4.4.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.
Files changed (4) hide show
  1. package/README.md +32 -0
  2. package/index.d.ts +124 -99
  3. package/index.js +125 -98
  4. package/package.json +4 -4
package/README.md CHANGED
@@ -73,6 +73,38 @@ The analysis will return: `http` (in try), `crypto`, `util` and `fs`.
73
73
 
74
74
  > ⚠️ There is also a lot of suspicious code example in the root cases directory. Feel free to try the tool on these files.
75
75
 
76
+ ## Warnings
77
+
78
+ This section describes how use `warnings` export.
79
+
80
+ The structure of the `warnings` is as follows:
81
+ ```
82
+ /**
83
+ * @property {object} warnings - The default values for Constants.
84
+ * @property {string} warnings[name] - The default warning name (parsingError, unsafeImport etc...).
85
+ * @property {string} warnings[name].i18n - i18n token.
86
+ * @property {string} warnings[name].code - Used to perform unit tests.
87
+ */
88
+
89
+ export const warnings = Object.freeze({
90
+ parsingError: {
91
+ i18n: "sast_warnings.ast_error"
92
+ code: "ast-error",
93
+ },
94
+ ...otherWarnings
95
+ });
96
+ ```
97
+
98
+ We make a call to `i18n` through the package `NodeSecure/i18n` to get the translation.
99
+
100
+ ```
101
+ import * as jsxray from "@nodesecure/js-x-ray";
102
+ import * as i18n from "@nodesecure/i18n";
103
+
104
+ console.log(i18n.getToken(jsxray.warnings.parsingError.i18n));
105
+
106
+ ```
107
+
76
108
  ## Warnings Legends (v2.0+)
77
109
 
78
110
  > Node-secure versions equal or lower than 0.7.0 are no longer compatible with the warnings table below.
package/index.d.ts CHANGED
@@ -1,99 +1,124 @@
1
- declare class ASTDeps {
2
- constructor();
3
- removeByName(name: string): void;
4
- add(depName: string): void;
5
- getDependenciesInTryStatement(): IterableIterator<string>;
6
-
7
- public isInTryStmt: boolean;
8
- public dependencies: Record<string, JSXRay.Dependency>;
9
- public readonly size: number;
10
- }
11
-
12
- declare namespace JSXRay {
13
- type kindWithValue = "parsing-error"
14
- | "encoded-literal"
15
- | "unsafe-regex"
16
- | "unsafe-stmt"
17
- | "unsafe-assign"
18
- | "short-identifiers"
19
- | "suspicious-literal"
20
- | "obfuscated-code";
21
-
22
- type WarningLocation = [[number, number], [number, number]];
23
- interface BaseWarning {
24
- kind: "unsafe-import" | kindWithValue;
25
- file?: string;
26
- value: string;
27
- location: WarningLocation | WarningLocation[];
28
- }
29
-
30
- type Warning<T extends BaseWarning> = T extends { kind: kindWithValue } ? T : Omit<T, "value">;
31
-
32
- interface Report {
33
- dependencies: ASTDeps;
34
- warnings: Warning<BaseWarning>[];
35
- idsLengthAvg: number;
36
- stringScore: number;
37
- isOneLineRequire: boolean;
38
- }
39
-
40
- interface SourceLocation {
41
- start: {
42
- line: number;
43
- column: number;
44
- };
45
- end: {
46
- line: number;
47
- column: number;
48
- }
49
- }
50
-
51
- interface Dependency {
52
- unsafe: boolean;
53
- inTry: boolean;
54
- location?: SourceLocation;
55
- }
56
-
57
- interface WarningsNames {
58
- parsingError: "parsing-error",
59
- unsafeImport: "unsafe-import",
60
- unsafeStmt: "unsafe-stmt",
61
- unsafeRegex: "unsafe-regex",
62
- unsafeAssign: "unsafe-assign",
63
- encodedLiteral: "encoded-literal",
64
- shortIdentifiers: "short-identifiers",
65
- suspiciousLiteral: "suspicious-literal",
66
- obfuscatedCode: "obfuscated-code"
67
- }
68
-
69
- interface RuntimeOptions {
70
- module?: boolean;
71
- isMinified?: boolean;
72
- }
73
-
74
- export function runASTAnalysis(str: string, options?: RuntimeOptions): Report;
75
-
76
- export type ReportOnFile = {
77
- ok: true,
78
- warnings: Warning<BaseWarning>[];
79
- dependencies: ASTDeps;
80
- isMinified: boolean;
81
- } | {
82
- ok: false,
83
- warnings: Warning<BaseWarning>[];
84
- }
85
-
86
- export interface RuntimeFileOptions {
87
- packageName?: string;
88
- module?: boolean;
89
- }
90
-
91
- export function runASTAnalysisOnFile(pathToFile: string, options?: RuntimeFileOptions): Promise<ReportOnFile>;
92
-
93
- export namespace CONSTANTS {
94
- export const Warnings: WarningsNames;
95
- }
96
- }
97
-
98
- export = JSXRay;
99
- export as namespace JSXRay;
1
+ declare class ASTDeps {
2
+ constructor();
3
+ removeByName(name: string): void;
4
+ add(depName: string): void;
5
+ getDependenciesInTryStatement(): IterableIterator<string>;
6
+
7
+ public isInTryStmt: boolean;
8
+ public dependencies: Record<string, JSXRay.Dependency>;
9
+ public readonly size: number;
10
+ }
11
+
12
+ declare namespace JSXRay {
13
+ type kindWithValue = "parsing-error"
14
+ | "encoded-literal"
15
+ | "unsafe-regex"
16
+ | "unsafe-stmt"
17
+ | "unsafe-assign"
18
+ | "short-identifiers"
19
+ | "suspicious-literal"
20
+ | "obfuscated-code";
21
+
22
+ type WarningLocation = [[number, number], [number, number]];
23
+ interface BaseWarning {
24
+ kind: "unsafe-import" | kindWithValue;
25
+ file?: string;
26
+ value: string;
27
+ location: WarningLocation | WarningLocation[];
28
+ }
29
+
30
+ type Warning<T extends BaseWarning> = T extends { kind: kindWithValue } ? T : Omit<T, "value">;
31
+
32
+ interface Report {
33
+ dependencies: ASTDeps;
34
+ warnings: Warning<BaseWarning>[];
35
+ idsLengthAvg: number;
36
+ stringScore: number;
37
+ isOneLineRequire: boolean;
38
+ }
39
+
40
+ interface SourceLocation {
41
+ start: {
42
+ line: number;
43
+ column: number;
44
+ };
45
+ end: {
46
+ line: number;
47
+ column: number;
48
+ }
49
+ }
50
+
51
+ interface Dependency {
52
+ unsafe: boolean;
53
+ inTry: boolean;
54
+ location?: SourceLocation;
55
+ }
56
+
57
+ interface WarningsNames {
58
+ parsingError: {
59
+ code: "ast-error",
60
+ i18n: "sast_warnings.ast_error"
61
+ },
62
+ unsafeImport: {
63
+ code: "unsafe-import",
64
+ i18n: "sast_warnings.unsafe_import"
65
+ },
66
+ unsafeRegex: {
67
+ code: "unsafe-regex",
68
+ i18n: "sast_warnings.unsafe_regex"
69
+ },
70
+ unsafeStmt: {
71
+ code: "unsafe-stmt",
72
+ i18n: "sast_warnings.unsafe_stmt"
73
+ },
74
+ unsafeAssign: {
75
+ code: "unsafe-assign",
76
+ i18n: "sast_warnings.unsafe_assign"
77
+ },
78
+ encodedLiteral: {
79
+ code: "encoded-literal",
80
+ i18n: "sast_warnings.encoded_literal"
81
+ },
82
+ shortIdentifiers: {
83
+ code: "short-identifiers",
84
+ i18n: "sast_warnings.short_identifiers"
85
+ },
86
+ suspiciousLiteral: {
87
+ code: "suspicious-literal",
88
+ i18n: "sast_warnings.suspicious_literal"
89
+ },
90
+ obfuscatedCode: {
91
+ code: "obfuscated-code",
92
+ i18n: "sast_warnings.obfuscated_code"
93
+ }
94
+ }
95
+
96
+ interface RuntimeOptions {
97
+ module?: boolean;
98
+ isMinified?: boolean;
99
+ }
100
+
101
+ export function runASTAnalysis(str: string, options?: RuntimeOptions): Report;
102
+
103
+ export type ReportOnFile = {
104
+ ok: true,
105
+ warnings: Warning<BaseWarning>[];
106
+ dependencies: ASTDeps;
107
+ isMinified: boolean;
108
+ } | {
109
+ ok: false,
110
+ warnings: Warning<BaseWarning>[];
111
+ }
112
+
113
+ export interface RuntimeFileOptions {
114
+ packageName?: string;
115
+ module?: boolean;
116
+ }
117
+
118
+ export function runASTAnalysisOnFile(pathToFile: string, options?: RuntimeFileOptions): Promise<ReportOnFile>;
119
+
120
+ export const warnings: WarningsNames;
121
+ }
122
+
123
+ export = JSXRay;
124
+ export as namespace JSXRay;
package/index.js CHANGED
@@ -1,98 +1,125 @@
1
- // Import Node.js Dependencies
2
- import fs from "fs/promises";
3
- import path from "path";
4
-
5
- // Import Third-party Dependencies
6
- import { walk } from "estree-walker";
7
- import * as meriyah from "meriyah";
8
- import isMinified from "is-minified-code";
9
-
10
- // Import Internal Dependencies
11
- import Analysis from "./src/Analysis.js";
12
-
13
- export function runASTAnalysis(str, options = Object.create(null)) {
14
- const { module = true, isMinified = false } = options;
15
-
16
- // Note: if the file start with a shebang then we remove it because 'parseScript' may fail to parse it.
17
- // Example: #!/usr/bin/env node
18
- const strToAnalyze = str.charAt(0) === "#" ? str.slice(str.indexOf("\n")) : str;
19
- const isEcmaScriptModule = Boolean(module);
20
- const { body } = meriyah.parseScript(strToAnalyze, {
21
- next: true,
22
- loc: true,
23
- raw: true,
24
- module: isEcmaScriptModule,
25
- globalReturn: !isEcmaScriptModule
26
- });
27
-
28
- const sastAnalysis = new Analysis();
29
- sastAnalysis.analyzeSourceString(str);
30
-
31
- // we walk each AST Nodes, this is a purely synchronous I/O
32
- walk(body, {
33
- enter(node) {
34
- // Skip the root of the AST.
35
- if (Array.isArray(node)) {
36
- return;
37
- }
38
-
39
- const action = sastAnalysis.walk(node);
40
- if (action === "skip") {
41
- this.skip();
42
- }
43
- }
44
- });
45
-
46
- const dependencies = sastAnalysis.dependencies;
47
- const { idsLengthAvg, stringScore, warnings } = sastAnalysis.getResult(isMinified);
48
- const isOneLineRequire = body.length <= 1 && dependencies.size <= 1;
49
-
50
- return {
51
- dependencies, warnings, idsLengthAvg, stringScore, isOneLineRequire
52
- };
53
- }
54
-
55
- export async function runASTAnalysisOnFile(pathToFile, options = {}) {
56
- try {
57
- const { packageName = null, module = true } = options;
58
- const str = await fs.readFile(pathToFile, "utf-8");
59
-
60
- const isMin = pathToFile.includes(".min") || isMinified(str);
61
- const data = runASTAnalysis(str, {
62
- isMinified: isMin,
63
- module: path.extname(pathToFile) === ".mjs" ? true : module
64
- });
65
- if (packageName !== null) {
66
- data.dependencies.removeByName(packageName);
67
- }
68
-
69
- return {
70
- ok: true,
71
- dependencies: data.dependencies,
72
- warnings: data.warnings,
73
- isMinified: !data.isOneLineRequire && isMin
74
- };
75
- }
76
- catch (error) {
77
- return {
78
- ok: false,
79
- warnings: [
80
- { kind: "parsing-error", value: error.message, location: [[0, 0], [0, 0]] }
81
- ]
82
- };
83
- }
84
- }
85
-
86
- export const CONSTANTS = {
87
- Warnings: Object.freeze({
88
- parsingError: "ast-error",
89
- unsafeImport: "unsafe-import",
90
- unsafeRegex: "unsafe-regex",
91
- unsafeStmt: "unsafe-stmt",
92
- unsafeAssign: "unsafe-assign",
93
- encodedLiteral: "encoded-literal",
94
- shortIdentifiers: "short-identifiers",
95
- suspiciousLiteral: "suspicious-literal",
96
- obfuscatedCode: "obfuscated-code"
97
- })
98
- };
1
+ // Import Node.js Dependencies
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+
5
+ // Import Third-party Dependencies
6
+ import { walk } from "estree-walker";
7
+ import * as meriyah from "meriyah";
8
+ import isMinified from "is-minified-code";
9
+
10
+ // Import Internal Dependencies
11
+ import Analysis from "./src/Analysis.js";
12
+
13
+ export function runASTAnalysis(str, options = Object.create(null)) {
14
+ const { module = true, isMinified = false } = options;
15
+
16
+ // Note: if the file start with a shebang then we remove it because 'parseScript' may fail to parse it.
17
+ // Example: #!/usr/bin/env node
18
+ const strToAnalyze = str.charAt(0) === "#" ? str.slice(str.indexOf("\n")) : str;
19
+ const isEcmaScriptModule = Boolean(module);
20
+ const { body } = meriyah.parseScript(strToAnalyze, {
21
+ next: true,
22
+ loc: true,
23
+ raw: true,
24
+ module: isEcmaScriptModule,
25
+ globalReturn: !isEcmaScriptModule
26
+ });
27
+
28
+ const sastAnalysis = new Analysis();
29
+ sastAnalysis.analyzeSourceString(str);
30
+
31
+ // we walk each AST Nodes, this is a purely synchronous I/O
32
+ walk(body, {
33
+ enter(node) {
34
+ // Skip the root of the AST.
35
+ if (Array.isArray(node)) {
36
+ return;
37
+ }
38
+
39
+ const action = sastAnalysis.walk(node);
40
+ if (action === "skip") {
41
+ this.skip();
42
+ }
43
+ }
44
+ });
45
+
46
+ const dependencies = sastAnalysis.dependencies;
47
+ const { idsLengthAvg, stringScore, warnings } = sastAnalysis.getResult(isMinified);
48
+ const isOneLineRequire = body.length <= 1 && dependencies.size <= 1;
49
+
50
+ return {
51
+ dependencies, warnings, idsLengthAvg, stringScore, isOneLineRequire
52
+ };
53
+ }
54
+
55
+ export async function runASTAnalysisOnFile(pathToFile, options = {}) {
56
+ try {
57
+ const { packageName = null, module = true } = options;
58
+ const str = await fs.readFile(pathToFile, "utf-8");
59
+
60
+ const isMin = pathToFile.includes(".min") || isMinified(str);
61
+ const data = runASTAnalysis(str, {
62
+ isMinified: isMin,
63
+ module: path.extname(pathToFile) === ".mjs" ? true : module
64
+ });
65
+ if (packageName !== null) {
66
+ data.dependencies.removeByName(packageName);
67
+ }
68
+
69
+ return {
70
+ ok: true,
71
+ dependencies: data.dependencies,
72
+ warnings: data.warnings,
73
+ isMinified: !data.isOneLineRequire && isMin
74
+ };
75
+ }
76
+ catch (error) {
77
+ return {
78
+ ok: false,
79
+ warnings: [
80
+ { kind: "parsing-error", value: error.message, location: [[0, 0], [0, 0]] }
81
+ ]
82
+ };
83
+ }
84
+ }
85
+
86
+ export const warnings = Object.freeze({
87
+ parsingError: {
88
+ code: "ast-error",
89
+ i18n: "sast_warnings.ast_error"
90
+ },
91
+ unsafeImport: {
92
+ code: "unsafe-import",
93
+ i18n: "sast_warnings.unsafe_import"
94
+ },
95
+ unsafeRegex: {
96
+ code: "unsafe-regex",
97
+ i18n: "sast_warnings.unsafe_regex"
98
+ },
99
+ unsafeStmt: {
100
+ code: "unsafe-stmt",
101
+ i18n: "sast_warnings.unsafe_stmt"
102
+ },
103
+ unsafeAssign: {
104
+ code: "unsafe-assign",
105
+ i18n: "sast_warnings.unsafe_assign"
106
+ },
107
+ encodedLiteral: {
108
+ code: "encoded-literal",
109
+ i18n: "sast_warnings.encoded_literal"
110
+ },
111
+ shortIdentifiers: {
112
+ code: "short-identifiers",
113
+ i18n: "sast_warnings.short_identifiers"
114
+ },
115
+ suspiciousLiteral: {
116
+ code: "suspicious-literal",
117
+ i18n: "sast_warnings.suspicious_literal"
118
+ },
119
+ obfuscatedCode: {
120
+ code: "obfuscated-code",
121
+ i18n: "sast_warnings.obfuscated_code"
122
+ }
123
+ });
124
+
125
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodesecure/js-x-ray",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "description": "JavaScript AST XRay analysis",
5
5
  "type": "module",
6
6
  "exports": "./index.js",
@@ -48,10 +48,10 @@
48
48
  "@slimio/is": "^1.5.1",
49
49
  "@small-tech/esm-tape-runner": "^2.0.0",
50
50
  "@small-tech/tap-monkey": "^1.3.0",
51
- "@types/node": "^17.0.23",
51
+ "@types/node": "^17.0.31",
52
52
  "cross-env": "^7.0.3",
53
- "eslint": "^8.12.0",
53
+ "eslint": "^8.15.0",
54
54
  "pkg-ok": "^3.0.0",
55
- "tape": "^5.5.2"
55
+ "tape": "^5.5.3"
56
56
  }
57
57
  }