/home/suroeste/public_html/payments.transportessuroeste.com/src/Middleware
NameSizeModeActions
AuthMiddleware.php55210644editdlrm
RateLimiter.php67230644editdlrm
SecurityMiddleware.php97050644editdlrm
Edit: /home/suroeste/public_html/payments.transportessuroeste.com/src/Middleware/AuthMiddleware.php (5521B)
db = Database::getInstance(); } /** * Autenticar petición */ public function authenticate(): array { $apiKey = $_SERVER['HTTP_X_API_KEY'] ?? ''; $timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? ''; $signature = $_SERVER['HTTP_X_SIGNATURE'] ?? ''; if (empty($apiKey)) { LogService::security('auth_failure', 'API Key no proporcionada'); throw new AuthenticationException('API Key requerida'); } // Validar timestamp si se envía (previene replay attacks) if (!empty($timestamp) && !$this->validateTimestamp($timestamp)) { LogService::security('auth_failure', 'Timestamp inválido', [ 'api_key' => substr($apiKey, 0, 10) . '...' ]); throw new AuthenticationException('Timestamp inválido o expirado'); } // Buscar cliente - soporta key directa o hasheada $apiKeyHash = hash('sha256', $apiKey); $client = $this->db->fetchOne( "SELECT * FROM api_clients WHERE (api_key = :key OR api_key = :key_hash) AND is_active = 1", ['key' => $apiKey, 'key_hash' => $apiKeyHash] ); if (!$client) { LogService::security('auth_failure', 'API Key inválida', [ 'api_key' => substr($apiKey, 0, 10) . '...' ]); throw new AuthenticationException('Credenciales inválidas'); } // Validar IP si hay whitelist if (!empty($client['allowed_ips'])) { $allowedIps = json_decode($client['allowed_ips'], true) ?? []; $clientIp = LogService::getClientIp(); // Siempre permitir localhost $localhostIps = ['127.0.0.1', '::1', 'localhost']; $allAllowedIps = array_merge($allowedIps, $localhostIps); if (!in_array($clientIp, $allAllowedIps)) { LogService::security('auth_failure', 'IP no autorizada', [ 'client' => $client['client_name'], 'ip' => $clientIp ]); throw new SecurityException('IP no autorizada: ' . $clientIp); } } // Validar firma HMAC si se envía if (!empty($signature) && !empty($timestamp)) { if (!$this->validateSignature($client, $signature, $timestamp)) { LogService::security('auth_failure', 'Firma inválida', [ 'client' => $client['client_name'] ]); throw new AuthenticationException('Firma inválida'); } } // Actualizar último acceso try { $this->db->update( 'api_clients', ['last_access_at' => date('Y-m-d H:i:s')], 'id = :id', ['id' => $client['id']] ); } catch (\Exception $e) { // No fallar por esto } LogService::info('auth', 'Cliente autenticado', ['client' => $client['client_name']]); return [ 'id' => $client['id'], 'uuid' => $client['client_uuid'], 'name' => $client['client_name'], 'environment' => $client['environment'], 'rate_limit' => $client['rate_limit'], 'webhook_url' => $client['webhook_url'], 'webhook_secret' => $client['webhook_secret'] ]; } /** * Validar timestamp (máximo 5 minutos de diferencia) */ private function validateTimestamp(string $timestamp): bool { $ts = (int) $timestamp; $now = time(); $maxDiff = 300; // 5 minutos return abs($now - $ts) <= $maxDiff; } /** * Validar firma HMAC */ private function validateSignature(array $client, string $signature, string $timestamp): bool { $method = $_SERVER['REQUEST_METHOD']; $uri = $_SERVER['REQUEST_URI']; $body = file_get_contents('php://input'); $dataToSign = "{$method}\n{$uri}\n{$timestamp}\n{$body}"; $secret = $client['webhook_secret'] ?? $client['api_secret_hash'] ?? ''; $expectedSignature = hash_hmac('sha512', $dataToSign, $secret); return hash_equals($expectedSignature, $signature); } /** * Generar nuevas credenciales para un cliente */ public static function generateCredentials(string $prefix = 'ts'): array { $apiKey = $prefix . '_' . bin2hex(random_bytes(24)); $apiSecret = bin2hex(random_bytes(32)); $webhookSecret = bin2hex(random_bytes(32)); return [ 'api_key' => $apiKey, 'api_key_hash' => hash('sha256', $apiKey), 'api_secret' => $apiSecret, 'api_secret_hash' => password_hash($apiSecret, defined('PASSWORD_ARGON2ID') ? PASSWORD_ARGON2ID : PASSWORD_BCRYPT), 'webhook_secret' => $webhookSecret ]; } }