Files

194 lines
6.0 KiB
PHP
Raw Permalink Normal View History

<?php
/**
* Umbrix Update Server API для Desktop Платформ
*
* Сервер обновлений для Windows, macOS и Linux версий приложения.
* Android использует Google Play Store для обновлений.
*
* Версия: 1.1
*
* Использование:
* GET /api/latest - получить последнюю версию для Desktop
* GET /api/latest?include_prerelease=true - включая бета-версии
*/
// === НАСТРОЙКИ ===
// Разрешенные домены для CORS (замените на свой домен)
$allowed_origins = [
'https://umbrix.net',
'https://www.umbrix.net',
'https://api.umbrix.net'
];
// Путь к файлу с информацией о версии
$version_file = __DIR__ . '/latest.json';
// Включить логирование запросов
$enable_logging = true;
$log_file = __DIR__ . '/logs/access.log';
// Ограничение запросов (Rate Limiting)
$rate_limit_enabled = true;
$max_requests_per_minute = 10;
// === КОНЕЦ НАСТРОЕК ===
// Установка заголовков
header('Content-Type: application/json; charset=utf-8');
header('X-Powered-By: Umbrix Update Server');
// CORS - разрешаем запросы с приложения
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowed_origins)) {
header("Access-Control-Allow-Origin: $origin");
} else {
header('Access-Control-Allow-Origin: *'); // Разрешаем все для начала
}
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
// Обработка preflight запроса
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}
// Только GET запросы
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
sendError(405, 'Method Not Allowed');
}
// Rate Limiting
if ($rate_limit_enabled && !checkRateLimit($max_requests_per_minute)) {
sendError(429, 'Too Many Requests', 'Превышен лимит запросов. Попробуйте позже.');
}
// Логирование
if ($enable_logging) {
logRequest($log_file);
}
// Проверка существования файла с версией
if (!file_exists($version_file)) {
sendError(500, 'Internal Server Error', 'Файл с версией не найден');
}
// Чтение и парсинг JSON
$version_data = file_get_contents($version_file);
$version_info = json_decode($version_data, true);
if (json_last_error() !== JSON_ERROR_NONE) {
sendError(500, 'Internal Server Error', 'Ошибка парсинга JSON: ' . json_last_error_msg());
}
// Проверка обязательных полей
$required_fields = ['version', 'build_number', 'download_url', 'published_at'];
foreach ($required_fields as $field) {
if (!isset($version_info[$field])) {
sendError(500, 'Internal Server Error', "Отсутствует обязательное поле: $field");
}
}
// Фильтр пре-релизов
$include_prerelease = isset($_GET['include_prerelease']) && $_GET['include_prerelease'] === 'true';
if (!$include_prerelease && isset($version_info['is_prerelease']) && $version_info['is_prerelease'] === true) {
// Вернуть пустой ответ, если пре-релиз не запрошен
sendError(404, 'Not Found', 'Стабильная версия не найдена');
}
// Добавление дополнительной информации
$version_info['server_time'] = date('c');
$version_info['api_version'] = '1.0';
// Успешный ответ
http_response_code(200);
echo json_encode($version_info, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit();
// === ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ===
/**
* Отправка ошибки в формате JSON
*/
function sendError($code, $message, $details = null) {
http_response_code($code);
$error = [
'error' => $message,
'code' => $code,
'timestamp' => date('c')
];
if ($details) {
$error['details'] = $details;
}
echo json_encode($error, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit();
}
/**
* Проверка лимита запросов
*/
function checkRateLimit($max_requests) {
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$cache_file = sys_get_temp_dir() . '/umbrix_ratelimit_' . md5($ip);
$current_time = time();
$window_start = $current_time - 60; // Окно в 1 минуту
$requests = [];
if (file_exists($cache_file)) {
$requests = json_decode(file_get_contents($cache_file), true) ?? [];
}
// Удаляем старые запросы
$requests = array_filter($requests, function($timestamp) use ($window_start) {
return $timestamp > $window_start;
});
// Проверяем лимит
if (count($requests) >= $max_requests) {
return false;
}
// Добавляем текущий запрос
$requests[] = $current_time;
file_put_contents($cache_file, json_encode($requests));
return true;
}
/**
* Логирование запроса
*/
function logRequest($log_file) {
$log_dir = dirname($log_file);
if (!is_dir($log_dir)) {
mkdir($log_dir, 0755, true);
}
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
$request_uri = $_SERVER['REQUEST_URI'] ?? 'unknown';
$timestamp = date('Y-m-d H:i:s');
// Извлекаем версию приложения из User-Agent (если есть)
$app_version = 'unknown';
if (preg_match('/Umbrix\/([0-9.]+)/', $user_agent, $matches)) {
$app_version = $matches[1];
}
$log_entry = sprintf(
"[%s] IP: %s | App Version: %s | URI: %s | User-Agent: %s\n",
$timestamp,
$ip,
$app_version,
$request_uri,
$user_agent
);
file_put_contents($log_file, $log_entry, FILE_APPEND | LOCK_EX);
}
?>