zitinexus-router-script/UI/includes/api_client.php

210 lines
7.0 KiB
PHP

<?php
/**
* API Client for ZitiNexus Portal communication
*/
require_once 'config.php';
class ApiClient {
private $apiEndpoint;
private $userAgent;
private $timeout;
private $maxRetries;
public function __construct($apiEndpoint = DEFAULT_API_ENDPOINT) {
$this->apiEndpoint = rtrim($apiEndpoint, '/');
$this->userAgent = 'ZitiRouter-EnrollmentUI/' . APP_VERSION;
$this->timeout = 60;
$this->maxRetries = 3;
}
/**
* Register router with ZitiNexus Portal
*/
public function registerRouter($hashKey) {
$url = $this->apiEndpoint . '/api/router/register';
$payload = json_encode(['hashKey' => $hashKey]);
logMessage('INFO', "Registering router with API: $url");
$response = $this->makeRequest('POST', $url, $payload);
if (!$response['success']) {
logMessage('ERROR', "API registration failed: " . $response['error']);
return $response;
}
$data = json_decode($response['body'], true);
if (!$data || !isset($data['success']) || !$data['success']) {
$errorMsg = isset($data['error']['message']) ? $data['error']['message'] : 'Registration failed';
logMessage('ERROR', "Registration failed: $errorMsg");
return [
'success' => false,
'error' => $errorMsg
];
}
logMessage('SUCCESS', "Router registered successfully");
return [
'success' => true,
'data' => $data['data']
];
}
/**
* Report enrollment status to portal
*/
public function reportStatus($callbackUrl, $hashKey, $status, $routerInfo = null, $errorMessage = null) {
if (empty($callbackUrl)) {
logMessage('WARNING', 'No callback URL provided, skipping status report');
return ['success' => true];
}
// Fix callback URL domain mismatch if needed
$fixedCallbackUrl = $this->fixCallbackUrl($callbackUrl);
$payload = [
'hashKey' => $hashKey,
'status' => $status
];
if ($status === 'success' && $routerInfo) {
$payload['routerInfo'] = $routerInfo;
} elseif ($status === 'failed' && $errorMessage) {
$payload['error'] = $errorMessage;
}
logMessage('INFO', "Reporting status '$status' to: $fixedCallbackUrl");
$response = $this->makeRequest('POST', $fixedCallbackUrl, json_encode($payload));
if ($response['success']) {
logMessage('SUCCESS', 'Status reported successfully');
} else {
logMessage('WARNING', 'Failed to report status: ' . $response['error']);
}
return $response;
}
/**
* Make HTTP request with retry logic
*/
private function makeRequest($method, $url, $data = null) {
$retryCount = 0;
while ($retryCount < $this->maxRetries) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_CONNECTTIMEOUT => 30,
CURLOPT_USERAGENT => $this->userAgent,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json'
],
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 3
]);
if ($method === 'POST' && $data) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($response === false) {
logMessage('ERROR', "cURL error: $error");
$retryCount++;
if ($retryCount < $this->maxRetries) {
$waitTime = $retryCount * 2;
logMessage('INFO', "Retrying in {$waitTime}s... (attempt $retryCount/$this->maxRetries)");
sleep($waitTime);
}
continue;
}
if ($httpCode === 200) {
return [
'success' => true,
'body' => $response,
'http_code' => $httpCode
];
} elseif ($httpCode === 429) {
// Rate limited
$retryCount++;
if ($retryCount < $this->maxRetries) {
$waitTime = $retryCount * 2;
logMessage('WARNING', "Rate limited. Waiting {$waitTime}s before retry $retryCount/$this->maxRetries");
sleep($waitTime);
}
continue;
} else {
$errorMsg = "HTTP $httpCode";
if ($response) {
$responseData = json_decode($response, true);
if ($responseData && isset($responseData['error']['message'])) {
$errorMsg .= ': ' . $responseData['error']['message'];
} elseif ($responseData && isset($responseData['message'])) {
$errorMsg .= ': ' . $responseData['message'];
}
}
return [
'success' => false,
'error' => $errorMsg,
'http_code' => $httpCode,
'body' => $response
];
}
}
return [
'success' => false,
'error' => 'Max retries exceeded',
'http_code' => 0
];
}
/**
* Fix callback URL domain mismatch
*/
private function fixCallbackUrl($callbackUrl) {
// Replace api.zitinexus.com with backend.zitinexus.com to match script's API endpoint
if (strpos($callbackUrl, 'api.zitinexus.com') !== false) {
$fixedUrl = str_replace('api.zitinexus.com', 'backend.zitinexus.com', $callbackUrl);
logMessage('INFO', "Fixed callback URL domain: $fixedUrl");
return $fixedUrl;
}
return $callbackUrl;
}
/**
* Validate hash key format
*/
public static function validateHashKey($hashKey) {
return preg_match('/^[a-fA-F0-9]{32}$/', $hashKey);
}
/**
* Validate API endpoint format
*/
public static function validateApiEndpoint($endpoint) {
return filter_var($endpoint, FILTER_VALIDATE_URL) &&
(strpos($endpoint, 'http://') === 0 || strpos($endpoint, 'https://') === 0);
}
}
?>