From cb5fca3d0feba457b3e68b74601c247fb4675bb0 Mon Sep 17 00:00:00 2001 From: andrey271192 <76248502+andrey271192@users.noreply.github.com> Date: Sun, 21 Jun 2026 19:00:51 +0300 Subject: [PATCH] fix: load clients for selected profile --- docs/panel-guide.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- public/app.js | 22 ++++++++++++++++------ server.js | 12 ++++++------ 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/docs/panel-guide.md b/docs/panel-guide.md index 48fd0fe..bc7f5c0 100644 --- a/docs/panel-guide.md +++ b/docs/panel-guide.md @@ -34,6 +34,8 @@ Если проверка на сервере показывает два разных контейнера, например `amnezia-awg2` и `amnezia-awg`, с разными портами и разным числом клиентов — это не дубль, а два инстанса. Начиная с **v1.2.33** карточки используют реальное имя профиля (`label`), чтобы `AmneziaWG 2.0` и `AmneziaWG` не выглядели одинаково. +Если переключатель **«Инстанс»** показывает правильный контейнер, но таблица **«Пользователи»** остаётся от другого инстанса, обновите до **v1.2.34**. Клиентские запросы (`/api/clients` и операции над пользователями) теперь всегда передают явный `profileId`, а не полагаются только на cookie выбранного профиля. + ## Лендинг не поднимается (порт 80 занят) При ошибке bind `:80` используйте при установке **`SKIP_LANDING=1`** или **`LANDING_PORT=8081`** — админка на `HOST_PORT` (например 8080) от этого не зависит. diff --git a/package-lock.json b/package-lock.json index 9e218e5..4cb57ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "amnezia-admin", - "version": "1.2.33", + "version": "1.2.34", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "amnezia-admin", - "version": "1.2.33", + "version": "1.2.34", "license": "MIT", "dependencies": { "express": "^4.21.2" diff --git a/package.json b/package.json index 140faf3..4827b48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "amnezia-admin", - "version": "1.2.33", + "version": "1.2.34", "private": false, "description": "amnezia_web-PRO — веб-панель AmneziaWG: несколько инстансов, WARP, каскад/Endpoint, экспорт .conf (Docker)", "license": "MIT", diff --git a/public/app.js b/public/app.js index df20fa3..8176379 100644 --- a/public/app.js +++ b/public/app.js @@ -434,18 +434,18 @@ dtOk.addEventListener("click", async () => { setStatus("Выполняю…", false); await api("/api/clients/disable", { method: "POST", - body: JSON.stringify({ clientId: dtClient.clientId, disconnectedAt: iso }), + body: JSON.stringify(withCurrentProfile({ clientId: dtClient.clientId, disconnectedAt: iso })), }); } else { const scheduleTunnel = Boolean(dtScheduleTunnel.checked && dtClient.activeInConf); setStatus(scheduleTunnel ? "Сохраняю расписание отключения…" : "Сохраняю дату…", false); await api("/api/clients/disconnect-date", { method: "POST", - body: JSON.stringify({ + body: JSON.stringify(withCurrentProfile({ clientId: dtClient.clientId, disconnectedAt: iso, scheduleTunnelDisconnect: scheduleTunnel, - }), + })), }); } dtDialog.close(); @@ -1247,6 +1247,16 @@ function currentProfileQuerySuffix() { return pid ? `&profileId=${encodeURIComponent(pid)}` : ""; } +function currentProfileQueryString() { + const pid = currentProfileIdValue(); + return pid ? `?profileId=${encodeURIComponent(pid)}` : ""; +} + +function withCurrentProfile(body = {}) { + const pid = currentProfileIdValue(); + return pid ? { ...body, profileId: pid } : body; +} + /** Прямая GET-ссылка на скачивание (работает в браузере с активной сессией панели). */ function clientExportGetUrl(clientId) { const q = `clientId=${encodeURIComponent(clientId)}${currentProfileQuerySuffix()}`; @@ -1576,7 +1586,7 @@ async function renameClient(c) { setStatus("Сохраняю имя…", false); await api("/api/clients/rename", { method: "POST", - body: JSON.stringify({ clientId: c.clientId, name: trimmed }), + body: JSON.stringify(withCurrentProfile({ clientId: c.clientId, name: trimmed })), }); setStatus("Готово.", false); await loadClients(); @@ -1588,7 +1598,7 @@ async function renameClient(c) { async function mutate(path, clientId) { try { setStatus("Выполняю…", false); - await api(path, { method: "POST", body: JSON.stringify({ clientId }) }); + await api(path, { method: "POST", body: JSON.stringify(withCurrentProfile({ clientId })) }); setStatus("Готово.", false); await loadClients(); } catch (e) { @@ -1607,7 +1617,7 @@ async function confirmDelete(name, clientId) { async function loadClients() { try { setStatus("Загрузка…", false); - const data = await api("/api/clients"); + const data = await api(`/api/clients${currentProfileQueryString()}`); applyEditionPayload(data); applyUiHiddenFromPayload(data); const pref = data.profileLabel ? `${data.profileLabel} · ` : ""; diff --git a/server.js b/server.js index 7d765d7..41f0ac5 100644 --- a/server.js +++ b/server.js @@ -2229,7 +2229,7 @@ app.post("/api/protocol", requireAuth, (req, res) => { }); app.get("/api/clients", requireAuth, async (req, res) => { - const rt = runtimeForRequest(req); + const rt = runtimeFromExportRequest(req); try { let wgShow = ""; try { @@ -2701,7 +2701,7 @@ app.post("/api/warp/routing", requireAuth, requireProTier, async (req, res) => { }); app.post("/api/clients/disable", requireAuth, requireProTier, async (req, res) => { - const rt = runtimeForRequest(req); + const rt = runtimeFromExportRequest(req); const clientId = req.body?.clientId; if (!clientId) return res.status(400).json({ error: "clientId required" }); let ts; @@ -2724,7 +2724,7 @@ app.post("/api/clients/disable", requireAuth, requireProTier, async (req, res) = }); app.post("/api/clients/enable", requireAuth, requireProTier, async (req, res) => { - const rt = runtimeForRequest(req); + const rt = runtimeFromExportRequest(req); const clientId = req.body?.clientId; if (!clientId) return res.status(400).json({ error: "clientId required" }); try { @@ -2774,7 +2774,7 @@ AllowedIPs = ${ips}`; }); app.post("/api/clients/disconnect-date", requireAuth, requireProTier, async (req, res) => { - const rt = runtimeForRequest(req); + const rt = runtimeFromExportRequest(req); const clientId = req.body?.clientId; if (!clientId) return res.status(400).json({ error: "clientId required" }); let iso; @@ -2814,7 +2814,7 @@ app.post("/api/clients/disconnect-date", requireAuth, requireProTier, async (req }); app.post("/api/clients/rename", requireAuth, requireProTier, async (req, res) => { - const rt = runtimeForRequest(req); + const rt = runtimeFromExportRequest(req); const clientId = req.body?.clientId; const rawName = req.body?.name ?? req.body?.clientName; if (!clientId) return res.status(400).json({ error: "clientId required" }); @@ -2841,7 +2841,7 @@ app.post("/api/clients/rename", requireAuth, requireProTier, async (req, res) => }); app.post("/api/clients/delete", requireAuth, requireProTier, async (req, res) => { - const rt = runtimeForRequest(req); + const rt = runtimeFromExportRequest(req); const clientId = req.body?.clientId; if (!clientId) return res.status(400).json({ error: "clientId required" }); try {