<?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class LicenseService
{
private const CACHE_KEY = '_tmit_lic';
private const GRACE_KEY = '_tmit_lic_grace';
public function isValid(): bool
{
// Primary cache (24h) — avoid hitting server every request
if (Cache::has(self::CACHE_KEY)) {
return (bool) Cache::get(self::CACHE_KEY);
}
$serverUrl = config('license.server_url');
// Bypass if URL is empty or clearly a placeholder — allow access
if (empty($serverUrl) || $this->isPlaceholderUrl($serverUrl)) {
return true;
}
try {
$valid = $this->queryServer($serverUrl);
Cache::put(self::CACHE_KEY, $valid, config('license.cache_ttl', 86400));
if ($valid) {
// Refresh grace period whenever we get a valid response
Cache::put(self::GRACE_KEY, true, config('license.grace_ttl', 604800));
} else {
// Definitive invalid — clear grace cache immediately
Cache::forget(self::GRACE_KEY);
}
return $valid;
} catch (\Exception $e) {
// Server unreachable — fall back to grace cache
Log::warning('[License] Server unreachable: ' . $e->getMessage());
return (bool) Cache::get(self::GRACE_KEY, false);
}
}
private function isPlaceholderUrl(string $url): bool
{
$placeholders = [
'yourdomain.com',
'yourlicenseserver.com',
'example.com',
'your-server.com',
];
foreach ($placeholders as $p) {
if (str_contains($url, $p)) {
return true;
}
}
return false;
}
private function queryServer(string $serverUrl): bool
{
$domain = request()->getHost();
$domain = preg_replace('/^www\./i', '', strtolower($domain));
$domain = explode(':', $domain)[0]; // strip port
$response = Http::timeout(5)
->withoutVerifying() // allow self-signed SSL on license server
->get($serverUrl, [
'domain' => $domain,
'code' => config('license.purchase_code', ''),
'secret' => config('license.secret', ''),
]);
if ($response->successful()) {
$data = $response->json();
return (bool) ($data['valid'] ?? false);
}
// Non-2xx response counts as server error — use grace
throw new \RuntimeException('License server returned HTTP ' . $response->status());
}
public function clearCache(): void
{
Cache::forget(self::CACHE_KEY);
Cache::forget(self::GRACE_KEY);
}
public function status(): array
{
$serverUrl = config('license.server_url');
$domain = request()->getHost();
$domain = preg_replace('/^www\./i', '', strtolower($domain));
return [
'domain' => $domain,
'server_url' => $serverUrl ?: '(not configured)',
'cached_valid' => Cache::get(self::CACHE_KEY, null),
'grace_active' => Cache::has(self::GRACE_KEY),
'cache_ttl_left' => Cache::has(self::CACHE_KEY) ? 'cached' : 'expired',
];
}
}