mirror of
https://github.com/andrey271192/amnezia_web-PRO.git
synced 2026-09-20 14:42:00 +00:00
feat: direct client creation + auto-detect AWG container
Add "Новый клиент" (direct) flow alongside cascade: - server.js: POST /api/clients/create — Endpoint = this server's public IP:ListenPort (CLIENT_CONFIG_ENDPOINT or request host), reuses the same key/peer/conf pipeline as create-cascade. - public/index.html: "Новый клиент" panel with #direct-form (name + optional tunnel IP). - public/app.js: downloadDirectConf() handler + form binding. install.sh hardening so fresh installs work out of the box: - Auto-detect a single amnezia-awg* container (e.g. amnezia-awg2, Amnezia AWG 2.0 default) -> AWG_CONTAINER, instead of the fixed "amnezia-awg" default that mismatched and blocked client ops. - Auto-default CLIENT_CONFIG_ENDPOINT to the host primary IP so direct .conf exports get a correct Endpoint without manual env. Fixes "cannot create users" on servers whose WG container is named amnezia-awg2.
This commit is contained in:
@@ -651,6 +651,11 @@ if (cascadeForm) {
|
||||
cascadeForm.addEventListener("submit", (ev) => void downloadCascadeConf(ev));
|
||||
}
|
||||
|
||||
const directForm = document.querySelector("#direct-form");
|
||||
if (directForm) {
|
||||
directForm.addEventListener("submit", (ev) => void downloadDirectConf(ev));
|
||||
}
|
||||
|
||||
protoSelect.addEventListener("change", async () => {
|
||||
try {
|
||||
setStatus("Смена инстанса…", false);
|
||||
@@ -1349,6 +1354,58 @@ async function downloadCascadeConf(ev) {
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadDirectConf(ev) {
|
||||
ev.preventDefault();
|
||||
const nameEl = document.querySelector("#direct-name");
|
||||
const tunnelEl = document.querySelector("#direct-tunnel-ip");
|
||||
const body = {};
|
||||
const nm = nameEl?.value.trim();
|
||||
if (nm) body.clientName = nm;
|
||||
const tip = tunnelEl?.value.trim();
|
||||
if (tip) body.tunnelIp = tip;
|
||||
const pid = currentProfileIdValue();
|
||||
if (pid) body.profileId = pid;
|
||||
try {
|
||||
setStatus("Создаю клиента на сервере и собираю .conf…", false);
|
||||
const res = await fetch("/api/clients/create", {
|
||||
method: "POST",
|
||||
credentials: "same-origin",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const text = await res.text();
|
||||
if (!res.ok) {
|
||||
let msg = text;
|
||||
try {
|
||||
const j = JSON.parse(text);
|
||||
msg = typeof j.error === "string" ? j.error : msg;
|
||||
} catch {
|
||||
/* raw */
|
||||
}
|
||||
throw new Error(msg);
|
||||
}
|
||||
const blob = new Blob([text], { type: "text/plain;charset=utf-8" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
const safe = (nm || "client")
|
||||
.replace(/[^\w\u0400-\u04FF\-]+/g, "_")
|
||||
.slice(0, 60);
|
||||
a.href = url;
|
||||
a.download = `amnezia-${safe}.conf`;
|
||||
a.rel = "noopener";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
if (nameEl) nameEl.value = "";
|
||||
if (tunnelEl) tunnelEl.value = "";
|
||||
setStatus("Клиент добавлен на сервер, .conf скачан. Обновите таблицу.", false);
|
||||
await loadClients();
|
||||
} catch (e) {
|
||||
setStatus(String(e.message || e), true);
|
||||
}
|
||||
}
|
||||
|
||||
async function renameClient(c) {
|
||||
const next = prompt(`Новое имя для «${c.name}»:`, c.name);
|
||||
if (next === null) return;
|
||||
|
||||
Reference in New Issue
Block a user