feat(ClamAvService): Add stream scanning methods to ClamAvService
This commit is contained in:
parent
8acfedd7f3
commit
6300843616
@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-02-05 - 1.2.0 - feat(ClamAvService)
|
||||
Add stream scanning methods to ClamAvService
|
||||
|
||||
- Added scanStream method to support scanning NodeJS streams directly.
|
||||
- Introduced scanWebStream method for scanning web resources as streams.
|
||||
- Integrated stream scanning into existing ClamAvService class.
|
||||
|
||||
## 2025-02-03 - 1.1.2 - fix(documentation)
|
||||
Update readme with additional legal and trademark information
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
"dependencies": {
|
||||
"@push.rocks/smartfile": "^11.1.5",
|
||||
"@push.rocks/smartpath": "^5.0.18",
|
||||
"@push.rocks/smartstream": "^3.2.5",
|
||||
"axios": "^1.7.9",
|
||||
"tar": "^7.4.3"
|
||||
},
|
||||
|
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@ -14,6 +14,9 @@ importers:
|
||||
'@push.rocks/smartpath':
|
||||
specifier: ^5.0.18
|
||||
version: 5.0.18
|
||||
'@push.rocks/smartstream':
|
||||
specifier: ^3.2.5
|
||||
version: 3.2.5
|
||||
axios:
|
||||
specifier: ^1.7.9
|
||||
version: 1.7.9
|
||||
|
29
readme.md
29
readme.md
@ -94,6 +94,35 @@ async function main() {
|
||||
main().catch(console.error);
|
||||
```
|
||||
|
||||
### Streaming Scanning
|
||||
|
||||
The `ClamAvService` now also supports scanning streams directly using two new methods:
|
||||
|
||||
- `scanStream(stream: NodeJS.ReadableStream)`: Scans a NodeJS stream (local file streams, network streams, etc.)
|
||||
- `scanWebStream(url: string)`: Fetches a web resource as a stream and scans it
|
||||
|
||||
#### Example Usage
|
||||
|
||||
```typescript
|
||||
import { ClamAvService } from '@push.rocks/smartantivirus';
|
||||
import { createReadStream } from 'fs';
|
||||
|
||||
async function main() {
|
||||
const clamService = new ClamAvService('127.0.0.1', 3310);
|
||||
|
||||
// Example 1: Scanning a local file stream
|
||||
const fileStream = createReadStream('path/to/local/file');
|
||||
const streamResult = await clamService.scanStream(fileStream);
|
||||
console.log('Stream Scan Result:', streamResult);
|
||||
|
||||
// Example 2: Scanning a web resource
|
||||
const webResult = await clamService.scanWebStream('http://example.com/file');
|
||||
console.log('Web Stream Scan Result:', webResult);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
```
|
||||
|
||||
**Breaking Down the Example:**
|
||||
|
||||
1. **Initialization**: We start by creating an instance of the `ClamAvService` class. It takes two optional parameters: the host and port where your ClamAV daemon is running. By default, it assumes `127.0.0.1` and `3310`.
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { expect, tap } from '../ts/plugins.js';
|
||||
import { tap, expect } from '@push.rocks/tapbundle';
|
||||
import * as smartantivirus from '../ts/index.js';
|
||||
import { setupClamAV, cleanupClamAV } from './helpers/clamav.helper.js';
|
||||
|
||||
|
@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@push.rocks/smartantivirus',
|
||||
version: '1.1.2',
|
||||
version: '1.2.0',
|
||||
description: 'A Node.js package for integrating antivirus scanning capabilities using ClamAV, allowing in-memory file and data scanning.'
|
||||
}
|
||||
|
@ -111,4 +111,77 @@ export class ClamAvService {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans data from a NodeJS stream using ClamAV daemon's INSTREAM command.
|
||||
*/
|
||||
public async scanStream(stream: NodeJS.ReadableStream): Promise<{ isInfected: boolean; reason?: string }> {
|
||||
await this.ensureContainerStarted();
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = new net.Socket();
|
||||
|
||||
client.connect(this.port, this.host, () => {
|
||||
console.log('Connected to ClamAV daemon for stream scanning');
|
||||
client.write('zINSTREAM\0');
|
||||
|
||||
stream.on('data', (chunk: Buffer) => {
|
||||
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
||||
const sizeBuf = Buffer.alloc(4);
|
||||
sizeBuf.writeUInt32BE(buf.length, 0);
|
||||
client.write(sizeBuf);
|
||||
client.write(buf);
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
const endOfStream = Buffer.alloc(4);
|
||||
endOfStream.writeUInt32BE(0, 0);
|
||||
console.log('Stream ended, sending end-of-stream signal');
|
||||
client.write(endOfStream);
|
||||
});
|
||||
|
||||
stream.on('error', (err) => {
|
||||
console.error('Error reading stream:', err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
|
||||
client.on('data', (data) => {
|
||||
const response = data.toString();
|
||||
console.log('Raw Response from ClamAV (stream):', response);
|
||||
const isInfected = response.includes('FOUND');
|
||||
const reason = isInfected ? response.split('FOUND')[0].trim() : undefined;
|
||||
resolve({ isInfected, reason });
|
||||
client.end();
|
||||
});
|
||||
|
||||
client.on('error', (err) => {
|
||||
console.error('Error with ClamAV stream scanning:', err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a file from a web URL as a stream using ClamAV daemon's INSTREAM command.
|
||||
*/
|
||||
public async scanFileFromWebAsStream(url: string): Promise<{ isInfected: boolean; reason?: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const protocol = url.startsWith('https') ? plugins.https : plugins.http;
|
||||
protocol.get(url, (response) => {
|
||||
this.scanStream(response).then(resolve).catch(reject);
|
||||
}).on('error', (err) => {
|
||||
console.error('Error fetching URL:', err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a web resource by URL using ClamAV daemon's INSTREAM command.
|
||||
*/
|
||||
public async scanWebStream(webstreamArg: ReadableStream): Promise<{ isInfected: boolean; reason?: string }> {
|
||||
// Convert the web ReadableStream to a NodeJS ReadableStream
|
||||
const nodeStream = plugins.smartstream.nodewebhelpers.convertWebReadableToNodeReadable(webstreamArg);
|
||||
return this.scanStream(nodeStream);
|
||||
}
|
||||
}
|
@ -1,2 +1,2 @@
|
||||
export * from './classes.smartantivirus.js';
|
||||
export * from './classes.clamavservice.js';
|
||||
export * from './classes.clamav.manager.js';
|
@ -5,6 +5,8 @@ import { exec, spawn } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import { EventEmitter } from 'events';
|
||||
import net from 'net';
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
|
||||
export {
|
||||
fs,
|
||||
@ -13,19 +15,20 @@ export {
|
||||
spawn,
|
||||
promisify,
|
||||
EventEmitter,
|
||||
net
|
||||
net,
|
||||
http,
|
||||
https
|
||||
};
|
||||
|
||||
// @push.rocks scope
|
||||
import * as smartpath from '@push.rocks/smartpath';
|
||||
import * as smartfile from '@push.rocks/smartfile';
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import * as smartstream from '@push.rocks/smartstream';
|
||||
|
||||
export {
|
||||
smartpath,
|
||||
smartfile,
|
||||
expect,
|
||||
tap
|
||||
smartstream,
|
||||
};
|
||||
|
||||
// Third party scope
|
||||
|
Loading…
x
Reference in New Issue
Block a user