Reusable antivirus file scanning module using ClamAV
Project description
tns-antivirus
Reusable antivirus file scanning module using ClamAV. Scan files and get clean / infected results. All connection details passed at initialization — no hardcoded config, no env vars.
Installation
pip install tns-antivirus
Quick Start
from antivirus import AntivirusScanner
scanner = AntivirusScanner(clamav_host="107.21.176.2", clamav_port=3310)
result = scanner.scan(file_bytes, filename="resume.pdf")
if result.is_clean:
print("Safe to upload!")
elif result.is_infected:
print(f"Virus detected: {result.virus_name}")
How It Works
Your Service → AntivirusScanner.scan(file_bytes) → ClamAV Daemon (TCP)
↓
ScanResult(is_clean=True/False)
- Sends file bytes to ClamAV daemon over raw TCP socket (
zINSTREAMprotocol) - Validates file before scanning (dangerous extensions, empty files, size limits)
- Retries with exponential backoff if ClamAV is temporarily unavailable
- Returns a
ScanResult— your service decides what to do with it
Integration Example (FastAPI Service)
Step 1: Add to requirements.txt
tns-antivirus==0.1.0
Step 2: Add settings to app/core/config.py
CLAMAV_HOST: str = "107.21.176.2"
CLAMAV_PORT: int = 3310
Step 3: Create app/core/antivirus_config.py
from antivirus import AntivirusScanner
from app.core.config import settings
scanner = AntivirusScanner(
clamav_host=settings.CLAMAV_HOST,
clamav_port=settings.CLAMAV_PORT,
)
Step 4: Use in your route or service
from fastapi import UploadFile
from app.core.antivirus_config import scanner
async def upload_document(file: UploadFile):
file_bytes = await file.read()
result = scanner.scan(file_bytes, filename=file.filename)
if result.is_infected:
return {"error": f"Virus detected: {result.virus_name}"}
if not result.is_clean:
return {"error": result.error}
# File is safe — upload to S3, save to DB, etc.
s3_url = upload_to_s3(file_bytes, key=f"uploads/{file.filename}")
return {"file_url": s3_url, "scan_status": result.status}
API Reference
AntivirusScanner(clamav_host, clamav_port, ...)
| Parameter | Type | Default | Description |
|---|---|---|---|
clamav_host |
str |
required | ClamAV daemon IP/hostname |
clamav_port |
int |
3310 |
ClamAV daemon port |
timeout |
int |
5 |
Socket timeout in seconds |
max_retries |
int |
3 |
Retry attempts with exponential backoff |
max_file_size |
int |
104857600 |
Max file size in bytes (default 100MB) |
dangerous_extensions |
list |
see below | Blocked file extensions |
Default dangerous extensions: .exe, .bat, .cmd, .scr, .com, .pif, .vbs, .js, .msi, .dll
Methods
| Method | Returns | Description |
|---|---|---|
scan(file_data, filename) |
ScanResult |
Validate + scan file bytes |
is_healthy() |
bool |
Check if ClamAV daemon is reachable |
get_version() |
str | None |
Get ClamAV version string |
ScanResult
| Field | Type | Description |
|---|---|---|
status |
str |
"clean", "infected", "validation_failed", "error" |
is_clean |
bool |
True if file passed all checks |
is_infected |
bool |
True if virus found |
filename |
str |
Original filename |
file_size |
int |
File size in bytes |
virus_name |
str | None |
Virus name (only if infected) |
file_hash |
str | None |
SHA-256 hash of the file |
scan_time_ms |
float |
Total scan time in milliseconds |
error |
str | None |
Error message (only if failed) |
timestamp |
datetime |
When the scan was performed |
Response Examples
Clean file:
{
"status": "clean",
"is_clean": true,
"is_infected": false,
"filename": "resume.pdf",
"file_size": 45231,
"file_hash": "a3f2b8c1d4e5f6...",
"scan_time_ms": 120.5,
"virus_name": null,
"error": null
}
Infected file:
{
"status": "infected",
"is_clean": false,
"is_infected": true,
"filename": "bad.pdf",
"file_size": 12000,
"virus_name": "Eicar-Test-Signature",
"scan_time_ms": 85.2,
"error": null
}
Validation failed (e.g., .exe file):
{
"status": "validation_failed",
"is_clean": false,
"is_infected": false,
"filename": "program.exe",
"error": "Upload Failed - Dangerous file type detected: .exe"
}
ClamAV unavailable:
{
"status": "error",
"is_clean": false,
"is_infected": false,
"filename": "doc.pdf",
"error": "ClamAV unavailable after 3 attempts: Connection refused"
}
Development & Deployment
Prerequisites
pip install twine build
Run Tests
pip install -e .
pip install pytest
pytest tests/ -v
Deploy to PyPI
# Clean, build, and deploy
rm -rf dist/ build/ *.egg-info/
python setup.py sdist bdist_wheel
twine upload dist/*
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tns_antivirus-0.1.0.tar.gz.
File metadata
- Download URL: tns_antivirus-0.1.0.tar.gz
- Upload date:
- Size: 9.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e980504b8b872ebe16e81cbb902d7148a23da55fa17c166f60e53d6790029628
|
|
| MD5 |
83d93f3dc221f95e341d47b1340ace5a
|
|
| BLAKE2b-256 |
1cfb25f18133f8232cb5983ae423adc98d2a342402b02b8e517e90e8f81890d5
|
File details
Details for the file tns_antivirus-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tns_antivirus-0.1.0-py3-none-any.whl
- Upload date:
- Size: 7.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a846777ca3d858d7292a45f9f863f2ca95ca20fcd078e8620ff891acb109eab
|
|
| MD5 |
ce42fe0d231f20542bd7345f92ae8aef
|
|
| BLAKE2b-256 |
74ec5d68e463f90c57ab53b03629692c3e523ac12acac615fd0d884ce256b880
|