Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
VerifyHoneypot
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
1 / 1
 handle
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3namespace App\Http\Middleware;
4
5use Closure;
6use Illuminate\Http\Request;
7use Symfony\Component\HttpFoundation\Response;
8
9/**
10 * Lightweight bot deterrent for public forms — no CAPTCHA, pairs with the
11 * <x-honeypot> component. Two signals, either one is enough to reject:
12 *   1. A field real visitors never see (off-screen via CSS) got filled in —
13 *      only an automated form-filler does that.
14 *   2. The form was submitted less than 2 seconds after it rendered — no
15 *      human reads a checkout form and fills it out that fast.
16 * Both fail open on a stale/missing timestamp rather than blocking a real
17 * shopper over a client clock quirk.
18 */
19class VerifyHoneypot
20{
21    private const MIN_SECONDS = 2;
22
23    public function handle(Request $request, Closure $next): Response
24    {
25        if (filled($request->input('hp_website'))) {
26            abort(422, 'Something went wrong. Please try again.');
27        }
28
29        $renderedAt = (int) $request->input('hp_time', 0);
30
31        if ($renderedAt > 0 && (time() - $renderedAt) < self::MIN_SECONDS) {
32            abort(422, 'Please take a moment and try again.');
33        }
34
35        return $next($request);
36    }
37}