63 lines
2.3 KiB
TypeScript
63 lines
2.3 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { checkContactSubmission, resetRateLimiter } from '@/lib/antispam/contact-guard';
|
|
|
|
const validInput = {
|
|
honeypot: '',
|
|
formLoadedAt: Date.now() - 10_000,
|
|
now: Date.now(),
|
|
ip: '1.2.3.4',
|
|
email: 'customer@example.com',
|
|
message: 'I would like a quote for 50 cables.',
|
|
};
|
|
|
|
describe('contact form anti-spam guard', () => {
|
|
beforeEach(() => resetRateLimiter());
|
|
|
|
it('allows a legitimate submission', () => {
|
|
const result = checkContactSubmission(validInput);
|
|
expect(result.allowed).toBe(true);
|
|
});
|
|
|
|
it('blocks submissions where the honeypot field is filled', () => {
|
|
const result = checkContactSubmission({ ...validInput, honeypot: 'http://spam.example' });
|
|
expect(result.allowed).toBe(false);
|
|
expect(result.reason).toBe('honeypot');
|
|
});
|
|
|
|
it('blocks submissions sent faster than a human could fill the form', () => {
|
|
const result = checkContactSubmission({ ...validInput, formLoadedAt: validInput.now - 1_000 });
|
|
expect(result.allowed).toBe(false);
|
|
expect(result.reason).toBe('too_fast');
|
|
});
|
|
|
|
it('blocks submissions with an invalid email address', () => {
|
|
const result = checkContactSubmission({ ...validInput, email: 'not-an-email' });
|
|
expect(result.allowed).toBe(false);
|
|
expect(result.reason).toBe('invalid_email');
|
|
});
|
|
|
|
it('blocks messages containing more than 5 links (typical SEO spam)', () => {
|
|
const spammy = Array.from({ length: 6 }, (_, i) => `https://spam${i}.example`).join(' ');
|
|
const result = checkContactSubmission({ ...validInput, message: spammy });
|
|
expect(result.allowed).toBe(false);
|
|
expect(result.reason).toBe('too_many_links');
|
|
});
|
|
|
|
it('rate-limits an IP after 3 submissions within 10 minutes', () => {
|
|
for (let i = 0; i < 3; i++) {
|
|
expect(checkContactSubmission(validInput).allowed).toBe(true);
|
|
}
|
|
const result = checkContactSubmission(validInput);
|
|
expect(result.allowed).toBe(false);
|
|
expect(result.reason).toBe('rate_limited');
|
|
});
|
|
|
|
it('does not rate-limit different IPs independently', () => {
|
|
for (let i = 0; i < 3; i++) {
|
|
checkContactSubmission(validInput);
|
|
}
|
|
const result = checkContactSubmission({ ...validInput, ip: '5.6.7.8' });
|
|
expect(result.allowed).toBe(true);
|
|
});
|
|
});
|