mirror of
https://github.com/anten-ka/gotelegram_pro.git
synced 2026-05-19 12:16:01 +00:00
v2.4.1: full docs (DOCS_HUMAN.md + DOCS_AI.md)
- DOCS_HUMAN.md: user-facing guide (quick start, lite/pro, menu, bot, backup, requirements, FAQ, file locations, changelog) - DOCS_AI.md: deep technical reference for AI agents (architecture, telemt v3 TOML format, subshell capture rules, bug history incl. start_telemt restart fix, github push workflow, VPS test workflow) - lib/common.sh: bump GOTELEGRAM_VERSION 2.4.0 -> 2.4.1
This commit is contained in:
632
DOCS_AI.md
Normal file
632
DOCS_AI.md
Normal file
@@ -0,0 +1,632 @@
|
||||
# GoTelegram Pro — техническая документация для ИИ-агентов
|
||||
|
||||
**Версия:** 2.4.1
|
||||
**Репозиторий:** `anten-ka/gotelegram_pro`
|
||||
**Активная ветка:** `alfa-test` (ветка `test` заморожена и содержит stable для конечных пользователей)
|
||||
**Целевая ОС:** Ubuntu 20.04+, Debian 11+
|
||||
|
||||
Этот документ описывает устройство проекта с максимальным количеством нюансов — все ловушки, на которые мы уже наступали, все причины «почему именно так», формат всех внешних интерфейсов, и checklist действий для типовых задач. Цель: чтобы новый агент мог продолжить работу без повторения ошибок и без регрессий.
|
||||
|
||||
---
|
||||
|
||||
## 1. Общая картина
|
||||
|
||||
GoTelegram Pro — это менеджер MTProxy для Telegram, собранный вокруг Rust-ядра **telemt** (порт mtproto-proxy с поддержкой fake-TLS, v3.3.x). Проект даёт три вещи:
|
||||
|
||||
1. **CLI-меню на bash** (`install.sh` + `lib/*.sh`) — установка, настройка, обновление, бекап, перезапуск, смена режима, управление сайтом-маскировкой, выбор шаблона. Единая точка входа `gotelegram` (symlink → `/opt/gotelegram/install.sh`).
|
||||
2. **Сайт-маскировку** — поднимает рядом nginx с настоящим сайтом на настоящем домене (Let's Encrypt) из каталога 1801 HTML-шаблонов (html5up / startbootstrap / ThemeWagon / dawidolko). В stealth-режиме telemt слушает 443, маскировочный трафик проксирует на локальный nginx (127.0.0.1:8443) через `dns_overrides`.
|
||||
3. **Telegram-бота** (`gotelegram-bot/bot.py`, python-telegram-bot v21+) — управление прокси со смартфона: статус/ссылка/QR/перезапуск/бекап/смена режима/смена домена/смена шаблона/переключение языка per-user (RU/EN).
|
||||
|
||||
Архитектура stealth-режима:
|
||||
```
|
||||
Клиент Telegram ──┐
|
||||
├─► anten-ka.com:443 (telemt, 0.0.0.0:443)
|
||||
Обычный браузер ───┘ │
|
||||
│ dns_overrides:
|
||||
▼ "anten-ka.com:8443:127.0.0.1"
|
||||
127.0.0.1:8443 (nginx)
|
||||
│
|
||||
▼
|
||||
/var/www/gotelegram-site/ (HTML шаблон)
|
||||
```
|
||||
|
||||
Lite-режим (без домена):
|
||||
```
|
||||
Клиент Telegram ─► IP:443 (telemt) ─► Telegram DC
|
||||
Fake-TLS эмулируется (tls_emulation=true), mask-трафик падает никуда
|
||||
tls_domain = google.com (или любой из QUICK_DOMAINS)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Репозиторий и ветки
|
||||
|
||||
```
|
||||
anten-ka/gotelegram_pro
|
||||
├── test ← frozen stable, пользователи ставятся отсюда через bootstrap.sh
|
||||
└── alfa-test ← активная разработка, пуши туда
|
||||
```
|
||||
|
||||
**Правило коммитов (из auto-memory):** все новые изменения идут ТОЛЬКО в `alfa-test`. `test` не трогаем без явной команды пользователя. Когда пользователь в диалоге скажет «влей в stable» — тогда мёржим alfa-test → test.
|
||||
|
||||
**Инструменты для коммитов (специфика окружения):**
|
||||
- `git push` через Windows Git CLI **не работает** — credential helper вешает процесс.
|
||||
- Linux sandbox **не имеет доступа к github.com** — прокси возвращает 403 на raw.githubusercontent.com и api.github.com.
|
||||
- **Единственный работающий путь:** Python-скрипт через GitHub REST API, запускаемый через Desktop Commander с `shell="cmd.exe"` (НЕ powershell, иначе не захватывается stdout).
|
||||
- PAT токен — см. CLAUDE.md.
|
||||
- Workflow: `POST git/blobs` для каждого файла → `POST git/trees` (с `base_tree` от текущего HEAD) → `POST git/commits` (parents=[текущий HEAD]) → `PATCH git/refs/heads/alfa-test` (sha=новый commit) → при необходимости `PATCH git/refs/tags/vX.Y.Z`.
|
||||
- **Важно про `base_tree`:** при частичном обновлении (1-2 файла) ОБЯЗАТЕЛЬНО передавать `base_tree` — иначе дерево получится только из переданных файлов, и все остальные файлы пропадут из коммита. `base_tree` можно опускать только при коммите с полным набором файлов.
|
||||
|
||||
---
|
||||
|
||||
## 3. Карта файлов
|
||||
|
||||
```
|
||||
install.sh главная точка входа, CLI-меню из 14 пунктов
|
||||
install_gotelegram_bot.sh legacy-установщик бота (функционал продублирован в install.sh)
|
||||
bootstrap.sh установщик приватного репо через raw.githubusercontent.com с PAT
|
||||
templates_catalog.json каталог 1801 шаблонов, 18 категорий, 4 источника (~460KB)
|
||||
DOCS_HUMAN.md документация для пользователя (этот каталог)
|
||||
DOCS_AI.md этот файл
|
||||
|
||||
lib/common.sh цвета, log_*, confirm, select_option, _valid_ip, config_get,
|
||||
save_gotelegram_config, get_server_ip, run_with_spinner,
|
||||
version, GOTELEGRAM_VERSION, пути
|
||||
lib/telemt.sh download_telemt, install_telemt_full, start/stop/restart_telemt,
|
||||
update_telemt, remove_telemt, telemt_status, telemt_logs,
|
||||
install_telemt_service (systemd юнит)
|
||||
lib/telemt_config.sh generate_telemt_toml (TOML v3), generate_proxy_link,
|
||||
get_config_value, validate_telemt_config, QUICK_DOMAINS[],
|
||||
select_quick_domain, select_port, show_proxy_info[_pro]
|
||||
lib/templates_catalog.sh download_template, select_category, select_template,
|
||||
show_template_preview, поддержка 5 источников
|
||||
lib/website.sh nginx + certbot + деплой шаблона
|
||||
lib/backup.sh create_backup, restore_backup, list_backups
|
||||
lib/i18n.sh t(), tf(), switch_language(), загрузка lang/ru.sh и lang/en.sh
|
||||
lib/lang/ru.sh 328 i18n ключей на русском
|
||||
lib/lang/en.sh 328 i18n ключей на английском
|
||||
lib/stats.sh телеметрия (опциональная)
|
||||
|
||||
gotelegram-bot/bot.py Telegram-бот (python-telegram-bot v21+)
|
||||
gotelegram-bot/config.example.env
|
||||
gotelegram-bot/requirements.txt
|
||||
gotelegram-bot/README.md
|
||||
gotelegram-bot/locales/*.json 99 ключей i18n для бота с per-user persistence
|
||||
```
|
||||
|
||||
**Где что лежит на VPS после установки:**
|
||||
| Что | Путь |
|
||||
| --- | --- |
|
||||
| Репо-скрипты | `/opt/gotelegram/` |
|
||||
| Symlink запуска | `/usr/local/bin/gotelegram` → `/opt/gotelegram/install.sh` |
|
||||
| Конфиг GoTelegram (JSON) | `/opt/gotelegram/config.json` |
|
||||
| Конфиг telemt | `/etc/telemt/config.toml` |
|
||||
| Бинарник telemt | `/usr/local/bin/telemt` |
|
||||
| Systemd юнит telemt | `/etc/systemd/system/telemt.service` |
|
||||
| Bot | `/opt/gotelegram-bot/` |
|
||||
| Systemd юнит бота | `/etc/systemd/system/gotelegram-bot.service` |
|
||||
| Сайт | `/var/www/gotelegram-site/` |
|
||||
| nginx конфиг | `/etc/nginx/sites-available/gotelegram` |
|
||||
| nginx enabled | `/etc/nginx/sites-enabled/gotelegram` |
|
||||
| Бекапы | `/opt/gotelegram/backups/` |
|
||||
| Лог GoTelegram | `/var/log/gotelegram.log` |
|
||||
| Логи telemt | `journalctl -u telemt` |
|
||||
| Логи бота | `journalctl -u gotelegram-bot` |
|
||||
|
||||
---
|
||||
|
||||
## 4. Формат telemt v3 TOML (КРИТИЧЕСКИ ВАЖНО)
|
||||
|
||||
telemt v3.3.39 использует собственный TOML-формат, **несовместимый с mtg и mtproto-proxy**. Попытка скормить ему старый формат (`[security]`, `[[users]]`, `[listen] bind_to`) приводит к тому, что telemt молча игнорирует секции и запускается с дефолтами → клиенты отваливаются с ошибкой SNI.
|
||||
|
||||
### Минимальный рабочий конфиг для Lite-режима
|
||||
|
||||
```toml
|
||||
[server]
|
||||
port = 443
|
||||
listen_addr_ipv4 = "0.0.0.0"
|
||||
|
||||
[censorship]
|
||||
tls_domain = "google.com"
|
||||
mask = true
|
||||
mask_port = 443
|
||||
tls_emulation = true # true → telemt сам эмулирует TLS handshake от имени tls_domain
|
||||
|
||||
[access.users]
|
||||
main = "HEX_SECRET_32" # 16 байт = 32 hex символа, БЕЗ префикса ee
|
||||
```
|
||||
|
||||
### Минимальный рабочий конфиг для Pro-режима (stealth)
|
||||
|
||||
```toml
|
||||
[server]
|
||||
port = 443
|
||||
listen_addr_ipv4 = "0.0.0.0"
|
||||
|
||||
[censorship]
|
||||
tls_domain = "anten-ka.com"
|
||||
mask = true
|
||||
mask_port = 8443
|
||||
tls_emulation = false # false → mask-трафик идёт на mask_port, nginx имеет свой Let's Encrypt cert
|
||||
|
||||
[access.users]
|
||||
main = "HEX_SECRET_32"
|
||||
|
||||
[network]
|
||||
dns_overrides = ["anten-ka.com:8443:127.0.0.1"]
|
||||
# формат host:port:ip — именно три поля через двоеточие
|
||||
```
|
||||
|
||||
### Поля по секциям (полный набор, который telemt принимает в дефолтном gen-config)
|
||||
|
||||
- `[general]` — modes, telemetry, links (опционально, можно не трогать).
|
||||
- `[general.modes]` — включение/отключение режимов прокси.
|
||||
- `[general.telemetry]` — отправка статистики (по умолчанию выключено).
|
||||
- `[general.links]` — формат публикуемых ссылок.
|
||||
- `[server]` — `port`, `listen_addr_ipv4`, `listen_addr_ipv6`.
|
||||
- `[server.api]` — HTTP-админка (не используем).
|
||||
- `[server.conntrack_control]` — ограничения на conntrack.
|
||||
- `[timeouts]` — таймауты handshake, idle и т.д.
|
||||
- `[network]` — `stun_servers`, `dns_overrides`.
|
||||
- `[censorship]` — `tls_domain`, `mask`, `mask_port`, `tls_emulation`, `unknown_sni_action` (значения: `Drop`, `Proxy`).
|
||||
- `[censorship.tls_fetch]` — параметры получения реального cert от tls_domain (используется только если `tls_emulation=false` И нет dns_overrides).
|
||||
- `[access]` — rate limits, доступ.
|
||||
- `[access.users]` — таблица `name = "secret"` (секрет — 32 hex).
|
||||
|
||||
### Почему `unknown_sni_action = Drop` нас кусал
|
||||
|
||||
В Pro-режиме при старом конфиге с `tls_domain = anten-ka.com` telemt дропает всех клиентов, которые приходят с другим SNI. Если потом перегенерировать конфиг в Lite (`tls_domain = google.com`), но НЕ перезапустить telemt полноценно (`systemctl start` no-op на живом сервисе), то у telemt в памяти остаётся старое `anten-ka.com`, и клиенты с SNI=google.com дропаются. Симптом пользователя: «ключ Lite не работает, telemt живой». Фикс — в `start_telemt()`, см. раздел 10, баг #23.
|
||||
|
||||
### Fake-TLS секрет (ee-формат)
|
||||
|
||||
Что присылается клиенту в ссылке `tg://proxy?...`:
|
||||
|
||||
```
|
||||
секрет_в_ссылке = "ee" + <hex_secret_32chars> + <hex(tls_domain)>
|
||||
```
|
||||
|
||||
Пример для secret=`2de6920b1e17ccd440933ba0600f578f6` (длинное — 32 hex) и domain=`google.com`:
|
||||
- hex(google.com) = `676f6f676c652e636f6d`
|
||||
- итог: `ee2de6920b1e17ccd440933ba0600f578f676f6f676c652e636f6d`
|
||||
|
||||
В конфиге telemt (`[access.users] main = ...`) секрет хранится **без** префикса `ee` и **без** hex-домена. telemt сам склеивает при handshake. Функция `generate_proxy_link()` в `lib/telemt_config.sh` делает эту конкатенацию при формировании ссылки.
|
||||
|
||||
### Systemd юнит
|
||||
|
||||
Генерируется функцией `install_telemt_service()` в `lib/telemt.sh`:
|
||||
```ini
|
||||
[Unit]
|
||||
Description=GoTelegram MTProxy (telemt engine)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
ExecStart=/usr/local/bin/telemt run /etc/telemt/config.toml
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
LimitNOFILE=65535
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=full
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
- `ProtectSystem=full` (НЕ `strict`!) — telemt пишет cache-файлы, при `strict` он падает.
|
||||
- `User=root` — telemt нужен для bind на 443. Можно заменить на `telemt` + `AmbientCapabilities=CAP_NET_BIND_SERVICE`, но это усложнение ради эстетики.
|
||||
|
||||
---
|
||||
|
||||
## 5. Жизненный цикл установки (Lite)
|
||||
|
||||
Функция `install_lite_mode` в `install.sh`. Порядок:
|
||||
|
||||
1. `select_quick_domain` (lib/telemt_config.sh) — интерактивный выбор `tls_domain` из списка QUICK_DOMAINS[] (20 доменов: google.com, microsoft.com, cloudflare.com, apple.com, amazon.com, github.com …). Функция **ОБЯЗАТЕЛЬНО** выводит UI через `>&2`, потому что она вызывается через `$()` — см. раздел 10, баг #14.
|
||||
2. `select_port` — порт (443 по умолчанию, проверяется занятость через `check_port`).
|
||||
3. Генерация секрета: `openssl rand -hex 16` → 32 hex символа.
|
||||
4. `install_telemt_full` → `download_telemt` (скачивает бинарник из telemt/telemt GitHub Releases с фильтром `telemt-x86_64-linux-gnu.tar.gz`) → `install_telemt_service` → `enable_telemt`.
|
||||
5. `generate_telemt_toml "$secret" "$port" "lite" "$domain" "$port"` → пишет `/etc/telemt/config.toml`.
|
||||
6. `save_gotelegram_config` → пишет `/opt/gotelegram/config.json` с полями `mode=lite`, `domain=""`, `mask_host=$domain`, `secret`, `port`.
|
||||
7. `start_telemt` → **restart** если уже active (см. баг #23), иначе `start`. Проверяет `systemctl is-active` через 2 сек.
|
||||
8. `show_proxy_info` — выводит IP/port/secret/tls_domain и `tg://proxy?...` ссылку, QR через qrencode если есть.
|
||||
|
||||
## 6. Жизненный цикл установки (Pro / stealth)
|
||||
|
||||
Функция `install_pro_mode` в `install.sh`. Добавляет к Lite-флоу:
|
||||
|
||||
1. Запрос домена (`read_user_input domain`), `validate_domain` — проверка формата.
|
||||
2. `dig +short $domain` → проверка DNS = IP VPS. Если не совпало — предупреждение, но продолжаем (пользователь может знать лучше).
|
||||
3. `apt install nginx certbot python3-certbot-nginx` (если ещё нет).
|
||||
4. `interactive_template_selection` → `select_category` → `select_template` → `show_template_preview` → возвращает `tpl_id`. Все UI через `>&2` — иначе ID замусоривается.
|
||||
5. `download_template "$tpl_id"` → клонирует репо шаблона в temp, проверяет `index.html`, копирует в `/var/www/gotelegram-site/`. Для StartBootstrap проверяет `dist/index.html` — см. баг #21.
|
||||
6. Запись временного nginx-конфига на порту 80 (для challenge), reload nginx.
|
||||
7. `certbot --nginx -d $domain` → получает Let's Encrypt сертификат.
|
||||
8. Переписывание nginx-конфига: listen `127.0.0.1:8443 ssl`, root `/var/www/gotelegram-site`, используем cert от certbot.
|
||||
9. Генерация `telemt/config.toml` в режиме `pro` с `tls_emulation=false`, `mask_port=8443`, `dns_overrides = ["$domain:8443:127.0.0.1"]`.
|
||||
10. `save_gotelegram_config mode=pro domain=$domain ...`.
|
||||
11. `start_telemt` (restart-safe) → `show_proxy_info_pro` выводит ссылку через доменное имя.
|
||||
|
||||
---
|
||||
|
||||
## 7. Правила subshell-capture (железно)
|
||||
|
||||
Это **самое частое место ошибок** в проекте. Любая функция, которая вызывается через `$(...)` для получения значения, должна писать ВСЕ логи и UI в stderr (`>&2`). Единственный разрешённый вывод в stdout — это финальный `echo "$result"` с возвращаемым значением.
|
||||
|
||||
Что обязательно `>&2`:
|
||||
- **Все** `log_info/success/warning/error/step/dim` в `lib/common.sh` (это уже сделано).
|
||||
- `confirm`, `select_option` в `lib/common.sh` (сделано).
|
||||
- `select_quick_domain`, `select_port` в `lib/telemt_config.sh` (сделано).
|
||||
- `select_category`, `select_template`, `show_template_preview` в `lib/templates_catalog.sh` (сделано, баг #18 был о том, что 4 строки в show_template_preview выводили без >&2).
|
||||
- Любой `echo`/`printf` внутри `download_template` при ошибочном пути — см. баг #22 (`ls -la` без `>&2` замусоривал вывод).
|
||||
- Любая новая интерактивная функция, которую добавляешь.
|
||||
|
||||
Чек-лист когда пишешь новую функцию:
|
||||
1. Она вызывается через `$()`? → все echo/printf/log_* через `>&2`, кроме финального.
|
||||
2. Возвращает строку через echo → именно **одна** финальная строка, без лишних переводов строки.
|
||||
3. Ошибочный путь (early return) → НЕ писать в stdout, только в stderr, `return 1`.
|
||||
|
||||
---
|
||||
|
||||
## 8. SCRIPT_DIR и symlink
|
||||
|
||||
`install.sh` запускается через symlink `/usr/local/bin/gotelegram → /opt/gotelegram/install.sh`. Если наивно использовать `dirname "${BASH_SOURCE[0]}"`, получим `/usr/local/bin`, а там нет каталога `lib/`. Правильный паттерн:
|
||||
|
||||
```bash
|
||||
SCRIPT_PATH="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
|
||||
```
|
||||
|
||||
`readlink -f` резолвит symlink до реального файла → `SCRIPT_DIR=/opt/gotelegram`, и `source "$SCRIPT_DIR/lib/common.sh"` работает. Это зафиксировано в баге #19.
|
||||
|
||||
---
|
||||
|
||||
## 9. Каталог шаблонов
|
||||
|
||||
Файл `templates_catalog.json`, ~460KB, ~18000 строк. Формат:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "2.4.1",
|
||||
"sources": ["html5up", "startbootstrap", "themewagon", "dawidolko"],
|
||||
"categories": ["landing", "portfolio", "agency", "saas", "restaurant", ...],
|
||||
"templates": [
|
||||
{
|
||||
"id": "h5up_massively",
|
||||
"name": "Massively",
|
||||
"source": "html5up",
|
||||
"repo": "https://github.com/html5up-inc/massively.git",
|
||||
"category": "personal",
|
||||
"preview": "https://html5up.net/massively"
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Источники и как они скачиваются (`download_template` в `lib/templates_catalog.sh`):
|
||||
|
||||
| Источник | Префикс id | Метод | Где index.html |
|
||||
| --- | --- | --- | --- |
|
||||
| html5up | `h5up_*` | `git clone --depth 1 $repo` | в корне |
|
||||
| startbootstrap | `sb_*` | `git clone --depth 1` → **ищем `dist/index.html`** → копируем `dist/*` | в `dist/` |
|
||||
| themewagon | `tw_*` | `git clone --depth 1 $repo` (каждый шаблон в отдельном репо) | в корне |
|
||||
| dawidolko | `dw_*` / `colorlib_*` | sparse checkout одного большого репо | в подпапке |
|
||||
|
||||
Fallback: если по известным правилам index.html не найден, `download_template` делает `find -name "index.html"` по всему клону и берёт первый. Это спасает для нестандартных структур.
|
||||
|
||||
**ColorlibHQ отброшен** — оказались WordPress-темы (PHP), index.html пустой. Не пытаться включать обратно.
|
||||
|
||||
---
|
||||
|
||||
## 10. История багов (не наступать на те же грабли)
|
||||
|
||||
Все решены в текущем HEAD (`alfa-test`). Перечисление для того, чтобы новый агент не «чинил» то, что уже починено, и понимал контекст.
|
||||
|
||||
1. `telemt.sh grep` — URL формат `telemt-x86_64-linux-gnu.tar.gz`, arch перед `linux`. Нужен `grep -iE "$arch_pattern"` + цепочка фильтров (`grep -i linux`, `grep -v sha256`, `grep gnu`, `head -1`).
|
||||
2. `bot.py safe_edit_message` — обёртка для `query.edit_message_text`, ловит `BadRequest: message is not modified`.
|
||||
3. `bot.py QR cleanup` — `os.remove(qr_file)` в `finally` блоке.
|
||||
4. `common.sh _valid_ip` — проверка октетов 0-255, раньше пропускал 999.
|
||||
5. `common.sh os-release injection` — блокирует `;`, backticks, `$(`, `${` при парсинге `/etc/os-release`.
|
||||
6. `common.sh config_get` — return codes: `0=ok`, `2=файл отсутствует`, `3=невалидный JSON`.
|
||||
7. `common.sh run_with_spinner` — stderr в temp-файл, показ первых 3 строк при ошибке.
|
||||
8. `install.sh` — проверка пустого домена **перед** `validate_domain` (валидатор падал на пустой строке).
|
||||
9. `install.sh mode_choice` — санитизация `${mode_choice:-}` чтобы `set -u` не ронял скрипт.
|
||||
10. `backup.sh` — инициализация `final_file`/`tar_file`/`backup_file` перед ветвлением (иначе unset var).
|
||||
11. `bot.py XSS` — `html.escape(preview_url, quote=True)` с двойными кавычками.
|
||||
12. `common.sh` — версия была устаревшая, обновлена (сейчас 2.4.1).
|
||||
13. `install.sh` — добавлен пункт 12 меню (Telegram-бот) с подменю установка/статус/логи/настройки/удаление.
|
||||
14. **КРИТИЧЕСКИЙ subshell capture** — интерактивные функции (`select_quick_domain`, `select_port`, `select_category`, `select_template`, `show_template_preview`) выводили UI в stdout. Вызов через `$()` → меню уходило в переменную. Фикс: весь UI через `>&2`.
|
||||
15. **КРИТИЧЕСКИЙ download_telemt extract** — `find -newer` не находил извлечённый файл (таймстамп архива старше). Фикс: извлечение в отдельную директорию `$extract_dir` + проверка размера файла + fallback через `file` для определения ELF.
|
||||
16. `common.sh log_*` — все `log_info/success/warning/error/step/dim` выводят в stderr (`>&2`).
|
||||
17. `common.sh confirm/select_option` — UI через `>&2`.
|
||||
18. **КРИТИЧЕСКИЙ show_template_preview stdout leak** — 4 строки (блок «Спасибо авторам» + разделители) выводили без `>&2`. Цепочка `interactive_template_selection → select_template → show_template_preview` → мусор подмешивался к `tpl_id` → `download_template` получал мусорный ID → «шаблон не содержит index.html». Фикс: `>&2` ко всем 4 echo.
|
||||
19. **symlink SCRIPT_DIR** — `readlink -f "${BASH_SOURCE[0]}"` для резолва symlink `/usr/local/bin/gotelegram`.
|
||||
20. **bootstrap.sh** — скачивание приватного репо через `raw.githubusercontent.com/.../bootstrap.sh?token=...`, создание symlink, запуск install.sh.
|
||||
21. **КРИТИЧЕСКИЙ StartBootstrap dist/** — sb_* шаблоны хранят production в `dist/`. Фикс: клонируем в `$sb_tmp`, проверяем `dist/index.html`, копируем `dist/*` в `$clone_dir`, + universal fallback через `find`.
|
||||
22. **templates_catalog.sh ls stdout leak** — `ls -la` в блоке ошибки `download_template` шёл в stdout. Фикс: `>&2`.
|
||||
23. **КРИТИЧЕСКИЙ start_telemt stale config (v2.4.1)** — `systemctl start` это no-op для уже активного сервиса. После переустановки Lite поверх Pro конфиг на диске менялся, но telemt держал в памяти старый `tls_domain=anten-ka.com` и дропал клиентов с SNI=google.com. Фикс: `start_telemt` теперь делает `restart` если сервис уже активен. См. `lib/telemt.sh:189-213`.
|
||||
|
||||
---
|
||||
|
||||
## 11. Telegram-бот
|
||||
|
||||
Файл `gotelegram-bot/bot.py`, python-telegram-bot v21+, systemd сервис `gotelegram-bot.service`.
|
||||
|
||||
Ключевые моменты:
|
||||
- **Admin ID** — бот отвечает только пользователю с `ADMIN_TG_ID` из `.env`. Всё остальное игнорируется.
|
||||
- **safe_edit_message** — обёртка над `query.edit_message_text` + `query.edit_message_caption`, глотает `BadRequest: message is not modified`. Используй её всегда вместо прямого вызова.
|
||||
- **Language per-user** — файл `locales/users.json` хранит `{user_id: "ru"/"en"}`. При каждом сообщении бот читает язык пользователя и подставляет строку через `t(key, lang)`.
|
||||
- **QR-коды** — генерятся в `/tmp/gotelegram_qr_*.png`, отправляются как `InputFile`, удаляются в `finally`.
|
||||
- **Шаблон preview в HTML** — URL экранируется через `html.escape(url, quote=True)` (баг #11).
|
||||
- **Системные действия** — бот вызывает тот же `install.sh` через `subprocess.run(["bash", "/opt/gotelegram/install.sh", "--action=...", "--json"])` (флаги add как задача на будущее).
|
||||
- **Устанавливается** из меню `install.sh → 12) Telegram-бот → Установить`. Пользователь вводит BotFather token + свой Telegram ID, `.env` пишется в `/opt/gotelegram-bot/.env`.
|
||||
|
||||
---
|
||||
|
||||
## 12. i18n (bash CLI)
|
||||
|
||||
`lib/i18n.sh` экспортирует функции:
|
||||
|
||||
```bash
|
||||
t "key" # вернуть строку на текущем языке
|
||||
tf "key" arg1 arg2 # t + printf-интерполяция
|
||||
switch_language ru|en
|
||||
```
|
||||
|
||||
Под капотом — ассоциативный массив `I18N`, ключи в `lib/lang/ru.sh` и `lib/lang/en.sh`. ~328 ключей.
|
||||
|
||||
Добавление нового ключа:
|
||||
1. Придумай стабильный key (snake_case, без пробелов): `menu_install`, `error_port_busy`.
|
||||
2. Добавь строку в `lib/lang/ru.sh`: `I18N[menu_install]="Установить / обновить"`.
|
||||
3. Добавь строку в `lib/lang/en.sh`: `I18N[menu_install]="Install / update"`.
|
||||
4. В коде вызови `t menu_install`.
|
||||
5. Если есть интерполяция — используй `%s`/`%d`: `I18N[info_port]="Порт %s свободен"` + `tf info_port "$port"`.
|
||||
|
||||
Выбор языка сохраняется в `$GOTELEGRAM_CONFIG` → `config.json` → ключ `lang`. Первый запуск — интерактивный выбор.
|
||||
|
||||
---
|
||||
|
||||
## 13. Бекапы
|
||||
|
||||
`lib/backup.sh`. Собирает в `.tar.gz`:
|
||||
- `/etc/telemt/config.toml`
|
||||
- `/opt/gotelegram/config.json`
|
||||
- `/var/www/gotelegram-site/` (если есть)
|
||||
- `/etc/letsencrypt/live/<domain>/` + `/etc/letsencrypt/archive/<domain>/` (если Pro)
|
||||
- `/etc/nginx/sites-available/gotelegram` (если есть)
|
||||
|
||||
Складывает в `/opt/gotelegram/backups/backup_YYYY-MM-DD_HH-MM-SS.tar.gz`.
|
||||
|
||||
`restore_backup` разворачивает архив обратно, перезапускает telemt и nginx.
|
||||
|
||||
---
|
||||
|
||||
## 14. Checklist: как обновить один файл и запушить
|
||||
|
||||
1. Прочитай текущее состояние файла: `Read` для локальной версии + `git_get_contents` (raw.githubusercontent.com) если нужно убедиться что на GitHub то же самое.
|
||||
2. Применяй правки через `Edit` в локальном каталоге `/sessions/.../gotelegram-v2/`.
|
||||
3. Напиши `C:\Temp\push_<описание>.py`:
|
||||
```python
|
||||
import os, base64, json, urllib.request, ssl
|
||||
TOKEN = "github_pat_..."
|
||||
REPO = "anten-ka/gotelegram_pro"
|
||||
BRANCH = "alfa-test"
|
||||
API = f"https://api.github.com/repos/{REPO}"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
"Accept": "application/vnd.github+json",
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
"User-Agent": "gotelegram-push",
|
||||
}
|
||||
def req(method, path, body=None):
|
||||
data = json.dumps(body).encode() if body else None
|
||||
r = urllib.request.Request(API + path, data=data, headers={**headers, "Content-Type": "application/json"}, method=method)
|
||||
return json.loads(urllib.request.urlopen(r).read())
|
||||
|
||||
# 1. current ref
|
||||
ref = req("GET", f"/git/refs/heads/{BRANCH}")
|
||||
parent_sha = ref["object"]["sha"]
|
||||
commit = req("GET", f"/git/commits/{parent_sha}")
|
||||
base_tree = commit["tree"]["sha"]
|
||||
|
||||
# 2. blobs
|
||||
files = {
|
||||
"lib/common.sh": open("C:/.../gotelegram-v2/lib/common.sh","rb").read(),
|
||||
"DOCS_AI.md": open("C:/.../gotelegram-v2/DOCS_AI.md","rb").read(),
|
||||
}
|
||||
tree_items = []
|
||||
for path, content in files.items():
|
||||
blob = req("POST", "/git/blobs", {"content": base64.b64encode(content).decode(), "encoding": "base64"})
|
||||
tree_items.append({"path": path, "mode": "100644", "type": "blob", "sha": blob["sha"]})
|
||||
|
||||
# 3. tree (С base_tree — обязательно при частичном апдейте)
|
||||
tree = req("POST", "/git/trees", {"base_tree": base_tree, "tree": tree_items})
|
||||
|
||||
# 4. commit
|
||||
new_commit = req("POST", "/git/commits", {
|
||||
"message": "v2.4.1: docs + start_telemt restart-safe",
|
||||
"tree": tree["sha"],
|
||||
"parents": [parent_sha],
|
||||
})
|
||||
|
||||
# 5. patch ref
|
||||
req("PATCH", f"/git/refs/heads/{BRANCH}", {"sha": new_commit["sha"], "force": False})
|
||||
print("pushed:", new_commit["sha"])
|
||||
```
|
||||
4. Запускай через Desktop Commander `start_process` с `shell="cmd.exe"`:
|
||||
```
|
||||
cmd /c "python C:\Temp\push_docs.py"
|
||||
```
|
||||
НЕ через PowerShell — там stdout не захватывается в нашем окружении.
|
||||
5. Проверь результат: `GET /commits/<sha>` или открой ветку в браузере вручную.
|
||||
|
||||
**Частые грабли:**
|
||||
- Забыл `base_tree` → все остальные файлы исчезли из коммита. ВСЕГДА передавай `base_tree` кроме случая «чистый коммит со всеми файлами».
|
||||
- `cp1251` в cmd ломает юникод → пиши в файл через Python с `encoding='utf-8'`, не выводи кириллицу в stdout.
|
||||
- GitHub API кеширует raw-ответы по path → при проверке обновления используй `?ref=<commit_sha>`, не ветку.
|
||||
|
||||
---
|
||||
|
||||
## 15. Checklist: тестирование на VPS
|
||||
|
||||
VPS: `95.163.176.222`, root, пароль в CLAUDE.md.
|
||||
|
||||
**Путь из Linux sandbox:** `ssh`/`sshpass` нет, `pip install paramiko` падает (прокси 403). Идём через Windows Python, где paramiko уже установлен.
|
||||
|
||||
**Хелперы:**
|
||||
- `C:\Temp\ssh_cmd.py` — однократная команда, читает из `C:\Temp\ssh_input.txt`, пишет в `C:\Temp\ssh_output.txt`.
|
||||
- `C:\Temp\ssh_a1.py` / `ssh_a2.py` / `ssh_a3.py` — для параллельных агентов (разные output-файлы).
|
||||
|
||||
**Базовый шаблон ssh_cmd.py:**
|
||||
```python
|
||||
import sys, paramiko
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect("95.163.176.222", username="root", password="...", timeout=20)
|
||||
cmd = open("C:/Temp/ssh_input.txt", "r", encoding="utf-8").read()
|
||||
stdin, stdout, stderr = ssh.exec_command(cmd, timeout=60)
|
||||
out = stdout.read().decode(errors="replace")
|
||||
err = stderr.read().decode(errors="replace")
|
||||
open("C:/Temp/ssh_output.txt", "w", encoding="utf-8").write(f"STDOUT:\n{out}\nSTDERR:\n{err}")
|
||||
ssh.close()
|
||||
```
|
||||
|
||||
**Заливка одного файла через SFTP:**
|
||||
```python
|
||||
sftp = ssh.open_sftp()
|
||||
sftp.put("C:/.../lib/telemt.sh", "/opt/gotelegram/lib/telemt.sh")
|
||||
sftp.close()
|
||||
```
|
||||
|
||||
**CRLF:** файлы из GitHub API приходят с `\r\n` → ОБЯЗАТЕЛЬНО `sed -i 's/\r$//' /opt/gotelegram/install.sh /opt/gotelegram/lib/*.sh` перед запуском, иначе bash падает с `bad interpreter`.
|
||||
|
||||
**chmod:** `chmod +x /opt/gotelegram/install.sh /opt/gotelegram/install_gotelegram_bot.sh` — GitHub раздаёт как 644.
|
||||
|
||||
**Быстрая проверка live-состояния:**
|
||||
```bash
|
||||
systemctl is-active telemt nginx gotelegram-bot
|
||||
telemt --version
|
||||
cat /etc/telemt/config.toml | grep tls_domain
|
||||
journalctl -u telemt --no-pager -n 30
|
||||
curl -sk -o /dev/null -w "%{http_code}\n" https://127.0.0.1:8443
|
||||
```
|
||||
|
||||
**Проверка что Lite-ключ реально работает через Fake-TLS:**
|
||||
```python
|
||||
import ssl, socket
|
||||
ctx = ssl.create_default_context()
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
with socket.create_connection(("95.163.176.222", 443), timeout=5) as s:
|
||||
with ctx.wrap_socket(s, server_hostname="google.com") as ss:
|
||||
print(ss.version(), ss.getpeercert(True)[:40])
|
||||
```
|
||||
Ожидаемо: `TLSv1.3`, сертификат с CN=`*.google.com` (его telemt эмулирует через tls_fetch).
|
||||
|
||||
---
|
||||
|
||||
## 16. Меню (install.sh)
|
||||
|
||||
```
|
||||
── Прокси ──
|
||||
1) menu_install (Lite/Pro выбор, domain, template, certbot)
|
||||
2) menu_status (telemt_status + show_proxy_info)
|
||||
3) menu_link (ссылка + QR)
|
||||
4) menu_share (текст «для друзей»)
|
||||
5) menu_restart (restart_telemt)
|
||||
6) menu_logs (telemt_logs 40)
|
||||
7) menu_change_mode (lite↔pro, смена шаблона, смена домена маскировки)
|
||||
|
||||
── Управление ──
|
||||
8) interactive_backup (create_backup)
|
||||
9) interactive_restore (select_backup + restore_backup)
|
||||
10) update_telemt (check_telemt_update → download → restart)
|
||||
11) menu_website (nginx restart, certbot renew)
|
||||
|
||||
── Бот и прочее ──
|
||||
12) menu_bot (install_bot / start / stop / logs / change_token / remove)
|
||||
13) menu_remove (только прокси / только бот / всё)
|
||||
14) menu_promo (подарочные ссылки — маркетинг)
|
||||
|
||||
0) exit
|
||||
```
|
||||
|
||||
Диспатчер в `install.sh` принимает `--action=` для автоматизации из бота (будущая работа).
|
||||
|
||||
---
|
||||
|
||||
## 17. Changelog
|
||||
|
||||
- **2.4.1 (2026-04-10)** — баг #23: `start_telemt` делает `restart` если сервис активен (иначе stale in-memory config после переустановки Lite поверх Pro). Полная документация проекта — `DOCS_HUMAN.md` и `DOCS_AI.md` (этот файл).
|
||||
- **2.4.0** — i18n EN/RU для CLI (328 ключей) и бота (99 ключей JSON с per-user persistence). Возможность загрузить свой шаблон сайта из произвольного git-репозитория (валидация URL, таймауты, лимит размера клона).
|
||||
- **2.3.x** — каталог шаблонов расширен до 1801, 4 источника, 18 категорий. Поддержка StartBootstrap `dist/` структуры.
|
||||
- **2.2.1** — критические фиксы `$()` capture (все UI через `>&2`), StartBootstrap dist, symlink SCRIPT_DIR через `readlink -f`, XSS в HTML-превью бота, OS-release injection.
|
||||
- **2.2** — переход с mtg на telemt v3, новый TOML-формат конфига, stealth-архитектура.
|
||||
|
||||
---
|
||||
|
||||
## 18. Быстрый справочник: «хочу сделать X»
|
||||
|
||||
**Добавить новый пункт меню:**
|
||||
1. `install.sh`: добавь `menu_new_thing()`, впиши в диспатчер `case` в главном цикле.
|
||||
2. Добавь i18n ключи `menu_new_thing` в ru.sh и en.sh.
|
||||
3. Если функция интерактивная + возвращает значение → ВСЁ UI через `>&2`.
|
||||
|
||||
**Добавить новый домен в QUICK_DOMAINS:**
|
||||
- `lib/telemt_config.sh` → массив `QUICK_DOMAINS=(...)`. Убедись что домен не заблокирован ни в одной из популярных стран и действительно отвечает на 443 с валидным сертификатом (telemt при `tls_emulation=true` вынимает реальный cert через tls_fetch).
|
||||
|
||||
**Сменить версию:**
|
||||
- `lib/common.sh:6` → `GOTELEGRAM_VERSION="X.Y.Z"`.
|
||||
- `DOCS_HUMAN.md` / `DOCS_AI.md` → раздел Changelog + версия в шапке.
|
||||
- Тэг (опционально): `PATCH /git/refs/tags/vX.Y.Z` на новый commit sha.
|
||||
|
||||
**Добавить новый шаблон в каталог:**
|
||||
- Найди git-репо со статическим HTML (index.html в корне или в `dist/`).
|
||||
- Придумай id: `<source_prefix>_<name>` (например `h5up_future`, `sb_portfolio_x`).
|
||||
- Добавь запись в `templates_catalog.json` с `id`, `name`, `source`, `repo`, `category`, `preview`.
|
||||
- Убедись что `download_template` знает префикс источника (`case "$tpl_id" in h5up_*) ... sb_*) ... esac`).
|
||||
|
||||
**Отладить «ключ не работает»:**
|
||||
1. `systemctl is-active telemt` → живой?
|
||||
2. `cat /etc/telemt/config.toml` → какой `tls_domain`? Какой `port`? Какой `secret`?
|
||||
3. `journalctl -u telemt --no-pager -n 50` → есть `unknown_sni_action=Drop`? `port in use`? `failed to bind`?
|
||||
4. Сравни `tls_domain` в конфиге и hex-домен в конце ссылки клиента (`hex(domain) === суффикс секрета после ee+32hex`).
|
||||
5. Если telemt жив но дропает — **restart** (не start). Это баг #23.
|
||||
6. Если порт занят — `ss -ltnp | grep :443` → убей конкурента.
|
||||
7. Если Pro и не открывается сайт в браузере — `curl -k https://127.0.0.1:8443` (nginx жив?), `dig +short $domain` (DNS правильный?).
|
||||
|
||||
---
|
||||
|
||||
## 19. Где НЕ копаться
|
||||
|
||||
- `install_gotelegram_bot.sh` — legacy, функционал дублирован в install.sh пункте 12. Можно удалить после того как убедимся что никто им не пользуется.
|
||||
- `lib/stats.sh` — опциональная телеметрия, не критичная для работы.
|
||||
- `ColorlibHQ` в каталоге — wordpress-темы, отброшены. Не возвращать.
|
||||
- Старый формат конфига mtg (`[security]`, `[[users]]`, `bind_to`) — telemt v3 его игнорирует. Не пытаться «починить» совместимость.
|
||||
|
||||
---
|
||||
|
||||
## 20. Контрольные точки и инварианты
|
||||
|
||||
Перед любым пушем в `alfa-test`:
|
||||
1. `bash -n install.sh lib/*.sh` — синтаксис bash ОК.
|
||||
2. Все новые `$()`-вызываемые функции пишут UI через `>&2`.
|
||||
3. Все пути к lib/ идут через `$SCRIPT_DIR/lib/...`, а `SCRIPT_DIR` — через `readlink -f`.
|
||||
4. `GOTELEGRAM_VERSION` обновлена если изменения меняют поведение.
|
||||
5. Changelog в `DOCS_HUMAN.md` и `DOCS_AI.md` дополнен.
|
||||
6. Если бекап-формат изменился — прописать в `restore_backup` обратную совместимость.
|
||||
7. `generate_telemt_toml` не роняет telemt v3 (проверить `telemt run --check config.toml`).
|
||||
|
||||
После пуша:
|
||||
1. Подождать пока `alfa-test` обновится (GitHub API мгновенно, raw кеш ~30 сек).
|
||||
2. На VPS: `bash bootstrap.sh?token=...&ref=alfa-test` (или ручной `git pull` в клоне) + `sed -i 's/\r$//'` + `chmod +x` + `systemctl restart telemt`.
|
||||
3. `telemt_status` → running. `journalctl -u telemt` → нет ошибок. Ссылка открывается в Telegram-клиенте.
|
||||
|
||||
---
|
||||
|
||||
**Если в чём-то сомневаешься — открой `CLAUDE.md` в корне `MT-proxy/`. Там суммированы все ранее пройденные грабли и рабочие паттерны под Windows + Desktop Commander + paramiko.**
|
||||
Reference in New Issue
Block a user