2025-05-07 20:20:17 +00:00
|
|
|
import { tap, expect } from '@push.rocks/tapbundle';
|
|
|
|
import { ContentScanner, ThreatCategory } from '../ts/security/classes.contentscanner.js';
|
2025-05-08 01:13:54 +00:00
|
|
|
import { Email } from '../ts/mail/core/classes.email.js';
|
2025-05-07 20:20:17 +00:00
|
|
|
|
|
|
|
// Test instantiation
|
|
|
|
tap.test('ContentScanner - should be instantiable', async () => {
|
|
|
|
const scanner = ContentScanner.getInstance({
|
|
|
|
scanBody: true,
|
|
|
|
scanSubject: true,
|
|
|
|
scanAttachments: true
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(scanner).toBeTruthy();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test singleton pattern
|
|
|
|
tap.test('ContentScanner - should use singleton pattern', async () => {
|
|
|
|
const scanner1 = ContentScanner.getInstance();
|
|
|
|
const scanner2 = ContentScanner.getInstance();
|
|
|
|
|
|
|
|
// Both instances should be the same object
|
|
|
|
expect(scanner1 === scanner2).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test clean email can be correctly distinguished from high-risk email
|
|
|
|
tap.test('ContentScanner - should distinguish between clean and suspicious emails', async () => {
|
|
|
|
// Create an instance with a higher minimum threat score
|
|
|
|
const scanner = new ContentScanner({
|
|
|
|
minThreatScore: 50 // Higher threshold to consider clean
|
|
|
|
});
|
|
|
|
|
|
|
|
// Create a truly clean email with no potentially sensitive data patterns
|
|
|
|
const cleanEmail = new Email({
|
|
|
|
from: 'sender@example.com',
|
|
|
|
to: 'recipient@example.com',
|
|
|
|
subject: 'Project Update',
|
|
|
|
text: 'The project is on track. Let me know if you have questions.',
|
|
|
|
html: '<p>The project is on track. Let me know if you have questions.</p>'
|
|
|
|
});
|
|
|
|
|
|
|
|
// Create a highly suspicious email
|
|
|
|
const suspiciousEmail = new Email({
|
|
|
|
from: 'admin@bank-fake.com',
|
|
|
|
to: 'victim@example.com',
|
|
|
|
subject: 'URGENT: Your account needs verification now!',
|
|
|
|
text: 'Click here to verify your account or it will be suspended: https://bit.ly/12345',
|
|
|
|
html: '<p>Click here to verify your account or it will be suspended: <a href="https://bit.ly/12345">click here</a></p>'
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test both emails
|
|
|
|
const cleanResult = await scanner.scanEmail(cleanEmail);
|
|
|
|
const suspiciousResult = await scanner.scanEmail(suspiciousEmail);
|
|
|
|
|
|
|
|
console.log('Clean vs Suspicious results:', {
|
|
|
|
cleanScore: cleanResult.threatScore,
|
|
|
|
suspiciousScore: suspiciousResult.threatScore
|
|
|
|
});
|
|
|
|
|
|
|
|
// Verify the scanner can distinguish between them
|
|
|
|
// Suspicious email should have a significantly higher score
|
|
|
|
expect(suspiciousResult.threatScore > cleanResult.threatScore + 40).toEqual(true);
|
|
|
|
|
|
|
|
// Verify clean email scans all expected elements
|
|
|
|
expect(cleanResult.scannedElements.length > 0).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test phishing detection in subject
|
|
|
|
tap.test('ContentScanner - should detect phishing in subject', async () => {
|
|
|
|
// Create a dedicated scanner for this test
|
|
|
|
const scanner = new ContentScanner({
|
|
|
|
scanSubject: true,
|
|
|
|
scanBody: true,
|
|
|
|
scanAttachments: false,
|
|
|
|
customRules: []
|
|
|
|
});
|
|
|
|
|
|
|
|
const email = new Email({
|
|
|
|
from: 'security@bank-account-verify.com',
|
|
|
|
to: 'victim@example.com',
|
|
|
|
subject: 'URGENT: Verify your bank account details immediately',
|
|
|
|
text: 'Your account will be suspended. Please verify your details.',
|
|
|
|
html: '<p>Your account will be suspended. Please verify your details.</p>'
|
|
|
|
});
|
|
|
|
|
|
|
|
const result = await scanner.scanEmail(email);
|
|
|
|
|
|
|
|
console.log('Phishing email scan result:', result);
|
|
|
|
|
|
|
|
// We only care that it detected something suspicious
|
|
|
|
expect(result.threatScore >= 20).toEqual(true);
|
|
|
|
|
|
|
|
// Check if any threat was detected (specific type may vary)
|
|
|
|
expect(result.threatType).toBeTruthy();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test malware indicators in body
|
|
|
|
tap.test('ContentScanner - should detect malware indicators in body', async () => {
|
|
|
|
const scanner = ContentScanner.getInstance();
|
|
|
|
|
|
|
|
const email = new Email({
|
|
|
|
from: 'invoice@company.com',
|
|
|
|
to: 'recipient@example.com',
|
|
|
|
subject: 'Your invoice',
|
|
|
|
text: 'Please see the attached invoice. You need to enable macros to view this document properly.',
|
|
|
|
html: '<p>Please see the attached invoice. You need to enable macros to view this document properly.</p>'
|
|
|
|
});
|
|
|
|
|
|
|
|
const result = await scanner.scanEmail(email);
|
|
|
|
|
|
|
|
expect(result.isClean).toEqual(false);
|
|
|
|
expect(result.threatType === ThreatCategory.MALWARE || result.threatType).toBeTruthy();
|
|
|
|
expect(result.threatScore >= 30).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test suspicious link detection
|
|
|
|
tap.test('ContentScanner - should detect suspicious links', async () => {
|
|
|
|
const scanner = ContentScanner.getInstance();
|
|
|
|
|
|
|
|
const email = new Email({
|
|
|
|
from: 'newsletter@example.com',
|
|
|
|
to: 'recipient@example.com',
|
|
|
|
subject: 'Weekly Newsletter',
|
|
|
|
text: 'Check our latest offer at https://bit.ly/2x3F5 and https://t.co/abc123',
|
|
|
|
html: '<p>Check our latest offer at <a href="https://bit.ly/2x3F5">here</a> and <a href="https://t.co/abc123">here</a></p>'
|
|
|
|
});
|
|
|
|
|
|
|
|
const result = await scanner.scanEmail(email);
|
|
|
|
|
|
|
|
expect(result.isClean).toEqual(false);
|
|
|
|
expect(result.threatType).toEqual(ThreatCategory.SUSPICIOUS_LINK);
|
|
|
|
expect(result.threatScore >= 30).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test script injection detection
|
|
|
|
tap.test('ContentScanner - should detect script injection', async () => {
|
|
|
|
const scanner = ContentScanner.getInstance();
|
|
|
|
|
|
|
|
const email = new Email({
|
|
|
|
from: 'newsletter@example.com',
|
|
|
|
to: 'recipient@example.com',
|
|
|
|
subject: 'Newsletter',
|
|
|
|
text: 'Check our website',
|
|
|
|
html: '<p>Check our website</p><script>document.cookie="session="+localStorage.getItem("token");</script>'
|
|
|
|
});
|
|
|
|
|
|
|
|
const result = await scanner.scanEmail(email);
|
|
|
|
|
|
|
|
expect(result.isClean).toEqual(false);
|
|
|
|
expect(result.threatType).toEqual(ThreatCategory.XSS);
|
|
|
|
expect(result.threatScore >= 40).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test executable attachment detection
|
|
|
|
tap.test('ContentScanner - should detect executable attachments', async () => {
|
|
|
|
const scanner = ContentScanner.getInstance();
|
|
|
|
|
|
|
|
const email = new Email({
|
|
|
|
from: 'sender@example.com',
|
|
|
|
to: 'recipient@example.com',
|
|
|
|
subject: 'Software Update',
|
|
|
|
text: 'Please install the attached software update.',
|
|
|
|
attachments: [{
|
|
|
|
filename: 'update.exe',
|
|
|
|
content: Buffer.from('MZ...fake executable content...'),
|
|
|
|
contentType: 'application/octet-stream'
|
|
|
|
}]
|
|
|
|
});
|
|
|
|
|
|
|
|
const result = await scanner.scanEmail(email);
|
|
|
|
|
|
|
|
expect(result.isClean).toEqual(false);
|
|
|
|
expect(result.threatType).toEqual(ThreatCategory.EXECUTABLE);
|
|
|
|
expect(result.threatScore >= 70).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test macro document detection
|
|
|
|
tap.test('ContentScanner - should detect macro documents', async () => {
|
|
|
|
// Create a mock Office document with macro indicators
|
|
|
|
const fakeDocContent = Buffer.from('Document content...vbaProject.bin...Auto_Open...DocumentOpen...Microsoft VBA...');
|
|
|
|
|
|
|
|
const scanner = ContentScanner.getInstance();
|
|
|
|
|
|
|
|
const email = new Email({
|
|
|
|
from: 'sender@example.com',
|
|
|
|
to: 'recipient@example.com',
|
|
|
|
subject: 'Financial Report',
|
|
|
|
text: 'Please review the attached financial report.',
|
|
|
|
attachments: [{
|
|
|
|
filename: 'report.docm',
|
|
|
|
content: fakeDocContent,
|
|
|
|
contentType: 'application/vnd.ms-word.document.macroEnabled.12'
|
|
|
|
}]
|
|
|
|
});
|
|
|
|
|
|
|
|
const result = await scanner.scanEmail(email);
|
|
|
|
|
|
|
|
expect(result.isClean).toEqual(false);
|
|
|
|
expect(result.threatType).toEqual(ThreatCategory.MALICIOUS_MACRO);
|
|
|
|
expect(result.threatScore >= 60).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test compound threat detection (multiple indicators)
|
|
|
|
tap.test('ContentScanner - should detect compound threats', async () => {
|
|
|
|
const scanner = ContentScanner.getInstance();
|
|
|
|
|
|
|
|
const email = new Email({
|
|
|
|
from: 'security@bank-verify.com',
|
|
|
|
to: 'victim@example.com',
|
|
|
|
subject: 'URGENT: Verify your account details immediately',
|
|
|
|
text: 'Your account will be suspended unless you verify your details at https://bit.ly/2x3F5',
|
|
|
|
html: '<p>Your account will be suspended unless you verify your details <a href="https://bit.ly/2x3F5">here</a>.</p>',
|
|
|
|
attachments: [{
|
|
|
|
filename: 'verification.exe',
|
|
|
|
content: Buffer.from('MZ...fake executable content...'),
|
|
|
|
contentType: 'application/octet-stream'
|
|
|
|
}]
|
|
|
|
});
|
|
|
|
|
|
|
|
const result = await scanner.scanEmail(email);
|
|
|
|
|
|
|
|
expect(result.isClean).toEqual(false);
|
|
|
|
expect(result.threatScore > 70).toEqual(true); // Should have a high score due to multiple threats
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test custom rules
|
|
|
|
tap.test('ContentScanner - should apply custom rules', async () => {
|
|
|
|
// Create a scanner with custom rules
|
|
|
|
const scanner = new ContentScanner({
|
|
|
|
customRules: [
|
|
|
|
{
|
|
|
|
pattern: /CUSTOM_PATTERN_FOR_TESTING/,
|
|
|
|
type: ThreatCategory.CUSTOM_RULE,
|
|
|
|
score: 50,
|
|
|
|
description: 'Custom pattern detected'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
const email = new Email({
|
|
|
|
from: 'sender@example.com',
|
|
|
|
to: 'recipient@example.com',
|
|
|
|
subject: 'Test Custom Rule',
|
|
|
|
text: 'This message contains CUSTOM_PATTERN_FOR_TESTING that should be detected.'
|
|
|
|
});
|
|
|
|
|
|
|
|
const result = await scanner.scanEmail(email);
|
|
|
|
|
|
|
|
expect(result.isClean).toEqual(false);
|
|
|
|
expect(result.threatType).toEqual(ThreatCategory.CUSTOM_RULE);
|
|
|
|
expect(result.threatScore >= 50).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Test threat level classification
|
|
|
|
tap.test('ContentScanner - should classify threat levels correctly', async () => {
|
|
|
|
expect(ContentScanner.getThreatLevel(10)).toEqual('none');
|
|
|
|
expect(ContentScanner.getThreatLevel(25)).toEqual('low');
|
|
|
|
expect(ContentScanner.getThreatLevel(50)).toEqual('medium');
|
|
|
|
expect(ContentScanner.getThreatLevel(80)).toEqual('high');
|
|
|
|
});
|
|
|
|
|
2025-05-07 22:06:55 +00:00
|
|
|
tap.test('stop', async () => {
|
|
|
|
await tap.stopForcefully();
|
|
|
|
});
|
|
|
|
|
2025-05-07 20:20:17 +00:00
|
|
|
export default tap.start();
|