mirror of
https://github.com/andrey271192/PCAtelegram_web.git
synced 2026-09-21 12:01:56 +00:00
refactor: rename project to PCAtelegram_web
This commit is contained in:
46
README.md
46
README.md
@@ -1,45 +1,45 @@
|
|||||||
# GoTelegram Pro
|
# PCAtelegram_web
|
||||||
|
|
||||||
Отдельный проект GoTelegram Pro: MTProxy на базе `telemt`, Telegram-бот, локальная web-admin панель, статистика, backup/restore, шаблоны сайта.
|
Отдельный проект PCAtelegram_web: MTProxy на базе `telemt`, Telegram-бот, локальная web-admin панель, статистика, backup/restore, шаблоны сайта.
|
||||||
|
|
||||||
## Установка
|
## Установка
|
||||||
|
|
||||||
На сервере под `root`:
|
На сервере под `root`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://raw.githubusercontent.com/andrey271192/gotelegram/main/bootstrap.sh | bash
|
curl -fsSL https://raw.githubusercontent.com/andrey271192/PCAtelegram_web/main/bootstrap.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
Если репозиторий private, первый `curl` тоже должен получить GitHub token:
|
Если репозиторий private, первый `curl` тоже должен получить GitHub token:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL -H "Authorization: Bearer $GITHUB_TOKEN" \
|
curl -fsSL -H "Authorization: Bearer $GITHUB_TOKEN" \
|
||||||
https://raw.githubusercontent.com/andrey271192/gotelegram/main/bootstrap.sh | \
|
https://raw.githubusercontent.com/andrey271192/PCAtelegram_web/main/bootstrap.sh | \
|
||||||
GITHUB_TOKEN="$GITHUB_TOKEN" bash
|
GITHUB_TOKEN="$GITHUB_TOKEN" bash
|
||||||
```
|
```
|
||||||
|
|
||||||
После установки команда доступна как:
|
После установки команда доступна как:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gotelegram
|
pcatelegram_web
|
||||||
```
|
```
|
||||||
|
|
||||||
## Локальная проверка без GitHub
|
## Локальная проверка без GitHub
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
rsync -a ./ root@SERVER:/opt/gotelegram/
|
rsync -a ./ root@SERVER:/opt/pcatelegram_web/
|
||||||
ssh root@SERVER 'chmod +x /opt/gotelegram/install.sh /opt/gotelegram/install_gotelegram_bot.sh /opt/gotelegram/lib/*.sh && ln -sf /opt/gotelegram/install.sh /usr/local/bin/gotelegram && gotelegram'
|
ssh root@SERVER 'chmod +x /opt/pcatelegram_web/install.sh /opt/pcatelegram_web/install_pcatelegram_web_bot.sh /opt/pcatelegram_web/lib/*.sh && ln -sf /opt/pcatelegram_web/install.sh /usr/local/bin/pcatelegram_web && pcatelegram_web'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Состав
|
## Состав
|
||||||
|
|
||||||
| Путь | Назначение |
|
| Путь | Назначение |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `bootstrap.sh` | загружает файлы проекта в `/opt/gotelegram` и запускает меню |
|
| `bootstrap.sh` | загружает файлы проекта в `/opt/pcatelegram_web` и запускает меню |
|
||||||
| `install.sh` | основное CLI-меню GoTelegram |
|
| `install.sh` | основное CLI-меню PCAtelegram_web |
|
||||||
| `install_gotelegram_bot.sh` | отдельная установка Telegram-бота |
|
| `install_pcatelegram_web_bot.sh` | отдельная установка Telegram-бота |
|
||||||
| `lib/` | общие функции, telemt, nginx/site, stats, backup, i18n |
|
| `lib/` | общие функции, telemt, nginx/site, stats, backup, i18n |
|
||||||
| `gotelegram-bot/` | Python Telegram bot |
|
| `pcatelegram_web-bot/` | Python Telegram bot |
|
||||||
| `admin-web/` | локальная web-admin панель |
|
| `admin-web/` | локальная web-admin панель |
|
||||||
| `templates_catalog.json` | каталог HTML-шаблонов |
|
| `templates_catalog.json` | каталог HTML-шаблонов |
|
||||||
|
|
||||||
@@ -47,17 +47,17 @@ ssh root@SERVER 'chmod +x /opt/gotelegram/install.sh /opt/gotelegram/install_got
|
|||||||
|
|
||||||
| Переменная | По умолчанию | Описание |
|
| Переменная | По умолчанию | Описание |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `GOTELEGRAM_BASE` | `https://raw.githubusercontent.com/andrey271192/gotelegram/main` | база загрузки файлов |
|
| `PCATELEGRAM_WEB_BASE` | `https://raw.githubusercontent.com/andrey271192/PCAtelegram_web/main` | база загрузки файлов |
|
||||||
| `GOTELEGRAM_INSTALL_DIR` | `/opt/gotelegram` | путь установки |
|
| `PCATELEGRAM_WEB_INSTALL_DIR` | `/opt/pcatelegram_web` | путь установки |
|
||||||
| `GITHUB_TOKEN` / `GH_TOKEN` | пусто | token для private GitHub raw downloads |
|
| `GITHUB_TOKEN` / `GH_TOKEN` | пусто | token для private GitHub raw downloads |
|
||||||
| `GOTELEGRAM_ADMIN_HOST` | `127.0.0.1` | bind web-admin |
|
| `PCATELEGRAM_WEB_ADMIN_HOST` | `127.0.0.1` | bind web-admin |
|
||||||
| `GOTELEGRAM_ADMIN_PORT` | `1984` | port web-admin |
|
| `PCATELEGRAM_WEB_ADMIN_PORT` | `1984` | port web-admin |
|
||||||
| `GOTELEGRAM_ADMIN_USER` | `admin` | Basic Auth login |
|
| `PCATELEGRAM_WEB_ADMIN_USER` | `admin` | Basic Auth login |
|
||||||
| `GOTELEGRAM_ADMIN_PASSWORD` | пусто | Basic Auth password; обязателен при public bind |
|
| `PCATELEGRAM_WEB_ADMIN_PASSWORD` | пусто | Basic Auth password; обязателен при public bind |
|
||||||
|
|
||||||
## Web-admin
|
## Web-admin
|
||||||
|
|
||||||
После первого запуска `gotelegram` локальная web-admin панель ставится как `gotelegram-admin.service`.
|
После первого запуска `pcatelegram_web` локальная web-admin панель ставится как `pcatelegram_web-admin.service`.
|
||||||
|
|
||||||
Безопасный локальный доступ через SSH tunnel:
|
Безопасный локальный доступ через SSH tunnel:
|
||||||
|
|
||||||
@@ -70,10 +70,10 @@ open http://127.0.0.1:1984/
|
|||||||
|
|
||||||
```ini
|
```ini
|
||||||
[Service]
|
[Service]
|
||||||
Environment=GOTELEGRAM_ADMIN_HOST=0.0.0.0
|
Environment=PCATELEGRAM_WEB_ADMIN_HOST=0.0.0.0
|
||||||
Environment=GOTELEGRAM_ADMIN_PORT=1984
|
Environment=PCATELEGRAM_WEB_ADMIN_PORT=1984
|
||||||
Environment=GOTELEGRAM_ADMIN_USER=admin
|
Environment=PCATELEGRAM_WEB_ADMIN_USER=admin
|
||||||
Environment=GOTELEGRAM_ADMIN_PASSWORD=change-me
|
Environment=PCATELEGRAM_WEB_ADMIN_PASSWORD=change-me
|
||||||
```
|
```
|
||||||
|
|
||||||
Без HTTPS public Basic Auth гонит пароль открытым текстом. Для постоянного доступа лучше reverse proxy с TLS.
|
Без HTTPS public Basic Auth гонит пароль открытым текстом. Для постоянного доступа лучше reverse proxy с TLS.
|
||||||
@@ -81,6 +81,6 @@ Environment=GOTELEGRAM_ADMIN_PASSWORD=change-me
|
|||||||
## Проверки
|
## Проверки
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash -n bootstrap.sh install.sh install_gotelegram_bot.sh lib/*.sh lib/lang/*.sh
|
bash -n bootstrap.sh install.sh install_pcatelegram_web_bot.sh lib/*.sh lib/lang/*.sh
|
||||||
rg -i "old-brand-name" .
|
rg -i "old-brand-name" .
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
goTelegram Pro local web admin.
|
PCAtelegram_web local web admin.
|
||||||
|
|
||||||
The service is intentionally bound to 127.0.0.1:1984. Operators reach it
|
The service is intentionally bound to 127.0.0.1:1984. Operators reach it
|
||||||
through an SSH tunnel by default. If exposed through a reverse proxy or public
|
through an SSH tunnel by default. If exposed through a reverse proxy or public
|
||||||
bind, enable GOTELEGRAM_ADMIN_PASSWORD.
|
bind, enable PCATELEGRAM_WEB_ADMIN_PASSWORD.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -32,35 +32,35 @@ from pathlib import Path
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
ADMIN_DIR = Path(os.getenv("GOTELEGRAM_ADMIN_DIR", "/opt/gotelegram-admin"))
|
ADMIN_DIR = Path(os.getenv("PCATELEGRAM_WEB_ADMIN_DIR", "/opt/pcatelegram_web-admin"))
|
||||||
STATIC_DIR = Path(os.getenv("GOTELEGRAM_ADMIN_STATIC", str(ADMIN_DIR / "static")))
|
STATIC_DIR = Path(os.getenv("PCATELEGRAM_WEB_ADMIN_STATIC", str(ADMIN_DIR / "static")))
|
||||||
|
|
||||||
GOTELEGRAM_CONFIG = Path(os.getenv("GOTELEGRAM_CONFIG", "/opt/gotelegram/config.json"))
|
PCATELEGRAM_WEB_CONFIG = Path(os.getenv("PCATELEGRAM_WEB_CONFIG", "/opt/pcatelegram_web/config.json"))
|
||||||
TELEMT_CONFIG = Path(os.getenv("TELEMT_CONFIG", "/etc/telemt/config.toml"))
|
TELEMT_CONFIG = Path(os.getenv("TELEMT_CONFIG", "/etc/telemt/config.toml"))
|
||||||
HISTORY_FILE = Path(os.getenv("GOTELEGRAM_STATS_HISTORY", "/opt/gotelegram/stats_history.csv"))
|
HISTORY_FILE = Path(os.getenv("PCATELEGRAM_WEB_STATS_HISTORY", "/opt/pcatelegram_web/stats_history.csv"))
|
||||||
USER_HISTORY_FILE = Path(os.getenv("GOTELEGRAM_USER_STATS_HISTORY", "/opt/gotelegram/user_stats_history.csv"))
|
USER_HISTORY_FILE = Path(os.getenv("PCATELEGRAM_WEB_USER_STATS_HISTORY", "/opt/pcatelegram_web/user_stats_history.csv"))
|
||||||
CURRENT_STATS = Path(os.getenv("GOTELEGRAM_STATS_CURRENT", "/run/gotelegram/stats_current.json"))
|
CURRENT_STATS = Path(os.getenv("PCATELEGRAM_WEB_STATS_CURRENT", "/run/pcatelegram_web/stats_current.json"))
|
||||||
BACKUP_DIR = Path(os.getenv("GOTELEGRAM_BACKUP_DIR", "/opt/gotelegram/backups"))
|
BACKUP_DIR = Path(os.getenv("PCATELEGRAM_WEB_BACKUP_DIR", "/opt/pcatelegram_web/backups"))
|
||||||
INSTALL_DIR = Path(os.getenv("GOTELEGRAM_DIR", "/opt/gotelegram"))
|
INSTALL_DIR = Path(os.getenv("PCATELEGRAM_WEB_DIR", "/opt/pcatelegram_web"))
|
||||||
BOT_DIR = Path(os.getenv("GOTELEGRAM_BOT_DIR", "/opt/gotelegram-bot"))
|
BOT_DIR = Path(os.getenv("PCATELEGRAM_WEB_BOT_DIR", "/opt/pcatelegram_web-bot"))
|
||||||
DISABLED_USERS_FILE = Path(os.getenv("GOTELEGRAM_DISABLED_USERS", "/opt/gotelegram/disabled_users.json"))
|
DISABLED_USERS_FILE = Path(os.getenv("PCATELEGRAM_WEB_DISABLED_USERS", "/opt/pcatelegram_web/disabled_users.json"))
|
||||||
USER_LOCK_FILE = Path(os.getenv("GOTELEGRAM_USER_LOCK", "/run/gotelegram/admin-users.lock"))
|
USER_LOCK_FILE = Path(os.getenv("PCATELEGRAM_WEB_USER_LOCK", "/run/pcatelegram_web/admin-users.lock"))
|
||||||
SHARED_443_CONFIG = Path(os.getenv("GOTELEGRAM_SHARED_443", "/opt/gotelegram/shared-443.json"))
|
SHARED_443_CONFIG = Path(os.getenv("PCATELEGRAM_WEB_SHARED_443", "/opt/pcatelegram_web/shared-443.json"))
|
||||||
BACKUP_SCHEDULE_FILE = Path(os.getenv("GOTELEGRAM_BACKUP_SCHEDULE", "/opt/gotelegram/backup_schedule.json"))
|
BACKUP_SCHEDULE_FILE = Path(os.getenv("PCATELEGRAM_WEB_BACKUP_SCHEDULE", "/opt/pcatelegram_web/backup_schedule.json"))
|
||||||
BACKUP_RESTORE_LOG = Path(os.getenv("GOTELEGRAM_BACKUP_RESTORE_LOG", "/var/log/gotelegram-restore.log"))
|
BACKUP_RESTORE_LOG = Path(os.getenv("PCATELEGRAM_WEB_BACKUP_RESTORE_LOG", "/var/log/pcatelegram_web-restore.log"))
|
||||||
|
|
||||||
HOST = os.getenv("GOTELEGRAM_ADMIN_HOST", "127.0.0.1")
|
HOST = os.getenv("PCATELEGRAM_WEB_ADMIN_HOST", "127.0.0.1")
|
||||||
PORT = int(os.getenv("GOTELEGRAM_ADMIN_PORT", "1984"))
|
PORT = int(os.getenv("PCATELEGRAM_WEB_ADMIN_PORT", "1984"))
|
||||||
ADMIN_USER = os.getenv("GOTELEGRAM_ADMIN_USER", "admin")
|
ADMIN_USER = os.getenv("PCATELEGRAM_WEB_ADMIN_USER", "admin")
|
||||||
ADMIN_PASSWORD = os.getenv("GOTELEGRAM_ADMIN_PASSWORD", "")
|
ADMIN_PASSWORD = os.getenv("PCATELEGRAM_WEB_ADMIN_PASSWORD", "")
|
||||||
ADMIN_REALM = os.getenv("GOTELEGRAM_ADMIN_REALM", "GoTelegram")
|
ADMIN_REALM = os.getenv("PCATELEGRAM_WEB_ADMIN_REALM", "PCAtelegram_web")
|
||||||
VERSION = "2.5.0"
|
VERSION = "2.5.0"
|
||||||
USER_RE = re.compile(r"^[A-Za-z0-9_.-]{1,48}$")
|
USER_RE = re.compile(r"^[A-Za-z0-9_.-]{1,48}$")
|
||||||
LANG_RE = re.compile(r"^(en|ru)$")
|
LANG_RE = re.compile(r"^(en|ru)$")
|
||||||
SENSITIVE_CONFIG_KEYS = {"secret"}
|
SENSITIVE_CONFIG_KEYS = {"secret"}
|
||||||
BACKUP_NAME_RE = re.compile(r"^[A-Za-z0-9_.-]+\.tar\.gz(\.enc)?$")
|
BACKUP_NAME_RE = re.compile(r"^[A-Za-z0-9_.-]+\.tar\.gz(\.enc)?$")
|
||||||
MAX_UNIQUE_IP_LIMIT = 1000000
|
MAX_UNIQUE_IP_LIMIT = 1000000
|
||||||
TELEMT_RESTART_DEBOUNCE_SECONDS = float(os.getenv("GOTELEGRAM_TELEMT_RESTART_DEBOUNCE", "8"))
|
TELEMT_RESTART_DEBOUNCE_SECONDS = float(os.getenv("PCATELEGRAM_WEB_TELEMT_RESTART_DEBOUNCE", "8"))
|
||||||
_LAST_TELEMT_RESTART = 0.0
|
_LAST_TELEMT_RESTART = 0.0
|
||||||
TRAFFIC_WINDOWS = {
|
TRAFFIC_WINDOWS = {
|
||||||
"15m": 15 * 60,
|
"15m": 15 * 60,
|
||||||
@@ -135,7 +135,7 @@ def save_json(path: Path, data: Any, mode: int = 0o600) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def read_language(config: dict[str, Any] | None = None) -> str:
|
def read_language(config: dict[str, Any] | None = None) -> str:
|
||||||
config = config or load_json(GOTELEGRAM_CONFIG, {}) or {}
|
config = config or load_json(PCATELEGRAM_WEB_CONFIG, {}) or {}
|
||||||
lang = str(config.get("language") or config.get("lang") or "").strip().lower()
|
lang = str(config.get("language") or config.get("lang") or "").strip().lower()
|
||||||
marker = INSTALL_DIR / ".language"
|
marker = INSTALL_DIR / ".language"
|
||||||
if lang not in {"en", "ru"} and marker.exists():
|
if lang not in {"en", "ru"} and marker.exists():
|
||||||
@@ -154,12 +154,12 @@ def write_language(lang: str) -> dict[str, Any]:
|
|||||||
lang = str(lang or "").strip().lower()
|
lang = str(lang or "").strip().lower()
|
||||||
if not LANG_RE.match(lang):
|
if not LANG_RE.match(lang):
|
||||||
raise ValueError("unsupported language")
|
raise ValueError("unsupported language")
|
||||||
config = load_json(GOTELEGRAM_CONFIG, {}) or {}
|
config = load_json(PCATELEGRAM_WEB_CONFIG, {}) or {}
|
||||||
if not isinstance(config, dict):
|
if not isinstance(config, dict):
|
||||||
config = {}
|
config = {}
|
||||||
config["language"] = lang
|
config["language"] = lang
|
||||||
config["updated_at"] = utc_now()
|
config["updated_at"] = utc_now()
|
||||||
save_json(GOTELEGRAM_CONFIG, config)
|
save_json(PCATELEGRAM_WEB_CONFIG, config)
|
||||||
INSTALL_DIR.mkdir(parents=True, exist_ok=True)
|
INSTALL_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
(INSTALL_DIR / ".language").write_text(lang + "\n", encoding="utf-8")
|
(INSTALL_DIR / ".language").write_text(lang + "\n", encoding="utf-8")
|
||||||
bot_env = BOT_DIR / ".env"
|
bot_env = BOT_DIR / ".env"
|
||||||
@@ -593,7 +593,7 @@ def listener_for_target(target: str) -> dict[str, Any] | None:
|
|||||||
|
|
||||||
|
|
||||||
def routed_behind_443() -> list[dict[str, Any]]:
|
def routed_behind_443() -> list[dict[str, Any]]:
|
||||||
config = load_json(GOTELEGRAM_CONFIG, {}) or {}
|
config = load_json(PCATELEGRAM_WEB_CONFIG, {}) or {}
|
||||||
mode = str(config.get("mode") or "")
|
mode = str(config.get("mode") or "")
|
||||||
domain = str(config.get("domain") or "")
|
domain = str(config.get("domain") or "")
|
||||||
settings = read_telemt_edge_settings()
|
settings = read_telemt_edge_settings()
|
||||||
@@ -694,7 +694,7 @@ def public_ip() -> str:
|
|||||||
|
|
||||||
|
|
||||||
def proxy_link(secret: str) -> str:
|
def proxy_link(secret: str) -> str:
|
||||||
config = load_json(GOTELEGRAM_CONFIG, {}) or {}
|
config = load_json(PCATELEGRAM_WEB_CONFIG, {}) or {}
|
||||||
mode = str(config.get("mode", "lite"))
|
mode = str(config.get("mode", "lite"))
|
||||||
port = int(config.get("port", 443) or 443)
|
port = int(config.get("port", 443) or 443)
|
||||||
domain = str(config.get("domain", "") or "")
|
domain = str(config.get("domain", "") or "")
|
||||||
@@ -721,7 +721,7 @@ def telemt_api(path: str) -> Any:
|
|||||||
|
|
||||||
|
|
||||||
def site_status(config: dict[str, Any] | None = None) -> dict[str, Any]:
|
def site_status(config: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||||
config = config or load_json(GOTELEGRAM_CONFIG, {}) or {}
|
config = config or load_json(PCATELEGRAM_WEB_CONFIG, {}) or {}
|
||||||
host = str(config.get("domain") or "").strip()
|
host = str(config.get("domain") or "").strip()
|
||||||
if not host:
|
if not host:
|
||||||
return {"host": "", "url": "", "http_code": 0, "ok": False, "checked": False, "error": "domain_missing"}
|
return {"host": "", "url": "", "http_code": 0, "ok": False, "checked": False, "error": "domain_missing"}
|
||||||
@@ -1002,7 +1002,7 @@ def count_user_history_rows(name: str | None = None) -> int:
|
|||||||
def stats_status(current: dict[str, Any] | None = None, history: list[dict[str, int]] | None = None) -> dict[str, Any]:
|
def stats_status(current: dict[str, Any] | None = None, history: list[dict[str, int]] | None = None) -> dict[str, Any]:
|
||||||
current = current if current is not None else (load_json(CURRENT_STATS, {}) or {})
|
current = current if current is not None else (load_json(CURRENT_STATS, {}) or {})
|
||||||
history = history if history is not None else load_stats_history(limit=2)
|
history = history if history is not None else load_stats_history(limit=2)
|
||||||
service = service_status("gotelegram-stats")
|
service = service_status("pcatelegram_web-stats")
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
ts = int(current.get("ts") or 0) if isinstance(current, dict) else 0
|
ts = int(current.get("ts") or 0) if isinstance(current, dict) else 0
|
||||||
age = max(0, now - ts) if ts else None
|
age = max(0, now - ts) if ts else None
|
||||||
@@ -1034,9 +1034,9 @@ def stats_status(current: dict[str, Any] | None = None, history: list[dict[str,
|
|||||||
def run_stats_action(action: str) -> tuple[bool, str, dict[str, Any]]:
|
def run_stats_action(action: str) -> tuple[bool, str, dict[str, Any]]:
|
||||||
if action == "repair":
|
if action == "repair":
|
||||||
body = (
|
body = (
|
||||||
"source /opt/gotelegram/lib/common.sh; "
|
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||||
"source /opt/gotelegram/lib/i18n.sh; "
|
"source /opt/pcatelegram_web/lib/i18n.sh; "
|
||||||
"source /opt/gotelegram/lib/stats.sh; "
|
"source /opt/pcatelegram_web/lib/stats.sh; "
|
||||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||||
"install_stats_collector; "
|
"install_stats_collector; "
|
||||||
"stats_collect"
|
"stats_collect"
|
||||||
@@ -1044,8 +1044,8 @@ def run_stats_action(action: str) -> tuple[bool, str, dict[str, Any]]:
|
|||||||
timeout = 180
|
timeout = 180
|
||||||
else:
|
else:
|
||||||
body = (
|
body = (
|
||||||
"source /opt/gotelegram/lib/common.sh; "
|
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||||
"source /opt/gotelegram/lib/stats.sh; "
|
"source /opt/pcatelegram_web/lib/stats.sh; "
|
||||||
"stats_init >/dev/null 2>&1 || true; "
|
"stats_init >/dev/null 2>&1 || true; "
|
||||||
"stats_collect"
|
"stats_collect"
|
||||||
)
|
)
|
||||||
@@ -1100,9 +1100,9 @@ def backup_schedule_status() -> dict[str, Any]:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
frequency = "off"
|
frequency = "off"
|
||||||
calendar = None
|
calendar = None
|
||||||
active_code, active, _ = run(["systemctl", "is-active", "gotelegram-backup.timer"], timeout=5)
|
active_code, active, _ = run(["systemctl", "is-active", "pcatelegram_web-backup.timer"], timeout=5)
|
||||||
enabled_code, enabled, _ = run(["systemctl", "is-enabled", "gotelegram-backup.timer"], timeout=5)
|
enabled_code, enabled, _ = run(["systemctl", "is-enabled", "pcatelegram_web-backup.timer"], timeout=5)
|
||||||
_, next_run, _ = run(["systemctl", "show", "gotelegram-backup.timer", "--property=NextElapseUSecRealtime", "--value"], timeout=5)
|
_, next_run, _ = run(["systemctl", "show", "pcatelegram_web-backup.timer", "--property=NextElapseUSecRealtime", "--value"], timeout=5)
|
||||||
return {
|
return {
|
||||||
"frequency": frequency,
|
"frequency": frequency,
|
||||||
"calendar": calendar,
|
"calendar": calendar,
|
||||||
@@ -1116,9 +1116,9 @@ def backup_schedule_status() -> dict[str, Any]:
|
|||||||
def set_backup_schedule(frequency: str) -> tuple[bool, str, dict[str, Any]]:
|
def set_backup_schedule(frequency: str) -> tuple[bool, str, dict[str, Any]]:
|
||||||
backup_schedule_calendar(frequency)
|
backup_schedule_calendar(frequency)
|
||||||
script = (
|
script = (
|
||||||
"source /opt/gotelegram/lib/common.sh; "
|
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||||
"source /opt/gotelegram/lib/i18n.sh; "
|
"source /opt/pcatelegram_web/lib/i18n.sh; "
|
||||||
"source /opt/gotelegram/lib/backup.sh; "
|
"source /opt/pcatelegram_web/lib/backup.sh; "
|
||||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||||
f"set_backup_schedule {shlex.quote(frequency)}"
|
f"set_backup_schedule {shlex.quote(frequency)}"
|
||||||
)
|
)
|
||||||
@@ -1129,11 +1129,11 @@ def set_backup_schedule(frequency: str) -> tuple[bool, str, dict[str, Any]]:
|
|||||||
|
|
||||||
def create_backup() -> tuple[bool, str]:
|
def create_backup() -> tuple[bool, str]:
|
||||||
script = (
|
script = (
|
||||||
"source /opt/gotelegram/lib/common.sh; "
|
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||||
"source /opt/gotelegram/lib/i18n.sh; "
|
"source /opt/pcatelegram_web/lib/i18n.sh; "
|
||||||
"source /opt/gotelegram/lib/telemt.sh; "
|
"source /opt/pcatelegram_web/lib/telemt.sh; "
|
||||||
"source /opt/gotelegram/lib/website.sh; "
|
"source /opt/pcatelegram_web/lib/website.sh; "
|
||||||
"source /opt/gotelegram/lib/backup.sh; "
|
"source /opt/pcatelegram_web/lib/backup.sh; "
|
||||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||||
"create_backup \"\"; "
|
"create_backup \"\"; "
|
||||||
"cleanup_old_backups 30"
|
"cleanup_old_backups 30"
|
||||||
@@ -1166,11 +1166,11 @@ def launch_restore_backup(name: str, password: str = "") -> dict[str, Any]:
|
|||||||
quoted_log = shlex.quote(str(BACKUP_RESTORE_LOG))
|
quoted_log = shlex.quote(str(BACKUP_RESTORE_LOG))
|
||||||
script = (
|
script = (
|
||||||
"sleep 1; "
|
"sleep 1; "
|
||||||
"source /opt/gotelegram/lib/common.sh; "
|
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||||
"source /opt/gotelegram/lib/i18n.sh; "
|
"source /opt/pcatelegram_web/lib/i18n.sh; "
|
||||||
"source /opt/gotelegram/lib/telemt.sh; "
|
"source /opt/pcatelegram_web/lib/telemt.sh; "
|
||||||
"source /opt/gotelegram/lib/website.sh; "
|
"source /opt/pcatelegram_web/lib/website.sh; "
|
||||||
"source /opt/gotelegram/lib/backup.sh; "
|
"source /opt/pcatelegram_web/lib/backup.sh; "
|
||||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||||
"create_backup \"\" >/dev/null 2>&1 || true; "
|
"create_backup \"\" >/dev/null 2>&1 || true; "
|
||||||
f"restore_backup {quoted_path} {quoted_password} yes; "
|
f"restore_backup {quoted_path} {quoted_password} yes; "
|
||||||
@@ -1201,7 +1201,7 @@ def user_qr_png(name: str) -> tuple[bytes, str]:
|
|||||||
|
|
||||||
|
|
||||||
def read_log_payload(service: str) -> dict[str, Any]:
|
def read_log_payload(service: str) -> dict[str, Any]:
|
||||||
allowed = {"telemt", "nginx", "gotelegram-bot", "gotelegram-stats", "gotelegram-admin"}
|
allowed = {"telemt", "nginx", "pcatelegram_web-bot", "pcatelegram_web-stats", "pcatelegram_web-admin"}
|
||||||
if service not in allowed:
|
if service not in allowed:
|
||||||
raise ValueError("unsupported service")
|
raise ValueError("unsupported service")
|
||||||
code, stdout, stderr = run(["journalctl", "-u", service, "-n", "180", "--no-pager", "-o", "short-iso"], timeout=10)
|
code, stdout, stderr = run(["journalctl", "-u", service, "-n", "180", "--no-pager", "-o", "short-iso"], timeout=10)
|
||||||
@@ -1249,7 +1249,7 @@ def user_payload(
|
|||||||
|
|
||||||
|
|
||||||
def overview_payload() -> dict[str, Any]:
|
def overview_payload() -> dict[str, Any]:
|
||||||
config = load_json(GOTELEGRAM_CONFIG, {}) or {}
|
config = load_json(PCATELEGRAM_WEB_CONFIG, {}) or {}
|
||||||
language = read_language(config)
|
language = read_language(config)
|
||||||
users = read_user_records()
|
users = read_user_records()
|
||||||
current = load_json(CURRENT_STATS, {}) or {}
|
current = load_json(CURRENT_STATS, {}) or {}
|
||||||
@@ -1258,9 +1258,9 @@ def overview_payload() -> dict[str, Any]:
|
|||||||
services = {
|
services = {
|
||||||
"telemt": service_status("telemt"),
|
"telemt": service_status("telemt"),
|
||||||
"nginx": service_status("nginx"),
|
"nginx": service_status("nginx"),
|
||||||
"bot": service_status("gotelegram-bot"),
|
"bot": service_status("pcatelegram_web-bot"),
|
||||||
"stats": service_status("gotelegram-stats"),
|
"stats": service_status("pcatelegram_web-stats"),
|
||||||
"admin": service_status("gotelegram-admin"),
|
"admin": service_status("pcatelegram_web-admin"),
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
"version": VERSION,
|
"version": VERSION,
|
||||||
@@ -1282,7 +1282,7 @@ def overview_payload() -> dict[str, Any]:
|
|||||||
|
|
||||||
|
|
||||||
class AdminHandler(BaseHTTPRequestHandler):
|
class AdminHandler(BaseHTTPRequestHandler):
|
||||||
server_version = "goTelegramProAdmin/2.5.0"
|
server_version = "PCAtelegram_webProAdmin/2.5.0"
|
||||||
|
|
||||||
def log_message(self, fmt: str, *args: Any) -> None:
|
def log_message(self, fmt: str, *args: Any) -> None:
|
||||||
print("%s - %s" % (self.address_string(), fmt % args))
|
print("%s - %s" % (self.address_string(), fmt % args))
|
||||||
@@ -1345,7 +1345,7 @@ class AdminHandler(BaseHTTPRequestHandler):
|
|||||||
return json.loads(self.rfile.read(length).decode("utf-8"))
|
return json.loads(self.rfile.read(length).decode("utf-8"))
|
||||||
|
|
||||||
def require_write_guard(self) -> bool:
|
def require_write_guard(self) -> bool:
|
||||||
if self.command in {"POST", "PUT", "PATCH", "DELETE"} and self.headers.get("X-GoTelegram-Admin") != "1":
|
if self.command in {"POST", "PUT", "PATCH", "DELETE"} and self.headers.get("X-PCAtelegram-Web-Admin") != "1":
|
||||||
self.send_error_json(403, "missing write guard")
|
self.send_error_json(403, "missing write guard")
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
@@ -1602,7 +1602,7 @@ class AdminHandler(BaseHTTPRequestHandler):
|
|||||||
self.send_json({"ok": True, "data": lang_payload})
|
self.send_json({"ok": True, "data": lang_payload})
|
||||||
elif path.startswith("/api/services/") and path.endswith("/restart"):
|
elif path.startswith("/api/services/") and path.endswith("/restart"):
|
||||||
service = path[len("/api/services/"):-len("/restart")]
|
service = path[len("/api/services/"):-len("/restart")]
|
||||||
allowed = {"telemt", "nginx", "gotelegram-bot", "gotelegram-stats"}
|
allowed = {"telemt", "nginx", "pcatelegram_web-bot", "pcatelegram_web-stats"}
|
||||||
if service not in allowed:
|
if service not in allowed:
|
||||||
self.send_error_json(400, "unsupported service")
|
self.send_error_json(400, "unsupported service")
|
||||||
return
|
return
|
||||||
@@ -1698,7 +1698,7 @@ def main() -> None:
|
|||||||
if not STATIC_DIR.exists():
|
if not STATIC_DIR.exists():
|
||||||
raise SystemExit(f"static dir not found: {STATIC_DIR}")
|
raise SystemExit(f"static dir not found: {STATIC_DIR}")
|
||||||
httpd = ThreadingHTTPServer((HOST, PORT), AdminHandler)
|
httpd = ThreadingHTTPServer((HOST, PORT), AdminHandler)
|
||||||
print(f"goTelegram Pro admin listening on http://{HOST}:{PORT}")
|
print(f"PCAtelegram_web admin listening on http://{HOST}:{PORT}")
|
||||||
httpd.serve_forever()
|
httpd.serve_forever()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ const i18n = {
|
|||||||
backupScheduleTitle: "Automatic backups",
|
backupScheduleTitle: "Automatic backups",
|
||||||
backupScheduleLoading: "Loading schedule...",
|
backupScheduleLoading: "Loading schedule...",
|
||||||
backupIncludesTitle: "Backup contents",
|
backupIncludesTitle: "Backup contents",
|
||||||
backupIncludesText: "telemt config, goTelegram settings, keys, disabled keys, site, templates, SSL certificates, bot, admin panel and traffic history.",
|
backupIncludesText: "telemt config, PCAtelegram_web settings, keys, disabled keys, site, templates, SSL certificates, bot, admin panel and traffic history.",
|
||||||
scheduleOff: "Off",
|
scheduleOff: "Off",
|
||||||
scheduleDaily: "Daily",
|
scheduleDaily: "Daily",
|
||||||
scheduleWeekly: "Weekly",
|
scheduleWeekly: "Weekly",
|
||||||
@@ -210,7 +210,7 @@ const i18n = {
|
|||||||
ariaTrafficRange: "Traffic range",
|
ariaTrafficRange: "Traffic range",
|
||||||
ariaTrafficView: "Traffic view",
|
ariaTrafficView: "Traffic view",
|
||||||
promoEyebrow: "Promo",
|
promoEyebrow: "Promo",
|
||||||
promoTitle: "Support goTelegram Pro",
|
promoTitle: "Support PCAtelegram_web",
|
||||||
promoHosting1: "Hosting #1",
|
promoHosting1: "Hosting #1",
|
||||||
promoHosting2: "Hosting #2",
|
promoHosting2: "Hosting #2",
|
||||||
promoTips: "Tips",
|
promoTips: "Tips",
|
||||||
@@ -313,7 +313,7 @@ const i18n = {
|
|||||||
backupScheduleTitle: "Автобекапы",
|
backupScheduleTitle: "Автобекапы",
|
||||||
backupScheduleLoading: "Загрузка расписания...",
|
backupScheduleLoading: "Загрузка расписания...",
|
||||||
backupIncludesTitle: "Что входит в бекап",
|
backupIncludesTitle: "Что входит в бекап",
|
||||||
backupIncludesText: "конфиг telemt, настройки goTelegram, ключи, отключённые ключи, сайт, шаблоны, SSL-сертификаты, бот, админка и история трафика.",
|
backupIncludesText: "конфиг telemt, настройки PCAtelegram_web, ключи, отключённые ключи, сайт, шаблоны, SSL-сертификаты, бот, админка и история трафика.",
|
||||||
scheduleOff: "Выкл",
|
scheduleOff: "Выкл",
|
||||||
scheduleDaily: "Каждый день",
|
scheduleDaily: "Каждый день",
|
||||||
scheduleWeekly: "Каждую неделю",
|
scheduleWeekly: "Каждую неделю",
|
||||||
@@ -437,7 +437,7 @@ const i18n = {
|
|||||||
ariaTrafficRange: "Период трафика",
|
ariaTrafficRange: "Период трафика",
|
||||||
ariaTrafficView: "Вид трафика",
|
ariaTrafficView: "Вид трафика",
|
||||||
promoEyebrow: "Промо",
|
promoEyebrow: "Промо",
|
||||||
promoTitle: "Поддержать goTelegram Pro",
|
promoTitle: "Поддержать PCAtelegram_web",
|
||||||
promoHosting1: "Хостинг #1",
|
promoHosting1: "Хостинг #1",
|
||||||
promoHosting2: "Хостинг #2",
|
promoHosting2: "Хостинг #2",
|
||||||
promoTips: "Чаевые",
|
promoTips: "Чаевые",
|
||||||
@@ -478,7 +478,7 @@ const state = {
|
|||||||
qrLink: "",
|
qrLink: "",
|
||||||
pendingUsers: new Set(),
|
pendingUsers: new Set(),
|
||||||
refreshingAll: false,
|
refreshingAll: false,
|
||||||
autoRefreshEnabled: localStorage.getItem("gotelegram-auto-refresh") !== "0",
|
autoRefreshEnabled: localStorage.getItem("pcatelegram_web-auto-refresh") !== "0",
|
||||||
};
|
};
|
||||||
|
|
||||||
const t = (key) => (i18n[state.lang] && i18n[state.lang][key]) || i18n.en[key] || key;
|
const t = (key) => (i18n[state.lang] && i18n[state.lang][key]) || i18n.en[key] || key;
|
||||||
@@ -562,7 +562,7 @@ function syncAutoRefreshTimer() {
|
|||||||
|
|
||||||
function setAutoRefresh(enabled) {
|
function setAutoRefresh(enabled) {
|
||||||
state.autoRefreshEnabled = Boolean(enabled);
|
state.autoRefreshEnabled = Boolean(enabled);
|
||||||
localStorage.setItem("gotelegram-auto-refresh", state.autoRefreshEnabled ? "1" : "0");
|
localStorage.setItem("pcatelegram_web-auto-refresh", state.autoRefreshEnabled ? "1" : "0");
|
||||||
updateAutoRefreshToggle();
|
updateAutoRefreshToggle();
|
||||||
syncAutoRefreshTimer();
|
syncAutoRefreshTimer();
|
||||||
}
|
}
|
||||||
@@ -570,7 +570,7 @@ function setAutoRefresh(enabled) {
|
|||||||
async function api(path, options = {}) {
|
async function api(path, options = {}) {
|
||||||
const headers = {
|
const headers = {
|
||||||
"Accept": "application/json",
|
"Accept": "application/json",
|
||||||
"X-GoTelegram-Admin": "1",
|
"X-PCAtelegram-Web-Admin": "1",
|
||||||
...(options.headers || {}),
|
...(options.headers || {}),
|
||||||
};
|
};
|
||||||
if (options.body && !headers["Content-Type"]) headers["Content-Type"] = "application/json";
|
if (options.body && !headers["Content-Type"]) headers["Content-Type"] = "application/json";
|
||||||
@@ -610,7 +610,7 @@ function applyI18n() {
|
|||||||
function setTheme(theme) {
|
function setTheme(theme) {
|
||||||
state.theme = theme === "dark" ? "dark" : "light";
|
state.theme = theme === "dark" ? "dark" : "light";
|
||||||
document.documentElement.dataset.theme = state.theme;
|
document.documentElement.dataset.theme = state.theme;
|
||||||
localStorage.setItem("gotelegram-theme", state.theme);
|
localStorage.setItem("pcatelegram_web-theme", state.theme);
|
||||||
applyI18n();
|
applyI18n();
|
||||||
if (state.overview) renderStats();
|
if (state.overview) renderStats();
|
||||||
if (state.userTraffic) renderUserTraffic();
|
if (state.userTraffic) renderUserTraffic();
|
||||||
@@ -691,9 +691,9 @@ function renderServices(services = {}) {
|
|||||||
const items = [
|
const items = [
|
||||||
{ key: "telemt", label: "telemt", api: "telemt" },
|
{ key: "telemt", label: "telemt", api: "telemt" },
|
||||||
{ key: "nginx", label: "nginx", api: "nginx" },
|
{ key: "nginx", label: "nginx", api: "nginx" },
|
||||||
{ key: "bot", label: "bot", api: "gotelegram-bot" },
|
{ key: "bot", label: "bot", api: "pcatelegram_web-bot" },
|
||||||
{ key: "stats", label: "stats", api: "gotelegram-stats" },
|
{ key: "stats", label: "stats", api: "pcatelegram_web-stats" },
|
||||||
{ key: "admin", label: "admin", api: "gotelegram-admin" },
|
{ key: "admin", label: "admin", api: "pcatelegram_web-admin" },
|
||||||
];
|
];
|
||||||
$("#services").innerHTML = items.map((item) => {
|
$("#services").innerHTML = items.map((item) => {
|
||||||
const status = services[item.key] || "unknown";
|
const status = services[item.key] || "unknown";
|
||||||
@@ -1639,7 +1639,7 @@ async function copyText(value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function maybeShowPromo() {
|
function maybeShowPromo() {
|
||||||
const key = "gotelegram-promo-last";
|
const key = "pcatelegram_web-promo-last";
|
||||||
const now = Math.floor(Date.now() / 1000);
|
const now = Math.floor(Date.now() / 1000);
|
||||||
const last = Number(localStorage.getItem(key) || 0);
|
const last = Number(localStorage.getItem(key) || 0);
|
||||||
if (now - last < 86400) return;
|
if (now - last < 86400) return;
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>goTelegram Pro Admin</title>
|
<title>PCAtelegram_web Admin</title>
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
var stored = localStorage.getItem("gotelegram-theme");
|
var stored = localStorage.getItem("pcatelegram_web-theme");
|
||||||
var theme = stored || (matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
|
var theme = stored || (matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
|
||||||
document.documentElement.dataset.theme = theme;
|
document.documentElement.dataset.theme = theme;
|
||||||
}());
|
}());
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<div class="brand">
|
<div class="brand">
|
||||||
<div class="brand-mark">GT</div>
|
<div class="brand-mark">GT</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>goTelegram Pro</strong>
|
<strong>PCAtelegram_web</strong>
|
||||||
<span data-i18n="brandSubtitle">Local Admin</span>
|
<span data-i18n="brandSubtitle">Local Admin</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
<section class="page-panel active" data-page="dashboard">
|
<section class="page-panel active" data-page="dashboard">
|
||||||
<section class="visual-overview">
|
<section class="visual-overview">
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">goTelegram Pro</p>
|
<p class="eyebrow">PCAtelegram_web</p>
|
||||||
<h2 id="visualTitle">Port 443</h2>
|
<h2 id="visualTitle">Port 443</h2>
|
||||||
<p id="visualText">Website, MTProxy and local admin status in one operational view.</p>
|
<p id="visualText">Website, MTProxy and local admin status in one operational view.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="backup-includes">
|
<div class="backup-includes">
|
||||||
<strong data-i18n="backupIncludesTitle">Backup contents</strong>
|
<strong data-i18n="backupIncludesTitle">Backup contents</strong>
|
||||||
<span data-i18n="backupIncludesText">telemt config, goTelegram settings, keys, disabled keys, site, templates, SSL certificates, bot, admin panel and traffic history.</span>
|
<span data-i18n="backupIncludesText">telemt config, PCAtelegram_web settings, keys, disabled keys, site, templates, SSL certificates, bot, admin panel and traffic history.</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="backupsList" class="backup-list"></div>
|
<div id="backupsList" class="backup-list"></div>
|
||||||
</section>
|
</section>
|
||||||
@@ -307,9 +307,9 @@
|
|||||||
<select id="logService">
|
<select id="logService">
|
||||||
<option value="telemt">telemt</option>
|
<option value="telemt">telemt</option>
|
||||||
<option value="nginx">nginx</option>
|
<option value="nginx">nginx</option>
|
||||||
<option value="gotelegram-bot">bot</option>
|
<option value="pcatelegram_web-bot">bot</option>
|
||||||
<option value="gotelegram-stats">stats</option>
|
<option value="pcatelegram_web-stats">stats</option>
|
||||||
<option value="gotelegram-admin">admin</option>
|
<option value="pcatelegram_web-admin">admin</option>
|
||||||
</select>
|
</select>
|
||||||
<button id="loadLogsBtn" type="button" data-i18n="loadLogs">Load</button>
|
<button id="loadLogsBtn" type="button" data-i18n="loadLogs">Load</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -376,7 +376,7 @@
|
|||||||
<div class="promo-card" role="dialog" aria-modal="true" aria-labelledby="promoTitle">
|
<div class="promo-card" role="dialog" aria-modal="true" aria-labelledby="promoTitle">
|
||||||
<button id="promoClose" class="icon-btn ghost" type="button" aria-label="Close" data-i18n-aria-label="ariaClose">×</button>
|
<button id="promoClose" class="icon-btn ghost" type="button" aria-label="Close" data-i18n-aria-label="ariaClose">×</button>
|
||||||
<p class="eyebrow" data-i18n="promoEyebrow">Promo</p>
|
<p class="eyebrow" data-i18n="promoEyebrow">Promo</p>
|
||||||
<h2 id="promoTitle" data-i18n="promoTitle">Support goTelegram Pro</h2>
|
<h2 id="promoTitle" data-i18n="promoTitle">Support PCAtelegram_web</h2>
|
||||||
<div class="promo-grid">
|
<div class="promo-grid">
|
||||||
<a href="https://vk.cc/ct29NQ" target="_blank" rel="noreferrer">
|
<a href="https://vk.cc/ct29NQ" target="_blank" rel="noreferrer">
|
||||||
<strong data-i18n="promoHosting1">Hosting #1</strong>
|
<strong data-i18n="promoHosting1">Hosting #1</strong>
|
||||||
|
|||||||
26
bootstrap.sh
Normal file → Executable file
26
bootstrap.sh
Normal file → Executable file
@@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# GoTelegram Pro — bootstrap installer from this repository.
|
# PCAtelegram_web — bootstrap installer from this repository.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
GOTELEGRAM_BASE="${GOTELEGRAM_BASE:-https://raw.githubusercontent.com/andrey271192/gotelegram/main}"
|
PCATELEGRAM_WEB_BASE="${PCATELEGRAM_WEB_BASE:-https://raw.githubusercontent.com/andrey271192/PCAtelegram_web/main}"
|
||||||
INSTALL_DIR="${GOTELEGRAM_INSTALL_DIR:-/opt/gotelegram}"
|
INSTALL_DIR="${PCATELEGRAM_WEB_INSTALL_DIR:-/opt/pcatelegram_web}"
|
||||||
|
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
@@ -23,13 +23,13 @@ for cmd in curl jq; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
FILES=(
|
FILES=(
|
||||||
"install.sh" "install_gotelegram_bot.sh" "templates_catalog.json"
|
"install.sh" "install_pcatelegram_web_bot.sh" "templates_catalog.json"
|
||||||
"lib/common.sh" "lib/telemt.sh" "lib/telemt_config.sh" "lib/backup.sh"
|
"lib/common.sh" "lib/telemt.sh" "lib/telemt_config.sh" "lib/backup.sh"
|
||||||
"lib/website.sh" "lib/templates_catalog.sh" "lib/stats.sh" "lib/i18n.sh"
|
"lib/website.sh" "lib/templates_catalog.sh" "lib/stats.sh" "lib/i18n.sh"
|
||||||
"lib/lang/en.sh" "lib/lang/ru.sh"
|
"lib/lang/en.sh" "lib/lang/ru.sh"
|
||||||
"gotelegram-bot/bot.py" "gotelegram-bot/i18n.py"
|
"pcatelegram_web-bot/bot.py" "pcatelegram_web-bot/i18n.py"
|
||||||
"gotelegram-bot/lang/en.json" "gotelegram-bot/lang/ru.json"
|
"pcatelegram_web-bot/lang/en.json" "pcatelegram_web-bot/lang/ru.json"
|
||||||
"gotelegram-bot/config.example.env" "gotelegram-bot/requirements.txt" "gotelegram-bot/README.md"
|
"pcatelegram_web-bot/config.example.env" "pcatelegram_web-bot/requirements.txt" "pcatelegram_web-bot/README.md"
|
||||||
"admin-web/server.py" "admin-web/static/index.html" "admin-web/static/styles.css" "admin-web/static/app.js"
|
"admin-web/server.py" "admin-web/static/index.html" "admin-web/static/styles.css" "admin-web/static/app.js"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ download_file() {
|
|||||||
|
|
||||||
mkdir -p "$(dirname "$local_path")"
|
mkdir -p "$(dirname "$local_path")"
|
||||||
for attempt in 1 2 3; do
|
for attempt in 1 2 3; do
|
||||||
http_code=$(curl -sL "${curl_headers[@]}" -w "%{http_code}" -o "$local_path" "${GOTELEGRAM_BASE%/}/${remote_path}" 2>/dev/null || echo "000")
|
http_code=$(curl -sL "${curl_headers[@]}" -w "%{http_code}" -o "$local_path" "${PCATELEGRAM_WEB_BASE%/}/${remote_path}" 2>/dev/null || echo "000")
|
||||||
if [ "$http_code" = "200" ]; then
|
if [ "$http_code" = "200" ]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -56,8 +56,8 @@ download_file() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
echo -e " ${CYAN}↻${NC} Загрузка GoTelegram из ${GOTELEGRAM_BASE%/}..."
|
echo -e " ${CYAN}↻${NC} Загрузка PCAtelegram_web из ${PCATELEGRAM_WEB_BASE%/}..."
|
||||||
mkdir -p "${INSTALL_DIR}/lib/lang" "${INSTALL_DIR}/gotelegram-bot/lang" "${INSTALL_DIR}/admin-web/static"
|
mkdir -p "${INSTALL_DIR}/lib/lang" "${INSTALL_DIR}/pcatelegram_web-bot/lang" "${INSTALL_DIR}/admin-web/static"
|
||||||
|
|
||||||
failed=0
|
failed=0
|
||||||
for f in "${FILES[@]}"; do
|
for f in "${FILES[@]}"; do
|
||||||
@@ -69,10 +69,10 @@ for f in "${FILES[@]}"; do
|
|||||||
done
|
done
|
||||||
[ "$failed" -eq 0 ] || exit 1
|
[ "$failed" -eq 0 ] || exit 1
|
||||||
|
|
||||||
chmod +x "${INSTALL_DIR}/install.sh" "${INSTALL_DIR}/install_gotelegram_bot.sh"
|
chmod +x "${INSTALL_DIR}/install.sh" "${INSTALL_DIR}/install_pcatelegram_web_bot.sh"
|
||||||
chmod +x "${INSTALL_DIR}"/lib/*.sh
|
chmod +x "${INSTALL_DIR}"/lib/*.sh
|
||||||
chmod +x "${INSTALL_DIR}/admin-web/server.py" 2>/dev/null || true
|
chmod +x "${INSTALL_DIR}/admin-web/server.py" 2>/dev/null || true
|
||||||
sed -i 's/\r$//' "${INSTALL_DIR}/install.sh" "${INSTALL_DIR}/install_gotelegram_bot.sh" "${INSTALL_DIR}"/lib/*.sh "${INSTALL_DIR}"/lib/lang/*.sh 2>/dev/null || true
|
sed -i 's/\r$//' "${INSTALL_DIR}/install.sh" "${INSTALL_DIR}/install_pcatelegram_web_bot.sh" "${INSTALL_DIR}"/lib/*.sh "${INSTALL_DIR}"/lib/lang/*.sh 2>/dev/null || true
|
||||||
ln -sf "${INSTALL_DIR}/install.sh" /usr/local/bin/gotelegram
|
ln -sf "${INSTALL_DIR}/install.sh" /usr/local/bin/pcatelegram_web
|
||||||
|
|
||||||
exec bash "${INSTALL_DIR}/install.sh" "$@"
|
exec bash "${INSTALL_DIR}/install.sh" "$@"
|
||||||
|
|||||||
150
install.sh
Normal file → Executable file
150
install.sh
Normal file → Executable file
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# ══════════════════════════════════════════════════════════════════════════════
|
# ══════════════════════════════════════════════════════════════════════════════
|
||||||
# goTelegram Pro v2.5.0 — MTProxy powered by telemt (Rust + Tokio)
|
# PCAtelegram_web v2.5.0 — MTProxy powered by telemt (Rust + Tokio)
|
||||||
# Anti-DPI • Fake TLS • TCP Splice • JA3/JA4 Resistance • i18n (EN/RU)
|
# Anti-DPI • Fake TLS • TCP Splice • JA3/JA4 Resistance • i18n (EN/RU)
|
||||||
#
|
#
|
||||||
# Install:
|
# Install:
|
||||||
@@ -46,7 +46,7 @@ show_main_menu() {
|
|||||||
# ── Header (no right border — ANSI breaks alignment) ──
|
# ── Header (no right border — ANSI breaks alignment) ──
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}${CYAN}━${line}━${NC}"
|
echo -e " ${BOLD}${CYAN}━${line}━${NC}"
|
||||||
echo -e " ${BOLD}${WHITE} goTelegram Pro v${GOTELEGRAM_VERSION}${NC} ${DIM}— $(t dashboard_title)${NC}"
|
echo -e " ${BOLD}${WHITE} PCAtelegram_web v${PCATELEGRAM_WEB_VERSION}${NC} ${DIM}— $(t dashboard_title)${NC}"
|
||||||
echo -e " ${BOLD}${CYAN}━${line}━${NC}"
|
echo -e " ${BOLD}${CYAN}━${line}━${NC}"
|
||||||
|
|
||||||
# ── Service health ──
|
# ── Service health ──
|
||||||
@@ -239,7 +239,7 @@ menu_version() {
|
|||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}${WHITE}$(t version_title)${NC}"
|
echo -e " ${BOLD}${WHITE}$(t version_title)${NC}"
|
||||||
echo -e " ${DIM}$(printf '─%.0s' {1..54})${NC}"
|
echo -e " ${DIM}$(printf '─%.0s' {1..54})${NC}"
|
||||||
echo -e " ${WHITE}$(t version_label)${NC} v${GOTELEGRAM_VERSION}"
|
echo -e " ${WHITE}$(t version_label)${NC} v${PCATELEGRAM_WEB_VERSION}"
|
||||||
echo -e " ${WHITE}$(t version_engine)${NC} telemt (Rust + Tokio)"
|
echo -e " ${WHITE}$(t version_engine)${NC} telemt (Rust + Tokio)"
|
||||||
echo -e " ${WHITE}$(t version_tech)${NC} Anti-DPI, Fake TLS, TCP Splice"
|
echo -e " ${WHITE}$(t version_tech)${NC} Anti-DPI, Fake TLS, TCP Splice"
|
||||||
echo -e " ${WHITE}$(t version_license)${NC} MIT"
|
echo -e " ${WHITE}$(t version_license)${NC} MIT"
|
||||||
@@ -248,21 +248,21 @@ menu_version() {
|
|||||||
|
|
||||||
# ── Upgrade migration ────────────────────────────────────────────────────────
|
# ── Upgrade migration ────────────────────────────────────────────────────────
|
||||||
snapshot_preupgrade_state() {
|
snapshot_preupgrade_state() {
|
||||||
local marker="$GOTELEGRAM_DIR/.preupgrade_${GOTELEGRAM_VERSION}_done"
|
local marker="$PCATELEGRAM_WEB_DIR/.preupgrade_${PCATELEGRAM_WEB_VERSION}_done"
|
||||||
[ -f "$marker" ] && return 0
|
[ -f "$marker" ] && return 0
|
||||||
mkdir -p "$BACKUP_DIR"
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
local ts tmp archive
|
local ts tmp archive
|
||||||
ts=$(date +%Y%m%d_%H%M%S)
|
ts=$(date +%Y%m%d_%H%M%S)
|
||||||
tmp="/tmp/gotelegram_preupgrade_${ts}"
|
tmp="/tmp/pcatelegram_web_preupgrade_${ts}"
|
||||||
archive="$BACKUP_DIR/preupgrade_${GOTELEGRAM_VERSION}_${ts}.tar.gz"
|
archive="$BACKUP_DIR/preupgrade_${PCATELEGRAM_WEB_VERSION}_${ts}.tar.gz"
|
||||||
mkdir -p "$tmp"
|
mkdir -p "$tmp"
|
||||||
|
|
||||||
[ -f "$GOTELEGRAM_CONFIG" ] && mkdir -p "$tmp/opt/gotelegram" && cp "$GOTELEGRAM_CONFIG" "$tmp/opt/gotelegram/config.json" 2>/dev/null
|
[ -f "$PCATELEGRAM_WEB_CONFIG" ] && mkdir -p "$tmp/opt/pcatelegram_web" && cp "$PCATELEGRAM_WEB_CONFIG" "$tmp/opt/pcatelegram_web/config.json" 2>/dev/null
|
||||||
[ -f "$TELEMT_CONFIG" ] && mkdir -p "$tmp/etc/telemt" && cp "$TELEMT_CONFIG" "$tmp/etc/telemt/config.toml" 2>/dev/null
|
[ -f "$TELEMT_CONFIG" ] && mkdir -p "$tmp/etc/telemt" && cp "$TELEMT_CONFIG" "$tmp/etc/telemt/config.toml" 2>/dev/null
|
||||||
[ -f "$NGINX_SITE_CONF" ] && mkdir -p "$tmp/etc/nginx/sites-available" && cp "$NGINX_SITE_CONF" "$tmp/etc/nginx/sites-available/gotelegram" 2>/dev/null
|
[ -f "$NGINX_SITE_CONF" ] && mkdir -p "$tmp/etc/nginx/sites-available" && cp "$NGINX_SITE_CONF" "$tmp/etc/nginx/sites-available/pcatelegram_web" 2>/dev/null
|
||||||
[ -d "$WEBSITE_ROOT" ] && mkdir -p "$tmp/var/www/gotelegram-site" && cp -a "$WEBSITE_ROOT/." "$tmp/var/www/gotelegram-site/" 2>/dev/null
|
[ -d "$WEBSITE_ROOT" ] && mkdir -p "$tmp/var/www/pcatelegram_web-site" && cp -a "$WEBSITE_ROOT/." "$tmp/var/www/pcatelegram_web-site/" 2>/dev/null
|
||||||
[ -f "$BOT_DIR/.env" ] && mkdir -p "$tmp/opt/gotelegram-bot" && cp "$BOT_DIR/.env" "$tmp/opt/gotelegram-bot/.env" 2>/dev/null
|
[ -f "$BOT_DIR/.env" ] && mkdir -p "$tmp/opt/pcatelegram_web-bot" && cp "$BOT_DIR/.env" "$tmp/opt/pcatelegram_web-bot/.env" 2>/dev/null
|
||||||
|
|
||||||
if tar czf "$archive" -C "$tmp" . 2>/dev/null; then
|
if tar czf "$archive" -C "$tmp" . 2>/dev/null; then
|
||||||
log_dim "Pre-upgrade snapshot: $archive"
|
log_dim "Pre-upgrade snapshot: $archive"
|
||||||
@@ -278,8 +278,8 @@ read_config_or_default() {
|
|||||||
|
|
||||||
detect_deployed_template_id() {
|
detect_deployed_template_id() {
|
||||||
local tpl=""
|
local tpl=""
|
||||||
if [ -f "$WEBSITE_ROOT/.gotelegram_template_id" ]; then
|
if [ -f "$WEBSITE_ROOT/.pcatelegram_web_template_id" ]; then
|
||||||
tpl=$(head -1 "$WEBSITE_ROOT/.gotelegram_template_id" 2>/dev/null || echo "")
|
tpl=$(head -1 "$WEBSITE_ROOT/.pcatelegram_web_template_id" 2>/dev/null || echo "")
|
||||||
[ -n "$tpl" ] && { echo "$tpl"; return 0; }
|
[ -n "$tpl" ] && { echo "$tpl"; return 0; }
|
||||||
fi
|
fi
|
||||||
if [ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ]; then
|
if [ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ]; then
|
||||||
@@ -293,15 +293,15 @@ detect_deployed_template_id() {
|
|||||||
|
|
||||||
detect_template_source() {
|
detect_template_source() {
|
||||||
local src
|
local src
|
||||||
if [ -f "$WEBSITE_ROOT/.gotelegram_template_source" ]; then
|
if [ -f "$WEBSITE_ROOT/.pcatelegram_web_template_source" ]; then
|
||||||
src=$(head -1 "$WEBSITE_ROOT/.gotelegram_template_source" 2>/dev/null || echo "")
|
src=$(head -1 "$WEBSITE_ROOT/.pcatelegram_web_template_source" 2>/dev/null || echo "")
|
||||||
[ -n "$src" ] && { echo "$src"; return 0; }
|
[ -n "$src" ] && { echo "$src"; return 0; }
|
||||||
fi
|
fi
|
||||||
[ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ] && return 0
|
[ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ] && return 0
|
||||||
read_config_or_default template_source ""
|
read_config_or_default template_source ""
|
||||||
}
|
}
|
||||||
|
|
||||||
write_normalized_gotelegram_config() {
|
write_normalized_pcatelegram_web_config() {
|
||||||
local mode="$1" port="$2" secret="$3" mask_host="$4" domain="$5" tpl_id="$6" tpl_source="$7"
|
local mode="$1" port="$2" secret="$3" mask_host="$4" domain="$5" tpl_id="$6" tpl_source="$7"
|
||||||
local lang installed_at stats_enabled tmp
|
local lang installed_at stats_enabled tmp
|
||||||
lang=$(read_config_or_default language "$(get_language 2>/dev/null || echo en)")
|
lang=$(read_config_or_default language "$(get_language 2>/dev/null || echo en)")
|
||||||
@@ -310,7 +310,7 @@ write_normalized_gotelegram_config() {
|
|||||||
tmp=$(mktemp) || return 1
|
tmp=$(mktemp) || return 1
|
||||||
|
|
||||||
jq -n \
|
jq -n \
|
||||||
--arg version "$GOTELEGRAM_VERSION" \
|
--arg version "$PCATELEGRAM_WEB_VERSION" \
|
||||||
--arg engine "telemt" \
|
--arg engine "telemt" \
|
||||||
--arg mode "$mode" \
|
--arg mode "$mode" \
|
||||||
--argjson port "$port" \
|
--argjson port "$port" \
|
||||||
@@ -340,22 +340,22 @@ write_normalized_gotelegram_config() {
|
|||||||
+ (if $stats_enabled == "true" then {stats_enabled: true} elif $stats_enabled == "false" then {stats_enabled: false} else {} end)' \
|
+ (if $stats_enabled == "true" then {stats_enabled: true} elif $stats_enabled == "false" then {stats_enabled: false} else {} end)' \
|
||||||
> "$tmp" || { rm -f "$tmp"; return 1; }
|
> "$tmp" || { rm -f "$tmp"; return 1; }
|
||||||
|
|
||||||
mkdir -p "$(dirname "$GOTELEGRAM_CONFIG")"
|
mkdir -p "$(dirname "$PCATELEGRAM_WEB_CONFIG")"
|
||||||
mv "$tmp" "$GOTELEGRAM_CONFIG"
|
mv "$tmp" "$PCATELEGRAM_WEB_CONFIG"
|
||||||
chmod 600 "$GOTELEGRAM_CONFIG"
|
chmod 600 "$PCATELEGRAM_WEB_CONFIG"
|
||||||
}
|
}
|
||||||
|
|
||||||
auto_migrate_legacy_state() {
|
auto_migrate_legacy_state() {
|
||||||
local marker="$GOTELEGRAM_DIR/.migrated_${GOTELEGRAM_VERSION}"
|
local marker="$PCATELEGRAM_WEB_DIR/.migrated_${PCATELEGRAM_WEB_VERSION}"
|
||||||
local current_version
|
local current_version
|
||||||
current_version=$(read_config_or_default version "")
|
current_version=$(read_config_or_default version "")
|
||||||
if [ -f "$marker" ] && [ "$current_version" = "$GOTELEGRAM_VERSION" ]; then
|
if [ -f "$marker" ] && [ "$current_version" = "$PCATELEGRAM_WEB_VERSION" ]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ -f "$TELEMT_CONFIG" ] || [ -f "$GOTELEGRAM_CONFIG" ] || [ -d "$WEBSITE_ROOT" ] || return 0
|
[ -f "$TELEMT_CONFIG" ] || [ -f "$PCATELEGRAM_WEB_CONFIG" ] || [ -d "$WEBSITE_ROOT" ] || return 0
|
||||||
|
|
||||||
log_step "Миграция состояния goTelegram Pro"
|
log_step "Миграция состояния PCAtelegram_web"
|
||||||
snapshot_preupgrade_state
|
snapshot_preupgrade_state
|
||||||
|
|
||||||
local mode port secret mask_host domain mask_port tpl_id tpl_source users_block tls_emulation changed=0 users_block_needs_write=0
|
local mode port secret mask_host domain mask_port tpl_id tpl_source users_block tls_emulation changed=0 users_block_needs_write=0
|
||||||
@@ -405,14 +405,14 @@ auto_migrate_legacy_state() {
|
|||||||
tpl_id=$(detect_deployed_template_id)
|
tpl_id=$(detect_deployed_template_id)
|
||||||
tpl_source=$(detect_template_source || echo "")
|
tpl_source=$(detect_template_source || echo "")
|
||||||
if [ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ] && [ -n "$tpl_id" ]; then
|
if [ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ] && [ -n "$tpl_id" ]; then
|
||||||
echo "$tpl_id" > "$WEBSITE_ROOT/.gotelegram_template_id" 2>/dev/null || true
|
echo "$tpl_id" > "$WEBSITE_ROOT/.pcatelegram_web_template_id" 2>/dev/null || true
|
||||||
[ -n "$tpl_source" ] && echo "$tpl_source" > "$WEBSITE_ROOT/.gotelegram_template_source" 2>/dev/null || true
|
[ -n "$tpl_source" ] && echo "$tpl_source" > "$WEBSITE_ROOT/.pcatelegram_web_template_source" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f "$TELEMT_CONFIG" ]; then
|
if [ -f "$TELEMT_CONFIG" ]; then
|
||||||
if ! grep -q '\[server.api\]' "$TELEMT_CONFIG" 2>/dev/null || \
|
if ! grep -q '\[server.api\]' "$TELEMT_CONFIG" 2>/dev/null || \
|
||||||
! grep -q 'metrics_listen' "$TELEMT_CONFIG" 2>/dev/null || \
|
! grep -q 'metrics_listen' "$TELEMT_CONFIG" 2>/dev/null || \
|
||||||
! grep -q "goTelegram Pro v${GOTELEGRAM_VERSION}" "$TELEMT_CONFIG" 2>/dev/null; then
|
! grep -q "PCAtelegram_web v${PCATELEGRAM_WEB_VERSION}" "$TELEMT_CONFIG" 2>/dev/null; then
|
||||||
generate_telemt_toml "$secret" "$port" "$mode" "$mask_host" "$mask_port" "$TELEMT_CONFIG" >&2
|
generate_telemt_toml "$secret" "$port" "$mode" "$mask_host" "$mask_port" "$TELEMT_CONFIG" >&2
|
||||||
replace_telemt_users_block "$users_block" "$TELEMT_CONFIG"
|
replace_telemt_users_block "$users_block" "$TELEMT_CONFIG"
|
||||||
changed=1
|
changed=1
|
||||||
@@ -423,7 +423,7 @@ auto_migrate_legacy_state() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
write_normalized_gotelegram_config "$mode" "$port" "$secret" "$mask_host" "$domain" "$tpl_id" "$tpl_source" || \
|
write_normalized_pcatelegram_web_config "$mode" "$port" "$secret" "$mask_host" "$domain" "$tpl_id" "$tpl_source" || \
|
||||||
log_warning "Не удалось нормализовать config.json"
|
log_warning "Не удалось нормализовать config.json"
|
||||||
|
|
||||||
if [ "$changed" = "1" ] && systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then
|
if [ "$changed" = "1" ] && systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then
|
||||||
@@ -520,15 +520,15 @@ install_lite_mode() {
|
|||||||
# Start
|
# Start
|
||||||
start_telemt || return
|
start_telemt || return
|
||||||
|
|
||||||
# Save goTelegram Pro config
|
# Save PCAtelegram_web config
|
||||||
save_gotelegram_config "telemt" "lite" "$port" "$secret" "$domain" "" ""
|
save_pcatelegram_web_config "telemt" "lite" "$port" "$secret" "$domain" "" ""
|
||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
show_credits
|
show_credits
|
||||||
|
|
||||||
# Result
|
# Result
|
||||||
show_proxy_info
|
show_proxy_info
|
||||||
log_success "$(tf install_done "$GOTELEGRAM_VERSION" "Lite")"
|
log_success "$(tf install_done "$PCATELEGRAM_WEB_VERSION" "Lite")"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Pro mode ────────────────────────────────────────────────────────────────
|
# ── Pro mode ────────────────────────────────────────────────────────────────
|
||||||
@@ -620,12 +620,12 @@ install_pro_mode() {
|
|||||||
# Save config
|
# Save config
|
||||||
local tpl_id
|
local tpl_id
|
||||||
tpl_id=$(basename "$template_dir")
|
tpl_id=$(basename "$template_dir")
|
||||||
save_gotelegram_config "telemt" "pro" "443" "$raw_secret" "$user_domain" "$user_domain" "$tpl_id"
|
save_pcatelegram_web_config "telemt" "pro" "443" "$raw_secret" "$user_domain" "$user_domain" "$tpl_id"
|
||||||
|
|
||||||
# Result — use domain and fake-TLS link
|
# Result — use domain and fake-TLS link
|
||||||
show_proxy_info_pro "$user_domain" "$faketls_secret"
|
show_proxy_info_pro "$user_domain" "$faketls_secret"
|
||||||
echo -e " ${WHITE}$(t svc_site):${NC} ${GREEN}https://${user_domain}${NC}"
|
echo -e " ${WHITE}$(t svc_site):${NC} ${GREEN}https://${user_domain}${NC}"
|
||||||
log_success "$(tf install_done "$GOTELEGRAM_VERSION" "Pro")"
|
log_success "$(tf install_done "$PCATELEGRAM_WEB_VERSION" "Pro")"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Статус ───────────────────────────────────────────────────────────────────
|
# ── Статус ───────────────────────────────────────────────────────────────────
|
||||||
@@ -699,7 +699,7 @@ menu_share() {
|
|||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}$(t share_title)${NC}"
|
echo -e " ${BOLD}$(t share_title)${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
printf "$(t share_line1)\n" "$GOTELEGRAM_VERSION"
|
printf "$(t share_line1)\n" "$PCATELEGRAM_WEB_VERSION"
|
||||||
echo ""
|
echo ""
|
||||||
printf "$(t share_server)\n" "$server_display"
|
printf "$(t share_server)\n" "$server_display"
|
||||||
printf "$(t share_port)\n" "$port"
|
printf "$(t share_port)\n" "$port"
|
||||||
@@ -842,7 +842,7 @@ menu_remove() {
|
|||||||
if [ "$mode" = "pro" ]; then
|
if [ "$mode" = "pro" ]; then
|
||||||
remove_pro_mode
|
remove_pro_mode
|
||||||
fi
|
fi
|
||||||
rm -f "$GOTELEGRAM_CONFIG"
|
rm -f "$PCATELEGRAM_WEB_CONFIG"
|
||||||
log_success "$(t remove_proxy_done)"
|
log_success "$(t remove_proxy_done)"
|
||||||
;;
|
;;
|
||||||
2)
|
2)
|
||||||
@@ -861,7 +861,7 @@ menu_remove() {
|
|||||||
if [ "$mode" = "pro" ]; then
|
if [ "$mode" = "pro" ]; then
|
||||||
remove_pro_mode
|
remove_pro_mode
|
||||||
fi
|
fi
|
||||||
rm -f "$GOTELEGRAM_CONFIG"
|
rm -f "$PCATELEGRAM_WEB_CONFIG"
|
||||||
# Bot
|
# Bot
|
||||||
if [ "$(bot_service_status)" != "not_installed" ]; then
|
if [ "$(bot_service_status)" != "not_installed" ]; then
|
||||||
systemctl stop "$BOT_SERVICE" 2>/dev/null
|
systemctl stop "$BOT_SERVICE" 2>/dev/null
|
||||||
@@ -877,8 +877,8 @@ menu_remove() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ── Telegram-бот ────────────────────────────────────────────────────────────
|
# ── Telegram-бот ────────────────────────────────────────────────────────────
|
||||||
BOT_DIR="/opt/gotelegram-bot"
|
BOT_DIR="/opt/pcatelegram_web-bot"
|
||||||
BOT_SERVICE="gotelegram-bot"
|
BOT_SERVICE="pcatelegram_web-bot"
|
||||||
|
|
||||||
admin_web_service_status() {
|
admin_web_service_status() {
|
||||||
if ! systemctl list-unit-files "$ADMIN_WEB_SERVICE.service" &>/dev/null 2>&1; then
|
if ! systemctl list-unit-files "$ADMIN_WEB_SERVICE.service" &>/dev/null 2>&1; then
|
||||||
@@ -906,7 +906,7 @@ install_admin_web() {
|
|||||||
python_bin=$(command -v python3)
|
python_bin=$(command -v python3)
|
||||||
cat > "/etc/systemd/system/${ADMIN_WEB_SERVICE}.service" << SVCEOF
|
cat > "/etc/systemd/system/${ADMIN_WEB_SERVICE}.service" << SVCEOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=goTelegram Pro v${GOTELEGRAM_VERSION} Local Web Admin
|
Description=PCAtelegram_web v${PCATELEGRAM_WEB_VERSION} Local Web Admin
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
@@ -915,8 +915,8 @@ WorkingDirectory=$ADMIN_WEB_DIR
|
|||||||
ExecStart=$python_bin $ADMIN_WEB_DIR/server.py
|
ExecStart=$python_bin $ADMIN_WEB_DIR/server.py
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
Environment=GOTELEGRAM_ADMIN_HOST=$ADMIN_WEB_HOST
|
Environment=PCATELEGRAM_WEB_ADMIN_HOST=$ADMIN_WEB_HOST
|
||||||
Environment=GOTELEGRAM_ADMIN_PORT=$ADMIN_WEB_PORT
|
Environment=PCATELEGRAM_WEB_ADMIN_PORT=$ADMIN_WEB_PORT
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
@@ -964,20 +964,20 @@ bot_service_status() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto_update_bot_if_possible() {
|
auto_update_bot_if_possible() {
|
||||||
[ -d "$SCRIPT_DIR/gotelegram-bot" ] || return 0
|
[ -d "$SCRIPT_DIR/pcatelegram_web-bot" ] || return 0
|
||||||
[ "$(bot_service_status)" = "not_installed" ] && return 0
|
[ "$(bot_service_status)" = "not_installed" ] && return 0
|
||||||
[ -f "$BOT_DIR/.env" ] || return 0
|
[ -f "$BOT_DIR/.env" ] || return 0
|
||||||
|
|
||||||
local needs_update=0
|
local needs_update=0
|
||||||
[ -f "$SCRIPT_DIR/gotelegram-bot/bot.py" ] && \
|
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" ] && \
|
||||||
! cmp -s "$SCRIPT_DIR/gotelegram-bot/bot.py" "$BOT_DIR/bot.py" && needs_update=1
|
! cmp -s "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" "$BOT_DIR/bot.py" && needs_update=1
|
||||||
[ -f "$SCRIPT_DIR/gotelegram-bot/i18n.py" ] && \
|
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/i18n.py" ] && \
|
||||||
! cmp -s "$SCRIPT_DIR/gotelegram-bot/i18n.py" "$BOT_DIR/i18n.py" && needs_update=1
|
! cmp -s "$SCRIPT_DIR/pcatelegram_web-bot/i18n.py" "$BOT_DIR/i18n.py" && needs_update=1
|
||||||
[ -f "$SCRIPT_DIR/gotelegram-bot/requirements.txt" ] && \
|
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/requirements.txt" ] && \
|
||||||
! cmp -s "$SCRIPT_DIR/gotelegram-bot/requirements.txt" "$BOT_DIR/requirements.txt" && needs_update=1
|
! cmp -s "$SCRIPT_DIR/pcatelegram_web-bot/requirements.txt" "$BOT_DIR/requirements.txt" && needs_update=1
|
||||||
|
|
||||||
local lang_file lang_name
|
local lang_file lang_name
|
||||||
for lang_file in "$SCRIPT_DIR"/gotelegram-bot/lang/*.json; do
|
for lang_file in "$SCRIPT_DIR"/pcatelegram_web-bot/lang/*.json; do
|
||||||
[ -e "$lang_file" ] || continue
|
[ -e "$lang_file" ] || continue
|
||||||
lang_name=$(basename "$lang_file")
|
lang_name=$(basename "$lang_file")
|
||||||
! cmp -s "$lang_file" "$BOT_DIR/lang/$lang_name" && needs_update=1
|
! cmp -s "$lang_file" "$BOT_DIR/lang/$lang_name" && needs_update=1
|
||||||
@@ -1101,27 +1101,27 @@ bot_install() {
|
|||||||
|
|
||||||
# Copy bot files
|
# Copy bot files
|
||||||
mkdir -p "$BOT_DIR"
|
mkdir -p "$BOT_DIR"
|
||||||
if [ -f "$SCRIPT_DIR/gotelegram-bot/bot.py" ]; then
|
if [ -f "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" ]; then
|
||||||
cp "$SCRIPT_DIR/gotelegram-bot/bot.py" "$BOT_DIR/"
|
cp "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" "$BOT_DIR/"
|
||||||
cp "$SCRIPT_DIR/gotelegram-bot/requirements.txt" "$BOT_DIR/"
|
cp "$SCRIPT_DIR/pcatelegram_web-bot/requirements.txt" "$BOT_DIR/"
|
||||||
[ -f "$SCRIPT_DIR/gotelegram-bot/config.example.env" ] && \
|
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/config.example.env" ] && \
|
||||||
cp "$SCRIPT_DIR/gotelegram-bot/config.example.env" "$BOT_DIR/"
|
cp "$SCRIPT_DIR/pcatelegram_web-bot/config.example.env" "$BOT_DIR/"
|
||||||
# Copy i18n language files for bot
|
# Copy i18n language files for bot
|
||||||
if [ -d "$SCRIPT_DIR/gotelegram-bot/lang" ]; then
|
if [ -d "$SCRIPT_DIR/pcatelegram_web-bot/lang" ]; then
|
||||||
mkdir -p "$BOT_DIR/lang"
|
mkdir -p "$BOT_DIR/lang"
|
||||||
cp -f "$SCRIPT_DIR/gotelegram-bot/lang/"*.json "$BOT_DIR/lang/" 2>/dev/null
|
cp -f "$SCRIPT_DIR/pcatelegram_web-bot/lang/"*.json "$BOT_DIR/lang/" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
[ -f "$SCRIPT_DIR/gotelegram-bot/i18n.py" ] && \
|
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/i18n.py" ] && \
|
||||||
cp "$SCRIPT_DIR/gotelegram-bot/i18n.py" "$BOT_DIR/"
|
cp "$SCRIPT_DIR/pcatelegram_web-bot/i18n.py" "$BOT_DIR/"
|
||||||
else
|
else
|
||||||
log_error "$(tf bot_files_not_found "$SCRIPT_DIR/gotelegram-bot/")"
|
log_error "$(tf bot_files_not_found "$SCRIPT_DIR/pcatelegram_web-bot/")"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Templates catalog — skip if source and dest are the same file (symlink install case)
|
# Templates catalog — skip if source and dest are the same file (symlink install case)
|
||||||
if [ -f "$SCRIPT_DIR/templates_catalog.json" ]; then
|
if [ -f "$SCRIPT_DIR/templates_catalog.json" ]; then
|
||||||
local src_tc="$SCRIPT_DIR/templates_catalog.json"
|
local src_tc="$SCRIPT_DIR/templates_catalog.json"
|
||||||
local dst_tc="$GOTELEGRAM_DIR/templates_catalog.json"
|
local dst_tc="$PCATELEGRAM_WEB_DIR/templates_catalog.json"
|
||||||
if [ "$(readlink -f "$src_tc" 2>/dev/null)" != "$(readlink -f "$dst_tc" 2>/dev/null)" ]; then
|
if [ "$(readlink -f "$src_tc" 2>/dev/null)" != "$(readlink -f "$dst_tc" 2>/dev/null)" ]; then
|
||||||
cp "$src_tc" "$dst_tc"
|
cp "$src_tc" "$dst_tc"
|
||||||
fi
|
fi
|
||||||
@@ -1217,7 +1217,7 @@ bot_install() {
|
|||||||
# Systemd
|
# Systemd
|
||||||
cat > "/etc/systemd/system/${BOT_SERVICE}.service" << SVCEOF
|
cat > "/etc/systemd/system/${BOT_SERVICE}.service" << SVCEOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=goTelegram Pro v${GOTELEGRAM_VERSION} Telegram Bot
|
Description=PCAtelegram_web v${PCATELEGRAM_WEB_VERSION} Telegram Bot
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
@@ -1407,7 +1407,7 @@ bot_remove() {
|
|||||||
_promo_block() {
|
_promo_block() {
|
||||||
# Print a promo section without width-fragile box borders (i18n safe)
|
# Print a promo section without width-fragile box borders (i18n safe)
|
||||||
local line2; line2=$(printf '─%.0s' {1..54})
|
local line2; line2=$(printf '─%.0s' {1..54})
|
||||||
local youtube_link="${GOTELEGRAM_YOUTUBE_LINK:-}"
|
local youtube_link="${PCATELEGRAM_WEB_YOUTUBE_LINK:-}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${DIM}${line2}${NC}"
|
echo -e " ${DIM}${line2}${NC}"
|
||||||
echo -e " ${BOLD}${YELLOW}$(t promo_host1_title)${NC}"
|
echo -e " ${BOLD}${YELLOW}$(t promo_host1_title)${NC}"
|
||||||
@@ -1437,7 +1437,7 @@ menu_promo() {
|
|||||||
|
|
||||||
# ── Проверка: показывать ли промо (раз в сутки) ────────────────────────────
|
# ── Проверка: показывать ли промо (раз в сутки) ────────────────────────────
|
||||||
should_show_promo() {
|
should_show_promo() {
|
||||||
local stamp_file="$GOTELEGRAM_DIR/.promo_last_shown"
|
local stamp_file="$PCATELEGRAM_WEB_DIR/.promo_last_shown"
|
||||||
if [ ! -f "$stamp_file" ]; then
|
if [ ! -f "$stamp_file" ]; then
|
||||||
return 0 # никогда не показывали
|
return 0 # никогда не показывали
|
||||||
fi
|
fi
|
||||||
@@ -1452,8 +1452,8 @@ should_show_promo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mark_promo_shown() {
|
mark_promo_shown() {
|
||||||
mkdir -p "$GOTELEGRAM_DIR"
|
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||||
date +%s > "$GOTELEGRAM_DIR/.promo_last_shown"
|
date +%s > "$PCATELEGRAM_WEB_DIR/.promo_last_shown"
|
||||||
}
|
}
|
||||||
|
|
||||||
_promo_qr() {
|
_promo_qr() {
|
||||||
@@ -1473,7 +1473,7 @@ show_promo_with_qr() {
|
|||||||
_promo_qr "$(t promo_qr_host1)" "https://vk.cc/ct29NQ"
|
_promo_qr "$(t promo_qr_host1)" "https://vk.cc/ct29NQ"
|
||||||
_promo_qr "$(t promo_qr_host2)" "https://vk.cc/cUxAhj"
|
_promo_qr "$(t promo_qr_host2)" "https://vk.cc/cUxAhj"
|
||||||
_promo_qr "$(t promo_qr_tips)" "https://pay.cloudtips.ru/p/7410814f"
|
_promo_qr "$(t promo_qr_tips)" "https://pay.cloudtips.ru/p/7410814f"
|
||||||
_promo_qr "$(t promo_qr_youtube)" "${GOTELEGRAM_YOUTUBE_LINK:-}"
|
_promo_qr "$(t promo_qr_youtube)" "${PCATELEGRAM_WEB_YOUTUBE_LINK:-}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mark_promo_shown
|
mark_promo_shown
|
||||||
@@ -1489,10 +1489,10 @@ show_promo_with_qr() {
|
|||||||
# ── First-run: pick language ─────────────────────────────────────────────────
|
# ── First-run: pick language ─────────────────────────────────────────────────
|
||||||
first_run_language_picker() {
|
first_run_language_picker() {
|
||||||
# Show picker only if language not yet saved
|
# Show picker only if language not yet saved
|
||||||
local marker="${GOTELEGRAM_DIR:-/opt/gotelegram}/.language"
|
local marker="${PCATELEGRAM_WEB_DIR:-/opt/pcatelegram_web}/.language"
|
||||||
local cfg_lang=""
|
local cfg_lang=""
|
||||||
if [ -f "$GOTELEGRAM_CONFIG" ] && command -v jq >/dev/null 2>&1; then
|
if [ -f "$PCATELEGRAM_WEB_CONFIG" ] && command -v jq >/dev/null 2>&1; then
|
||||||
cfg_lang=$(jq -r '.language // empty' "$GOTELEGRAM_CONFIG" 2>/dev/null)
|
cfg_lang=$(jq -r '.language // empty' "$PCATELEGRAM_WEB_CONFIG" 2>/dev/null)
|
||||||
fi
|
fi
|
||||||
if [ -f "$marker" ] || [ -n "$cfg_lang" ]; then
|
if [ -f "$marker" ] || [ -n "$cfg_lang" ]; then
|
||||||
return 0
|
return 0
|
||||||
@@ -1524,8 +1524,8 @@ menu_language() {
|
|||||||
# Non-interactive action dispatcher (bot / CI / scripting interface)
|
# Non-interactive action dispatcher (bot / CI / scripting interface)
|
||||||
# ══════════════════════════════════════════════════════════════════════════════
|
# ══════════════════════════════════════════════════════════════════════════════
|
||||||
# Usage examples:
|
# Usage examples:
|
||||||
# gotelegram --action=change-template --template=th_ariclaw --json
|
# pcatelegram_web --action=change-template --template=th_ariclaw --json
|
||||||
# gotelegram --action=change-lite-domain --domain=google.com --json
|
# pcatelegram_web --action=change-lite-domain --domain=google.com --json
|
||||||
#
|
#
|
||||||
# Rules for action handlers:
|
# Rules for action handlers:
|
||||||
# - Only JSON may be written to stdout (the caller parses it).
|
# - Only JSON may be written to stdout (the caller parses it).
|
||||||
@@ -1558,7 +1558,7 @@ bot_emit_json() {
|
|||||||
bot_update_config_field() {
|
bot_update_config_field() {
|
||||||
local key="$1"
|
local key="$1"
|
||||||
local value="$2"
|
local value="$2"
|
||||||
if [ ! -f "$GOTELEGRAM_CONFIG" ]; then
|
if [ ! -f "$PCATELEGRAM_WEB_CONFIG" ]; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
local tmp now
|
local tmp now
|
||||||
@@ -1566,9 +1566,9 @@ bot_update_config_field() {
|
|||||||
now=$(date -Iseconds 2>/dev/null || date +%Y-%m-%dT%H:%M:%S%z)
|
now=$(date -Iseconds 2>/dev/null || date +%Y-%m-%dT%H:%M:%S%z)
|
||||||
if jq --arg k "$key" --arg v "$value" --arg t "$now" \
|
if jq --arg k "$key" --arg v "$value" --arg t "$now" \
|
||||||
'.[$k] = $v | .updated_at = $t' \
|
'.[$k] = $v | .updated_at = $t' \
|
||||||
"$GOTELEGRAM_CONFIG" > "$tmp" 2>/dev/null; then
|
"$PCATELEGRAM_WEB_CONFIG" > "$tmp" 2>/dev/null; then
|
||||||
mv "$tmp" "$GOTELEGRAM_CONFIG"
|
mv "$tmp" "$PCATELEGRAM_WEB_CONFIG"
|
||||||
chmod 600 "$GOTELEGRAM_CONFIG"
|
chmod 600 "$PCATELEGRAM_WEB_CONFIG"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
rm -f "$tmp"
|
rm -f "$tmp"
|
||||||
@@ -1713,7 +1713,7 @@ bot_action_change_lite_domain() {
|
|||||||
# parallel `change-lite-domain` calls raced on the jq-rewrite of config.json
|
# parallel `change-lite-domain` calls raced on the jq-rewrite of config.json
|
||||||
# and one process would see a truncated file ("no secret in config").
|
# and one process would see a truncated file ("no secret in config").
|
||||||
bot_action_dispatch() {
|
bot_action_dispatch() {
|
||||||
local lock_file="/var/lock/gotelegram-bot-action.lock"
|
local lock_file="/var/lock/pcatelegram_web-bot-action.lock"
|
||||||
# Make sure /var/lock exists (it does on Debian/Ubuntu; be defensive for minimal images)
|
# Make sure /var/lock exists (it does on Debian/Ubuntu; be defensive for minimal images)
|
||||||
[ -d /var/lock ] || mkdir -p /var/lock 2>/dev/null || true
|
[ -d /var/lock ] || mkdir -p /var/lock 2>/dev/null || true
|
||||||
|
|
||||||
|
|||||||
36
install_gotelegram_bot.sh → install_pcatelegram_web_bot.sh
Normal file → Executable file
36
install_gotelegram_bot.sh → install_pcatelegram_web_bot.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# GoTelegram v2.5.0 — Установка Telegram-бота
|
# PCAtelegram_web v2.5.0 — Установка Telegram-бота
|
||||||
# Создаёт venv, ставит зависимости, настраивает systemd
|
# Создаёт venv, ставит зависимости, настраивает systemd
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@@ -9,11 +9,11 @@ YELLOW='\033[1;33m'
|
|||||||
CYAN='\033[0;36m'
|
CYAN='\033[0;36m'
|
||||||
NC='\033[0m'
|
NC='\033[0m'
|
||||||
|
|
||||||
BOT_DIR="/opt/gotelegram-bot"
|
BOT_DIR="/opt/pcatelegram_web-bot"
|
||||||
SERVICE_NAME="gotelegram-bot"
|
SERVICE_NAME="pcatelegram_web-bot"
|
||||||
GOTELEGRAM_DIR="/opt/gotelegram"
|
PCATELEGRAM_WEB_DIR="/opt/pcatelegram_web"
|
||||||
ADMIN_WEB_DIR="/opt/gotelegram-admin"
|
ADMIN_WEB_DIR="/opt/pcatelegram_web-admin"
|
||||||
ADMIN_WEB_SERVICE="gotelegram-admin"
|
ADMIN_WEB_SERVICE="pcatelegram_web-admin"
|
||||||
ADMIN_WEB_PORT="1984"
|
ADMIN_WEB_PORT="1984"
|
||||||
|
|
||||||
if [ "$EUID" -ne 0 ]; then
|
if [ "$EUID" -ne 0 ]; then
|
||||||
@@ -22,7 +22,7 @@ if [ "$EUID" -ne 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "${CYAN}╔═══════════════════════════════════════════╗${NC}"
|
echo -e "${CYAN}╔═══════════════════════════════════════════╗${NC}"
|
||||||
echo -e "${CYAN}║${NC} ${GREEN}GoTelegram v2.5.0 — Установка бота${NC} ${CYAN}║${NC}"
|
echo -e "${CYAN}║${NC} ${GREEN}PCAtelegram_web v2.5.0 — Установка бота${NC} ${CYAN}║${NC}"
|
||||||
echo -e "${CYAN}╚═══════════════════════════════════════════╝${NC}"
|
echo -e "${CYAN}╚═══════════════════════════════════════════╝${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
@@ -44,20 +44,20 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
[ -f "$SCRIPT_DIR/lib/common.sh" ] && source "$SCRIPT_DIR/lib/common.sh" || true
|
[ -f "$SCRIPT_DIR/lib/common.sh" ] && source "$SCRIPT_DIR/lib/common.sh" || true
|
||||||
[ -f "$SCRIPT_DIR/lib/stats.sh" ] && source "$SCRIPT_DIR/lib/stats.sh" || true
|
[ -f "$SCRIPT_DIR/lib/stats.sh" ] && source "$SCRIPT_DIR/lib/stats.sh" || true
|
||||||
|
|
||||||
if [ -f "$SCRIPT_DIR/gotelegram-bot/bot.py" ]; then
|
if [ -f "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" ]; then
|
||||||
echo -e "${GREEN}[*] Копирование файлов бота...${NC}"
|
echo -e "${GREEN}[*] Копирование файлов бота...${NC}"
|
||||||
cp "$SCRIPT_DIR/gotelegram-bot/bot.py" "$BOT_DIR/"
|
cp "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" "$BOT_DIR/"
|
||||||
cp "$SCRIPT_DIR/gotelegram-bot/requirements.txt" "$BOT_DIR/"
|
cp "$SCRIPT_DIR/pcatelegram_web-bot/requirements.txt" "$BOT_DIR/"
|
||||||
[ -f "$SCRIPT_DIR/gotelegram-bot/config.example.env" ] && cp "$SCRIPT_DIR/gotelegram-bot/config.example.env" "$BOT_DIR/"
|
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/config.example.env" ] && cp "$SCRIPT_DIR/pcatelegram_web-bot/config.example.env" "$BOT_DIR/"
|
||||||
else
|
else
|
||||||
echo -e "${RED}Файлы бота не найдены в $SCRIPT_DIR/gotelegram-bot/${NC}"
|
echo -e "${RED}Файлы бота не найдены в $SCRIPT_DIR/pcatelegram_web-bot/${NC}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Копируем каталог шаблонов
|
# Копируем каталог шаблонов
|
||||||
if [ -f "$SCRIPT_DIR/templates_catalog.json" ]; then
|
if [ -f "$SCRIPT_DIR/templates_catalog.json" ]; then
|
||||||
mkdir -p "$GOTELEGRAM_DIR"
|
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||||
cp "$SCRIPT_DIR/templates_catalog.json" "$GOTELEGRAM_DIR/"
|
cp "$SCRIPT_DIR/templates_catalog.json" "$PCATELEGRAM_WEB_DIR/"
|
||||||
echo -e "${GREEN}[*] Каталог шаблонов скопирован${NC}"
|
echo -e "${GREEN}[*] Каталог шаблонов скопирован${NC}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ fi
|
|||||||
# ── Systemd ──────────────────────────────────────────────────────────────────
|
# ── Systemd ──────────────────────────────────────────────────────────────────
|
||||||
cat > "/etc/systemd/system/${SERVICE_NAME}.service" << EOF
|
cat > "/etc/systemd/system/${SERVICE_NAME}.service" << EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=GoTelegram v2.5.0 Telegram Bot
|
Description=PCAtelegram_web v2.5.0 Telegram Bot
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
@@ -130,7 +130,7 @@ if [ -f "$SCRIPT_DIR/admin-web/server.py" ]; then
|
|||||||
PYTHON_BIN=$(command -v python3)
|
PYTHON_BIN=$(command -v python3)
|
||||||
cat > "/etc/systemd/system/${ADMIN_WEB_SERVICE}.service" << EOF
|
cat > "/etc/systemd/system/${ADMIN_WEB_SERVICE}.service" << EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=GoTelegram v2.5.0 Local Web Admin
|
Description=PCAtelegram_web v2.5.0 Local Web Admin
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
@@ -139,8 +139,8 @@ WorkingDirectory=$ADMIN_WEB_DIR
|
|||||||
ExecStart=$PYTHON_BIN $ADMIN_WEB_DIR/server.py
|
ExecStart=$PYTHON_BIN $ADMIN_WEB_DIR/server.py
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
Environment=GOTELEGRAM_ADMIN_HOST=127.0.0.1
|
Environment=PCATELEGRAM_WEB_ADMIN_HOST=127.0.0.1
|
||||||
Environment=GOTELEGRAM_ADMIN_PORT=$ADMIN_WEB_PORT
|
Environment=PCATELEGRAM_WEB_ADMIN_PORT=$ADMIN_WEB_PORT
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
142
lib/backup.sh
Normal file → Executable file
142
lib/backup.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# goTelegram Pro v2.5.0 — backup and restore (i18n-aware)
|
# PCAtelegram_web v2.5.0 — backup and restore (i18n-aware)
|
||||||
|
|
||||||
# ── Создание бекапа ──────────────────────────────────────────────────────────
|
# ── Создание бекапа ──────────────────────────────────────────────────────────
|
||||||
create_backup() {
|
create_backup() {
|
||||||
@@ -12,9 +12,9 @@ create_backup() {
|
|||||||
mkdir -p "$output_dir"
|
mkdir -p "$output_dir"
|
||||||
while true; do
|
while true; do
|
||||||
if [ "$suffix" -eq 0 ]; then
|
if [ "$suffix" -eq 0 ]; then
|
||||||
backup_name="gotelegram_backup_${timestamp}"
|
backup_name="pcatelegram_web_backup_${timestamp}"
|
||||||
else
|
else
|
||||||
backup_name="gotelegram_backup_${timestamp}_${suffix}"
|
backup_name="pcatelegram_web_backup_${timestamp}_${suffix}"
|
||||||
fi
|
fi
|
||||||
tmp_dir="/tmp/${backup_name}"
|
tmp_dir="/tmp/${backup_name}"
|
||||||
if [ ! -e "$tmp_dir" ] && \
|
if [ ! -e "$tmp_dir" ] && \
|
||||||
@@ -34,20 +34,20 @@ create_backup() {
|
|||||||
cp "$TELEMT_CONFIG" "$tmp_dir/config.toml"
|
cp "$TELEMT_CONFIG" "$tmp_dir/config.toml"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# goTelegram Pro конфиг
|
# PCAtelegram_web конфиг
|
||||||
if [ -f "$GOTELEGRAM_CONFIG" ]; then
|
if [ -f "$PCATELEGRAM_WEB_CONFIG" ]; then
|
||||||
cp "$GOTELEGRAM_CONFIG" "$tmp_dir/gotelegram.json"
|
cp "$PCATELEGRAM_WEB_CONFIG" "$tmp_dir/pcatelegram_web.json"
|
||||||
fi
|
fi
|
||||||
if [ -f "$GOTELEGRAM_DIR/disabled_users.json" ]; then
|
if [ -f "$PCATELEGRAM_WEB_DIR/disabled_users.json" ]; then
|
||||||
cp "$GOTELEGRAM_DIR/disabled_users.json" "$tmp_dir/disabled_users.json" 2>/dev/null
|
cp "$PCATELEGRAM_WEB_DIR/disabled_users.json" "$tmp_dir/disabled_users.json" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
if [ -f "$GOTELEGRAM_DIR/backup_schedule.json" ]; then
|
if [ -f "$PCATELEGRAM_WEB_DIR/backup_schedule.json" ]; then
|
||||||
cp "$GOTELEGRAM_DIR/backup_schedule.json" "$tmp_dir/backup_schedule.json" 2>/dev/null
|
cp "$PCATELEGRAM_WEB_DIR/backup_schedule.json" "$tmp_dir/backup_schedule.json" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Language marker (i18n)
|
# Language marker (i18n)
|
||||||
if [ -f "$GOTELEGRAM_DIR/.language" ]; then
|
if [ -f "$PCATELEGRAM_WEB_DIR/.language" ]; then
|
||||||
cp "$GOTELEGRAM_DIR/.language" "$tmp_dir/.language"
|
cp "$PCATELEGRAM_WEB_DIR/.language" "$tmp_dir/.language"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# nginx конфиг (stealth mode)
|
# nginx конфиг (stealth mode)
|
||||||
@@ -76,12 +76,12 @@ create_backup() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Custom templates and catalog
|
# Custom templates and catalog
|
||||||
if [ -d "$GOTELEGRAM_DIR/custom_templates" ]; then
|
if [ -d "$PCATELEGRAM_WEB_DIR/custom_templates" ]; then
|
||||||
mkdir -p "$tmp_dir/custom_templates"
|
mkdir -p "$tmp_dir/custom_templates"
|
||||||
cp -a "$GOTELEGRAM_DIR/custom_templates/." "$tmp_dir/custom_templates/" 2>/dev/null
|
cp -a "$PCATELEGRAM_WEB_DIR/custom_templates/." "$tmp_dir/custom_templates/" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
if [ -f "$GOTELEGRAM_DIR/templates_catalog.json" ]; then
|
if [ -f "$PCATELEGRAM_WEB_DIR/templates_catalog.json" ]; then
|
||||||
cp "$GOTELEGRAM_DIR/templates_catalog.json" "$tmp_dir/templates_catalog.json" 2>/dev/null
|
cp "$PCATELEGRAM_WEB_DIR/templates_catalog.json" "$tmp_dir/templates_catalog.json" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Bot state (.env has BotFather token, so encrypted backups are strongly recommended)
|
# Bot state (.env has BotFather token, so encrypted backups are strongly recommended)
|
||||||
@@ -100,14 +100,14 @@ create_backup() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Traffic history
|
# Traffic history
|
||||||
if [ -f "$GOTELEGRAM_DIR/stats_history.csv" ]; then
|
if [ -f "$PCATELEGRAM_WEB_DIR/stats_history.csv" ]; then
|
||||||
cp "$GOTELEGRAM_DIR/stats_history.csv" "$tmp_dir/stats_history.csv" 2>/dev/null
|
cp "$PCATELEGRAM_WEB_DIR/stats_history.csv" "$tmp_dir/stats_history.csv" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
if [ -f "$GOTELEGRAM_DIR/user_stats_history.csv" ]; then
|
if [ -f "$PCATELEGRAM_WEB_DIR/user_stats_history.csv" ]; then
|
||||||
cp "$GOTELEGRAM_DIR/user_stats_history.csv" "$tmp_dir/user_stats_history.csv" 2>/dev/null
|
cp "$PCATELEGRAM_WEB_DIR/user_stats_history.csv" "$tmp_dir/user_stats_history.csv" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
if [ -f "$GOTELEGRAM_DIR/shared-443.json" ]; then
|
if [ -f "$PCATELEGRAM_WEB_DIR/shared-443.json" ]; then
|
||||||
cp "$GOTELEGRAM_DIR/shared-443.json" "$tmp_dir/shared-443.json" 2>/dev/null
|
cp "$PCATELEGRAM_WEB_DIR/shared-443.json" "$tmp_dir/shared-443.json" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Метаданные
|
# Метаданные
|
||||||
@@ -124,7 +124,7 @@ create_backup() {
|
|||||||
cat > "$tmp_dir/metadata.json" << EOMETA
|
cat > "$tmp_dir/metadata.json" << EOMETA
|
||||||
{
|
{
|
||||||
"backup_version": "1.6",
|
"backup_version": "1.6",
|
||||||
"gotelegram_version": "$GOTELEGRAM_VERSION",
|
"pcatelegram_web_version": "$PCATELEGRAM_WEB_VERSION",
|
||||||
"created_at": "$(date -Iseconds)",
|
"created_at": "$(date -Iseconds)",
|
||||||
"hostname": "$(hostname)",
|
"hostname": "$(hostname)",
|
||||||
"ip": "$ip",
|
"ip": "$ip",
|
||||||
@@ -201,7 +201,7 @@ restore_backup() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local tmp_dir="/tmp/gotelegram_restore_$$"
|
local tmp_dir="/tmp/pcatelegram_web_restore_$$"
|
||||||
mkdir -p "$tmp_dir"
|
mkdir -p "$tmp_dir"
|
||||||
|
|
||||||
# Расшифровываем если нужно
|
# Расшифровываем если нужно
|
||||||
@@ -212,7 +212,7 @@ restore_backup() {
|
|||||||
read -rs password
|
read -rs password
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
tar_file="/tmp/gotelegram_restore_$$.tar.gz"
|
tar_file="/tmp/pcatelegram_web_restore_$$.tar.gz"
|
||||||
openssl enc -aes-256-cbc -d -pbkdf2 -in "$backup_file" -out "$tar_file" -pass "pass:${password}" 2>/dev/null
|
openssl enc -aes-256-cbc -d -pbkdf2 -in "$backup_file" -out "$tar_file" -pass "pass:${password}" 2>/dev/null
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
log_error "$(_t_or backup_bad_pass 'Неверный пароль или повреждённый файл')"
|
log_error "$(_t_or backup_bad_pass 'Неверный пароль или повреждённый файл')"
|
||||||
@@ -233,25 +233,25 @@ restore_backup() {
|
|||||||
|
|
||||||
# Находим папку бекапа
|
# Находим папку бекапа
|
||||||
local backup_dir
|
local backup_dir
|
||||||
backup_dir=$(find "$tmp_dir" -maxdepth 1 -type d -name "gotelegram_backup_*" | head -1)
|
backup_dir=$(find "$tmp_dir" -maxdepth 1 -type d -name "pcatelegram_web_backup_*" | head -1)
|
||||||
[ -z "$backup_dir" ] && backup_dir="$tmp_dir"
|
[ -z "$backup_dir" ] && backup_dir="$tmp_dir"
|
||||||
|
|
||||||
# Legacy bot backups before v2.5.0 stored absolute paths directly in tar:
|
# Legacy bot backups before v2.5.0 stored absolute paths directly in tar:
|
||||||
# opt/gotelegram/config.json and etc/telemt/config.toml.
|
# opt/pcatelegram_web/config.json and etc/telemt/config.toml.
|
||||||
if [ ! -f "$backup_dir/config.toml" ] && [ -f "$tmp_dir/etc/telemt/config.toml" ]; then
|
if [ ! -f "$backup_dir/config.toml" ] && [ -f "$tmp_dir/etc/telemt/config.toml" ]; then
|
||||||
cp "$tmp_dir/etc/telemt/config.toml" "$backup_dir/config.toml" 2>/dev/null || true
|
cp "$tmp_dir/etc/telemt/config.toml" "$backup_dir/config.toml" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
if [ ! -f "$backup_dir/gotelegram.json" ] && [ -f "$tmp_dir/opt/gotelegram/config.json" ]; then
|
if [ ! -f "$backup_dir/pcatelegram_web.json" ] && [ -f "$tmp_dir/opt/pcatelegram_web/config.json" ]; then
|
||||||
cp "$tmp_dir/opt/gotelegram/config.json" "$backup_dir/gotelegram.json" 2>/dev/null || true
|
cp "$tmp_dir/opt/pcatelegram_web/config.json" "$backup_dir/pcatelegram_web.json" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
if [ ! -f "$backup_dir/disabled_users.json" ] && [ -f "$tmp_dir/opt/gotelegram/disabled_users.json" ]; then
|
if [ ! -f "$backup_dir/disabled_users.json" ] && [ -f "$tmp_dir/opt/pcatelegram_web/disabled_users.json" ]; then
|
||||||
cp "$tmp_dir/opt/gotelegram/disabled_users.json" "$backup_dir/disabled_users.json" 2>/dev/null || true
|
cp "$tmp_dir/opt/pcatelegram_web/disabled_users.json" "$backup_dir/disabled_users.json" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Проверяем метаданные
|
# Проверяем метаданные
|
||||||
if [ -f "$backup_dir/metadata.json" ]; then
|
if [ -f "$backup_dir/metadata.json" ]; then
|
||||||
local bk_version bk_mode bk_ip bk_lang bk_date
|
local bk_version bk_mode bk_ip bk_lang bk_date
|
||||||
bk_version=$(jq -r '.gotelegram_version // "unknown"' "$backup_dir/metadata.json")
|
bk_version=$(jq -r '.pcatelegram_web_version // "unknown"' "$backup_dir/metadata.json")
|
||||||
bk_mode=$(jq -r '.mode // "unknown"' "$backup_dir/metadata.json")
|
bk_mode=$(jq -r '.mode // "unknown"' "$backup_dir/metadata.json")
|
||||||
bk_ip=$(jq -r '.ip // "unknown"' "$backup_dir/metadata.json")
|
bk_ip=$(jq -r '.ip // "unknown"' "$backup_dir/metadata.json")
|
||||||
bk_lang=$(jq -r '.language // "-"' "$backup_dir/metadata.json")
|
bk_lang=$(jq -r '.language // "-"' "$backup_dir/metadata.json")
|
||||||
@@ -280,24 +280,24 @@ restore_backup() {
|
|||||||
log_success "$(_t_or backup_restored_telemt 'telemt конфиг восстановлен')"
|
log_success "$(_t_or backup_restored_telemt 'telemt конфиг восстановлен')"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Восстанавливаем goTelegram Pro конфиг
|
# Восстанавливаем PCAtelegram_web конфиг
|
||||||
if [ -f "$backup_dir/gotelegram.json" ]; then
|
if [ -f "$backup_dir/pcatelegram_web.json" ]; then
|
||||||
mkdir -p "$GOTELEGRAM_DIR"
|
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||||
cp "$backup_dir/gotelegram.json" "$GOTELEGRAM_CONFIG"
|
cp "$backup_dir/pcatelegram_web.json" "$PCATELEGRAM_WEB_CONFIG"
|
||||||
log_success "$(_t_or backup_restored_gotelegram 'GoTelegram конфиг восстановлен')"
|
log_success "$(_t_or backup_restored_pcatelegram_web 'PCAtelegram_web конфиг восстановлен')"
|
||||||
fi
|
fi
|
||||||
if [ -f "$backup_dir/disabled_users.json" ]; then
|
if [ -f "$backup_dir/disabled_users.json" ]; then
|
||||||
mkdir -p "$GOTELEGRAM_DIR"
|
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||||
cp "$backup_dir/disabled_users.json" "$GOTELEGRAM_DIR/disabled_users.json"
|
cp "$backup_dir/disabled_users.json" "$PCATELEGRAM_WEB_DIR/disabled_users.json"
|
||||||
chmod 600 "$GOTELEGRAM_DIR/disabled_users.json" 2>/dev/null || true
|
chmod 600 "$PCATELEGRAM_WEB_DIR/disabled_users.json" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
if [ -f "$backup_dir/backup_schedule.json" ]; then
|
if [ -f "$backup_dir/backup_schedule.json" ]; then
|
||||||
mkdir -p "$GOTELEGRAM_DIR"
|
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||||
cp "$backup_dir/backup_schedule.json" "$GOTELEGRAM_DIR/backup_schedule.json" 2>/dev/null
|
cp "$backup_dir/backup_schedule.json" "$PCATELEGRAM_WEB_DIR/backup_schedule.json" 2>/dev/null
|
||||||
chmod 600 "$GOTELEGRAM_DIR/backup_schedule.json" 2>/dev/null || true
|
chmod 600 "$PCATELEGRAM_WEB_DIR/backup_schedule.json" 2>/dev/null || true
|
||||||
if command -v jq >/dev/null 2>&1; then
|
if command -v jq >/dev/null 2>&1; then
|
||||||
local restored_schedule
|
local restored_schedule
|
||||||
restored_schedule=$(jq -r '.frequency // "off"' "$GOTELEGRAM_DIR/backup_schedule.json" 2>/dev/null || echo "off")
|
restored_schedule=$(jq -r '.frequency // "off"' "$PCATELEGRAM_WEB_DIR/backup_schedule.json" 2>/dev/null || echo "off")
|
||||||
case "$restored_schedule" in
|
case "$restored_schedule" in
|
||||||
off|daily|weekly|monthly) set_backup_schedule "$restored_schedule" >/dev/null 2>&1 || true ;;
|
off|daily|weekly|monthly) set_backup_schedule "$restored_schedule" >/dev/null 2>&1 || true ;;
|
||||||
esac
|
esac
|
||||||
@@ -306,8 +306,8 @@ restore_backup() {
|
|||||||
|
|
||||||
# Восстанавливаем language marker (i18n)
|
# Восстанавливаем language marker (i18n)
|
||||||
if [ -f "$backup_dir/.language" ]; then
|
if [ -f "$backup_dir/.language" ]; then
|
||||||
mkdir -p "$GOTELEGRAM_DIR"
|
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||||
cp "$backup_dir/.language" "$GOTELEGRAM_DIR/.language"
|
cp "$backup_dir/.language" "$PCATELEGRAM_WEB_DIR/.language"
|
||||||
log_success "$(_t_or backup_restored_lang 'Язык интерфейса восстановлен')"
|
log_success "$(_t_or backup_restored_lang 'Язык интерфейса восстановлен')"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -347,23 +347,23 @@ restore_backup() {
|
|||||||
|
|
||||||
# Восстанавливаем custom templates/catalog/statistics
|
# Восстанавливаем custom templates/catalog/statistics
|
||||||
if [ -d "$backup_dir/custom_templates" ]; then
|
if [ -d "$backup_dir/custom_templates" ]; then
|
||||||
mkdir -p "$GOTELEGRAM_DIR/custom_templates"
|
mkdir -p "$PCATELEGRAM_WEB_DIR/custom_templates"
|
||||||
cp -a "$backup_dir/custom_templates/." "$GOTELEGRAM_DIR/custom_templates/" 2>/dev/null
|
cp -a "$backup_dir/custom_templates/." "$PCATELEGRAM_WEB_DIR/custom_templates/" 2>/dev/null
|
||||||
log_success "Пользовательские шаблоны восстановлены"
|
log_success "Пользовательские шаблоны восстановлены"
|
||||||
fi
|
fi
|
||||||
if [ -f "$backup_dir/templates_catalog.json" ]; then
|
if [ -f "$backup_dir/templates_catalog.json" ]; then
|
||||||
cp "$backup_dir/templates_catalog.json" "$GOTELEGRAM_DIR/templates_catalog.json" 2>/dev/null
|
cp "$backup_dir/templates_catalog.json" "$PCATELEGRAM_WEB_DIR/templates_catalog.json" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
if [ -f "$backup_dir/stats_history.csv" ]; then
|
if [ -f "$backup_dir/stats_history.csv" ]; then
|
||||||
cp "$backup_dir/stats_history.csv" "$GOTELEGRAM_DIR/stats_history.csv" 2>/dev/null
|
cp "$backup_dir/stats_history.csv" "$PCATELEGRAM_WEB_DIR/stats_history.csv" 2>/dev/null
|
||||||
log_success "История статистики восстановлена"
|
log_success "История статистики восстановлена"
|
||||||
fi
|
fi
|
||||||
if [ -f "$backup_dir/user_stats_history.csv" ]; then
|
if [ -f "$backup_dir/user_stats_history.csv" ]; then
|
||||||
cp "$backup_dir/user_stats_history.csv" "$GOTELEGRAM_DIR/user_stats_history.csv" 2>/dev/null
|
cp "$backup_dir/user_stats_history.csv" "$PCATELEGRAM_WEB_DIR/user_stats_history.csv" 2>/dev/null
|
||||||
log_success "История статистики пользователей восстановлена"
|
log_success "История статистики пользователей восстановлена"
|
||||||
fi
|
fi
|
||||||
if [ -f "$backup_dir/shared-443.json" ]; then
|
if [ -f "$backup_dir/shared-443.json" ]; then
|
||||||
cp "$backup_dir/shared-443.json" "$GOTELEGRAM_DIR/shared-443.json" 2>/dev/null
|
cp "$backup_dir/shared-443.json" "$PCATELEGRAM_WEB_DIR/shared-443.json" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Восстанавливаем состояние бота
|
# Восстанавливаем состояние бота
|
||||||
@@ -392,8 +392,8 @@ restore_backup() {
|
|||||||
start_telemt
|
start_telemt
|
||||||
fi
|
fi
|
||||||
command -v nginx &>/dev/null && systemctl start nginx 2>/dev/null
|
command -v nginx &>/dev/null && systemctl start nginx 2>/dev/null
|
||||||
systemctl restart gotelegram-bot 2>/dev/null || true
|
systemctl restart pcatelegram_web-bot 2>/dev/null || true
|
||||||
systemctl restart gotelegram-admin 2>/dev/null || true
|
systemctl restart pcatelegram_web-admin 2>/dev/null || true
|
||||||
|
|
||||||
# Очистка
|
# Очистка
|
||||||
rm -rf "$tmp_dir"
|
rm -rf "$tmp_dir"
|
||||||
@@ -469,43 +469,43 @@ set_backup_schedule() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$GOTELEGRAM_DIR" "$BACKUP_DIR"
|
mkdir -p "$PCATELEGRAM_WEB_DIR" "$BACKUP_DIR"
|
||||||
|
|
||||||
if [ "$frequency" = "off" ]; then
|
if [ "$frequency" = "off" ]; then
|
||||||
systemctl disable --now gotelegram-backup.timer >/dev/null 2>&1 || true
|
systemctl disable --now pcatelegram_web-backup.timer >/dev/null 2>&1 || true
|
||||||
rm -f /etc/systemd/system/gotelegram-backup.timer /etc/systemd/system/gotelegram-backup.service
|
rm -f /etc/systemd/system/pcatelegram_web-backup.timer /etc/systemd/system/pcatelegram_web-backup.service
|
||||||
systemctl daemon-reload >/dev/null 2>&1 || true
|
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||||
else
|
else
|
||||||
cat > /etc/systemd/system/gotelegram-backup.service << 'EOSVC'
|
cat > /etc/systemd/system/pcatelegram_web-backup.service << 'EOSVC'
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=goTelegram Pro backup
|
Description=PCAtelegram_web backup
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
Environment=GOTELEGRAM_BACKUP_KEEP=30
|
Environment=PCATELEGRAM_WEB_BACKUP_KEEP=30
|
||||||
ExecStart=/bin/bash -lc 'source /opt/gotelegram/lib/common.sh; source /opt/gotelegram/lib/i18n.sh; source /opt/gotelegram/lib/telemt.sh; source /opt/gotelegram/lib/website.sh; source /opt/gotelegram/lib/backup.sh; load_language "$(detect_language 2>/dev/null || echo en)"; create_backup ""; cleanup_old_backups "${GOTELEGRAM_BACKUP_KEEP:-30}"'
|
ExecStart=/bin/bash -lc 'source /opt/pcatelegram_web/lib/common.sh; source /opt/pcatelegram_web/lib/i18n.sh; source /opt/pcatelegram_web/lib/telemt.sh; source /opt/pcatelegram_web/lib/website.sh; source /opt/pcatelegram_web/lib/backup.sh; load_language "$(detect_language 2>/dev/null || echo en)"; create_backup ""; cleanup_old_backups "${PCATELEGRAM_WEB_BACKUP_KEEP:-30}"'
|
||||||
EOSVC
|
EOSVC
|
||||||
|
|
||||||
cat > /etc/systemd/system/gotelegram-backup.timer << EOTIMER
|
cat > /etc/systemd/system/pcatelegram_web-backup.timer << EOTIMER
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=goTelegram Pro scheduled backup
|
Description=PCAtelegram_web scheduled backup
|
||||||
|
|
||||||
[Timer]
|
[Timer]
|
||||||
OnCalendar=$calendar
|
OnCalendar=$calendar
|
||||||
Persistent=true
|
Persistent=true
|
||||||
RandomizedDelaySec=15m
|
RandomizedDelaySec=15m
|
||||||
Unit=gotelegram-backup.service
|
Unit=pcatelegram_web-backup.service
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=timers.target
|
WantedBy=timers.target
|
||||||
EOTIMER
|
EOTIMER
|
||||||
systemctl daemon-reload >/dev/null 2>&1 || return 1
|
systemctl daemon-reload >/dev/null 2>&1 || return 1
|
||||||
systemctl enable --now gotelegram-backup.timer >/dev/null 2>&1 || return 1
|
systemctl enable --now pcatelegram_web-backup.timer >/dev/null 2>&1 || return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat > "$GOTELEGRAM_DIR/backup_schedule.json" << EOSCHEDULE
|
cat > "$PCATELEGRAM_WEB_DIR/backup_schedule.json" << EOSCHEDULE
|
||||||
{
|
{
|
||||||
"frequency": "$frequency",
|
"frequency": "$frequency",
|
||||||
"calendar": "$calendar",
|
"calendar": "$calendar",
|
||||||
@@ -513,19 +513,19 @@ EOTIMER
|
|||||||
"updated_at": "$(date -Iseconds)"
|
"updated_at": "$(date -Iseconds)"
|
||||||
}
|
}
|
||||||
EOSCHEDULE
|
EOSCHEDULE
|
||||||
chmod 600 "$GOTELEGRAM_DIR/backup_schedule.json" 2>/dev/null || true
|
chmod 600 "$PCATELEGRAM_WEB_DIR/backup_schedule.json" 2>/dev/null || true
|
||||||
log_success "Backup schedule: $frequency"
|
log_success "Backup schedule: $frequency"
|
||||||
echo "$frequency"
|
echo "$frequency"
|
||||||
}
|
}
|
||||||
|
|
||||||
backup_schedule_status() {
|
backup_schedule_status() {
|
||||||
local frequency="off" calendar=""
|
local frequency="off" calendar=""
|
||||||
if [ -f "$GOTELEGRAM_DIR/backup_schedule.json" ] && command -v jq >/dev/null 2>&1; then
|
if [ -f "$PCATELEGRAM_WEB_DIR/backup_schedule.json" ] && command -v jq >/dev/null 2>&1; then
|
||||||
frequency=$(jq -r '.frequency // "off"' "$GOTELEGRAM_DIR/backup_schedule.json" 2>/dev/null || echo "off")
|
frequency=$(jq -r '.frequency // "off"' "$PCATELEGRAM_WEB_DIR/backup_schedule.json" 2>/dev/null || echo "off")
|
||||||
calendar=$(jq -r '.calendar // ""' "$GOTELEGRAM_DIR/backup_schedule.json" 2>/dev/null || echo "")
|
calendar=$(jq -r '.calendar // ""' "$PCATELEGRAM_WEB_DIR/backup_schedule.json" 2>/dev/null || echo "")
|
||||||
fi
|
fi
|
||||||
echo "frequency=$frequency calendar=$calendar"
|
echo "frequency=$frequency calendar=$calendar"
|
||||||
systemctl list-timers gotelegram-backup.timer --no-pager 2>/dev/null || true
|
systemctl list-timers pcatelegram_web-backup.timer --no-pager 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Интерактивный бекап ──────────────────────────────────────────────────────
|
# ── Интерактивный бекап ──────────────────────────────────────────────────────
|
||||||
|
|||||||
96
lib/common.sh
Normal file → Executable file
96
lib/common.sh
Normal file → Executable file
@@ -1,32 +1,32 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# goTelegram Pro v2.5.0 — common utilities
|
# PCAtelegram_web v2.5.0 — common utilities
|
||||||
# Colors, logging, spinner, system helpers, v1 compat, i18n-aware
|
# Colors, logging, spinner, system helpers, v1 compat, i18n-aware
|
||||||
|
|
||||||
# ── Version ───────────────────────────────────────────────────────────────────
|
# ── Version ───────────────────────────────────────────────────────────────────
|
||||||
GOTELEGRAM_VERSION="2.5.0"
|
PCATELEGRAM_WEB_VERSION="2.5.0"
|
||||||
GOTELEGRAM_NAME="goTelegram Pro"
|
PCATELEGRAM_WEB_NAME="PCAtelegram_web"
|
||||||
|
|
||||||
# ── Пути ──────────────────────────────────────────────────────────────────────
|
# ── Пути ──────────────────────────────────────────────────────────────────────
|
||||||
GOTELEGRAM_DIR="/opt/gotelegram"
|
PCATELEGRAM_WEB_DIR="/opt/pcatelegram_web"
|
||||||
GOTELEGRAM_CONFIG="$GOTELEGRAM_DIR/config.json"
|
PCATELEGRAM_WEB_CONFIG="$PCATELEGRAM_WEB_DIR/config.json"
|
||||||
TELEMT_CONFIG="/etc/telemt/config.toml"
|
TELEMT_CONFIG="/etc/telemt/config.toml"
|
||||||
TELEMT_BIN="/usr/local/bin/telemt"
|
TELEMT_BIN="/usr/local/bin/telemt"
|
||||||
TELEMT_SERVICE="telemt"
|
TELEMT_SERVICE="telemt"
|
||||||
NGINX_SITE_CONF="/etc/nginx/sites-available/gotelegram"
|
NGINX_SITE_CONF="/etc/nginx/sites-available/pcatelegram_web"
|
||||||
NGINX_SITE_LINK="/etc/nginx/sites-enabled/gotelegram"
|
NGINX_SITE_LINK="/etc/nginx/sites-enabled/pcatelegram_web"
|
||||||
WEBSITE_ROOT="/var/www/gotelegram-site"
|
WEBSITE_ROOT="/var/www/pcatelegram_web-site"
|
||||||
BACKUP_DIR="$GOTELEGRAM_DIR/backups"
|
BACKUP_DIR="$PCATELEGRAM_WEB_DIR/backups"
|
||||||
LOG_FILE="/var/log/gotelegram.log"
|
LOG_FILE="/var/log/pcatelegram_web.log"
|
||||||
BOT_DIR="/opt/gotelegram-bot"
|
BOT_DIR="/opt/pcatelegram_web-bot"
|
||||||
ADMIN_WEB_DIR="/opt/gotelegram-admin"
|
ADMIN_WEB_DIR="/opt/pcatelegram_web-admin"
|
||||||
ADMIN_WEB_SERVICE="gotelegram-admin"
|
ADMIN_WEB_SERVICE="pcatelegram_web-admin"
|
||||||
ADMIN_WEB_HOST="127.0.0.1"
|
ADMIN_WEB_HOST="127.0.0.1"
|
||||||
ADMIN_WEB_PORT="1984"
|
ADMIN_WEB_PORT="1984"
|
||||||
|
|
||||||
# ── V1 совместимость ─────────────────────────────────────────────────────────
|
# ── V1 совместимость ─────────────────────────────────────────────────────────
|
||||||
V1_CONTAINER_NAME="mtproto-proxy"
|
V1_CONTAINER_NAME="mtproto-proxy"
|
||||||
V1_CONFIG_FILE="/opt/gotelegram-bot/proxy.json"
|
V1_CONFIG_FILE="/opt/pcatelegram_web-bot/proxy.json"
|
||||||
V1_SERVICE_NAME="gotelegram-bot"
|
V1_SERVICE_NAME="pcatelegram_web-bot"
|
||||||
|
|
||||||
# ── Цвета ────────────────────────────────────────────────────────────────────
|
# ── Цвета ────────────────────────────────────────────────────────────────────
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
@@ -93,7 +93,7 @@ progress_bar() {
|
|||||||
# ── Выполнение с индикатором ─────────────────────────────────────────────────
|
# ── Выполнение с индикатором ─────────────────────────────────────────────────
|
||||||
run_with_spinner() {
|
run_with_spinner() {
|
||||||
local label="$1"; shift
|
local label="$1"; shift
|
||||||
local err_file="/tmp/.gotelegram_spinner_err_$$"
|
local err_file="/tmp/.pcatelegram_web_spinner_err_$$"
|
||||||
spinner_start "$label"
|
spinner_start "$label"
|
||||||
"$@" >/dev/null 2>"$err_file"
|
"$@" >/dev/null 2>"$err_file"
|
||||||
local rc=$?
|
local rc=$?
|
||||||
@@ -119,11 +119,11 @@ show_banner() {
|
|||||||
echo ""
|
echo ""
|
||||||
echo -e "${CYAN}${line}${NC}"
|
echo -e "${CYAN}${line}${NC}"
|
||||||
if type tf &>/dev/null; then
|
if type tf &>/dev/null; then
|
||||||
echo -e " ${BOLD}${WHITE}🚀 $(tf banner_title "$GOTELEGRAM_VERSION")${NC}"
|
echo -e " ${BOLD}${WHITE}🚀 $(tf banner_title "$PCATELEGRAM_WEB_VERSION")${NC}"
|
||||||
echo -e " ${DIM}$(t banner_subtitle)${NC}"
|
echo -e " ${DIM}$(t banner_subtitle)${NC}"
|
||||||
echo -e " ${DIM}$(t banner_features)${NC}"
|
echo -e " ${DIM}$(t banner_features)${NC}"
|
||||||
else
|
else
|
||||||
echo -e " ${BOLD}${WHITE}🚀 goTelegram Pro v${GOTELEGRAM_VERSION}${NC}"
|
echo -e " ${BOLD}${WHITE}🚀 PCAtelegram_web v${PCATELEGRAM_WEB_VERSION}${NC}"
|
||||||
echo -e " ${DIM}MTProxy powered by telemt (Rust + Tokio)${NC}"
|
echo -e " ${DIM}MTProxy powered by telemt (Rust + Tokio)${NC}"
|
||||||
echo -e " ${DIM}Anti-DPI • Fake TLS • TCP Splice • JA3/JA4${NC}"
|
echo -e " ${DIM}Anti-DPI • Fake TLS • TCP Splice • JA3/JA4${NC}"
|
||||||
fi
|
fi
|
||||||
@@ -306,7 +306,7 @@ apt_update() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Зависимости GoTelegram ──────────────────────────────────────────────────
|
# ── Зависимости PCAtelegram_web ──────────────────────────────────────────────────
|
||||||
# Полный список внешних команд, которые скрипт использует. Для каждой команды
|
# Полный список внешних команд, которые скрипт использует. Для каждой команды
|
||||||
# указан пакет на apt и dnf/yum (имена различаются: например dig = dnsutils на
|
# указан пакет на apt и dnf/yum (имена различаются: например dig = dnsutils на
|
||||||
# Debian, bind-utils на RHEL).
|
# Debian, bind-utils на RHEL).
|
||||||
@@ -429,7 +429,7 @@ ensure_deps() {
|
|||||||
|
|
||||||
if [ ${#still_missing[@]} -gt 0 ]; then
|
if [ ${#still_missing[@]} -gt 0 ]; then
|
||||||
log_error "Critical dependencies still missing: ${still_missing[*]}"
|
log_error "Critical dependencies still missing: ${still_missing[*]}"
|
||||||
log_error "Install manually and re-run gotelegram"
|
log_error "Install manually and re-run pcatelegram_web"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -483,32 +483,32 @@ detect_3xui_443_listener() {
|
|||||||
warn_3xui_443_conflict() {
|
warn_3xui_443_conflict() {
|
||||||
detect_3xui_443_listener || return 1
|
detect_3xui_443_listener || return 1
|
||||||
log_warning "Обнаружен 3x-ui/Xray, который уже слушает TCP/443."
|
log_warning "Обнаружен 3x-ui/Xray, который уже слушает TCP/443."
|
||||||
log_warning "goTelegram Pro не будет молча останавливать или переписывать 3x-ui."
|
log_warning "PCAtelegram_web не будет молча останавливать или переписывать 3x-ui."
|
||||||
log_dim "Для настоящего shared-443 нужен один фронтовой TLS/SNI-диспетчер и разные SNI-домены для Xray и goTelegram Pro."
|
log_dim "Для настоящего shared-443 нужен один фронтовой TLS/SNI-диспетчер и разные SNI-домены для Xray и PCAtelegram_web."
|
||||||
mkdir -p "$GOTELEGRAM_DIR" 2>/dev/null
|
mkdir -p "$PCATELEGRAM_WEB_DIR" 2>/dev/null
|
||||||
cat > "$GOTELEGRAM_DIR/shared-443-3xui.md" <<'EOF' 2>/dev/null || true
|
cat > "$PCATELEGRAM_WEB_DIR/shared-443-3xui.md" <<'EOF' 2>/dev/null || true
|
||||||
# goTelegram Pro + 3x-ui on one TCP/443
|
# PCAtelegram_web + 3x-ui on one TCP/443
|
||||||
|
|
||||||
goTelegram Pro detected that 3x-ui/Xray already owns TCP/443. Two independent
|
PCAtelegram_web detected that 3x-ui/Xray already owns TCP/443. Two independent
|
||||||
processes cannot bind the same IP:port at the same time. A safe shared setup
|
processes cannot bind the same IP:port at the same time. A safe shared setup
|
||||||
needs one front TLS/SNI dispatcher on 443 and internal backends, for example:
|
needs one front TLS/SNI dispatcher on 443 and internal backends, for example:
|
||||||
|
|
||||||
- dispatcher: 0.0.0.0:443 (nginx stream ssl_preread)
|
- dispatcher: 0.0.0.0:443 (nginx stream ssl_preread)
|
||||||
- goTelegram Pro telemt: 127.0.0.1:7443
|
- PCAtelegram_web telemt: 127.0.0.1:7443
|
||||||
- 3x-ui/Xray inbound: 127.0.0.1:9443
|
- 3x-ui/Xray inbound: 127.0.0.1:9443
|
||||||
- goTelegram Pro nginx mask site: 127.0.0.1:8443
|
- PCAtelegram_web nginx mask site: 127.0.0.1:8443
|
||||||
|
|
||||||
The dispatcher routes Xray SNI domains to Xray. Everything else goes to telemt;
|
The dispatcher routes Xray SNI domains to Xray. Everything else goes to telemt;
|
||||||
telemt then decides whether the session is MTProxy or regular HTTPS and forwards
|
telemt then decides whether the session is MTProxy or regular HTTPS and forwards
|
||||||
the website to nginx through dns_overrides.
|
the website to nginx through dns_overrides.
|
||||||
|
|
||||||
goTelegram Pro can generate the dispatcher with:
|
PCAtelegram_web can generate the dispatcher with:
|
||||||
|
|
||||||
source /opt/gotelegram/lib/shared443.sh
|
source /opt/pcatelegram_web/lib/shared443.sh
|
||||||
shared443_enable <gotelegram-domain> <xray-sni-domain> 127.0.0.1:9443
|
shared443_enable <pcatelegram_web-domain> <xray-sni-domain> 127.0.0.1:9443
|
||||||
|
|
||||||
Move the 3x-ui/Xray inbound from 0.0.0.0:443 to 127.0.0.1:9443 in the panel first,
|
Move the 3x-ui/Xray inbound from 0.0.0.0:443 to 127.0.0.1:9443 in the panel first,
|
||||||
or nginx will not be able to own the public 443 socket. goTelegram Pro intentionally
|
or nginx will not be able to own the public 443 socket. PCAtelegram_web intentionally
|
||||||
does not rewrite the 3x-ui SQLite database or generated Xray config without explicit
|
does not rewrite the 3x-ui SQLite database or generated Xray config without explicit
|
||||||
operator confirmation, because 3x-ui can overwrite manual JSON edits on the next
|
operator confirmation, because 3x-ui can overwrite manual JSON edits on the next
|
||||||
panel change.
|
panel change.
|
||||||
@@ -531,14 +531,14 @@ check_disk_space() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Конфигурация GoTelegram (JSON) ──────────────────────────────────────────
|
# ── Конфигурация PCAtelegram_web (JSON) ──────────────────────────────────────────
|
||||||
save_gotelegram_config() {
|
save_pcatelegram_web_config() {
|
||||||
mkdir -p "$(dirname "$GOTELEGRAM_CONFIG")"
|
mkdir -p "$(dirname "$PCATELEGRAM_WEB_CONFIG")"
|
||||||
local cur_lang
|
local cur_lang
|
||||||
cur_lang=$(type get_language &>/dev/null && get_language || echo en)
|
cur_lang=$(type get_language &>/dev/null && get_language || echo en)
|
||||||
cat > "$GOTELEGRAM_CONFIG" << EOJSON
|
cat > "$PCATELEGRAM_WEB_CONFIG" << EOJSON
|
||||||
{
|
{
|
||||||
"version": "$GOTELEGRAM_VERSION",
|
"version": "$PCATELEGRAM_WEB_VERSION",
|
||||||
"engine": "${1:-telemt}",
|
"engine": "${1:-telemt}",
|
||||||
"mode": "${2:-lite}",
|
"mode": "${2:-lite}",
|
||||||
"port": ${3:-443},
|
"port": ${3:-443},
|
||||||
@@ -551,12 +551,12 @@ save_gotelegram_config() {
|
|||||||
"updated_at": "$(date -Iseconds)"
|
"updated_at": "$(date -Iseconds)"
|
||||||
}
|
}
|
||||||
EOJSON
|
EOJSON
|
||||||
chmod 600 "$GOTELEGRAM_CONFIG"
|
chmod 600 "$PCATELEGRAM_WEB_CONFIG"
|
||||||
}
|
}
|
||||||
|
|
||||||
load_gotelegram_config() {
|
load_pcatelegram_web_config() {
|
||||||
if [ -f "$GOTELEGRAM_CONFIG" ]; then
|
if [ -f "$PCATELEGRAM_WEB_CONFIG" ]; then
|
||||||
cat "$GOTELEGRAM_CONFIG"
|
cat "$PCATELEGRAM_WEB_CONFIG"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
echo "{}"
|
echo "{}"
|
||||||
@@ -565,11 +565,11 @@ load_gotelegram_config() {
|
|||||||
|
|
||||||
config_get() {
|
config_get() {
|
||||||
local key="$1"
|
local key="$1"
|
||||||
if [ ! -f "$GOTELEGRAM_CONFIG" ]; then
|
if [ ! -f "$PCATELEGRAM_WEB_CONFIG" ]; then
|
||||||
return 2 # file missing
|
return 2 # file missing
|
||||||
fi
|
fi
|
||||||
local val
|
local val
|
||||||
val=$(jq -r ".$key // empty" "$GOTELEGRAM_CONFIG" 2>/dev/null)
|
val=$(jq -r ".$key // empty" "$PCATELEGRAM_WEB_CONFIG" 2>/dev/null)
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
return 3 # invalid JSON
|
return 3 # invalid JSON
|
||||||
fi
|
fi
|
||||||
@@ -671,12 +671,12 @@ migrate_v1_to_v2() {
|
|||||||
|
|
||||||
# Backup v1 config
|
# Backup v1 config
|
||||||
if [ -f "$V1_CONFIG_FILE" ]; then
|
if [ -f "$V1_CONFIG_FILE" ]; then
|
||||||
mkdir -p "$GOTELEGRAM_DIR"
|
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||||
cp "$V1_CONFIG_FILE" "$GOTELEGRAM_DIR/v1_backup_proxy.json" 2>/dev/null
|
cp "$V1_CONFIG_FILE" "$PCATELEGRAM_WEB_DIR/v1_backup_proxy.json" 2>/dev/null
|
||||||
if type tf &>/dev/null; then
|
if type tf &>/dev/null; then
|
||||||
log_success "$(tf v1_config_saved "$GOTELEGRAM_DIR/v1_backup_proxy.json")"
|
log_success "$(tf v1_config_saved "$PCATELEGRAM_WEB_DIR/v1_backup_proxy.json")"
|
||||||
else
|
else
|
||||||
log_success "v1 config saved to $GOTELEGRAM_DIR/v1_backup_proxy.json"
|
log_success "v1 config saved to $PCATELEGRAM_WEB_DIR/v1_backup_proxy.json"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -735,6 +735,6 @@ validate_domain() {
|
|||||||
|
|
||||||
# ── Init: создание директорий ────────────────────────────────────────────────
|
# ── Init: создание директорий ────────────────────────────────────────────────
|
||||||
init_dirs() {
|
init_dirs() {
|
||||||
mkdir -p "$GOTELEGRAM_DIR" "$BACKUP_DIR" /etc/telemt 2>/dev/null
|
mkdir -p "$PCATELEGRAM_WEB_DIR" "$BACKUP_DIR" /etc/telemt 2>/dev/null
|
||||||
touch "$LOG_FILE" 2>/dev/null
|
touch "$LOG_FILE" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|||||||
12
lib/i18n.sh
Normal file → Executable file
12
lib/i18n.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# GoTelegram v2.5.0 — i18n engine
|
# PCAtelegram_web v2.5.0 — i18n engine
|
||||||
# Internationalization support: EN (English) / RU (Русский)
|
# Internationalization support: EN (English) / RU (Русский)
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
@@ -74,14 +74,14 @@ get_language() {
|
|||||||
|
|
||||||
# ── Detect saved language from config.json, default en ──
|
# ── Detect saved language from config.json, default en ──
|
||||||
detect_language() {
|
detect_language() {
|
||||||
local cfg="${GOTELEGRAM_CONFIG:-/opt/gotelegram/config.json}"
|
local cfg="${PCATELEGRAM_WEB_CONFIG:-/opt/pcatelegram_web/config.json}"
|
||||||
local lang=""
|
local lang=""
|
||||||
if [ -f "$cfg" ] && command -v jq >/dev/null 2>&1; then
|
if [ -f "$cfg" ] && command -v jq >/dev/null 2>&1; then
|
||||||
lang=$(jq -r '.language // empty' "$cfg" 2>/dev/null)
|
lang=$(jq -r '.language // empty' "$cfg" 2>/dev/null)
|
||||||
fi
|
fi
|
||||||
# Also check marker file (language set before config.json exists)
|
# Also check marker file (language set before config.json exists)
|
||||||
if [ -z "$lang" ]; then
|
if [ -z "$lang" ]; then
|
||||||
local marker="${GOTELEGRAM_DIR:-/opt/gotelegram}/.language"
|
local marker="${PCATELEGRAM_WEB_DIR:-/opt/pcatelegram_web}/.language"
|
||||||
if [ -f "$marker" ]; then
|
if [ -f "$marker" ]; then
|
||||||
lang=$(head -c 2 "$marker" 2>/dev/null | tr -d '[:space:]')
|
lang=$(head -c 2 "$marker" 2>/dev/null | tr -d '[:space:]')
|
||||||
fi
|
fi
|
||||||
@@ -100,11 +100,11 @@ save_language() {
|
|||||||
if ! [[ "$lang" =~ ^(en|ru)$ ]]; then
|
if ! [[ "$lang" =~ ^(en|ru)$ ]]; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
mkdir -p "${GOTELEGRAM_DIR:-/opt/gotelegram}" 2>/dev/null
|
mkdir -p "${PCATELEGRAM_WEB_DIR:-/opt/pcatelegram_web}" 2>/dev/null
|
||||||
# Always write marker for early-access (before config.json exists)
|
# Always write marker for early-access (before config.json exists)
|
||||||
echo "$lang" > "${GOTELEGRAM_DIR:-/opt/gotelegram}/.language" 2>/dev/null
|
echo "$lang" > "${PCATELEGRAM_WEB_DIR:-/opt/pcatelegram_web}/.language" 2>/dev/null
|
||||||
|
|
||||||
local cfg="${GOTELEGRAM_CONFIG:-/opt/gotelegram/config.json}"
|
local cfg="${PCATELEGRAM_WEB_CONFIG:-/opt/pcatelegram_web/config.json}"
|
||||||
if [ -f "$cfg" ] && command -v jq >/dev/null 2>&1; then
|
if [ -f "$cfg" ] && command -v jq >/dev/null 2>&1; then
|
||||||
local tmp
|
local tmp
|
||||||
tmp=$(mktemp) || return 1
|
tmp=$(mktemp) || return 1
|
||||||
|
|||||||
18
lib/lang/en.sh
Normal file → Executable file
18
lib/lang/en.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# goTelegram Pro v2.5.0 — English translations
|
# PCAtelegram_web v2.5.0 — English translations
|
||||||
# shellcheck disable=SC2034,SC2148
|
# shellcheck disable=SC2034,SC2148
|
||||||
|
|
||||||
# ── Common words ────────────────────────────────────────────────────────
|
# ── Common words ────────────────────────────────────────────────────────
|
||||||
@@ -25,7 +25,7 @@ I18N[success]="Done"
|
|||||||
I18N[wait]="Please wait..."
|
I18N[wait]="Please wait..."
|
||||||
|
|
||||||
# ── Banner ──────────────────────────────────────────────────────────────
|
# ── Banner ──────────────────────────────────────────────────────────────
|
||||||
I18N[banner_title]="goTelegram Pro v%s"
|
I18N[banner_title]="PCAtelegram_web v%s"
|
||||||
I18N[banner_subtitle]="MTProxy powered by telemt (Rust + Tokio)"
|
I18N[banner_subtitle]="MTProxy powered by telemt (Rust + Tokio)"
|
||||||
I18N[banner_features]="Anti-DPI • Fake TLS • TCP Splice • JA3/JA4"
|
I18N[banner_features]="Anti-DPI • Fake TLS • TCP Splice • JA3/JA4"
|
||||||
I18N[credits_title]="Credits / Thanks"
|
I18N[credits_title]="Credits / Thanks"
|
||||||
@@ -75,7 +75,7 @@ I18N[submenu_about_title]="ℹ️ ABOUT"
|
|||||||
I18N[about_version_info]="Version info"
|
I18N[about_version_info]="Version info"
|
||||||
I18N[about_promo]="Promo / Donate"
|
I18N[about_promo]="Promo / Donate"
|
||||||
I18N[version_title]="🔍 Information"
|
I18N[version_title]="🔍 Information"
|
||||||
I18N[version_label]="goTelegram Pro:"
|
I18N[version_label]="PCAtelegram_web:"
|
||||||
I18N[version_engine]="Engine:"
|
I18N[version_engine]="Engine:"
|
||||||
I18N[version_tech]="Technology:"
|
I18N[version_tech]="Technology:"
|
||||||
I18N[version_license]="License:"
|
I18N[version_license]="License:"
|
||||||
@@ -106,7 +106,7 @@ I18N[install_cfg_mode]="Mode:"
|
|||||||
I18N[install_cfg_domain]="Domain:"
|
I18N[install_cfg_domain]="Domain:"
|
||||||
I18N[install_confirm_proxy]="Install proxy?"
|
I18N[install_confirm_proxy]="Install proxy?"
|
||||||
I18N[install_confirm_proxy_site]="Install proxy + website?"
|
I18N[install_confirm_proxy_site]="Install proxy + website?"
|
||||||
I18N[install_done]="goTelegram Pro v%s installed! (%s mode)"
|
I18N[install_done]="PCAtelegram_web v%s installed! (%s mode)"
|
||||||
I18N[install_arch_desc1]="telemt accepts all traffic on 443 (HTTPS masquerade)"
|
I18N[install_arch_desc1]="telemt accepts all traffic on 443 (HTTPS masquerade)"
|
||||||
I18N[install_arch_desc2]="nginx serves the site on internal port %s"
|
I18N[install_arch_desc2]="nginx serves the site on internal port %s"
|
||||||
I18N[install_arch_desc3]="ISP only sees HTTPS traffic to %s:443"
|
I18N[install_arch_desc3]="ISP only sees HTTPS traffic to %s:443"
|
||||||
@@ -125,7 +125,7 @@ I18N[logs_telemt_title]="📋 telemt logs (last %s lines):"
|
|||||||
# ── Link / Share ────────────────────────────────────────────────────────
|
# ── Link / Share ────────────────────────────────────────────────────────
|
||||||
I18N[link_title]="🔗 Connection link:"
|
I18N[link_title]="🔗 Connection link:"
|
||||||
I18N[share_title]="📤 Forward this message:"
|
I18N[share_title]="📤 Forward this message:"
|
||||||
I18N[share_line1]="🔐 MTProxy for Telegram (goTelegram Pro v%s)"
|
I18N[share_line1]="🔐 MTProxy for Telegram (PCAtelegram_web v%s)"
|
||||||
I18N[share_server]="🌍 Server: %s"
|
I18N[share_server]="🌍 Server: %s"
|
||||||
I18N[share_port]="🔌 Port: %s"
|
I18N[share_port]="🔌 Port: %s"
|
||||||
I18N[share_connect_cta]="👉 Connect with one tap:"
|
I18N[share_connect_cta]="👉 Connect with one tap:"
|
||||||
@@ -141,7 +141,7 @@ I18N[website_restart_nginx]="Restart nginx"
|
|||||||
I18N[website_change_template]="Change template"
|
I18N[website_change_template]="Change template"
|
||||||
|
|
||||||
# ── Remove ──────────────────────────────────────────────────────────────
|
# ── Remove ──────────────────────────────────────────────────────────────
|
||||||
I18N[remove_title]="🗑 Remove goTelegram Pro"
|
I18N[remove_title]="🗑 Remove PCAtelegram_web"
|
||||||
I18N[remove_proxy_only]="Remove proxy only (telemt)"
|
I18N[remove_proxy_only]="Remove proxy only (telemt)"
|
||||||
I18N[remove_bot_only]="Remove Telegram bot only"
|
I18N[remove_bot_only]="Remove Telegram bot only"
|
||||||
I18N[remove_all]="Remove everything (proxy + bot + settings)"
|
I18N[remove_all]="Remove everything (proxy + bot + settings)"
|
||||||
@@ -151,7 +151,7 @@ I18N[remove_backup_before]="Create a backup before removal?"
|
|||||||
I18N[remove_warn_all]="This will remove EVERYTHING: proxy, bot, site, settings."
|
I18N[remove_warn_all]="This will remove EVERYTHING: proxy, bot, site, settings."
|
||||||
I18N[remove_confirm_all]="Are you absolutely sure?"
|
I18N[remove_confirm_all]="Are you absolutely sure?"
|
||||||
I18N[remove_proxy_done]="Proxy removed"
|
I18N[remove_proxy_done]="Proxy removed"
|
||||||
I18N[remove_all_done]="goTelegram Pro fully removed (proxy + bot)"
|
I18N[remove_all_done]="PCAtelegram_web fully removed (proxy + bot)"
|
||||||
|
|
||||||
# ── Telegram bot submenu ────────────────────────────────────────────────
|
# ── Telegram bot submenu ────────────────────────────────────────────────
|
||||||
I18N[bot_title]="🤖 Telegram bot"
|
I18N[bot_title]="🤖 Telegram bot"
|
||||||
@@ -332,7 +332,7 @@ I18N[backup_lang_label]="Language"
|
|||||||
I18N[backup_date_label]="Date"
|
I18N[backup_date_label]="Date"
|
||||||
I18N[backup_confirm_restore]="Restore configuration? Current settings will be overwritten."
|
I18N[backup_confirm_restore]="Restore configuration? Current settings will be overwritten."
|
||||||
I18N[backup_restored_telemt]="telemt config restored"
|
I18N[backup_restored_telemt]="telemt config restored"
|
||||||
I18N[backup_restored_gotelegram]="goTelegram Pro config restored"
|
I18N[backup_restored_pcatelegram_web]="PCAtelegram_web config restored"
|
||||||
I18N[backup_restored_lang]="Interface language restored"
|
I18N[backup_restored_lang]="Interface language restored"
|
||||||
I18N[backup_restored_nginx]="nginx config restored"
|
I18N[backup_restored_nginx]="nginx config restored"
|
||||||
I18N[backup_restored_ssl]="SSL certificates restored"
|
I18N[backup_restored_ssl]="SSL certificates restored"
|
||||||
@@ -362,7 +362,7 @@ I18N[auto_refresh]="Refresh in 30 sec"
|
|||||||
I18N[deps_installing]="Installing dependencies: %s"
|
I18N[deps_installing]="Installing dependencies: %s"
|
||||||
|
|
||||||
# ── Migration ───────────────────────────────────────────────────────────
|
# ── Migration ───────────────────────────────────────────────────────────
|
||||||
I18N[v1_detected]="⚠️ goTelegram Pro v1 (mtg) installation detected"
|
I18N[v1_detected]="⚠️ PCAtelegram_web v1 (mtg) installation detected"
|
||||||
I18N[v1_container]="Container: %s"
|
I18N[v1_container]="Container: %s"
|
||||||
I18N[v1_migration_step]="Migrating from v1 (mtg) to v2 (telemt)"
|
I18N[v1_migration_step]="Migrating from v1 (mtg) to v2 (telemt)"
|
||||||
I18N[v1_found_title]="Found v1 (mtg) installation:"
|
I18N[v1_found_title]="Found v1 (mtg) installation:"
|
||||||
|
|||||||
18
lib/lang/ru.sh
Normal file → Executable file
18
lib/lang/ru.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# goTelegram Pro v2.5.0 — Russian translations
|
# PCAtelegram_web v2.5.0 — Russian translations
|
||||||
# shellcheck disable=SC2034,SC2148
|
# shellcheck disable=SC2034,SC2148
|
||||||
|
|
||||||
# ── Common words ────────────────────────────────────────────────────────
|
# ── Common words ────────────────────────────────────────────────────────
|
||||||
@@ -25,7 +25,7 @@ I18N[success]="Готово"
|
|||||||
I18N[wait]="Подождите..."
|
I18N[wait]="Подождите..."
|
||||||
|
|
||||||
# ── Banner ──────────────────────────────────────────────────────────────
|
# ── Banner ──────────────────────────────────────────────────────────────
|
||||||
I18N[banner_title]="goTelegram Pro v%s"
|
I18N[banner_title]="PCAtelegram_web v%s"
|
||||||
I18N[banner_subtitle]="MTProxy на ядре telemt (Rust + Tokio)"
|
I18N[banner_subtitle]="MTProxy на ядре telemt (Rust + Tokio)"
|
||||||
I18N[banner_features]="Anti-DPI • Fake TLS • TCP Splice • JA3/JA4"
|
I18N[banner_features]="Anti-DPI • Fake TLS • TCP Splice • JA3/JA4"
|
||||||
I18N[credits_title]="Благодарности / Credits"
|
I18N[credits_title]="Благодарности / Credits"
|
||||||
@@ -75,7 +75,7 @@ I18N[submenu_about_title]="ℹ️ О ПРОГРАММЕ"
|
|||||||
I18N[about_version_info]="Информация о версии"
|
I18N[about_version_info]="Информация о версии"
|
||||||
I18N[about_promo]="Промо / Донат"
|
I18N[about_promo]="Промо / Донат"
|
||||||
I18N[version_title]="🔍 Информация"
|
I18N[version_title]="🔍 Информация"
|
||||||
I18N[version_label]="goTelegram Pro:"
|
I18N[version_label]="PCAtelegram_web:"
|
||||||
I18N[version_engine]="Ядро:"
|
I18N[version_engine]="Ядро:"
|
||||||
I18N[version_tech]="Технология:"
|
I18N[version_tech]="Технология:"
|
||||||
I18N[version_license]="Лицензия:"
|
I18N[version_license]="Лицензия:"
|
||||||
@@ -106,7 +106,7 @@ I18N[install_cfg_mode]="Режим:"
|
|||||||
I18N[install_cfg_domain]="Домен:"
|
I18N[install_cfg_domain]="Домен:"
|
||||||
I18N[install_confirm_proxy]="Установить прокси?"
|
I18N[install_confirm_proxy]="Установить прокси?"
|
||||||
I18N[install_confirm_proxy_site]="Установить прокси + сайт?"
|
I18N[install_confirm_proxy_site]="Установить прокси + сайт?"
|
||||||
I18N[install_done]="goTelegram Pro v%s установлен! (%s-режим)"
|
I18N[install_done]="PCAtelegram_web v%s установлен! (%s-режим)"
|
||||||
I18N[install_arch_desc1]="telemt принимает весь трафик на 443 (маскировка под HTTPS)"
|
I18N[install_arch_desc1]="telemt принимает весь трафик на 443 (маскировка под HTTPS)"
|
||||||
I18N[install_arch_desc2]="nginx обслуживает сайт на внутреннем порту %s"
|
I18N[install_arch_desc2]="nginx обслуживает сайт на внутреннем порту %s"
|
||||||
I18N[install_arch_desc3]="Провайдер видит только HTTPS-трафик к %s:443"
|
I18N[install_arch_desc3]="Провайдер видит только HTTPS-трафик к %s:443"
|
||||||
@@ -125,7 +125,7 @@ I18N[logs_telemt_title]="📋 Логи telemt (последние %s строк)
|
|||||||
# ── Link / Share ────────────────────────────────────────────────────────
|
# ── Link / Share ────────────────────────────────────────────────────────
|
||||||
I18N[link_title]="🔗 Ссылка для подключения:"
|
I18N[link_title]="🔗 Ссылка для подключения:"
|
||||||
I18N[share_title]="📤 Перешлите это сообщение:"
|
I18N[share_title]="📤 Перешлите это сообщение:"
|
||||||
I18N[share_line1]="🔐 MTProxy для Telegram (goTelegram Pro v%s)"
|
I18N[share_line1]="🔐 MTProxy для Telegram (PCAtelegram_web v%s)"
|
||||||
I18N[share_server]="🌍 Сервер: %s"
|
I18N[share_server]="🌍 Сервер: %s"
|
||||||
I18N[share_port]="🔌 Порт: %s"
|
I18N[share_port]="🔌 Порт: %s"
|
||||||
I18N[share_connect_cta]="👉 Подключиться одним нажатием:"
|
I18N[share_connect_cta]="👉 Подключиться одним нажатием:"
|
||||||
@@ -141,7 +141,7 @@ I18N[website_restart_nginx]="Перезапустить nginx"
|
|||||||
I18N[website_change_template]="Сменить шаблон"
|
I18N[website_change_template]="Сменить шаблон"
|
||||||
|
|
||||||
# ── Remove ──────────────────────────────────────────────────────────────
|
# ── Remove ──────────────────────────────────────────────────────────────
|
||||||
I18N[remove_title]="🗑 Удаление goTelegram Pro"
|
I18N[remove_title]="🗑 Удаление PCAtelegram_web"
|
||||||
I18N[remove_proxy_only]="Удалить только прокси (telemt)"
|
I18N[remove_proxy_only]="Удалить только прокси (telemt)"
|
||||||
I18N[remove_bot_only]="Удалить только Telegram-бота"
|
I18N[remove_bot_only]="Удалить только Telegram-бота"
|
||||||
I18N[remove_all]="Удалить всё (прокси + бот + настройки)"
|
I18N[remove_all]="Удалить всё (прокси + бот + настройки)"
|
||||||
@@ -151,7 +151,7 @@ I18N[remove_backup_before]="Сделать бекап перед удалени
|
|||||||
I18N[remove_warn_all]="Это удалит ВСЁ: прокси, бот, сайт, настройки."
|
I18N[remove_warn_all]="Это удалит ВСЁ: прокси, бот, сайт, настройки."
|
||||||
I18N[remove_confirm_all]="Вы точно уверены?"
|
I18N[remove_confirm_all]="Вы точно уверены?"
|
||||||
I18N[remove_proxy_done]="Прокси удалён"
|
I18N[remove_proxy_done]="Прокси удалён"
|
||||||
I18N[remove_all_done]="goTelegram Pro полностью удалён (прокси + бот)"
|
I18N[remove_all_done]="PCAtelegram_web полностью удалён (прокси + бот)"
|
||||||
|
|
||||||
# ── Telegram bot submenu ────────────────────────────────────────────────
|
# ── Telegram bot submenu ────────────────────────────────────────────────
|
||||||
I18N[bot_title]="🤖 Telegram-бот"
|
I18N[bot_title]="🤖 Telegram-бот"
|
||||||
@@ -332,7 +332,7 @@ I18N[backup_lang_label]="Язык"
|
|||||||
I18N[backup_date_label]="Дата"
|
I18N[backup_date_label]="Дата"
|
||||||
I18N[backup_confirm_restore]="Восстановить конфигурацию? Текущие настройки будут перезаписаны."
|
I18N[backup_confirm_restore]="Восстановить конфигурацию? Текущие настройки будут перезаписаны."
|
||||||
I18N[backup_restored_telemt]="telemt конфиг восстановлен"
|
I18N[backup_restored_telemt]="telemt конфиг восстановлен"
|
||||||
I18N[backup_restored_gotelegram]="goTelegram Pro конфиг восстановлен"
|
I18N[backup_restored_pcatelegram_web]="PCAtelegram_web конфиг восстановлен"
|
||||||
I18N[backup_restored_lang]="Язык интерфейса восстановлен"
|
I18N[backup_restored_lang]="Язык интерфейса восстановлен"
|
||||||
I18N[backup_restored_nginx]="nginx конфиг восстановлен"
|
I18N[backup_restored_nginx]="nginx конфиг восстановлен"
|
||||||
I18N[backup_restored_ssl]="SSL сертификаты восстановлены"
|
I18N[backup_restored_ssl]="SSL сертификаты восстановлены"
|
||||||
@@ -362,7 +362,7 @@ I18N[auto_refresh]="Обновление через 30 сек"
|
|||||||
I18N[deps_installing]="Установка зависимостей: %s"
|
I18N[deps_installing]="Установка зависимостей: %s"
|
||||||
|
|
||||||
# ── Migration ───────────────────────────────────────────────────────────
|
# ── Migration ───────────────────────────────────────────────────────────
|
||||||
I18N[v1_detected]="⚠️ Обнаружена установка goTelegram Pro v1 (mtg)"
|
I18N[v1_detected]="⚠️ Обнаружена установка PCAtelegram_web v1 (mtg)"
|
||||||
I18N[v1_container]="Контейнер: %s"
|
I18N[v1_container]="Контейнер: %s"
|
||||||
I18N[v1_migration_step]="Миграция с v1 (mtg) на v2 (telemt)"
|
I18N[v1_migration_step]="Миграция с v1 (mtg) на v2 (telemt)"
|
||||||
I18N[v1_found_title]="Найдена установка v1 (mtg):"
|
I18N[v1_found_title]="Найдена установка v1 (mtg):"
|
||||||
|
|||||||
60
lib/stats.sh
Normal file → Executable file
60
lib/stats.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# stats.sh — Traffic statistics module for GoTelegram v2.5.0
|
# stats.sh — Traffic statistics module for PCAtelegram_web v2.5.0
|
||||||
# Tracks proxy (telemt port 443) and site (nginx port 8443) traffic
|
# Tracks proxy (telemt port 443) and site (nginx port 8443) traffic
|
||||||
# Uses iptables counters + real-time snapshots + historical CSV
|
# Uses iptables counters + real-time snapshots + historical CSV
|
||||||
|
|
||||||
@@ -10,12 +10,12 @@ YELLOW='\033[1;33m'
|
|||||||
BLUE='\033[0;34m'
|
BLUE='\033[0;34m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
STATS_DIR="/run/gotelegram"
|
STATS_DIR="/run/pcatelegram_web"
|
||||||
HISTORY_FILE="/opt/gotelegram/stats_history.csv"
|
HISTORY_FILE="/opt/pcatelegram_web/stats_history.csv"
|
||||||
USER_HISTORY_FILE="/opt/gotelegram/user_stats_history.csv"
|
USER_HISTORY_FILE="/opt/pcatelegram_web/user_stats_history.csv"
|
||||||
SNAPSHOTS_DIR="$STATS_DIR/snapshots"
|
SNAPSHOTS_DIR="$STATS_DIR/snapshots"
|
||||||
CURRENT_SNAPSHOT="$STATS_DIR/stats_current.json"
|
CURRENT_SNAPSHOT="$STATS_DIR/stats_current.json"
|
||||||
CONFIG_FILE="/opt/gotelegram/config.json"
|
CONFIG_FILE="/opt/pcatelegram_web/config.json"
|
||||||
TELEMT_CONFIG_FILE="/etc/telemt/config.toml"
|
TELEMT_CONFIG_FILE="/etc/telemt/config.toml"
|
||||||
STATS_RETENTION_DAYS="${STATS_RETENTION_DAYS:-365}"
|
STATS_RETENTION_DAYS="${STATS_RETENTION_DAYS:-365}"
|
||||||
STATS_MINUTE_RETENTION_DAYS="${STATS_MINUTE_RETENTION_DAYS:-31}"
|
STATS_MINUTE_RETENTION_DAYS="${STATS_MINUTE_RETENTION_DAYS:-31}"
|
||||||
@@ -35,23 +35,23 @@ stats_init() {
|
|||||||
chmod 755 "$STATS_DIR" "$SNAPSHOTS_DIR" 2>/dev/null
|
chmod 755 "$STATS_DIR" "$SNAPSHOTS_DIR" 2>/dev/null
|
||||||
|
|
||||||
# Create iptables chain if not exists
|
# Create iptables chain if not exists
|
||||||
if ! iptables -L GOTELEGRAM_STATS -n >/dev/null 2>&1; then
|
if ! iptables -L PCATELEGRAM_WEB_STATS -n >/dev/null 2>&1; then
|
||||||
iptables -N GOTELEGRAM_STATS 2>/dev/null
|
iptables -N PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add chain to INPUT if not already present
|
# Add chain to INPUT if not already present
|
||||||
if ! iptables -C INPUT -j GOTELEGRAM_STATS 2>/dev/null; then
|
if ! iptables -C INPUT -j PCATELEGRAM_WEB_STATS 2>/dev/null; then
|
||||||
iptables -I INPUT -j GOTELEGRAM_STATS 2>/dev/null
|
iptables -I INPUT -j PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add rule for proxy traffic (port 443, TCP)
|
# Add rule for proxy traffic (port 443, TCP)
|
||||||
if ! iptables -C GOTELEGRAM_STATS -p tcp --dport 443 2>/dev/null; then
|
if ! iptables -C PCATELEGRAM_WEB_STATS -p tcp --dport 443 2>/dev/null; then
|
||||||
iptables -A GOTELEGRAM_STATS -p tcp --dport 443 2>/dev/null
|
iptables -A PCATELEGRAM_WEB_STATS -p tcp --dport 443 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add rule for site traffic (loopback, port 8443, TCP)
|
# Add rule for site traffic (loopback, port 8443, TCP)
|
||||||
if ! iptables -C GOTELEGRAM_STATS -i lo -p tcp --dport 8443 2>/dev/null; then
|
if ! iptables -C PCATELEGRAM_WEB_STATS -i lo -p tcp --dport 8443 2>/dev/null; then
|
||||||
iptables -A GOTELEGRAM_STATS -i lo -p tcp --dport 8443 2>/dev/null
|
iptables -A PCATELEGRAM_WEB_STATS -i lo -p tcp --dport 8443 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Initialize CSV header if file doesn't exist
|
# Initialize CSV header if file doesn't exist
|
||||||
@@ -81,7 +81,7 @@ stats_collect() {
|
|||||||
|
|
||||||
# Parse iptables output: format is "pkts bytes target"
|
# Parse iptables output: format is "pkts bytes target"
|
||||||
# We need to extract bytes (2nd column) for each rule
|
# We need to extract bytes (2nd column) for each rule
|
||||||
local iptables_output=$(iptables -L GOTELEGRAM_STATS -v -n -x 2>/dev/null)
|
local iptables_output=$(iptables -L PCATELEGRAM_WEB_STATS -v -n -x 2>/dev/null)
|
||||||
|
|
||||||
# Extract counters for port 443 (proxy)
|
# Extract counters for port 443 (proxy)
|
||||||
proxy_bytes=$(echo "$iptables_output" | grep "dpt:443" | grep -v "lo" | awk '{print $2}')
|
proxy_bytes=$(echo "$iptables_output" | grep "dpt:443" | grep -v "lo" | awk '{print $2}')
|
||||||
@@ -140,7 +140,7 @@ EOF
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Print active telemt usernames from [access.users]. Usernames are restricted by
|
# Print active telemt usernames from [access.users]. Usernames are restricted by
|
||||||
# goTelegram to A-Z/a-z/0-9/_.- so they are safe in URLs and CSV fields.
|
# PCAtelegram_web to A-Z/a-z/0-9/_.- so they are safe in URLs and CSV fields.
|
||||||
stats_active_users() {
|
stats_active_users() {
|
||||||
[[ -f "$TELEMT_CONFIG_FILE" ]] || return 0
|
[[ -f "$TELEMT_CONFIG_FILE" ]] || return 0
|
||||||
awk '
|
awk '
|
||||||
@@ -478,9 +478,9 @@ toggle_stats() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove iptables rules
|
# Remove iptables rules
|
||||||
iptables -D INPUT -j GOTELEGRAM_STATS 2>/dev/null
|
iptables -D INPUT -j PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||||
iptables -F GOTELEGRAM_STATS 2>/dev/null
|
iptables -F PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||||
iptables -X GOTELEGRAM_STATS 2>/dev/null
|
iptables -X PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||||
|
|
||||||
# Clean up directories
|
# Clean up directories
|
||||||
rm -rf "$STATS_DIR" 2>/dev/null
|
rm -rf "$STATS_DIR" 2>/dev/null
|
||||||
@@ -504,7 +504,7 @@ toggle_stats() {
|
|||||||
|
|
||||||
# Install systemd service for stats collection
|
# Install systemd service for stats collection
|
||||||
install_stats_collector() {
|
install_stats_collector() {
|
||||||
local service_file="/etc/systemd/system/gotelegram-stats.service"
|
local service_file="/etc/systemd/system/pcatelegram_web-stats.service"
|
||||||
|
|
||||||
# Check if running as root
|
# Check if running as root
|
||||||
if [[ $EUID -ne 0 ]]; then
|
if [[ $EUID -ne 0 ]]; then
|
||||||
@@ -527,14 +527,14 @@ install_stats_collector() {
|
|||||||
# Create systemd service file
|
# Create systemd service file
|
||||||
cat > "$service_file" <<'EOF'
|
cat > "$service_file" <<'EOF'
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=goTelegram Pro Traffic Stats Collector
|
Description=PCAtelegram_web Traffic Stats Collector
|
||||||
After=network.target
|
After=network.target
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=root
|
User=root
|
||||||
ExecStart=/bin/bash -c 'source /opt/gotelegram/lib/common.sh; source /opt/gotelegram/lib/stats.sh; stats_init; while true; do stats_collect; sleep 1; done'
|
ExecStart=/bin/bash -c 'source /opt/pcatelegram_web/lib/common.sh; source /opt/pcatelegram_web/lib/stats.sh; stats_init; while true; do stats_collect; sleep 1; done'
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
StandardOutput=journal
|
StandardOutput=journal
|
||||||
@@ -546,8 +546,8 @@ EOF
|
|||||||
|
|
||||||
chmod 644 "$service_file"
|
chmod 644 "$service_file"
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable gotelegram-stats.service
|
systemctl enable pcatelegram_web-stats.service
|
||||||
systemctl restart gotelegram-stats.service
|
systemctl restart pcatelegram_web-stats.service
|
||||||
|
|
||||||
if [[ -f "$CONFIG_FILE" ]] && command -v jq &>/dev/null; then
|
if [[ -f "$CONFIG_FILE" ]] && command -v jq &>/dev/null; then
|
||||||
local tmp
|
local tmp
|
||||||
@@ -560,7 +560,7 @@ EOF
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Сервис gotelegram-stats установлен и запущен" >&2
|
echo "Сервис pcatelegram_web-stats установлен и запущен" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove stats collector service
|
# Remove stats collector service
|
||||||
@@ -570,15 +570,15 @@ remove_stats_collector() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
systemctl stop gotelegram-stats.service 2>/dev/null
|
systemctl stop pcatelegram_web-stats.service 2>/dev/null
|
||||||
systemctl disable gotelegram-stats.service 2>/dev/null
|
systemctl disable pcatelegram_web-stats.service 2>/dev/null
|
||||||
rm -f /etc/systemd/system/gotelegram-stats.service
|
rm -f /etc/systemd/system/pcatelegram_web-stats.service
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
|
||||||
# Remove iptables rules
|
# Remove iptables rules
|
||||||
iptables -D INPUT -j GOTELEGRAM_STATS 2>/dev/null
|
iptables -D INPUT -j PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||||
iptables -F GOTELEGRAM_STATS 2>/dev/null
|
iptables -F PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||||
iptables -X GOTELEGRAM_STATS 2>/dev/null
|
iptables -X PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||||
|
|
||||||
# Clean up directories and files
|
# Clean up directories and files
|
||||||
rm -rf "$STATS_DIR" 2>/dev/null
|
rm -rf "$STATS_DIR" 2>/dev/null
|
||||||
|
|||||||
4
lib/telemt.sh
Normal file → Executable file
4
lib/telemt.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# GoTelegram v2.5.0 — Управление telemt binary
|
# PCAtelegram_web v2.5.0 — Управление telemt binary
|
||||||
# Скачивание, обновление, запуск, остановка через systemd
|
# Скачивание, обновление, запуск, остановка через systemd
|
||||||
|
|
||||||
TELEMT_GITHUB="telemt/telemt"
|
TELEMT_GITHUB="telemt/telemt"
|
||||||
@@ -159,7 +159,7 @@ install_telemt_service() {
|
|||||||
|
|
||||||
cat > "/etc/systemd/system/${TELEMT_SERVICE}.service" << EOF
|
cat > "/etc/systemd/system/${TELEMT_SERVICE}.service" << EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=goTelegram Pro MTProxy (telemt engine)
|
Description=PCAtelegram_web MTProxy (telemt engine)
|
||||||
Documentation=https://github.com/telemt/telemt
|
Documentation=https://github.com/telemt/telemt
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
|||||||
4
lib/telemt_config.sh
Normal file → Executable file
4
lib/telemt_config.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# GoTelegram v2.5.0 — Генерация TOML конфигурации для telemt
|
# PCAtelegram_web v2.5.0 — Генерация TOML конфигурации для telemt
|
||||||
|
|
||||||
# ── Популярные домены (не заблокированные в РФ) ──────────────────────────────
|
# ── Популярные домены (не заблокированные в РФ) ──────────────────────────────
|
||||||
QUICK_DOMAINS=(
|
QUICK_DOMAINS=(
|
||||||
@@ -44,7 +44,7 @@ generate_telemt_toml() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cat > "$output" << EOTOML
|
cat > "$output" << EOTOML
|
||||||
# GoTelegram v${GOTELEGRAM_VERSION} — telemt v3 configuration
|
# PCAtelegram_web v${PCATELEGRAM_WEB_VERSION} — telemt v3 configuration
|
||||||
# Сгенерировано: $(date -Iseconds)
|
# Сгенерировано: $(date -Iseconds)
|
||||||
# Режим: ${mask_mode}
|
# Режим: ${mask_mode}
|
||||||
|
|
||||||
|
|||||||
4
lib/templates_catalog.sh
Normal file → Executable file
4
lib/templates_catalog.sh
Normal file → Executable file
@@ -1,10 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# GoTelegram v2.5.0 — website templates catalog
|
# PCAtelegram_web v2.5.0 — website templates catalog
|
||||||
# Pick from ~1800 templates, preview links, git sparse-checkout downloads,
|
# Pick from ~1800 templates, preview links, git sparse-checkout downloads,
|
||||||
# + custom git URL templates (user-supplied public repos)
|
# + custom git URL templates (user-supplied public repos)
|
||||||
|
|
||||||
CATALOG_FILE="$(dirname "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")/templates_catalog.json"
|
CATALOG_FILE="$(dirname "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")/templates_catalog.json"
|
||||||
TEMPLATES_CACHE="/tmp/gotelegram_templates"
|
TEMPLATES_CACHE="/tmp/pcatelegram_web_templates"
|
||||||
|
|
||||||
# Custom git template limits
|
# Custom git template limits
|
||||||
CUSTOM_GIT_MAX_SIZE_MB=100
|
CUSTOM_GIT_MAX_SIZE_MB=100
|
||||||
|
|||||||
14
lib/website.sh
Normal file → Executable file
14
lib/website.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# GoTelegram v2.5.0 — Управление сайтом (nginx + certbot + шаблоны)
|
# PCAtelegram_web v2.5.0 — Управление сайтом (nginx + certbot + шаблоны)
|
||||||
|
|
||||||
# ── Установка nginx ──────────────────────────────────────────────────────────
|
# ── Установка nginx ──────────────────────────────────────────────────────────
|
||||||
install_nginx() {
|
install_nginx() {
|
||||||
@@ -39,7 +39,7 @@ generate_nginx_config() {
|
|||||||
mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
|
mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
|
||||||
|
|
||||||
cat > "$NGINX_SITE_CONF" << 'EONGINX'
|
cat > "$NGINX_SITE_CONF" << 'EONGINX'
|
||||||
# GoTelegram v2.5.0 — nginx config
|
# PCAtelegram_web v2.5.0 — nginx config
|
||||||
# Pro: nginx на 127.0.0.1:8443 (внутренний), telemt на 0.0.0.0:443 (внешний)
|
# Pro: nginx на 127.0.0.1:8443 (внутренний), telemt на 0.0.0.0:443 (внешний)
|
||||||
# Обычный браузер → :443 → telemt → 127.0.0.1:8443 → nginx (сайт)
|
# Обычный браузер → :443 → telemt → 127.0.0.1:8443 → nginx (сайт)
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ server {
|
|||||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||||
|
|
||||||
# Корень сайта
|
# Корень сайта
|
||||||
root /var/www/gotelegram-site;
|
root /var/www/pcatelegram_web-site;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
@@ -127,7 +127,7 @@ generate_nginx_temp_config() {
|
|||||||
local domain="$1"
|
local domain="$1"
|
||||||
|
|
||||||
cat > "$NGINX_SITE_CONF" << EONGINX_TEMP
|
cat > "$NGINX_SITE_CONF" << EONGINX_TEMP
|
||||||
# GoTelegram — временный конфиг (до получения SSL)
|
# PCAtelegram_web — временный конфиг (до получения SSL)
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
@@ -138,7 +138,7 @@ server {
|
|||||||
allow all;
|
allow all;
|
||||||
}
|
}
|
||||||
|
|
||||||
root /var/www/gotelegram-site;
|
root /var/www/pcatelegram_web-site;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
@@ -257,8 +257,8 @@ deploy_template_to_nginx() {
|
|||||||
mkdir -p "$WEBSITE_ROOT"
|
mkdir -p "$WEBSITE_ROOT"
|
||||||
cp -a "$template_dir/." "$WEBSITE_ROOT/"
|
cp -a "$template_dir/." "$WEBSITE_ROOT/"
|
||||||
rm -f "$WEBSITE_ROOT/.custom_git_source" 2>/dev/null || true
|
rm -f "$WEBSITE_ROOT/.custom_git_source" 2>/dev/null || true
|
||||||
echo "$template_id" > "$WEBSITE_ROOT/.gotelegram_template_id" 2>/dev/null || true
|
echo "$template_id" > "$WEBSITE_ROOT/.pcatelegram_web_template_id" 2>/dev/null || true
|
||||||
[ -n "$source_url" ] && echo "$source_url" > "$WEBSITE_ROOT/.gotelegram_template_source" 2>/dev/null || true
|
[ -n "$source_url" ] && echo "$source_url" > "$WEBSITE_ROOT/.pcatelegram_web_template_source" 2>/dev/null || true
|
||||||
chown -R www-data:www-data "$WEBSITE_ROOT" 2>/dev/null || chown -R nginx:nginx "$WEBSITE_ROOT" 2>/dev/null
|
chown -R www-data:www-data "$WEBSITE_ROOT" 2>/dev/null || chown -R nginx:nginx "$WEBSITE_ROOT" 2>/dev/null
|
||||||
chmod -R 755 "$WEBSITE_ROOT"
|
chmod -R 755 "$WEBSITE_ROOT"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# goTelegram Pro v2.5.0 Bot
|
# PCAtelegram_web v2.5.0 Bot
|
||||||
|
|
||||||
Production-quality Telegram bot for managing MTProxy (telemt engine) on Linux servers.
|
Production-quality Telegram bot for managing MTProxy (telemt engine) on Linux servers.
|
||||||
|
|
||||||
@@ -34,10 +34,10 @@ Production-quality Telegram bot for managing MTProxy (telemt engine) on Linux se
|
|||||||
Recommended installation path is the main CLI menu:
|
Recommended installation path is the main CLI menu:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gotelegram
|
pcatelegram_web
|
||||||
```
|
```
|
||||||
|
|
||||||
Then choose `12) Telegram-bot` → install/update. On repeat goTelegram Pro bootstrap/update, an already installed bot is refreshed automatically: code, i18n files and requirements are copied to `/opt/gotelegram-bot`, `.env` is preserved, dependencies are checked and `gotelegram-bot` is restarted.
|
Then choose `12) Telegram-bot` → install/update. On repeat PCAtelegram_web bootstrap/update, an already installed bot is refreshed automatically: code, i18n files and requirements are copied to `/opt/pcatelegram_web-bot`, `.env` is preserved, dependencies are checked and `pcatelegram_web-bot` is restarted.
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
@@ -76,16 +76,16 @@ For systemd service:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=goTelegram Pro Bot
|
Description=PCAtelegram_web Bot
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
WorkingDirectory=/opt/gotelegram-bot
|
WorkingDirectory=/opt/pcatelegram_web-bot
|
||||||
ExecStart=/opt/gotelegram-bot/venv/bin/python /opt/gotelegram-bot/bot.py
|
ExecStart=/opt/pcatelegram_web-bot/venv/bin/python /opt/pcatelegram_web-bot/bot.py
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
Environment=PATH=/opt/gotelegram-bot/venv/bin:/usr/bin
|
Environment=PATH=/opt/pcatelegram_web-bot/venv/bin:/usr/bin
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
@@ -97,17 +97,17 @@ WantedBy=multi-user.target
|
|||||||
|
|
||||||
- `BOT_TOKEN` - Telegram bot token (required)
|
- `BOT_TOKEN` - Telegram bot token (required)
|
||||||
- `ALLOWED_IDS` - Comma-separated user IDs (optional, all users allowed if empty)
|
- `ALLOWED_IDS` - Comma-separated user IDs (optional, all users allowed if empty)
|
||||||
- `BOT_LANG` - Default language inherited from goTelegram Pro install language
|
- `BOT_LANG` - Default language inherited from PCAtelegram_web install language
|
||||||
|
|
||||||
### System Paths
|
### System Paths
|
||||||
|
|
||||||
- `GOTELEGRAM_CONFIG` - `/opt/gotelegram/config.json`
|
- `PCATELEGRAM_WEB_CONFIG` - `/opt/pcatelegram_web/config.json`
|
||||||
- `TELEMT_CONFIG` - `/etc/telemt/config.toml`
|
- `TELEMT_CONFIG` - `/etc/telemt/config.toml`
|
||||||
- `TELEMT_SERVICE` - `telemt` (systemd service name)
|
- `TELEMT_SERVICE` - `telemt` (systemd service name)
|
||||||
- `WEBSITE_ROOT` - `/var/www/gotelegram-site`
|
- `WEBSITE_ROOT` - `/var/www/pcatelegram_web-site`
|
||||||
- `BACKUP_DIR` - `/opt/gotelegram/backups`
|
- `BACKUP_DIR` - `/opt/pcatelegram_web/backups`
|
||||||
- `BACKUP_SCHEDULE_FILE` - `/opt/gotelegram/backup_schedule.json`
|
- `BACKUP_SCHEDULE_FILE` - `/opt/pcatelegram_web/backup_schedule.json`
|
||||||
- `TEMPLATES_CATALOG` - `/opt/gotelegram/templates_catalog.json`
|
- `TEMPLATES_CATALOG` - `/opt/pcatelegram_web/templates_catalog.json`
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
@@ -158,4 +158,4 @@ code, stdout, stderr = await sh("command", "arg1", "arg2")
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
goTelegram Pro v2.5.0 - Open source community project
|
PCAtelegram_web v2.5.0 - Open source community project
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
goTelegram Pro v2.5.0 Bot - MTProxy Management for Linux
|
PCAtelegram_web v2.5.0 Bot - MTProxy Management for Linux
|
||||||
Manages telemt engine via Telegram interface with full CLI feature parity
|
Manages telemt engine via Telegram interface with full CLI feature parity
|
||||||
Uses python-telegram-bot v21+
|
Uses python-telegram-bot v21+
|
||||||
Supports EN/RU UI with per-user language preferences.
|
Supports EN/RU UI with per-user language preferences.
|
||||||
@@ -103,28 +103,28 @@ logger = logging.getLogger(__name__)
|
|||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
GOTELEGRAM_VERSION = "2.5.0"
|
PCATELEGRAM_WEB_VERSION = "2.5.0"
|
||||||
GOTELEGRAM_CONFIG = "/opt/gotelegram/config.json"
|
PCATELEGRAM_WEB_CONFIG = "/opt/pcatelegram_web/config.json"
|
||||||
DISABLED_USERS_FILE = "/opt/gotelegram/disabled_users.json"
|
DISABLED_USERS_FILE = "/opt/pcatelegram_web/disabled_users.json"
|
||||||
USER_STATS_HISTORY = "/opt/gotelegram/user_stats_history.csv"
|
USER_STATS_HISTORY = "/opt/pcatelegram_web/user_stats_history.csv"
|
||||||
USER_LOCK_FILE = "/run/gotelegram/admin-users.lock"
|
USER_LOCK_FILE = "/run/pcatelegram_web/admin-users.lock"
|
||||||
TELEMT_CONFIG = "/etc/telemt/config.toml"
|
TELEMT_CONFIG = "/etc/telemt/config.toml"
|
||||||
TELEMT_SERVICE = "telemt"
|
TELEMT_SERVICE = "telemt"
|
||||||
WEBSITE_ROOT = "/var/www/gotelegram-site"
|
WEBSITE_ROOT = "/var/www/pcatelegram_web-site"
|
||||||
BACKUP_DIR = "/opt/gotelegram/backups"
|
BACKUP_DIR = "/opt/pcatelegram_web/backups"
|
||||||
BACKUP_SCHEDULE_FILE = "/opt/gotelegram/backup_schedule.json"
|
BACKUP_SCHEDULE_FILE = "/opt/pcatelegram_web/backup_schedule.json"
|
||||||
TEMPLATES_CATALOG = "/opt/gotelegram/templates_catalog.json"
|
TEMPLATES_CATALOG = "/opt/pcatelegram_web/templates_catalog.json"
|
||||||
INSTALL_SH = "/opt/gotelegram/install.sh"
|
INSTALL_SH = "/opt/pcatelegram_web/install.sh"
|
||||||
|
|
||||||
PROMO_LINK_1 = "https://vk.cc/ct29NQ"
|
PROMO_LINK_1 = "https://vk.cc/ct29NQ"
|
||||||
PROMO_LINK_2 = "https://vk.cc/cUxAhj"
|
PROMO_LINK_2 = "https://vk.cc/cUxAhj"
|
||||||
TIP_LINK = "https://pay.cloudtips.ru/p/7410814f"
|
TIP_LINK = "https://pay.cloudtips.ru/p/7410814f"
|
||||||
YOUTUBE_LINK = os.getenv("GOTELEGRAM_YOUTUBE_LINK", "").strip()
|
YOUTUBE_LINK = os.getenv("PCATELEGRAM_WEB_YOUTUBE_LINK", "").strip()
|
||||||
PROMO_STAMP_FILE = "/opt/gotelegram/.promo_bot_last_shown"
|
PROMO_STAMP_FILE = "/opt/pcatelegram_web/.promo_bot_last_shown"
|
||||||
|
|
||||||
BOT_TOKEN = os.getenv("BOT_TOKEN")
|
BOT_TOKEN = os.getenv("BOT_TOKEN")
|
||||||
ENV_FILE = "/opt/gotelegram-bot/.env"
|
ENV_FILE = "/opt/pcatelegram_web-bot/.env"
|
||||||
ADMIN_WEB_SERVICE = "gotelegram-admin"
|
ADMIN_WEB_SERVICE = "pcatelegram_web-admin"
|
||||||
ADMIN_WEB_PORT = 1984
|
ADMIN_WEB_PORT = 1984
|
||||||
|
|
||||||
|
|
||||||
@@ -263,7 +263,7 @@ async def sh(*args, timeout: int = 60) -> Tuple[int, str, str]:
|
|||||||
|
|
||||||
# Per-host mutex preventing concurrent install.sh --action invocations. Two
|
# Per-host mutex preventing concurrent install.sh --action invocations. Two
|
||||||
# admins hitting "change template" at the same second could race each other
|
# admins hitting "change template" at the same second could race each other
|
||||||
# and corrupt /var/www/gotelegram-site. One global lock is fine — these are
|
# and corrupt /var/www/pcatelegram_web-site. One global lock is fine — these are
|
||||||
# rare operations and should serialize cleanly.
|
# rare operations and should serialize cleanly.
|
||||||
_BOT_ACTION_LOCK = asyncio.Lock()
|
_BOT_ACTION_LOCK = asyncio.Lock()
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ _DOMAIN_RE = re.compile(
|
|||||||
)
|
)
|
||||||
_USER_NAME_RE = re.compile(r"^[A-Za-z0-9_.-]{1,48}$")
|
_USER_NAME_RE = re.compile(r"^[A-Za-z0-9_.-]{1,48}$")
|
||||||
MAX_UNIQUE_IP_LIMIT = 1000000
|
MAX_UNIQUE_IP_LIMIT = 1000000
|
||||||
TELEMT_RESTART_DEBOUNCE_SECONDS = float(os.getenv("GOTELEGRAM_TELEMT_RESTART_DEBOUNCE", "8"))
|
TELEMT_RESTART_DEBOUNCE_SECONDS = float(os.getenv("PCATELEGRAM_WEB_TELEMT_RESTART_DEBOUNCE", "8"))
|
||||||
_LAST_TELEMT_RESTART = 0.0
|
_LAST_TELEMT_RESTART = 0.0
|
||||||
|
|
||||||
|
|
||||||
@@ -391,7 +391,7 @@ def template_display_name(template_id: str) -> str:
|
|||||||
if template_id in ("deployed_site", "existing_site"):
|
if template_id in ("deployed_site", "existing_site"):
|
||||||
return "Existing deployed site"
|
return "Existing deployed site"
|
||||||
if template_id.startswith("custom_"):
|
if template_id.startswith("custom_"):
|
||||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
config = load_json(PCATELEGRAM_WEB_CONFIG) or {}
|
||||||
source = config.get("template_source", "")
|
source = config.get("template_source", "")
|
||||||
return f"{template_id} ({source})" if source else template_id
|
return f"{template_id} ({source})" if source else template_id
|
||||||
catalog = load_json(TEMPLATES_CATALOG) or {}
|
catalog = load_json(TEMPLATES_CATALOG) or {}
|
||||||
@@ -652,7 +652,7 @@ async def cmd_start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
welcome = (
|
welcome = (
|
||||||
f"<b>{_tf(user_id, 'welcome_title', GOTELEGRAM_VERSION)}</b>\n\n"
|
f"<b>{_tf(user_id, 'welcome_title', PCATELEGRAM_WEB_VERSION)}</b>\n\n"
|
||||||
f"{_t(user_id, 'welcome_subtitle')}\n"
|
f"{_t(user_id, 'welcome_subtitle')}\n"
|
||||||
f"{_t(user_id, 'welcome_powered')}\n\n"
|
f"{_t(user_id, 'welcome_powered')}\n\n"
|
||||||
f"{_t(user_id, 'welcome_prompt')}"
|
f"{_t(user_id, 'welcome_prompt')}"
|
||||||
@@ -750,10 +750,10 @@ async def get_status_text(user_id: Optional[int] = None) -> str:
|
|||||||
lines.append(f"<b>{_t(user_id, 'status_telemt')}:</b> v{version}")
|
lines.append(f"<b>{_t(user_id, 'status_telemt')}:</b> v{version}")
|
||||||
|
|
||||||
# Config status
|
# Config status
|
||||||
config = load_json(GOTELEGRAM_CONFIG)
|
config = load_json(PCATELEGRAM_WEB_CONFIG)
|
||||||
if config:
|
if config:
|
||||||
lines.append(f"<b>{_t(user_id, 'status_mode')}:</b> {html.escape(str(config.get('mode', 'unknown')))}")
|
lines.append(f"<b>{_t(user_id, 'status_mode')}:</b> {html.escape(str(config.get('mode', 'unknown')))}")
|
||||||
# install.sh/save_gotelegram_config uses "template_id" (not "template")
|
# install.sh/save_pcatelegram_web_config uses "template_id" (not "template")
|
||||||
tpl = config.get("template_id") or config.get("template")
|
tpl = config.get("template_id") or config.get("template")
|
||||||
if tpl:
|
if tpl:
|
||||||
lines.append(f"<b>{_t(user_id, 'status_template')}:</b> {html.escape(template_display_name(str(tpl)))}")
|
lines.append(f"<b>{_t(user_id, 'status_template')}:</b> {html.escape(template_display_name(str(tpl)))}")
|
||||||
@@ -795,15 +795,15 @@ async def get_traffic_stats() -> str:
|
|||||||
await sh(
|
await sh(
|
||||||
"bash",
|
"bash",
|
||||||
"-lc",
|
"-lc",
|
||||||
"source /opt/gotelegram/lib/common.sh; "
|
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||||
"source /opt/gotelegram/lib/stats.sh; "
|
"source /opt/pcatelegram_web/lib/stats.sh; "
|
||||||
"stats_init >/dev/null 2>&1 || true; stats_collect >/dev/null 2>&1 || true",
|
"stats_init >/dev/null 2>&1 || true; stats_collect >/dev/null 2>&1 || true",
|
||||||
timeout=15,
|
timeout=15,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Read current snapshot
|
# Read current snapshot
|
||||||
current_file = "/run/gotelegram/stats_current.json"
|
current_file = "/run/pcatelegram_web/stats_current.json"
|
||||||
history_file = "/opt/gotelegram/stats_history.csv"
|
history_file = "/opt/pcatelegram_web/stats_history.csv"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(current_file, "r") as f:
|
with open(current_file, "r") as f:
|
||||||
@@ -1032,7 +1032,7 @@ async def cb_lite_domain(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
|
|
||||||
await query.answer()
|
await query.answer()
|
||||||
|
|
||||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
config = load_json(PCATELEGRAM_WEB_CONFIG) or {}
|
||||||
current_mode = config.get("mode", "")
|
current_mode = config.get("mode", "")
|
||||||
|
|
||||||
if current_mode != "lite":
|
if current_mode != "lite":
|
||||||
@@ -1040,7 +1040,7 @@ async def cb_lite_domain(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
"<b>⚠️ Установка Lite из бота пока не поддерживается</b>\n\n"
|
"<b>⚠️ Установка Lite из бота пока не поддерживается</b>\n\n"
|
||||||
f"Выбранный домен: <code>{html.escape(domain)}</code>\n\n"
|
f"Выбранный домен: <code>{html.escape(domain)}</code>\n\n"
|
||||||
"Чтобы установить Lite, запустите на сервере:\n"
|
"Чтобы установить Lite, запустите на сервере:\n"
|
||||||
"<code>gotelegram</code> → <b>1) Прокси → 1) Установить/Обновить → Lite</b>\n\n"
|
"<code>pcatelegram_web</code> → <b>1) Прокси → 1) Установить/Обновить → Lite</b>\n\n"
|
||||||
"Существующая конфигурация <b>не была изменена</b>."
|
"Существующая конфигурация <b>не была изменена</b>."
|
||||||
)
|
)
|
||||||
keyboard = InlineKeyboardMarkup(
|
keyboard = InlineKeyboardMarkup(
|
||||||
@@ -1185,7 +1185,7 @@ async def _download_custom_git_template(url_with_branch: str) -> Tuple[bool, str
|
|||||||
url = base
|
url = base
|
||||||
|
|
||||||
tpl_id = "custom_" + hashlib.md5(url_with_branch.encode("utf-8")).hexdigest()[:10]
|
tpl_id = "custom_" + hashlib.md5(url_with_branch.encode("utf-8")).hexdigest()[:10]
|
||||||
target_dir = f"/opt/gotelegram/custom_templates/{tpl_id}"
|
target_dir = f"/opt/pcatelegram_web/custom_templates/{tpl_id}"
|
||||||
|
|
||||||
# Clean previous copy
|
# Clean previous copy
|
||||||
if os.path.isdir(target_dir):
|
if os.path.isdir(target_dir):
|
||||||
@@ -1403,7 +1403,7 @@ async def cb_pro_confirm(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Read current config to decide: in-place change-template vs fresh install
|
# Read current config to decide: in-place change-template vs fresh install
|
||||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
config = load_json(PCATELEGRAM_WEB_CONFIG) or {}
|
||||||
current_mode = config.get("mode", "")
|
current_mode = config.get("mode", "")
|
||||||
|
|
||||||
if current_mode != "pro":
|
if current_mode != "pro":
|
||||||
@@ -1413,7 +1413,7 @@ async def cb_pro_confirm(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
f"Выбранный шаблон: <code>{html.escape(tpl_id)}</code>\n\n"
|
f"Выбранный шаблон: <code>{html.escape(tpl_id)}</code>\n\n"
|
||||||
"Pro-режим требует ввода домена, email и проверки DNS. "
|
"Pro-режим требует ввода домена, email и проверки DNS. "
|
||||||
"Чтобы установить Pro, запустите на сервере:\n"
|
"Чтобы установить Pro, запустите на сервере:\n"
|
||||||
"<code>gotelegram</code> → <b>1) Прокси → 1) Установить/Обновить → Pro</b>\n\n"
|
"<code>pcatelegram_web</code> → <b>1) Прокси → 1) Установить/Обновить → Pro</b>\n\n"
|
||||||
"Существующая конфигурация <b>не была изменена</b>."
|
"Существующая конфигурация <b>не была изменена</b>."
|
||||||
)
|
)
|
||||||
keyboard = InlineKeyboardMarkup(
|
keyboard = InlineKeyboardMarkup(
|
||||||
@@ -1466,7 +1466,7 @@ async def cb_pro_confirm(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
+ (f" (<code>{html.escape(err_code)}</code>)" if err_code else "")
|
+ (f" (<code>{html.escape(err_code)}</code>)" if err_code else "")
|
||||||
+ "\n\n"
|
+ "\n\n"
|
||||||
"Существующая конфигурация <b>не была изменена</b>. "
|
"Существующая конфигурация <b>не была изменена</b>. "
|
||||||
"Попробуйте другой шаблон или запустите <code>gotelegram</code> из консоли."
|
"Попробуйте другой шаблон или запустите <code>pcatelegram_web</code> из консоли."
|
||||||
)
|
)
|
||||||
|
|
||||||
keyboard = InlineKeyboardMarkup(
|
keyboard = InlineKeyboardMarkup(
|
||||||
@@ -1766,7 +1766,7 @@ def user_traffic_history_summary(name: str) -> str:
|
|||||||
|
|
||||||
async def get_proxy_link_for_secret(secret: str) -> Optional[str]:
|
async def get_proxy_link_for_secret(secret: str) -> Optional[str]:
|
||||||
"""Generate a fake-TLS proxy link for an arbitrary telemt user secret."""
|
"""Generate a fake-TLS proxy link for an arbitrary telemt user secret."""
|
||||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
config = load_json(PCATELEGRAM_WEB_CONFIG) or {}
|
||||||
if not secret:
|
if not secret:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -1789,7 +1789,7 @@ async def get_proxy_link_for_secret(secret: str) -> Optional[str]:
|
|||||||
|
|
||||||
async def get_proxy_link() -> Optional[str]:
|
async def get_proxy_link() -> Optional[str]:
|
||||||
"""Generate proxy link from config. Pro-mode uses domain + fake-TLS secret."""
|
"""Generate proxy link from config. Pro-mode uses domain + fake-TLS secret."""
|
||||||
config = load_json(GOTELEGRAM_CONFIG)
|
config = load_json(PCATELEGRAM_WEB_CONFIG)
|
||||||
if not config:
|
if not config:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -1959,7 +1959,7 @@ async def _user_detail_text(name: str, secret: str, enabled: bool = True, max_un
|
|||||||
compact = json.dumps(data, ensure_ascii=False)[:600]
|
compact = json.dumps(data, ensure_ascii=False)[:600]
|
||||||
details = f"\n<pre>{html.escape(compact)}</pre>"
|
details = f"\n<pre>{html.escape(compact)}</pre>"
|
||||||
elif enabled:
|
elif enabled:
|
||||||
details = "\n<i>Runtime API недоступен. Новые установки goTelegram Pro включают его автоматически.</i>"
|
details = "\n<i>Runtime API недоступен. Новые установки PCAtelegram_web включают его автоматически.</i>"
|
||||||
else:
|
else:
|
||||||
details = "\n<i>Ключ отключён и сейчас не принимается telemt.</i>"
|
details = "\n<i>Ключ отключён и сейчас не принимается telemt.</i>"
|
||||||
details += user_traffic_history_summary(name)
|
details += user_traffic_history_summary(name)
|
||||||
@@ -2033,7 +2033,7 @@ async def cb_user_qr(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None
|
|||||||
await query.answer("Ссылка недоступна", show_alert=True)
|
await query.answer("Ссылка недоступна", show_alert=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
qr_file = f"/tmp/gotelegram_user_qr_{hashlib.sha256(name.encode()).hexdigest()[:10]}.png"
|
qr_file = f"/tmp/pcatelegram_web_user_qr_{hashlib.sha256(name.encode()).hexdigest()[:10]}.png"
|
||||||
code, _, _ = await sh("which", "qrencode")
|
code, _, _ = await sh("which", "qrencode")
|
||||||
if code == 0:
|
if code == 0:
|
||||||
code, _, _ = await sh("qrencode", "-o", qr_file, link)
|
code, _, _ = await sh("qrencode", "-o", qr_file, link)
|
||||||
@@ -2340,11 +2340,11 @@ def backup_schedule_state() -> Dict[str, Any]:
|
|||||||
|
|
||||||
async def run_full_backup() -> Tuple[bool, str]:
|
async def run_full_backup() -> Tuple[bool, str]:
|
||||||
script = (
|
script = (
|
||||||
"source /opt/gotelegram/lib/common.sh; "
|
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||||
"source /opt/gotelegram/lib/i18n.sh; "
|
"source /opt/pcatelegram_web/lib/i18n.sh; "
|
||||||
"source /opt/gotelegram/lib/telemt.sh; "
|
"source /opt/pcatelegram_web/lib/telemt.sh; "
|
||||||
"source /opt/gotelegram/lib/website.sh; "
|
"source /opt/pcatelegram_web/lib/website.sh; "
|
||||||
"source /opt/gotelegram/lib/backup.sh; "
|
"source /opt/pcatelegram_web/lib/backup.sh; "
|
||||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||||
"create_backup \"\"; "
|
"create_backup \"\"; "
|
||||||
"cleanup_old_backups 30"
|
"cleanup_old_backups 30"
|
||||||
@@ -2358,9 +2358,9 @@ async def set_full_backup_schedule(frequency: str) -> Tuple[bool, str]:
|
|||||||
if frequency not in {"off", "daily", "weekly", "monthly"}:
|
if frequency not in {"off", "daily", "weekly", "monthly"}:
|
||||||
return False, "unsupported schedule"
|
return False, "unsupported schedule"
|
||||||
script = (
|
script = (
|
||||||
"source /opt/gotelegram/lib/common.sh; "
|
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||||
"source /opt/gotelegram/lib/i18n.sh; "
|
"source /opt/pcatelegram_web/lib/i18n.sh; "
|
||||||
"source /opt/gotelegram/lib/backup.sh; "
|
"source /opt/pcatelegram_web/lib/backup.sh; "
|
||||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||||
f"set_backup_schedule {shlex.quote(frequency)}"
|
f"set_backup_schedule {shlex.quote(frequency)}"
|
||||||
)
|
)
|
||||||
@@ -2373,11 +2373,11 @@ async def launch_full_restore(backup_path: str) -> None:
|
|||||||
quoted_path = shlex.quote(backup_path)
|
quoted_path = shlex.quote(backup_path)
|
||||||
script = (
|
script = (
|
||||||
"sleep 1; "
|
"sleep 1; "
|
||||||
"source /opt/gotelegram/lib/common.sh; "
|
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||||
"source /opt/gotelegram/lib/i18n.sh; "
|
"source /opt/pcatelegram_web/lib/i18n.sh; "
|
||||||
"source /opt/gotelegram/lib/telemt.sh; "
|
"source /opt/pcatelegram_web/lib/telemt.sh; "
|
||||||
"source /opt/gotelegram/lib/website.sh; "
|
"source /opt/pcatelegram_web/lib/website.sh; "
|
||||||
"source /opt/gotelegram/lib/backup.sh; "
|
"source /opt/pcatelegram_web/lib/backup.sh; "
|
||||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||||
"create_backup \"\" >/dev/null 2>&1 || true; "
|
"create_backup \"\" >/dev/null 2>&1 || true; "
|
||||||
f"restore_backup {quoted_path} \"\" yes; "
|
f"restore_backup {quoted_path} \"\" yes; "
|
||||||
@@ -2431,14 +2431,14 @@ async def cb_menu_backup(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
"<b>💾 Бекапы</b>\n\n"
|
"<b>💾 Бекапы</b>\n\n"
|
||||||
f"Файлов: <code>{len(backups)}</code>\n"
|
f"Файлов: <code>{len(backups)}</code>\n"
|
||||||
f"Расписание: <b>{labels.get(schedule['frequency'], schedule['frequency'])}</b>\n\n"
|
f"Расписание: <b>{labels.get(schedule['frequency'], schedule['frequency'])}</b>\n\n"
|
||||||
"В бекап входит: telemt config, настройки goTelegram, ключи, отключённые ключи, сайт, шаблоны, SSL, бот, админка и история трафика."
|
"В бекап входит: telemt config, настройки PCAtelegram_web, ключи, отключённые ключи, сайт, шаблоны, SSL, бот, админка и история трафика."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
text = (
|
text = (
|
||||||
"<b>💾 Backups</b>\n\n"
|
"<b>💾 Backups</b>\n\n"
|
||||||
f"Files: <code>{len(backups)}</code>\n"
|
f"Files: <code>{len(backups)}</code>\n"
|
||||||
f"Schedule: <b>{labels.get(schedule['frequency'], schedule['frequency'])}</b>\n\n"
|
f"Schedule: <b>{labels.get(schedule['frequency'], schedule['frequency'])}</b>\n\n"
|
||||||
"Backups include telemt config, goTelegram settings, keys, disabled keys, site, templates, SSL, bot, admin panel and traffic history."
|
"Backups include telemt config, PCAtelegram_web settings, keys, disabled keys, site, templates, SSL, bot, admin panel and traffic history."
|
||||||
)
|
)
|
||||||
keyboard = InlineKeyboardMarkup(buttons)
|
keyboard = InlineKeyboardMarkup(buttons)
|
||||||
await safe_edit_message(query,text, reply_markup=keyboard, parse_mode="HTML")
|
await safe_edit_message(query,text, reply_markup=keyboard, parse_mode="HTML")
|
||||||
@@ -2583,7 +2583,7 @@ async def cb_restore_backup(update: Update, context: ContextTypes.DEFAULT_TYPE)
|
|||||||
if not safe_path:
|
if not safe_path:
|
||||||
text = "❌ Файл бекапа не найден" if get_user_lang(user_id) == "ru" else "❌ Backup file not found"
|
text = "❌ Файл бекапа не найден" if get_user_lang(user_id) == "ru" else "❌ Backup file not found"
|
||||||
elif safe_path.endswith(".enc"):
|
elif safe_path.endswith(".enc"):
|
||||||
text = "❌ Зашифрованный бекап пока восстанавливается через CLI: gotelegram → Восстановить." if get_user_lang(user_id) == "ru" else "❌ Encrypted backups are restored from CLI for now: gotelegram → Restore."
|
text = "❌ Зашифрованный бекап пока восстанавливается через CLI: pcatelegram_web → Восстановить." if get_user_lang(user_id) == "ru" else "❌ Encrypted backups are restored from CLI for now: pcatelegram_web → Restore."
|
||||||
else:
|
else:
|
||||||
await launch_full_restore(safe_path)
|
await launch_full_restore(safe_path)
|
||||||
text = (
|
text = (
|
||||||
@@ -2759,7 +2759,7 @@ async def cb_ssl_status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> N
|
|||||||
|
|
||||||
|
|
||||||
async def admin_web_host_hint() -> str:
|
async def admin_web_host_hint() -> str:
|
||||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
config = load_json(PCATELEGRAM_WEB_CONFIG) or {}
|
||||||
domain = str(config.get("domain") or "")
|
domain = str(config.get("domain") or "")
|
||||||
if domain:
|
if domain:
|
||||||
return domain
|
return domain
|
||||||
@@ -2998,7 +2998,7 @@ async def cb_menu_credits(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
|
|
||||||
text = (
|
text = (
|
||||||
f"<b>ℹ️ Credits & Acknowledgements</b>\n\n"
|
f"<b>ℹ️ Credits & Acknowledgements</b>\n\n"
|
||||||
f"<b>goTelegram Pro v{GOTELEGRAM_VERSION}</b>\n\n"
|
f"<b>PCAtelegram_web v{PCATELEGRAM_WEB_VERSION}</b>\n\n"
|
||||||
f"Built with love for the Telegram community\n\n"
|
f"Built with love for the Telegram community\n\n"
|
||||||
f"<b>Special thanks to:</b>\n\n"
|
f"<b>Special thanks to:</b>\n\n"
|
||||||
f"🙏 <b>telemt</b> - MTProxy engine\n"
|
f"🙏 <b>telemt</b> - MTProxy engine\n"
|
||||||
@@ -3010,7 +3010,7 @@ async def cb_menu_credits(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
f"🚀 <b>Start Bootstrap</b> - Bootstrap templates\n"
|
f"🚀 <b>Start Bootstrap</b> - Bootstrap templates\n"
|
||||||
f" Professional design framework\n\n"
|
f" Professional design framework\n\n"
|
||||||
f"💬 <b>Community</b> - Your feedback & support\n\n"
|
f"💬 <b>Community</b> - Your feedback & support\n\n"
|
||||||
f"<i>goTelegram Pro is open-source and community-driven</i>"
|
f"<i>PCAtelegram_web is open-source and community-driven</i>"
|
||||||
)
|
)
|
||||||
|
|
||||||
keyboard = InlineKeyboardMarkup(
|
keyboard = InlineKeyboardMarkup(
|
||||||
@@ -3030,7 +3030,7 @@ async def cb_menu_remove(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
await query.answer()
|
await query.answer()
|
||||||
|
|
||||||
text = (
|
text = (
|
||||||
"<b>⚠️ Remove goTelegram Pro</b>\n\n"
|
"<b>⚠️ Remove PCAtelegram_web</b>\n\n"
|
||||||
"This will completely remove the installation.\n"
|
"This will completely remove the installation.\n"
|
||||||
"Are you sure?"
|
"Are you sure?"
|
||||||
)
|
)
|
||||||
@@ -3048,16 +3048,16 @@ async def cb_remove_confirm(update: Update, context: ContextTypes.DEFAULT_TYPE)
|
|||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
await query.answer()
|
await query.answer()
|
||||||
|
|
||||||
await safe_edit_message(query,"⏳ Removing goTelegram Pro...")
|
await safe_edit_message(query,"⏳ Removing PCAtelegram_web...")
|
||||||
|
|
||||||
# Stop service
|
# Stop service
|
||||||
await sh("systemctl", "stop", TELEMT_SERVICE)
|
await sh("systemctl", "stop", TELEMT_SERVICE)
|
||||||
|
|
||||||
# Remove directories
|
# Remove directories
|
||||||
for path in ["/opt/gotelegram", WEBSITE_ROOT]:
|
for path in ["/opt/pcatelegram_web", WEBSITE_ROOT]:
|
||||||
await sh("rm", "-rf", path)
|
await sh("rm", "-rf", path)
|
||||||
|
|
||||||
text = "✅ goTelegram Pro removed successfully"
|
text = "✅ PCAtelegram_web removed successfully"
|
||||||
keyboard = InlineKeyboardMarkup(
|
keyboard = InlineKeyboardMarkup(
|
||||||
[[InlineKeyboardButton(_t(_uid(update), "btn_back"), callback_data="menu_main")]]
|
[[InlineKeyboardButton(_t(_uid(update), "btn_back"), callback_data="menu_main")]]
|
||||||
)
|
)
|
||||||
@@ -3120,7 +3120,7 @@ async def handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
await query.answer()
|
await query.answer()
|
||||||
buttons = get_main_menu(user_id)
|
buttons = get_main_menu(user_id)
|
||||||
text = (
|
text = (
|
||||||
f"<b>{_tf(user_id, 'welcome_title', GOTELEGRAM_VERSION)}</b>\n\n"
|
f"<b>{_tf(user_id, 'welcome_title', PCATELEGRAM_WEB_VERSION)}</b>\n\n"
|
||||||
f"{_t(user_id, 'welcome_subtitle')}\n"
|
f"{_t(user_id, 'welcome_subtitle')}\n"
|
||||||
f"{_t(user_id, 'welcome_prompt')}"
|
f"{_t(user_id, 'welcome_prompt')}"
|
||||||
)
|
)
|
||||||
@@ -3158,7 +3158,7 @@ async def handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
# Re-render main menu in the new language
|
# Re-render main menu in the new language
|
||||||
buttons = get_main_menu(user_id)
|
buttons = get_main_menu(user_id)
|
||||||
text = (
|
text = (
|
||||||
f"<b>{_tf(user_id, 'welcome_title', GOTELEGRAM_VERSION)}</b>\n\n"
|
f"<b>{_tf(user_id, 'welcome_title', PCATELEGRAM_WEB_VERSION)}</b>\n\n"
|
||||||
f"{_t(user_id, 'welcome_subtitle')}\n"
|
f"{_t(user_id, 'welcome_subtitle')}\n"
|
||||||
f"{_t(user_id, 'welcome_prompt')}"
|
f"{_t(user_id, 'welcome_prompt')}"
|
||||||
)
|
)
|
||||||
@@ -3282,12 +3282,12 @@ async def handle_text_message(update: Update, context: ContextTypes.DEFAULT_TYPE
|
|||||||
if not ok:
|
if not ok:
|
||||||
await update.message.reply_text(_t(user_id, info), parse_mode="HTML")
|
await update.message.reply_text(_t(user_id, info), parse_mode="HTML")
|
||||||
return
|
return
|
||||||
# Success — record in goTelegram Pro config. Use "template_id" (canonical
|
# Success — record in PCAtelegram_web config. Use "template_id" (canonical
|
||||||
# field name written by install.sh/save_gotelegram_config).
|
# field name written by install.sh/save_pcatelegram_web_config).
|
||||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
config = load_json(PCATELEGRAM_WEB_CONFIG) or {}
|
||||||
config["template_id"] = tpl_id
|
config["template_id"] = tpl_id
|
||||||
config["template_source"] = url
|
config["template_source"] = url
|
||||||
save_json(GOTELEGRAM_CONFIG, config)
|
save_json(PCATELEGRAM_WEB_CONFIG, config)
|
||||||
if config.get("mode") == "pro" and os.path.isdir(info):
|
if config.get("mode") == "pro" and os.path.isdir(info):
|
||||||
try:
|
try:
|
||||||
os.makedirs(WEBSITE_ROOT, exist_ok=True)
|
os.makedirs(WEBSITE_ROOT, exist_ok=True)
|
||||||
@@ -3353,7 +3353,7 @@ def main() -> None:
|
|||||||
application.add_error_handler(error_handler)
|
application.add_error_handler(error_handler)
|
||||||
|
|
||||||
# Run the bot
|
# Run the bot
|
||||||
logger.info(f"goTelegram Pro v{GOTELEGRAM_VERSION} bot starting...")
|
logger.info(f"PCAtelegram_web v{PCATELEGRAM_WEB_VERSION} bot starting...")
|
||||||
application.run_polling(allowed_updates=Update.ALL_TYPES)
|
application.run_polling(allowed_updates=Update.ALL_TYPES)
|
||||||
|
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# goTelegram Pro v2.5.0 Bot Configuration
|
# PCAtelegram_web v2.5.0 Bot Configuration
|
||||||
# Copy this to .env and fill in your values
|
# Copy this to .env and fill in your values
|
||||||
|
|
||||||
# Telegram Bot Token from @BotFather
|
# Telegram Bot Token from @BotFather
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
goTelegram Pro v2.5.0 Bot — i18n module
|
PCAtelegram_web v2.5.0 Bot — i18n module
|
||||||
Provides per-user language preferences and a simple t()/tf() API.
|
Provides per-user language preferences and a simple t()/tf() API.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@@ -23,9 +23,9 @@ logger = logging.getLogger(__name__)
|
|||||||
# ── Paths ─────────────────────────────────────────────────────────────────
|
# ── Paths ─────────────────────────────────────────────────────────────────
|
||||||
_MODULE_DIR = Path(__file__).resolve().parent
|
_MODULE_DIR = Path(__file__).resolve().parent
|
||||||
LANG_DIR = _MODULE_DIR / "lang"
|
LANG_DIR = _MODULE_DIR / "lang"
|
||||||
USER_LANG_FILE = Path("/opt/gotelegram-bot/user_langs.json")
|
USER_LANG_FILE = Path("/opt/pcatelegram_web-bot/user_langs.json")
|
||||||
GOTELEGRAM_CONFIG = Path("/opt/gotelegram/config.json")
|
PCATELEGRAM_WEB_CONFIG = Path("/opt/pcatelegram_web/config.json")
|
||||||
GOTELEGRAM_LANG_MARKER = Path("/opt/gotelegram/.language")
|
PCATELEGRAM_WEB_LANG_MARKER = Path("/opt/pcatelegram_web/.language")
|
||||||
|
|
||||||
# Supported codes; keep in sync with lang/*.json
|
# Supported codes; keep in sync with lang/*.json
|
||||||
SUPPORTED_LANGS = ("en", "ru")
|
SUPPORTED_LANGS = ("en", "ru")
|
||||||
@@ -34,18 +34,18 @@ SUPPORTED_LANGS = ("en", "ru")
|
|||||||
def _detect_default_lang() -> str:
|
def _detect_default_lang() -> str:
|
||||||
candidates = []
|
candidates = []
|
||||||
try:
|
try:
|
||||||
if GOTELEGRAM_CONFIG.exists():
|
if PCATELEGRAM_WEB_CONFIG.exists():
|
||||||
with open(GOTELEGRAM_CONFIG, "r", encoding="utf-8") as f:
|
with open(PCATELEGRAM_WEB_CONFIG, "r", encoding="utf-8") as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
candidates.extend([data.get("language"), data.get("lang")])
|
candidates.extend([data.get("language"), data.get("lang")])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("failed to read goTelegram Pro language config: %s", e)
|
logger.warning("failed to read PCAtelegram_web language config: %s", e)
|
||||||
try:
|
try:
|
||||||
if GOTELEGRAM_LANG_MARKER.exists():
|
if PCATELEGRAM_WEB_LANG_MARKER.exists():
|
||||||
candidates.append(GOTELEGRAM_LANG_MARKER.read_text(encoding="utf-8").strip()[:2])
|
candidates.append(PCATELEGRAM_WEB_LANG_MARKER.read_text(encoding="utf-8").strip()[:2])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("failed to read goTelegram Pro language marker: %s", e)
|
logger.warning("failed to read PCAtelegram_web language marker: %s", e)
|
||||||
candidates.append(os.getenv("BOT_LANG", ""))
|
candidates.append(os.getenv("BOT_LANG", ""))
|
||||||
for raw in candidates:
|
for raw in candidates:
|
||||||
code = str(raw or "").strip().lower()
|
code = str(raw or "").strip().lower()
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
"lang_saved": "Language saved: %s",
|
"lang_saved": "Language saved: %s",
|
||||||
"lang_choose": "Choose your language:",
|
"lang_choose": "Choose your language:",
|
||||||
|
|
||||||
"welcome_title": "goTelegram Pro v%s",
|
"welcome_title": "PCAtelegram_web v%s",
|
||||||
"welcome_subtitle": "🤖 MTProxy Management Bot",
|
"welcome_subtitle": "🤖 MTProxy Management Bot",
|
||||||
"welcome_powered": "Powered by telemt engine",
|
"welcome_powered": "Powered by telemt engine",
|
||||||
"welcome_prompt": "Select an action from the menu below:",
|
"welcome_prompt": "Select an action from the menu below:",
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"btn_no": "❌ No",
|
"btn_no": "❌ No",
|
||||||
|
|
||||||
"access_denied": "⛔ Access denied.\nYour ID: <code>%s</code>",
|
"access_denied": "⛔ Access denied.\nYour ID: <code>%s</code>",
|
||||||
"help_title": "goTelegram Pro Bot — Commands",
|
"help_title": "PCAtelegram_web Bot — Commands",
|
||||||
"help_lines": "/start — Main menu\n/help — This help\n/status — Quick status\n/logs — Latest logs\n/lang — Change language\n/addadmin ID — Add admin\n/deladmin ID — Remove admin\n\nUse the menu buttons for other operations.",
|
"help_lines": "/start — Main menu\n/help — This help\n/status — Quick status\n/logs — Latest logs\n/lang — Change language\n/addadmin ID — Add admin\n/deladmin ID — Remove admin\n\nUse the menu buttons for other operations.",
|
||||||
|
|
||||||
"menu_install": "⚙️ Install",
|
"menu_install": "⚙️ Install",
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
"lang_saved": "Язык сохранён: %s",
|
"lang_saved": "Язык сохранён: %s",
|
||||||
"lang_choose": "Выберите язык:",
|
"lang_choose": "Выберите язык:",
|
||||||
|
|
||||||
"welcome_title": "goTelegram Pro v%s",
|
"welcome_title": "PCAtelegram_web v%s",
|
||||||
"welcome_subtitle": "🤖 Бот управления MTProxy",
|
"welcome_subtitle": "🤖 Бот управления MTProxy",
|
||||||
"welcome_powered": "На базе движка telemt",
|
"welcome_powered": "На базе движка telemt",
|
||||||
"welcome_prompt": "Выберите действие в меню ниже:",
|
"welcome_prompt": "Выберите действие в меню ниже:",
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"btn_no": "❌ Нет",
|
"btn_no": "❌ Нет",
|
||||||
|
|
||||||
"access_denied": "⛔ Доступ запрещён.\nВаш ID: <code>%s</code>",
|
"access_denied": "⛔ Доступ запрещён.\nВаш ID: <code>%s</code>",
|
||||||
"help_title": "goTelegram Pro Bot — Команды",
|
"help_title": "PCAtelegram_web Bot — Команды",
|
||||||
"help_lines": "/start — Главное меню\n/help — Эта справка\n/status — Быстрый статус\n/logs — Последние логи\n/lang — Сменить язык\n/addadmin ID — Добавить админа\n/deladmin ID — Удалить админа\n\nИспользуйте кнопки меню для остальных операций.",
|
"help_lines": "/start — Главное меню\n/help — Эта справка\n/status — Быстрый статус\n/logs — Последние логи\n/lang — Сменить язык\n/addadmin ID — Добавить админа\n/deladmin ID — Удалить админа\n\nИспользуйте кнопки меню для остальных операций.",
|
||||||
|
|
||||||
"menu_install": "⚙️ Установить",
|
"menu_install": "⚙️ Установить",
|
||||||
Reference in New Issue
Block a user