diff --git a/app/Http/Controllers/LegalRequestController.php b/app/Http/Controllers/LegalRequestController.php index 77bb9e68..566f94ca 100644 --- a/app/Http/Controllers/LegalRequestController.php +++ b/app/Http/Controllers/LegalRequestController.php @@ -39,6 +39,13 @@ class LegalRequestController extends Controller { $release = $this->resolvePublishedRelease($slug); + // Bot: ein ausgefülltes Honeypot-Feld → still und neutral abnicken, + // nichts speichern. Bewusst VOR der Validierung — eine size:0-Regel + // würde mit ihrer Fehlermeldung einem Bot die Falle verraten. + if (filled($request->input('website')) || filled($request->input('homepage'))) { + return $this->done($release); + } + $validated = $request->validate([ 'type' => ['required', Rule::enum(LegalRequestType::class)], // E-Mail für DSGVO/Persönlichkeitsrecht nötig (Rückmeldung); bei @@ -51,19 +58,10 @@ class LegalRequestController extends Controller 'nullable', 'email', 'max:255', ], 'message' => ['required', 'string', 'min:10', 'max:5000'], - // Honeypots: müssen leer bleiben (versteckte Felder, nur für Bots). - 'website' => ['nullable', 'size:0'], - 'homepage' => ['nullable', 'size:0'], ]); $type = LegalRequestType::from($validated['type']); - // Bot: ein ausgefülltes Honeypot-Feld → still und neutral abnicken, - // nichts speichern (keine Fehlermeldung, die einem Bot etwas verrät). - if (filled($request->input('website')) || filled($request->input('homepage'))) { - return $this->done($release); - } - $this->ensureNotRateLimited($release); // Bremse: max. 1 offene Anfrage pro PM + Typ (nicht hart gesperrt – andere diff --git a/tests/Feature/LegalRequestTest.php b/tests/Feature/LegalRequestTest.php index 3cde06f3..05eac3bb 100644 --- a/tests/Feature/LegalRequestTest.php +++ b/tests/Feature/LegalRequestTest.php @@ -99,11 +99,15 @@ test('a filled honeypot field blocks bots without creating a request', function /** @var TestCase $this */ $release = publishedRelease(); + // Soll: still und neutral abnicken — kein Validierungsfehler, der einem + // Bot die Falle verrät, sondern der normale Erfolgs-Redirect. $this->post(route('legal-request.store', ['slug' => $release->slug]), [ 'type' => LegalRequestType::Report->value, 'message' => 'Spam spam spam spam.', $field => 'http://spam.example', - ]); + ]) + ->assertSessionHasNoErrors() + ->assertRedirect(route('release.detail', ['slug' => $release->slug])); expect(LegalRequest::query()->count())->toBe(0); })->with(['website', 'homepage']);