mirror of
https://github.com/andrey271192/amnezia_web.git
synced 2026-09-20 14:41:59 +00:00
feat(community): allow deleting clients in FREE tier
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# amnezia_web
|
||||
|
||||
Открытая **базовая** веб-панель для **просмотра** клиентов **AmneziaWG** на своём VPS: таблица клиентов, статус «в туннеле», AllowedIPs, несколько инстансов через **`AWG_PROFILES`**, часы сервера и браузера.
|
||||
**Нет** в интерфейсе и по API: включение/выключение peer, правка дат отключения, переименование, удаление, экспорт `.conf`, «Новый клиент под каскад», Cloudflare WARP, синхронизация времени хоста по SSH — это **[версия PRO](https://boosty.to/andrey27/purchase/3906453?ssource=DIRECT&share=subscription_link)** (приватный репозиторий **amnezia_web-PRO**, доступ подписчикам).
|
||||
Открытая **базовая** веб-панель для **просмотра** клиентов **AmneziaWG** на своём VPS: таблица клиентов, статус «в туннеле», AllowedIPs, несколько инстансов через **`AWG_PROFILES`**, часы сервера и браузера. В редакции **FREE/community** можно **удалить** клиента с сервера (peer и строка в таблице).
|
||||
**Нет** в интерфейсе и по API в FREE: включение/выключение peer, правка дат отключения, переименование, экспорт `.conf`, «Новый клиент под каскад», Cloudflare WARP, синхронизация времени хоста по SSH — это **[версия PRO](https://boosty.to/andrey27/purchase/3906453?ssource=DIRECT&share=subscription_link)** (приватный репозиторий **amnezia_web-PRO**, доступ подписчикам).
|
||||
|
||||
Редакция **`community`** задаётся автоматически файлом **`.amnezia-panel-edition`** в корне репозитория (`community`) или переменной окружения **`AMNEZIA_EDITION=community`** в контейнере. Кнопка и текст про подписку настраиваются **`COMMUNITY_UPGRADE_URL`** и **`COMMUNITY_UPGRADE_PITCH`**.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
| **Время** | Отображение часов контейнера и браузера; синхронизация времени хоста VPS по SSH (если доступно). |
|
||||
| **Cloudflare WARP** | *Необязательно.* Вывод части клиентов в интернет через интерфейс `warp` в контейнере AWG. Если WARP не ставили — статус **«Не установлен»** нормален; панель и VPN без этого работают. Установка и удаление — скрипт `scripts/warp-amnezia.sh` на хосте (`install` / **`uninstall`**), подробности в основном [README](../README.md). |
|
||||
| **Новый клиент под каскад** | Создание нового peer на сервере с **вашим Endpoint** (промежуточный узел); выдача готового `.conf`. |
|
||||
| **Пользователи** | Вкл/выкл peer, удаление, переименование, даты отключения; экспорт `.conf` если в записи есть `userData.last_config`. |
|
||||
| **Пользователи** | В FREE: просмотр и **удаление** peer с сервера. В PRO дополнительно: вкл/выкл, переименование, даты отключения; экспорт `.conf` если в записи есть `userData.last_config`. |
|
||||
|
||||
## Переключатель «Инстанс» не отображается
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "amnezia-admin",
|
||||
"version": "1.1.8",
|
||||
"private": true,
|
||||
"description": "amnezia_web — базовая панель AmneziaWG (только просмотр клиентов; полная версия — PRO).",
|
||||
"description": "amnezia_web — базовая панель AmneziaWG (FREE: просмотр и удаление клиентов; полная версия — PRO).",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -63,10 +63,11 @@ let uiHidden = { users: false, warp: false, cascade: false };
|
||||
const editionBanner = document.querySelector("#edition-banner");
|
||||
const DEFAULT_HEADER_SUB = document.querySelector(".top .sub")?.textContent?.trim() || "";
|
||||
|
||||
/** Состояние редакции панели (community = только просмотр клиентов). */
|
||||
/** Состояние редакции панели (community = просмотр + удаление; остальные мутации — PRO). */
|
||||
let editionState = {
|
||||
tier: "pro",
|
||||
readOnlyClients: false,
|
||||
allowDeleteClients: false,
|
||||
upgradeUrl: null,
|
||||
upgradePitch: null,
|
||||
showDebugWg: true,
|
||||
@@ -79,6 +80,7 @@ function applyEditionPayload(data) {
|
||||
editionState = {
|
||||
tier: ed.tier === "community" ? "community" : "pro",
|
||||
readOnlyClients: Boolean(ed.readOnlyClients),
|
||||
allowDeleteClients: Boolean(ed.allowDeleteClients),
|
||||
upgradeUrl: typeof ed.upgradeUrl === "string" ? ed.upgradeUrl : null,
|
||||
upgradePitch: typeof ed.upgradePitch === "string" ? ed.upgradePitch : null,
|
||||
showDebugWg: ed.showDebugWg !== false,
|
||||
@@ -95,7 +97,7 @@ function applyEditionPayload(data) {
|
||||
if (subEl) {
|
||||
if (editionState.tier === "community") {
|
||||
subEl.textContent =
|
||||
"Базовая панель amnezia_web: только просмотр клиентов AmneziaWG и статусов. Управление туннелем, экспорт .conf, каскад, Cloudflare WARP и синхронизация времени хоста — в версии PRO.";
|
||||
"Базовая панель amnezia_web: просмотр клиентов и статусов, а также удаление клиента с сервера. Включение/выключение туннеля, даты, переименование, экспорт .conf, каскад, Cloudflare WARP и синхронизация времени хоста — в версии PRO.";
|
||||
} else {
|
||||
subEl.textContent = DEFAULT_HEADER_SUB;
|
||||
}
|
||||
@@ -109,7 +111,7 @@ function applyEditionPayload(data) {
|
||||
const textCol = document.createElement("div");
|
||||
textCol.className = "edition-banner-text";
|
||||
const strong = document.createElement("strong");
|
||||
strong.textContent = "Базовая версия · только просмотр";
|
||||
strong.textContent = "Базовая версия · просмотр и удаление клиентов";
|
||||
const pitch = document.createElement("p");
|
||||
pitch.className = "edition-banner-pitch muted";
|
||||
pitch.textContent = editionState.upgradePitch || "";
|
||||
@@ -823,10 +825,20 @@ function renderRows(clients) {
|
||||
actTd.className = "actions";
|
||||
|
||||
if (editionState.readOnlyClients) {
|
||||
if (editionState.allowDeleteClients) {
|
||||
const note = document.createElement("div");
|
||||
note.className = "muted";
|
||||
note.style.fontSize = "0.85rem";
|
||||
note.style.marginBottom = "0.35rem";
|
||||
note.textContent = "Вкл/выкл, даты, переименование, экспорт — PRO";
|
||||
actTd.appendChild(note);
|
||||
actTd.appendChild(btn("Удалить", "btn small warn", () => confirmDelete(c.name, c.clientId)));
|
||||
} else {
|
||||
const lock = document.createElement("span");
|
||||
lock.className = "muted";
|
||||
lock.textContent = "Только PRO";
|
||||
actTd.appendChild(lock);
|
||||
}
|
||||
} else {
|
||||
if (c.activeInConf) {
|
||||
actTd.appendChild(btn("Выключить", "btn small ghost", () => openDisableDialog(c)));
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
<a href="https://t.me/lot_andrey" target="_blank" rel="noopener noreferrer">✉️ Telegram @lot_andrey</a>
|
||||
</div>
|
||||
<p class="support-blurb">
|
||||
Открытая базовая сборка — только просмотр клиентов. Полная панель PRO (приватный репозиторий) и доступ по подписке — см. Boosty и плашку в интерфейсе после входа.
|
||||
Открытая базовая сборка — просмотр клиентов и удаление записи с сервера. Полная панель PRO (приватный репозиторий) и доступ по подписке — см. Boosty и плашку в интерфейсе после входа.
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
||||
@@ -52,12 +52,14 @@ const COMMUNITY_UPGRADE_URL =
|
||||
"https://boosty.to/andrey27/purchase/3906453?ssource=DIRECT&share=subscription_link";
|
||||
const COMMUNITY_UPGRADE_PITCH =
|
||||
process.env.COMMUNITY_UPGRADE_PITCH?.trim() ||
|
||||
"В PRO: вкл/выкл клиентов, даты и расписание отключений, переименование, удаление, экспорт .conf, каскад, Cloudflare WARP, синхронизация времени хоста. Полная сборка — приватный репозиторий amnezia_web-PRO; доступ по подписке Boosty.";
|
||||
"В PRO: вкл/выкл клиентов, даты и расписание отключений, переименование, экспорт .conf, каскад, Cloudflare WARP, синхронизация времени хоста. В FREE можно удалять клиента с сервера (peer и строка в таблице). Полная сборка — приватный репозиторий amnezia_web-PRO; доступ по подписке Boosty.";
|
||||
|
||||
function editionPayload() {
|
||||
return {
|
||||
tier: IS_COMMUNITY ? "community" : "pro",
|
||||
readOnlyClients: IS_COMMUNITY,
|
||||
/** В FREE разрешено удаление записи клиента (остальные мутации — PRO). */
|
||||
allowDeleteClients: IS_COMMUNITY,
|
||||
upgradeUrl: IS_COMMUNITY ? COMMUNITY_UPGRADE_URL : null,
|
||||
upgradePitch: IS_COMMUNITY ? COMMUNITY_UPGRADE_PITCH : null,
|
||||
showDebugWg: !IS_COMMUNITY,
|
||||
@@ -1388,7 +1390,7 @@ if (UI_HIDDEN.users || UI_HIDDEN.warp || UI_HIDDEN.cascade) {
|
||||
);
|
||||
}
|
||||
if (IS_COMMUNITY) {
|
||||
console.warn(`Редакция community (только просмотр клиентов). PRO: ${COMMUNITY_UPGRADE_URL}`);
|
||||
console.warn(`Редакция community (просмотр клиентов и удаление). Остальное — PRO: ${COMMUNITY_UPGRADE_URL}`);
|
||||
}
|
||||
if (ALLOW_COMMUNITY_GITHUB_ACTIVATION && IS_COMMUNITY) {
|
||||
console.warn(
|
||||
@@ -2227,7 +2229,7 @@ app.post("/api/clients/rename", requireAuth, requireProTier, async (req, res) =>
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/api/clients/delete", requireAuth, requireProTier, async (req, res) => {
|
||||
app.post("/api/clients/delete", requireAuth, async (req, res) => {
|
||||
const rt = runtimeForRequest(req);
|
||||
const clientId = req.body?.clientId;
|
||||
if (!clientId) return res.status(400).json({ error: "clientId required" });
|
||||
|
||||
Reference in New Issue
Block a user