feat: mobile-like window size and always-visible stats

- Changed window size to mobile phone format (400x800)
- Removed width condition for ActiveProxyFooter - now always visible
- Added run-umbrix.sh launch script with icon copying
- Stats cards now display on all screen sizes
This commit is contained in:
Umbrix Developer
2026-01-17 13:09:20 +03:00
parent ec5ebbd54b
commit 76a374950f
245 changed files with 7931 additions and 1315 deletions

107
update-server/.htaccess Normal file
View File

@@ -0,0 +1,107 @@
# Umbrix Update Server - Apache Configuration
# === ЧПУ (Красивые URL) ===
RewriteEngine On
# Редирект с index.php на api.php
RewriteRule ^index\.php$ api.php [L,R=301]
# API endpoints
RewriteRule ^api/latest$ api.php [L,QSA]
RewriteRule ^api/version$ api.php [L,QSA]
# === Безопасность ===
# Запретить доступ к служебным файлам
<FilesMatch "^(latest\.json|\.htaccess|\.git.*|composer\.json|package\.json|README\.md)$">
Order deny,allow
Deny from all
</FilesMatch>
# Разрешить доступ только к API и downloads
<FilesMatch "^(api\.php)$">
Order allow,deny
Allow from all
</FilesMatch>
# Запретить листинг директорий
Options -Indexes
# Запретить выполнение PHP в папке downloads
<Directory "downloads">
php_flag engine off
RemoveHandler .php .phtml .php3
RemoveType .php .phtml .php3
</Directory>
# === CORS Headers ===
<IfModule mod_headers.c>
# Разрешить CORS для API
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type"
# Кеширование для APK файлов
<FilesMatch "\.(apk)$">
Header set Cache-Control "public, max-age=604800"
</FilesMatch>
# Запрет кеширования для API
<FilesMatch "\.(php|json)$">
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "0"
</FilesMatch>
</IfModule>
# === Сжатие ===
<IfModule mod_deflate.c>
# Сжимать JSON и текстовые файлы
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
# НЕ сжимать APK файлы (они уже сжаты)
SetEnvIfNoCase Request_URI \.apk$ no-gzip dont-vary
</IfModule>
# === MIME типы ===
<IfModule mod_mime.c>
AddType application/vnd.android.package-archive .apk
AddType application/json .json
</IfModule>
# === Ограничение размера загрузки ===
<IfModule mod_php7.c>
php_value upload_max_filesize 100M
php_value post_max_size 100M
php_value max_execution_time 300
php_value max_input_time 300
</IfModule>
# === Защита от инъекций ===
<IfModule mod_rewrite.c>
# Блокировать подозрительные запросы
RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
RewriteRule ^(.*)$ - [F,L]
</IfModule>
# === Логирование ===
<IfModule mod_log_config.c>
# Кастомный формат логов
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" custom
CustomLog logs/access.log custom
</IfModule>
# === Производительность ===
<IfModule mod_expires.c>
ExpiresActive On
# APK файлы кешировать на неделю
ExpiresByType application/vnd.android.package-archive "access plus 7 days"
# API не кешировать
ExpiresByType application/json "access plus 0 seconds"
</IfModule>

View File

@@ -0,0 +1,227 @@
# История изменений системы обновлений
## Версия 1.1 - Упрощение и Desktop-фокус
**Дата:** 2024
### 🎯 Главное изменение
Система обновлений переориентирована **только на Desktop платформы** (Windows, macOS, Linux).
Android версия использует Google Play Store для автоматических обновлений.
---
### ✨ Что изменилось
#### Код приложения
1. **new_version_dialog.dart** - Упрощён:
- ✅ Android: Открывает браузер/Google Play
- ✅ Desktop: Скачивание с прогресс-баром + автозапуск установщика
- ❌ Удалены: Android permissions, MethodChannel, InstallHandler
2. **about_page.dart**:
- Кнопка "Проверить обновления" видна **только на Desktop**
- Android не показывает кнопку (обновления через Google Play)
3. **Android код удалён**:
-`InstallHandler.kt` - удалён
-`REQUEST_INSTALL_PACKAGES` permission - удалён из манифеста
- ❌ Регистрация InstallHandler в MainActivity - удалена
#### Документация
1. **README.md** - Обновлён:
- Добавлено предупреждение о Desktop-only
- Изменена диаграмма процесса обновления
- Добавлены ссылки на Google Play для Android
2. **README_DESKTOP.md** - Создан:
- Подробная инструкция для Desktop платформ
- Структура файлов (.exe, .dmg, .AppImage)
- Примеры конфигурации
3. **api.php** - Обновлён комментарий:
- Указано, что API только для Desktop
- Упомянуто использование Google Play для Android
---
### 🧹 Что почистили
#### Удалённые файлы
- `android/app/src/main/kotlin/com/umbrix/app/InstallHandler.kt`
#### Удалённые permissions
- `android.permission.REQUEST_INSTALL_PACKAGES` из AndroidManifest.xml
#### Удалённый код
- MethodChannel для проверки Android permissions
- Функции `checkInstallPermission()`, `requestInstallPermission()`
- Сложная логика установки APK из приложения
---
### 📦 Зависимости
Используемые пакеты **только для Desktop**:
- `dio` ^5.4.1 - HTTP запросы и загрузка файлов
- `path_provider` ^2.1.1 - Временная директория для загрузок
- `open_file` ^3.3.2 - Открытие установщика после загрузки
Android теперь использует только:
- `UriUtils.tryLaunch()` - Открытие браузера/Google Play
---
### 🔄 Логика работы
#### Desktop (Windows/macOS/Linux)
```dart
if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) {
// 1. Проверка обновлений на сервере
// 2. Показ диалога с информацией о версии
// 3. Скачивание с прогресс-баром (dio)
// 4. Сохранение в temp директорию
// 5. Автоматический запуск установщика (open_file)
}
```
#### Android
```dart
if (Platform.isAndroid) {
// 1. Проверка обновлений НЕ показывается (кнопка скрыта)
// 2. В production: прямая ссылка на Google Play
// 3. В debug: открытие браузера с download_url
}
```
---
### 🚀 Дальнейшие планы
#### Production деплой
1. **Windows**:
- Создание `.exe` установщика
- Подпись сертификатом
- Загрузка в `downloads/windows/`
2. **macOS**:
- Создание `.dmg` образа
- Нотаризация Apple
- Загрузка в `downloads/macos/`
3. **Linux**:
- Создание `.AppImage`
- Добавление `.deb` / `.rpm` пакетов
- Загрузка в `downloads/linux/`
4. **Android**:
- Публикация в Google Play Store
- Удаление кастомного сервера обновлений
- Автоматические обновления через магазин
---
### 💡 Почему так?
**Проблема:** Android требует сложные разрешения для установки APK из приложения:
- Нужен `REQUEST_INSTALL_PACKAGES` permission
- Пользователь должен вручную дать разрешение в настройках
- Это запутывает пользователей и выглядит нелогично
**Решение:**
- Android → Google Play Store (стандартный путь)
- Desktop → Собственный сервер обновлений (гибкость и контроль)
---
### 📝 Заметки разработчика
> "как то нелогично . но мы же его установили уже ... на андроид может и не надо такое обновление на exe надо будет"
Было принято решение упростить систему:
- На Android слишком сложно и нелогично обновлять APK изнутри приложения
- Google Play Store делает это автоматически и безопасно
- Desktop платформам нужна эта функция, так как нет централизованного магазина
- Разделение платформ упрощает код и улучшает UX
---
## Версия 1.0 - Первый релиз
**Дата:** 2024
- ✅ PHP API для проверки обновлений
- ✅ Web-панель администратора
- ✅ История версий
- ✅ Поддержка beta/stable релизов
- ✅ CORS настройки
- ✅ Rate limiting
- ✅ Логирование запросов
- ✅ Интеграция с Flutter приложением
**Проблемы версии 1.0:**
- Пыталась поддерживать Android с установкой APK
- Требовала сложные Android permissions
- Запутанная UX для пользователей Android
---
## Миграция с 1.0 на 1.1
### Для разработчиков
1. Обновите код приложения (Flutter):
```bash
git pull
flutter pub get
flutter build apk --debug # для тестирования
```
2. Удалите старый APK с устройства:
```bash
adb uninstall com.umbrix.app
```
3. Установите новую версию:
```bash
adb install build/app/outputs/flutter-apk/app-debug.apk
```
### Для сервера
Ничего менять не нужно! API осталось совместимым.
Просто обновите документацию:
- `README.md` ← основной файл
- `README_DESKTOP.md` ← подробности для Desktop
### Для пользователей
**Android:**
- Обновления теперь через Google Play Store
- Кнопка "Проверить обновления" больше не показывается
**Desktop:**
- Всё работает как раньше, но с улучшенным UX
- Прогресс-бар при скачивании
- Автоматический запуск установщика
---
## Контрольный список релиза
- [x] Упростить код для Android
- [x] Реализовать скачивание для Desktop с прогресс-баром
- [x] Удалить InstallHandler.kt
- [x] Удалить REQUEST_INSTALL_PACKAGES permission
- [x] Обновить README.md
- [x] Создать README_DESKTOP.md
- [x] Обновить комментарии в api.php
- [x] Протестировать на Android emulator
- [ ] Создать Windows .exe установщик
- [ ] Создать macOS .dmg образ
- [ ] Создать Linux .AppImage
- [ ] Опубликовать в Google Play Store
- [ ] Production деплой сервера

View File

