-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscanner.ts
More file actions
78 lines (65 loc) · 2.23 KB
/
scanner.ts
File metadata and controls
78 lines (65 loc) · 2.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import { initClamAV, scanFileWithClamAV } from './clamav';
import { scanFileWithVirusTotal } from './virustotal';
import { downloadFromS3ToTemp, cleanupTempFile } from './storage';
import type { ClamAVResult } from './clamav';
import type { VirusTotalResult } from './virustotal';
export interface ScanResult {
clean: boolean;
clamav: ClamAVResult;
virustotal?: VirusTotalResult;
decision: 'clean' | 'infected' | 'suspicious';
score: number;
}
const VIRUSTOTAL_THRESHOLD = 3; // If 3+ engines detect malware, flag as infected
const QUARANTINE_BUCKET = process.env.S3_BUCKET_QUARANTINE!;
export async function scanFile(s3Key: string, sha256: string): Promise<ScanResult> {
let tempFile: string | null = null;
try {
// Download file from S3 quarantine bucket
console.log(`Downloading ${s3Key} for scanning...`);
tempFile = await downloadFromS3ToTemp(QUARANTINE_BUCKET, s3Key);
// Scan with ClamAV (fast, local)
console.log('Scanning with ClamAV...');
const clamavResult = await scanFileWithClamAV(tempFile);
// If ClamAV detects infection, no need to check VirusTotal
if (clamavResult.infected) {
return {
clean: false,
clamav: clamavResult,
decision: 'infected',
score: 100,
};
}
// Scan with VirusTotal (optional, slower, more comprehensive)
console.log('Scanning with VirusTotal...');
const virusTotalResult = await scanFileWithVirusTotal(tempFile, sha256);
// Determine final decision
let decision: 'clean' | 'infected' | 'suspicious' = 'clean';
let score = 0;
if (virusTotalResult) {
score = virusTotalResult.positives;
if (virusTotalResult.positives >= VIRUSTOTAL_THRESHOLD) {
decision = 'infected';
} else if (virusTotalResult.positives > 0) {
decision = 'suspicious';
}
}
return {
clean: decision === 'clean',
clamav: clamavResult,
virustotal: virusTotalResult || undefined,
decision,
score,
};
} finally {
// Cleanup temp file
if (tempFile) {
await cleanupTempFile(tempFile);
}
}
}
export async function initScanner(): Promise<void> {
console.log('Initializing malware scanner...');
await initClamAV();
console.log('Scanner ready');
}