diff --git a/README.md b/README.md index 97f77f5..6598218 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ | Компонент | Роль | |---|---| | **awg-ctrl** | Привилегированный REST-бэкенд. Управляет пирами через `awg`/`awg-quick`, ведёт SQLite-базу, генерирует `vpn://` ключи. Слушает только loopback. | -| **awg-ui** | Express + React. Веб-панель, аутентификация (JWT), интеграция с API MA7, прокси к awg-ctrl. Единственный сервис, доступный по сети. | +| **awg-ui** | Express + React. Веб-панель, аутентификация (JWT), прокси к awg-ctrl. Единственный сервис, доступный по сети. | | **cli** | Менеджер процессов: `start`/`stop`/`restart`/`status`, смена логина/пароля панели, интерактивное TUI-меню. | Внутренняя связь awg-ui → awg-ctrl подписывается асимметрично (Ed25519): приватный ключ только у awg-ui, awg-ctrl проверяет подпись публичным. @@ -94,38 +94,5 @@ awg-ctrl systemctl start|stop|restart awg-control ``` -## Интеграция с MA7 - -Этот сервер персональный — принадлежит одному абоненту MA7 (сервиса -VPN-подписки). Панель ничем не управляет в MA7 и не отдаёт наружу свой API: -вкладка «Профиль» только читает баланс своего владельца. Секрет MA7 живёт -только в `awg-ui` (`cli.env`) и в браузер не попадает — фронт ходит на свой -бэкенд, тот читает MA7. - -Нужные переменные (задаются при установке или руками в `cli.env`): - -| Переменная | Назначение | -|---|---| -| `MA7_API_BASE_URL` | адрес API MA7, например `https://amnesia.ma7neko.ru` | -| `MA7_JWT_SECRET` | секрет, которым панель сама подписывает `X-Bot-Token` (эндпоинта, выдающего токен, в MA7 нет) | -| `MA7_LOGIN` | логин владельца этого сервера в MA7 (`ma7_xxxxxx`) | - -Вкладка «Профиль» просто показывает текущий баланс `MA7_LOGIN`. При установке -`MA7_LOGIN` заодно предлагается как логин панели (`UI_USER`) — сервер -персональный, и заказчик входит тем же именем, что знает по MA7; при желании -логин панели можно задать свой. Это разные переменные: `UI_USER` решает, кого -пускать в панель, `MA7_LOGIN` — чей баланс показывать. - -`MA7_LOGIN` задаётся один раз при установке и **не редактируется из панели**: у панели -один общий пароль (`UI_USER`/`UI_PASS`) без отдельного клиентского входа, а -`MA7_JWT_SECRET` умеет искать в MA7 любого абонента — редактируемый в браузере -логин превратил бы личный баланс в инструмент подглядывания за чужими. - -> [!WARNING] -> `MA7_JWT_SECRET` — мастер-ключ ко всему MA7: с ним можно читать данные любых -> пользователей MA7, не только этого сервера. Токены MA7 без срока действия, -> отзыва нет — «отобрать доступ» значит одновременно сменить `MA7_JWT_SECRET` -> во всех сервисах MA7 и здесь, в `cli.env`. - ## Лицензия [MIT](LICENSE) © 2026 Ivan Vasilev diff --git a/awg-ui/server.ts b/awg-ui/server.ts index 191b6e0..e980a81 100644 --- a/awg-ui/server.ts +++ b/awg-ui/server.ts @@ -6,7 +6,6 @@ import path from "path"; import fs from "fs"; import crypto from "crypto"; import axios from "axios"; -import { ma7 } from "./ma7"; const app = express(); const PORT = Number(process.env.PORT) || 8080; @@ -154,38 +153,6 @@ async function ctrl(method: string, urlPath: string, body?: unknown) { }); } -// ── Интеграция с MA7 (вкладка «Профиль») ─────────────────────────────────── -// Сервер персональный — панель показывает баланс своего единственного -// владельца, не список абонентов. Логин владельца (MA7_LOGIN) — часть -// конфигурации сервера, задаётся один раз при установке (cli.env), а НЕ -// вводится через UI: бот-токен MA7_JWT_SECRET умеет искать любого абонента -// MA7, и если бы логин можно было менять прямо в панели, любой, кто знает -// пароль от панели, мог бы подсматривать баланс чужих абонентов — панель -// защищена одним общим UI_USER/UI_PASS, отдельного «клиентского» входа нет. -const MA7_LOGIN = process.env.MA7_LOGIN ?? ""; - -app.get("/ui/ma7/profile", requireAuth, async (_req: Request, res: Response) => { - if (!/^[a-zA-Z0-9_-]{1,32}$/.test(MA7_LOGIN)) { - res.status(500).json({ error: "MA7_LOGIN не задан — укажи его в cli.env" }); return; - } - try { - const r = await ma7.get("/api/admin/users", { params: { q: MA7_LOGIN, limit: 1 } }); - if (r.status >= 400) { - const msg = r.status === 401 ? "MA7: неверный MA7_JWT_SECRET" - : r.status === 403 ? "MA7: не та роль в токене" - : (r.data as { error?: string })?.error ?? "Ошибка MA7"; - res.status(r.status === 401 || r.status === 403 ? 502 : r.status).json({ error: msg }); - return; - } - const user = (r.data.users as { login: string; balance: number }[] ?? []) - .find(u => u.login === MA7_LOGIN); - if (!user) { res.status(404).json({ error: "MA7_LOGIN не найден в MA7" }); return; } - res.json({ login: user.login, balance: user.balance }); - } catch { - res.status(502).json({ error: "MA7 недоступен" }); - } -}); - app.use(["/api", "/health", "/awg"], requireAuth, proxy); app.use(express.static(path.join(__dirname, "dist"))); diff --git a/cli/src/index.ts b/cli/src/index.ts index 659ff08..628c2fc 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -90,13 +90,6 @@ const SERVICES = { UI_USER: process.env.UI_USER ?? "admin", UI_PASS: process.env.UI_PASS ?? "", JWT_SECRET: process.env.JWT_SECRET ?? "", - // Интеграция с API MA7 (см. awg-ui/ma7.ts) — секрет чужого сервиса, - // не совпадает с UI_* / JWT_SECRET этой панели. MA7_LOGIN — логин - // владельца этого персонального сервера в MA7 ('ma7_xxxxxx'): - // задаётся один раз при установке, в панели не редактируется. - MA7_API_BASE_URL: process.env.MA7_API_BASE_URL ?? "", - MA7_JWT_SECRET: process.env.MA7_JWT_SECRET ?? "", - MA7_LOGIN: process.env.MA7_LOGIN ?? "", }, pidFile: "/tmp/awg-ui.pid", logFile: path.join(LOGS, "awg-ui.log"), diff --git a/install.sh b/install.sh index 486d0ba..a176762 100644 --- a/install.sh +++ b/install.sh @@ -398,26 +398,8 @@ AWGCTRL_PORT=$(( (RANDOM % 22768) + 32768 )) read -rp " UI port (Enter — случайный): " UI_PORT UI_PORT="${UI_PORT:-$(( (RANDOM % 22768) + 32768 ))}" -# Интеграция с API MA7 (см. README.md, раздел «Интеграция с MA7») — этот -# сервер персональный, панель показывает баланс своего единственного -# владельца. Спрашивается ДО логина панели: логин MA7 по умолчанию становится -# и логином панели (см. ниже). Пустые значения допустимы — вкладку «Профиль» -# можно настроить позже вручную в cli.env. -echo -echo -e "${BLD}Интеграция с MA7 (Enter — оставить пустым и настроить позже):${NC}" -read -rp " MA7 API base URL [https://amnesia.ma7neko.ru]: " MA7_API_BASE_URL -MA7_API_BASE_URL="${MA7_API_BASE_URL:-https://amnesia.ma7neko.ru}" -read -rsp " MA7 JWT_SECRET (мастер-ключ MA7, см. предупреждение в README): " MA7_JWT_SECRET; echo -read -rp " Логин заказчика в MA7 (ma7_xxxxxx, владелец этого сервера): " MA7_LOGIN - -echo -# Логин панели по умолчанию = логин заказчика в MA7: сервер персональный, и -# заказчик входит тем же именем, что знает по MA7. Если MA7_LOGIN не задан — -# откатываемся на admin. UI_USER и MA7_LOGIN остаются разными переменными: -# первая решает, кого пускать в панель, вторая — чей баланс показывать. -UI_USER_DEFAULT="${MA7_LOGIN:-admin}" -read -rp " UI логин [$UI_USER_DEFAULT]: " UI_USER -UI_USER="${UI_USER:-$UI_USER_DEFAULT}" +read -rp " UI логин [admin]: " UI_USER +UI_USER="${UI_USER:-admin}" SUGGESTED_PASS=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c 12 2>/dev/null || openssl rand -hex 6) read -rsp " UI пароль [$SUGGESTED_PASS]: " UI_PASS; echo @@ -896,11 +878,6 @@ UI_PORT=${UI_PORT} UI_USER=${UI_USER} UI_PASS=${UI_PASS} JWT_SECRET=${JWT_SECRET} - -# ── интеграция с MA7 (секрет чужого сервиса, не путать с JWT_SECRET выше) ── -MA7_API_BASE_URL=${MA7_API_BASE_URL} -MA7_JWT_SECRET=${MA7_JWT_SECRET} -MA7_LOGIN=${MA7_LOGIN} ENV # Имя продукта попадает в cli.env, только если оператор задал его явно