pompelmi 0.35.5 โ†’ 1.0.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 (133) hide show
  1. package/.claude/settings.local.json +40 -0
  2. package/LICENSE +12 -18
  3. package/README.md +159 -183
  4. package/eslint.config.mjs +8 -0
  5. package/package.json +26 -251
  6. package/src/ClamAVDatabaseUpdater.js +48 -0
  7. package/src/ClamAVInstaller.js +49 -0
  8. package/src/ClamAVScanner.js +31 -0
  9. package/src/InstallerCommand.js +11 -0
  10. package/src/config.js +22 -0
  11. package/src/constants.js +3 -0
  12. package/src/favicon.ico +0 -0
  13. package/src/grapefruit.png +0 -0
  14. package/src/index.js +5 -0
  15. package/CHANGELOG.md +0 -71
  16. package/dist/pompelmi.audit.cjs +0 -128
  17. package/dist/pompelmi.audit.cjs.map +0 -1
  18. package/dist/pompelmi.audit.esm.js +0 -107
  19. package/dist/pompelmi.audit.esm.js.map +0 -1
  20. package/dist/pompelmi.browser.cjs +0 -1549
  21. package/dist/pompelmi.browser.cjs.map +0 -1
  22. package/dist/pompelmi.browser.esm.js +0 -1523
  23. package/dist/pompelmi.browser.esm.js.map +0 -1
  24. package/dist/pompelmi.cjs +0 -2591
  25. package/dist/pompelmi.cjs.map +0 -1
  26. package/dist/pompelmi.esm.js +0 -2525
  27. package/dist/pompelmi.esm.js.map +0 -1
  28. package/dist/pompelmi.hooks.cjs +0 -75
  29. package/dist/pompelmi.hooks.cjs.map +0 -1
  30. package/dist/pompelmi.hooks.esm.js +0 -72
  31. package/dist/pompelmi.hooks.esm.js.map +0 -1
  32. package/dist/pompelmi.policy-packs.cjs +0 -240
  33. package/dist/pompelmi.policy-packs.cjs.map +0 -1
  34. package/dist/pompelmi.policy-packs.esm.js +0 -232
  35. package/dist/pompelmi.policy-packs.esm.js.map +0 -1
  36. package/dist/pompelmi.quarantine.cjs +0 -317
  37. package/dist/pompelmi.quarantine.cjs.map +0 -1
  38. package/dist/pompelmi.quarantine.esm.js +0 -293
  39. package/dist/pompelmi.quarantine.esm.js.map +0 -1
  40. package/dist/pompelmi.react.cjs +0 -1580
  41. package/dist/pompelmi.react.cjs.map +0 -1
  42. package/dist/pompelmi.react.esm.js +0 -1553
  43. package/dist/pompelmi.react.esm.js.map +0 -1
  44. package/dist/types/audit.d.ts +0 -84
  45. package/dist/types/browser-index.d.ts +0 -29
  46. package/dist/types/config.d.ts +0 -143
  47. package/dist/types/engines/dynamic-taint.d.ts +0 -102
  48. package/dist/types/engines/hybrid-orchestrator.d.ts +0 -65
  49. package/dist/types/engines/hybrid-taint-integration.d.ts +0 -129
  50. package/dist/types/engines/taint-policies.d.ts +0 -84
  51. package/dist/types/hipaa-compliance.d.ts +0 -110
  52. package/dist/types/hooks.d.ts +0 -89
  53. package/dist/types/index.d.ts +0 -29
  54. package/dist/types/magic.d.ts +0 -7
  55. package/dist/types/node/scanDir.d.ts +0 -30
  56. package/dist/types/policy-packs.d.ts +0 -98
  57. package/dist/types/policy.d.ts +0 -12
  58. package/dist/types/presets.d.ts +0 -72
  59. package/dist/types/quarantine/index.d.ts +0 -18
  60. package/dist/types/quarantine/storage.d.ts +0 -77
  61. package/dist/types/quarantine/types.d.ts +0 -78
  62. package/dist/types/quarantine/workflow.d.ts +0 -97
  63. package/dist/types/react-index.d.ts +0 -13
  64. package/dist/types/risk.d.ts +0 -18
  65. package/dist/types/scan/remote.d.ts +0 -12
  66. package/dist/types/scan.d.ts +0 -17
  67. package/dist/types/scanners/common-heuristics.d.ts +0 -14
  68. package/dist/types/scanners/zip-bomb-guard.d.ts +0 -9
  69. package/dist/types/scanners/zipTraversalGuard.d.ts +0 -19
  70. package/dist/types/src/audit.d.ts +0 -84
  71. package/dist/types/src/browser-index.d.ts +0 -29
  72. package/dist/types/src/config.d.ts +0 -143
  73. package/dist/types/src/engines/dynamic-taint.d.ts +0 -102
  74. package/dist/types/src/engines/hybrid-orchestrator.d.ts +0 -65
  75. package/dist/types/src/engines/hybrid-taint-integration.d.ts +0 -129
  76. package/dist/types/src/engines/taint-policies.d.ts +0 -84
  77. package/dist/types/src/hipaa-compliance.d.ts +0 -110
  78. package/dist/types/src/hooks.d.ts +0 -89
  79. package/dist/types/src/index.d.ts +0 -29
  80. package/dist/types/src/magic.d.ts +0 -7
  81. package/dist/types/src/node/scanDir.d.ts +0 -30
  82. package/dist/types/src/policy-packs.d.ts +0 -98
  83. package/dist/types/src/policy.d.ts +0 -12
  84. package/dist/types/src/presets.d.ts +0 -72
  85. package/dist/types/src/quarantine/index.d.ts +0 -18
  86. package/dist/types/src/quarantine/storage.d.ts +0 -77
  87. package/dist/types/src/quarantine/types.d.ts +0 -78
  88. package/dist/types/src/quarantine/workflow.d.ts +0 -97
  89. package/dist/types/src/react-index.d.ts +0 -13
  90. package/dist/types/src/risk.d.ts +0 -18
  91. package/dist/types/src/scan/remote.d.ts +0 -12
  92. package/dist/types/src/scan.d.ts +0 -17
  93. package/dist/types/src/scanners/common-heuristics.d.ts +0 -14
  94. package/dist/types/src/scanners/zip-bomb-guard.d.ts +0 -11
  95. package/dist/types/src/scanners/zipTraversalGuard.d.ts +0 -19
  96. package/dist/types/src/stream.d.ts +0 -10
  97. package/dist/types/src/types/decompilation.d.ts +0 -96
  98. package/dist/types/src/types/taint-tracking.d.ts +0 -495
  99. package/dist/types/src/types.d.ts +0 -48
  100. package/dist/types/src/useFileScanner.d.ts +0 -15
  101. package/dist/types/src/utils/advanced-detection.d.ts +0 -21
  102. package/dist/types/src/utils/batch-scanner.d.ts +0 -62
  103. package/dist/types/src/utils/cache-manager.d.ts +0 -95
  104. package/dist/types/src/utils/export.d.ts +0 -51
  105. package/dist/types/src/utils/performance-metrics.d.ts +0 -68
  106. package/dist/types/src/utils/threat-intelligence.d.ts +0 -96
  107. package/dist/types/src/validate.d.ts +0 -7
  108. package/dist/types/src/verdict.d.ts +0 -2
  109. package/dist/types/src/yara/browser.d.ts +0 -7
  110. package/dist/types/src/yara/index.d.ts +0 -17
  111. package/dist/types/src/yara/node.d.ts +0 -2
  112. package/dist/types/src/yara/remote.d.ts +0 -10
  113. package/dist/types/src/yara-bridge.d.ts +0 -3
  114. package/dist/types/src/zip.d.ts +0 -13
  115. package/dist/types/stream.d.ts +0 -10
  116. package/dist/types/types/decompilation.d.ts +0 -96
  117. package/dist/types/types/taint-tracking.d.ts +0 -495
  118. package/dist/types/types.d.ts +0 -48
  119. package/dist/types/useFileScanner.d.ts +0 -15
  120. package/dist/types/utils/advanced-detection.d.ts +0 -21
  121. package/dist/types/utils/batch-scanner.d.ts +0 -62
  122. package/dist/types/utils/cache-manager.d.ts +0 -95
  123. package/dist/types/utils/export.d.ts +0 -51
  124. package/dist/types/utils/performance-metrics.d.ts +0 -68
  125. package/dist/types/utils/threat-intelligence.d.ts +0 -96
  126. package/dist/types/validate.d.ts +0 -7
  127. package/dist/types/verdict.d.ts +0 -2
  128. package/dist/types/yara/browser.d.ts +0 -7
  129. package/dist/types/yara/index.d.ts +0 -17
  130. package/dist/types/yara/node.d.ts +0 -2
  131. package/dist/types/yara/remote.d.ts +0 -10
  132. package/dist/types/yara-bridge.d.ts +0 -3
  133. package/dist/types/zip.d.ts +0 -13