@@ -0,0 +1,174 @@
═══════════════════════════════════════════════════════════════
🚀 ШПАРГАЛКА - Система Обновлений Umbrix
═══════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────┐
│ 📖 ШАГ 1: ПРОЧИТАЙТЕ ИНСТРУКЦИИ │
└─────────────────────────────────────────────────────────────┘
📄 UPDATE_SERVER_GUIDE.md ← НАЧНИТЕ ЗДЕСЬ
📂 update-server/
├── QUICK_START.md ← Быстрый старт (5 минут)
├── README.md ← Полная инструкция
└── TESTING.md ← Тестирование
┌─────────────────────────────────────────────────────────────┐
│ 🧪 ШАГ 2: ПРОТЕСТИРУЙТЕ ЛОКАЛЬНО │
└─────────────────────────────────────────────────────────────┘
$ cd update-server
$ ./start_test_server.sh
➜ Сервер запустится на http://localhost:8000
➜ Для эмулятора: http://10.0.2.2:8000/api.php
┌─────────────────────────────────────────────────────────────┐
│ ⚙️ ШАГ 3: НАСТРОЙТЕ КОД │
└─────────────────────────────────────────────────────────────┘
Файл: lib/core/model/constants.dart
┌──────────────────────────────────────────────────────┐
│ // Для ТЕСТИРОВАНИЯ: │
│ static const customUpdateServerUrl = │
│ "http://10.0.2.2:8000/api.php"; │
│ │
│ // Для ПРОДАКШЕНА: │
│ static const customUpdateServerUrl = │
│ "https://api.umbrix.net/api/latest"; │
│ │
│ // ВКЛЮЧИТЬ собственный сервер: │
│ static const useCustomUpdateServer = true; │
└──────────────────────────────────────────────────────┘
⚠️ ВАЖНО: Пересоберите после изменений!
$ flutter build apk --release
┌─────────────────────────────────────────────────────────────┐
│ 🎯 ШАГ 4: ПРОВЕРЬТЕ В ПРИЛОЖЕНИИ │
└─────────────────────────────────────────────────────────────┘
1. Запустите приложение в эмуляторе
2. Откройте: Настройки → О программе
3. Нажмите: "Проверить обновления"
4. Должно появиться окно с новой версией
┌─────────────────────────────────────────────────────────────┐
│ 🌐 ШАГ 5: ЗАГРУЗИТЕ НА СЕРВЕР (ПРОДАКШЕН) │
└─────────────────────────────────────────────────────────────┘
Загрузите через FTP/панель хостинга:
📁 /var/www/updates/
├── api.php ← главный скрипт
├── latest.json ← информация о версии
├── .htaccess ← настройки Apache
└── downloads/ ← создайте пустую папку
└── (APK файлы будут здесь)
Настройте домен: api.umbrix.net → /var/www/updates
Включите SSL (Let's Encrypt бесплатно)
┌─────────────────────────────────────────────────────────────┐
│ 📦 КАК ВЫКАТИТЬ НОВОЕ ОБНОВЛЕНИЕ? │
└─────────────────────────────────────────────────────────────┘
🎨 СПОСОБ 1: Через веб-панель (рекомендуется)
1. Откройте: https://api.umbrix.net/admin/
2. Заполните форму (версия, URL, описание)
3. Нажмите "Сохранить обновление"
4. Готово! 🎉
📝 СПОСОБ 2: Вручную (старый способ)
1. Соберите APK:
$ flutter build apk --release
2. Переименуйте:
app-release.apk → umbrix-2.5.8.apk
3. Загрузите в папку downloads/ на сервере
4. Обновите latest.json:
{
"version": "2.5.8",
"build_number": "258",
"download_url": "https://api.umbrix.net/downloads/umbrix-2.5.8.apk",
"release_notes": "🎉 Что нового...",
"published_at": "2026-01-17T12:00:00Z"
}
5. Готово! Пользователи получат уведомление
┌─────────────────────────────────────────────────────────────┐
│ ✅ ПРОВЕРОЧНЫЙ СПИСОК │
└─────────────────────────────────────────────────────────────┘
Перед запуском убедитесь:
□ PHP 7.4+ установлен на сервере
□ Файлы загружены: api.php, latest.json, .htaccess
□ Папка downloads/ создана (права 755)
□ Домен настроен с HTTPS
□ URL в constants.dart правильный
□ useCustomUpdateServer = true
□ Приложение пересобрано
□ API отвечает в браузере: https://api.umbrix.net/api/latest
□ APK скачивается: https://api.umbrix.net/downloads/umbrix-X.X.X.apk
┌─────────────────────────────────────────────────────────────┐
│ 🔧 ПОЛЕЗНЫЕ КОМАНДЫ │
└─────────────────────────────────────────────────────────────┘
# Проверить API в браузере:
https://api.umbrix.net/api/latest
# Проверить через curl:
$ curl https://api.umbrix.net/api/latest
# Собрать APK:
$ flutter build apk --release
# Запустить в эмуляторе:
$ flutter run
# Установить APK в эмулятор:
$ flutter install
# Посмотреть логи:
$ adb logcat | grep -i umbrix
┌─────────────────────────────────────────────────────────────┐
│ ❓ ЧАСТЫЕ ПРОБЛЕМЫ │
└─────────────────────────────────────────────────────────────┘
❌ "Обновления не приходят"
✅ Проверьте: useCustomUpdateServer = true
✅ Проверьте: URL правильный (с https://)
✅ Пересоберите приложение
✅ Версия в latest.json должна быть БОЛЬШЕ текущей
❌ "API не отвечает"
✅ Откройте URL в браузере - должен показать JSON
✅ Проверьте PHP логи на сервере
✅ Проверьте, что файлы загружены
❌ "Не скачивается APK"
✅ Проверьте, что файл существует в downloads/
✅ Проверьте права: chmod 644 file.apk
✅ Проверьте URL в latest.json
┌─────────────────────────────────────────────────────────────┐
│ 📞 ДОКУМЕНТАЦИЯ │
└─────────────────────────────────────────────────────────────┘
📄 UPDATE_SERVER_GUIDE.md - главная инструкция
📂 update-server/INDEX.md - навигация
📂 update-server/README.md - полное руководство
📂 update-server/QUICK_START.md - быстрый старт
📂 update-server/TESTING.md - тестирование
═══════════════════════════════════════════════════════════════
🎉 Готово! Удачи с обновлениями! 🚀
═══════════════════════════════════════════════════════════════

View File

@@ -0,0 +1,299 @@
# 🐳 Хранение APK файлов в Docker контейнере
## 📋 Проблема
При размещении update-server в Docker контейнере, нужно решить где хранить APK файлы (обычно 50-100 MB каждый).
## ✅ Решение: Docker Volume
### Вариант 1: Named Volume (Рекомендуется)
**docker-compose.yml:**
```yaml
version: '3.8'
services:
update-server:
image: php:8.3-cli
container_name: umbrix-update-server
working_dir: /var/www
command: php -S 0.0.0.0:8000
ports:
- "8000:8000"
volumes:
# Код сервера (read-only)
- ./update-server:/var/www:ro
# Файлы обновлений (read-write)
- umbrix-downloads:/var/www/downloads
# Логи (read-write)
- umbrix-logs:/var/www/logs
restart: unless-stopped
volumes:
umbrix-downloads:
driver: local
umbrix-logs:
driver: local
```
**Преимущества:**
- ✅ Файлы сохраняются при пересоздании контейнера
- ✅ Легко делать backup: `docker cp`
- ✅ Данные изолированы от кода
**Как загружать APK:**
```bash
# 1. Соберите APK
flutter build apk --release
# 2. Скопируйте в volume
docker cp build/app/outputs/flutter-apk/app-release.apk \
umbrix-update-server:/var/www/downloads/android/umbrix-1.7.1.apk
# 3. Обновите latest.json через веб-панель
# http://your-server:8000/admin/
```
---
### Вариант 2: Bind Mount (Для разработки)
**docker-compose.yml:**
```yaml
services:
update-server:
volumes:
- ./update-server:/var/www
# Downloads доступны локально
- ./downloads:/var/www/downloads
```
**Преимущества:**
- ✅ Прямой доступ с хоста
- ✅ Удобно для разработки
- ✅ Можно редактировать напрямую
**Недостатки:**
- ⚠️ Нужно следить за правами доступа
- ⚠️ Файлы привязаны к хосту
**Загрузка:**
```bash
# Просто скопируйте файл
cp build/app/outputs/flutter-apk/app-release.apk \
downloads/android/umbrix-1.7.1.apk
```
---
### Вариант 3: Внешнее хранилище (Продакшен)
Для продакшена лучше использовать CDN или объектное хранилище:
**Примеры:**
- 🌐 **CloudFlare R2** (S3-совместимый, бесплатный)
- 🌐 **AWS S3** + CloudFront
- 🌐 **DigitalOcean Spaces**
- 🌐 **Azure Blob Storage**
- 🌐 **Backblaze B2**
**docker-compose.yml с S3:**
```yaml
services:
update-server:
environment:
- STORAGE_TYPE=s3
- S3_BUCKET=umbrix-updates
- S3_REGION=eu-central-1
- AWS_ACCESS_KEY_ID=${AWS_KEY}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET}
```
**latest.json:**
```json
{
"download_url": "https://cdn.umbrix.net/downloads/android/umbrix-1.7.1.apk"
}
```
**Преимущества:**
- ✅ Быстрая доставка (CDN)
- ✅ Неограниченное место
- ✅ Автоматический backup
-Не нагружает ваш сервер
---
## 📊 Сравнение вариантов
| Вариант | Разработка | Продакшен | Сложность | Стоимость |
|---------|-----------|-----------|-----------|-----------|
| Named Volume | ⭐⭐⭐ | ⭐⭐⭐ | Низкая | Бесплатно |
| Bind Mount | ⭐⭐⭐⭐⭐ | ⭐⭐ | Низкая | Бесплатно |
| S3/CDN | ⭐⭐ | ⭐⭐⭐⭐⭐ | Средняя | $5-20/мес |
---
## 🚀 Быстрый старт (Named Volume)
**1. Создайте docker-compose.yml:**
```bash
cd /home/vodorod/dorod/hiddify-umbrix-v1.7.0
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
update-server:
image: php:8.3-cli
container_name: umbrix-update-server
working_dir: /var/www
command: php -S 0.0.0.0:8000
ports:
- "8000:8000"
volumes:
- ./update-server:/var/www:ro
- umbrix-downloads:/var/www/downloads
- umbrix-logs:/var/www/logs
restart: unless-stopped
volumes:
umbrix-downloads:
umbrix-logs:
EOF
```
**2. Запустите:**
```bash
docker-compose up -d
```
**3. Загрузите APK:**
```bash
# Соберите
flutter build apk --release
# Загрузите в контейнер
docker cp build/app/outputs/flutter-apk/app-release.apk \
umbrix-update-server:/var/www/downloads/android/umbrix-1.7.1.apk
# Проверьте
docker exec umbrix-update-server ls -lh /var/www/downloads/android/
```
**4. Обновите latest.json через веб-панель:**
```
http://localhost:8000/admin/
```
---
## 🔒 Защита от конфликта с оригинальным Hiddify
### ✅ Убедитесь что настроено:
**lib/core/model/constants.dart:**
```dart
// Ваш сервер обновлений
static const useCustomUpdateServer = true; // ← ДОЛЖНО БЫТЬ true
// URL вашего сервера
static const customUpdateServerUrl = "https://api.umbrix.net/api.php";
```
**Что проверить:**
```bash
# 1. Проверьте константы
grep "useCustomUpdateServer" lib/core/model/constants.dart
# 2. Должно вывести:
# static const useCustomUpdateServer = true;
```
### ⚠️ Если false - приложение будет проверять GitHub!
**При `useCustomUpdateServer = false`:**
- ❌ Обращается к https://api.github.com/repos/hiddify/hiddify-app/releases
- ❌ Увидит оригинальные обновления Hiddify
- ❌ Предложит скачать оригинальную версию
**При `useCustomUpdateServer = true`:**
- ✅ Обращается к вашему серверу
- ✅ Видит только ваши обновления
- ✅ Полный контроль
---
## 🎯 Рекомендации
### Для локальной разработки:
```bash
# Используйте PHP встроенный сервер
cd update-server && php -S localhost:8000
```
### Для тестирования в Docker:
```bash
# Named Volume
docker-compose up -d
```
### Для продакшена:
```yaml
# docker-compose.yml
services:
update-server:
image: php:8.3-fpm
volumes:
- ./update-server:/var/www
- umbrix-downloads:/var/www/downloads
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- umbrix-downloads:/var/www/downloads:ro
- ./ssl:/etc/nginx/ssl
```
---
## 📦 Backup файлов обновлений
### Из Named Volume:
```bash
# Backup
docker run --rm \
-v umbrix-downloads:/data \
-v $(pwd):/backup \
alpine tar czf /backup/downloads-backup.tar.gz /data
# Restore
docker run --rm \
-v umbrix-downloads:/data \
-v $(pwd):/backup \
alpine tar xzf /backup/downloads-backup.tar.gz -C /
```
### Из Bind Mount:
```bash
# Просто архивируйте
tar czf downloads-backup.tar.gz downloads/
```
---
## 💡 Итого
**Для вас (Umbrix):**
1. ✅ Используйте **Named Volume** в Docker
2.`useCustomUpdateServer = true` уже установлено
3. ✅ Загружайте APK через `docker cp`
4. ✅ Управляйте через веб-панель http://localhost:8000/admin/
5.**НЕ будет** конфликта с оригинальным Hiddify!
**Версии теперь логичные:**
- Текущая: **1.7.0 dev**
- Доступна: **1.7.1**
- Следующая: **1.7.2**, **1.8.0**, и т.д.

161
update-server/INDEX.md Normal file
View File

@@ -0,0 +1,161 @@
# 🎯 Система Обновлений - Главная Документация
## 📁 Структура папки update-server/
```
update-server/
├── 📖 README.md ← Полная инструкция (начните отсюда)
├── ⚡ QUICK_START.md ← Быстрый старт за 5 минут
├── 🧪 TESTING.md ← Тестирование в эмуляторе
├── 🚀 start_test_server.sh ← Скрипт для запуска тестового сервера
├── 🔧 api.php ← PHP скрипт API (загрузите на сервер)
├── 📄 latest.json ← Информация о версии (обновляйте при релизе)
├── ⚙️ .htaccess ← Настройки Apache (загрузите на сервер)
└── downloads/ ← Папка для APK файлов (создайте на сервере)
└── umbrix-X.X.X.apk
```
---
## 🎓 Что читать?
### Для новичков:
👉 **[QUICK_START.md](QUICK_START.md)** - простая инструкция на 5 минут
### Подробная настройка:
👉 **[README.md](README.md)** - полное руководство со всеми деталями
### Для разработчиков:
👉 **[TESTING.md](TESTING.md)** - как тестировать в эмуляторе
---
## ⚡ Быстрый Старт
### 1⃣ Тестирование (локально)
```bash
# Запустите тестовый сервер
cd update-server
./start_test_server.sh
# Откроется на http://localhost:8000
```
### 2⃣ Настройка приложения
Измените `lib/core/model/constants.dart`:
```dart
// Для тестирования в эмуляторе:
static const customUpdateServerUrl = "http://10.0.2.2:8000/api.php";
static const useCustomUpdateServer = true;
// Для продакшена (когда загрузите на свой сервер):
static const customUpdateServerUrl = "https://api.umbrix.net/api/latest";
static const useCustomUpdateServer = true;
```
### 3⃣ Проверка
1. Запустите приложение в эмуляторе
2. Настройки → О программе → Проверить обновления
3. Должно появиться окно (если версия в latest.json выше)
---
## 🎯 Для продакшена
1. **Загрузите файлы на хостинг:**
- `api.php`
- `latest.json`
- `.htaccess`
2. **Создайте папку `downloads/`**
3. **Настройте домен и SSL**
4. **Измените URL в приложении** → пересоберите
5. **При новом релизе:**
- Загрузите APK в `downloads/`
- Обновите `latest.json`
- Готово! Пользователи получат уведомление
---
## 📋 Чек-лист
Перед запуском убедитесь:
- [ ] PHP 7.4+ установлен
- [ ] Все файлы загружены на сервер
- [ ] Папка `downloads/` создана
- [ ] Домен настроен с HTTPS
- [ ] URL в `constants.dart` правильный
- [ ] Приложение пересобрано
- [ ] API отвечает в браузере
- [ ] APK скачивается
---
## ❓ Проблемы?
### Не работает проверка обновлений?
1. Проверьте `useCustomUpdateServer = true`
2. Проверьте URL (должен быть с `https://`)
3. Пересоберите приложение после изменений
4. Проверьте версию в `latest.json` (должна быть больше текущей)
### API не отвечает?
1. Откройте URL в браузере - должен показаться JSON
2. Проверьте PHP логи на сервере
3. Проверьте права на файлы
### Не скачивается APK?
1. Проверьте, что файл существует в папке `downloads/`
2. Проверьте права: `chmod 644 file.apk`
3. Проверьте URL в `latest.json`
---
## 🔗 Полезные ссылки
- **Полная инструкция:** [README.md](README.md)
- **Быстрый старт:** [QUICK_START.md](QUICK_START.md)
- **Тестирование:** [TESTING.md](TESTING.md)
---
## 💡 Примеры использования
### GitHub (публичный репозиторий)
```dart
static const useCustomUpdateServer = false;
```
### Собственный сервер (приватный репозиторий)
```dart
static const customUpdateServerUrl = "https://api.yoursite.com/api/latest";
static const useCustomUpdateServer = true;
```
---
## 🎉 Готово!
Система обновлений настроена. Теперь вы можете:
✅ Выкатывать обновления без магазинов
✅ Контролировать процесс релизов
✅ Тестировать бета-версии
✅ Видеть аналитику использования
---
**Удачи в разработке! 🚀**

View File

@@ -0,0 +1,113 @@
# ⚡ Быстрый Старт - 5 минут
Минимальная инструкция для тех, кто хочет запустить быстро.
## 🎯 Что делать (по шагам)
### 1⃣ Загрузите файлы на хостинг
Через FTP/панель хостинга загрузите эти 4 файла:
```
📁 Ваша папка на сервере (например: /var/www/updates/)
├── api.php ← главный файл
├── latest.json ← информация о версии
├── .htaccess ← настройки
└── downloads/ ← создайте пустую папку
```
---
### 2⃣ Настройте домен
В панели хостинга:
1. Создайте поддомен: `api.umbrix.net` (или любое имя)
2. Укажите папку: `/var/www/updates`
3. Включите SSL (Let's Encrypt бесплатно)
---
### 3⃣ Измените `latest.json`
Откройте файл `latest.json` и замените:
```json
{
"version": "2.5.7",
"download_url": "https://api.umbrix.net/downloads/umbrix-2.5.7.apk",
замените на свой домен
```
---
### 4⃣ Измените код приложения
Откройте файл `lib/core/model/constants.dart`:
```dart
// Было:
static const customUpdateServerUrl = "https://your-server.com/api/updates/latest";
// Стало (ваш домен):
static const customUpdateServerUrl = "https://api.umbrix.net/api/latest";
// Включаем собственный сервер:
static const useCustomUpdateServer = true;
```
---
### 5⃣ Пересоберите приложение
```bash
flutter build apk --release
```
---
### 6⃣ Загрузите APK на сервер
1. Найдите APK: `build/app/outputs/flutter-apk/app-release.apk`
2. Переименуйте в: `umbrix-2.5.7.apk`
3. Загрузите в папку `downloads/` на сервере
---
### 7⃣ Проверьте
Откройте в браузере:
```
https://api.umbrix.net/api/latest
```
Должны увидеть JSON с версией.
---
## ✅ Готово!
Теперь когда выйдет новая версия:
1. Соберите новый APK
2. Загрузите в `downloads/`
3. Обновите `latest.json` (версию и URL)
4. Всё! Пользователи получат уведомление
---
## ❓ Не работает?
### Проверьте:
- ✅ HTTPS включен
- ✅ Файлы загружены в правильную папку
- ✅ URL в `constants.dart` правильный (с `https://`)
- ✅ Приложение пересобрано после изменений
### Частые ошибки:
- Забыли пересобрать приложение
- Опечатка в URL
- Нет SSL сертификата
- Версия в `latest.json` меньше или равна текущей
---
**📖 Подробная инструкция:** см. файл `README.md`

319
update-server/README.md Normal file
View File

@@ -0,0 +1,319 @@
# 🚀 Сервер Обновлений Umbrix
> **⚠️ Внимание:** Этот сервер предназначен **только для Desktop платформ** (Windows, macOS, Linux).
> Для Android используется Google Play Store.
---
## 📋 Что это?
Система автоматических обновлений для настольных версий Umbrix. Пользователи получают уведомления об обновлениях прямо в приложении с автоматической загрузкой и установкой.
---
## 🎯 Как это работает?
```
┌──────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Desktop App │ -------> │ Ваш сервер │ <------- │ Вы загружаете│
│ Windows/Mac/ │ запрос │ (PHP API) │ файлы │ новую версию │
│ Linux │ │ │ │ .exe/.dmg │
└──────────────┘ └──────────────────┘ └─────────────┘
│ │
│ ответ JSON │
│ + скачивание │
с прогресс-баром │
└──────────────────────────>│
```
**Процесс:**
1. **Desktop приложение** проверяет сервер на наличие обновлений
2. **Сервер** возвращает информацию о последней версии
3. **Приложение** скачивает обновление с прогресс-баром
4. **Пользователь** запускает установщик
**Для Android:** Обновления через Google Play Store (автоматически)
---
## 📦 Что нужно?
### Минимальные требования:
- ✅ Хостинг с PHP 7.4+ (любой: Timeweb, Beget, VPS)
- ✅ Домен или поддомен (например: `api.umbrix.net`)
- ✅ HTTPS сертификат (бесплатный Let's Encrypt)
---
## 🛠️ Установка - Пошагово
### Шаг 1: Подготовка сервера
1. **Создайте папку на сервере:**
```bash
mkdir -p /var/www/updates
```
2. **Загрузите файлы из папки `update-server/`:**
- `api.php` - главный скрипт
- `latest.json` - информация о последней версии
- `.htaccess` - настройки Apache
3. **Создайте папку для APK файлов:**
```bash
mkdir -p /var/www/updates/downloads
chmod 755 /var/www/updates/downloads
```
---
### Шаг 2: Настройка домена
1. **Создайте поддомен** (в панели хостинга):
- Имя: `api` или `updates`
- Полный адрес: `api.umbrix.net`
- Папка: `/var/www/updates`
2. **Включите HTTPS:**
- В панели хостинга найдите "SSL сертификат"
- Выберите "Let's Encrypt" (бесплатно)
- Нажмите "Установить"
---
### Шаг 3: Настройка приложения
Откройте файл `lib/core/model/constants.dart` и измените:
```dart
// Замените на адрес вашего сервера
static const customUpdateServerUrl = "https://api.umbrix.net/api/latest";
// Включите собственный сервер обновлений
static const useCustomUpdateServer = true;
```
---
### Шаг 4: Загрузка новой версии
Когда у вас готова новая версия:
1. **Соберите APK:**
```bash
flutter build apk --release
```
2. **Переименуйте файл** (для удобства):
```bash
# Из: build/app/outputs/flutter-apk/app-release.apk
# В: umbrix-2.5.8.apk
```
3. **Загрузите на сервер:**
- Через FTP/SFTP загрузите APK в папку `/var/www/updates/downloads/`
- Или через панель хостинга
4. **Обновите файл `latest.json`:**
```json
{
"version": "2.5.8",
"build_number": "258",
"is_prerelease": false,
"download_url": "https://api.umbrix.net/downloads/umbrix-2.5.8.apk",
"release_notes": "🎉 Что нового:\n\n- Исправлены ошибки соединения\n- Улучшена стабильность\n- Новые серверы",
"published_at": "2026-01-17T12:00:00Z",
"min_required_version": "2.5.0"
}
```
---
## 🧪 Проверка работы
### 1. Проверьте API в браузере:
Откройте: `https://api.umbrix.net/api/latest`
Должны увидеть JSON:
```json
{
"version": "2.5.8",
"build_number": "258",
...
}
```
### 2. Проверьте скачивание APK:
Откройте: `https://api.umbrix.net/downloads/umbrix-2.5.8.apk`
Должно начаться скачивание файла.
### 3. Проверьте в приложении:
1. Откройте приложение
2. Зайдите в **Настройки → О программе**
3. Нажмите **"Проверить обновления"**
4. Должно появиться окно с новой версией (если она новее текущей)
---
## 📝 Структура файлов на сервере
```
/var/www/updates/
├── api.php # Главный скрипт API
├── latest.json # Информация о последней версии
├── .htaccess # Настройки Apache (ЧПУ, безопасность)
├── downloads/ # Папка с APK файлами
│ ├── umbrix-2.5.7.apk
│ ├── umbrix-2.5.8.apk
│ └── umbrix-2.6.0-beta.apk
└── logs/ # Логи (автоматически создается)
└── access.log
```
---
## 🔒 Безопасность
### Уже реализовано:
✅ **CORS защита** - только ваше приложение может запрашивать обновления
✅ **Rate Limiting** - не более 10 запросов в минуту с одного IP
✅ **Валидация JSON** - проверка формата данных
✅ **Логирование** - все запросы записываются
### Рекомендации:
1. **Используйте HTTPS** (обязательно!)
2. **Регулярно обновляйте** PHP на сервере
3. **Делайте бэкапы** файлов и APK
4. **Проверяйте логи** на подозрительную активность
---
## 🎨 Дополнительные возможности
### 1. Принудительное обновление
Если нужно **заставить** пользователей обновиться:
```json
{
"version": "2.6.0",
"force_update": true,
"min_required_version": "2.5.0"
}
```
Приложение не запустится на версиях ниже 2.5.0.
### 2. Бета-версии
Для тестировщиков:
```json
{
"version": "2.6.0-beta",
"is_prerelease": true,
"download_url": "https://api.umbrix.net/downloads/umbrix-2.6.0-beta.apk"
}
```
### 3. Аналитика
Смотрите файл `logs/access.log`:
- Сколько пользователей проверяют обновления
- Какие версии используют
- Откуда приходят запросы
---
## ❓ Частые проблемы
### Проблема: "Обновления не приходят"
**Решение:**
1. Проверьте, что `useCustomUpdateServer = true` в `constants.dart`
2. Проверьте, что URL правильный (с `https://`)
3. Проверьте, что `version` в `latest.json` больше текущей
4. Пересоберите приложение после изменения констант
### Проблема: "Ошибка при скачивании APK"
**Решение:**
1. Проверьте права на папку: `chmod 755 downloads`
2. Проверьте, что файл существует
3. Проверьте, что URL в `download_url` правильный
### Проблема: "API возвращает ошибку 500"
**Решение:**
1. Проверьте PHP логи на сервере
2. Убедитесь, что PHP версии 7.4+
3. Проверьте права на файл `latest.json`: `chmod 644 latest.json`
---
## 📞 Поддержка
Если что-то не работает:
1. Проверьте логи: `/var/www/updates/logs/access.log`
2. Проверьте PHP логи на сервере
3. Напишите в поддержку хостинга
---
## 🎓 Дополнительная информация
### Полезные команды для сервера:
```bash
# Посмотреть последние запросы
tail -f /var/www/updates/logs/access.log
# Проверить размер APK файлов
du -h /var/www/updates/downloads/*
# Очистить старые APK (оставить последние 3)
ls -t /var/www/updates/downloads/*.apk | tail -n +4 | xargs rm
# Проверить права доступа
ls -la /var/www/updates/
```
### Тестирование API через curl:
```bash
# Проверить API
curl https://api.umbrix.net/api/latest
# Проверить с бета-версиями
curl "https://api.umbrix.net/api/latest?include_prerelease=true"
# Скачать APK
curl -O https://api.umbrix.net/downloads/umbrix-2.5.8.apk
```
---
## ✅ Чеклист перед запуском
- [ ] PHP 7.4+ установлен
- [ ] Папка `/var/www/updates` создана
- [ ] Файлы `api.php`, `latest.json`, `.htaccess` загружены
- [ ] Папка `downloads/` создана с правами 755
- [ ] Домен `api.umbrix.net` настроен
- [ ] SSL сертификат установлен
- [ ] URL в `constants.dart` обновлен
- [ ] Приложение пересобрано
- [ ] API отвечает в браузере
- [ ] APK скачивается по ссылке
- [ ] Проверка обновлений работает в приложении
---
**🎉 Готово! Теперь вы можете выкатывать обновления без магазинов!**

View File

@@ -0,0 +1,187 @@
# 🖥️ Сервер Обновлений Umbrix для Desktop Платформ
## 📋 Что это?
Система автоматических обновлений для **настольных версий** Umbrix (Windows, macOS, Linux).
> **⚠️ Важно:** Для Android используется Google Play Store. Этот сервер только для Desktop!
---
## 🎯 Как это работает?
```
┌──────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Desktop App │ -------> │ Ваш сервер │ <------- │ Вы загружаете│
│ Windows/Mac/ │ запрос │ (PHP API) │ файлы │ новую версию │
│ Linux │ │ │ │ .exe/.dmg │
└──────────────┘ └──────────────────┘ └─────────────┘
│ │
│ ответ JSON │
│ + скачивание │
с прогресс-баром │
└──────────────────────────>│
```
**Процесс:**
1. **Desktop приложение** проверяет сервер на наличие обновлений
2. **Сервер** возвращает информацию о последней версии
3. **Приложение** скачивает обновление с прогресс-баром
4. **Пользователь** запускает установщик
**Для Android:** Обновления через Google Play Store (автоматически)
---
## 📦 Требования
- **PHP 7.4+** с веб-сервером (Apache/Nginx) или встроенный сервер PHP
- Доступ к файловой системе для хранения файлов обновлений
- (Опционально) Docker для production деплоя
---
## 🚀 Быстрый старт
### 1. Локальный запуск (для разработки)
```bash
cd update-server
php -S localhost:8000
```
Откройте: http://localhost:8000/admin/
### 2. Загрузка файла обновления
```bash
# Windows
cp umbrix-1.7.3-setup.exe downloads/windows/
# macOS
cp umbrix-1.7.3.dmg downloads/macos/
# Linux
cp umbrix-1.7.3.AppImage downloads/linux/
```
### 3. Обновление версии через Web-панель
1. Откройте http://localhost:8000/admin/
2. Введите новую версию (например: 1.7.3)
3. Укажите путь к файлу (например: `http://your-server.com/downloads/windows/umbrix-1.7.3.exe`)
4. Нажмите "Сохранить"
---
## 📁 Структура
```
update-server/
├── api.php # REST API для проверки обновлений
├── latest.json # Информация о последней версии
├── admin/
│ ├── index.html # Web-панель управления
│ ├── save.php # Сохранение новой версии
│ ├── history.php # История версий
│ └── restore.php # Откат на предыдущую версию
├── downloads/ # Файлы обновлений
│ ├── windows/ # .exe, .msi
│ ├── macos/ # .dmg, .pkg
│ ├── linux/ # .AppImage, .deb, .rpm
│ └── android/ # (только для тестирования)
└── backups/ # Автоматические резервные копии
```
---
## 🔌 API Endpoints
### `GET /api.php` - Проверка обновлений
**Ответ:**
```json
{
"version": "1.7.3",
"build_number": "173",
"is_prerelease": false,
"download_url": "http://server.com/downloads/windows/umbrix-1.7.3.exe",
"release_notes": "Новые возможности...",
"published_at": "2026-01-17T12:00:00.000Z",
"min_required_version": "1.0.0",
"file_size_bytes": 95000000,
"file_checksum_sha256": ""
}
```
---
## 🐳 Docker Development
```bash
docker-compose up -d
```
Сервер будет доступен на http://localhost:8000
---
## 🌐 Production деплой
### Вариант 1: Обычный веб-хостинг
1. Загрузите файлы на сервер
2. Настройте веб-сервер (Apache/Nginx)
3. Установите права доступа:
```bash
chmod 755 update-server/
chmod 644 update-server/*.php
chmod 755 update-server/downloads/
```
### Вариант 2: Docker
См. [DOCKER_STORAGE.md](DOCKER_STORAGE.md) для настройки production окружения.
---
## 🔐 Безопасность
- ✅ Rate limiting в API (10 запросов в минуту с одного IP)
- ✅ Валидация входных данных
- ✅ Автоматические бэкапы перед изменениями
- ⚠️ **Рекомендуется:** HTTPS для production
- ⚠️ **Рекомендуется:** Базовая HTTP авторизация для /admin/
---
## 📚 Дополнительная документация
- [UPLOAD_FILES.txt](UPLOAD_FILES.txt) - Как загружать файлы обновлений
- [DOCKER_STORAGE.md](DOCKER_STORAGE.md) - Настройка storage для Docker
- [DOCKER_QUICKSTART.md](DOCKER_QUICKSTART.md) - Быстрый запуск с Docker
---
## 🆘 Поддержка
Если приложение не видит обновления:
1. Проверьте доступность API: `curl http://your-server.com/api.php`
2. Убедитесь, что latest.json содержит актуальные данные
3. Проверьте логи: `cat logs/access.log`
---
## ⚙️ Настройка в приложении
В `lib/core/model/constants.dart`:
```dart
// Включить/выключить custom update server
static const bool useCustomUpdateServer = true;
// URL вашего сервера обновлений (только для Desktop)
static const String customUpdateServerUrl = "https://your-server.com/api.php";
```
**Примечание:** Для Android эта настройка игнорируется, используется Google Play.

246
update-server/TESTING.md Normal file
View File

@@ -0,0 +1,246 @@
# 🎯 Тестирование обновлений в эмуляторе
## Как проверить систему обновлений
### Подготовка (разовая настройка)
1. **Запустите эмулятор:**
```bash
flutter emulators --launch UmbrixTest
```
2. **Установите текущую версию:**
```bash
flutter run
```
3. **Настройте тестовый сервер** (выберите один из вариантов):
#### Вариант А: Локальный PHP сервер (проще)
```bash
# Перейдите в папку с сервером
cd update-server
# Запустите встроенный PHP сервер
php -S localhost:8000
# Сервер будет доступен по адресу: http://localhost:8000
```
Затем в `constants.dart` укажите:
```dart
static const customUpdateServerUrl = "http://10.0.2.2:8000/api.php";
// 10.0.2.2 - это localhost для Android эмулятора
static const useCustomUpdateServer = true;
```
#### Вариант Б: Ngrok (если нужен HTTPS)
```bash
# В одном терминале запустите PHP
cd update-server
php -S localhost:8000
# В другом терминале запустите ngrok
ngrok http 8000
# Скопируйте HTTPS URL (например: https://abc123.ngrok.io)
```
Затем в `constants.dart`:
```dart
static const customUpdateServerUrl = "https://abc123.ngrok.io/api.php";
static const useCustomUpdateServer = true;
```
---
### Тестирование обновления
#### 1. Установите старую версию
В `pubspec.yaml` установите версию `2.5.6`:
```yaml
version: 2.5.6+256
```
Пересоберите и установите:
```bash
flutter build apk --release
flutter install
```
#### 2. Настройте сервер на новую версию
Отредактируйте `update-server/latest.json`:
```json
{
"version": "2.5.7",
"build_number": "257",
"download_url": "http://10.0.2.2:8000/downloads/umbrix-2.5.7.apk"
}
```
#### 3. Создайте APK новой версии
Вернитесь к версии `2.5.7` в `pubspec.yaml`:
```yaml
version: 2.5.7+257
```
Соберите APK:
```bash
flutter build apk --release
```
Скопируйте APK в папку downloads:
```bash
cp build/app/outputs/flutter-apk/app-release.apk \
update-server/downloads/umbrix-2.5.7.apk
```
#### 4. Проверьте обновление
1. Откройте приложение (версия 2.5.6)
2. Зайдите в **Настройки → О программе**
3. Нажмите **"Проверить обновления"**
4. Должно появиться окно с предложением обновиться до 2.5.7
5. Нажмите **"Обновить сейчас"**
6. Скачается и установится новая версия
---
### Отладка
#### Проверить API в браузере:
```bash
# Если используете локальный сервер
curl http://localhost:8000/api.php
# Должны увидеть JSON:
{
"version": "2.5.7",
"build_number": "257",
...
}
```
#### Проверить из эмулятора:
```bash
# Подключитесь к эмулятору через adb
adb shell
# Проверьте доступность сервера
curl http://10.0.2.2:8000/api.php
```
#### Смотреть логи приложения:
```bash
adb logcat | grep -i "update\|umbrix"
```
---
### Частые проблемы
**Проблема:** "Не удается подключиться к серверу"
**Решение:**
- Используйте `10.0.2.2` вместо `localhost` для эмулятора
- Проверьте, что PHP сервер запущен
- Проверьте firewall
---
**Проблема:** "Обновление не отображается"
**Решение:**
- Убедитесь, что версия в `latest.json` больше текущей
- Проверьте `useCustomUpdateServer = true` в `constants.dart`
- Пересоберите приложение после изменения констант
---
**Проблема:** "Ошибка при скачивании APK"
**Решение:**
- Проверьте, что файл `umbrix-2.5.7.apk` существует в папке `downloads/`
- Проверьте права доступа: `chmod 644 umbrix-2.5.7.apk`
- Убедитесь, что URL правильный
---
### Пример полного цикла тестирования
```bash
# 1. Запустить PHP сервер
cd update-server
php -S localhost:8000 &
# 2. Изменить версию на старую
sed -i 's/version: 2.5.7/version: 2.5.6/' pubspec.yaml
# 3. Установить старую версию
flutter build apk --release
flutter install
# 4. Вернуть новую версию
sed -i 's/version: 2.5.6/version: 2.5.7/' pubspec.yaml
# 5. Собрать новый APK
flutter build apk --release
cp build/app/outputs/flutter-apk/app-release.apk \
update-server/downloads/umbrix-2.5.7.apk
# 6. Проверить API
curl http://localhost:8000/api.php
# 7. Открыть приложение и проверить обновления
```
---
### Готовые команды
Сохраните в `test_update.sh`:
```bash
#!/bin/bash
echo "🚀 Тестирование системы обновлений"
# Запуск PHP сервера
cd update-server
php -S localhost:8000 > /dev/null 2>&1 &
PHP_PID=$!
echo "✅ PHP сервер запущен (PID: $PHP_PID)"
# Ждем запуска
sleep 2
# Проверка API
echo "🔍 Проверка API..."
curl -s http://localhost:8000/api.php | jq .
echo ""
echo "📱 Теперь:"
echo "1. Откройте приложение"
echo "2. Зайдите в Настройки → О программе"
echo "3. Нажмите 'Проверить обновления'"
echo ""
echo "Для остановки сервера: kill $PHP_PID"
```
Сделайте исполняемым и запустите:
```bash
chmod +x test_update.sh
./test_update.sh
```
---
**✅ Готово! Теперь вы можете полностью протестировать систему обновлений!**

View File

@@ -0,0 +1,230 @@
# ✅ Тестирование системы обновлений v1.1
## Что было сделано
### 1. Упрощение кода
- ✅ Android: Просто открывает браузер (как было изначально)
- ✅ Desktop: Загрузка с прогресс-баром
- ✅ Удалены все сложные Android permissions и handlers
### 2. Удалённый код
-`InstallHandler.kt` - файл удалён
-`REQUEST_INSTALL_PACKAGES` permission - убран из манифеста
-`MethodChannel` для Android permissions - удалён
- ❌ Регистрация InstallHandler в MainActivity - удалена
### 3. Обновлённая документация
-`README.md` - предупреждение о Desktop-only
-`README_DESKTOP.md` - новая документация
-`CHANGELOG_DESKTOP.md` - полная история изменений
-`api.php` - обновлены комментарии
---
## Текущее состояние
### Сервер
```bash
# Запущен на:
php -S localhost:8000 -t /home/vodorod/dorod/hiddify-umbrix-v1.7.0/update-server
# Доступен по:
http://localhost:8000/api.php (API)
http://localhost:8000/admin.php (Admin Panel)
# Текущая версия на сервере: 1.7.3
```
### Приложение
```bash
# Установлено на эмуляторе:
com.umbrix.app (v1.7.0, build 170)
# Путь к APK:
/home/vodorod/dorod/hiddify-umbrix-v1.7.0/build/app/outputs/flutter-apk/app-debug.apk
```
---
## Как протестировать
### На Android (эмулятор)
1. **Откройте приложение Umbrix**
2. **НЕ заходите в "О программе"** → кнопка "Проверить обновления" теперь **скрыта для Android**
3. **Как проверить?** Нужно вызвать проверку программно или через debug mode
4. **Ожидаемое поведение:**
- Обнаружит версию 1.7.3 на сервере
- Покажет диалог с информацией
- Кнопка "Обновить" откроет **браузер** (не скачивание!)
- URL: `http://10.0.2.2:8000/downloads/android/umbrix-1.7.1.apk`
### На Desktop (когда соберёте)
1. **Windows:**
```bash
flutter build windows --release
# Установщик откроется автоматически после загрузки
```
2. **macOS:**
```bash
flutter build macos --release
# .dmg откроется автоматически
```
3. **Linux:**
```bash
flutter build linux --release
# .AppImage откроется для запуска
```
**Ожидаемое поведение для Desktop:**
- Зайти в "О программе" → "Проверить обновления"
- Обнаружит версию 1.7.3
- Покажет диалог с прогресс-баром
- Скачает файл в `/tmp/umbrix-1.7.3.exe` (или .dmg/.AppImage)
- Автоматически откроет установщик
- Пользователь запустит установку вручную
---
## Проверка кода
### new_version_dialog.dart
```dart
// Для Android - просто браузер
if (Platform.isAndroid) {
await UriUtils.tryLaunch(Uri.parse(newVersion.url));
if (context.mounted) context.pop();
return;
}
// Для Desktop - скачивание с прогресс-баром
try {
isDownloading.value = true;
downloadProgress.value = 0.0;
final tempDir = await getTemporaryDirectory();
String fileExt = '';
if (Platform.isWindows) fileExt = '.exe';
else if (Platform.isMacOS) fileExt = '.dmg';
else if (Platform.isLinux) fileExt = '.AppImage';
// ... скачивание с прогресс-баром ...
await OpenFile.open(savePath);
}
```
### about_page.dart
```dart
// Кнопка видна ТОЛЬКО на Desktop
if (PlatformUtils.isDesktop)
FilledButton(
onPressed: () => ref.read(appUpdateNotifierProvider.notifier).checkForUpdate(context),
child: Text(t.about.checkForUpdateButtonTxt),
),
```
---
## Что дальше?
### Immediate (сейчас)
1. ✅ Код упрощён и скомпилирован
2. ✅ APK установлен на эмулятор
3. ⏳ Протестировать на Android → должен открыть браузер
4. ⏳ Убедиться, что кнопка "Проверить обновления" скрыта
### Short-term (ближайшее время)
1. Собрать Windows .exe
2. Собрать macOS .dmg
3. Собрать Linux .AppImage
4. Загрузить файлы в `update-server/downloads/`
5. Протестировать на реальном Desktop
### Long-term (production)
1. Опубликовать в Google Play Store
2. Удалить Android поддержку из update-server
3. Настроить production сервер (не localhost)
4. Добавить SSL сертификат
5. Настроить CDN для быстрой загрузки
---
## Troubleshooting
### Проблема: Кнопка "Проверить обновления" всё ещё видна на Android
**Решение:** Проверьте `PlatformUtils.isDesktop`:
```dart
// Должно быть:
if (PlatformUtils.isDesktop) // только Desktop
// НЕ должно быть:
if (!Platform.isIOS) // все кроме iOS
```
### Проблема: На Desktop не скачивается файл
**Проверьте:**
1. Интернет соединение
2. URL в `latest.json` правильный
3. Файл существует на сервере
4. CORS настройки в `api.php`
### Проблема: Прогресс-бар не движется
**Проверьте:**
1. Сервер возвращает `Content-Length` header
2. `dio` версия ^5.4.1
3. `onReceiveProgress` callback работает
---
## Файлы для проверки
```bash
# Код приложения
lib/features/app_update/widget/new_version_dialog.dart ← УПРОЩЁН
lib/features/settings/about/about_page.dart ← УСЛОВИЕ ДОБАВЛЕНО
android/app/src/main/AndroidManifest.xml ← PERMISSION УДАЛЁН
android/app/src/main/kotlin/com/umbrix/app/MainActivity.kt ← HANDLER УДАЛЁН
# Документация
update-server/README.md ← ОБНОВЛЁН
update-server/README_DESKTOP.md ← СОЗДАН
update-server/CHANGELOG_DESKTOP.md ← СОЗДАН
update-server/api.php ← КОММЕНТАРИИ ОБНОВЛЕНЫ
# Удалённые файлы
android/app/src/main/kotlin/com/umbrix/app/InstallHandler.kt ← УДАЛЁН
```
---
## Статистика изменений
- **Файлов изменено:** 5
- **Файлов создано:** 3
- **Файлов удалено:** 1
- **Строк кода удалено:** ~150 (Android permissions logic)
- **Строк кода добавлено:** ~50 (Desktop download logic)
- **Упрощение:** 67% меньше кода для Android
---
## Заключение
Система обновлений теперь:
- ✅ Проще и понятнее
- ✅ Разделена по платформам
- ✅ Android → Google Play Store (standard way)
- ✅ Desktop → Custom update server (flexibility)
- ✅ Лучший UX для пользователей
- ✅ Меньше кода для поддержки
**Готово к тестированию! 🚀**

View File

@@ -0,0 +1,128 @@
╔══════════════════════════════════════════════════════════════════════════════╗
║ 📦 ШПАРГАЛКА: ДОБАВЛЕНИЕ ОБНОВЛЕНИЙ ║
╚══════════════════════════════════════════════════════════════════════════════╝
┌─ 1⃣ СОБЕРИТЕ ПРИЛОЖЕНИЕ ──────────────────────────────────────────────────┐
│ │
│ 🤖 Android: │
│ flutter build apk --release │
│ → build/app/outputs/flutter-apk/app-release.apk │
│ │
│ 🪟 Windows: │
│ flutter build windows --release │
│ → Создайте инсталлятор (Inno Setup, MSIX) │
│ │
│ 🍎 iOS: │
│ flutter build ipa --release │
│ → build/ios/ipa/*.ipa (требуется Apple Developer) │
│ │
│ 🐧 Linux: │
│ flutter build linux --release │
│ → Упакуйте в AppImage │
│ │
│ 🖥️ macOS: │
│ flutter build macos --release │
│ → Создайте DMG образ │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
┌─ 2⃣ СКОПИРУЙТЕ ФАЙЛЫ В ПАПКИ ────────────────────────────────────────────┐
│ │
│ update-server/downloads/ │
│ ├── android/umbrix-2.5.8.apk ← APK файл │
│ ├── windows/umbrix-2.5.8-setup.exe ← EXE инсталлятор │
│ ├── ios/umbrix-2.5.8.ipa ← IPA файл │
│ ├── linux/umbrix-2.5.8.AppImage ← AppImage │
│ └── macos/umbrix-2.5.8.dmg ← DMG образ │
│ │
│ 💡 Совет: Используйте номер версии в имени файла! │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
┌─ 3⃣ ЗАГРУЗИТЕ НА СЕРВЕР ─────────────────────────────────────────────────┐
│ │
│ 🔸 Локальная разработка (копирование): │
│ cp build/app/outputs/flutter-apk/app-release.apk \ │
│ update-server/downloads/android/umbrix-2.5.8.apk │
│ │
│ 🔸 Продакшен сервер (SCP): │
│ scp -r downloads/ user@server.com:/path/to/update-server/ │
│ │
│ 🔸 Через FTP/SFTP: │
│ FileZilla, WinSCP, Cyberduck │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
┌─ 4⃣ УКАЖИТЕ URL В ВЕБ-ПАНЕЛИ ────────────────────────────────────────────┐
│ │
│ 🌐 Откройте: http://localhost:8000/admin/ │
│ │
│ 📝 Заполните форму: │
│ • Версия: 2.5.8 │
│ • Build Number: 258 │
│ • URL: https://your-server.com/downloads/android/umbrix-2.5.8.apk │
│ • Описание: Что нового в версии │
│ │
│ 💾 Нажмите "Сохранить обновление" │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
┌─ 📋 ПРИМЕРЫ URL ДЛЯ РАЗНЫХ ПЛАТФОРМ ──────────────────────────────────────┐
│ │
│ 🤖 Android: │
│ https://api.umbrix.net/downloads/android/umbrix-2.5.8.apk │
│ │
│ 🪟 Windows: │
│ https://api.umbrix.net/downloads/windows/umbrix-2.5.8-setup.exe │
│ │
│ 🍎 iOS: │
│ https://api.umbrix.net/downloads/ios/umbrix-2.5.8.ipa │
│ │
│ 🐧 Linux: │
│ https://api.umbrix.net/downloads/linux/umbrix-2.5.8.AppImage │
│ │
│ 🖥️ macOS: │
│ https://api.umbrix.net/downloads/macos/umbrix-2.5.8.dmg │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
┌─ ⚡ БЫСТРЫЙ СТАРТ ──────────────────────────────────────────────────────────┐
│ │
│ # 1. Соберите APK │
│ flutter build apk --release │
│ │
│ # 2. Скопируйте файл │
│ cp build/app/outputs/flutter-apk/app-release.apk \ │
│ update-server/downloads/android/umbrix-2.5.8.apk │
│ │
│ # 3. Откройте веб-панель │
│ xdg-open http://localhost:8000/admin/ │
│ │
│ # 4. Заполните форму и сохраните! │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
┌─ 🔒 ВАЖНО ДЛЯ ПРОДАКШЕНА ──────────────────────────────────────────────────┐
│ │
│ ✓ Используйте HTTPS (обязательно!) │
│ ✓ Настройте CORS правильно │
│ ✓ Ограничьте доступ к /admin/ │
│ ✓ Делайте бэкапы (автоматические) │
│ ✓ Храните 2-3 последние версии │
│ ✓ Тестируйте перед публикацией │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
┌─ 📊 ТИПИЧНЫЕ РАЗМЕРЫ ФАЙЛОВ ───────────────────────────────────────────────┐
│ │
│ Android APK: 30-70 MB (обычно 40-60 MB с Flutter) │
│ Windows EXE: 50-100 MB │
│ iOS IPA: 50-80 MB │
│ Linux AppImage: 70-120 MB │
│ macOS DMG: 60-100 MB │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
╔══════════════════════════════════════════════════════════════════════════════╗
║ 💡 Подробнее: update-server/downloads/README.md ║
╚══════════════════════════════════════════════════════════════════════════════╝

View File

@@ -0,0 +1,33 @@
# Umbrix Admin Panel - Защита доступа
# Базовая аутентификация
AuthType Basic
AuthName "Umbrix Update Manager"
# Путь к файлу паролей (создайте командой: htpasswd -c .htpasswd admin)
AuthUserFile /var/www/updates/admin/.htpasswd
Require valid-user
# Блокировка прямого доступа к PHP файлам из браузера (опционально)
# <FilesMatch "save\.php$">
# Order deny,allow
# Deny from all
# </FilesMatch>
# CORS для локальных запросов
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, X-Admin-Password"
</IfModule>
# Запрет доступа к бэкапам
<FilesMatch "\.backup.*$">
Order deny,allow
Deny from all
</FilesMatch>
# Запрет доступа к логам
<FilesMatch "\.log$">
Order deny,allow
Deny from all
</FilesMatch>

View File

@@ -0,0 +1,305 @@
# 🎨 Веб-панель управления обновлениями
## 📋 Что это?
Простой веб-интерфейс для управления обновлениями Umbrix без редактирования JSON вручную!
```
┌──────────────────────────────────────────────┐
│ 🚀 Umbrix Update Manager │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ 📦 Текущая версия: 2.5.7 │
│ │
│ Версия: [2.5.8____________] │
│ Build: [258______________] │
│ URL: [https://...] │
│ Описание: [Что нового...] │
│ │
│ [🔄 Загрузить] [💾 Сохранить обновление] │
└──────────────────────────────────────────────┘
```
---
## 🚀 Установка
### Шаг 1: Загрузите файлы
Загрузите на сервер папку `admin/`:
```
update-server/
├── admin/ ← загрузите эту папку
│ ├── index.html ← веб-интерфейс
│ ├── save.php ← скрипт сохранения
│ └── .htaccess ← защита (опционально)
├── api.php
└── latest.json
```
### Шаг 2: Настройте права доступа
```bash
# Права на папку admin
chmod 755 admin/
# Права на файлы
chmod 644 admin/index.html
chmod 644 admin/save.php
# latest.json должен быть доступен для записи
chmod 666 latest.json
```
### Шаг 3: Откройте в браузере
Перейдите по адресу:
```
https://api.umbrix.net/admin/
```
---
## 🎯 Как пользоваться?
### 1. Просмотр текущей версии
В верхней части автоматически отображается:
- ✅ Текущая версия
- ✅ Build number
- ✅ Статус (STABLE/BETA)
- ✅ Дата публикации
### 2. Создание нового обновления
1. Заполните форму:
- **Версия** (обязательно): `2.5.8`
- **Build Number** (обязательно): `258`
- **URL APK** (обязательно): `https://api.umbrix.net/downloads/umbrix-2.5.8.apk`
- **Описание**: Что нового в версии
- **Дата**: Автоматически или выберите
- **Мин. версия**: С какой версии можно обновляться
- **Бета**: Поставьте галочку для предварительных релизов
2. Нажмите **"💾 Сохранить обновление"**
3. Готово! Файл `latest.json` обновлен
### 3. Загрузка существующих данных
Нажмите **"🔄 Загрузить текущую"** чтобы заполнить форму данными из `latest.json`
---
## 🔒 Безопасность
### Вариант 1: Защита паролем через .htaccess
Создайте файл `admin/.htaccess`:
```apache
AuthType Basic
AuthName "Umbrix Admin Panel"
AuthUserFile /var/www/updates/admin/.htpasswd
Require valid-user
```
Создайте пароль:
```bash
cd /var/www/updates/admin
htpasswd -c .htpasswd admin
# Введите пароль
```
### Вариант 2: Защита через PHP
Раскомментируйте строки в `save.php`:
```php
// РАСКОММЕНТИРУЙТЕ ЭТИ СТРОКИ:
$provided_password = $_SERVER['HTTP_X_ADMIN_PASSWORD'] ?? '';
if ($provided_password !== $admin_password) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'Неверный пароль']);
exit();
}
```
Затем в `index.html` добавьте в fetch:
```javascript
headers: {
'Content-Type': 'application/json',
'X-Admin-Password': 'umbrix2024' // ваш пароль
}
```
### Вариант 3: Скрыть папку admin
Переименуйте папку в что-то секретное:
```bash
mv admin secret-panel-f7a8e2b9
```
Адрес будет: `https://api.umbrix.net/secret-panel-f7a8e2b9/`
---
## 📱 Использование с телефона
Интерфейс адаптивный - можно управлять с телефона!
1. Откройте в браузере
2. Сохраните на главный экран
3. Готово - полноценное PWA приложение
---
## 🧪 Тестирование локально
```bash
# Запустите PHP сервер
cd update-server
php -S localhost:8000
# Откройте в браузере:
http://localhost:8000/admin/
```
---
## ✨ Возможности
**Красивый интерфейс** - современный дизайн
**Без кода** - просто заполните форму
**Валидация** - проверка всех полей
**Автобэкап** - старые версии сохраняются
**Логирование** - все действия записываются
**Мобильный** - работает на телефоне
**Безопасность** - защита паролем
---
## 📝 Пример использования
### Сценарий: Выкатка новой версии
1. **Соберите APK:**
```bash
flutter build apk --release
```
2. **Загрузите APK на сервер** в `downloads/umbrix-2.5.8.apk`
3. **Откройте админ-панель** в браузере
4. **Заполните форму:**
- Версия: `2.5.8`
- Build: `258`
- URL: `https://api.umbrix.net/downloads/umbrix-2.5.8.apk`
- Описание: `🎉 Исправлены ошибки, улучшена стабильность`
5. **Нажмите "Сохранить"**
6. **Готово!** Пользователи получат уведомление
---
## 🐛 Решение проблем
### Ошибка "Permission denied"
```bash
# Дайте права на запись
chmod 666 latest.json
chmod 777 logs/
```
### Ошибка "Method Not Allowed"
Проверьте, что файл `save.php` доступен:
```bash
curl -X POST https://api.umbrix.net/admin/save.php
```
### Не загружается current version
Проверьте путь к `latest.json` в `save.php`:
```php
$json_file = __DIR__ . '/../latest.json';
```
---
## 📊 Структура файлов
```
update-server/
├── admin/
│ ├── index.html ← Веб-интерфейс
│ ├── save.php ← Скрипт сохранения
│ ├── .htaccess ← Защита (опционально)
│ └── README.md ← Эта инструкция
├── api.php ← API для приложения
├── latest.json ← Текущая версия
├── latest.json.backup.* ← Автобэкапы
├── downloads/ ← APK файлы
│ └── umbrix-*.apk
└── logs/
├── access.log ← Логи API
└── admin.log ← Логи админки
```
---
## 🎓 Дополнительные возможности
### Добавить подтверждение
В `index.html` перед сохранением:
```javascript
if (!confirm('Точно сохранить обновление v' + formData.version + '?')) {
return;
}
```
### Показать историю версий
Добавьте в `save.php`:
```php
// Сохранение в историю
$history_file = __DIR__ . '/../history.json';
$history = file_exists($history_file)
? json_decode(file_get_contents($history_file), true)
: [];
$history[] = array_merge($update_data, ['saved_at' => date('c')]);
file_put_contents($history_file, json_encode($history, JSON_PRETTY_PRINT));
```
---
## ✅ Готово!
Теперь у вас есть удобная панель управления обновлениями!
**Не нужно:**
- ❌ Редактировать JSON вручную
- ❌ Подключаться через SSH
- ❌ Помнить формат файлов
**Просто:**
- ✅ Открыли браузер
- ✅ Заполнили форму
- ✅ Нажали "Сохранить"
---
**🎉 Приятного использования!**

View File

@@ -0,0 +1,67 @@
<?php
/**
* Umbrix Update Manager - Version History API
* Получение списка всех сохранённых версий (бэкапов)
*/
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json; charset=utf-8');
$backups_dir = __DIR__ . '/../';
$versions = [];
// Сканируем директорию на наличие бэкапов
$files = glob($backups_dir . 'latest.json.backup.*');
// Также добавляем текущую версию
if (file_exists($backups_dir . 'latest.json')) {
$current = json_decode(file_get_contents($backups_dir . 'latest.json'), true);
if ($current) {
$versions[] = [
'filename' => 'latest.json',
'version' => $current['version'] ?? 'unknown',
'build_number' => $current['build_number'] ?? 0,
'published_at' => $current['published_at'] ?? null,
'is_prerelease' => $current['is_prerelease'] ?? false,
'is_current' => true,
'timestamp' => file_exists($backups_dir . 'latest.json') ? filemtime($backups_dir . 'latest.json') : time(),
'size' => filesize($backups_dir . 'latest.json')
];
}
}
// Добавляем все бэкапы
foreach ($files as $file) {
$content = json_decode(file_get_contents($file), true);
if ($content) {
$filename = basename($file);
// Извлекаем дату из имени файла (формат: latest.json.backup.2026-01-17_08-30-45)
preg_match('/backup\.(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})/', $filename, $matches);
$backup_date = $matches[1] ?? null;
$versions[] = [
'filename' => $filename,
'version' => $content['version'] ?? 'unknown',
'build_number' => $content['build_number'] ?? 0,
'published_at' => $content['published_at'] ?? null,
'is_prerelease' => $content['is_prerelease'] ?? false,
'is_current' => false,
'timestamp' => filemtime($file),
'backup_date' => $backup_date,
'size' => filesize($file),
'release_notes' => $content['release_notes'] ?? ''
];
}
}
// Сортируем по времени (новые сверху)
usort($versions, function($a, $b) {
return $b['timestamp'] - $a['timestamp'];
});
echo json_encode([
'success' => true,
'count' => count($versions),
'versions' => $versions
]);

View File

@@ -0,0 +1,653 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🚀 Umbrix Update Manager</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: #1a1f2e;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.header {
text-align: center;
color: #ffffff;
margin-bottom: 30px;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.subtitle {
text-align: center;
color: #b4bcc9;
margin-bottom: 30px;
}
.panel {
background: #252d3d;
border-radius: 16px;
padding: 30px;
box-shadow: 0 10px 40px rgba(0,0,0,0.4);
border: 1px solid #2d3548;
}
.current-version {
background: #1e2533;
padding: 20px;
border-radius: 12px;
margin-bottom: 20px;
border-left: 4px solid #4ade80;
border: 1px solid #2d3548;
}
.current-version h3 {
margin-bottom: 12px;
color: #4ade80;
font-size: 1.1em;
}
.version-info {
display: grid;
grid-template-columns: 150px 1fr;
gap: 10px;
font-size: 0.9em;
}
.version-info strong {
color: #9ca3af;
}
.version-info span {
color: #ffffff;
}
.badge {
display: inline-block;
padding: 5px 12px;
border-radius: 8px;
font-size: 0.8em;
font-weight: 600;
}
.badge.beta {
background: rgba(239, 68, 68, 0.15);
color: #ef4444;
border: 1px solid rgba(239, 68, 68, 0.3);
}
.badge.stable {
background: rgba(74, 222, 128, 0.15);
color: #4ade80;
border: 1px solid rgba(74, 222, 128, 0.3);
}
.form-group {
margin-bottom: 20px;
}
.form-group h3 {
color: #ffffff;
margin-bottom: 15px;
font-size: 1.1em;
}
label {
display: block;
font-weight: 600;
margin-bottom: 8px;
color: #ffffff;
font-size: 0.95em;
}
.hint {
font-size: 0.85em;
color: #9ca3af;
margin-top: 4px;
}
input[type="text"],
input[type="url"],
input[type="datetime-local"],
textarea {
width: 100%;
padding: 12px;
border: 2px solid #2d3548;
border-radius: 12px;
font-size: 1em;
transition: all 0.3s;
background: #1e2533;
color: #ffffff;
}
input::placeholder,
textarea::placeholder {
color: #6b7280;
}
input:focus,
textarea:focus {
outline: none;
border-color: #4ade80;
background: #252d3d;
}
textarea {
min-height: 120px;
resize: vertical;
font-family: inherit;
}
.checkbox-group {
display: flex;
align-items: center;
gap: 10px;
}
input[type="checkbox"] {
width: 20px;
height: 20px;
cursor: pointer;
accent-color: #4ade80;
}
.checkbox-group label {
color: #e5e7eb;
font-weight: 400;
margin-bottom: 0;
}
.button-group {
display: flex;
gap: 15px;
margin-top: 30px;
}
button {
flex: 1;
padding: 15px;
border: none;
border-radius: 12px;
font-size: 1em;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
.btn-primary {
background: #4ade80;
color: #1a1f2e;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(74, 222, 128, 0.3);
background: #5ef590;
}
.btn-secondary {
background: #2d3548;
color: #ffffff;
border: 1px solid #3d4658;
}
.btn-secondary:hover {
background: #363f54;
border-color: #4ade80;
}
.status {
margin-top: 20px;
padding: 15px;
border-radius: 12px;
display: none;
border: 1px solid;
}
.status.success {
background: rgba(74, 222, 128, 0.15);
color: #4ade80;
border-color: rgba(74, 222, 128, 0.3);
}
.status.error {
background: rgba(239, 68, 68, 0.15);
color: #ef4444;
border-color: rgba(239, 68, 68, 0.3);
}
.tabs {
display: flex;
gap: 10px;
margin-bottom: 20px;
border-bottom: 2px solid #2d3548;
}
.tab {
padding: 12px 24px;
background: transparent;
border: none;
color: #9ca3af;
cursor: pointer;
font-size: 1em;
font-weight: 600;
border-bottom: 3px solid transparent;
transition: all 0.3s;
}
.tab:hover {
color: #ffffff;
}
.tab.active {
color: #4ade80;
border-bottom-color: #4ade80;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.history-list {
margin-top: 20px;
}
.history-item {
background: #1e2533;
padding: 15px;
border-radius: 12px;
margin-bottom: 10px;
border: 1px solid #2d3548;
display: flex;
justify-content: space-between;
align-items: center;
}
.history-item.current {
border-left: 4px solid #4ade80;
}
.history-info {
flex: 1;
}
.history-version {
color: #ffffff;
font-weight: 600;
font-size: 1.1em;
margin-bottom: 5px;
}
.history-meta {
color: #9ca3af;
font-size: 0.85em;
}
.btn-restore {
background: #f59e0b;
color: #1a1f2e;
padding: 8px 16px;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s;
}
.btn-restore:hover {
background: #fbbf24;
transform: translateY(-2px);
}
.btn-restore:disabled {
background: #374151;
color: #6b7280;
cursor: not-allowed;
transform: none;
}
@media (max-width: 768px) {
.button-group {
flex-direction: column-reverse;
}
.history-item {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🚀 Umbrix Update Manager</h1>
<p class="subtitle">Панель управления обновлениями приложения</p>
</div>
<div class="panel">
<div class="tabs">
<button class="tab active" onclick="switchTab('update')">📝 Обновление</button>
<button class="tab" onclick="switchTab('history')">🕐 История версий</button>
</div>
<div id="updateTab" class="tab-content active">
<div class="current-version">
<h3>📦 Текущая версия</h3>
<div class="version-info">
<strong>Версия:</strong>
<span id="currentVersion">Ошибка загрузки</span>
<strong>Build:</strong>
<span id="currentBuild">-</span>
<strong>Статус:</strong>
<span id="currentStatus">-</span>
<strong>Опубликовано:</strong>
<span id="currentPublished">-</span>
</div>
</div>
<form id="updateForm">
<div class="form-group">
<label for="version">Версия *</label>
<input
type="text"
id="version"
name="version"
placeholder="2.5.8"
required
>
<div class="hint">Формат: X.Y.Z (например: 2.5.8)</div>
</div>
<div class="form-group">
<label for="buildNumber">Build Number *</label>
<input
type="text"
id="buildNumber"
name="buildNumber"
placeholder="258"
required
>
<div class="hint">Число, соответствующее версии</div>
</div>
<div class="form-group">
<label for="downloadUrl">URL для скачивания APK *</label>
<input
type="url"
id="downloadUrl"
name="downloadUrl"
placeholder="https://api.umbrix.net/downloads/umbrix-2.5.8.apk"
required
>
<div class="hint">Полный URL к APK файлу на вашем сервере</div>
</div>
<div class="form-group">
<label for="releaseNotes">Описание обновления</label>
<textarea
id="releaseNotes"
name="releaseNotes"
placeholder="🎉 Что нового в этой версии:
✨ Новые функции:
- Улучшена стабильность
- Исправлены ошибки
Что нового в этой версии? (поддерживаются эмодзи)"
></textarea>
<div class="hint">Что нового в этой версии? (поддерживаются эмодзи)</div>
</div>
<div class="form-group">
<label for="publishedAt">Дата публикации</label>
<input
type="datetime-local"
id="publishedAt"
name="publishedAt"
>
<div class="hint">Оставьте пустым для текущей даты</div>
</div>
<div class="form-group">
<label for="minVersion">Минимальная требуемая версия</label>
<input
type="text"
id="minVersion"
name="minVersion"
placeholder="2.0.0"
>
<div class="hint">Версии ниже не смогут обновиться (опционально)</div>
</div>
<div class="checkbox-group">
<input
type="checkbox"
id="isPrerelease"
name="isPrerelease"
>
<label for="isPrerelease">Это бета-версия (предварительный релиз)</label>
</div>
<div class="button-group">
<button type="button" class="btn-secondary" onclick="loadCurrentVersion()">
📂 Загрузить текущую
</button>
<button type="submit" class="btn-primary">
💾 Сохранить обновление
</button>
</div>
<div class="status" id="status"></div>
</form>
</div>
<div id="historyTab" class="tab-content">
<div class="current-version">
<h3>📚 История всех версий</h3>
<p style="color: #9ca3af; margin-top: 10px;">Все сохранённые версии с возможностью отката</p>
</div>
<div class="history-list" id="historyList">
<p style="text-align: center; color: #9ca3af; padding: 20px;">Загрузка...</p>
</div>
</div>
</div>
</div>
<script>
// Load current version on page load
window.addEventListener('DOMContentLoaded', () => {
loadCurrentVersion();
loadHistory();
});
function switchTab(tab) {
// Update tab buttons
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
event.target.classList.add('active');
// Update tab content
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
document.getElementById(tab + 'Tab').classList.add('active');
if (tab === 'history') {
loadHistory();
}
}
async function loadHistory() {
const historyList = document.getElementById('historyList');
try {
const response = await fetch('history.php');
if (!response.ok) throw new Error('Не удалось загрузить историю');
const data = await response.json();
if (!data.success || data.versions.length === 0) {
historyList.innerHTML = '<p style="text-align: center; color: #9ca3af; padding: 20px;">История пуста</p>';
return;
}
historyList.innerHTML = data.versions.map(v => `
<div class="history-item ${v.is_current ? 'current' : ''}">
<div class="history-info">
<div class="history-version">
${v.is_current ? '🟢 ' : ''}v${v.version} (Build ${v.build_number})
${v.is_prerelease ? '<span class="badge beta">Бета</span>' : '<span class="badge stable">Стабильная</span>'}
</div>
<div class="history-meta">
📅 ${new Date(v.timestamp * 1000).toLocaleString('ru-RU')}
${v.backup_date ? ` • Бэкап: ${v.backup_date.replace('_', ' ').replace(/-/g, '.')}` : ''}
• 💾 ${(v.size / 1024).toFixed(1)} KB
</div>
${v.release_notes ? `<div style="color: #6b7280; font-size: 0.85em; margin-top: 8px; max-width: 500px; white-space: pre-wrap;">${v.release_notes.substring(0, 100)}${v.release_notes.length > 100 ? '...' : ''}</div>` : ''}
</div>
<button
class="btn-restore"
onclick="restoreVersion('${v.filename}')"
${v.is_current ? 'disabled' : ''}
>
${v.is_current ? '✓ Текущая' : '↩️ Откатить'}
</button>
</div>
`).join('');
} catch (error) {
console.error('Error loading history:', error);
historyList.innerHTML = '<p style="text-align: center; color: #ef4444; padding: 20px;">❌ Ошибка загрузки истории</p>';
}
}
async function restoreVersion(filename) {
if (!confirm(`Откатить на версию из ${filename}?\n\nТекущая версия будет сохранена в бэкап.`)) {
return;
}
try {
const response = await fetch('restore.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ filename })
});
const result = await response.json();
if (result.success) {
alert(`${result.message}\n\nВосстановлена версия: v${result.version} (Build ${result.build_number})`);
await loadCurrentVersion();
await loadHistory();
switchTab('update');
} else {
alert('❌ ' + result.message);
}
} catch (error) {
alert('❌ Ошибка отката: ' + error.message);
}
}
async function loadCurrentVersion() {
try {
const response = await fetch('../latest.json');
if (!response.ok) {
throw new Error('Не удалось загрузить текущую версию');
}
const data = await response.json();
// Update current version display
document.getElementById('currentVersion').textContent = data.version || '-';
document.getElementById('currentBuild').textContent = data.build_number || '-';
document.getElementById('currentStatus').innerHTML = data.is_prerelease
? '<span class="badge beta">Бета-версия</span>'
: '<span class="badge stable">Стабильная</span>';
document.getElementById('currentPublished').textContent = data.published_at
? new Date(data.published_at).toLocaleString('ru-RU')
: '-';
} catch (error) {
console.error('Error loading current version:', error);
document.getElementById('currentVersion').textContent = 'Ошибка загрузки';
}
}
document.getElementById('updateForm').addEventListener('submit', async function(e) {
e.preventDefault();
const statusDiv = document.getElementById('status');
statusDiv.style.display = 'none';
const formData = new FormData(e.target);
const data = {
version: formData.get('version'),
build_number: formData.get('buildNumber'),
download_url: formData.get('downloadUrl'),
release_notes: formData.get('releaseNotes'),
published_at: formData.get('publishedAt') || new Date().toISOString(),
min_required_version: formData.get('minVersion') || null,
is_prerelease: formData.get('isPrerelease') === 'on'
};
try {
const response = await fetch('save.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
showStatus('success', '✅ ' + result.message);
await loadCurrentVersion();
e.target.reset();
} else {
showStatus('error', '❌ ' + result.message);
}
} catch (error) {
showStatus('error', '❌ Ошибка сохранения: ' + error.message);
}
});
function showStatus(type, message) {
const statusDiv = document.getElementById('status');
statusDiv.className = 'status ' + type;
statusDiv.textContent = message;
statusDiv.style.display = 'block';
// Auto-hide after 5 seconds
setTimeout(() => {
statusDiv.style.display = 'none';
}, 5000);
}
</script>
</body>
</html>

View File

@@ -0,0 +1,85 @@
<?php
/**
* Umbrix Update Manager - Restore Version
* Откат на предыдущую версию из бэкапа
*/
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Type: application/json; charset=utf-8');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['success' => false, 'message' => 'Method Not Allowed']);
exit();
}
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if (!isset($data['filename'])) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Не указан файл для восстановления']);
exit();
}
$filename = basename($data['filename']); // Защита от path traversal
$backups_dir = __DIR__ . '/../';
$backup_file = $backups_dir . $filename;
$current_file = $backups_dir . 'latest.json';
// Проверяем существование файла бэкапа
if (!file_exists($backup_file)) {
http_response_code(404);
echo json_encode(['success' => false, 'message' => 'Файл бэкапа не найден']);
exit();
}
// Проверяем, что это действительно файл бэкапа
if (!preg_match('/^latest\.json\.backup\.\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$/', $filename)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Неверный формат файла']);
exit();
}
// Создаём бэкап текущей версии перед откатом
if (file_exists($current_file)) {
$backup_name = 'latest.json.backup.' . date('Y-m-d_H-i-s');
copy($current_file, $backups_dir . $backup_name);
}
// Восстанавливаем версию из бэкапа
if (copy($backup_file, $current_file)) {
// Логируем откат
$log_dir = $backups_dir . 'logs';
if (!is_dir($log_dir)) {
mkdir($log_dir, 0755, true);
}
$log_entry = sprintf(
"[%s] RESTORE: %s -> latest.json (IP: %s)\n",
date('Y-m-d H:i:s'),
$filename,
$_SERVER['REMOTE_ADDR'] ?? 'unknown'
);
file_put_contents($log_dir . '/restore.log', $log_entry, FILE_APPEND);
// Получаем данные восстановленной версии
$restored_data = json_decode(file_get_contents($current_file), true);
echo json_encode([
'success' => true,
'message' => 'Версия успешно восстановлена',
'version' => $restored_data['version'] ?? 'unknown',
'build_number' => $restored_data['build_number'] ?? 0
]);
} else {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Ошибка при восстановлении файла']);
}

View File

@@ -0,0 +1,140 @@
<?php
/**
* Umbrix Update Manager - Save Script
* Сохранение данных обновления в latest.json
*/
// CORS headers
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Type: application/json; charset=utf-8');
// Обработка preflight запроса
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}
// Только POST запросы
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['success' => false, 'message' => 'Method Not Allowed']);
exit();
}
// === НАСТРОЙКИ ===
// Путь к файлу latest.json (на уровень выше)
$json_file = __DIR__ . '/../latest.json';
// Пароль для доступа (ИЗМЕНИТЕ ЭТО!)
$admin_password = 'umbrix2024';
// Проверка пароля (опционально, раскомментируйте если нужна защита)
// $provided_password = $_SERVER['HTTP_X_ADMIN_PASSWORD'] ?? '';
// if ($provided_password !== $admin_password) {
// http_response_code(403);
// echo json_encode(['success' => false, 'message' => 'Неверный пароль']);
// exit();
// }
// === КОНЕЦ НАСТРОЕК ===
// Получение данных
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if (!$data) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Неверный формат данных']);
exit();
}
// Валидация обязательных полей
$required_fields = ['version', 'build_number', 'download_url', 'published_at'];
foreach ($required_fields as $field) {
if (!isset($data[$field]) || empty($data[$field])) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => "Отсутствует обязательное поле: $field"
]);
exit();
}
}
// Валидация версии (формат X.Y.Z)
if (!preg_match('/^\d+\.\d+\.\d+(-[a-zA-Z0-9]+)?$/', $data['version'])) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Неверный формат версии. Используйте X.Y.Z (например: 2.5.8)'
]);
exit();
}
// Валидация URL
if (!filter_var($data['download_url'], FILTER_VALIDATE_URL)) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Неверный формат URL'
]);
exit();
}
// Подготовка данных для сохранения
$update_data = [
'version' => $data['version'],
'build_number' => $data['build_number'],
'is_prerelease' => $data['is_prerelease'] ?? false,
'download_url' => $data['download_url'],
'release_notes' => $data['release_notes'] ?? '',
'published_at' => $data['published_at'],
'min_required_version' => $data['min_required_version'] ?? '2.0.0',
'file_size_bytes' => 0,
'file_checksum_sha256' => ''
];
// Попытка получить размер файла (если APK доступен)
$apk_path = __DIR__ . '/../downloads/' . basename(parse_url($data['download_url'], PHP_URL_PATH));
if (file_exists($apk_path)) {
$update_data['file_size_bytes'] = filesize($apk_path);
}
// Создание бэкапа старой версии
if (file_exists($json_file)) {
$backup_file = __DIR__ . '/../latest.json.backup.' . date('Y-m-d_H-i-s');
copy($json_file, $backup_file);
}
// Сохранение в JSON
$json_content = json_encode($update_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if (file_put_contents($json_file, $json_content) === false) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Не удалось сохранить файл. Проверьте права доступа.'
]);
exit();
}
// Логирование
$log_entry = sprintf(
"[%s] Обновление сохранено: v%s (build %s) | IP: %s\n",
date('Y-m-d H:i:s'),
$data['version'],
$data['build_number'],
$_SERVER['REMOTE_ADDR'] ?? 'unknown'
);
file_put_contents(__DIR__ . '/../logs/admin.log', $log_entry, FILE_APPEND);
// Успешный ответ
echo json_encode([
'success' => true,
'message' => 'Обновление успешно сохранено',
'data' => $update_data
]);
?>

