presseportale/tests/Feature/Web/QuarantineContactSpamTest.php
Kevin Adametz 06d2889a4d feat: Spamschutz für Kontakt-Widget und Registrierung mit Cloudflare Turnstile
- Turnstile für Gäste und unbestätigte Konten (TurnstileVerifier,
  <x-turnstile>); ist Cloudflare nicht erreichbar, wird durchgelassen und
  im Verlauf, in der Kontakt-Queue und in der Betriebsüberwachung markiert
- Inhaltsfilter des Kontaktformulars (fremde Links, Floskel mit
  Seitentitel, Zeichensalat, Sperrliste, Absenden unter 3 Sekunden);
  Treffer landen in der Spam-Quarantäne ohne Mail, Löschung nach 30 Tagen
- Admin: Filter „Spam“, Sammelaktion, „Kein Spam“ holt die Mail nach
- Registrierung lehnt Zufallsnamen ab; users:prune-bot-registrations
  (täglicher Lauf erst mit USERS_PRUNE_BOT_REGISTRATIONS=true)
- contact-messages:quarantine-spam für den Altbestand
- CSP erlaubt challenges.cloudflare.com, Log-Kanal spam
- Datenschutzerklärung: Abschnitt 6a Cloudflare Turnstile (Vorschlag)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:49:58 +00:00

43 lines
1.8 KiB
PHP

<?php
use App\Enums\ContactMessageStatus;
use App\Models\ContactMessage;
use App\Models\User;
use Tests\TestCase;
/*
* contact-messages:quarantine-spam — einmalig für den Altbestand
* (Spamschutz, Entscheidung 2).
*/
test('open guest messages caught by the filter move into the quarantine', function () {
/** @var TestCase $this */
$spam = ContactMessage::factory()->create(['message' => 'WIN A 2026 ROLLS-ROYCE https://telegra.ph/win-123']);
$clean = ContactMessage::factory()->create(['message' => 'Guten Tag, ich habe eine Frage zu Ihren Preisen.']);
$customer = ContactMessage::factory()->create([
'message' => 'Unser Logo auf https://beispiel-firma.de ist veraltet.',
'user_id' => User::factory()->create()->id,
]);
$resolved = ContactMessage::factory()->resolved()->create(['message' => 'Alt: https://telegra.ph/alt']);
$this->artisan('contact-messages:quarantine-spam')
->expectsOutputToContain('1 Anliegen als Spam markiert.')
->assertSuccessful();
expect($spam->refresh()->status)->toBe(ContactMessageStatus::Spam)
->and($spam->payload['spam_reason'])->toBe('link')
->and($clean->refresh()->status)->toBe(ContactMessageStatus::Open)
->and($customer->refresh()->status)->toBe(ContactMessageStatus::Open)
->and($resolved->refresh()->status)->toBe(ContactMessageStatus::Resolved);
});
test('the dry run changes nothing', function () {
/** @var TestCase $this */
$spam = ContactMessage::factory()->create(['message' => 'WIN A 2026 ROLLS-ROYCE https://telegra.ph/win-123']);
$this->artisan('contact-messages:quarantine-spam', ['--dry-run' => true])
->expectsOutputToContain('Probelauf: 1 Anliegen würden als Spam markiert.')
->assertSuccessful();
expect($spam->refresh()->status)->toBe(ContactMessageStatus::Open);
});