package/package.json CHANGED
@@ -1,263 +1,38 @@
1
1
  {
2
2
  "name": "pompelmi",
3
- "version": "0.35.5",
4
- "description": "Inspect untrusted uploads before storage in Node.js. Open-source upload security with checks for spoofing, archive abuse, risky document and binary signals, and optional YARA.",
5
- "main": "./dist/pompelmi.cjs",
6
- "module": "./dist/pompelmi.esm.js",
7
- "type": "module",
8
- "browser": {
9
- "yara": false,
10
- "util": false,
11
- "crypto": false,
12
- "os": false,
13
- "path": false,
14
- "unzipper": false,
15
- "child_process": false
16
- },
3
+ "version": "1.0.0",
4
+ "description": "ClamAV for humans โ€” scan any file and get back Clean, Malicious, or ScanError. No daemons. No cloud. No native bindings.",
5
+ "license": "ISC",
6
+ "author": "pompelmi contributors",
7
+ "homepage": "https://pompelmi.app",
17
8
  "repository": {
18
9
  "type": "git",
19
10
  "url": "https://github.com/pompelmi/pompelmi.git"
20
11
  },
21
- "homepage": "https://pompelmi.github.io/pompelmi/",
22
- "funding": {
23
- "type": "github",
24
- "url": "https://github.com/sponsors/pompelmi"
25
- },
26
- "pnpm": {
27
- "overrides": {
28
- "process": "0.11.10",
29
- "regjsgen": "0.8.0",
30
- "fflate": "0.8.2",
31
- "@tokenizer/inflate>fflate": "0.8.2",
32
- "file-type>fflate": "0.8.2",
33
- "regexpu-core>regjsgen": "0.8.0",
34
- "@babel/helper-create-regexp-features-plugin>regjsgen": "0.8.0",
35
- "vitest": "2.1.9",
36
- "@vitest/coverage-v8": "2.1.9",
37
- "babel-plugin-polyfill-corejs3": "^0.13.0",
38
- "@types/cookies": "0.9.1",
39
- "@types/koa>@types/cookies": "0.9.1",
40
- "pompelmi": "workspace:*",
41
- "@pompelmi/core": "workspace:*",
42
- "katex": "0.16.21",
43
- "react": "^19.2.0",
44
- "react-dom": "^19.2.0",
45
- "@types/react": "^19.2.0",
46
- "@types/react-dom": "^19.2.0",
47
- "esbuild@<=0.24.2": ">=0.25.0",
48
- "devalue@<5.3.2": ">=5.3.2",
49
- "vite@>=6.0.0 <=6.3.5": ">=6.3.6",
50
- "katex@>=0.12.0 <=0.16.20": ">=0.16.21",
51
- "astro@<5.14.3": ">=5.14.3",
52
- "vite@>=6.0.0 <=6.4.0": ">=6.4.1",
53
- "astro@>=2.16.0 <5.15.5": ">=5.15.5",
54
- "js-yaml@<3.14.2": ">=3.14.2",
55
- "js-yaml@>=4.0.0 <4.1.1": ">=4.1.1",
56
- "glob@>=10.2.0 <10.5.0": ">=10.5.0",
57
- "astro@<=5.15.6": ">=5.15.8",
58
- "body-parser@>=2.2.0 <2.2.1": ">=2.2.1",
59
- "astro@<5.15.9": ">=5.15.9",
60
- "astro@<5.15.8": ">=5.15.8",
61
- "astro@>=5.2.0 <5.15.6": ">=5.15.6",
62
- "mdast-util-to-hast@>=13.0.0 <13.2.1": ">=13.2.1",
63
- "next@>=16.0.0-canary.0 <16.0.7": ">=16.0.7",
64
- "next@>=16.0.0-beta.0 <16.0.9": ">=16.0.9",
65
- "qs@<6.14.2": ">=6.14.2",
66
- "multer@<2.0.2": ">=2.0.2",
67
- "@isaacs/brace-expansion@<=5.0.0": ">=5.0.1",
68
- "ajv@<8.18.0": ">=8.18.0",
69
- "fastify@<5.7.3": ">=5.7.3",
70
- "next@>=16.0.9 <16.1.5": ">=16.1.5",
71
- "preact@>=10.28.0 <10.28.2": ">=10.28.2",
72
- "devalue@>=5.1.0 <5.6.2": ">=5.6.2",
73
- "h3@<=1.15.4": ">=1.15.5",
74
- "koa@>=2.16.2 <2.16.3": ">=2.16.3",
75
- "lodash-es@>=4.0.0 <=4.17.22": ">=4.17.23",
76
- "lodash@>=4.0.0 <=4.17.22": ">=4.17.23",
77
- "diff@>=5.0.0 <5.2.2": ">=5.2.2"
78
- }
79
- },
80
- "scripts": {
81
- "build": "rollup -c",
82
- "test": "vitest run --passWithNoTests",
83
- "test:coverage": "vitest run --coverage --passWithNoTests",
84
- "test:coverage:ci": "vitest run --coverage --reporter=verbose --passWithNoTests",
85
- "prepublishOnly": "npm run build && npm run pack:strict",
86
- "yara:node:smoke": "tsx scripts/yara-node-smoke.ts",
87
- "yara:int:smoke": "tsx scripts/yara-integration-smoke.ts",
88
- "dev:remote": "tsx examples/remote-yara-server.ts",
89
- "docs:build": "hugo -s docs -D -d docs",
90
- "predocs:deploy": "npm run docs:build",
91
- "docs:deploy": "gh-pages -d docs -b gh-pages",
92
- "format": "biome format --write .",
93
- "format:check": "biome format .",
94
- "lint": "biome ci .",
95
- "lint:fix": "biome check --write .",
96
- "yara:check": "node scripts/yara-quick-check-cli.mjs",
97
- "build:core": "pnpm -r --filter '!./examples/*' --if-present build",
98
- "preview": "npm pack --dry-run",
99
- "typecheck": "tsc -p tsconfig.json --noEmit || tsc -p tsconfig.build.json --noEmit",
100
- "typecheck:strict": "tsc -p tsconfig.strict.json --noEmit",
101
- "smoke": "node scripts/smoke.mjs",
102
- "test:e2e": "node scripts/e2e.mjs",
103
- "repo:doctor": "pnpm install --frozen-lockfile && pnpm -r --if-present build && pnpm -r --if-present test && npm run -s preview || true && node scripts/smoke.mjs && node scripts/e2e.mjs || true",
104
- "audit:deps": "depcheck --skip-missing true || true",
105
- "audit:code": "knip --reporter compact || true",
106
- "audit:exports": "ts-prune -p tsconfig.json || true",
107
- "repo:audit": "node scripts/audit.mjs",
108
- "pack:check": "node scripts/pack-check.mjs",
109
- "pack:list": "pnpm -r --filter \"@pompelmi/*\" --if-present pack --json --dry-run",
110
- "pack:strict": "node scripts/pack-check.mjs --strict",
111
- "clean": "rimraf dist",
112
- "mentions:find": "node scripts/find-mentions.mjs",
113
- "mentions:render": "node scripts/render-mentions-readme.mjs",
114
- "mentions:inject": "node scripts/inject-mentions-readme.mjs",
115
- "mentions:update": "npm run mentions:find && npm run mentions:render && npm run mentions:inject"
116
- },
117
- "license": "MIT",
118
- "devDependencies": {
119
- "@biomejs/biome": "^2.2.4",
120
- "@pompelmi/core": "workspace:*",
121
- "@pompelmi/engine": "workspace:*",
122
- "@pompelmi/engine-heuristics": "workspace:^0.2.0",
123
- "@rollup/plugin-commonjs": "^29.0.2",
124
- "@rollup/plugin-node-resolve": "^16.0.1",
125
- "@rollup/plugin-typescript": "^12.1.4",
126
- "@types/cors": "^2.8.19",
127
- "@types/express": "^5.0.3",
128
- "@types/multer": "^2.0.0",
129
- "@types/node": "^25.5.0",
130
- "@types/react": "^19.1.8",
131
- "@types/unzipper": "^0.10.11",
132
- "@vitest/coverage-v8": "^4",
133
- "cors": "^2.8.5",
134
- "depcheck": "^1.4.7",
135
- "express": "^5.1.0",
136
- "gh-pages": "^6.3.0",
137
- "knip": "^6.1.1",
138
- "multer": "^2.0.2",
139
- "react": "^19.2.0",
140
- "rollup": "^4.x",
141
- "ts-prune": "^0.10.3",
142
- "tslib": "^2.8.1",
143
- "tsup": "^8",
144
- "tsx": "^4.20.3",
145
- "typescript": "^6.0.2",
146
- "vitest": "4.1.2"
147
- },
148
- "peerDependencies": {
149
- "react": "^18.0.0 || ^19.0.0",
150
- "react-dom": "^18.0.0 || ^19.0.0"
151
- },
152
- "peerDependenciesMeta": {
153
- "react": {
154
- "optional": true
155
- },
156
- "react-dom": {
157
- "optional": true
158
- }
12
+ "bugs": {
13
+ "url": "https://github.com/pompelmi/pompelmi/issues"
159
14
  },
160
- "optionalDependencies": {
161
- "@litko/yara-x": "^0.2.1"
162
- },
163
- "exports": {
164
- ".": {
165
- "types": "./dist/types/index.d.ts",
166
- "import": "./dist/pompelmi.esm.js",
167
- "require": "./dist/pompelmi.cjs",
168
- "default": "./dist/pompelmi.esm.js"
169
- },
170
- "./node": {
171
- "types": "./dist/types/index.d.ts",
172
- "import": "./dist/pompelmi.esm.js",
173
- "require": "./dist/pompelmi.cjs",
174
- "default": "./dist/pompelmi.esm.js"
175
- },
176
- "./browser": {
177
- "types": "./dist/types/browser-index.d.ts",
178
- "import": "./dist/pompelmi.browser.esm.js",
179
- "require": "./dist/pompelmi.browser.cjs",
180
- "default": "./dist/pompelmi.browser.esm.js"
181
- },
182
- "./react": {
183
- "types": "./dist/types/react-index.d.ts",
184
- "import": "./dist/pompelmi.react.esm.js",
185
- "require": "./dist/pompelmi.react.cjs",
186
- "default": "./dist/pompelmi.react.esm.js"
187
- },
188
- "./quarantine": {
189
- "types": "./dist/types/quarantine/index.d.ts",
190
- "import": "./dist/pompelmi.quarantine.esm.js",
191
- "require": "./dist/pompelmi.quarantine.cjs",
192
- "default": "./dist/pompelmi.quarantine.esm.js"
193
- },
194
- "./hooks": {
195
- "types": "./dist/types/hooks.d.ts",
196
- "import": "./dist/pompelmi.hooks.esm.js",
197
- "require": "./dist/pompelmi.hooks.cjs",
198
- "default": "./dist/pompelmi.hooks.esm.js"
199
- },
200
- "./audit": {
201
- "types": "./dist/types/audit.d.ts",
202
- "import": "./dist/pompelmi.audit.esm.js",
203
- "require": "./dist/pompelmi.audit.cjs",
204
- "default": "./dist/pompelmi.audit.esm.js"
205
- },
206
- "./policy-packs": {
207
- "types": "./dist/types/policy-packs.d.ts",
208
- "import": "./dist/pompelmi.policy-packs.esm.js",
209
- "require": "./dist/pompelmi.policy-packs.cjs",
210
- "default": "./dist/pompelmi.policy-packs.esm.js"
211
- },
212
- "./package.json": "./package.json"
213
- },
214
- "files": [
215
- "dist/",
216
- "README.md",
217
- "LICENSE",
218
- "package.json",
219
- "CHANGELOG*"
220
- ],
221
15
  "keywords": [
222
- "secure-file-upload",
223
- "file-upload-security",
224
- "upload-security",
225
- "upload-scanning",
226
- "file-scanning",
227
- "file-validation",
228
- "malware-scanner",
229
- "mime-sniffing",
230
- "magic-bytes",
231
- "archive-security",
232
- "zip-bomb-protection",
233
- "yara",
234
- "yara-rules",
235
- "local-first-security",
236
- "self-hosted-security",
237
- "nodejs-security",
238
- "typescript",
239
- "nodejs",
240
- "express",
241
- "nextjs",
242
- "nestjs",
243
- "fastify",
244
- "koa",
245
- "nuxt"
16
+ "clamav",
17
+ "antivirus",
18
+ "malware",
19
+ "virus",
20
+ "scan",
21
+ "security",
22
+ "file-scan"
246
23
  ],
247
- "directories": {
248
- "example": "examples"
249
- },
250
- "author": "Tommaso Bertocchi",
251
- "packageManager": "pnpm@9.12.0",
252
- "resolutions": {
253
- "process": "0.11.10"
254
- },
255
- "sideEffects": false,
256
- "engines": {
257
- "node": ">=18"
24
+ "type": "commonjs",
25
+ "main": "./src/index.js",
26
+ "scripts": {
27
+ "test": "node --test test/unit.test.js && node test/scan.test.js",
28
+ "lint": "eslint src/"
258
29
  },
259
- "publishConfig": {
260
- "access": "public"
30
+ "dependencies": {
31
+ "cross-spawn": "^7.0.6"
261
32
  },
262
- "types": "./dist/types/index.d.ts"
33
+ "devDependencies": {
34
+ "@eslint/js": "^10.0.1",
35
+ "eslint": "^10.2.0",
36
+ "globals": "^17.4.0"
37
+ }
263
38
  }
@@ -0,0 +1,48 @@
1
+ const spawn = require("cross-spawn");
2
+ const fs = require("fs");
3
+ const { getUpdaterCommand } = require('./InstallerCommand.js');
4
+ const { PLATFORM } = require('./constants.js');
5
+ const { DB_PATHS } = require('./config.js');
6
+
7
+ const MESSAGES = {
8
+ DB_PRESENT: "Virus database already present, skipping.",
9
+ SUCCESS: "Database updated successfully!",
10
+ FAILURE: (code) => `Database update failed with exit code: ${code}`,
11
+ STARTING: "Downloading virus definitions...",
12
+ PLATFORM_NOT_SUPPORTED: "Current platform is not supported."
13
+ };
14
+
15
+ function isDatabasePresent() {
16
+ const dbPath = DB_PATHS[PLATFORM];
17
+ return dbPath ? fs.existsSync(dbPath) : false;
18
+ }
19
+
20
+ function updateClamAVDatabase() {
21
+ return new Promise((resolve, reject) => {
22
+ if (isDatabasePresent()) {
23
+ console.log(MESSAGES.DB_PRESENT);
24
+ return resolve(MESSAGES.DB_PRESENT);
25
+ }
26
+
27
+ const [command, args] = getUpdaterCommand(PLATFORM);
28
+
29
+ if (!command) {
30
+ console.log(MESSAGES.PLATFORM_NOT_SUPPORTED);
31
+ return resolve(MESSAGES.PLATFORM_NOT_SUPPORTED);
32
+ }
33
+
34
+ console.log(MESSAGES.STARTING);
35
+
36
+ const child = spawn(command, args, { stdio: 'inherit' });
37
+ child.on('error', (err) => reject(err));
38
+ child.on('close', (code) => {
39
+ if (code !== 0) {
40
+ return reject(new Error(MESSAGES.FAILURE(code)));
41
+ }
42
+ console.log(MESSAGES.SUCCESS);
43
+ resolve(MESSAGES.SUCCESS);
44
+ });
45
+ });
46
+ }
47
+
48
+ module.exports = { updateClamAVDatabase };
@@ -0,0 +1,49 @@
1
+ const spawn = require("cross-spawn");
2
+ const { execSync } = require("child_process");
3
+ const { getInstallerCommand } = require('./InstallerCommand.js');
4
+ const { PLATFORM } = require('./constants.js')
5
+
6
+ const MESSAGES = {
7
+ ALREADY_INSTALLED: "ClamAV is already installed, skipping.",
8
+ SUCCESS: "Installation completed successfully!",
9
+ PLATFORM_NOT_SUPPORTED: "Current platform is not supported.",
10
+ FAILURE: (code) => `Installation failed with exit code: ${code}`
11
+ };
12
+
13
+ function isClamAVInstalled() {
14
+ const command = PLATFORM === 'win32' ? 'where clamscan' : 'which clamscan';
15
+ try {
16
+ execSync(command, { stdio: 'ignore' });
17
+ return true;
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+
23
+ function ClamAVInstaller() {
24
+ return new Promise((resolve, reject) => {
25
+ if (isClamAVInstalled()) {
26
+ console.log(MESSAGES.ALREADY_INSTALLED);
27
+ return resolve(MESSAGES.ALREADY_INSTALLED);
28
+ }
29
+
30
+ const [packageManager, packageToInstall] = getInstallerCommand(PLATFORM);
31
+
32
+ if (!packageManager) {
33
+ console.log(MESSAGES.PLATFORM_NOT_SUPPORTED);
34
+ return resolve(MESSAGES.PLATFORM_NOT_SUPPORTED);
35
+ }
36
+
37
+ const child = spawn(packageManager, packageToInstall, { stdio: 'inherit' });
38
+ child.on('error', (err) => reject(err));
39
+ child.on('close', (code) => {
40
+ if (code !== 0) {
41
+ return reject(new Error(MESSAGES.FAILURE(code)));
42
+ }
43
+ console.log(MESSAGES.SUCCESS);
44
+ resolve(MESSAGES.SUCCESS);
45
+ });
46
+ });
47
+ }
48
+
49
+ module.exports = { ClamAVInstaller};
@@ -0,0 +1,31 @@
1
+ const spawn = require("cross-spawn");
2
+ const fs = require("fs");
3
+ const { SCAN_RESULTS } = require('./config.js');
4
+
5
+ const MESSAGES = {
6
+ FILE_NOT_FOUND: (filePath) => `File not found: ${filePath}`,
7
+ UNEXPECTED_EXIT_CODE: (code) => `Unexpected exit code: ${code}`,
8
+ PROCESS_KILLED: (signal) => `Process killed by signal: ${signal}`,
9
+ };
10
+
11
+ function scan(filePath) {
12
+ return new Promise((resolve, reject) => {
13
+ if (typeof filePath !== 'string') {
14
+ return reject(new Error('filePath must be a string'));
15
+ }
16
+ if (!fs.existsSync(filePath)) {
17
+ return reject(new Error(MESSAGES.FILE_NOT_FOUND(filePath)));
18
+ }
19
+
20
+ const child = spawn('clamscan', ['--no-summary', filePath]);
21
+ child.on('error', (err) => reject(err));
22
+ child.on('close', (code, signal) => {
23
+ if (code === null) return reject(new Error(MESSAGES.PROCESS_KILLED(signal)));
24
+ const result = SCAN_RESULTS[code];
25
+ if (!result) return reject(new Error(MESSAGES.UNEXPECTED_EXIT_CODE(code)));
26
+ resolve(result);
27
+ });
28
+ });
29
+ }
30
+
31
+ module.exports = { scan };
@@ -0,0 +1,11 @@
1
+ const { INSTALLER_COMMANDS, UPDATER_COMMANDS } = require('./config.js');
2
+
3
+ function getInstallerCommand(platform) {
4
+ return INSTALLER_COMMANDS[platform] ?? [null, []];
5
+ }
6
+
7
+ function getUpdaterCommand(platform) {
8
+ return UPDATER_COMMANDS[platform] ?? [null, []];
9
+ }
10
+
11
+ module.exports = { getInstallerCommand, getUpdaterCommand };
package/src/config.js ADDED
@@ -0,0 +1,22 @@
1
+ module.exports = Object.freeze({
2
+ INSTALLER_COMMANDS: Object.freeze({
3
+ win32: ['choco', ['install', 'clamav', '-y']],
4
+ darwin: ['brew', ['install', 'clamav']],
5
+ linux: ['sudo', ['apt-get', 'install', '-y', 'clamav', 'clamav-daemon']],
6
+ }),
7
+ UPDATER_COMMANDS: Object.freeze({
8
+ win32: ['freshclam', []],
9
+ darwin: ['freshclam', []],
10
+ linux: ['sudo', ['freshclam']],
11
+ }),
12
+ DB_PATHS: Object.freeze({
13
+ darwin: '/usr/local/share/clamav/main.cvd',
14
+ linux: '/var/lib/clamav/main.cvd',
15
+ win32: 'C:\\ProgramData\\ClamAV\\main.cvd',
16
+ }),
17
+ SCAN_RESULTS: Object.freeze({
18
+ 0: 'Clean',
19
+ 1: 'Malicious',
20
+ 2: 'ScanError'
21
+ }),
22
+ });
@@ -0,0 +1,3 @@
1
+ module.exports = Object.freeze({
2
+ PLATFORM: process.platform
3
+ });
Binary file
Binary file
package/src/index.js ADDED
@@ -0,0 +1,5 @@
1
+ const { scan } = require('./ClamAVScanner.js');
2
+
3
+ const pompelmi = { scan };
4
+
5
+ module.exports = pompelmi;
package/CHANGELOG.md DELETED
@@ -1,71 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## Unreleased (main)
9
-
10
- ### Highlights
11
-
12
- - Fixed `@pompelmi/fastify-plugin` multipart dependency wiring and removed an unnecessary promise hop.
13
- - Refined the root README layout for faster first-run onboarding and clearer repo entry points.
14
- - Refreshed README badges and demo media so the public repo surface is easier to scan quickly.
15
- - Added verified mention badges to strengthen the top-level trust signals around adoption.
16
- - Tightened onboarding copy across the repo surfaces to make the docs-and-examples path easier to follow.
17
-
18
- ### Notes
19
-
20
- This section summarizes changes since the last tag: `v0.34.8`.
21
- Post-tag activity is currently limited, so the highlights above also surface the most recent user-visible commits from the current `v0.34.x` line for context.
22
- For full details, see GitHub Releases / tag diffs.
23
-
24
- ## [0.27.1] - 2026-01-26
25
-
26
- ### Security
27
- - ๐Ÿ” **Critical Security Fixes**: Fixed 89 vulnerabilities (6 critical, 36 high, 35 moderate, 12 low)
28
- - ๐Ÿ” **Dependency Updates**: Updated 26 package overrides including esbuild, vite, astro, next, body-parser, qs, lodash
29
- - ๐Ÿ” **CVE Fixes**: Patched multiple CVEs in dependencies
30
-
31
- ### Fixed
32
- - ๐Ÿ› Fixed GitHub Actions workflow with correct pnpm/action-setup SHA
33
- - ๐Ÿ› Resolved CI/CD pipeline execution errors
34
-
35
- ## [0.27.0] - 2026-01-26
36
-
37
- ### Added
38
- - ๐Ÿš€ **Enhanced Performance Monitoring**: Added detailed performance metrics tracking for scan operations
39
- - ๐Ÿ”’ **Advanced Threat Detection**: Improved heuristics engine with better polyglot file detection
40
- - ๐Ÿ“Š **Scan Statistics API**: New utility functions to aggregate and analyze scan results
41
- - ๐Ÿ›ก๏ธ **Enhanced ZIP Bomb Protection**: Improved nested archive detection with configurable depth limits
42
- - ๐Ÿ” **Content Analysis**: Advanced content inspection for embedded scripts and obfuscated code
43
- - ๐Ÿ“ **Better TypeScript Types**: Enhanced type definitions for improved developer experience
44
- - โšก **Async Performance**: Optimized async operations for better throughput
45
- - ๐ŸŽฏ **Scan Context Enrichment**: Enhanced metadata collection during file scanning
46
-
47
- ### Improved
48
- - ๐Ÿ”ง **Error Handling**: More descriptive error messages with actionable suggestions
49
- - ๐Ÿ“ˆ **Memory Efficiency**: Reduced memory footprint for large file operations
50
- - ๐Ÿšฆ **CI/CD Pipeline**: Enhanced GitHub Actions workflows with better caching
51
- - ๐Ÿ“š **Documentation**: Updated examples and API documentation
52
- - ๐Ÿงช **Test Coverage**: Added comprehensive test cases for new features
53
-
54
- ### Fixed
55
- - ๐Ÿ› Fixed edge cases in MIME type detection
56
- - ๐Ÿ› Resolved memory leaks in stream processing
57
- - ๐Ÿ› Corrected verdict mapping for multi-threaded scenarios
58
-
59
- ### Security
60
- - ๐Ÿ” Updated dependencies to patch known vulnerabilities
61
- - ๐Ÿ” Enhanced input validation for all public APIs
62
- - ๐Ÿ” Improved sanitization for file metadata
63
-
64
- ## [0.26.0] - 2025-12-15
65
-
66
- ### Added
67
- - Initial stable release with core scanning functionality
68
- - YARA integration support
69
- - ZIP bomb protection
70
- - Framework adapters (Express, Koa, Fastify, Next.js)
71
- - Browser and Node.js support
@@ -1,128 +0,0 @@
1
- 'use strict';
2
-
3
- var fs = require('fs');
4
-
5
- function _interopNamespaceDefault(e) {
6
- var n = Object.create(null);
7
- if (e) {
8
- Object.keys(e).forEach(function (k) {
9
- if (k !== 'default') {
10
- var d = Object.getOwnPropertyDescriptor(e, k);
11
- Object.defineProperty(n, k, d.get ? d : {
12
- enumerable: true,
13
- get: function () { return e[k]; }
14
- });
15
- }
16
- });
17
- }
18
- n.default = e;
19
- return Object.freeze(n);
20
- }
21
-
22
- var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
23
-
24
- /**
25
- * Audit trail for Pompelmi scan and quarantine events.
26
- *
27
- * Produces structured, append-only audit records suitable for:
28
- * - compliance logging (HIPAA, SOC 2, ISO 27001)
29
- * - SIEM ingestion
30
- * - operational dashboards
31
- * - incident response
32
- *
33
- * Usage:
34
- * ```ts
35
- * import { AuditTrail } from 'pompelmi/audit';
36
- *
37
- * const audit = new AuditTrail({ dest: 'file', path: './audit.jsonl' });
38
- * audit.logScanComplete({ filename: 'upload.zip', verdict: 'suspicious', ... });
39
- * audit.logQuarantine({ entryId: '...', sha256: '...', ... });
40
- * ```
41
- *
42
- * @module audit
43
- */
44
- // โ”€โ”€ AuditTrail โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
45
- class AuditTrail {
46
- constructor(options = {}) {
47
- this.options = {
48
- output: options.output ?? { dest: "console" },
49
- pretty: options.pretty ?? false,
50
- };
51
- }
52
- /** Log a completed scan. */
53
- logScanComplete(report, extra) {
54
- const record = {
55
- timestamp: new Date().toISOString(),
56
- event: report.verdict !== "clean" ? "threat.detected" : "scan.complete",
57
- verdict: report.verdict,
58
- matchCount: report.matches?.length ?? 0,
59
- durationMs: report.durationMs,
60
- engine: report.engine,
61
- mimeType: report.file?.mimeType,
62
- ...extra,
63
- };
64
- void this.write(record);
65
- }
66
- /** Log a scan error. */
67
- logScanError(error, extra) {
68
- const record = {
69
- timestamp: new Date().toISOString(),
70
- event: "scan.error",
71
- verdict: "clean", // unknown at this point
72
- matchCount: 0,
73
- error: error instanceof Error ? error.message : String(error),
74
- ...extra,
75
- };
76
- void this.write(record);
77
- }
78
- /** Log a new quarantine entry. */
79
- logQuarantine(entry, correlationId) {
80
- const record = {
81
- timestamp: new Date().toISOString(),
82
- event: "quarantine.created",
83
- quarantineId: entry.id,
84
- filename: entry.file.originalName,
85
- sha256: entry.file.sha256,
86
- uploadedBy: entry.file.uploadedBy,
87
- correlationId,
88
- };
89
- void this.write(record);
90
- }
91
- /** Log a quarantine resolution (promote or delete). */
92
- logQuarantineResolved(entry, correlationId) {
93
- const record = {
94
- timestamp: new Date().toISOString(),
95
- event: entry.status === "deleted" ? "quarantine.deleted" : "quarantine.resolved",
96
- quarantineId: entry.id,
97
- filename: entry.file.originalName,
98
- sha256: entry.file.sha256,
99
- decision: entry.status === "promoted" ? "promote" : "delete",
100
- reviewedBy: entry.reviewedBy,
101
- reviewNote: entry.reviewNote,
102
- correlationId,
103
- };
104
- void this.write(record);
105
- }
106
- async write(record) {
107
- const line = this.options.pretty ? JSON.stringify(record, null, 2) : JSON.stringify(record);
108
- const { output } = this.options;
109
- try {
110
- if (output.dest === "console") {
111
- process.stdout.write(line + "\n");
112
- }
113
- else if (output.dest === "file") {
114
- // Append a newline-delimited JSON (NDJSON) record.
115
- await fs__namespace.promises.appendFile(output.path, line + "\n", "utf8");
116
- }
117
- else if (output.dest === "custom") {
118
- await output.write(record);
119
- }
120
- }
121
- catch {
122
- // Audit failures must never interrupt the upload pipeline.
123
- }
124
- }
125
- }
126
-
127
- exports.AuditTrail = AuditTrail;
128
- //# sourceMappingURL=pompelmi.audit.cjs.map