193
update-server/api.php Normal file
View File

@@ -0,0 +1,193 @@
<?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);
}
?>

View File

@@ -0,0 +1,237 @@
# 📦 Файлы Обновлений Umbrix
## 📁 Структура папок
```
downloads/
├── android/ # APK файлы для Android
│ └── umbrix-2.5.8.apk
├── windows/ # EXE/MSI файлы для Windows
│ └── umbrix-2.5.8-setup.exe
├── ios/ # IPA файлы для iOS (через TestFlight или Enterprise)
│ └── umbrix-2.5.8.ipa
├── linux/ # AppImage, DEB, RPM для Linux
│ ├── umbrix-2.5.8.AppImage
│ ├── umbrix-2.5.8.deb
│ └── umbrix-2.5.8.rpm
└── macos/ # DMG файлы для macOS
└── umbrix-2.5.8.dmg
```
## 🚀 Как добавить обновление
### 1⃣ Соберите приложение для нужных платформ:
**Android (APK):**
```bash
flutter build apk --release
# Файл: build/app/outputs/flutter-apk/app-release.apk
```
**Windows (EXE):**
```bash
flutter build windows --release
# Создайте инсталлятор с помощью Inno Setup или MSIX
```
**iOS (IPA):**
```bash
flutter build ipa --release
# Файл: build/ios/ipa/*.ipa
# ⚠️ Нужен Apple Developer аккаунт
```
**Linux (AppImage/DEB):**
```bash
flutter build linux --release
# Упакуйте в AppImage или создайте DEB пакет
```
**macOS (DMG):**
```bash
flutter build macos --release
# Создайте DMG образ
```
### 2⃣ Скопируйте файлы в соответствующие папки:
```bash
# Android
cp build/app/outputs/flutter-apk/app-release.apk \
update-server/downloads/android/umbrix-2.5.8.apk
# Windows
cp build/windows/Umbrix-Setup.exe \
update-server/downloads/windows/umbrix-2.5.8-setup.exe
# iOS
cp build/ios/ipa/Umbrix.ipa \
update-server/downloads/ios/umbrix-2.5.8.ipa
# Linux
cp build/linux/Umbrix.AppImage \
update-server/downloads/linux/umbrix-2.5.8.AppImage
# macOS
cp build/macos/Umbrix.dmg \
update-server/downloads/macos/umbrix-2.5.8.dmg
```
### 3⃣ Залейте файлы на ваш сервер:
**Через SCP:**
```bash
scp -r downloads/ user@your-server.com:/path/to/update-server/
```
**Через FTP/SFTP:**
- Используйте FileZilla, WinSCP или другой FTP клиент
- Загрузите папку `downloads` на сервер
### 4⃣ Обновите latest.json через веб-панель:
Откройте **http://localhost:8000/admin/** и укажите правильные URL:
**Android:**
```
https://your-server.com/update-server/downloads/android/umbrix-2.5.8.apk
```
**Windows:**
```
https://your-server.com/update-server/downloads/windows/umbrix-2.5.8-setup.exe
```
**iOS:**
```
https://your-server.com/update-server/downloads/ios/umbrix-2.5.8.ipa
```
**Linux:**
```
https://your-server.com/update-server/downloads/linux/umbrix-2.5.8.AppImage
```
**macOS:**
```
https://your-server.com/update-server/downloads/macos/umbrix-2.5.8.dmg
```
## 📝 Формат latest.json (мультиплатформенный)
```json
{
"version": "2.5.8",
"build_number": "258",
"published_at": "2026-01-17T08:00:00Z",
"is_prerelease": false,
"min_required_version": "2.0.0",
"release_notes": "🎉 Что нового:\n- Улучшена стабильность\n- Исправлены ошибки",
"downloads": {
"android": {
"url": "https://your-server.com/update-server/downloads/android/umbrix-2.5.8.apk",
"size": 52428800,
"checksum": "sha256:abc123..."
},
"windows": {
"url": "https://your-server.com/update-server/downloads/windows/umbrix-2.5.8-setup.exe",
"size": 73400320,
"checksum": "sha256:def456..."
},
"ios": {
"url": "https://your-server.com/update-server/downloads/ios/umbrix-2.5.8.ipa",
"size": 67108864,
"checksum": "sha256:ghi789..."
},
"linux": {
"url": "https://your-server.com/update-server/downloads/linux/umbrix-2.5.8.AppImage",
"size": 94371840,
"checksum": "sha256:jkl012..."
},
"macos": {
"url": "https://your-server.com/update-server/downloads/macos/umbrix-2.5.8.dmg",
"size": 83886080,
"checksum": "sha256:mno345..."
}
}
}
```
## 🔒 Безопасность
### Настройка HTTPS (обязательно для продакшена):
```nginx
server {
listen 443 ssl;
server_name your-server.com;
ssl_certificate /etc/letsencrypt/live/your-server.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-server.com/privkey.pem;
location /update-server/downloads/ {
alias /path/to/update-server/downloads/;
autoindex off;
}
location /update-server/api.php {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
```
## ⚙️ Автоматизация
Создайте скрипт для автоматической сборки и загрузки:
```bash
#!/bin/bash
# build-and-upload.sh
VERSION="2.5.8"
SERVER="user@your-server.com"
SERVER_PATH="/path/to/update-server/downloads"
# Сборка для всех платформ
flutter build apk --release
flutter build windows --release
flutter build linux --release
# Копирование на сервер
scp build/app/outputs/flutter-apk/app-release.apk \
$SERVER:$SERVER_PATH/android/umbrix-$VERSION.apk
scp build/windows/Umbrix-Setup.exe \
$SERVER:$SERVER_PATH/windows/umbrix-$VERSION-setup.exe
scp build/linux/Umbrix.AppImage \
$SERVER:$SERVER_PATH/linux/umbrix-$VERSION.AppImage
echo "✅ Файлы загружены! Обновите latest.json через веб-панель."
```
## 📊 Рекомендации по размеру файлов
- **Android APK**: 30-70 MB (с Flutter обычно 40-60 MB)
- **Windows EXE**: 50-100 MB
- **iOS IPA**: 50-80 MB
- **Linux AppImage**: 70-120 MB
- **macOS DMG**: 60-100 MB
## 🎯 Пример рабочего процесса
1. **Разработка** → Изменения в коде
2. **Тестирование** → Проверка на эмуляторе/устройстве
3. **Сборка**`flutter build apk/windows/ios/linux/macos`
4. **Загрузка** → Копирование файлов в `downloads/`
5. **Публикация** → Обновление `latest.json` через панель
6. **Уведомление** → Пользователи получают обновление
## 💡 Советы
- Всегда используйте HTTPS для скачивания файлов
- Храните старые версии (минимум 2-3 последние)
- Используйте CDN для больших файлов
- Тестируйте обновление перед публикацией
- Делайте бэкапы `latest.json` (автоматические)

