optimizations
This commit is contained in:
@@ -21,6 +21,14 @@ class ForumBotProtectionMiddleware
|
||||
|
||||
public function handle(Request $request, Closure $next, string $action = 'generic'): Response|RedirectResponse|JsonResponse
|
||||
{
|
||||
if (! (bool) config('forum_bot_protection.enabled', true)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if ($this->shouldBypassForLocalE2E($request)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
$assessment = $this->botProtectionService->assess($request, $action);
|
||||
$request->attributes->set('forum_bot_assessment', $assessment);
|
||||
|
||||
@@ -93,4 +101,19 @@ class ForumBotProtectionMiddleware
|
||||
|
||||
return in_array($action, (array) config('forum_bot_protection.captcha.actions', []), true);
|
||||
}
|
||||
|
||||
private function shouldBypassForLocalE2E(Request $request): bool
|
||||
{
|
||||
if (! app()->environment(['local', 'testing'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($request->cookies->get('e2e_bot_bypass') === '1') {
|
||||
return true;
|
||||
}
|
||||
|
||||
$userAgent = strtolower((string) $request->userAgent());
|
||||
|
||||
return str_contains($userAgent, 'headlesschrome') || str_contains($userAgent, 'playwright');
|
||||
}
|
||||
}
|
||||
|
||||
68
app/Http/Middleware/UpdateLastVisit.php
Normal file
68
app/Http/Middleware/UpdateLastVisit.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
final class UpdateLastVisit
|
||||
{
|
||||
private const SESSION_KEY = 'last_visit.logged_at';
|
||||
|
||||
private const THROTTLE_SECONDS = 300;
|
||||
|
||||
private static ?bool $usersTableHasLastVisitAt = null;
|
||||
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$response = $next($request);
|
||||
|
||||
$user = $request->user();
|
||||
if (! $user) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (! $this->usersTableHasLastVisitAt()) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$now = now();
|
||||
$session = $request->hasSession() ? $request->session() : null;
|
||||
$lastLoggedAt = $session?->get(self::SESSION_KEY);
|
||||
|
||||
if (is_numeric($lastLoggedAt) && ((int) $lastLoggedAt + self::THROTTLE_SECONDS) > $now->getTimestamp()) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$lastVisitAt = $user->last_visit_at;
|
||||
if ($lastVisitAt !== null && method_exists($lastVisitAt, 'getTimestamp')) {
|
||||
if (($lastVisitAt->getTimestamp() + self::THROTTLE_SECONDS) > $now->getTimestamp()) {
|
||||
$session?->put(self::SESSION_KEY, $lastVisitAt->getTimestamp());
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
DB::table('users')
|
||||
->where('id', $user->id)
|
||||
->update([
|
||||
'last_visit_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
$user->forceFill(['last_visit_at' => $now]);
|
||||
$session?->put(self::SESSION_KEY, $now->getTimestamp());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function usersTableHasLastVisitAt(): bool
|
||||
{
|
||||
return self::$usersTableHasLastVisitAt ??= Schema::hasColumn('users', 'last_visit_at');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user