122 lines
3.4 KiB
PHP
122 lines
3.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Middleware;
|
|
|
|
use Closure;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Session\Middleware\StartSession;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class ConditionalStartSession extends StartSession
|
|
{
|
|
public function handle($request, Closure $next): mixed
|
|
{
|
|
if (! $request instanceof Request || ! config('skinbase-sessions.enabled', true)) {
|
|
return parent::handle($request, $next);
|
|
}
|
|
|
|
if ($this->shouldSkipSession($request)) {
|
|
$request->attributes->set('skinbase.session_skipped', true);
|
|
|
|
$response = $next($request);
|
|
|
|
if ($response instanceof Response && config('skinbase-sessions.debug_header', false)) {
|
|
$response->headers->set('X-Skinbase-Session', 'skipped');
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
$request->attributes->set('skinbase.session_skipped', false);
|
|
|
|
$response = parent::handle($request, $next);
|
|
|
|
if ($response instanceof Response && config('skinbase-sessions.debug_header', false)) {
|
|
$response->headers->set('X-Skinbase-Session', 'started');
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
protected function shouldSkipSession(Request $request): bool
|
|
{
|
|
if (! $this->isSafeReadMethod($request)) {
|
|
return false;
|
|
}
|
|
|
|
if ($this->hasExistingSessionCookie($request)) {
|
|
return false;
|
|
}
|
|
|
|
if ($this->matchesAnyPath($request, config('skinbase-sessions.always_session_paths', []))) {
|
|
return false;
|
|
}
|
|
|
|
if (! $this->matchesAnyPath($request, config('skinbase-sessions.public_paths', []))) {
|
|
return false;
|
|
}
|
|
|
|
if (config('skinbase-sessions.skip_anonymous_public_get', true)) {
|
|
return true;
|
|
}
|
|
|
|
return config('skinbase-sessions.skip_known_crawlers_on_public_get', true)
|
|
&& $this->isKnownCrawler($request);
|
|
}
|
|
|
|
protected function isSafeReadMethod(Request $request): bool
|
|
{
|
|
return in_array($request->getMethod(), ['GET', 'HEAD'], true);
|
|
}
|
|
|
|
protected function hasExistingSessionCookie(Request $request): bool
|
|
{
|
|
$cookieName = config('session.cookie');
|
|
|
|
return is_string($cookieName)
|
|
&& $cookieName !== ''
|
|
&& $request->cookies->has($cookieName);
|
|
}
|
|
|
|
protected function matchesAnyPath(Request $request, array $patterns): bool
|
|
{
|
|
foreach ($patterns as $pattern) {
|
|
if (! is_string($pattern) || $pattern === '') {
|
|
continue;
|
|
}
|
|
|
|
if ($pattern === '/' && $request->path() === '/') {
|
|
return true;
|
|
}
|
|
|
|
$normalizedPattern = trim($pattern, '/');
|
|
|
|
if ($normalizedPattern !== '' && $request->is($normalizedPattern)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected function isKnownCrawler(Request $request): bool
|
|
{
|
|
$userAgent = strtolower((string) $request->userAgent());
|
|
|
|
if ($userAgent === '') {
|
|
return false;
|
|
}
|
|
|
|
foreach (config('skinbase-sessions.bot_user_agent_keywords', []) as $keyword) {
|
|
$normalizedKeyword = strtolower((string) $keyword);
|
|
|
|
if ($normalizedKeyword !== '' && str_contains($userAgent, $normalizedKeyword)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
} |