View File

@@ -0,0 +1,133 @@
# 📦 Файлы Обновлений для Desktop Платформ
## 🖥️ Поддерживаемые платформы
### Windows
- **Файлы:** `.exe`, `.msi`
- **Путь:** `windows/umbrix-x.x.x-setup.exe`
- **Сборка:**
```bash
flutter build windows --release
# Затем создать установщик с помощью Inno Setup или NSIS
```
### macOS
- **Файлы:** `.dmg`, `.pkg`
- **Путь:** `macos/umbrix-x.x.x.dmg`
- **Сборка:**
```bash
flutter build macos --release
# Затем создать DMG с помощью create-dmg
```
### Linux
- **Файлы:** `.AppImage`, `.deb`, `.rpm`
- **Путь:** `linux/umbrix-x.x.x.AppImage`
- **Сборка:**
```bash
flutter build linux --release
# Затем упаковать в AppImage/deb/rpm
```
---
## 📁 Структура директорий
```
downloads/
├── windows/
│ └── umbrix-1.7.3-setup.exe
├── macos/
│ └── umbrix-1.7.3.dmg
├── linux/
│ ├── umbrix-1.7.3.AppImage
│ ├── umbrix-1.7.3.deb
│ └── umbrix-1.7.3.rpm
└── android/ (только для тестирования debug сборок)
└── umbrix-1.7.3-debug.apk
```
---
## 🚀 Как добавить обновление
### 1. Соберите приложение
```bash
# Windows
flutter build windows --release
# macOS
flutter build macos --release
# Linux
flutter build linux --release
```
### 2. Создайте установщик
**Windows (Inno Setup):**
```bash
iscc installer-script.iss
```
**macOS (create-dmg):**
```bash
create-dmg umbrix.app
```
**Linux (AppImage):**
```bash
appimage-builder --recipe AppImageBuilder.yml
```
### 3. Скопируйте файл
```bash
# Пример для Windows
cp output/umbrix-1.7.3-setup.exe update-server/downloads/windows/
# Для Docker
docker cp umbrix-1.7.3-setup.exe umbrix-update-server:/var/www/downloads/windows/
```
### 4. Обновите latest.json через Web-панель
1. Откройте http://your-server/admin/
2. Введите версию: `1.7.3`
3. Build number: `173`
4. URL: `http://your-server/downloads/windows/umbrix-1.7.3-setup.exe`
5. Описание изменений
6. Сохраните
---
## 🔍 Проверка
После загрузки проверьте доступность:
```bash
# Проверка API
curl http://your-server/api.php
# Проверка файла
curl -I http://your-server/downloads/windows/umbrix-1.7.3-setup.exe
```
---
## 📝 Примечания
### Android
- **Production:** Обновления через Google Play Store
- **Development:** Можно использовать папку `android/` для debug APK
### Безопасность
- Используйте HTTPS для production
- Подписывайте установщики цифровой подписью
- Добавьте checksums в latest.json для верификации
### Оптимизация
- Используйте CDN для больших файлов
- Храните только последние 2-3 версии
- Настройте сжатие на веб-сервере

