mirror of
https://github.com/andrey271192/PCAtelegram_web.git
synced 2026-09-20 11:55:32 +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`:
|
||||
|
||||
```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:
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
После установки команда доступна как:
|
||||
|
||||
```bash
|
||||
gotelegram
|
||||
pcatelegram_web
|
||||
```
|
||||
|
||||
## Локальная проверка без GitHub
|
||||
|
||||
```bash
|
||||
rsync -a ./ root@SERVER:/opt/gotelegram/
|
||||
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'
|
||||
rsync -a ./ root@SERVER:/opt/pcatelegram_web/
|
||||
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` и запускает меню |
|
||||
| `install.sh` | основное CLI-меню GoTelegram |
|
||||
| `install_gotelegram_bot.sh` | отдельная установка Telegram-бота |
|
||||
| `bootstrap.sh` | загружает файлы проекта в `/opt/pcatelegram_web` и запускает меню |
|
||||
| `install.sh` | основное CLI-меню PCAtelegram_web |
|
||||
| `install_pcatelegram_web_bot.sh` | отдельная установка Telegram-бота |
|
||||
| `lib/` | общие функции, telemt, nginx/site, stats, backup, i18n |
|
||||
| `gotelegram-bot/` | Python Telegram bot |
|
||||
| `pcatelegram_web-bot/` | Python Telegram bot |
|
||||
| `admin-web/` | локальная web-admin панель |
|
||||
| `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` | база загрузки файлов |
|
||||
| `GOTELEGRAM_INSTALL_DIR` | `/opt/gotelegram` | путь установки |
|
||||
| `PCATELEGRAM_WEB_BASE` | `https://raw.githubusercontent.com/andrey271192/PCAtelegram_web/main` | база загрузки файлов |
|
||||
| `PCATELEGRAM_WEB_INSTALL_DIR` | `/opt/pcatelegram_web` | путь установки |
|
||||
| `GITHUB_TOKEN` / `GH_TOKEN` | пусто | token для private GitHub raw downloads |
|
||||
| `GOTELEGRAM_ADMIN_HOST` | `127.0.0.1` | bind web-admin |
|
||||
| `GOTELEGRAM_ADMIN_PORT` | `1984` | port web-admin |
|
||||
| `GOTELEGRAM_ADMIN_USER` | `admin` | Basic Auth login |
|
||||
| `GOTELEGRAM_ADMIN_PASSWORD` | пусто | Basic Auth password; обязателен при public bind |
|
||||
| `PCATELEGRAM_WEB_ADMIN_HOST` | `127.0.0.1` | bind web-admin |
|
||||
| `PCATELEGRAM_WEB_ADMIN_PORT` | `1984` | port web-admin |
|
||||
| `PCATELEGRAM_WEB_ADMIN_USER` | `admin` | Basic Auth login |
|
||||
| `PCATELEGRAM_WEB_ADMIN_PASSWORD` | пусто | Basic Auth password; обязателен при public bind |
|
||||
|
||||
## Web-admin
|
||||
|
||||
После первого запуска `gotelegram` локальная web-admin панель ставится как `gotelegram-admin.service`.
|
||||
После первого запуска `pcatelegram_web` локальная web-admin панель ставится как `pcatelegram_web-admin.service`.
|
||||
|
||||
Безопасный локальный доступ через SSH tunnel:
|
||||
|
||||
@@ -70,10 +70,10 @@ open http://127.0.0.1:1984/
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
Environment=GOTELEGRAM_ADMIN_HOST=0.0.0.0
|
||||
Environment=GOTELEGRAM_ADMIN_PORT=1984
|
||||
Environment=GOTELEGRAM_ADMIN_USER=admin
|
||||
Environment=GOTELEGRAM_ADMIN_PASSWORD=change-me
|
||||
Environment=PCATELEGRAM_WEB_ADMIN_HOST=0.0.0.0
|
||||
Environment=PCATELEGRAM_WEB_ADMIN_PORT=1984
|
||||
Environment=PCATELEGRAM_WEB_ADMIN_USER=admin
|
||||
Environment=PCATELEGRAM_WEB_ADMIN_PASSWORD=change-me
|
||||
```
|
||||
|
||||
Без HTTPS public Basic Auth гонит пароль открытым текстом. Для постоянного доступа лучше reverse proxy с TLS.
|
||||
@@ -81,6 +81,6 @@ Environment=GOTELEGRAM_ADMIN_PASSWORD=change-me
|
||||
## Проверки
|
||||
|
||||
```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" .
|
||||
```
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/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
|
||||
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
|
||||
@@ -32,35 +32,35 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
ADMIN_DIR = Path(os.getenv("GOTELEGRAM_ADMIN_DIR", "/opt/gotelegram-admin"))
|
||||
STATIC_DIR = Path(os.getenv("GOTELEGRAM_ADMIN_STATIC", str(ADMIN_DIR / "static")))
|
||||
ADMIN_DIR = Path(os.getenv("PCATELEGRAM_WEB_ADMIN_DIR", "/opt/pcatelegram_web-admin"))
|
||||
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"))
|
||||
HISTORY_FILE = Path(os.getenv("GOTELEGRAM_STATS_HISTORY", "/opt/gotelegram/stats_history.csv"))
|
||||
USER_HISTORY_FILE = Path(os.getenv("GOTELEGRAM_USER_STATS_HISTORY", "/opt/gotelegram/user_stats_history.csv"))
|
||||
CURRENT_STATS = Path(os.getenv("GOTELEGRAM_STATS_CURRENT", "/run/gotelegram/stats_current.json"))
|
||||
BACKUP_DIR = Path(os.getenv("GOTELEGRAM_BACKUP_DIR", "/opt/gotelegram/backups"))
|
||||
INSTALL_DIR = Path(os.getenv("GOTELEGRAM_DIR", "/opt/gotelegram"))
|
||||
BOT_DIR = Path(os.getenv("GOTELEGRAM_BOT_DIR", "/opt/gotelegram-bot"))
|
||||
DISABLED_USERS_FILE = Path(os.getenv("GOTELEGRAM_DISABLED_USERS", "/opt/gotelegram/disabled_users.json"))
|
||||
USER_LOCK_FILE = Path(os.getenv("GOTELEGRAM_USER_LOCK", "/run/gotelegram/admin-users.lock"))
|
||||
SHARED_443_CONFIG = Path(os.getenv("GOTELEGRAM_SHARED_443", "/opt/gotelegram/shared-443.json"))
|
||||
BACKUP_SCHEDULE_FILE = Path(os.getenv("GOTELEGRAM_BACKUP_SCHEDULE", "/opt/gotelegram/backup_schedule.json"))
|
||||
BACKUP_RESTORE_LOG = Path(os.getenv("GOTELEGRAM_BACKUP_RESTORE_LOG", "/var/log/gotelegram-restore.log"))
|
||||
HISTORY_FILE = Path(os.getenv("PCATELEGRAM_WEB_STATS_HISTORY", "/opt/pcatelegram_web/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("PCATELEGRAM_WEB_STATS_CURRENT", "/run/pcatelegram_web/stats_current.json"))
|
||||
BACKUP_DIR = Path(os.getenv("PCATELEGRAM_WEB_BACKUP_DIR", "/opt/pcatelegram_web/backups"))
|
||||
INSTALL_DIR = Path(os.getenv("PCATELEGRAM_WEB_DIR", "/opt/pcatelegram_web"))
|
||||
BOT_DIR = Path(os.getenv("PCATELEGRAM_WEB_BOT_DIR", "/opt/pcatelegram_web-bot"))
|
||||
DISABLED_USERS_FILE = Path(os.getenv("PCATELEGRAM_WEB_DISABLED_USERS", "/opt/pcatelegram_web/disabled_users.json"))
|
||||
USER_LOCK_FILE = Path(os.getenv("PCATELEGRAM_WEB_USER_LOCK", "/run/pcatelegram_web/admin-users.lock"))
|
||||
SHARED_443_CONFIG = Path(os.getenv("PCATELEGRAM_WEB_SHARED_443", "/opt/pcatelegram_web/shared-443.json"))
|
||||
BACKUP_SCHEDULE_FILE = Path(os.getenv("PCATELEGRAM_WEB_BACKUP_SCHEDULE", "/opt/pcatelegram_web/backup_schedule.json"))
|
||||
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")
|
||||
PORT = int(os.getenv("GOTELEGRAM_ADMIN_PORT", "1984"))
|
||||
ADMIN_USER = os.getenv("GOTELEGRAM_ADMIN_USER", "admin")
|
||||
ADMIN_PASSWORD = os.getenv("GOTELEGRAM_ADMIN_PASSWORD", "")
|
||||
ADMIN_REALM = os.getenv("GOTELEGRAM_ADMIN_REALM", "GoTelegram")
|
||||
HOST = os.getenv("PCATELEGRAM_WEB_ADMIN_HOST", "127.0.0.1")
|
||||
PORT = int(os.getenv("PCATELEGRAM_WEB_ADMIN_PORT", "1984"))
|
||||
ADMIN_USER = os.getenv("PCATELEGRAM_WEB_ADMIN_USER", "admin")
|
||||
ADMIN_PASSWORD = os.getenv("PCATELEGRAM_WEB_ADMIN_PASSWORD", "")
|
||||
ADMIN_REALM = os.getenv("PCATELEGRAM_WEB_ADMIN_REALM", "PCAtelegram_web")
|
||||
VERSION = "2.5.0"
|
||||
USER_RE = re.compile(r"^[A-Za-z0-9_.-]{1,48}$")
|
||||
LANG_RE = re.compile(r"^(en|ru)$")
|
||||
SENSITIVE_CONFIG_KEYS = {"secret"}
|
||||
BACKUP_NAME_RE = re.compile(r"^[A-Za-z0-9_.-]+\.tar\.gz(\.enc)?$")
|
||||
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
|
||||
TRAFFIC_WINDOWS = {
|
||||
"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:
|
||||
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()
|
||||
marker = INSTALL_DIR / ".language"
|
||||
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()
|
||||
if not LANG_RE.match(lang):
|
||||
raise ValueError("unsupported language")
|
||||
config = load_json(GOTELEGRAM_CONFIG, {}) or {}
|
||||
config = load_json(PCATELEGRAM_WEB_CONFIG, {}) or {}
|
||||
if not isinstance(config, dict):
|
||||
config = {}
|
||||
config["language"] = lang
|
||||
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 / ".language").write_text(lang + "\n", encoding="utf-8")
|
||||
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]]:
|
||||
config = load_json(GOTELEGRAM_CONFIG, {}) or {}
|
||||
config = load_json(PCATELEGRAM_WEB_CONFIG, {}) or {}
|
||||
mode = str(config.get("mode") or "")
|
||||
domain = str(config.get("domain") or "")
|
||||
settings = read_telemt_edge_settings()
|
||||
@@ -694,7 +694,7 @@ def public_ip() -> 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"))
|
||||
port = int(config.get("port", 443) or 443)
|
||||
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]:
|
||||
config = config or load_json(GOTELEGRAM_CONFIG, {}) or {}
|
||||
config = config or load_json(PCATELEGRAM_WEB_CONFIG, {}) or {}
|
||||
host = str(config.get("domain") or "").strip()
|
||||
if not host:
|
||||
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]:
|
||||
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)
|
||||
service = service_status("gotelegram-stats")
|
||||
service = service_status("pcatelegram_web-stats")
|
||||
now = int(time.time())
|
||||
ts = int(current.get("ts") or 0) if isinstance(current, dict) else 0
|
||||
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]]:
|
||||
if action == "repair":
|
||||
body = (
|
||||
"source /opt/gotelegram/lib/common.sh; "
|
||||
"source /opt/gotelegram/lib/i18n.sh; "
|
||||
"source /opt/gotelegram/lib/stats.sh; "
|
||||
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||
"source /opt/pcatelegram_web/lib/i18n.sh; "
|
||||
"source /opt/pcatelegram_web/lib/stats.sh; "
|
||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||
"install_stats_collector; "
|
||||
"stats_collect"
|
||||
@@ -1044,8 +1044,8 @@ def run_stats_action(action: str) -> tuple[bool, str, dict[str, Any]]:
|
||||
timeout = 180
|
||||
else:
|
||||
body = (
|
||||
"source /opt/gotelegram/lib/common.sh; "
|
||||
"source /opt/gotelegram/lib/stats.sh; "
|
||||
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||
"source /opt/pcatelegram_web/lib/stats.sh; "
|
||||
"stats_init >/dev/null 2>&1 || true; "
|
||||
"stats_collect"
|
||||
)
|
||||
@@ -1100,9 +1100,9 @@ def backup_schedule_status() -> dict[str, Any]:
|
||||
except ValueError:
|
||||
frequency = "off"
|
||||
calendar = None
|
||||
active_code, active, _ = run(["systemctl", "is-active", "gotelegram-backup.timer"], timeout=5)
|
||||
enabled_code, enabled, _ = run(["systemctl", "is-enabled", "gotelegram-backup.timer"], timeout=5)
|
||||
_, next_run, _ = run(["systemctl", "show", "gotelegram-backup.timer", "--property=NextElapseUSecRealtime", "--value"], timeout=5)
|
||||
active_code, active, _ = run(["systemctl", "is-active", "pcatelegram_web-backup.timer"], timeout=5)
|
||||
enabled_code, enabled, _ = run(["systemctl", "is-enabled", "pcatelegram_web-backup.timer"], timeout=5)
|
||||
_, next_run, _ = run(["systemctl", "show", "pcatelegram_web-backup.timer", "--property=NextElapseUSecRealtime", "--value"], timeout=5)
|
||||
return {
|
||||
"frequency": frequency,
|
||||
"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]]:
|
||||
backup_schedule_calendar(frequency)
|
||||
script = (
|
||||
"source /opt/gotelegram/lib/common.sh; "
|
||||
"source /opt/gotelegram/lib/i18n.sh; "
|
||||
"source /opt/gotelegram/lib/backup.sh; "
|
||||
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||
"source /opt/pcatelegram_web/lib/i18n.sh; "
|
||||
"source /opt/pcatelegram_web/lib/backup.sh; "
|
||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||
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]:
|
||||
script = (
|
||||
"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; "
|
||||
"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 30"
|
||||
@@ -1166,11 +1166,11 @@ def launch_restore_backup(name: str, password: str = "") -> dict[str, Any]:
|
||||
quoted_log = shlex.quote(str(BACKUP_RESTORE_LOG))
|
||||
script = (
|
||||
"sleep 1; "
|
||||
"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; "
|
||||
"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 \"\" >/dev/null 2>&1 || true; "
|
||||
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]:
|
||||
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:
|
||||
raise ValueError("unsupported service")
|
||||
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]:
|
||||
config = load_json(GOTELEGRAM_CONFIG, {}) or {}
|
||||
config = load_json(PCATELEGRAM_WEB_CONFIG, {}) or {}
|
||||
language = read_language(config)
|
||||
users = read_user_records()
|
||||
current = load_json(CURRENT_STATS, {}) or {}
|
||||
@@ -1258,9 +1258,9 @@ def overview_payload() -> dict[str, Any]:
|
||||
services = {
|
||||
"telemt": service_status("telemt"),
|
||||
"nginx": service_status("nginx"),
|
||||
"bot": service_status("gotelegram-bot"),
|
||||
"stats": service_status("gotelegram-stats"),
|
||||
"admin": service_status("gotelegram-admin"),
|
||||
"bot": service_status("pcatelegram_web-bot"),
|
||||
"stats": service_status("pcatelegram_web-stats"),
|
||||
"admin": service_status("pcatelegram_web-admin"),
|
||||
}
|
||||
return {
|
||||
"version": VERSION,
|
||||
@@ -1282,7 +1282,7 @@ def overview_payload() -> dict[str, Any]:
|
||||
|
||||
|
||||
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:
|
||||
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"))
|
||||
|
||||
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")
|
||||
return False
|
||||
return True
|
||||
@@ -1602,7 +1602,7 @@ class AdminHandler(BaseHTTPRequestHandler):
|
||||
self.send_json({"ok": True, "data": lang_payload})
|
||||
elif path.startswith("/api/services/") and path.endswith("/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:
|
||||
self.send_error_json(400, "unsupported service")
|
||||
return
|
||||
@@ -1698,7 +1698,7 @@ def main() -> None:
|
||||
if not STATIC_DIR.exists():
|
||||
raise SystemExit(f"static dir not found: {STATIC_DIR}")
|
||||
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()
|
||||
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ const i18n = {
|
||||
backupScheduleTitle: "Automatic backups",
|
||||
backupScheduleLoading: "Loading schedule...",
|
||||
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",
|
||||
scheduleDaily: "Daily",
|
||||
scheduleWeekly: "Weekly",
|
||||
@@ -210,7 +210,7 @@ const i18n = {
|
||||
ariaTrafficRange: "Traffic range",
|
||||
ariaTrafficView: "Traffic view",
|
||||
promoEyebrow: "Promo",
|
||||
promoTitle: "Support goTelegram Pro",
|
||||
promoTitle: "Support PCAtelegram_web",
|
||||
promoHosting1: "Hosting #1",
|
||||
promoHosting2: "Hosting #2",
|
||||
promoTips: "Tips",
|
||||
@@ -313,7 +313,7 @@ const i18n = {
|
||||
backupScheduleTitle: "Автобекапы",
|
||||
backupScheduleLoading: "Загрузка расписания...",
|
||||
backupIncludesTitle: "Что входит в бекап",
|
||||
backupIncludesText: "конфиг telemt, настройки goTelegram, ключи, отключённые ключи, сайт, шаблоны, SSL-сертификаты, бот, админка и история трафика.",
|
||||
backupIncludesText: "конфиг telemt, настройки PCAtelegram_web, ключи, отключённые ключи, сайт, шаблоны, SSL-сертификаты, бот, админка и история трафика.",
|
||||
scheduleOff: "Выкл",
|
||||
scheduleDaily: "Каждый день",
|
||||
scheduleWeekly: "Каждую неделю",
|
||||
@@ -437,7 +437,7 @@ const i18n = {
|
||||
ariaTrafficRange: "Период трафика",
|
||||
ariaTrafficView: "Вид трафика",
|
||||
promoEyebrow: "Промо",
|
||||
promoTitle: "Поддержать goTelegram Pro",
|
||||
promoTitle: "Поддержать PCAtelegram_web",
|
||||
promoHosting1: "Хостинг #1",
|
||||
promoHosting2: "Хостинг #2",
|
||||
promoTips: "Чаевые",
|
||||
@@ -478,7 +478,7 @@ const state = {
|
||||
qrLink: "",
|
||||
pendingUsers: new Set(),
|
||||
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;
|
||||
@@ -562,7 +562,7 @@ function syncAutoRefreshTimer() {
|
||||
|
||||
function setAutoRefresh(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();
|
||||
syncAutoRefreshTimer();
|
||||
}
|
||||
@@ -570,7 +570,7 @@ function setAutoRefresh(enabled) {
|
||||
async function api(path, options = {}) {
|
||||
const headers = {
|
||||
"Accept": "application/json",
|
||||
"X-GoTelegram-Admin": "1",
|
||||
"X-PCAtelegram-Web-Admin": "1",
|
||||
...(options.headers || {}),
|
||||
};
|
||||
if (options.body && !headers["Content-Type"]) headers["Content-Type"] = "application/json";
|
||||
@@ -610,7 +610,7 @@ function applyI18n() {
|
||||
function setTheme(theme) {
|
||||
state.theme = theme === "dark" ? "dark" : "light";
|
||||
document.documentElement.dataset.theme = state.theme;
|
||||
localStorage.setItem("gotelegram-theme", state.theme);
|
||||
localStorage.setItem("pcatelegram_web-theme", state.theme);
|
||||
applyI18n();
|
||||
if (state.overview) renderStats();
|
||||
if (state.userTraffic) renderUserTraffic();
|
||||
@@ -691,9 +691,9 @@ function renderServices(services = {}) {
|
||||
const items = [
|
||||
{ key: "telemt", label: "telemt", api: "telemt" },
|
||||
{ key: "nginx", label: "nginx", api: "nginx" },
|
||||
{ key: "bot", label: "bot", api: "gotelegram-bot" },
|
||||
{ key: "stats", label: "stats", api: "gotelegram-stats" },
|
||||
{ key: "admin", label: "admin", api: "gotelegram-admin" },
|
||||
{ key: "bot", label: "bot", api: "pcatelegram_web-bot" },
|
||||
{ key: "stats", label: "stats", api: "pcatelegram_web-stats" },
|
||||
{ key: "admin", label: "admin", api: "pcatelegram_web-admin" },
|
||||
];
|
||||
$("#services").innerHTML = items.map((item) => {
|
||||
const status = services[item.key] || "unknown";
|
||||
@@ -1639,7 +1639,7 @@ async function copyText(value) {
|
||||
}
|
||||
|
||||
function maybeShowPromo() {
|
||||
const key = "gotelegram-promo-last";
|
||||
const key = "pcatelegram_web-promo-last";
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const last = Number(localStorage.getItem(key) || 0);
|
||||
if (now - last < 86400) return;
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>goTelegram Pro Admin</title>
|
||||
<title>PCAtelegram_web Admin</title>
|
||||
<script>
|
||||
(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");
|
||||
document.documentElement.dataset.theme = theme;
|
||||
}());
|
||||
@@ -19,7 +19,7 @@
|
||||
<div class="brand">
|
||||
<div class="brand-mark">GT</div>
|
||||
<div>
|
||||
<strong>goTelegram Pro</strong>
|
||||
<strong>PCAtelegram_web</strong>
|
||||
<span data-i18n="brandSubtitle">Local Admin</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -66,7 +66,7 @@
|
||||
<section class="page-panel active" data-page="dashboard">
|
||||
<section class="visual-overview">
|
||||
<div>
|
||||
<p class="eyebrow">goTelegram Pro</p>
|
||||
<p class="eyebrow">PCAtelegram_web</p>
|
||||
<h2 id="visualTitle">Port 443</h2>
|
||||
<p id="visualText">Website, MTProxy and local admin status in one operational view.</p>
|
||||
</div>
|
||||
@@ -279,7 +279,7 @@
|
||||
</div>
|
||||
<div class="backup-includes">
|
||||
<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 id="backupsList" class="backup-list"></div>
|
||||
</section>
|
||||
@@ -307,9 +307,9 @@
|
||||
<select id="logService">
|
||||
<option value="telemt">telemt</option>
|
||||
<option value="nginx">nginx</option>
|
||||
<option value="gotelegram-bot">bot</option>
|
||||
<option value="gotelegram-stats">stats</option>
|
||||
<option value="gotelegram-admin">admin</option>
|
||||
<option value="pcatelegram_web-bot">bot</option>
|
||||
<option value="pcatelegram_web-stats">stats</option>
|
||||
<option value="pcatelegram_web-admin">admin</option>
|
||||
</select>
|
||||
<button id="loadLogsBtn" type="button" data-i18n="loadLogs">Load</button>
|
||||
</div>
|
||||
@@ -376,7 +376,7 @@
|
||||
<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>
|
||||
<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">
|
||||
<a href="https://vk.cc/ct29NQ" target="_blank" rel="noreferrer">
|
||||
<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
|
||||
# GoTelegram Pro — bootstrap installer from this repository.
|
||||
# PCAtelegram_web — bootstrap installer from this repository.
|
||||
set -euo pipefail
|
||||
|
||||
GOTELEGRAM_BASE="${GOTELEGRAM_BASE:-https://raw.githubusercontent.com/andrey271192/gotelegram/main}"
|
||||
INSTALL_DIR="${GOTELEGRAM_INSTALL_DIR:-/opt/gotelegram}"
|
||||
PCATELEGRAM_WEB_BASE="${PCATELEGRAM_WEB_BASE:-https://raw.githubusercontent.com/andrey271192/PCAtelegram_web/main}"
|
||||
INSTALL_DIR="${PCATELEGRAM_WEB_INSTALL_DIR:-/opt/pcatelegram_web}"
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
@@ -23,13 +23,13 @@ for cmd in curl jq; do
|
||||
done
|
||||
|
||||
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/website.sh" "lib/templates_catalog.sh" "lib/stats.sh" "lib/i18n.sh"
|
||||
"lib/lang/en.sh" "lib/lang/ru.sh"
|
||||
"gotelegram-bot/bot.py" "gotelegram-bot/i18n.py"
|
||||
"gotelegram-bot/lang/en.json" "gotelegram-bot/lang/ru.json"
|
||||
"gotelegram-bot/config.example.env" "gotelegram-bot/requirements.txt" "gotelegram-bot/README.md"
|
||||
"pcatelegram_web-bot/bot.py" "pcatelegram_web-bot/i18n.py"
|
||||
"pcatelegram_web-bot/lang/en.json" "pcatelegram_web-bot/lang/ru.json"
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -45,7 +45,7 @@ download_file() {
|
||||
|
||||
mkdir -p "$(dirname "$local_path")"
|
||||
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
|
||||
return 0
|
||||
fi
|
||||
@@ -56,8 +56,8 @@ download_file() {
|
||||
return 1
|
||||
}
|
||||
|
||||
echo -e " ${CYAN}↻${NC} Загрузка GoTelegram из ${GOTELEGRAM_BASE%/}..."
|
||||
mkdir -p "${INSTALL_DIR}/lib/lang" "${INSTALL_DIR}/gotelegram-bot/lang" "${INSTALL_DIR}/admin-web/static"
|
||||
echo -e " ${CYAN}↻${NC} Загрузка PCAtelegram_web из ${PCATELEGRAM_WEB_BASE%/}..."
|
||||
mkdir -p "${INSTALL_DIR}/lib/lang" "${INSTALL_DIR}/pcatelegram_web-bot/lang" "${INSTALL_DIR}/admin-web/static"
|
||||
|
||||
failed=0
|
||||
for f in "${FILES[@]}"; do
|
||||
@@ -69,10 +69,10 @@ for f in "${FILES[@]}"; do
|
||||
done
|
||||
[ "$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}/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
|
||||
ln -sf "${INSTALL_DIR}/install.sh" /usr/local/bin/gotelegram
|
||||
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/pcatelegram_web
|
||||
|
||||
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
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
# 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)
|
||||
#
|
||||
# Install:
|
||||
@@ -46,7 +46,7 @@ show_main_menu() {
|
||||
# ── Header (no right border — ANSI breaks alignment) ──
|
||||
echo ""
|
||||
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}"
|
||||
|
||||
# ── Service health ──
|
||||
@@ -239,7 +239,7 @@ menu_version() {
|
||||
echo ""
|
||||
echo -e " ${BOLD}${WHITE}$(t version_title)${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_tech)${NC} Anti-DPI, Fake TLS, TCP Splice"
|
||||
echo -e " ${WHITE}$(t version_license)${NC} MIT"
|
||||
@@ -248,21 +248,21 @@ menu_version() {
|
||||
|
||||
# ── Upgrade migration ────────────────────────────────────────────────────────
|
||||
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
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
local ts tmp archive
|
||||
ts=$(date +%Y%m%d_%H%M%S)
|
||||
tmp="/tmp/gotelegram_preupgrade_${ts}"
|
||||
archive="$BACKUP_DIR/preupgrade_${GOTELEGRAM_VERSION}_${ts}.tar.gz"
|
||||
tmp="/tmp/pcatelegram_web_preupgrade_${ts}"
|
||||
archive="$BACKUP_DIR/preupgrade_${PCATELEGRAM_WEB_VERSION}_${ts}.tar.gz"
|
||||
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 "$NGINX_SITE_CONF" ] && mkdir -p "$tmp/etc/nginx/sites-available" && cp "$NGINX_SITE_CONF" "$tmp/etc/nginx/sites-available/gotelegram" 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
|
||||
[ -f "$BOT_DIR/.env" ] && mkdir -p "$tmp/opt/gotelegram-bot" && cp "$BOT_DIR/.env" "$tmp/opt/gotelegram-bot/.env" 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/pcatelegram_web-site" && cp -a "$WEBSITE_ROOT/." "$tmp/var/www/pcatelegram_web-site/" 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
|
||||
log_dim "Pre-upgrade snapshot: $archive"
|
||||
@@ -278,8 +278,8 @@ read_config_or_default() {
|
||||
|
||||
detect_deployed_template_id() {
|
||||
local tpl=""
|
||||
if [ -f "$WEBSITE_ROOT/.gotelegram_template_id" ]; then
|
||||
tpl=$(head -1 "$WEBSITE_ROOT/.gotelegram_template_id" 2>/dev/null || echo "")
|
||||
if [ -f "$WEBSITE_ROOT/.pcatelegram_web_template_id" ]; then
|
||||
tpl=$(head -1 "$WEBSITE_ROOT/.pcatelegram_web_template_id" 2>/dev/null || echo "")
|
||||
[ -n "$tpl" ] && { echo "$tpl"; return 0; }
|
||||
fi
|
||||
if [ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ]; then
|
||||
@@ -293,15 +293,15 @@ detect_deployed_template_id() {
|
||||
|
||||
detect_template_source() {
|
||||
local src
|
||||
if [ -f "$WEBSITE_ROOT/.gotelegram_template_source" ]; then
|
||||
src=$(head -1 "$WEBSITE_ROOT/.gotelegram_template_source" 2>/dev/null || echo "")
|
||||
if [ -f "$WEBSITE_ROOT/.pcatelegram_web_template_source" ]; then
|
||||
src=$(head -1 "$WEBSITE_ROOT/.pcatelegram_web_template_source" 2>/dev/null || echo "")
|
||||
[ -n "$src" ] && { echo "$src"; return 0; }
|
||||
fi
|
||||
[ -d "$WEBSITE_ROOT" ] && [ -f "$WEBSITE_ROOT/index.html" ] && return 0
|
||||
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 lang installed_at stats_enabled tmp
|
||||
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
|
||||
|
||||
jq -n \
|
||||
--arg version "$GOTELEGRAM_VERSION" \
|
||||
--arg version "$PCATELEGRAM_WEB_VERSION" \
|
||||
--arg engine "telemt" \
|
||||
--arg mode "$mode" \
|
||||
--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)' \
|
||||
> "$tmp" || { rm -f "$tmp"; return 1; }
|
||||
|
||||
mkdir -p "$(dirname "$GOTELEGRAM_CONFIG")"
|
||||
mv "$tmp" "$GOTELEGRAM_CONFIG"
|
||||
chmod 600 "$GOTELEGRAM_CONFIG"
|
||||
mkdir -p "$(dirname "$PCATELEGRAM_WEB_CONFIG")"
|
||||
mv "$tmp" "$PCATELEGRAM_WEB_CONFIG"
|
||||
chmod 600 "$PCATELEGRAM_WEB_CONFIG"
|
||||
}
|
||||
|
||||
auto_migrate_legacy_state() {
|
||||
local marker="$GOTELEGRAM_DIR/.migrated_${GOTELEGRAM_VERSION}"
|
||||
local marker="$PCATELEGRAM_WEB_DIR/.migrated_${PCATELEGRAM_WEB_VERSION}"
|
||||
local current_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
|
||||
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
|
||||
|
||||
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_source=$(detect_template_source || echo "")
|
||||
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
|
||||
[ -n "$tpl_source" ] && echo "$tpl_source" > "$WEBSITE_ROOT/.gotelegram_template_source" 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/.pcatelegram_web_template_source" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
if [ -f "$TELEMT_CONFIG" ]; then
|
||||
if ! grep -q '\[server.api\]' "$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
|
||||
replace_telemt_users_block "$users_block" "$TELEMT_CONFIG"
|
||||
changed=1
|
||||
@@ -423,7 +423,7 @@ auto_migrate_legacy_state() {
|
||||
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"
|
||||
|
||||
if [ "$changed" = "1" ] && systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then
|
||||
@@ -520,15 +520,15 @@ install_lite_mode() {
|
||||
# Start
|
||||
start_telemt || return
|
||||
|
||||
# Save goTelegram Pro config
|
||||
save_gotelegram_config "telemt" "lite" "$port" "$secret" "$domain" "" ""
|
||||
# Save PCAtelegram_web config
|
||||
save_pcatelegram_web_config "telemt" "lite" "$port" "$secret" "$domain" "" ""
|
||||
|
||||
# Credits
|
||||
show_credits
|
||||
|
||||
# Result
|
||||
show_proxy_info
|
||||
log_success "$(tf install_done "$GOTELEGRAM_VERSION" "Lite")"
|
||||
log_success "$(tf install_done "$PCATELEGRAM_WEB_VERSION" "Lite")"
|
||||
}
|
||||
|
||||
# ── Pro mode ────────────────────────────────────────────────────────────────
|
||||
@@ -620,12 +620,12 @@ install_pro_mode() {
|
||||
# Save config
|
||||
local tpl_id
|
||||
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
|
||||
show_proxy_info_pro "$user_domain" "$faketls_secret"
|
||||
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 -e " ${BOLD}$(t share_title)${NC}"
|
||||
echo ""
|
||||
printf "$(t share_line1)\n" "$GOTELEGRAM_VERSION"
|
||||
printf "$(t share_line1)\n" "$PCATELEGRAM_WEB_VERSION"
|
||||
echo ""
|
||||
printf "$(t share_server)\n" "$server_display"
|
||||
printf "$(t share_port)\n" "$port"
|
||||
@@ -842,7 +842,7 @@ menu_remove() {
|
||||
if [ "$mode" = "pro" ]; then
|
||||
remove_pro_mode
|
||||
fi
|
||||
rm -f "$GOTELEGRAM_CONFIG"
|
||||
rm -f "$PCATELEGRAM_WEB_CONFIG"
|
||||
log_success "$(t remove_proxy_done)"
|
||||
;;
|
||||
2)
|
||||
@@ -861,7 +861,7 @@ menu_remove() {
|
||||
if [ "$mode" = "pro" ]; then
|
||||
remove_pro_mode
|
||||
fi
|
||||
rm -f "$GOTELEGRAM_CONFIG"
|
||||
rm -f "$PCATELEGRAM_WEB_CONFIG"
|
||||
# Bot
|
||||
if [ "$(bot_service_status)" != "not_installed" ]; then
|
||||
systemctl stop "$BOT_SERVICE" 2>/dev/null
|
||||
@@ -877,8 +877,8 @@ menu_remove() {
|
||||
}
|
||||
|
||||
# ── Telegram-бот ────────────────────────────────────────────────────────────
|
||||
BOT_DIR="/opt/gotelegram-bot"
|
||||
BOT_SERVICE="gotelegram-bot"
|
||||
BOT_DIR="/opt/pcatelegram_web-bot"
|
||||
BOT_SERVICE="pcatelegram_web-bot"
|
||||
|
||||
admin_web_service_status() {
|
||||
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)
|
||||
cat > "/etc/systemd/system/${ADMIN_WEB_SERVICE}.service" << SVCEOF
|
||||
[Unit]
|
||||
Description=goTelegram Pro v${GOTELEGRAM_VERSION} Local Web Admin
|
||||
Description=PCAtelegram_web v${PCATELEGRAM_WEB_VERSION} Local Web Admin
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
@@ -915,8 +915,8 @@ WorkingDirectory=$ADMIN_WEB_DIR
|
||||
ExecStart=$python_bin $ADMIN_WEB_DIR/server.py
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
Environment=GOTELEGRAM_ADMIN_HOST=$ADMIN_WEB_HOST
|
||||
Environment=GOTELEGRAM_ADMIN_PORT=$ADMIN_WEB_PORT
|
||||
Environment=PCATELEGRAM_WEB_ADMIN_HOST=$ADMIN_WEB_HOST
|
||||
Environment=PCATELEGRAM_WEB_ADMIN_PORT=$ADMIN_WEB_PORT
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -964,20 +964,20 @@ bot_service_status() {
|
||||
}
|
||||
|
||||
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
|
||||
[ -f "$BOT_DIR/.env" ] || return 0
|
||||
|
||||
local needs_update=0
|
||||
[ -f "$SCRIPT_DIR/gotelegram-bot/bot.py" ] && \
|
||||
! cmp -s "$SCRIPT_DIR/gotelegram-bot/bot.py" "$BOT_DIR/bot.py" && needs_update=1
|
||||
[ -f "$SCRIPT_DIR/gotelegram-bot/i18n.py" ] && \
|
||||
! cmp -s "$SCRIPT_DIR/gotelegram-bot/i18n.py" "$BOT_DIR/i18n.py" && needs_update=1
|
||||
[ -f "$SCRIPT_DIR/gotelegram-bot/requirements.txt" ] && \
|
||||
! cmp -s "$SCRIPT_DIR/gotelegram-bot/requirements.txt" "$BOT_DIR/requirements.txt" && needs_update=1
|
||||
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" ] && \
|
||||
! cmp -s "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" "$BOT_DIR/bot.py" && needs_update=1
|
||||
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/i18n.py" ] && \
|
||||
! cmp -s "$SCRIPT_DIR/pcatelegram_web-bot/i18n.py" "$BOT_DIR/i18n.py" && needs_update=1
|
||||
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/requirements.txt" ] && \
|
||||
! cmp -s "$SCRIPT_DIR/pcatelegram_web-bot/requirements.txt" "$BOT_DIR/requirements.txt" && needs_update=1
|
||||
|
||||
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
|
||||
lang_name=$(basename "$lang_file")
|
||||
! cmp -s "$lang_file" "$BOT_DIR/lang/$lang_name" && needs_update=1
|
||||
@@ -1101,27 +1101,27 @@ bot_install() {
|
||||
|
||||
# Copy bot files
|
||||
mkdir -p "$BOT_DIR"
|
||||
if [ -f "$SCRIPT_DIR/gotelegram-bot/bot.py" ]; then
|
||||
cp "$SCRIPT_DIR/gotelegram-bot/bot.py" "$BOT_DIR/"
|
||||
cp "$SCRIPT_DIR/gotelegram-bot/requirements.txt" "$BOT_DIR/"
|
||||
[ -f "$SCRIPT_DIR/gotelegram-bot/config.example.env" ] && \
|
||||
cp "$SCRIPT_DIR/gotelegram-bot/config.example.env" "$BOT_DIR/"
|
||||
if [ -f "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" ]; then
|
||||
cp "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" "$BOT_DIR/"
|
||||
cp "$SCRIPT_DIR/pcatelegram_web-bot/requirements.txt" "$BOT_DIR/"
|
||||
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/config.example.env" ] && \
|
||||
cp "$SCRIPT_DIR/pcatelegram_web-bot/config.example.env" "$BOT_DIR/"
|
||||
# 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"
|
||||
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
|
||||
[ -f "$SCRIPT_DIR/gotelegram-bot/i18n.py" ] && \
|
||||
cp "$SCRIPT_DIR/gotelegram-bot/i18n.py" "$BOT_DIR/"
|
||||
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/i18n.py" ] && \
|
||||
cp "$SCRIPT_DIR/pcatelegram_web-bot/i18n.py" "$BOT_DIR/"
|
||||
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
|
||||
fi
|
||||
|
||||
# Templates catalog — skip if source and dest are the same file (symlink install case)
|
||||
if [ -f "$SCRIPT_DIR/templates_catalog.json" ]; then
|
||||
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
|
||||
cp "$src_tc" "$dst_tc"
|
||||
fi
|
||||
@@ -1217,7 +1217,7 @@ bot_install() {
|
||||
# Systemd
|
||||
cat > "/etc/systemd/system/${BOT_SERVICE}.service" << SVCEOF
|
||||
[Unit]
|
||||
Description=goTelegram Pro v${GOTELEGRAM_VERSION} Telegram Bot
|
||||
Description=PCAtelegram_web v${PCATELEGRAM_WEB_VERSION} Telegram Bot
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
@@ -1407,7 +1407,7 @@ bot_remove() {
|
||||
_promo_block() {
|
||||
# Print a promo section without width-fragile box borders (i18n safe)
|
||||
local line2; line2=$(printf '─%.0s' {1..54})
|
||||
local youtube_link="${GOTELEGRAM_YOUTUBE_LINK:-}"
|
||||
local youtube_link="${PCATELEGRAM_WEB_YOUTUBE_LINK:-}"
|
||||
echo ""
|
||||
echo -e " ${DIM}${line2}${NC}"
|
||||
echo -e " ${BOLD}${YELLOW}$(t promo_host1_title)${NC}"
|
||||
@@ -1437,7 +1437,7 @@ menu_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
|
||||
return 0 # никогда не показывали
|
||||
fi
|
||||
@@ -1452,8 +1452,8 @@ should_show_promo() {
|
||||
}
|
||||
|
||||
mark_promo_shown() {
|
||||
mkdir -p "$GOTELEGRAM_DIR"
|
||||
date +%s > "$GOTELEGRAM_DIR/.promo_last_shown"
|
||||
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||
date +%s > "$PCATELEGRAM_WEB_DIR/.promo_last_shown"
|
||||
}
|
||||
|
||||
_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_host2)" "https://vk.cc/cUxAhj"
|
||||
_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
|
||||
|
||||
mark_promo_shown
|
||||
@@ -1489,10 +1489,10 @@ show_promo_with_qr() {
|
||||
# ── First-run: pick language ─────────────────────────────────────────────────
|
||||
first_run_language_picker() {
|
||||
# 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=""
|
||||
if [ -f "$GOTELEGRAM_CONFIG" ] && command -v jq >/dev/null 2>&1; then
|
||||
cfg_lang=$(jq -r '.language // empty' "$GOTELEGRAM_CONFIG" 2>/dev/null)
|
||||
if [ -f "$PCATELEGRAM_WEB_CONFIG" ] && command -v jq >/dev/null 2>&1; then
|
||||
cfg_lang=$(jq -r '.language // empty' "$PCATELEGRAM_WEB_CONFIG" 2>/dev/null)
|
||||
fi
|
||||
if [ -f "$marker" ] || [ -n "$cfg_lang" ]; then
|
||||
return 0
|
||||
@@ -1524,8 +1524,8 @@ menu_language() {
|
||||
# Non-interactive action dispatcher (bot / CI / scripting interface)
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
# Usage examples:
|
||||
# gotelegram --action=change-template --template=th_ariclaw --json
|
||||
# gotelegram --action=change-lite-domain --domain=google.com --json
|
||||
# pcatelegram_web --action=change-template --template=th_ariclaw --json
|
||||
# pcatelegram_web --action=change-lite-domain --domain=google.com --json
|
||||
#
|
||||
# Rules for action handlers:
|
||||
# - Only JSON may be written to stdout (the caller parses it).
|
||||
@@ -1558,7 +1558,7 @@ bot_emit_json() {
|
||||
bot_update_config_field() {
|
||||
local key="$1"
|
||||
local value="$2"
|
||||
if [ ! -f "$GOTELEGRAM_CONFIG" ]; then
|
||||
if [ ! -f "$PCATELEGRAM_WEB_CONFIG" ]; then
|
||||
return 1
|
||||
fi
|
||||
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)
|
||||
if jq --arg k "$key" --arg v "$value" --arg t "$now" \
|
||||
'.[$k] = $v | .updated_at = $t' \
|
||||
"$GOTELEGRAM_CONFIG" > "$tmp" 2>/dev/null; then
|
||||
mv "$tmp" "$GOTELEGRAM_CONFIG"
|
||||
chmod 600 "$GOTELEGRAM_CONFIG"
|
||||
"$PCATELEGRAM_WEB_CONFIG" > "$tmp" 2>/dev/null; then
|
||||
mv "$tmp" "$PCATELEGRAM_WEB_CONFIG"
|
||||
chmod 600 "$PCATELEGRAM_WEB_CONFIG"
|
||||
return 0
|
||||
fi
|
||||
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
|
||||
# and one process would see a truncated file ("no secret in config").
|
||||
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)
|
||||
[ -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
|
||||
# GoTelegram v2.5.0 — Установка Telegram-бота
|
||||
# PCAtelegram_web v2.5.0 — Установка Telegram-бота
|
||||
# Создаёт venv, ставит зависимости, настраивает systemd
|
||||
|
||||
set -e
|
||||
@@ -9,11 +9,11 @@ YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
BOT_DIR="/opt/gotelegram-bot"
|
||||
SERVICE_NAME="gotelegram-bot"
|
||||
GOTELEGRAM_DIR="/opt/gotelegram"
|
||||
ADMIN_WEB_DIR="/opt/gotelegram-admin"
|
||||
ADMIN_WEB_SERVICE="gotelegram-admin"
|
||||
BOT_DIR="/opt/pcatelegram_web-bot"
|
||||
SERVICE_NAME="pcatelegram_web-bot"
|
||||
PCATELEGRAM_WEB_DIR="/opt/pcatelegram_web"
|
||||
ADMIN_WEB_DIR="/opt/pcatelegram_web-admin"
|
||||
ADMIN_WEB_SERVICE="pcatelegram_web-admin"
|
||||
ADMIN_WEB_PORT="1984"
|
||||
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
@@ -22,7 +22,7 @@ if [ "$EUID" -ne 0 ]; then
|
||||
fi
|
||||
|
||||
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 ""
|
||||
|
||||
@@ -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/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}"
|
||||
cp "$SCRIPT_DIR/gotelegram-bot/bot.py" "$BOT_DIR/"
|
||||
cp "$SCRIPT_DIR/gotelegram-bot/requirements.txt" "$BOT_DIR/"
|
||||
[ -f "$SCRIPT_DIR/gotelegram-bot/config.example.env" ] && cp "$SCRIPT_DIR/gotelegram-bot/config.example.env" "$BOT_DIR/"
|
||||
cp "$SCRIPT_DIR/pcatelegram_web-bot/bot.py" "$BOT_DIR/"
|
||||
cp "$SCRIPT_DIR/pcatelegram_web-bot/requirements.txt" "$BOT_DIR/"
|
||||
[ -f "$SCRIPT_DIR/pcatelegram_web-bot/config.example.env" ] && cp "$SCRIPT_DIR/pcatelegram_web-bot/config.example.env" "$BOT_DIR/"
|
||||
else
|
||||
echo -e "${RED}Файлы бота не найдены в $SCRIPT_DIR/gotelegram-bot/${NC}"
|
||||
echo -e "${RED}Файлы бота не найдены в $SCRIPT_DIR/pcatelegram_web-bot/${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Копируем каталог шаблонов
|
||||
if [ -f "$SCRIPT_DIR/templates_catalog.json" ]; then
|
||||
mkdir -p "$GOTELEGRAM_DIR"
|
||||
cp "$SCRIPT_DIR/templates_catalog.json" "$GOTELEGRAM_DIR/"
|
||||
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||
cp "$SCRIPT_DIR/templates_catalog.json" "$PCATELEGRAM_WEB_DIR/"
|
||||
echo -e "${GREEN}[*] Каталог шаблонов скопирован${NC}"
|
||||
fi
|
||||
|
||||
@@ -98,7 +98,7 @@ fi
|
||||
# ── Systemd ──────────────────────────────────────────────────────────────────
|
||||
cat > "/etc/systemd/system/${SERVICE_NAME}.service" << EOF
|
||||
[Unit]
|
||||
Description=GoTelegram v2.5.0 Telegram Bot
|
||||
Description=PCAtelegram_web v2.5.0 Telegram Bot
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
@@ -130,7 +130,7 @@ if [ -f "$SCRIPT_DIR/admin-web/server.py" ]; then
|
||||
PYTHON_BIN=$(command -v python3)
|
||||
cat > "/etc/systemd/system/${ADMIN_WEB_SERVICE}.service" << EOF
|
||||
[Unit]
|
||||
Description=GoTelegram v2.5.0 Local Web Admin
|
||||
Description=PCAtelegram_web v2.5.0 Local Web Admin
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
@@ -139,8 +139,8 @@ WorkingDirectory=$ADMIN_WEB_DIR
|
||||
ExecStart=$PYTHON_BIN $ADMIN_WEB_DIR/server.py
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
Environment=GOTELEGRAM_ADMIN_HOST=127.0.0.1
|
||||
Environment=GOTELEGRAM_ADMIN_PORT=$ADMIN_WEB_PORT
|
||||
Environment=PCATELEGRAM_WEB_ADMIN_HOST=127.0.0.1
|
||||
Environment=PCATELEGRAM_WEB_ADMIN_PORT=$ADMIN_WEB_PORT
|
||||
|
||||
[Install]
|
||||
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
|
||||
# goTelegram Pro v2.5.0 — backup and restore (i18n-aware)
|
||||
# PCAtelegram_web v2.5.0 — backup and restore (i18n-aware)
|
||||
|
||||
# ── Создание бекапа ──────────────────────────────────────────────────────────
|
||||
create_backup() {
|
||||
@@ -12,9 +12,9 @@ create_backup() {
|
||||
mkdir -p "$output_dir"
|
||||
while true; do
|
||||
if [ "$suffix" -eq 0 ]; then
|
||||
backup_name="gotelegram_backup_${timestamp}"
|
||||
backup_name="pcatelegram_web_backup_${timestamp}"
|
||||
else
|
||||
backup_name="gotelegram_backup_${timestamp}_${suffix}"
|
||||
backup_name="pcatelegram_web_backup_${timestamp}_${suffix}"
|
||||
fi
|
||||
tmp_dir="/tmp/${backup_name}"
|
||||
if [ ! -e "$tmp_dir" ] && \
|
||||
@@ -34,20 +34,20 @@ create_backup() {
|
||||
cp "$TELEMT_CONFIG" "$tmp_dir/config.toml"
|
||||
fi
|
||||
|
||||
# goTelegram Pro конфиг
|
||||
if [ -f "$GOTELEGRAM_CONFIG" ]; then
|
||||
cp "$GOTELEGRAM_CONFIG" "$tmp_dir/gotelegram.json"
|
||||
# PCAtelegram_web конфиг
|
||||
if [ -f "$PCATELEGRAM_WEB_CONFIG" ]; then
|
||||
cp "$PCATELEGRAM_WEB_CONFIG" "$tmp_dir/pcatelegram_web.json"
|
||||
fi
|
||||
if [ -f "$GOTELEGRAM_DIR/disabled_users.json" ]; then
|
||||
cp "$GOTELEGRAM_DIR/disabled_users.json" "$tmp_dir/disabled_users.json" 2>/dev/null
|
||||
if [ -f "$PCATELEGRAM_WEB_DIR/disabled_users.json" ]; then
|
||||
cp "$PCATELEGRAM_WEB_DIR/disabled_users.json" "$tmp_dir/disabled_users.json" 2>/dev/null
|
||||
fi
|
||||
if [ -f "$GOTELEGRAM_DIR/backup_schedule.json" ]; then
|
||||
cp "$GOTELEGRAM_DIR/backup_schedule.json" "$tmp_dir/backup_schedule.json" 2>/dev/null
|
||||
if [ -f "$PCATELEGRAM_WEB_DIR/backup_schedule.json" ]; then
|
||||
cp "$PCATELEGRAM_WEB_DIR/backup_schedule.json" "$tmp_dir/backup_schedule.json" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Language marker (i18n)
|
||||
if [ -f "$GOTELEGRAM_DIR/.language" ]; then
|
||||
cp "$GOTELEGRAM_DIR/.language" "$tmp_dir/.language"
|
||||
if [ -f "$PCATELEGRAM_WEB_DIR/.language" ]; then
|
||||
cp "$PCATELEGRAM_WEB_DIR/.language" "$tmp_dir/.language"
|
||||
fi
|
||||
|
||||
# nginx конфиг (stealth mode)
|
||||
@@ -76,12 +76,12 @@ create_backup() {
|
||||
fi
|
||||
|
||||
# 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"
|
||||
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
|
||||
if [ -f "$GOTELEGRAM_DIR/templates_catalog.json" ]; then
|
||||
cp "$GOTELEGRAM_DIR/templates_catalog.json" "$tmp_dir/templates_catalog.json" 2>/dev/null
|
||||
if [ -f "$PCATELEGRAM_WEB_DIR/templates_catalog.json" ]; then
|
||||
cp "$PCATELEGRAM_WEB_DIR/templates_catalog.json" "$tmp_dir/templates_catalog.json" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Bot state (.env has BotFather token, so encrypted backups are strongly recommended)
|
||||
@@ -100,14 +100,14 @@ create_backup() {
|
||||
fi
|
||||
|
||||
# Traffic history
|
||||
if [ -f "$GOTELEGRAM_DIR/stats_history.csv" ]; then
|
||||
cp "$GOTELEGRAM_DIR/stats_history.csv" "$tmp_dir/stats_history.csv" 2>/dev/null
|
||||
if [ -f "$PCATELEGRAM_WEB_DIR/stats_history.csv" ]; then
|
||||
cp "$PCATELEGRAM_WEB_DIR/stats_history.csv" "$tmp_dir/stats_history.csv" 2>/dev/null
|
||||
fi
|
||||
if [ -f "$GOTELEGRAM_DIR/user_stats_history.csv" ]; then
|
||||
cp "$GOTELEGRAM_DIR/user_stats_history.csv" "$tmp_dir/user_stats_history.csv" 2>/dev/null
|
||||
if [ -f "$PCATELEGRAM_WEB_DIR/user_stats_history.csv" ]; then
|
||||
cp "$PCATELEGRAM_WEB_DIR/user_stats_history.csv" "$tmp_dir/user_stats_history.csv" 2>/dev/null
|
||||
fi
|
||||
if [ -f "$GOTELEGRAM_DIR/shared-443.json" ]; then
|
||||
cp "$GOTELEGRAM_DIR/shared-443.json" "$tmp_dir/shared-443.json" 2>/dev/null
|
||||
if [ -f "$PCATELEGRAM_WEB_DIR/shared-443.json" ]; then
|
||||
cp "$PCATELEGRAM_WEB_DIR/shared-443.json" "$tmp_dir/shared-443.json" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Метаданные
|
||||
@@ -124,7 +124,7 @@ create_backup() {
|
||||
cat > "$tmp_dir/metadata.json" << EOMETA
|
||||
{
|
||||
"backup_version": "1.6",
|
||||
"gotelegram_version": "$GOTELEGRAM_VERSION",
|
||||
"pcatelegram_web_version": "$PCATELEGRAM_WEB_VERSION",
|
||||
"created_at": "$(date -Iseconds)",
|
||||
"hostname": "$(hostname)",
|
||||
"ip": "$ip",
|
||||
@@ -201,7 +201,7 @@ restore_backup() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
local tmp_dir="/tmp/gotelegram_restore_$$"
|
||||
local tmp_dir="/tmp/pcatelegram_web_restore_$$"
|
||||
mkdir -p "$tmp_dir"
|
||||
|
||||
# Расшифровываем если нужно
|
||||
@@ -212,7 +212,7 @@ restore_backup() {
|
||||
read -rs password
|
||||
echo ""
|
||||
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
|
||||
if [ $? -ne 0 ]; then
|
||||
log_error "$(_t_or backup_bad_pass 'Неверный пароль или повреждённый файл')"
|
||||
@@ -233,25 +233,25 @@ restore_backup() {
|
||||
|
||||
# Находим папку бекапа
|
||||
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"
|
||||
|
||||
# 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
|
||||
cp "$tmp_dir/etc/telemt/config.toml" "$backup_dir/config.toml" 2>/dev/null || true
|
||||
fi
|
||||
if [ ! -f "$backup_dir/gotelegram.json" ] && [ -f "$tmp_dir/opt/gotelegram/config.json" ]; then
|
||||
cp "$tmp_dir/opt/gotelegram/config.json" "$backup_dir/gotelegram.json" 2>/dev/null || true
|
||||
if [ ! -f "$backup_dir/pcatelegram_web.json" ] && [ -f "$tmp_dir/opt/pcatelegram_web/config.json" ]; then
|
||||
cp "$tmp_dir/opt/pcatelegram_web/config.json" "$backup_dir/pcatelegram_web.json" 2>/dev/null || true
|
||||
fi
|
||||
if [ ! -f "$backup_dir/disabled_users.json" ] && [ -f "$tmp_dir/opt/gotelegram/disabled_users.json" ]; then
|
||||
cp "$tmp_dir/opt/gotelegram/disabled_users.json" "$backup_dir/disabled_users.json" 2>/dev/null || true
|
||||
if [ ! -f "$backup_dir/disabled_users.json" ] && [ -f "$tmp_dir/opt/pcatelegram_web/disabled_users.json" ]; then
|
||||
cp "$tmp_dir/opt/pcatelegram_web/disabled_users.json" "$backup_dir/disabled_users.json" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Проверяем метаданные
|
||||
if [ -f "$backup_dir/metadata.json" ]; then
|
||||
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_ip=$(jq -r '.ip // "unknown"' "$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 конфиг восстановлен')"
|
||||
fi
|
||||
|
||||
# Восстанавливаем goTelegram Pro конфиг
|
||||
if [ -f "$backup_dir/gotelegram.json" ]; then
|
||||
mkdir -p "$GOTELEGRAM_DIR"
|
||||
cp "$backup_dir/gotelegram.json" "$GOTELEGRAM_CONFIG"
|
||||
log_success "$(_t_or backup_restored_gotelegram 'GoTelegram конфиг восстановлен')"
|
||||
# Восстанавливаем PCAtelegram_web конфиг
|
||||
if [ -f "$backup_dir/pcatelegram_web.json" ]; then
|
||||
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||
cp "$backup_dir/pcatelegram_web.json" "$PCATELEGRAM_WEB_CONFIG"
|
||||
log_success "$(_t_or backup_restored_pcatelegram_web 'PCAtelegram_web конфиг восстановлен')"
|
||||
fi
|
||||
if [ -f "$backup_dir/disabled_users.json" ]; then
|
||||
mkdir -p "$GOTELEGRAM_DIR"
|
||||
cp "$backup_dir/disabled_users.json" "$GOTELEGRAM_DIR/disabled_users.json"
|
||||
chmod 600 "$GOTELEGRAM_DIR/disabled_users.json" 2>/dev/null || true
|
||||
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||
cp "$backup_dir/disabled_users.json" "$PCATELEGRAM_WEB_DIR/disabled_users.json"
|
||||
chmod 600 "$PCATELEGRAM_WEB_DIR/disabled_users.json" 2>/dev/null || true
|
||||
fi
|
||||
if [ -f "$backup_dir/backup_schedule.json" ]; then
|
||||
mkdir -p "$GOTELEGRAM_DIR"
|
||||
cp "$backup_dir/backup_schedule.json" "$GOTELEGRAM_DIR/backup_schedule.json" 2>/dev/null
|
||||
chmod 600 "$GOTELEGRAM_DIR/backup_schedule.json" 2>/dev/null || true
|
||||
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||
cp "$backup_dir/backup_schedule.json" "$PCATELEGRAM_WEB_DIR/backup_schedule.json" 2>/dev/null
|
||||
chmod 600 "$PCATELEGRAM_WEB_DIR/backup_schedule.json" 2>/dev/null || true
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
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
|
||||
off|daily|weekly|monthly) set_backup_schedule "$restored_schedule" >/dev/null 2>&1 || true ;;
|
||||
esac
|
||||
@@ -306,8 +306,8 @@ restore_backup() {
|
||||
|
||||
# Восстанавливаем language marker (i18n)
|
||||
if [ -f "$backup_dir/.language" ]; then
|
||||
mkdir -p "$GOTELEGRAM_DIR"
|
||||
cp "$backup_dir/.language" "$GOTELEGRAM_DIR/.language"
|
||||
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||
cp "$backup_dir/.language" "$PCATELEGRAM_WEB_DIR/.language"
|
||||
log_success "$(_t_or backup_restored_lang 'Язык интерфейса восстановлен')"
|
||||
fi
|
||||
|
||||
@@ -347,23 +347,23 @@ restore_backup() {
|
||||
|
||||
# Восстанавливаем custom templates/catalog/statistics
|
||||
if [ -d "$backup_dir/custom_templates" ]; then
|
||||
mkdir -p "$GOTELEGRAM_DIR/custom_templates"
|
||||
cp -a "$backup_dir/custom_templates/." "$GOTELEGRAM_DIR/custom_templates/" 2>/dev/null
|
||||
mkdir -p "$PCATELEGRAM_WEB_DIR/custom_templates"
|
||||
cp -a "$backup_dir/custom_templates/." "$PCATELEGRAM_WEB_DIR/custom_templates/" 2>/dev/null
|
||||
log_success "Пользовательские шаблоны восстановлены"
|
||||
fi
|
||||
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
|
||||
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 "История статистики восстановлена"
|
||||
fi
|
||||
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 "История статистики пользователей восстановлена"
|
||||
fi
|
||||
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
|
||||
|
||||
# Восстанавливаем состояние бота
|
||||
@@ -392,8 +392,8 @@ restore_backup() {
|
||||
start_telemt
|
||||
fi
|
||||
command -v nginx &>/dev/null && systemctl start nginx 2>/dev/null
|
||||
systemctl restart gotelegram-bot 2>/dev/null || true
|
||||
systemctl restart gotelegram-admin 2>/dev/null || true
|
||||
systemctl restart pcatelegram_web-bot 2>/dev/null || true
|
||||
systemctl restart pcatelegram_web-admin 2>/dev/null || true
|
||||
|
||||
# Очистка
|
||||
rm -rf "$tmp_dir"
|
||||
@@ -469,43 +469,43 @@ set_backup_schedule() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p "$GOTELEGRAM_DIR" "$BACKUP_DIR"
|
||||
mkdir -p "$PCATELEGRAM_WEB_DIR" "$BACKUP_DIR"
|
||||
|
||||
if [ "$frequency" = "off" ]; then
|
||||
systemctl disable --now gotelegram-backup.timer >/dev/null 2>&1 || true
|
||||
rm -f /etc/systemd/system/gotelegram-backup.timer /etc/systemd/system/gotelegram-backup.service
|
||||
systemctl disable --now pcatelegram_web-backup.timer >/dev/null 2>&1 || true
|
||||
rm -f /etc/systemd/system/pcatelegram_web-backup.timer /etc/systemd/system/pcatelegram_web-backup.service
|
||||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||
else
|
||||
cat > /etc/systemd/system/gotelegram-backup.service << 'EOSVC'
|
||||
cat > /etc/systemd/system/pcatelegram_web-backup.service << 'EOSVC'
|
||||
[Unit]
|
||||
Description=goTelegram Pro backup
|
||||
Description=PCAtelegram_web backup
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Environment=GOTELEGRAM_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}"'
|
||||
Environment=PCATELEGRAM_WEB_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
|
||||
|
||||
cat > /etc/systemd/system/gotelegram-backup.timer << EOTIMER
|
||||
cat > /etc/systemd/system/pcatelegram_web-backup.timer << EOTIMER
|
||||
[Unit]
|
||||
Description=goTelegram Pro scheduled backup
|
||||
Description=PCAtelegram_web scheduled backup
|
||||
|
||||
[Timer]
|
||||
OnCalendar=$calendar
|
||||
Persistent=true
|
||||
RandomizedDelaySec=15m
|
||||
Unit=gotelegram-backup.service
|
||||
Unit=pcatelegram_web-backup.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOTIMER
|
||||
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
|
||||
|
||||
cat > "$GOTELEGRAM_DIR/backup_schedule.json" << EOSCHEDULE
|
||||
cat > "$PCATELEGRAM_WEB_DIR/backup_schedule.json" << EOSCHEDULE
|
||||
{
|
||||
"frequency": "$frequency",
|
||||
"calendar": "$calendar",
|
||||
@@ -513,19 +513,19 @@ EOTIMER
|
||||
"updated_at": "$(date -Iseconds)"
|
||||
}
|
||||
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"
|
||||
echo "$frequency"
|
||||
}
|
||||
|
||||
backup_schedule_status() {
|
||||
local frequency="off" calendar=""
|
||||
if [ -f "$GOTELEGRAM_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")
|
||||
calendar=$(jq -r '.calendar // ""' "$GOTELEGRAM_DIR/backup_schedule.json" 2>/dev/null || echo "")
|
||||
if [ -f "$PCATELEGRAM_WEB_DIR/backup_schedule.json" ] && command -v jq >/dev/null 2>&1; then
|
||||
frequency=$(jq -r '.frequency // "off"' "$PCATELEGRAM_WEB_DIR/backup_schedule.json" 2>/dev/null || echo "off")
|
||||
calendar=$(jq -r '.calendar // ""' "$PCATELEGRAM_WEB_DIR/backup_schedule.json" 2>/dev/null || echo "")
|
||||
fi
|
||||
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
|
||||
# goTelegram Pro v2.5.0 — common utilities
|
||||
# PCAtelegram_web v2.5.0 — common utilities
|
||||
# Colors, logging, spinner, system helpers, v1 compat, i18n-aware
|
||||
|
||||
# ── Version ───────────────────────────────────────────────────────────────────
|
||||
GOTELEGRAM_VERSION="2.5.0"
|
||||
GOTELEGRAM_NAME="goTelegram Pro"
|
||||
PCATELEGRAM_WEB_VERSION="2.5.0"
|
||||
PCATELEGRAM_WEB_NAME="PCAtelegram_web"
|
||||
|
||||
# ── Пути ──────────────────────────────────────────────────────────────────────
|
||||
GOTELEGRAM_DIR="/opt/gotelegram"
|
||||
GOTELEGRAM_CONFIG="$GOTELEGRAM_DIR/config.json"
|
||||
PCATELEGRAM_WEB_DIR="/opt/pcatelegram_web"
|
||||
PCATELEGRAM_WEB_CONFIG="$PCATELEGRAM_WEB_DIR/config.json"
|
||||
TELEMT_CONFIG="/etc/telemt/config.toml"
|
||||
TELEMT_BIN="/usr/local/bin/telemt"
|
||||
TELEMT_SERVICE="telemt"
|
||||
NGINX_SITE_CONF="/etc/nginx/sites-available/gotelegram"
|
||||
NGINX_SITE_LINK="/etc/nginx/sites-enabled/gotelegram"
|
||||
WEBSITE_ROOT="/var/www/gotelegram-site"
|
||||
BACKUP_DIR="$GOTELEGRAM_DIR/backups"
|
||||
LOG_FILE="/var/log/gotelegram.log"
|
||||
BOT_DIR="/opt/gotelegram-bot"
|
||||
ADMIN_WEB_DIR="/opt/gotelegram-admin"
|
||||
ADMIN_WEB_SERVICE="gotelegram-admin"
|
||||
NGINX_SITE_CONF="/etc/nginx/sites-available/pcatelegram_web"
|
||||
NGINX_SITE_LINK="/etc/nginx/sites-enabled/pcatelegram_web"
|
||||
WEBSITE_ROOT="/var/www/pcatelegram_web-site"
|
||||
BACKUP_DIR="$PCATELEGRAM_WEB_DIR/backups"
|
||||
LOG_FILE="/var/log/pcatelegram_web.log"
|
||||
BOT_DIR="/opt/pcatelegram_web-bot"
|
||||
ADMIN_WEB_DIR="/opt/pcatelegram_web-admin"
|
||||
ADMIN_WEB_SERVICE="pcatelegram_web-admin"
|
||||
ADMIN_WEB_HOST="127.0.0.1"
|
||||
ADMIN_WEB_PORT="1984"
|
||||
|
||||
# ── V1 совместимость ─────────────────────────────────────────────────────────
|
||||
V1_CONTAINER_NAME="mtproto-proxy"
|
||||
V1_CONFIG_FILE="/opt/gotelegram-bot/proxy.json"
|
||||
V1_SERVICE_NAME="gotelegram-bot"
|
||||
V1_CONFIG_FILE="/opt/pcatelegram_web-bot/proxy.json"
|
||||
V1_SERVICE_NAME="pcatelegram_web-bot"
|
||||
|
||||
# ── Цвета ────────────────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'
|
||||
@@ -93,7 +93,7 @@ progress_bar() {
|
||||
# ── Выполнение с индикатором ─────────────────────────────────────────────────
|
||||
run_with_spinner() {
|
||||
local label="$1"; shift
|
||||
local err_file="/tmp/.gotelegram_spinner_err_$$"
|
||||
local err_file="/tmp/.pcatelegram_web_spinner_err_$$"
|
||||
spinner_start "$label"
|
||||
"$@" >/dev/null 2>"$err_file"
|
||||
local rc=$?
|
||||
@@ -119,11 +119,11 @@ show_banner() {
|
||||
echo ""
|
||||
echo -e "${CYAN}${line}${NC}"
|
||||
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_features)${NC}"
|
||||
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}Anti-DPI • Fake TLS • TCP Splice • JA3/JA4${NC}"
|
||||
fi
|
||||
@@ -306,7 +306,7 @@ apt_update() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── Зависимости GoTelegram ──────────────────────────────────────────────────
|
||||
# ── Зависимости PCAtelegram_web ──────────────────────────────────────────────────
|
||||
# Полный список внешних команд, которые скрипт использует. Для каждой команды
|
||||
# указан пакет на apt и dnf/yum (имена различаются: например dig = dnsutils на
|
||||
# Debian, bind-utils на RHEL).
|
||||
@@ -429,7 +429,7 @@ ensure_deps() {
|
||||
|
||||
if [ ${#still_missing[@]} -gt 0 ]; then
|
||||
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
|
||||
fi
|
||||
|
||||
@@ -483,32 +483,32 @@ detect_3xui_443_listener() {
|
||||
warn_3xui_443_conflict() {
|
||||
detect_3xui_443_listener || return 1
|
||||
log_warning "Обнаружен 3x-ui/Xray, который уже слушает TCP/443."
|
||||
log_warning "goTelegram Pro не будет молча останавливать или переписывать 3x-ui."
|
||||
log_dim "Для настоящего shared-443 нужен один фронтовой TLS/SNI-диспетчер и разные SNI-домены для Xray и goTelegram Pro."
|
||||
mkdir -p "$GOTELEGRAM_DIR" 2>/dev/null
|
||||
cat > "$GOTELEGRAM_DIR/shared-443-3xui.md" <<'EOF' 2>/dev/null || true
|
||||
# goTelegram Pro + 3x-ui on one TCP/443
|
||||
log_warning "PCAtelegram_web не будет молча останавливать или переписывать 3x-ui."
|
||||
log_dim "Для настоящего shared-443 нужен один фронтовой TLS/SNI-диспетчер и разные SNI-домены для Xray и PCAtelegram_web."
|
||||
mkdir -p "$PCATELEGRAM_WEB_DIR" 2>/dev/null
|
||||
cat > "$PCATELEGRAM_WEB_DIR/shared-443-3xui.md" <<'EOF' 2>/dev/null || true
|
||||
# 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
|
||||
needs one front TLS/SNI dispatcher on 443 and internal backends, for example:
|
||||
|
||||
- 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
|
||||
- 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;
|
||||
telemt then decides whether the session is MTProxy or regular HTTPS and forwards
|
||||
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
|
||||
shared443_enable <gotelegram-domain> <xray-sni-domain> 127.0.0.1:9443
|
||||
source /opt/pcatelegram_web/lib/shared443.sh
|
||||
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,
|
||||
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
|
||||
operator confirmation, because 3x-ui can overwrite manual JSON edits on the next
|
||||
panel change.
|
||||
@@ -531,14 +531,14 @@ check_disk_space() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── Конфигурация GoTelegram (JSON) ──────────────────────────────────────────
|
||||
save_gotelegram_config() {
|
||||
mkdir -p "$(dirname "$GOTELEGRAM_CONFIG")"
|
||||
# ── Конфигурация PCAtelegram_web (JSON) ──────────────────────────────────────────
|
||||
save_pcatelegram_web_config() {
|
||||
mkdir -p "$(dirname "$PCATELEGRAM_WEB_CONFIG")"
|
||||
local cur_lang
|
||||
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}",
|
||||
"mode": "${2:-lite}",
|
||||
"port": ${3:-443},
|
||||
@@ -551,12 +551,12 @@ save_gotelegram_config() {
|
||||
"updated_at": "$(date -Iseconds)"
|
||||
}
|
||||
EOJSON
|
||||
chmod 600 "$GOTELEGRAM_CONFIG"
|
||||
chmod 600 "$PCATELEGRAM_WEB_CONFIG"
|
||||
}
|
||||
|
||||
load_gotelegram_config() {
|
||||
if [ -f "$GOTELEGRAM_CONFIG" ]; then
|
||||
cat "$GOTELEGRAM_CONFIG"
|
||||
load_pcatelegram_web_config() {
|
||||
if [ -f "$PCATELEGRAM_WEB_CONFIG" ]; then
|
||||
cat "$PCATELEGRAM_WEB_CONFIG"
|
||||
return 0
|
||||
fi
|
||||
echo "{}"
|
||||
@@ -565,11 +565,11 @@ load_gotelegram_config() {
|
||||
|
||||
config_get() {
|
||||
local key="$1"
|
||||
if [ ! -f "$GOTELEGRAM_CONFIG" ]; then
|
||||
if [ ! -f "$PCATELEGRAM_WEB_CONFIG" ]; then
|
||||
return 2 # file missing
|
||||
fi
|
||||
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
|
||||
return 3 # invalid JSON
|
||||
fi
|
||||
@@ -671,12 +671,12 @@ migrate_v1_to_v2() {
|
||||
|
||||
# Backup v1 config
|
||||
if [ -f "$V1_CONFIG_FILE" ]; then
|
||||
mkdir -p "$GOTELEGRAM_DIR"
|
||||
cp "$V1_CONFIG_FILE" "$GOTELEGRAM_DIR/v1_backup_proxy.json" 2>/dev/null
|
||||
mkdir -p "$PCATELEGRAM_WEB_DIR"
|
||||
cp "$V1_CONFIG_FILE" "$PCATELEGRAM_WEB_DIR/v1_backup_proxy.json" 2>/dev/null
|
||||
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
|
||||
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
|
||||
|
||||
@@ -735,6 +735,6 @@ validate_domain() {
|
||||
|
||||
# ── Init: создание директорий ────────────────────────────────────────────────
|
||||
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
|
||||
}
|
||||
|
||||
12
lib/i18n.sh
Normal file → Executable file
12
lib/i18n.sh
Normal file → Executable file
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
# GoTelegram v2.5.0 — i18n engine
|
||||
# PCAtelegram_web v2.5.0 — i18n engine
|
||||
# Internationalization support: EN (English) / RU (Русский)
|
||||
#
|
||||
# Usage:
|
||||
@@ -74,14 +74,14 @@ get_language() {
|
||||
|
||||
# ── Detect saved language from config.json, default en ──
|
||||
detect_language() {
|
||||
local cfg="${GOTELEGRAM_CONFIG:-/opt/gotelegram/config.json}"
|
||||
local cfg="${PCATELEGRAM_WEB_CONFIG:-/opt/pcatelegram_web/config.json}"
|
||||
local lang=""
|
||||
if [ -f "$cfg" ] && command -v jq >/dev/null 2>&1; then
|
||||
lang=$(jq -r '.language // empty' "$cfg" 2>/dev/null)
|
||||
fi
|
||||
# Also check marker file (language set before config.json exists)
|
||||
if [ -z "$lang" ]; then
|
||||
local marker="${GOTELEGRAM_DIR:-/opt/gotelegram}/.language"
|
||||
local marker="${PCATELEGRAM_WEB_DIR:-/opt/pcatelegram_web}/.language"
|
||||
if [ -f "$marker" ]; then
|
||||
lang=$(head -c 2 "$marker" 2>/dev/null | tr -d '[:space:]')
|
||||
fi
|
||||
@@ -100,11 +100,11 @@ save_language() {
|
||||
if ! [[ "$lang" =~ ^(en|ru)$ ]]; then
|
||||
return 1
|
||||
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)
|
||||
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
|
||||
local tmp
|
||||
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
|
||||
# goTelegram Pro v2.5.0 — English translations
|
||||
# PCAtelegram_web v2.5.0 — English translations
|
||||
# shellcheck disable=SC2034,SC2148
|
||||
|
||||
# ── Common words ────────────────────────────────────────────────────────
|
||||
@@ -25,7 +25,7 @@ I18N[success]="Done"
|
||||
I18N[wait]="Please wait..."
|
||||
|
||||
# ── 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_features]="Anti-DPI • Fake TLS • TCP Splice • JA3/JA4"
|
||||
I18N[credits_title]="Credits / Thanks"
|
||||
@@ -75,7 +75,7 @@ I18N[submenu_about_title]="ℹ️ ABOUT"
|
||||
I18N[about_version_info]="Version info"
|
||||
I18N[about_promo]="Promo / Donate"
|
||||
I18N[version_title]="🔍 Information"
|
||||
I18N[version_label]="goTelegram Pro:"
|
||||
I18N[version_label]="PCAtelegram_web:"
|
||||
I18N[version_engine]="Engine:"
|
||||
I18N[version_tech]="Technology:"
|
||||
I18N[version_license]="License:"
|
||||
@@ -106,7 +106,7 @@ I18N[install_cfg_mode]="Mode:"
|
||||
I18N[install_cfg_domain]="Domain:"
|
||||
I18N[install_confirm_proxy]="Install proxy?"
|
||||
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_desc2]="nginx serves the site on internal port %s"
|
||||
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 ────────────────────────────────────────────────────────
|
||||
I18N[link_title]="🔗 Connection link:"
|
||||
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_port]="🔌 Port: %s"
|
||||
I18N[share_connect_cta]="👉 Connect with one tap:"
|
||||
@@ -141,7 +141,7 @@ I18N[website_restart_nginx]="Restart nginx"
|
||||
I18N[website_change_template]="Change template"
|
||||
|
||||
# ── Remove ──────────────────────────────────────────────────────────────
|
||||
I18N[remove_title]="🗑 Remove goTelegram Pro"
|
||||
I18N[remove_title]="🗑 Remove PCAtelegram_web"
|
||||
I18N[remove_proxy_only]="Remove proxy only (telemt)"
|
||||
I18N[remove_bot_only]="Remove Telegram bot only"
|
||||
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_confirm_all]="Are you absolutely sure?"
|
||||
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 ────────────────────────────────────────────────
|
||||
I18N[bot_title]="🤖 Telegram bot"
|
||||
@@ -332,7 +332,7 @@ I18N[backup_lang_label]="Language"
|
||||
I18N[backup_date_label]="Date"
|
||||
I18N[backup_confirm_restore]="Restore configuration? Current settings will be overwritten."
|
||||
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_nginx]="nginx config 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"
|
||||
|
||||
# ── 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_migration_step]="Migrating from v1 (mtg) to v2 (telemt)"
|
||||
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
|
||||
# goTelegram Pro v2.5.0 — Russian translations
|
||||
# PCAtelegram_web v2.5.0 — Russian translations
|
||||
# shellcheck disable=SC2034,SC2148
|
||||
|
||||
# ── Common words ────────────────────────────────────────────────────────
|
||||
@@ -25,7 +25,7 @@ I18N[success]="Готово"
|
||||
I18N[wait]="Подождите..."
|
||||
|
||||
# ── Banner ──────────────────────────────────────────────────────────────
|
||||
I18N[banner_title]="goTelegram Pro v%s"
|
||||
I18N[banner_title]="PCAtelegram_web v%s"
|
||||
I18N[banner_subtitle]="MTProxy на ядре telemt (Rust + Tokio)"
|
||||
I18N[banner_features]="Anti-DPI • Fake TLS • TCP Splice • JA3/JA4"
|
||||
I18N[credits_title]="Благодарности / Credits"
|
||||
@@ -75,7 +75,7 @@ I18N[submenu_about_title]="ℹ️ О ПРОГРАММЕ"
|
||||
I18N[about_version_info]="Информация о версии"
|
||||
I18N[about_promo]="Промо / Донат"
|
||||
I18N[version_title]="🔍 Информация"
|
||||
I18N[version_label]="goTelegram Pro:"
|
||||
I18N[version_label]="PCAtelegram_web:"
|
||||
I18N[version_engine]="Ядро:"
|
||||
I18N[version_tech]="Технология:"
|
||||
I18N[version_license]="Лицензия:"
|
||||
@@ -106,7 +106,7 @@ I18N[install_cfg_mode]="Режим:"
|
||||
I18N[install_cfg_domain]="Домен:"
|
||||
I18N[install_confirm_proxy]="Установить прокси?"
|
||||
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_desc2]="nginx обслуживает сайт на внутреннем порту %s"
|
||||
I18N[install_arch_desc3]="Провайдер видит только HTTPS-трафик к %s:443"
|
||||
@@ -125,7 +125,7 @@ I18N[logs_telemt_title]="📋 Логи telemt (последние %s строк)
|
||||
# ── Link / Share ────────────────────────────────────────────────────────
|
||||
I18N[link_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_port]="🔌 Порт: %s"
|
||||
I18N[share_connect_cta]="👉 Подключиться одним нажатием:"
|
||||
@@ -141,7 +141,7 @@ I18N[website_restart_nginx]="Перезапустить nginx"
|
||||
I18N[website_change_template]="Сменить шаблон"
|
||||
|
||||
# ── Remove ──────────────────────────────────────────────────────────────
|
||||
I18N[remove_title]="🗑 Удаление goTelegram Pro"
|
||||
I18N[remove_title]="🗑 Удаление PCAtelegram_web"
|
||||
I18N[remove_proxy_only]="Удалить только прокси (telemt)"
|
||||
I18N[remove_bot_only]="Удалить только Telegram-бота"
|
||||
I18N[remove_all]="Удалить всё (прокси + бот + настройки)"
|
||||
@@ -151,7 +151,7 @@ I18N[remove_backup_before]="Сделать бекап перед удалени
|
||||
I18N[remove_warn_all]="Это удалит ВСЁ: прокси, бот, сайт, настройки."
|
||||
I18N[remove_confirm_all]="Вы точно уверены?"
|
||||
I18N[remove_proxy_done]="Прокси удалён"
|
||||
I18N[remove_all_done]="goTelegram Pro полностью удалён (прокси + бот)"
|
||||
I18N[remove_all_done]="PCAtelegram_web полностью удалён (прокси + бот)"
|
||||
|
||||
# ── Telegram bot submenu ────────────────────────────────────────────────
|
||||
I18N[bot_title]="🤖 Telegram-бот"
|
||||
@@ -332,7 +332,7 @@ I18N[backup_lang_label]="Язык"
|
||||
I18N[backup_date_label]="Дата"
|
||||
I18N[backup_confirm_restore]="Восстановить конфигурацию? Текущие настройки будут перезаписаны."
|
||||
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_nginx]="nginx конфиг восстановлен"
|
||||
I18N[backup_restored_ssl]="SSL сертификаты восстановлены"
|
||||
@@ -362,7 +362,7 @@ I18N[auto_refresh]="Обновление через 30 сек"
|
||||
I18N[deps_installing]="Установка зависимостей: %s"
|
||||
|
||||
# ── Migration ───────────────────────────────────────────────────────────
|
||||
I18N[v1_detected]="⚠️ Обнаружена установка goTelegram Pro v1 (mtg)"
|
||||
I18N[v1_detected]="⚠️ Обнаружена установка PCAtelegram_web v1 (mtg)"
|
||||
I18N[v1_container]="Контейнер: %s"
|
||||
I18N[v1_migration_step]="Миграция с v1 (mtg) на v2 (telemt)"
|
||||
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
|
||||
# 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
|
||||
# Uses iptables counters + real-time snapshots + historical CSV
|
||||
|
||||
@@ -10,12 +10,12 @@ YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
STATS_DIR="/run/gotelegram"
|
||||
HISTORY_FILE="/opt/gotelegram/stats_history.csv"
|
||||
USER_HISTORY_FILE="/opt/gotelegram/user_stats_history.csv"
|
||||
STATS_DIR="/run/pcatelegram_web"
|
||||
HISTORY_FILE="/opt/pcatelegram_web/stats_history.csv"
|
||||
USER_HISTORY_FILE="/opt/pcatelegram_web/user_stats_history.csv"
|
||||
SNAPSHOTS_DIR="$STATS_DIR/snapshots"
|
||||
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"
|
||||
STATS_RETENTION_DAYS="${STATS_RETENTION_DAYS:-365}"
|
||||
STATS_MINUTE_RETENTION_DAYS="${STATS_MINUTE_RETENTION_DAYS:-31}"
|
||||
@@ -35,23 +35,23 @@ stats_init() {
|
||||
chmod 755 "$STATS_DIR" "$SNAPSHOTS_DIR" 2>/dev/null
|
||||
|
||||
# Create iptables chain if not exists
|
||||
if ! iptables -L GOTELEGRAM_STATS -n >/dev/null 2>&1; then
|
||||
iptables -N GOTELEGRAM_STATS 2>/dev/null
|
||||
if ! iptables -L PCATELEGRAM_WEB_STATS -n >/dev/null 2>&1; then
|
||||
iptables -N PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||
fi
|
||||
|
||||
# Add chain to INPUT if not already present
|
||||
if ! iptables -C INPUT -j GOTELEGRAM_STATS 2>/dev/null; then
|
||||
iptables -I INPUT -j GOTELEGRAM_STATS 2>/dev/null
|
||||
if ! iptables -C INPUT -j PCATELEGRAM_WEB_STATS 2>/dev/null; then
|
||||
iptables -I INPUT -j PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||
fi
|
||||
|
||||
# Add rule for proxy traffic (port 443, TCP)
|
||||
if ! iptables -C GOTELEGRAM_STATS -p tcp --dport 443 2>/dev/null; then
|
||||
iptables -A GOTELEGRAM_STATS -p tcp --dport 443 2>/dev/null
|
||||
if ! iptables -C PCATELEGRAM_WEB_STATS -p tcp --dport 443 2>/dev/null; then
|
||||
iptables -A PCATELEGRAM_WEB_STATS -p tcp --dport 443 2>/dev/null
|
||||
fi
|
||||
|
||||
# Add rule for site traffic (loopback, port 8443, TCP)
|
||||
if ! iptables -C GOTELEGRAM_STATS -i lo -p tcp --dport 8443 2>/dev/null; then
|
||||
iptables -A GOTELEGRAM_STATS -i lo -p tcp --dport 8443 2>/dev/null
|
||||
if ! iptables -C PCATELEGRAM_WEB_STATS -i lo -p tcp --dport 8443 2>/dev/null; then
|
||||
iptables -A PCATELEGRAM_WEB_STATS -i lo -p tcp --dport 8443 2>/dev/null
|
||||
fi
|
||||
|
||||
# Initialize CSV header if file doesn't exist
|
||||
@@ -81,7 +81,7 @@ stats_collect() {
|
||||
|
||||
# Parse iptables output: format is "pkts bytes target"
|
||||
# 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)
|
||||
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
|
||||
# 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() {
|
||||
[[ -f "$TELEMT_CONFIG_FILE" ]] || return 0
|
||||
awk '
|
||||
@@ -478,9 +478,9 @@ toggle_stats() {
|
||||
fi
|
||||
|
||||
# Remove iptables rules
|
||||
iptables -D INPUT -j GOTELEGRAM_STATS 2>/dev/null
|
||||
iptables -F GOTELEGRAM_STATS 2>/dev/null
|
||||
iptables -X GOTELEGRAM_STATS 2>/dev/null
|
||||
iptables -D INPUT -j PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||
iptables -F PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||
iptables -X PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||
|
||||
# Clean up directories
|
||||
rm -rf "$STATS_DIR" 2>/dev/null
|
||||
@@ -504,7 +504,7 @@ toggle_stats() {
|
||||
|
||||
# Install systemd service for stats collection
|
||||
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
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
@@ -527,14 +527,14 @@ install_stats_collector() {
|
||||
# Create systemd service file
|
||||
cat > "$service_file" <<'EOF'
|
||||
[Unit]
|
||||
Description=goTelegram Pro Traffic Stats Collector
|
||||
Description=PCAtelegram_web Traffic Stats Collector
|
||||
After=network.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
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
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
@@ -546,8 +546,8 @@ EOF
|
||||
|
||||
chmod 644 "$service_file"
|
||||
systemctl daemon-reload
|
||||
systemctl enable gotelegram-stats.service
|
||||
systemctl restart gotelegram-stats.service
|
||||
systemctl enable pcatelegram_web-stats.service
|
||||
systemctl restart pcatelegram_web-stats.service
|
||||
|
||||
if [[ -f "$CONFIG_FILE" ]] && command -v jq &>/dev/null; then
|
||||
local tmp
|
||||
@@ -560,7 +560,7 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Сервис gotelegram-stats установлен и запущен" >&2
|
||||
echo "Сервис pcatelegram_web-stats установлен и запущен" >&2
|
||||
}
|
||||
|
||||
# Remove stats collector service
|
||||
@@ -570,15 +570,15 @@ remove_stats_collector() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
systemctl stop gotelegram-stats.service 2>/dev/null
|
||||
systemctl disable gotelegram-stats.service 2>/dev/null
|
||||
rm -f /etc/systemd/system/gotelegram-stats.service
|
||||
systemctl stop pcatelegram_web-stats.service 2>/dev/null
|
||||
systemctl disable pcatelegram_web-stats.service 2>/dev/null
|
||||
rm -f /etc/systemd/system/pcatelegram_web-stats.service
|
||||
systemctl daemon-reload
|
||||
|
||||
# Remove iptables rules
|
||||
iptables -D INPUT -j GOTELEGRAM_STATS 2>/dev/null
|
||||
iptables -F GOTELEGRAM_STATS 2>/dev/null
|
||||
iptables -X GOTELEGRAM_STATS 2>/dev/null
|
||||
iptables -D INPUT -j PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||
iptables -F PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||
iptables -X PCATELEGRAM_WEB_STATS 2>/dev/null
|
||||
|
||||
# Clean up directories and files
|
||||
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
|
||||
# GoTelegram v2.5.0 — Управление telemt binary
|
||||
# PCAtelegram_web v2.5.0 — Управление telemt binary
|
||||
# Скачивание, обновление, запуск, остановка через systemd
|
||||
|
||||
TELEMT_GITHUB="telemt/telemt"
|
||||
@@ -159,7 +159,7 @@ install_telemt_service() {
|
||||
|
||||
cat > "/etc/systemd/system/${TELEMT_SERVICE}.service" << EOF
|
||||
[Unit]
|
||||
Description=goTelegram Pro MTProxy (telemt engine)
|
||||
Description=PCAtelegram_web MTProxy (telemt engine)
|
||||
Documentation=https://github.com/telemt/telemt
|
||||
After=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
|
||||
# GoTelegram v2.5.0 — Генерация TOML конфигурации для telemt
|
||||
# PCAtelegram_web v2.5.0 — Генерация TOML конфигурации для telemt
|
||||
|
||||
# ── Популярные домены (не заблокированные в РФ) ──────────────────────────────
|
||||
QUICK_DOMAINS=(
|
||||
@@ -44,7 +44,7 @@ generate_telemt_toml() {
|
||||
fi
|
||||
|
||||
cat > "$output" << EOTOML
|
||||
# GoTelegram v${GOTELEGRAM_VERSION} — telemt v3 configuration
|
||||
# PCAtelegram_web v${PCATELEGRAM_WEB_VERSION} — telemt v3 configuration
|
||||
# Сгенерировано: $(date -Iseconds)
|
||||
# Режим: ${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
|
||||
# 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,
|
||||
# + custom git URL templates (user-supplied public repos)
|
||||
|
||||
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_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
|
||||
# GoTelegram v2.5.0 — Управление сайтом (nginx + certbot + шаблоны)
|
||||
# PCAtelegram_web v2.5.0 — Управление сайтом (nginx + certbot + шаблоны)
|
||||
|
||||
# ── Установка nginx ──────────────────────────────────────────────────────────
|
||||
install_nginx() {
|
||||
@@ -39,7 +39,7 @@ generate_nginx_config() {
|
||||
mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
|
||||
|
||||
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 (внешний)
|
||||
# Обычный браузер → :443 → telemt → 127.0.0.1:8443 → nginx (сайт)
|
||||
|
||||
@@ -88,7 +88,7 @@ server {
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
# Корень сайта
|
||||
root /var/www/gotelegram-site;
|
||||
root /var/www/pcatelegram_web-site;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
@@ -127,7 +127,7 @@ generate_nginx_temp_config() {
|
||||
local domain="$1"
|
||||
|
||||
cat > "$NGINX_SITE_CONF" << EONGINX_TEMP
|
||||
# GoTelegram — временный конфиг (до получения SSL)
|
||||
# PCAtelegram_web — временный конфиг (до получения SSL)
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
@@ -138,7 +138,7 @@ server {
|
||||
allow all;
|
||||
}
|
||||
|
||||
root /var/www/gotelegram-site;
|
||||
root /var/www/pcatelegram_web-site;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
@@ -257,8 +257,8 @@ deploy_template_to_nginx() {
|
||||
mkdir -p "$WEBSITE_ROOT"
|
||||
cp -a "$template_dir/." "$WEBSITE_ROOT/"
|
||||
rm -f "$WEBSITE_ROOT/.custom_git_source" 2>/dev/null || true
|
||||
echo "$template_id" > "$WEBSITE_ROOT/.gotelegram_template_id" 2>/dev/null || true
|
||||
[ -n "$source_url" ] && echo "$source_url" > "$WEBSITE_ROOT/.gotelegram_template_source" 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/.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
|
||||
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.
|
||||
|
||||
@@ -34,10 +34,10 @@ Production-quality Telegram bot for managing MTProxy (telemt engine) on Linux se
|
||||
Recommended installation path is the main CLI menu:
|
||||
|
||||
```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
|
||||
|
||||
@@ -76,16 +76,16 @@ For systemd service:
|
||||
|
||||
```bash
|
||||
[Unit]
|
||||
Description=goTelegram Pro Bot
|
||||
Description=PCAtelegram_web Bot
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/gotelegram-bot
|
||||
ExecStart=/opt/gotelegram-bot/venv/bin/python /opt/gotelegram-bot/bot.py
|
||||
WorkingDirectory=/opt/pcatelegram_web-bot
|
||||
ExecStart=/opt/pcatelegram_web-bot/venv/bin/python /opt/pcatelegram_web-bot/bot.py
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
Environment=PATH=/opt/gotelegram-bot/venv/bin:/usr/bin
|
||||
Environment=PATH=/opt/pcatelegram_web-bot/venv/bin:/usr/bin
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -97,17 +97,17 @@ WantedBy=multi-user.target
|
||||
|
||||
- `BOT_TOKEN` - Telegram bot token (required)
|
||||
- `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
|
||||
|
||||
- `GOTELEGRAM_CONFIG` - `/opt/gotelegram/config.json`
|
||||
- `PCATELEGRAM_WEB_CONFIG` - `/opt/pcatelegram_web/config.json`
|
||||
- `TELEMT_CONFIG` - `/etc/telemt/config.toml`
|
||||
- `TELEMT_SERVICE` - `telemt` (systemd service name)
|
||||
- `WEBSITE_ROOT` - `/var/www/gotelegram-site`
|
||||
- `BACKUP_DIR` - `/opt/gotelegram/backups`
|
||||
- `BACKUP_SCHEDULE_FILE` - `/opt/gotelegram/backup_schedule.json`
|
||||
- `TEMPLATES_CATALOG` - `/opt/gotelegram/templates_catalog.json`
|
||||
- `WEBSITE_ROOT` - `/var/www/pcatelegram_web-site`
|
||||
- `BACKUP_DIR` - `/opt/pcatelegram_web/backups`
|
||||
- `BACKUP_SCHEDULE_FILE` - `/opt/pcatelegram_web/backup_schedule.json`
|
||||
- `TEMPLATES_CATALOG` - `/opt/pcatelegram_web/templates_catalog.json`
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -158,4 +158,4 @@ code, stdout, stderr = await sh("command", "arg1", "arg2")
|
||||
|
||||
## 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
|
||||
"""
|
||||
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
|
||||
Uses python-telegram-bot v21+
|
||||
Supports EN/RU UI with per-user language preferences.
|
||||
@@ -103,28 +103,28 @@ logger = logging.getLogger(__name__)
|
||||
# CONFIGURATION
|
||||
# ============================================================================
|
||||
|
||||
GOTELEGRAM_VERSION = "2.5.0"
|
||||
GOTELEGRAM_CONFIG = "/opt/gotelegram/config.json"
|
||||
DISABLED_USERS_FILE = "/opt/gotelegram/disabled_users.json"
|
||||
USER_STATS_HISTORY = "/opt/gotelegram/user_stats_history.csv"
|
||||
USER_LOCK_FILE = "/run/gotelegram/admin-users.lock"
|
||||
PCATELEGRAM_WEB_VERSION = "2.5.0"
|
||||
PCATELEGRAM_WEB_CONFIG = "/opt/pcatelegram_web/config.json"
|
||||
DISABLED_USERS_FILE = "/opt/pcatelegram_web/disabled_users.json"
|
||||
USER_STATS_HISTORY = "/opt/pcatelegram_web/user_stats_history.csv"
|
||||
USER_LOCK_FILE = "/run/pcatelegram_web/admin-users.lock"
|
||||
TELEMT_CONFIG = "/etc/telemt/config.toml"
|
||||
TELEMT_SERVICE = "telemt"
|
||||
WEBSITE_ROOT = "/var/www/gotelegram-site"
|
||||
BACKUP_DIR = "/opt/gotelegram/backups"
|
||||
BACKUP_SCHEDULE_FILE = "/opt/gotelegram/backup_schedule.json"
|
||||
TEMPLATES_CATALOG = "/opt/gotelegram/templates_catalog.json"
|
||||
INSTALL_SH = "/opt/gotelegram/install.sh"
|
||||
WEBSITE_ROOT = "/var/www/pcatelegram_web-site"
|
||||
BACKUP_DIR = "/opt/pcatelegram_web/backups"
|
||||
BACKUP_SCHEDULE_FILE = "/opt/pcatelegram_web/backup_schedule.json"
|
||||
TEMPLATES_CATALOG = "/opt/pcatelegram_web/templates_catalog.json"
|
||||
INSTALL_SH = "/opt/pcatelegram_web/install.sh"
|
||||
|
||||
PROMO_LINK_1 = "https://vk.cc/ct29NQ"
|
||||
PROMO_LINK_2 = "https://vk.cc/cUxAhj"
|
||||
TIP_LINK = "https://pay.cloudtips.ru/p/7410814f"
|
||||
YOUTUBE_LINK = os.getenv("GOTELEGRAM_YOUTUBE_LINK", "").strip()
|
||||
PROMO_STAMP_FILE = "/opt/gotelegram/.promo_bot_last_shown"
|
||||
YOUTUBE_LINK = os.getenv("PCATELEGRAM_WEB_YOUTUBE_LINK", "").strip()
|
||||
PROMO_STAMP_FILE = "/opt/pcatelegram_web/.promo_bot_last_shown"
|
||||
|
||||
BOT_TOKEN = os.getenv("BOT_TOKEN")
|
||||
ENV_FILE = "/opt/gotelegram-bot/.env"
|
||||
ADMIN_WEB_SERVICE = "gotelegram-admin"
|
||||
ENV_FILE = "/opt/pcatelegram_web-bot/.env"
|
||||
ADMIN_WEB_SERVICE = "pcatelegram_web-admin"
|
||||
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
|
||||
# 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.
|
||||
_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}$")
|
||||
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
|
||||
|
||||
|
||||
@@ -391,7 +391,7 @@ def template_display_name(template_id: str) -> str:
|
||||
if template_id in ("deployed_site", "existing_site"):
|
||||
return "Existing deployed site"
|
||||
if template_id.startswith("custom_"):
|
||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
||||
config = load_json(PCATELEGRAM_WEB_CONFIG) or {}
|
||||
source = config.get("template_source", "")
|
||||
return f"{template_id} ({source})" if source else template_id
|
||||
catalog = load_json(TEMPLATES_CATALOG) or {}
|
||||
@@ -652,7 +652,7 @@ async def cmd_start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
return
|
||||
|
||||
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_powered')}\n\n"
|
||||
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}")
|
||||
|
||||
# Config status
|
||||
config = load_json(GOTELEGRAM_CONFIG)
|
||||
config = load_json(PCATELEGRAM_WEB_CONFIG)
|
||||
if config:
|
||||
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")
|
||||
if 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(
|
||||
"bash",
|
||||
"-lc",
|
||||
"source /opt/gotelegram/lib/common.sh; "
|
||||
"source /opt/gotelegram/lib/stats.sh; "
|
||||
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||
"source /opt/pcatelegram_web/lib/stats.sh; "
|
||||
"stats_init >/dev/null 2>&1 || true; stats_collect >/dev/null 2>&1 || true",
|
||||
timeout=15,
|
||||
)
|
||||
|
||||
# Read current snapshot
|
||||
current_file = "/run/gotelegram/stats_current.json"
|
||||
history_file = "/opt/gotelegram/stats_history.csv"
|
||||
current_file = "/run/pcatelegram_web/stats_current.json"
|
||||
history_file = "/opt/pcatelegram_web/stats_history.csv"
|
||||
|
||||
try:
|
||||
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()
|
||||
|
||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
||||
config = load_json(PCATELEGRAM_WEB_CONFIG) or {}
|
||||
current_mode = config.get("mode", "")
|
||||
|
||||
if current_mode != "lite":
|
||||
@@ -1040,7 +1040,7 @@ async def cb_lite_domain(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
||||
"<b>⚠️ Установка Lite из бота пока не поддерживается</b>\n\n"
|
||||
f"Выбранный домен: <code>{html.escape(domain)}</code>\n\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>."
|
||||
)
|
||||
keyboard = InlineKeyboardMarkup(
|
||||
@@ -1185,7 +1185,7 @@ async def _download_custom_git_template(url_with_branch: str) -> Tuple[bool, str
|
||||
url = base
|
||||
|
||||
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
|
||||
if os.path.isdir(target_dir):
|
||||
@@ -1403,7 +1403,7 @@ async def cb_pro_confirm(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
||||
return
|
||||
|
||||
# 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", "")
|
||||
|
||||
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"
|
||||
"Pro-режим требует ввода домена, email и проверки DNS. "
|
||||
"Чтобы установить 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>."
|
||||
)
|
||||
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 "")
|
||||
+ "\n\n"
|
||||
"Существующая конфигурация <b>не была изменена</b>. "
|
||||
"Попробуйте другой шаблон или запустите <code>gotelegram</code> из консоли."
|
||||
"Попробуйте другой шаблон или запустите <code>pcatelegram_web</code> из консоли."
|
||||
)
|
||||
|
||||
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]:
|
||||
"""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:
|
||||
return None
|
||||
|
||||
@@ -1789,7 +1789,7 @@ async def get_proxy_link_for_secret(secret: str) -> Optional[str]:
|
||||
|
||||
async def get_proxy_link() -> Optional[str]:
|
||||
"""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:
|
||||
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]
|
||||
details = f"\n<pre>{html.escape(compact)}</pre>"
|
||||
elif enabled:
|
||||
details = "\n<i>Runtime API недоступен. Новые установки goTelegram Pro включают его автоматически.</i>"
|
||||
details = "\n<i>Runtime API недоступен. Новые установки PCAtelegram_web включают его автоматически.</i>"
|
||||
else:
|
||||
details = "\n<i>Ключ отключён и сейчас не принимается telemt.</i>"
|
||||
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)
|
||||
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")
|
||||
if code == 0:
|
||||
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]:
|
||||
script = (
|
||||
"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; "
|
||||
"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 30"
|
||||
@@ -2358,9 +2358,9 @@ async def set_full_backup_schedule(frequency: str) -> Tuple[bool, str]:
|
||||
if frequency not in {"off", "daily", "weekly", "monthly"}:
|
||||
return False, "unsupported schedule"
|
||||
script = (
|
||||
"source /opt/gotelegram/lib/common.sh; "
|
||||
"source /opt/gotelegram/lib/i18n.sh; "
|
||||
"source /opt/gotelegram/lib/backup.sh; "
|
||||
"source /opt/pcatelegram_web/lib/common.sh; "
|
||||
"source /opt/pcatelegram_web/lib/i18n.sh; "
|
||||
"source /opt/pcatelegram_web/lib/backup.sh; "
|
||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||
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)
|
||||
script = (
|
||||
"sleep 1; "
|
||||
"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; "
|
||||
"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 \"\" >/dev/null 2>&1 || true; "
|
||||
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"
|
||||
f"Файлов: <code>{len(backups)}</code>\n"
|
||||
f"Расписание: <b>{labels.get(schedule['frequency'], schedule['frequency'])}</b>\n\n"
|
||||
"В бекап входит: telemt config, настройки goTelegram, ключи, отключённые ключи, сайт, шаблоны, SSL, бот, админка и история трафика."
|
||||
"В бекап входит: telemt config, настройки PCAtelegram_web, ключи, отключённые ключи, сайт, шаблоны, SSL, бот, админка и история трафика."
|
||||
)
|
||||
else:
|
||||
text = (
|
||||
"<b>💾 Backups</b>\n\n"
|
||||
f"Files: <code>{len(backups)}</code>\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)
|
||||
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:
|
||||
text = "❌ Файл бекапа не найден" if get_user_lang(user_id) == "ru" else "❌ Backup file not found"
|
||||
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:
|
||||
await launch_full_restore(safe_path)
|
||||
text = (
|
||||
@@ -2759,7 +2759,7 @@ async def cb_ssl_status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> N
|
||||
|
||||
|
||||
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 "")
|
||||
if domain:
|
||||
return domain
|
||||
@@ -2998,7 +2998,7 @@ async def cb_menu_credits(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
||||
|
||||
text = (
|
||||
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"<b>Special thanks to:</b>\n\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" Professional design framework\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(
|
||||
@@ -3030,7 +3030,7 @@ async def cb_menu_remove(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
||||
await query.answer()
|
||||
|
||||
text = (
|
||||
"<b>⚠️ Remove goTelegram Pro</b>\n\n"
|
||||
"<b>⚠️ Remove PCAtelegram_web</b>\n\n"
|
||||
"This will completely remove the installation.\n"
|
||||
"Are you sure?"
|
||||
)
|
||||
@@ -3048,16 +3048,16 @@ async def cb_remove_confirm(update: Update, context: ContextTypes.DEFAULT_TYPE)
|
||||
query = update.callback_query
|
||||
await query.answer()
|
||||
|
||||
await safe_edit_message(query,"⏳ Removing goTelegram Pro...")
|
||||
await safe_edit_message(query,"⏳ Removing PCAtelegram_web...")
|
||||
|
||||
# Stop service
|
||||
await sh("systemctl", "stop", TELEMT_SERVICE)
|
||||
|
||||
# Remove directories
|
||||
for path in ["/opt/gotelegram", WEBSITE_ROOT]:
|
||||
for path in ["/opt/pcatelegram_web", WEBSITE_ROOT]:
|
||||
await sh("rm", "-rf", path)
|
||||
|
||||
text = "✅ goTelegram Pro removed successfully"
|
||||
text = "✅ PCAtelegram_web removed successfully"
|
||||
keyboard = InlineKeyboardMarkup(
|
||||
[[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()
|
||||
buttons = get_main_menu(user_id)
|
||||
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_prompt')}"
|
||||
)
|
||||
@@ -3158,7 +3158,7 @@ async def handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
||||
# Re-render main menu in the new language
|
||||
buttons = get_main_menu(user_id)
|
||||
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_prompt')}"
|
||||
)
|
||||
@@ -3282,12 +3282,12 @@ async def handle_text_message(update: Update, context: ContextTypes.DEFAULT_TYPE
|
||||
if not ok:
|
||||
await update.message.reply_text(_t(user_id, info), parse_mode="HTML")
|
||||
return
|
||||
# Success — record in goTelegram Pro config. Use "template_id" (canonical
|
||||
# field name written by install.sh/save_gotelegram_config).
|
||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
||||
# Success — record in PCAtelegram_web config. Use "template_id" (canonical
|
||||
# field name written by install.sh/save_pcatelegram_web_config).
|
||||
config = load_json(PCATELEGRAM_WEB_CONFIG) or {}
|
||||
config["template_id"] = tpl_id
|
||||
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):
|
||||
try:
|
||||
os.makedirs(WEBSITE_ROOT, exist_ok=True)
|
||||
@@ -3353,7 +3353,7 @@ def main() -> None:
|
||||
application.add_error_handler(error_handler)
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
# 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.
|
||||
|
||||
Usage:
|
||||
@@ -23,9 +23,9 @@ logger = logging.getLogger(__name__)
|
||||
# ── Paths ─────────────────────────────────────────────────────────────────
|
||||
_MODULE_DIR = Path(__file__).resolve().parent
|
||||
LANG_DIR = _MODULE_DIR / "lang"
|
||||
USER_LANG_FILE = Path("/opt/gotelegram-bot/user_langs.json")
|
||||
GOTELEGRAM_CONFIG = Path("/opt/gotelegram/config.json")
|
||||
GOTELEGRAM_LANG_MARKER = Path("/opt/gotelegram/.language")
|
||||
USER_LANG_FILE = Path("/opt/pcatelegram_web-bot/user_langs.json")
|
||||
PCATELEGRAM_WEB_CONFIG = Path("/opt/pcatelegram_web/config.json")
|
||||
PCATELEGRAM_WEB_LANG_MARKER = Path("/opt/pcatelegram_web/.language")
|
||||
|
||||
# Supported codes; keep in sync with lang/*.json
|
||||
SUPPORTED_LANGS = ("en", "ru")
|
||||
@@ -34,18 +34,18 @@ SUPPORTED_LANGS = ("en", "ru")
|
||||
def _detect_default_lang() -> str:
|
||||
candidates = []
|
||||
try:
|
||||
if GOTELEGRAM_CONFIG.exists():
|
||||
with open(GOTELEGRAM_CONFIG, "r", encoding="utf-8") as f:
|
||||
if PCATELEGRAM_WEB_CONFIG.exists():
|
||||
with open(PCATELEGRAM_WEB_CONFIG, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
if isinstance(data, dict):
|
||||
candidates.extend([data.get("language"), data.get("lang")])
|
||||
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:
|
||||
if GOTELEGRAM_LANG_MARKER.exists():
|
||||
candidates.append(GOTELEGRAM_LANG_MARKER.read_text(encoding="utf-8").strip()[:2])
|
||||
if PCATELEGRAM_WEB_LANG_MARKER.exists():
|
||||
candidates.append(PCATELEGRAM_WEB_LANG_MARKER.read_text(encoding="utf-8").strip()[:2])
|
||||
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", ""))
|
||||
for raw in candidates:
|
||||
code = str(raw or "").strip().lower()
|
||||
@@ -6,7 +6,7 @@
|
||||
"lang_saved": "Language saved: %s",
|
||||
"lang_choose": "Choose your language:",
|
||||
|
||||
"welcome_title": "goTelegram Pro v%s",
|
||||
"welcome_title": "PCAtelegram_web v%s",
|
||||
"welcome_subtitle": "🤖 MTProxy Management Bot",
|
||||
"welcome_powered": "Powered by telemt engine",
|
||||
"welcome_prompt": "Select an action from the menu below:",
|
||||
@@ -17,7 +17,7 @@
|
||||
"btn_no": "❌ No",
|
||||
|
||||
"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.",
|
||||
|
||||
"menu_install": "⚙️ Install",
|
||||
@@ -6,7 +6,7 @@
|
||||
"lang_saved": "Язык сохранён: %s",
|
||||
"lang_choose": "Выберите язык:",
|
||||
|
||||
"welcome_title": "goTelegram Pro v%s",
|
||||
"welcome_title": "PCAtelegram_web v%s",
|
||||
"welcome_subtitle": "🤖 Бот управления MTProxy",
|
||||
"welcome_powered": "На базе движка telemt",
|
||||
"welcome_prompt": "Выберите действие в меню ниже:",
|
||||
@@ -17,7 +17,7 @@
|
||||
"btn_no": "❌ Нет",
|
||||
|
||||
"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Используйте кнопки меню для остальных операций.",
|
||||
|
||||
"menu_install": "⚙️ Установить",
|
||||
Reference in New Issue
Block a user