pompelmi 0.17.0-dev.37 → 0.18.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 +18 -1
- package/package.json +15 -10
- package/dist/index.cjs.js +0 -86
- package/dist/index.esm.js +0 -82
- package/dist/local-file-scanner.cjs.js +0 -3003
- package/dist/local-file-scanner.cjs.js.map +0 -1
- package/dist/local-file-scanner.esm.js +0 -2997
- package/dist/local-file-scanner.esm.js.map +0 -1
- package/dist/pompelmi.cjs.js +0 -3279
- package/dist/pompelmi.cjs.js.map +0 -1
- package/dist/pompelmi.esm.js +0 -3266
- package/dist/pompelmi.esm.js.map +0 -1
- package/dist/types/browser-index.d.ts +0 -3
- package/dist/types/index.d.ts +0 -14
- package/dist/types/node/scanDir.d.ts +0 -30
- package/dist/types/scan/remote.d.ts +0 -12
- package/dist/types/scan.d.ts +0 -12
- package/dist/types/useFileScanner.d.ts +0 -15
- package/dist/types/validate.d.ts +0 -7
- package/dist/types/yara/browser.d.ts +0 -7
- package/dist/types/yara/index.d.ts +0 -17
- package/dist/types/yara/node.d.ts +0 -2
- package/dist/types/yara/remote.d.ts +0 -10
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
<img alt="node" src="https://img.shields.io/badge/node-%3E%3D18-339933?logo=node.js&logoColor=white">
|
|
34
34
|
<img alt="types" src="https://img.shields.io/badge/types-TypeScript-3178C6?logo=typescript&logoColor=white">
|
|
35
35
|
<a href="https://github.com/pompelmi/pompelmi/blob/main/LICENSE"><img alt="license" src="https://img.shields.io/npm/l/pompelmi"></a>
|
|
36
|
+
<a href="https://securityscorecards.dev/viewer/?uri=github.com/pompelmi/pompelmi"><img alt="OpenSSF Scorecard" src="https://api.securityscorecards.dev/projects/github.com/pompelmi/pompelmi/badge"/></a>
|
|
36
37
|
<a href="https://codecov.io/gh/pompelmi/pompelmi"><img alt="codecov" src="https://codecov.io/gh/pompelmi/pompelmi/branch/main/graph/badge.svg?flag=core"/></a>
|
|
37
38
|
<a href="https://github.com/pompelmi/pompelmi/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/pompelmi/pompelmi?style=social"></a>
|
|
38
39
|
<a href="https://github.com/pompelmi/pompelmi/actions/workflows/ci-release-publish.yml"><img alt="CI / Release / Publish" src="https://img.shields.io/github/actions/workflow/status/pompelmi/pompelmi/ci-release-publish.yml?branch=main&label=CI%20%2F%20Release%20%2F%20Publish"></a>
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
<p align="center"><a href="https://pompelmi.github.io/pompelmi/">Documentation</a> ·
|
|
46
47
|
<a href="#installation">Install</a> ·
|
|
47
48
|
<a href="#quick-start">Quick‑start</a> ·
|
|
49
|
+
<a href="#minimal-node-usage">Minimal Node</a> ·
|
|
48
50
|
<a href="#github-action">GitHub Action</a> ·
|
|
49
51
|
<a href="#adapters">Adapters</a> ·
|
|
50
52
|
<a href="#diagrams">Diagrams</a> ·
|
|
@@ -65,6 +67,7 @@
|
|
|
65
67
|
|
|
66
68
|
- [Install](#installation)
|
|
67
69
|
- [Quick‑start](#quick-start)
|
|
70
|
+
- [Minimal Node usage](#minimal-node-usage)
|
|
68
71
|
- [GitHub Action](#github-action)
|
|
69
72
|
- [Adapters](#adapters)
|
|
70
73
|
- [Diagrams](#diagrams)
|
|
@@ -131,7 +134,6 @@
|
|
|
131
134
|
|
|
132
135
|
```bash
|
|
133
136
|
# core library
|
|
134
|
-
[](https://securityscorecards.dev/viewer/?uri=github.com/pompelmi/pompelmi)
|
|
135
137
|
npm i pompelmi
|
|
136
138
|
# or
|
|
137
139
|
pnpm add pompelmi
|
|
@@ -175,6 +177,21 @@ export const scanner = composeScanners(
|
|
|
175
177
|
);
|
|
176
178
|
```
|
|
177
179
|
|
|
180
|
+
### Minimal Node usage
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
import { scanFile } from 'pompelmi';
|
|
184
|
+
|
|
185
|
+
const res = await scanFile('path/to/file.zip'); // or any file
|
|
186
|
+
console.log(res.verdict); // "clean" | "suspicious" | "malicious"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
> See `examples/scan-one-file.ts` for a runnable script:
|
|
190
|
+
>
|
|
191
|
+
> ```bash
|
|
192
|
+
> pnpm tsx examples/scan-one-file.ts ./path/to/file
|
|
193
|
+
> ```
|
|
194
|
+
|
|
178
195
|
### Express
|
|
179
196
|
|
|
180
197
|
```ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pompelmi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "RFI-safe file uploads for Node.js — Express/Koa/Next.js middleware with deep ZIP inspection, MIME/size checks, and optional YARA scanning.",
|
|
5
5
|
"main": "./dist/pompelmi.cjs",
|
|
6
6
|
"module": "./dist/pompelmi.esm.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "rollup -c",
|
|
38
|
-
"prepublishOnly": "npm run build",
|
|
38
|
+
"prepublishOnly": "npm run build && npm run pack:strict",
|
|
39
39
|
"yara:node:smoke": "tsx scripts/yara-node-smoke.ts",
|
|
40
40
|
"yara:int:smoke": "tsx scripts/yara-integration-smoke.ts",
|
|
41
41
|
"dev:remote": "tsx examples/remote-yara-server.ts",
|
|
@@ -56,13 +56,14 @@
|
|
|
56
56
|
"repo:audit": "node scripts/audit.mjs",
|
|
57
57
|
"pack:check": "node scripts/pack-check.mjs",
|
|
58
58
|
"pack:list": "pnpm -r --filter \"@pompelmi/*\" --if-present pack --json --dry-run",
|
|
59
|
-
"pack:strict": "node scripts/pack-check.mjs --strict"
|
|
59
|
+
"pack:strict": "node scripts/pack-check.mjs --strict",
|
|
60
|
+
"clean": "rimraf dist"
|
|
60
61
|
},
|
|
61
62
|
"license": "MIT",
|
|
62
63
|
"devDependencies": {
|
|
63
64
|
"@biomejs/biome": "^2.2.4",
|
|
64
65
|
"@pompelmi/core": "workspace:*",
|
|
65
|
-
"@pompelmi/engine": "workspace
|
|
66
|
+
"@pompelmi/engine": "workspace:*",
|
|
66
67
|
"@pompelmi/engine-heuristics": "workspace:^0.1.0",
|
|
67
68
|
"@rollup/plugin-commonjs": "^28.0.6",
|
|
68
69
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
@@ -89,9 +90,6 @@
|
|
|
89
90
|
"typescript": "^5.9.2",
|
|
90
91
|
"vitest": "2.1.9"
|
|
91
92
|
},
|
|
92
|
-
"dependencies": {
|
|
93
|
-
"rollup": "^4.45.1"
|
|
94
|
-
},
|
|
95
93
|
"peerDependencies": {
|
|
96
94
|
"react": "^18.0.0 || ^19.0.0",
|
|
97
95
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
@@ -100,7 +98,12 @@
|
|
|
100
98
|
"@litko/yara-x": "^0.2.1"
|
|
101
99
|
},
|
|
102
100
|
"exports": {
|
|
103
|
-
".": {
|
|
101
|
+
".": {
|
|
102
|
+
"import": "./dist/pompelmi.esm.js",
|
|
103
|
+
"require": "./dist/pompelmi.cjs",
|
|
104
|
+
"default": "./dist/pompelmi.esm.js",
|
|
105
|
+
"types": "./dist/types/index.d.ts"
|
|
106
|
+
},
|
|
104
107
|
"./package.json": "./package.json"
|
|
105
108
|
},
|
|
106
109
|
"files": [
|
|
@@ -109,7 +112,8 @@
|
|
|
109
112
|
"README.md",
|
|
110
113
|
"LICENSE*",
|
|
111
114
|
"package.json",
|
|
112
|
-
"CHANGELOG*"
|
|
115
|
+
"CHANGELOG*",
|
|
116
|
+
"LICENSE"
|
|
113
117
|
],
|
|
114
118
|
"keywords": [
|
|
115
119
|
"security",
|
|
@@ -151,5 +155,6 @@
|
|
|
151
155
|
},
|
|
152
156
|
"publishConfig": {
|
|
153
157
|
"access": "public"
|
|
154
|
-
}
|
|
158
|
+
},
|
|
159
|
+
"types": "./dist/types/index.d.ts"
|
|
155
160
|
}
|
package/dist/index.cjs.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var react = require('react');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Reads an array of File objects via FileReader and returns their text.
|
|
7
|
-
*/
|
|
8
|
-
async function scanFiles(files) {
|
|
9
|
-
const readText = file => new Promise((resolve, reject) => {
|
|
10
|
-
const reader = new FileReader();
|
|
11
|
-
reader.onload = () => resolve(reader.result);
|
|
12
|
-
reader.onerror = () => reject(reader.error);
|
|
13
|
-
reader.readAsText(file);
|
|
14
|
-
});
|
|
15
|
-
const results = [];
|
|
16
|
-
for (const file of files) {
|
|
17
|
-
const content = await readText(file);
|
|
18
|
-
results.push({
|
|
19
|
-
file,
|
|
20
|
-
content
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
return results;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Validates a File by MIME type and size (max 5 MB).
|
|
28
|
-
*/
|
|
29
|
-
function validateFile(file) {
|
|
30
|
-
const maxSize = 5 * 1024 * 1024;
|
|
31
|
-
const allowedTypes = ['text/plain', 'application/json', 'text/csv'];
|
|
32
|
-
if (!allowedTypes.includes(file.type)) {
|
|
33
|
-
return {
|
|
34
|
-
valid: false,
|
|
35
|
-
error: 'Unsupported file type'
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
if (file.size > maxSize) {
|
|
39
|
-
return {
|
|
40
|
-
valid: false,
|
|
41
|
-
error: 'File too large (max 5 MB)'
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
return {
|
|
45
|
-
valid: true
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* React Hook: handles <input type="file" onChange> with validation + scanning.
|
|
51
|
-
*/
|
|
52
|
-
function useFileScanner() {
|
|
53
|
-
const [results, setResults] = react.useState([]);
|
|
54
|
-
const [errors, setErrors] = react.useState([]);
|
|
55
|
-
const onChange = react.useCallback(async e => {
|
|
56
|
-
const fileList = Array.from(e.target.files || []);
|
|
57
|
-
const good = [];
|
|
58
|
-
const bad = [];
|
|
59
|
-
for (const file of fileList) {
|
|
60
|
-
const {
|
|
61
|
-
valid,
|
|
62
|
-
error
|
|
63
|
-
} = validateFile(file);
|
|
64
|
-
if (valid) good.push(file);else bad.push({
|
|
65
|
-
file,
|
|
66
|
-
error: error
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
setErrors(bad);
|
|
70
|
-
if (good.length) {
|
|
71
|
-
const scanned = await scanFiles(good);
|
|
72
|
-
setResults(scanned);
|
|
73
|
-
} else {
|
|
74
|
-
setResults([]);
|
|
75
|
-
}
|
|
76
|
-
}, []);
|
|
77
|
-
return {
|
|
78
|
-
results,
|
|
79
|
-
errors,
|
|
80
|
-
onChange
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
exports.scanFiles = scanFiles;
|
|
85
|
-
exports.useFileScanner = useFileScanner;
|
|
86
|
-
exports.validateFile = validateFile;
|
package/dist/index.esm.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback } from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Reads an array of File objects via FileReader and returns their text.
|
|
5
|
-
*/
|
|
6
|
-
async function scanFiles(files) {
|
|
7
|
-
const readText = file => new Promise((resolve, reject) => {
|
|
8
|
-
const reader = new FileReader();
|
|
9
|
-
reader.onload = () => resolve(reader.result);
|
|
10
|
-
reader.onerror = () => reject(reader.error);
|
|
11
|
-
reader.readAsText(file);
|
|
12
|
-
});
|
|
13
|
-
const results = [];
|
|
14
|
-
for (const file of files) {
|
|
15
|
-
const content = await readText(file);
|
|
16
|
-
results.push({
|
|
17
|
-
file,
|
|
18
|
-
content
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
return results;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Validates a File by MIME type and size (max 5 MB).
|
|
26
|
-
*/
|
|
27
|
-
function validateFile(file) {
|
|
28
|
-
const maxSize = 5 * 1024 * 1024;
|
|
29
|
-
const allowedTypes = ['text/plain', 'application/json', 'text/csv'];
|
|
30
|
-
if (!allowedTypes.includes(file.type)) {
|
|
31
|
-
return {
|
|
32
|
-
valid: false,
|
|
33
|
-
error: 'Unsupported file type'
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
if (file.size > maxSize) {
|
|
37
|
-
return {
|
|
38
|
-
valid: false,
|
|
39
|
-
error: 'File too large (max 5 MB)'
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
return {
|
|
43
|
-
valid: true
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* React Hook: handles <input type="file" onChange> with validation + scanning.
|
|
49
|
-
*/
|
|
50
|
-
function useFileScanner() {
|
|
51
|
-
const [results, setResults] = useState([]);
|
|
52
|
-
const [errors, setErrors] = useState([]);
|
|
53
|
-
const onChange = useCallback(async e => {
|
|
54
|
-
const fileList = Array.from(e.target.files || []);
|
|
55
|
-
const good = [];
|
|
56
|
-
const bad = [];
|
|
57
|
-
for (const file of fileList) {
|
|
58
|
-
const {
|
|
59
|
-
valid,
|
|
60
|
-
error
|
|
61
|
-
} = validateFile(file);
|
|
62
|
-
if (valid) good.push(file);else bad.push({
|
|
63
|
-
file,
|
|
64
|
-
error: error
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
setErrors(bad);
|
|
68
|
-
if (good.length) {
|
|
69
|
-
const scanned = await scanFiles(good);
|
|
70
|
-
setResults(scanned);
|
|
71
|
-
} else {
|
|
72
|
-
setResults([]);
|
|
73
|
-
}
|
|
74
|
-
}, []);
|
|
75
|
-
return {
|
|
76
|
-
results,
|
|
77
|
-
errors,
|
|
78
|
-
onChange
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export { scanFiles, useFileScanner, validateFile };
|