feat: кнопка «Скачать .conf» в модале WireGuard конфига

Добавлена кнопка «⬇ Скачать .conf» рядом с «Копировать».
Имя файла: wg0-server.conf для VPS, hydravpn-{name}.conf для роутера.
Hint роутера обновлён: «Загрузить из файла» вместо «Вставить из буфера».
This commit is contained in:
Андрей Бобырев
2026-04-28 20:06:29 +03:00
parent 1f55b09e09
commit b41e5c7dc8

View File

@@ -267,8 +267,9 @@ input[type=text]:focus,input[type=password]:focus{border-color:var(--accent)}
<button onclick="document.getElementById('wg-cfg-modal').style.display='none'" style="position:absolute;top:14px;right:16px;background:none;border:none;color:var(--muted);font-size:20px;cursor:pointer"></button> <button onclick="document.getElementById('wg-cfg-modal').style.display='none'" style="position:absolute;top:14px;right:16px;background:none;border:none;color:var(--muted);font-size:20px;cursor:pointer"></button>
<h2 style="font-size:15px;font-weight:700;margin-bottom:12px" id="wg-cfg-title">WireGuard конфиг</h2> <h2 style="font-size:15px;font-weight:700;margin-bottom:12px" id="wg-cfg-title">WireGuard конфиг</h2>
<textarea id="wg-cfg-text" readonly style="width:100%;min-height:260px;background:var(--card2);border:1px solid var(--border);border-radius:10px;padding:12px;font-size:11px;font-family:monospace;color:var(--text);resize:vertical;outline:none"></textarea> <textarea id="wg-cfg-text" readonly style="width:100%;min-height:260px;background:var(--card2);border:1px solid var(--border);border-radius:10px;padding:12px;font-size:11px;font-family:monospace;color:var(--text);resize:vertical;outline:none"></textarea>
<div style="display:flex;gap:8px;margin-top:12px"> <div style="display:flex;gap:8px;margin-top:12px;flex-wrap:wrap">
<button class="btn btn-b" onclick="copyWgCfg()">📋 Копировать</button> <button class="btn btn-b" onclick="copyWgCfg()">📋 Копировать</button>
<button class="btn btn-b" onclick="downloadWgCfg()" style="background:#2563eb">⬇ Скачать .conf</button>
<button class="btn btn-ghost" onclick="document.getElementById('wg-cfg-modal').style.display='none'">✓ Закрыть</button> <button class="btn btn-ghost" onclick="document.getElementById('wg-cfg-modal').style.display='none'">✓ Закрыть</button>
</div> </div>
<div id="wg-cfg-hint" style="margin-top:10px;font-size:11px;color:var(--muted)"></div> <div id="wg-cfg-hint" style="margin-top:10px;font-size:11px;color:var(--muted)"></div>
@@ -648,10 +649,13 @@ async function wgDeploy(name){
} catch(e){ log.textContent += '\nОшибка: '+e; } } catch(e){ log.textContent += '\nОшибка: '+e; }
} }
let _wgCfgFilename = 'wg0.conf';
async function wgShowServerConfig(){ async function wgShowServerConfig(){
try { try {
const r = await fetch('/api/wireguard/server-config', {headers: authHdr()}); const r = await fetch('/api/wireguard/server-config', {headers: authHdr()});
const text = await r.text(); const text = await r.text();
_wgCfgFilename = 'wg0-server.conf';
document.getElementById('wg-cfg-title').textContent = 'wg0.conf — конфиг VPS сервера'; document.getElementById('wg-cfg-title').textContent = 'wg0.conf — конфиг VPS сервера';
document.getElementById('wg-cfg-text').value = text; document.getElementById('wg-cfg-text').value = text;
document.getElementById('wg-cfg-hint').textContent = 'Этот файл лежит на VPS в /etc/wireguard/wg0.conf'; document.getElementById('wg-cfg-hint').textContent = 'Этот файл лежит на VPS в /etc/wireguard/wg0.conf';
@@ -663,9 +667,10 @@ async function wgShowRouterConfig(name){
try { try {
const r = await fetch(`/api/routers/${encodeURIComponent(name)}/wireguard-config`, {headers: authHdr()}); const r = await fetch(`/api/routers/${encodeURIComponent(name)}/wireguard-config`, {headers: authHdr()});
const text = await r.text(); const text = await r.text();
_wgCfgFilename = `hydravpn-${name}.conf`;
document.getElementById('wg-cfg-title').textContent = `wg0.conf — конфиг роутера «${name}»`; document.getElementById('wg-cfg-title').textContent = `wg0.conf — конфиг роутера «${name}»`;
document.getElementById('wg-cfg-text').value = text; document.getElementById('wg-cfg-text').value = text;
document.getElementById('wg-cfg-hint').textContent = 'Можно вручную добавить в Keenetic: Интернет → WireGuard → Добавить подключение → Вставить из буфера'; document.getElementById('wg-cfg-hint').textContent = 'Keenetic: Интернет → WireGuard → Загрузить из файла';
document.getElementById('wg-cfg-modal').style.display = 'flex'; document.getElementById('wg-cfg-modal').style.display = 'flex';
} catch(e){ alert('Ошибка: '+e); } } catch(e){ alert('Ошибка: '+e); }
} }
@@ -676,6 +681,16 @@ function copyWgCfg(){
else { document.getElementById('wg-cfg-text').select(); document.execCommand('copy'); } else { document.getElementById('wg-cfg-text').select(); document.execCommand('copy'); }
} }
function downloadWgCfg(){
const text = document.getElementById('wg-cfg-text').value;
const blob = new Blob([text], {type: 'text/plain'});
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = _wgCfgFilename;
a.click();
URL.revokeObjectURL(a.href);
}
// ── SETTINGS ────────────────────────────────────────────────────────────── // ── SETTINGS ──────────────────────────────────────────────────────────────
async function changePwd(){ const p1=document.getElementById('new-pwd').value; const p2=document.getElementById('new-pwd2').value; if(p1!==p2){sm('pwd-msg','err','❌ Пароли не совпадают');return;} if(p1.length<4){sm('pwd-msg','err','❌ Минимум 4 символа');return;} try{ const r=await fetch('/api/set_password',{method:'POST',headers:authHdr(),body:JSON.stringify({password:p1})}); if(r.ok){ sessionStorage.setItem('hm_pass',p1); sm('pwd-msg','ok','✅ Пароль сохранён'); document.getElementById('new-pwd').value=''; document.getElementById('new-pwd2').value=''; } }catch(e){sm('pwd-msg','err','❌ '+e)} } async function changePwd(){ const p1=document.getElementById('new-pwd').value; const p2=document.getElementById('new-pwd2').value; if(p1!==p2){sm('pwd-msg','err','❌ Пароли не совпадают');return;} if(p1.length<4){sm('pwd-msg','err','❌ Минимум 4 символа');return;} try{ const r=await fetch('/api/set_password',{method:'POST',headers:authHdr(),body:JSON.stringify({password:p1})}); if(r.ok){ sessionStorage.setItem('hm_pass',p1); sm('pwd-msg','ok','✅ Пароль сохранён'); document.getElementById('new-pwd').value=''; document.getElementById('new-pwd2').value=''; } }catch(e){sm('pwd-msg','err','❌ '+e)} }