fix: load clients for selected profile

This commit is contained in:
andrey271192
2026-06-21 19:00:51 +03:00
parent a9a67afb54
commit cb5fca3d0f
5 changed files with 27 additions and 15 deletions

View File

@@ -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) от этого не зависит.

4
package-lock.json generated
View File

@@ -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"

View File

@@ -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",

View File

@@ -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} · ` : "";

View File

@@ -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 {