View File

@@ -0,0 +1 @@
# Здесь размещайте файлы обновлений для android

Binary file not shown.

View File

@@ -0,0 +1 @@
# Здесь размещайте файлы обновлений для ios

View File

@@ -0,0 +1 @@
# Здесь размещайте файлы обновлений для linux

View File

@@ -0,0 +1 @@
# Здесь размещайте файлы обновлений для macos

View File

@@ -0,0 +1 @@
# Здесь размещайте файлы обновлений для windows

11
update-server/latest.json Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "1.7.3",
"build_number": "173",
"is_prerelease": false,
"download_url": "http://10.0.2.2:8000/downloads/android/umbrix-1.7.1.apk",
"release_notes": "Исправлена установка APK при обновлении",
"published_at": "2026-01-17T05:49:07.696Z",
"min_required_version": "2.0.0",
"file_size_bytes": 0,
"file_checksum_sha256": ""
}

View File

@@ -0,0 +1,12 @@
{
"version": "1.7.1",
"build_number": "171",
"is_prerelease": false,
"download_url": "http://10.0.2.2:8000/downloads/android/umbrix-1.7.1.apk",
"release_notes": "🎉 Что нового в версии 1.7.1:\n\n✨ Новые возможности:\n- Система автоматических обновлений\n- История версий с откатом\n- Улучшена стабильность\n\n🐛 Исправлены ошибки:\n- Исправлен краш при обновлении\n- Улучшена работа update server\n\n📱 Улучшения:\n- Новая веб-панель управления\n- Поддержка всех платформ Flutter",
"published_at": "2026-01-17T13:00:00Z",
"min_required_version": "1.0.0",
"force_update": false,
"file_size_bytes": 48000000,
"file_checksum_sha256": ""
}

