<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class LicenseCheck
{
public function handle(Request $request, Closure $next)
{
$domain = $this->parseDomain($request->getHost());
$cacheKey = 'lic_ok_' . md5($domain);
$graceKey = 'lic_grace_' . md5($domain);
$cacheHours = config('license.cache_hours', 24);
$graceHours = config('license.grace_hours', 72);
/* 1. Serve from cache if still fresh */
if (Cache::has($cacheKey)) {
return $next($request);
}
/* 2. Call license server */
$valid = $this->callServer($domain);
if ($valid) {
Cache::put($cacheKey, true, now()->addHours($cacheHours));
Cache::put($graceKey, true, now()->addHours($graceHours));
return $next($request);
}
/* 3. License server returned invalid — but allow grace window */
if (Cache::has($graceKey)) {
Log::warning("License invalid for [{$domain}] — running on grace period.");
return $next($request);
}
/* 4. No grace — block */
return response()->view('license.invalid', ['domain' => $domain], 403);
}
private function parseDomain(string $host): string
{
$domain = strtolower(trim($host));
$domain = preg_replace('/^www\./i', '', $domain);
return explode(':', $domain)[0];
}
private function callServer(string $domain): bool
{
try {
$response = Http::timeout(8)->get(config('license.server_url'), [
'secret' => config('license.secret'),
'domain' => $domain,
]);
if ($response->successful()) {
return (bool) ($response->json('valid') ?? false);
}
} catch (\Exception $e) {
Log::error("License server unreachable for [{$domain}]: " . $e->getMessage());
}
return false;
}
}