Clamscan
A robust ClamAV virus scanning library supporting scanning files, directories, and streams with local sockets, local/remote TCP, and local clamscan/clamdscan binaries (with failover).
Install / Use
/learn @kylefarris/ClamscanREADME
NodeJS Clamscan Virus Scanning Utility
[![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Node.js Version][node-image]][node-url]
Use Node JS to scan files on your server with ClamAV's clamscan/clamdscan binary or via TCP to a remote server or local UNIX Domain socket. This is especially useful for scanning uploaded files provided by un-trusted sources.
!!IMPORTANT
If you are using a version prior to 1.2.0, please upgrade! There was a security vulnerability in previous versions that can cause false negative in some edge cases. Specific details on how the attack could be implemented will not be disclosed here. Please update to 1.2.0 or greater ASAP. No breaking changes are included, only the security patch.
All older versions in NPM have been deprecated.
Version 1.0.0 Information
If you are migrating from v0.8.5 or less to v1.0.0 or greater, please read the release notes as there are some breaking changes (but also some awesome new features!).
Table of Contents
- Dependencies
- How to Install
- License Info
- Getting Started
- Basic Usage Example
- API
- Contribute
- Resources used to help develop this module
Dependencies
To use local binary method of scanning
You will need to install ClamAV's clamscan binary and/or have clamdscan daemon running on your server. On linux, it's quite simple.
Fedora-based distros:
sudo yum install clamav
Debian-based distros:
sudo apt-get install clamav clamav-daemon
For OS X, you can install clamav with brew:
sudo brew install clamav
To use ClamAV using TCP sockets
You will need access to either:
- A local UNIX Domain socket for a local instance of
clamd
- Follow instructions in To use local binary method of scanning.
- Socket file is usually:
/var/run/clamd.scan/clamd.sock - Make sure
clamdis running on your local server
- A local/remote
clamddaemon
- Must know the port the daemon is running on
- If running on remote server, you must have the IP address/domain name
- If running on remote server, it's firewall must have the appropriate TCP port(s) open
- Make sure
clamdis running on your local/remote server
NOTE: This module is not intended to work on a Windows server. This would be a welcome addition if someone wants to add that feature (I may get around to it one day but have no urgent need for this).
How to Install
npm install clamscan
License Info
Licensed under the MIT License:
Getting Started
All of the values listed in the example below represent the default values for their respective configuration item.
You can simply do this:
const NodeClam = require('clamscan');
const ClamScan = new NodeClam().init();
And, you'll be good to go.
BUT: If you want more control, you can specify all sorts of options.
const NodeClam = require('clamscan');
const ClamScan = new NodeClam().init({
removeInfected: false, // If true, removes infected files
quarantineInfected: false, // False: Don't quarantine, Path: Moves files to this place.
scanLog: null, // Path to a writeable log file to write scan results into
debugMode: false, // Whether or not to log info/debug/error msgs to the console
fileList: null, // path to file containing list of files to scan (for scanFiles method)
scanRecursively: true, // If true, deep scan folders recursively
clamscan: {
path: '/usr/bin/clamscan', // Path to clamscan binary on your server
db: null, // Path to a custom virus definition database
scanArchives: true, // If true, scan archives (ex. zip, rar, tar, dmg, iso, etc...)
active: true // If true, this module will consider using the clamscan binary
},
clamdscan: {
socket: false, // Socket file for connecting via TCP
host: false, // IP of host to connect to TCP interface
port: false, // Port of host to use when connecting via TCP interface
timeout: 60000, // Timeout for scanning files
localFallback: true, // Use local preferred binary to scan if socket/tcp fails
path: '/usr/bin/clamdscan', // Path to the clamdscan binary on your server
configFile: null, // Specify config file if it's in an unusual place
multiscan: true, // Scan using all available cores! Yay!
reloadDb: false, // If true, will re-load the DB on every call (slow)
active: true, // If true, this module will consider using the clamdscan binary
bypassTest: false, // Check to see if socket is available when applicable
tls: false, // Use plaintext TCP to connect to clamd
},
preference: 'clamdscan' // If clamdscan is found and active, it will be used by default
});
Here is a non-default values example (to help you get an idea of what proper-looking values could be):
const NodeClam = require('clamscan');
const ClamScan = new NodeClam().init({
removeInfected: true, // Removes files if they are infected
quarantineInfected: '~/infected/', // Move file here. removeInfected must be FALSE, though.
scanLog: '/var/log/node-clam', // You're a detail-oriented security professional.
debugMode: true, // This will put some debug info in your js console
fileList: '/home/webuser/scanFiles.txt', // path to file containing list of files to scan
scanRecursively: false, // Choosing false here will save some CPU cycles
clamscan: {
path: '/usr/bin/clam', // I dunno, maybe your clamscan is just call "clam"
scanArchives: false, // Choosing false here will save some CPU cycles
db: '/usr/bin/better_clam_db', // Path to a custom virus definition database
active: false // you don't want to use this at all because it's evil
},
clamdscan: {
socket: '/var/run/clamd.scan/clamd.sock', // This is pretty typical
host: '127.0.0.1', // If you want to connect locally but not through socket
port: 12345, // Because, why not
timeout: 300000, // 5 minutes
localFallback: false, // Do no fail over to binary-method of scanning
path: '/bin/clamdscan', // Special path to the clamdscan binary on your server
configFile: '/etc/clamd.d/daemon.conf', // A fairly typical config location
multiscan: false, // You hate speed and multi-threaded awesome-sauce
reloadDb: true, // You want your scans to run slow like with clamscan
active: false, // you don't want to use this at all because it's evil
bypassTest: true, // Don't check to see if socket is available. You should probably never set this to true.
tls: true, // Connect to clamd over TLS
},
preference: 'clamscan' // If clamscan is found and active, it will be used by default
});
NOTE: If a valid port is provided but no host value is provided, the clamscan will assume 'localhost' for host.
A note about using this module via sockets or TCP
As of version v1.0.0, this module supports communication with a local or remote ClamAV daemon through Unix Domain sockets or a TCP host/port combo. If you supply both in your configuration object, the UNIX Domain socket option will be used. The module will not not fallback to using the alternative Host/Port method. If you wish to connect via Host/Port and not a Socket, please either omit the socket property in the config object or use socket: null.
If you specify a valid clamscan/clamdscan binary in your config and you set clamdscan.localFallback: true in your config, this module will fallback to the traditional way this module has worked--using a binary directly/locally.
Also, there are some caveats to using the socket/tcp based approach:
-
The following configuration items are not honored (unless the module falls back to binary method):
removeInfected- remote clamd service config will dictate thisquarantineInfected- remote clamd service config will dictate thisscanLog- remote clamd service config will dictate thisfileList- this simply won't be availableclamscan.db- only available on fallbackclamscan.scanArchives- only available on fallbackclamscan.path- only available on fallbackclamdscan.configFile- only available on fallbackclamdscan.path- only available on fallback
Basic Usage Example
For the sake of brevity, all the examples in the API section will be shortened to just the relevant parts related specifically to that example. In those examples, we'll assume you already have an instance of the clamscan object. Since initializing the module returns a promise, you'll have to resolve that promise to get an instance of the clamscan object.
Below is the full example of how you could get that instance and run some methods:
const NodeClam = require('clamscan');
const ClamScan = new NodeClam().init(options);
// Get instance by resolving ClamScan promise object
ClamScan.then(async clamscan =>
