Skip to content

Commit b06cdac

Browse files
committed
refactor: use newest NodeSecure scanner features
1 parent 14587bb commit b06cdac

File tree

7 files changed

+6907
-3351
lines changed

7 files changed

+6907
-3351
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@ I personally created this project to analyze npm packages by various criteria (p
1919

2020
- Pull packages from the npm registry by divers criteria.
2121
- Offers you various methods to read and extract information from the npm tarball.
22-
- Include [js-x-ray](https://github.com/fraxken/js-x-ray) by default.
2322
- Functionalities can be extended
2423

2524
## Requirements
26-
- [Node.js](https://nodejs.org/en/) v14 or higher
25+
- [Node.js](https://nodejs.org/en/) v16 or higher
2726

2827
## Getting Started
2928

bin/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#!/usr/bin/env node
22

3-
import "make-promises-safe";
43
import dotenv from "dotenv";
54
dotenv.config();
65

@@ -11,7 +10,7 @@ import sade from "sade";
1110
// Import Internal Dependencies
1211
import * as commands from "./commands/index.js";
1312

14-
const prog = sade("npm-security-fetcher").version("1.0.0");
13+
const prog = sade("npm-security-fetcher").version("2.0.0");
1514
console.log(
1615
colors.gray(
1716
`\n > executing npm-security-fetch at: ${colors.yellow(process.cwd())}\n`

example/js-x-ray.ts

Lines changed: 21 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,43 @@
1-
/* eslint-disable max-params */
2-
3-
// Node.js
1+
// Import Node.js Dependencies
42
import fs from "node:fs/promises";
53
import path from "node:path";
64

7-
// Third-party
8-
import filenamify from "filenamify";
9-
10-
// Internal
11-
import { analyzeJavaScriptFile, Utils } from "../index";
12-
13-
// CONSTANTS
14-
const kJavaScriptExtensions = new Set([".js", ".mjs", ".cjs"]);
15-
const kJSONSpace = 2;
16-
const kDefaultReplacement = "#";
5+
// Import Third-party Dependencies
6+
import { tarball } from "@nodesecure/scanner";
177

18-
let count = 0;
8+
// Import Internal Dependencies
9+
import { IRunOptions } from "../index.js";
1910

20-
export async function init() {
21-
const baseDir = path.join(process.cwd(), "results");
11+
type Context = {
12+
outdir: string;
13+
count: number;
14+
};
2215

23-
const analysisDir = path.join(baseDir, "packages");
24-
const errorDir = path.join(baseDir, "parsing-errors");
25-
await fs.mkdir(analysisDir, { recursive: true });
26-
await fs.mkdir(errorDir, { recursive: true });
16+
export async function init(): Promise<Context> {
17+
const outdir = path.join(process.cwd(), "nsf-results");
18+
await fs.mkdir(outdir, { recursive: true });
2719

28-
return { analysisDir, errorDir };
20+
return { outdir, count: 0 };
2921
}
3022

3123
export async function close() {
3224
console.log("close triggered");
3325
}
3426

35-
type RunOptions = {
36-
name: string;
37-
location: string;
38-
root: string;
39-
};
27+
export async function run(ctx: Context, options: IRunOptions) {
28+
const { name, location } = options;
4029

41-
export async function run(ctx: Ctx, { name, location, root }: RunOptions) {
4230
try {
43-
console.log(`handle package name: ${name}, count: ${count++}`);
44-
const { files } = await Utils.getTarballComposition(location);
45-
const jsFiles = files.filter((name) => kJavaScriptExtensions.has(path.extname(name)));
46-
const toWait: any[] = [];
47-
48-
for (const file of jsFiles) {
49-
const cleanName = filenamify(
50-
path.relative(root, file).slice(name.length),
51-
{ replacement: kDefaultReplacement }
52-
);
53-
toWait.push(runASTAnalysis(ctx, cleanName, file, name));
54-
}
31+
console.log(`handle package name: ${name}, count: ${ctx.count++}`);
32+
const result = await tarball.scanPackage(location, name);
5533

56-
const results = (await Promise.allSettled(toWait))
57-
.filter(({ status }) => status === "fulfilled")
58-
.map((p) => (p as PromiseFulfilledResult<unknown>).value);
59-
60-
const content = JSON.stringify(
61-
Object.assign({}, ...results),
62-
null,
63-
kJSONSpace
34+
const fileName = path.join(ctx.outdir, name.replace(/\//g, "__")) + ".json";
35+
await fs.writeFile(
36+
fileName,
37+
JSON.stringify(result, null, 2)
6438
);
65-
66-
const fileName =
67-
path.join(ctx.analysisDir, name.replace(/\//g, "__")) + ".json";
68-
await fs.writeFile(fileName, content);
6939
}
7040
finally {
7141
await fs.rmdir(location, { recursive: true });
7242
}
7343
}
74-
75-
async function dumpParsingError(
76-
ctx: Ctx,
77-
error: { code: string; message: string; stack: string } | string,
78-
cleanName: string,
79-
pkgName: string
80-
) {
81-
try {
82-
const stack = typeof error === "string" ? "" : error.stack.split("\n");
83-
const dumpStr = JSON.stringify(
84-
{
85-
pkgName,
86-
code: typeof error === "string" ? null : error.code || null,
87-
message: typeof error === "string" ? error : error.message || "",
88-
stack
89-
},
90-
null,
91-
kJSONSpace
92-
);
93-
94-
await fs.writeFile(path.join(ctx.errorDir, `${cleanName}.json`), dumpStr);
95-
}
96-
catch {
97-
// ignore
98-
}
99-
}
100-
101-
type Ctx = { analysisDir: string; errorDir: string };
102-
103-
async function runASTAnalysis(
104-
ctx: Ctx,
105-
cleanName: string,
106-
location: string,
107-
pkgName: string
108-
) {
109-
try {
110-
const ASTAnalysis = await analyzeJavaScriptFile(location);
111-
// @ts-ignore
112-
const deps = [...ASTAnalysis.dependencies];
113-
const warnings = ASTAnalysis.warnings;
114-
115-
return { [cleanName]: { warnings, deps } };
116-
}
117-
catch (error: any) {
118-
if (error.name === "SyntaxError") {
119-
return {};
120-
}
121-
await dumpParsingError(ctx, error, cleanName, pkgName);
122-
123-
return {};
124-
}
125-
}

index.ts

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@ import { search } from "@nodesecure/npm-registry-sdk";
1010
import { klona } from "klona/json";
1111
import is from "@slimio/is";
1212
import Locker from "@slimio/lock";
13-
import * as JSXRay from "@nodesecure/js-x-ray";
14-
15-
// @ts-ignore
16-
import isMinified from "is-minified-code";
1713

1814
// Import Internal Dependencies
19-
import { fetchPackage, getTarballComposition } from "./src/utils.js";
15+
import { fetchPackage } from "./src/utils.js";
2016

2117
// CONSTANTS
2218
const kRegSearchLimit = 10;
@@ -27,15 +23,21 @@ const kDefaultLimit = 500;
2723
const kDefaultFetcher = (raw: { package: { name: string; version: number } }) => `${raw.package.name}@${raw.package.version}`;
2824
const kMaximumConcurrentDownload = 5;
2925

30-
type searchPackagesByCriteriaOptions = {
26+
export interface IRunOptions {
27+
name: string;
28+
location: string;
29+
root: string;
30+
}
31+
32+
export interface ISearchPackagesByCriteriaOptions {
3133
limit?: string;
3234
delay?: string;
3335
dataFetcher?: any;
3436
criteria?: any;
35-
};
37+
}
3638

3739
export async function* searchPackagesByCriteria(
38-
options: searchPackagesByCriteriaOptions = {}
40+
options: ISearchPackagesByCriteriaOptions = {}
3941
) {
4042
const limit = Number(options.limit) || kDefaultLimit;
4143
const delay = Number(options.delay) || 0;
@@ -102,13 +104,13 @@ export async function downloadFromSource(
102104
}
103105
}
104106

105-
type downloadPackageOnRegistryOptions = {
107+
export type IDownloadPackageOnRegistryOptions = {
106108
maxConcurrent?: string;
107109
};
108110

109111
export async function* downloadPackageOnRegistry(
110112
source: AsyncGenerator<any, void, any>,
111-
options: downloadPackageOnRegistryOptions = {}
113+
options: IDownloadPackageOnRegistryOptions = {}
112114
) {
113115
const maxConcurrent =
114116
Number(options.maxConcurrent) || kMaximumConcurrentDownload;
@@ -137,14 +139,3 @@ export async function* downloadPackageOnRegistry(
137139
await fs.rm(tmpLocation, { force: true, recursive: true });
138140
}
139141
}
140-
141-
export async function analyzeJavaScriptFile(fileLocation: string) {
142-
const str = await fs.readFile(fileLocation, "utf-8");
143-
const isMin = path.basename(fileLocation).includes(".min") || isMinified(str);
144-
145-
return JSXRay.runASTAnalysis(str, { isMinified: isMin });
146-
}
147-
148-
export const Utils = {
149-
getTarballComposition
150-
};

0 commit comments

Comments
 (0)