diff --git a/.gitignore b/.gitignore index b1d9ed3..16278c9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ npm-debug.log* *.swp .env .env.* +Новости/ diff --git a/00. НАЧНИ ОТСЮДА.md b/00. НАЧНИ ОТСЮДА.md index 35b5431..116848a 100644 --- a/00. НАЧНИ ОТСЮДА.md +++ b/00. НАЧНИ ОТСЮДА.md @@ -1,8 +1,10 @@ # 00. НАЧНИ ОТСЮДА — amnezia_web-PRO **Промпт для нового чата:** -> Проект «Открытые проекты/amnezia_web-PRO» — полностью открытая веб-панель Amnezia (Node, `server.js` + `public/`). Закрытой версии нет (старая — в `Архив/amnezia_web-PRO_test`). Прочитай `PROJECT_INDEX.md` и `09. История и грабли`. Тесты — на school-friends (сервер) и school-it-kruzhok (клиент) через svault. Релиз: тег + GitHub API, затем Gitea, Notes, новость в @PCAdministration ботом PCA_jarvis_bot (токен `TG_BOT_TOKEN` в `~/jarvis-ru-windows/.env`). +> Проект «Открытые проекты/amnezia_web-PRO» — полностью открытая веб-панель Amnezia (Node, `server.js` + `public/`). Закрытой версии нет (старая — в `Архив/amnezia_web-PRO_test`). Прочитай `PROJECT_INDEX.md` и `09. История и грабли`. Тесты — на school-friends (сервер) и school-it-kruzhok (клиент) через svault. Релиз: тег + GitHub API, затем Gitea, Notes, новость в группу PCA, тема «Новости» (chat_id -1003902709196, message_thread_id=131) ботом @PCAdmin27_bot (токен `TELEGRAM_MOD_BOT_TOKEN` в «Закрытые продукты/home_Friends_It/ДОСТУПЫ.md»); PCA_jarvis_bot не использовать. Gitea — pull-зеркало, обновлять mirror-sync. ## Оглавление - `PROJECT_INDEX.md` — что где лежит, установка - `09. История и грабли` — оглавление записей 09.N +- `scripts/checks/` — проверки парка AWG (запускать внутри контейнера панели, читают /app/data/data.json) +- `Новости/` — тексты новостей релизов (не в git) diff --git a/09. История и грабли.md b/09. История и грабли.md index eebdfa2..7842685 100644 --- a/09. История и грабли.md +++ b/09. История и грабли.md @@ -2,4 +2,5 @@ - [09.1 Версия 1.3.0 — протоколы с сайта, каскад, домен, тема](<09.1 Версия 1.3.0 — протоколы с сайта, каскад, домен, тема.md>) — 23.10.2026 - [09.2 Версия 1.4.0 — Xray VLESS, всё открыто](<09.2 Версия 1.4.0 — Xray VLESS, всё открыто.md>) — 23.10.2026 +- [09.3 Старые исправления июня 2026](<09.3 Старые исправления июня 2026.md>) — 13 частей 09.3.N, перенесены из Notes 23.10.2026 - 04.10.2026 — проект переехал в папку-группу; код не менялся. diff --git a/09.3 Старые исправления июня 2026.md b/09.3 Старые исправления июня 2026.md new file mode 100644 index 0000000..9b0216f --- /dev/null +++ b/09.3 Старые исправления июня 2026.md @@ -0,0 +1,17 @@ +# 09.3 Старые исправления июня 2026 + +Оглавление частей: заметки из Notes до регламента (июнь–июль 2026), по одной на исправление. + +- [09.3.1 Canonical public amnezia_web-PRO 06.06](<09.3.1 Canonical public amnezia_web-PRO 06.06.md>) +- [09.3.2 Canonical amnezia_web-PRO status 21.06](<09.3.2 Canonical amnezia_web-PRO status 21.06.md>) +- [09.3.3 Fix AWG auto profiles 21.06](<09.3.3 Fix AWG auto profiles 21.06.md>) +- [09.3.4 Fix stale AWG profile snapshot 21.06](<09.3.4 Fix stale AWG profile snapshot 21.06.md>) +- [09.3.5 Client import from Amnezia backup 21.06](<09.3.5 Client import from Amnezia backup 21.06.md>) +- [09.3.6 Fix duplicate AWG instances 21.06](<09.3.6 Fix duplicate AWG instances 21.06.md>) +- [09.3.7 Fix AWG instance labels 21.06](<09.3.7 Fix AWG instance labels 21.06.md>) +- [09.3.8 Fix clients selected profile 21.06](<09.3.8 Fix clients selected profile 21.06.md>) +- [09.3.9 Fix peers missing clientsTable 21.06](<09.3.9 Fix peers missing clientsTable 21.06.md>) +- [09.3.10 Sync app-created Amnezia users 21.06](<09.3.10 Sync app-created Amnezia users 21.06.md>) +- [09.3.11 Fix legacy clientsTable formats 21.06](<09.3.11 Fix legacy clientsTable formats 21.06.md>) +- [09.3.12 Fix Amnezia source auto-discovery 22.06](<09.3.12 Fix Amnezia source auto-discovery 22.06.md>) +- [09.3.13 Fix awg binary not found 22.06](<09.3.13 Fix awg binary not found 22.06.md>) diff --git a/09.3.1 Canonical public amnezia_web-PRO 06.06.md b/09.3.1 Canonical public amnezia_web-PRO 06.06.md new file mode 100644 index 0000000..3c03cfa --- /dev/null +++ b/09.3.1 Canonical public amnezia_web-PRO 06.06.md @@ -0,0 +1,17 @@ +# 09.3.1 Canonical public amnezia_web-PRO 06.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +amnezia_web-PRO canonical public repo — 06.06 +Keep one public project: https://github.com/andrey271192/amnezia_web-PRO +Install +curl -fsSL https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh | sudo bash +Defaults +Fresh login: admin +Fresh password: admin +Change password after first login. +GitHub +Repo is public. +Private download flow removed. +Separate deploy bundle removed from active docs and notes. +Commit: 05e6d00 docs: make pro repo public install source. diff --git a/09.3.10 Sync app-created Amnezia users 21.06.md b/09.3.10 Sync app-created Amnezia users 21.06.md new file mode 100644 index 0000000..8d46548 --- /dev/null +++ b/09.3.10 Sync app-created Amnezia users 21.06.md @@ -0,0 +1,23 @@ +# 09.3.10 Sync app-created Amnezia users 21.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Commit: dfeabe0 feat: sync app-created peers into clients table +Version: v1.2.36 +Задача +Клиенты уже были созданы в приложении Amnezia. Их нужно подтянуть в веб-панель, а не создавать заново. +Решение +Добавлена кнопка Пользователи → Подтянуть из awg0.conf. +POST /api/clients/sync-peers берёт активные [Peer] текущего инстанса и создаёт недостающие строки clientsTable. +VPN-конфиг не пересоздаётся, контейнеры клиентов не трогаются. +Имена создаются как Клиент IP или Peer KEY, потом можно переименовать. +Экспорт .conf появится после импорта клиентского .conf, потому приватный ключ клиента есть только в приложении. +Команда +curl -fsSL "https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh?nocache=$(date +%s)" | sudo env SKIP_LANDING=1 bash +Потом Ctrl+F5 → выбрать Инстанс → Пользователи → Подтянуть из awg0.conf. +Проверено +node --check server.js +node --check public/app.js +bash -n scripts/*.sh +npm audit --audit-level=moderate: 0 vulnerabilities +git diff --check diff --git a/09.3.11 Fix legacy clientsTable formats 21.06.md b/09.3.11 Fix legacy clientsTable formats 21.06.md new file mode 100644 index 0000000..54344ad --- /dev/null +++ b/09.3.11 Fix legacy clientsTable formats 21.06.md @@ -0,0 +1,17 @@ +# 09.3.11 Fix legacy clientsTable formats 21.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Commit: 4e6ab2d fix: parse legacy clients table formats +Version: v1.2.37 +Причина +Старые клиенты могли не подтягиваться, если clientsTable не был массивом [{clientId,userData}], а имел object/map/nested формат другой версии Amnezia. +Исправлено +parseClientsTable поддерживает array, object map, nested clients/users/rows/items/data/clientList/clientsTable. +clientRowId понимает clientId/id/publicKey/public_key/key/client_id и вложенные userData поля. +Добавлен GET /api/clients/source-report для диагностики источников без полных ключей. +Команда +curl -fsSL "https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh?nocache=$(date +%s)" | sudo env SKIP_LANDING=1 bash +Потом Ctrl+F5 → выбрать Инстанс → Пользователи → Подтянуть из awg0.conf. +Если всё равно пусто +Открыть в браузере после логина: /api/clients/source-report?profileId=awg и /api/clients/source-report?profileId=awg2 diff --git a/09.3.12 Fix Amnezia source auto-discovery 22.06.md b/09.3.12 Fix Amnezia source auto-discovery 22.06.md new file mode 100644 index 0000000..724b810 --- /dev/null +++ b/09.3.12 Fix Amnezia source auto-discovery 22.06.md @@ -0,0 +1,20 @@ +# 09.3.12 Fix Amnezia source auto-discovery 22.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Commit: b360095 fix: auto-discover amnezia client sources +Version: v1.2.38 +Root cause +Amnezia installs can keep old clients in /opt/amnezia/awg/wg0.conf, while profile pointed to /opt/amnezia/awg/awg0.conf. clientsTable can also live in /opt/amnezia/wireguard/clientsTable or have non-array format. +Fix +Runtime now scans config candidates: awg0.conf, wg0.conf, wireguard/wg0.conf. +Chooses config with max [Peer] count. +Runtime scans clientsTable candidates: awg/clientsTable and wireguard/clientsTable. +Chooses clientsTable with max parsed client count. +iface is inferred from selected config filename. +source-report shows resolved confPath/clientsPath/iface. +Command +curl -fsSL "https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh?nocache=$(date +%s)" | sudo env SKIP_LANDING=1 bash +Then Ctrl+F5 → select Instance → Users → Pull from awg0.conf. +Source +Amnezia issue #1615 mentions manual flow with /opt/amnezia/awg/wg0.conf and clientsTable; issue #2238 confirms clientsTable field variance. diff --git a/09.3.13 Fix awg binary not found 22.06.md b/09.3.13 Fix awg binary not found 22.06.md new file mode 100644 index 0000000..84d46b3 --- /dev/null +++ b/09.3.13 Fix awg binary not found 22.06.md @@ -0,0 +1,15 @@ +# 09.3.13 Fix awg binary not found 22.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Commit: 8e5d51a fix: auto-detect wg binary in containers +Version: v1.2.39 +Symptom +При добавлении/подтягивании старых .conf ошибка: sh: awg: not found. В amneziawg контейнере awg binary отсутствует. +Fix +Runtime auto-detects binary inside container: preferred wgBinary, then wg for wg0.conf, then awg, then wg. +show/pubkey/genkey/syncconf use resolved binary, not hardcoded profile.wgBinary. +source-report and /api/clients expose resolved wgBinary. +Command +curl -fsSL "https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh?nocache=$(date +%s)" | sudo env SKIP_LANDING=1 bash +Then Ctrl+F5 → Instance → Users → Pull from awg0.conf. diff --git a/09.3.2 Canonical amnezia_web-PRO status 21.06.md b/09.3.2 Canonical amnezia_web-PRO status 21.06.md new file mode 100644 index 0000000..a0001ec --- /dev/null +++ b/09.3.2 Canonical amnezia_web-PRO status 21.06.md @@ -0,0 +1,20 @@ +# 09.3.2 Canonical amnezia_web-PRO status 21.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Важно: amnezia_web-PRO_test — отдельный продукт/тестовая ветка. Canonical public product сейчас: amnezia_web-PRO. +GitHub: https://github.com/andrey271192/amnezia_web-PRO +Local: /Users/andrejbobyrev/andrey271192-repos/amnezia_web-PRO +Last pushed commit: c202f0b — chore: add npm lockfile +Правило +amnezia_web-PRO — основной публичный продукт. +amnezia_web-PRO_test — отдельный тестовый продукт, не смешивать с public PRO. +amnezia-web-pro-deploy — legacy/старый deploy repo, не использовать как основной продукт. +Install +curl -fsSL https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh | sudo bash +Defaults +Fresh login: admin +Fresh password: admin +Change password after first login. +AWG issue from client +Install-check видит два контейнера: amnezia-awg2 и amnezia-awg. Если веб показывает только awg2, причина в runtime-discovery/cache/UI-filter, не в Docker. Надо проверить конкретный VPS: docker ps, panel API/status, logs, затем исправить отображение обоих AWG profiles без ручного AWG_PROFILES. diff --git a/09.3.3 Fix AWG auto profiles 21.06.md b/09.3.3 Fix AWG auto profiles 21.06.md new file mode 100644 index 0000000..883cc4c --- /dev/null +++ b/09.3.3 Fix AWG auto profiles 21.06.md @@ -0,0 +1,22 @@ +# 09.3.3 Fix AWG auto profiles 21.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Repo: https://github.com/andrey271192/amnezia_web-PRO +Commit: cbc20a1 — fix: auto-detect awg profiles on install +Что исправлено +Переустановка из GitHub работает для /opt/amnezia-admin без .git. +Установщик сохраняет текущий порт панели. +Установщик сохраняет текущий Docker volume /data. +Перед заменой /opt/amnezia-admin создаётся backup папки. +Если найден один контейнер amnezia-awg*, он становится AWG_CONTAINER. +Если найдено 2+ контейнера amnezia-awg*, AWG_PROFILES создаётся автоматически и сохраняется в /root/amnezia-admin.awg-profiles.json. +Dockerfile использует npm ci по package-lock.json. +Что сказать пользователю +curl -fsSL https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh | sudo env SKIP_LANDING=1 bash +После установки: обновить страницу Ctrl+F5. AWG контейнеры не удаляются и не пересоздаются. +Проверено +bash -n scripts/install.sh +bash -n scripts/uninstall.sh +node --check server.js +npm audit --audit-level=moderate diff --git a/09.3.4 Fix stale AWG profile snapshot 21.06.md b/09.3.4 Fix stale AWG profile snapshot 21.06.md new file mode 100644 index 0000000..147187b --- /dev/null +++ b/09.3.4 Fix stale AWG profile snapshot 21.06.md @@ -0,0 +1,9 @@ +# 09.3.4 Fix stale AWG profile snapshot 21.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Commit: 8ba2a26 — fix: refresh stale awg profile snapshots +Причина повтора бага: старый /root/amnezia-admin.awg-profiles.json мог содержать один профиль. Installer восстанавливал его и не пересобирал profiles по двум контейнерам. +Теперь если контейнеров amnezia-awg* два или больше, а восстановленный AWG_PROFILES содержит меньше двух container, installer автоматически пересобирает profiles и перезаписывает snapshot. +rm -f /root/amnezia-admin.awg-profiles.json +curl -fsSL https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh?nocache=$(date +%s) | sudo env SKIP_LANDING=1 bash diff --git a/09.3.5 Client import from Amnezia backup 21.06.md b/09.3.5 Client import from Amnezia backup 21.06.md new file mode 100644 index 0000000..c9f35a6 --- /dev/null +++ b/09.3.5 Client import from Amnezia backup 21.06.md @@ -0,0 +1,24 @@ +# 09.3.5 Client import from Amnezia backup 21.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Project: amnezia_web-PRO +Repo: https://github.com/andrey271192/amnezia_web-PRO +Commit: cff27e2 feat: import clients from amnezia configs +Что добавлено +В панели появился блок Импорт клиента. +Можно вставить готовый клиентский .conf или JSON backup Amnezia, если внутри есть текстовый .conf. +Если peer уже есть в awg0.conf, дубль не создаётся: восстанавливается/обновляется строка clientsTable. +Если peer отсутствует, он добавляется в текущий выбранный Инстанс. +Исходный .conf сохраняется в userData.last_config, чтобы дальше работали экспорт и управление из веба. +Добавлена защита: импортируемый .conf должен относиться к текущему серверу/инстансу по PublicKey сервера. +Команда переустановки для пользователя +curl -fsSL "https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh?nocache=$(date +%s)" | sudo env SKIP_LANDING=1 bash +Проверено +node --check server.js +node --check public/app.js +bash -n для всех scripts/*.sh +npm audit --audit-level=moderate: 0 vulnerabilities +git diff --check +Что сказать пользователю +Обновите панель командой выше, зайдите в веб, выберите нужный Инстанс и откройте блок Импорт клиента. Вставьте экспортированный клиентский .conf из приложения Amnezia или backup, где внутри есть этот .conf. После импорта клиент появится в таблице, а старые peer-дубли создаваться не будут. diff --git a/09.3.6 Fix duplicate AWG instances 21.06.md b/09.3.6 Fix duplicate AWG instances 21.06.md new file mode 100644 index 0000000..a8b27c1 --- /dev/null +++ b/09.3.6 Fix duplicate AWG instances 21.06.md @@ -0,0 +1,22 @@ +# 09.3.6 Fix duplicate AWG instances 21.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Project: amnezia_web-PRO +Commit: 8c67d7d fix: dedupe duplicate awg instances +Version: v1.2.32 +Причина +После переустановки один и тот же AWG контейнер мог попасть в список дважды: из AWG_PROFILES и из saved managed instances. Старый dedup был только по id, поэтому при разных id веб показывал две одинаковые карточки. +Исправлено +Dedup профилей по container + confPath + iface + clientsPath. +/api/instances дополнительно дедупит runtime target после auto-resolve контейнера. +load/save managed profiles чистит дубли из instances.json. +Docs обновлены: раздел Инстансы задублировались. +Команда для пользователя +curl -fsSL "https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh?nocache=$(date +%s)" | sudo env SKIP_LANDING=1 bash +После установки: Ctrl+F5 в браузере. +Проверено +node --check server.js +node --check public/app.js +npm audit --audit-level=moderate: 0 vulnerabilities +git diff --check diff --git a/09.3.7 Fix AWG instance labels 21.06.md b/09.3.7 Fix AWG instance labels 21.06.md new file mode 100644 index 0000000..88d5d53 --- /dev/null +++ b/09.3.7 Fix AWG instance labels 21.06.md @@ -0,0 +1,15 @@ +# 09.3.7 Fix AWG instance labels 21.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Commit: a9a67af fix: show distinct awg instance labels +Version: v1.2.33 +Причина +У пользователя реально два контейнера: amnezia-awg2 и amnezia-awg. Порты и число клиентов разные, значит это не дубль. Но UI рисовал title по variant, поэтому обе карточки выглядели как AmneziaWG 2.0. +Исправлено +Карточка инстанса показывает profile label, а не только variant title. +Backend лучше определяет variant по profile/container/label до чтения конфига. +Docs уточнены: два разных контейнера с разными портами — нормальные два инстанса. +Команда +curl -fsSL "https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh?nocache=$(date +%s)" | sudo env SKIP_LANDING=1 bash +Потом Ctrl+F5. diff --git a/09.3.8 Fix clients selected profile 21.06.md b/09.3.8 Fix clients selected profile 21.06.md new file mode 100644 index 0000000..2369131 --- /dev/null +++ b/09.3.8 Fix clients selected profile 21.06.md @@ -0,0 +1,18 @@ +# 09.3.8 Fix clients selected profile 21.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Commit: cb5fca3 fix: load clients for selected profile +Version: v1.2.34 +Симптом +Переключатель Инстанс показывает правильный контейнер, но таблица Пользователи показывает клиентов от другого/старого инстанса. +Причина +Создание/экспорт уже передавали profileId явно, но /api/clients и операции таблицы опирались на cookie выбранного профиля. Cookie мог не примениться/устареть, поэтому список клиентов приходил не от выбранного инстанса. +Исправлено +GET /api/clients принимает явный profileId. +disable/enable/rename/delete/disconnect-date используют runtimeFromExportRequest и body.profileId. +Frontend передаёт profileId во все запросы таблицы клиентов. +Docs обновлены. +Команда +curl -fsSL "https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh?nocache=$(date +%s)" | sudo env SKIP_LANDING=1 bash +Потом Ctrl+F5. diff --git a/09.3.9 Fix peers missing clientsTable 21.06.md b/09.3.9 Fix peers missing clientsTable 21.06.md new file mode 100644 index 0000000..42314e1 --- /dev/null +++ b/09.3.9 Fix peers missing clientsTable 21.06.md @@ -0,0 +1,18 @@ +# 09.3.9 Fix peers missing clientsTable 21.06 + +_Старая заметка из Notes (июнь 2026), перенесена 23.10.2026. Оригинал: Архив/Старые заметки Notes 20261023._ + +Commit: fd66b0a fix: show peers missing clients table +Version: v1.2.35 +Симптом +Инстанс выбран правильно, но старые клиенты не появляются в таблице Пользователи. +Причина +UI строил список только из clientsTable. У старых/созданных приложением клиентов peer может быть в awg0.conf, а запись clientsTable отсутствовать или иметь другой формат. +Исправлено +GET /api/clients теперь возвращает union clientsTable + Peer из awg0.conf. +Peer-only строки показываются как Peer xxxx… и помечаются missingClientTable. +Rename/date/disable/delete умеют работать с peer-only строками. +Для экспорта .conf всё равно нужен импорт клиентского .conf, потому приватный ключ клиента сервер не знает. +Команда +curl -fsSL "https://raw.githubusercontent.com/andrey271192/amnezia_web-PRO/main/scripts/install.sh?nocache=$(date +%s)" | sudo env SKIP_LANDING=1 bash +Потом Ctrl+F5. diff --git a/scripts/checks/audit2.py b/scripts/checks/audit2.py new file mode 100644 index 0000000..db660b8 --- /dev/null +++ b/scripts/checks/audit2.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +"""Сверяем ПОДНЯТЫЕ интерфейсы с их собственными конфигами. + +Первый заход сравнивал wg0.conf с интерфейсом wg0, а в контейнере amnezia-awg +поднят awg0 — отсюда ложные «расхождения». +""" +import json, sys +sys.path.insert(0, "/app") +from managers.ssh_manager import SSHManager + +PROBE = r""" +for c in $(docker ps --format '{{.Names}}' 2>/dev/null | grep '^amnezia-' | grep -vE 'nginx|frontend|backend|landing|xray|socks|ipsec|openvpn'); do + for bin in awg wg; do + docker exec $c sh -c "command -v $bin >/dev/null" 2>/dev/null || continue + for i in $(docker exec $c sh -c "$bin show interfaces 2>/dev/null"); do + live=$(docker exec $c sh -c "$bin show $i peers 2>/dev/null | grep -c ." | tr -d '\n') + conf="" + for f in /opt/amnezia/awg/$i.conf /opt/amnezia/awg/awg0.conf /opt/amnezia/awg/wg0.conf; do + docker exec $c test -f $f 2>/dev/null && { conf=$f; break; } + done + [ -n "$conf" ] || { echo "$c $i live=$live конфиг=НЕ НАЙДЕН"; continue; } + infile=$(docker exec $c grep -c '^\[Peer\]' $conf 2>/dev/null | tr -d '\n') + echo "$c $i live=$live файл=$infile ($conf)" + done + done +done +""" + +d = json.load(open("/app/data/data.json")) +плохо = 0 +for s in d["servers"]: + try: + with SSHManager(s["host"], s.get("ssh_port", 22), s["username"], + password=s.get("password") or None, + private_key=s.get("private_key") or None, + connect_timeout=8) as ssh: + out, err, _ = ssh.run_command(PROBE, timeout=60) + строки = [x.strip() for x in (out or "").splitlines() if x.strip()] + if not строки: + print(" ? %-26s нет поднятых интерфейсов" % s["name"][:26]) + continue + for стр in строки: + беда = False + if "live=" in стр and "файл=" in стр: + l = int(стр.split("live=")[1].split()[0]) + f = int(стр.split("файл=")[1].split()[0]) + беда = (l != f) + плохо += 1 if беда else 0 + print(" %s %-26s %s" % ("!!" if беда else "ok", s["name"][:26], стр)) + except Exception as e: + плохо += 1 + print(" !! %-26s НЕ ДОСТУЧАЛСЯ: %s" % (s["name"][:26], str(e)[:60])) +print("\nрасхождений:", плохо) diff --git a/scripts/checks/audit_conf.py b/scripts/checks/audit_conf.py new file mode 100644 index 0000000..8ea686b --- /dev/null +++ b/scripts/checks/audit_conf.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""Целостность конфигов awg по всему парку: склейки, финальный перевод строки, +проходит ли awg-quick strip и совпадает ли число пиров с живым интерфейсом.""" +import json, sys +sys.path.insert(0, "/app") +from managers.ssh_manager import SSHManager + +PROBE = r""" +for c in amnezia-awg2 amnezia-awg amnezia-awg31 amnezia-awg3 amnezia-awg-legacy; do + docker ps --format '{{.Names}}' 2>/dev/null | grep -qx $c || continue + for f in awg0.conf wg0.conf; do + p=/opt/amnezia/awg/$f + docker exec $c test -f $p 2>/dev/null || continue + glue=$(docker exec $c grep -c '/32\[Peer\]' $p 2>/dev/null | tr -d '\n') + end=$(docker exec $c sh -c "tail -c 1 $p | od -An -c | tr -d ' \n'") + peers=$(docker exec $c grep -c '^\[Peer\]' $p 2>/dev/null | tr -d '\n') + mode=$(docker exec $c stat -c %a $p 2>/dev/null | tr -d '\n') + bin=wg; iface=wg0 + case $f in awg0.conf) bin=awg; iface=awg0;; esac + if docker exec $c sh -c "$bin-quick strip $p > /dev/null 2>&1"; then strip=ok; else strip=СБОЙ; fi + live=$(docker exec $c sh -c "$bin show $iface peers 2>/dev/null | grep -c ." | tr -d '\n') + echo "$c/$f peers=$peers live=$live glue=$glue end=$end mode=$mode strip=$strip" + done +done +""" + +d = json.load(open("/app/data/data.json")) +беда = 0 +for s in d["servers"]: + try: + with SSHManager(s["host"], s.get("ssh_port", 22), s["username"], + password=s.get("password") or None, + private_key=s.get("private_key") or None, + connect_timeout=8) as ssh: + out, err, _ = ssh.run_command(PROBE, timeout=60) + строки = [x.strip() for x in (out or "").splitlines() if x.strip()] + if not строки: + print(" ? %-26s нет контейнеров awg (%s)" % (s["name"][:26], (err or "")[:40])) + continue + for стр in строки: + плохо = ("glue=0" not in стр) or ("strip=ok" not in стр) or ("end=\\n" not in стр) + if "peers=" in стр and "live=" in стр: + try: + p = int(стр.split("peers=")[1].split()[0]) + l = int(стр.split("live=")[1].split()[0]) + if p != l: + плохо = True + стр += " ← файл и интерфейс расходятся" + except Exception: + pass + беда += 1 if плохо else 0 + print(" %s %-26s %s" % ("!!" if плохо else "ok", s["name"][:26], стр)) + except Exception as e: + беда += 1 + print(" !! %-26s НЕ ДОСТУЧАЛСЯ: %s" % (s["name"][:26], str(e)[:60])) +print("\nпроблемных строк:", беда) diff --git a/scripts/checks/check_conf.py b/scripts/checks/check_conf.py new file mode 100644 index 0000000..789320c --- /dev/null +++ b/scripts/checks/check_conf.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +"""Ищем склеенные строки в конфигах awg на всех серверах панели. + +Имена переменных в пробе латиницей: sh внутри контейнеров кириллицу не берёт. +""" +import json, sys +sys.path.insert(0, "/app") +from managers.ssh_manager import SSHManager + +ПРОБА = ( + "for c in amnezia-awg2 amnezia-awg amnezia-awg31 amnezia-awg3 amnezia-awg-legacy; do " + " docker ps --format '{{.Names}}' 2>/dev/null | grep -qx $c || continue; " + " for f in awg0.conf wg0.conf; do " + " p=/opt/amnezia/awg/$f; " + " docker exec $c test -f $p 2>/dev/null || continue; " + " glue=$(docker exec $c grep -c '/32\\[Peer\\]' $p 2>/dev/null || echo 0); " + " endnl=$(docker exec $c sh -c \"tail -c 1 $p | od -An -c | tr -d ' '\" 2>/dev/null); " + " peers=$(docker exec $c grep -c '^\\[Peer\\]' $p 2>/dev/null || echo 0); " + " echo \"$c/$f peers=$peers glue=$glue end=$endnl\"; " + " done; done" +) + +d = json.load(open("/app/data/data.json")) +for s in d["servers"]: + try: + with SSHManager(s["host"], s.get("ssh_port", 22), s["username"], + password=s.get("password") or None, + private_key=s.get("private_key") or None, + connect_timeout=8) as ssh: + out, err, _ = ssh.run_command(ПРОБА, timeout=40) + for строка in (out or err).splitlines(): + строка = строка.strip() + if not строка: + continue + плохо = ("glue=0" not in строка) or ("end=\\n" not in строка) + print("%s %-26s %s" % (" !!" if плохо else " ", s["name"][:26], строка)) + except Exception as e: + print(" %-26s СБОЙ: %s" % (s["name"][:26], str(e)[:50])) diff --git a/scripts/checks/check_garbage.py b/scripts/checks/check_garbage.py new file mode 100644 index 0000000..8bbbfb2 --- /dev/null +++ b/scripts/checks/check_garbage.py @@ -0,0 +1,30 @@ +"""Не осталось ли от проверок тестовых клиентов в clientsTable и в data.json.""" +import json, sys +sys.path.insert(0, "/app") +from managers.ssh_manager import SSHManager + +МЕТКА = "__проверка_связи" +d = json.load(open("/app/data/data.json")) + +в_панели = [c for c in json.dumps(d, ensure_ascii=False).split('"') if МЕТКА in c] +print("следов в data.json панели:", len(в_панели)) + +ПРОБА = ( + "for c in $(docker ps --format '{{.Names}}' 2>/dev/null | grep -E 'amnezia-(awg|wireguard|xray)'); do " + " n=$(docker exec $c sh -c \"grep -o '%s[^\\\"]*' /opt/amnezia/awg/clientsTable /opt/amnezia/xray/clientsTable 2>/dev/null | wc -l\"); " + " [ \"$n\" != \"0\" ] && echo \"$c: $n\"; done; echo готово" % МЕТКА +) +всего = 0 +for s in d["servers"]: + try: + with SSHManager(s["host"], s.get("ssh_port", 22), s["username"], + password=s.get("password") or None, + private_key=s.get("private_key") or None, connect_timeout=8) as ssh: + o, _, _ = ssh.run_command(ПРОБА, timeout=40) + строки = [x for x in (o or "").splitlines() if x.strip() and "готово" not in x] + if строки: + всего += len(строки) + print(" !!", s["name"], строки) + except Exception as e: + print(" ?", s["name"][:26], str(e)[:40]) +print("серверов с остатками:", всего) diff --git a/scripts/checks/test_create.py b/scripts/checks/test_create.py new file mode 100644 index 0000000..98337dc --- /dev/null +++ b/scripts/checks/test_create.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Боевая проверка: на каждом сервере и каждом протоколе создаём тестового +клиента и тут же удаляем. Именно так работает кнопка «Добавить подключение». + +Считаем пиров до и после: если после удаления число не вернулось — значит +за нами остался мусор, и это надо видеть. +""" +import json, sys, time +sys.path.insert(0, "/app") +from managers.ssh_manager import SSHManager +from managers.awg_manager import AWGManager + +ИМЯ = "__проверка_связи_" + time.strftime("%d%m_%H%M") +ПРОТОКОЛЫ = ("awg", "awg2", "awg3", "awg31", "wireguard") + +d = json.load(open("/app/data/data.json")) +итог = {"ok": 0, "сбой": 0, "мусор": 0} + +for s in d["servers"]: + протоколы = [p for p in ПРОТОКОЛЫ + if (s.get("protocols", {}).get(p) or {}).get("installed")] + if not протоколы: + print(" – %-26s протоколов AWG не заведено" % s["name"][:26]) + continue + for proto in протоколы: + метка = "%s / %s" % (s["name"][:22], proto) + try: + ssh = SSHManager(s["host"], s.get("ssh_port", 22), s["username"], + password=s.get("password") or None, + private_key=s.get("private_key") or None, + connect_timeout=10, connect_retries=1) + ssh.connect() + try: + m = AWGManager(ssh) + было = len(m._get_used_ips(proto)) + порт = (s["protocols"][proto] or {}).get("port", "55424") + r = m.add_client(proto, ИМЯ, s["host"], порт) + cid = r.get("client_id") or r.get("clientId") + есть_конфиг = bool(r.get("config")) + стало = len(m._get_used_ips(proto)) + m.remove_client(proto, cid) + после = len(m._get_used_ips(proto)) + finally: + ssh.disconnect() + + если_чисто = (после == было) + итог["ok" if (есть_конфиг and стало == было + 1) else "сбой"] += 1 + if not если_чисто: + итог["мусор"] += 1 + print(" %s %-30s пиров %d → %d → %d конфиг=%s" % ( + "ok" if (есть_конфиг and стало == было + 1 and если_чисто) else "!!", + метка, было, стало, после, "есть" if есть_конфиг else "НЕТ")) + except Exception as e: + итог["сбой"] += 1 + print(" !! %-30s %s" % (метка, str(e)[:70])) + +print("\nсоздалось и убралось начисто: %d, сбоев: %d, осталось мусора: %d" + % (итог["ok"], итог["сбой"], итог["мусор"]))