Files
e-tib.com/tests/form-token.test.ts
Marc Mintel 99467f1379
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 19s
Build & Deploy / 🧪 QA (push) Successful in 1m17s
Build & Deploy / 🏗️ Build (push) Successful in 2m33s
Build & Deploy / 🚀 Deploy (push) Successful in 25s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 51s
Build & Deploy / 🔔 Notify (push) Successful in 2s
fix(antispam): harden spam guard with signed form tokens and proxy-safe IP extraction
- Rate limit now uses the last X-Forwarded-For hop (appended by Traefik)
  instead of the client-controlled first hop, which bots rotated freely
- Time-trap anchored to server time via HMAC-signed form token
  (FORM_TOKEN_SECRET) instead of client-supplied form_loaded_at
- Fix RequestQuoteForm regression: FormData was built from scratch without
  honeypot/token hidden inputs and inputs lacked name attributes, so every
  legitimate quote request was silently blocked as spam
2026-09-02 10:06:07 +02:00

54 lines
1.9 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import {
createFormToken,
verifyFormToken,
MAX_FORM_AGE_MS,
} from '@/lib/antispam/form-token';
const SECRET = 'test-secret';
const NOW = 1_000_000_000_000;
describe('signed form token', () => {
it('issues a token that verifies with its issuance timestamp', () => {
const token = createFormToken(NOW, SECRET);
const result = verifyFormToken(token, NOW + 10_000, SECRET);
expect(result.ok).toBe(true);
expect(result.issuedAt).toBe(NOW);
});
it('rejects a token that was tampered with', () => {
const token = createFormToken(NOW, SECRET);
const [issuedAt, signature] = token.split('.');
const tampered = `${issuedAt}.${signature.slice(0, -2)}xx`;
const result = verifyFormToken(tampered, NOW + 10_000, SECRET);
expect(result.ok).toBe(false);
});
it('rejects a token forged with a different secret', () => {
const token = createFormToken(NOW, 'attacker-secret');
const result = verifyFormToken(token, NOW + 10_000, SECRET);
expect(result.ok).toBe(false);
});
it('rejects a token with a manipulated issuance timestamp', () => {
const token = createFormToken(NOW, SECRET);
const [, signature] = token.split('.');
const forged = `${NOW - 60_000}.${signature}`;
const result = verifyFormToken(forged, NOW, SECRET);
expect(result.ok).toBe(false);
});
it('rejects malformed tokens', () => {
expect(verifyFormToken('', NOW, SECRET).ok).toBe(false);
expect(verifyFormToken('garbage', NOW, SECRET).ok).toBe(false);
expect(verifyFormToken('123.456.789', NOW, SECRET).ok).toBe(false);
});
it('rejects tokens older than the maximum form age', () => {
const token = createFormToken(NOW, SECRET);
const result = verifyFormToken(token, NOW + MAX_FORM_AGE_MS + 1, SECRET);
expect(result.ok).toBe(false);
expect(result.reason).toBe('expired');
});
});