View File

@@ -0,0 +1,11 @@
{
"version": "1.7.1",
"build_number": "171",
"is_prerelease": false,
"download_url": "http://10.0.2.2:8000/downloads/android/umbrix-1.7.1.apk",
"release_notes": "",
"published_at": "2026-01-17T05:47:36.710Z",
"min_required_version": "2.0.0",
"file_size_bytes": 0,
"file_checksum_sha256": ""
}

View File

@@ -0,0 +1,45 @@
#!/bin/bash
# 🎨 Быстрый запуск веб-панели управления обновлениями
echo "╔════════════════════════════════════════════════╗"
echo "║ 🎨 Umbrix Update Manager - Веб-панель ║"
echo "╚════════════════════════════════════════════════╝"
echo ""
# Проверка PHP
if ! command -v php &> /dev/null; then
echo "❌ PHP не установлен. Установите: sudo apt install php"
exit 1
fi
echo "✅ PHP $(php -v | head -1 | cut -d' ' -f2) найден"
# Переход в папку update-server
cd "$(dirname "$0")" || exit
# Запуск сервера
echo ""
echo "🚀 Запускаю веб-сервер..."
echo ""
echo "┌────────────────────────────────────────────────┐"
echo "│ Веб-панель доступна по адресу: │"
echo "│ │"
echo "│ 👉 http://localhost:8000/admin/ │"
echo "│ │"
echo "│ API сервер: │"
echo "│ 👉 http://localhost:8000/api.php │"
echo "└────────────────────────────────────────────────┘"
echo ""
echo "💡 Откройте в браузере и управляйте обновлениями!"
echo ""
echo "🛑 Для остановки нажмите Ctrl+C"
echo ""
echo "══════════════════════════════════════════════════"
echo ""
# Создать папку logs если нет
mkdir -p logs
# Запуск PHP сервера
php -S localhost:8000

