pompelmi 1.14.0 → 1.16.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 +64 -1
- package/llms.txt +12 -0
- package/package.json +6 -3
- package/packages/hono/README.md +160 -0
- package/packages/hono/index.d.ts +29 -0
- package/packages/hono/index.js +74 -0
- package/packages/hono/package.json +40 -0
- package/packages/remix/README.md +142 -0
- package/packages/remix/index.d.ts +50 -0
- package/packages/remix/index.js +96 -0
- package/packages/remix/package.json +38 -0
- package/packages/sveltekit/README.md +138 -0
- package/packages/sveltekit/index.d.ts +59 -0
- package/packages/sveltekit/index.js +100 -0
- package/packages/sveltekit/package.json +38 -0
- package/packages/testing/README.md +126 -0
- package/packages/testing/index.d.ts +44 -0
- package/packages/testing/index.js +82 -0
- package/packages/testing/package.json +35 -0
- package/src/BufferScanner.js +3 -0
- package/src/ClamdScanner.js +38 -14
- package/src/StreamScanner.js +3 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Verdict } = require('pompelmi');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a mock pompelmi scanner where all scan methods resolve to
|
|
7
|
+
* the given verdict.
|
|
8
|
+
*
|
|
9
|
+
* @param {symbol} defaultVerdict - One of Verdict.Clean, Verdict.Malicious, or Verdict.ScanError.
|
|
10
|
+
* @returns {{ scan, scanBuffer, scanStream, Verdict }}
|
|
11
|
+
*/
|
|
12
|
+
function createMockScanner(defaultVerdict) {
|
|
13
|
+
if (defaultVerdict !== Verdict.Clean &&
|
|
14
|
+
defaultVerdict !== Verdict.Malicious &&
|
|
15
|
+
defaultVerdict !== Verdict.ScanError) {
|
|
16
|
+
throw new TypeError('defaultVerdict must be one of Verdict.Clean, Verdict.Malicious, or Verdict.ScanError');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
Verdict,
|
|
21
|
+
scan: () => Promise.resolve(defaultVerdict),
|
|
22
|
+
scanBuffer: () => Promise.resolve(defaultVerdict),
|
|
23
|
+
scanStream: () => Promise.resolve(defaultVerdict),
|
|
24
|
+
scanS3: () => Promise.resolve(defaultVerdict),
|
|
25
|
+
_verdict: defaultVerdict,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Shorthand: returns a mock scanner that always resolves to Verdict.Clean.
|
|
31
|
+
*/
|
|
32
|
+
function mockClean() {
|
|
33
|
+
return createMockScanner(Verdict.Clean);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Shorthand: returns a mock scanner that always resolves to Verdict.Malicious.
|
|
38
|
+
* The virusName parameter is stored on the scanner for inspection in tests.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} [virusName='Win.Malware.Test'] - Virus name label (stored as scanner.virusName).
|
|
41
|
+
*/
|
|
42
|
+
function mockInfected(virusName) {
|
|
43
|
+
const scanner = createMockScanner(Verdict.Malicious);
|
|
44
|
+
scanner.virusName = virusName || 'Win.Malware.Test';
|
|
45
|
+
return scanner;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Shorthand: returns a mock scanner that always resolves to Verdict.ScanError.
|
|
50
|
+
*/
|
|
51
|
+
function mockScanError() {
|
|
52
|
+
return createMockScanner(Verdict.ScanError);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Wraps a test function with a mocked pompelmi scanner.
|
|
57
|
+
* The scanner is passed as the first argument to fn.
|
|
58
|
+
*
|
|
59
|
+
* This is a lightweight helper — for full module-level mocking in Jest/Vitest,
|
|
60
|
+
* use jest.mock() / vi.mock() directly.
|
|
61
|
+
*
|
|
62
|
+
* @param {symbol} verdict - Verdict to mock.
|
|
63
|
+
* @param {Function} fn - Test function that receives the mock scanner.
|
|
64
|
+
* @returns {Promise}
|
|
65
|
+
*/
|
|
66
|
+
function withMockedPompelmi(verdict, fn) {
|
|
67
|
+
const scanner = createMockScanner(verdict);
|
|
68
|
+
try {
|
|
69
|
+
return Promise.resolve(fn(scanner));
|
|
70
|
+
} catch (err) {
|
|
71
|
+
return Promise.reject(err);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
createMockScanner,
|
|
77
|
+
mockClean,
|
|
78
|
+
mockInfected,
|
|
79
|
+
mockScanError,
|
|
80
|
+
withMockedPompelmi,
|
|
81
|
+
Verdict,
|
|
82
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pompelmi/testing",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Mock utilities for unit-testing applications that use pompelmi — Jest, Vitest, and Node test runner",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "pompelmi contributors",
|
|
7
|
+
"homepage": "https://pompelmi.app",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/pompelmi/pompelmi.git",
|
|
11
|
+
"directory": "packages/testing"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"pompelmi",
|
|
15
|
+
"testing",
|
|
16
|
+
"mock",
|
|
17
|
+
"jest",
|
|
18
|
+
"vitest",
|
|
19
|
+
"clamav",
|
|
20
|
+
"antivirus",
|
|
21
|
+
"unit-test"
|
|
22
|
+
],
|
|
23
|
+
"main": "./index.js",
|
|
24
|
+
"types": "./index.d.ts",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "node --test test/index.test.js"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"pompelmi": ">=1.14.0"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"registry": "https://registry.npmjs.org/",
|
|
33
|
+
"access": "public"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/BufferScanner.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
const net = require('net');
|
|
4
4
|
const { Verdict } = require('./verdicts.js');
|
|
5
5
|
|
|
6
|
+
// net.createConnection is polyfilled by Bun — no code changes needed
|
|
7
|
+
const isBun = typeof Bun !== 'undefined'; // eslint-disable-line no-unused-vars
|
|
8
|
+
|
|
6
9
|
const CLAMD_INSTREAM = Buffer.from('zINSTREAM\0');
|
|
7
10
|
const CHUNK_SIZE = 64 * 1024;
|
|
8
11
|
|
package/src/ClamdScanner.js
CHANGED
|
@@ -4,6 +4,8 @@ const net = require('net');
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const { Verdict } = require('./verdicts.js');
|
|
6
6
|
|
|
7
|
+
const isBun = typeof Bun !== 'undefined';
|
|
8
|
+
|
|
7
9
|
// ClamAV INSTREAM protocol:
|
|
8
10
|
// 1. Send "zINSTREAM\0"
|
|
9
11
|
// 2. Send N chunks, each prefixed with a 4-byte big-endian length
|
|
@@ -63,24 +65,46 @@ function scanViaClamd(filePath, options = {}) {
|
|
|
63
65
|
conn.on('data', (chunk) => chunks.push(chunk));
|
|
64
66
|
conn.on('end', () => settle(resolve, parseClamdResponse(Buffer.concat(chunks))));
|
|
65
67
|
|
|
66
|
-
conn.on('connect', () => {
|
|
68
|
+
conn.on('connect', async () => {
|
|
67
69
|
conn.write(CLAMD_INSTREAM);
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
if (isBun) {
|
|
72
|
+
// Bun.file() is faster than fs.createReadStream on Bun
|
|
73
|
+
let fileData;
|
|
74
|
+
try {
|
|
75
|
+
fileData = await Bun.file(filePath).bytes();
|
|
76
|
+
} catch (err) {
|
|
77
|
+
return settle(reject, err);
|
|
78
|
+
}
|
|
79
|
+
const buf = Buffer.from(fileData);
|
|
80
|
+
let offset = 0;
|
|
81
|
+
while (offset < buf.length) {
|
|
82
|
+
const chunk = buf.slice(offset, offset + CHUNK_SIZE);
|
|
83
|
+
const header = Buffer.allocUnsafe(4);
|
|
84
|
+
header.writeUInt32BE(chunk.length, 0);
|
|
85
|
+
conn.write(header);
|
|
86
|
+
conn.write(chunk);
|
|
87
|
+
offset += chunk.length;
|
|
88
|
+
}
|
|
81
89
|
conn.write(Buffer.alloc(4)); // terminating zero-length chunk
|
|
82
90
|
conn.end();
|
|
83
|
-
}
|
|
91
|
+
} else {
|
|
92
|
+
const fileStream = fs.createReadStream(filePath, { highWaterMark: CHUNK_SIZE });
|
|
93
|
+
|
|
94
|
+
fileStream.on('error', (err) => settle(reject, err));
|
|
95
|
+
|
|
96
|
+
fileStream.on('data', (chunk) => {
|
|
97
|
+
const header = Buffer.allocUnsafe(4);
|
|
98
|
+
header.writeUInt32BE(chunk.length, 0);
|
|
99
|
+
conn.write(header);
|
|
100
|
+
conn.write(chunk);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
fileStream.on('end', () => {
|
|
104
|
+
conn.write(Buffer.alloc(4)); // terminating zero-length chunk
|
|
105
|
+
conn.end();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
84
108
|
});
|
|
85
109
|
});
|
|
86
110
|
}
|
package/src/StreamScanner.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
const net = require('net');
|
|
4
4
|
const { Verdict } = require('./verdicts.js');
|
|
5
5
|
|
|
6
|
+
// net.createConnection is polyfilled by Bun — no code changes needed
|
|
7
|
+
const isBun = typeof Bun !== 'undefined'; // eslint-disable-line no-unused-vars
|
|
8
|
+
|
|
6
9
|
const CLAMD_INSTREAM = Buffer.from('zINSTREAM\0');
|
|
7
10
|
|
|
8
11
|
function parseClamdResponse(raw) {
|