mirror of
https://github.com/andrey271192/amnezia_web-PRO.git
synced 2026-09-20 14:42:00 +00:00
fix: load clients for selected profile
This commit is contained in:
@@ -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
4
package-lock.json
generated
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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} · ` : "";
|
||||
|
||||
12
server.js
12
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 {
|
||||
|
||||
Reference in New Issue
Block a user