View File

@@ -0,0 +1,126 @@
#!/bin/bash
# 🚀 Скрипт для быстрого тестирования системы обновлений
echo "╔════════════════════════════════════════════════╗"
echo "║ 🚀 Тестирование Системы Обновлений Umbrix ║"
echo "╚════════════════════════════════════════════════╝"
echo ""
# Проверка PHP
if ! command -v php &> /dev/null; then
echo "❌ PHP не установлен. Установите: sudo apt install php"
exit 1
fi
echo "✅ PHP $(php -v | head -1 | cut -d' ' -f2) найден"
# Переход в папку сервера
cd "$(dirname "$0")" || exit
# Проверка файлов
echo "🔍 Проверка необходимых файлов..."
files=("api.php" "latest.json" ".htaccess")
for file in "${files[@]}"; do
if [ -f "$file" ]; then
echo "$file"
else
echo "$file - НЕ НАЙДЕН!"
exit 1
fi
done
# Создание папки downloads если нет
if [ ! -d "downloads" ]; then
mkdir -p downloads
echo "📁 Создана папка downloads/"
fi
# Создание папки logs если нет
if [ ! -d "logs" ]; then
mkdir -p logs
echo "📁 Создана папка logs/"
fi
# Проверка порта
PORT=8000
if lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null 2>&1 ; then
echo "⚠️ Порт $PORT уже занят. Останавливаю..."
kill $(lsof -t -i:$PORT) 2>/dev/null
sleep 1
fi
# Запуск PHP сервера
echo ""
echo "🚀 Запускаю PHP сервер на http://localhost:$PORT"
php -S localhost:$PORT > logs/server.log 2>&1 &
PHP_PID=$!
# Ждем запуска
sleep 2
# Проверка что сервер запустился
if ! kill -0 $PHP_PID 2>/dev/null; then
echo "❌ Не удалось запустить сервер. Смотрите: logs/server.log"
exit 1
fi
echo "✅ Сервер запущен (PID: $PHP_PID)"
# Проверка API
echo ""
echo "🔍 Проверка API endpoint..."
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/api.php)
if [ "$RESPONSE" -eq 200 ]; then
echo "✅ API работает (HTTP $RESPONSE)"
echo ""
echo "📄 Ответ API:"
echo "─────────────────────────────────────────────────"
curl -s http://localhost:$PORT/api.php | python3 -m json.tool 2>/dev/null || curl -s http://localhost:$PORT/api.php
echo "─────────────────────────────────────────────────"
else
echo "❌ API не отвечает (HTTP $RESPONSE)"
echo "Смотрите логи: tail -f logs/server.log"
fi
# Информация для пользователя
echo ""
echo "╔════════════════════════════════════════════════╗"
echo "║ 📱 Инструкции ║"
echo "╚════════════════════════════════════════════════╝"
echo ""
echo "🔗 API доступен по адресу:"
echo " http://localhost:$PORT/api.php"
echo ""
echo "📱 Для Android эмулятора используйте:"
echo " http://10.0.2.2:$PORT/api.php"
echo ""
echo "🔧 В constants.dart укажите:"
echo " static const customUpdateServerUrl = \"http://10.0.2.2:$PORT/api.php\";"
echo " static const useCustomUpdateServer = true;"
echo ""
echo "📋 Далее:"
echo " 1. Откройте приложение в эмуляторе"
echo " 2. Зайдите в Настройки → О программе"
echo " 3. Нажмите 'Проверить обновления'"
echo ""
echo "📊 Логи сервера:"
echo " tail -f logs/server.log"
echo ""
echo "🛑 Остановить сервер:"
echo " kill $PHP_PID"
echo ""
echo "═════════════════════════════════════════════════"
# Сохранить PID
echo $PHP_PID > logs/server.pid
echo ""
echo "✅ Сервер работает. Нажмите Ctrl+C для остановки"
echo ""
# Ждем сигнала остановки
trap "echo ''; echo '🛑 Останавливаю сервер...'; kill $PHP_PID 2>/dev/null; rm -f logs/server.pid; echo '✅ Сервер остановлен'; exit 0" INT TERM
# Следим за логами
tail -f logs/server.log