chore: сделал

This commit is contained in:
protokey committed 2026-09-26 17:40:47 +04:00
1 parent 602199d510
commit 45e7a1d22f
25 files changed
+1164 -113

No files matched your search

+17 -3
View File
@@ -5,7 +5,7 @@ Django приложение связывающее все части сайта
-[x] Реализует кастомный менеджер модели и кастомную модель пользователя с отключенным email.
-[x] Модель данных для поддержки интерфейса и функционала
-[ ] Настройки домена и прокси у готовой точки
-[ ] Клиенты и статистика через API панели 3x-ui
-[x] Клиенты и статистика через API панели 3x-ui
Зависимости: `Telegram` (интерфейс бота, пользователи, уведомления) и `serverus` (настройка серверов).
@@ -13,6 +13,7 @@ Django приложение связывающее все части сайта
- `Point` - точка доступа: сервер с панелью 3x-ui и необязательный сервер маскировки. Владелец - `Telegram.User`. Хранит домен, прокси на выходе и доступ к панели.
- `Server` - сервер точки с ролью `panel` или `mask`. Хранит текущие порт ssh, пароль root, ключ и отпечаток ssh, а также пароль root, присланный пользователем при добавлении (`default_root_password`).
- `Key` - ключ клиента на панели точки: имя (оно же email клиента в панели), `uuid` и `sub_id`. Клиенту выдается `key.subscription_url`, после переустановки ключ восстанавливается с теми же ссылками.
С маскировкой клиенты подключаются к серверу маскировки, он перенаправляет трафик на панель и скрывает ее адрес. Маскировка требует домен.
@@ -20,14 +21,17 @@ Django приложение связывающее все части сайта
- создание: `Point.objects.create_point(owner, panel, mask=None, *, domain, outbound_proxy)` создает точку вместе с серверами, имя и доступ к панели генерирует сама. `Server.objects.create_server(point, role, credentials)`. `Credentials` - адрес и пароль root, которые прислал пользователь
- поиск: `Point.objects.owned_by(owner)`, дальше `find_by_name`, `find_by_pk`, `find_last`. У серверов `find_by_address` и `is_address_taken`, в том числе в пределах точки через `point.servers`
- изменение: `point.set_status(status, error)`, `server.reset_fingerprint()`
- изменение: `point.set_status(status, error)`, `server.reset_fingerprint()`. Статусы: `installing`, `updating` (меняется домен или прокси готовой точки), `ready`, `error`, `releasing`. Пока точка занята, с ней ничего не сделать. Неудачная смена домена или прокси оставляет точку `ready` с текстом ошибки: serverus применяет их только после выпуска сертификата и проверки прокси
- ключи: `services.issue_key(point, name)`, `services.revoke_key(key)`, поиск `point.keys.find_by_name(name)`
- удаление: `point.delete()`, серверы удаляются вместе с точкой
Соглашение для поиска: `get_*` и `point.server(role)` бросают `DoesNotExist`, если записи нет, а `find_*` возвращают `None`, и это видно по типу. `point.panel` всегда есть, потому что панель создается вместе с точкой, а `point.mask` может быть `None`.
## Модули
- `services.py` - сценарии поверх serverus: `install_point`, `reinstall`, `release_point`, у готовой точки `set_domain` (новый сертификат) и `set_outbound_proxy`.
- `services.py` - сценарии поверх serverus: `install_point`, `reinstall`, `release_point`, у готовой точки `set_domain` (новый сертификат) и `set_outbound_proxy`. Ключи через API панели: `issue_key`, `revoke_key`, `key_traffic`, `restore_keys`.
- `fields.py` - `EncryptedTextField`: секреты в базе зашифрованы Fernet ключами `FIELD_ENCRYPTION_KEYS` из `.env`.
- `management/commands/serve_ssh.py` - ручной вход на сервер: `make serve_ssh ip=<ip>`.
- `tasks.py` - задачи dramatiq: запускают сценарий и присылают результат в чат. Воркер: `make dj_worker`.
- `bot/interface.py` - интерфейс бота `MyPointInterface` (выбирается у бота в админке).
- `bot/texts.py` - кнопки и тексты.
@@ -38,6 +42,7 @@ Django приложение связывающее все части сайта
2. панель: 3x-ui с логином, паролем, портом и путем, которые сгенерировал App, сертификат на домен или ip, подписка, подключение reality `main`, исходящий прокси точки
3. маскировка: перенаправление трафика на адрес панели
4. facts: `uname -a` для карточки сервера
5. ключи точки восстанавливаются на панели (`restore_keys`), при первой установке их нет
"Переустановить" сбрасывает отпечаток ssh сервера и повторяет установку с новым паролем от провайдера или, по кнопке "Использовать старый", с паролем, присланным при добавлении сервера. Отпечаток можно сбросить и в админке.
@@ -52,3 +57,12 @@ Django приложение связывающее все части сайта
Решение: за Cloudflare не работаем. Reality через проксирование Cloudflare невозможен: Cloudflare сам завершает TLS.
- [x] нужна функция установки прокси в исходящие (outbound)
При установке ставится `point.outbound_proxy`, у готовой точки - `services.set_outbound_proxy(point, proxy)`. Поддерживаются socks5, http(s) и cf_warp.
- [x] кнопки "Домен" и "Прокси" у готовой точки: задачи `tasks.set_domain` и `tasks.set_outbound_proxy`, прокси в брокер уходит зашифрованным
## Секреты
Ключи и пароли серверов (`private_key`, `root_password`, `default_root_password`), доступ к панели (`panel_password`, `panel_api_token`), исходящий прокси и ключи клиентов (`uuid`, `sub_id`) хранятся зашифрованными (`App.fields.EncryptedTextField`, Fernet). Дамп базы без ключа не дает доступа к серверам. Искать по этим полям нельзя.
- Ключ - `FIELD_ENCRYPTION_KEYS` в `.env` (настройки сами читают `.env`, как бы ни был запущен сайт, воркер или бот). Потеря ключа - потеря доступа ко всем серверам: храните его отдельно от бэкапов базы.
- Смена ключа: новый ключ первым через запятую, старый следом, пересохранить записи, убрать старый.
- Ручной вход на сервер: `make serve_ssh ip=<ip>` (или `manage.py serve_ssh <ip> [команда]`). Ключ и отпечаток берутся из базы, ключ живет во временной папке только на время сессии. В админке и боте приватный ключ не показывается.