REDROOM
PHP 8.3.30
Path:
Logout
Edit File
Size: 4.52 KB
Close
/home/getspomw/royalsquad.us/app/Http/Middleware/AccessControlMiddleware.php
Text
Base64
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use App\Models\AccessControl; use Stevebauman\Location\Facades\Location; use Symfony\Component\HttpFoundation\Response; class AccessControlMiddleware { // Deny list behavior: only block when rule exists AND is_allowed = false // Never block by default. // Common SEO bots we’ll verify by reverse DNS protected $botUAs = [ 'Googlebot','AdsBot-Google','APIs-Google', 'Bingbot','DuckDuckBot','AhrefsBot','SemrushBot', 'facebookexternalhit','Twitterbot','LinkedInBot', ]; public function handle(Request $request, Closure $next): Response { // 0) Always allow SEO-critical endpoints if ($this->isSeoEndpoint($request)) { return $next($request); } // 1) Allow verified crawlers (prevents 403 to Googlebot etc.) if ($this->isLikelyCrawler($request) && $this->isVerifiedCrawler($request->ip())) { return $next($request); } $ip = $request->ip(); // 2) Explicit IP rule takes precedence $ipRule = AccessControl::where('type', 'ip') ->where('value', $ip) ->first(); if ($ipRule) { // If explicitly denied → block; if allowed → allow; if ambiguous → allow if ($ipRule->is_allowed === 0) { return $this->blockedResponse(); } return $next($request); // explicitly allowed (or not denied) } // 3) Country rule (fail-open if lookup fails OR there is no rule) $countryCode = $this->countryFromIp($ip); // returns 'IN', 'US', etc., or null if ($countryCode) { $countryRule = AccessControl::where('type', 'country') ->where('value', strtoupper($countryCode)) ->first(); // Only block if there is an explicit deny rule for this country if ($countryRule && (int)$countryRule->is_allowed === 0) { return $this->blockedResponse(); } // If rule says allowed or no rule found → allow return $next($request); } // GeoIP failed → allow (do NOT block on failure) return $next($request); } protected function isSeoEndpoint(Request $r): bool { $path = ltrim($r->path(), '/'); if ($path === 'robots.txt') return true; if (preg_match('#^sitemap(\.xml|[-_].*\.xml)?$#i', $path)) return true; if (preg_match('#^sitemap/.*\.xml$#i', $path)) return true; return false; } protected function isLikelyCrawler(Request $r): bool { $ua = $r->userAgent() ?? ''; foreach ($this->botUAs as $needle) { if (stripos($ua, $needle) !== false) return true; } return false; } /** * Verify crawler by reverse DNS then forward DNS. * Google: IP -> rdns ends with googlebot.com/google.com, then rdns -> A includes original IP. */ protected function isVerifiedCrawler(string $ip): bool { $rdns = @gethostbyaddr($ip); if (!$rdns) return false; $allowedDomains = [ 'googlebot.com','google.com', // Google 'search.msn.com', // Bing 'ahrefs.com', // Ahrefs 'semrush.com', // Semrush 'duckduckgo.com', // DuckDuckGo ]; $matchesAllowed = false; foreach ($allowedDomains as $suffix) { if (preg_match('/\.' . preg_quote($suffix, '/') . '$/i', $rdns)) { $matchesAllowed = true; break; } } if (!$matchesAllowed) return false; $fwd = @gethostbynamel($rdns); return $fwd && in_array($ip, $fwd, true); } protected function countryFromIp(string $ip): ?string { try { // Optional: cache to reduce latency return cache()->remember("geoip_cc:{$ip}", now()->addMinutes(10), function () use ($ip) { $pos = Location::get($ip); return $pos ? strtoupper((string)$pos->countryCode) : null; }); } catch (\Throwable $e) { \Log::warning('GeoIP failed: '.$e->getMessage()); return null; // fail open } } protected function blockedResponse(): Response { // 451 is clearer than 403 for policy/geo-based blocks and less scary for SEO return response()->view('maintenance', [], 451); } }
Save
Close
Exit & Reset
Text mode: syntax highlighting auto-detects file type.
Directory Contents
Dirs: 0 × Files: 1
Delete Selected
Select All
Select None
Sort:
Name
Size
Modified
Enable drag-to-move
Name
Size
Perms
Modified
Actions
AccessControlMiddleware.php
4.52 KB
lrw-rw-rw-
2025-10-03 12:43:56
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
Zip Selected
If ZipArchive is unavailable, a
.tar
will be created (no compression).