117 lines
4.5 KiB
PHP
117 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace App\Middleware;
|
|
|
|
use App\Utils\JWT;
|
|
use App\Utils\View;
|
|
|
|
class ApiMiddleware
|
|
{
|
|
public function handle()
|
|
{
|
|
$headers = getallheaders();
|
|
|
|
// Handle case-insensitive headers and Proxy fallbacks
|
|
$authHeader = $headers['Authorization'] ?? $headers['authorization'] ?? $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
|
$machineId = $headers['X-Machine-ID'] ?? $headers['x-machine-id'] ?? $_SERVER['HTTP_X_MACHINE_ID'] ?? '';
|
|
|
|
if (!preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
|
|
View::json(['error' => 'Serial Key not provided'], 401);
|
|
return false;
|
|
}
|
|
|
|
$serialKey = $matches[1];
|
|
|
|
if (empty($machineId)) {
|
|
View::json(['error' => 'Machine ID not provided'], 400);
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$conn = \App\Config\Database::getInstance()->getConnection();
|
|
|
|
// Find server by Serial Key
|
|
$stmt = $conn->prepare("SELECT id, machine_id, status, ip_v4 FROM servers WHERE serial_key = :serial");
|
|
$stmt->execute(['serial' => $serialKey]);
|
|
$server = $stmt->fetch();
|
|
|
|
if (!$server) {
|
|
$this->log(null, 'auth_failed', "Invalid Serial Key: $serialKey");
|
|
View::json(['error' => 'Invalid Serial Key'], 401);
|
|
return false;
|
|
}
|
|
|
|
// Get Client IP (Handle Proxy)
|
|
$clientIp = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
|
|
// If multiple IPs in X-Forwarded-For, take the first one
|
|
if (strpos($clientIp, ',') !== false) {
|
|
$clientIp = trim(explode(',', $clientIp)[0]);
|
|
}
|
|
|
|
// Validate IP
|
|
if ($server['ip_v4'] !== $clientIp) {
|
|
$this->log($server['id'], 'auth_blocked', "Invalid IP Address. Expected: {$server['ip_v4']}, Got: $clientIp");
|
|
View::json(['error' => 'Invalid IP Address'], 403);
|
|
return false;
|
|
}
|
|
|
|
if ($server['status'] !== 'active') {
|
|
$this->log($server['id'], 'auth_blocked', 'Server is inactive');
|
|
View::json(['error' => 'Server is inactive'], 403);
|
|
return false;
|
|
}
|
|
|
|
// Bind Machine ID if first use
|
|
if (empty($server['machine_id'])) {
|
|
$update = $conn->prepare("UPDATE servers SET machine_id = :mid WHERE id = :id");
|
|
$update->execute(['mid' => $machineId, 'id' => $server['id']]);
|
|
$this->log($server['id'], 'bind_machine', "Machine ID bound: $machineId");
|
|
}
|
|
// Validate Machine ID
|
|
elseif ($server['machine_id'] !== $machineId) {
|
|
$this->log($server['id'], 'auth_blocked', "Invalid Machine ID. Expected: {$server['machine_id']}, Got: $machineId");
|
|
View::json(['error' => 'Serial Key already bound to another machine'], 403);
|
|
return false;
|
|
}
|
|
|
|
// Log Success (Optional: Log every sync might be too much, maybe only on change?
|
|
// For now, let's log sync to show activity as requested "verificar conexões")
|
|
$this->log($server['id'], 'sync', 'Agent connected');
|
|
|
|
// Update Last Seen
|
|
$updateLastSeen = $conn->prepare("UPDATE servers SET last_seen = NOW() WHERE id = :id");
|
|
$updateLastSeen->execute(['id' => $server['id']]);
|
|
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
$this->log(null, 'error', 'System error: ' . $e->getMessage());
|
|
View::json(['error' => 'Authentication error'], 500);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private function log($serverId, $action, $message)
|
|
{
|
|
try {
|
|
$conn = \App\Config\Database::getInstance()->getConnection();
|
|
$stmt = $conn->prepare("INSERT INTO api_logs (server_id, action, message, ip_address) VALUES (:sid, :act, :msg, :ip)");
|
|
|
|
// Get Client IP (Handle Proxy)
|
|
$clientIp = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
|
|
// If multiple IPs in X-Forwarded-For, take the first one
|
|
if (strpos($clientIp, ',') !== false) {
|
|
$clientIp = trim(explode(',', $clientIp)[0]);
|
|
}
|
|
|
|
$stmt->execute([
|
|
'sid' => $serverId,
|
|
'act' => $action,
|
|
'msg' => $message,
|
|
'ip' => $clientIp
|
|
]);
|
|
} catch (\Exception $e) {
|
|
// Silent fail for logs
|
|
}
|
|
}
|
|
}
|