Add isolated WireGuard module with guarded access modes and server setup
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
/* Settings form stays mounted while status polling updates only status elements. */
|
||||
let networkBusy=false, networkState=null;
|
||||
async function networkRequest(action,body={}){
|
||||
const response=await fetch('/api/v1/network'+(action?'/'+action:''),{method:action?'POST':'GET',headers:action?{'Content-Type':'application/json','X-Athena-Deck':'1'}:{},body:action?JSON.stringify(body):undefined,signal:AbortSignal.timeout(40000)});
|
||||
const value=await response.json();if(!response.ok)throw Error(value.error||'Netzwerkaktion fehlgeschlagen.');return value;
|
||||
}
|
||||
async function networkAction(action,body={}){
|
||||
if(networkBusy)return;networkBusy=true;networkButtons();
|
||||
const output=document.querySelector('#network-message');output.textContent='Wird ausgeführt …';
|
||||
try{await networkRequest(action,body);output.textContent=action==='import'?'Konfiguration geprüft und geschützt auf Athena gespeichert.':action==='install'?'Installation läuft. Der Status aktualisiert sich automatisch.':'Einstellung übernommen.';}
|
||||
catch(e){output.textContent=e.message;}
|
||||
finally{networkBusy=false;await networkPage();}
|
||||
}
|
||||
function networkButtons(){
|
||||
if(!networkState)return;
|
||||
const s=networkState;
|
||||
document.querySelectorAll('#network-page button').forEach(b=>b.disabled=networkBusy||s.state==='installing');
|
||||
const set=(id,disabled)=>{const b=document.getElementById(id);if(b)b.disabled=b.disabled||disabled;};
|
||||
set('network-install',s.installed);
|
||||
set('network-import',!s.installed||s.enabled||s.mode!=='lan'||!!s.pending);
|
||||
set('network-connect',!s.configured||s.enabled);
|
||||
set('network-disconnect',!s.enabled);
|
||||
set('network-delete',!s.configured||s.enabled||s.mode!=='lan'||!!s.pending);
|
||||
set('network-apply',!s.installed||!!s.pending);
|
||||
const needed=s.pending?.target==='lan'?'lan':'tunnel';
|
||||
set('network-confirm',!s.pending||s.ingress!==needed);
|
||||
set('network-cancel',!s.pending);
|
||||
}
|
||||
async function networkPage(){
|
||||
const view=document.querySelector('#view');
|
||||
if(!document.querySelector('#network-page')){
|
||||
view.innerHTML=`<div id="network-page"><div class="kicker">EINSTELLUNGEN / NETZWERK</div><h1>Dein Weg zu Athena.</h1><p>Ein eigener WireGuard-Zugang für Athena Deck und seine internen API-Endpunkte.</p><section class="card network-card"><div class="card-top"><h2>WireGuard-Modul</h2><span id="network-state" class="pill">Wird geprüft …</span></div><div id="network-details" class="network-status"></div><p id="network-notice"></p><div id="network-setup"><h2>Auf Athena einrichten</h2><p>Installiert WireGuard und Deck in einem eigenen Container. Der vorhandene Gateway bleibt unverändert. Die erste Einrichtung startet im LAN-Modus auf Port 8110.</p><label for="network-password">Neues Deck-Passwort · mindestens 16 Zeichen</label><input id="network-password" type="password" autocomplete="new-password" minlength="16" maxlength="256"><button id="network-install">Modul auf Athena installieren</button><p class="note">Benötigt den vorhandenen SSH-Zugang und Docker auf Athena. LAN-Zugriff verwendet HTTP; für vertrauliche Eingaben WireGuard oder SSH-Tunnel verwenden.</p></div><div id="network-config" hidden><label for="network-file">Eigene WireGuard-Konfiguration (.conf)</label><input id="network-file" type="file" accept=".conf,text/plain"><p>Verwende einen eigenen Peer für Deck. Schlüssel werden nicht angezeigt. Ein Peer und IPv4 werden unterstützt; Shell-Hooks werden abgelehnt.</p><button id="network-import">Konfiguration importieren</button><button id="network-delete" class="secondary">Konfiguration löschen</button><div class="note"><button id="network-connect">WireGuard aktivieren</button><button id="network-disconnect" class="secondary">WireGuard deaktivieren</button><p>Aktivieren richtet den Tunnel ein. „Verbunden“ erscheint erst nach einem aktuellen Handshake.</p></div></div></section><section class="card network-card" id="network-access"><h2>Zugriff auf Deck und API</h2><label for="network-mode">Erreichbarkeit</label><select id="network-mode"><option value="lan">Nur lokales Netzwerk</option><option value="tunnel">Nur WireGuard-Tunnel</option><option value="both">Tunnel und lokales Netzwerk</option></select><button id="network-apply">Zugriffsmodus testen</button><p id="network-current"></p><div id="network-trial" hidden><p id="network-countdown" class="warning"></p><button id="network-confirm">Zugriff hier bestätigen</button><button id="network-cancel" class="secondary">Änderung zurücknehmen</button><p>Öffne die angezeigte Zieladresse und bestätige dort innerhalb von 120 Sekunden. Ohne Bestätigung wird der vorige Modus wiederhergestellt.</p></div><p class="note">Der lokale Mac-Zugang per SSH bleibt als Verwaltungskanal erhalten. Produktionsendpunkte werden nicht umgestellt. Im Modus „Nur Tunnel“ gibt es bei Tunnelausfall keinen LAN-Fallback.</p></section><p id="network-message" class="network-message" role="status" aria-live="polite"></p></div>`;
|
||||
document.querySelector('#network-install').onclick=()=>{const input=document.querySelector('#network-password'),password=input.value;input.value='';networkAction('install',{password});};
|
||||
document.querySelector('#network-import').onclick=async()=>{const input=document.querySelector('#network-file'),file=input.files[0];if(!file){document.querySelector('#network-message').textContent='Bitte zuerst eine .conf-Datei auswählen.';return}if(file.size>16384){document.querySelector('#network-message').textContent='Die Datei darf höchstens 16 KiB groß sein.';return}const config=await file.text();input.value='';await networkAction('import',{config});};
|
||||
for(const action of ['connect','disconnect','delete','cancel'])document.querySelector('#network-'+action).onclick=()=>networkAction(action);
|
||||
document.querySelector('#network-apply').onclick=()=>networkAction('mode',{mode:document.querySelector('#network-mode').value});
|
||||
document.querySelector('#network-confirm').onclick=()=>networkAction('confirm',{trial_id:networkState?.pending?.id});
|
||||
}
|
||||
try{
|
||||
const s=await networkRequest('');if(!document.querySelector('#network-page'))return;networkState=s;
|
||||
const labels={unavailable:'Nicht bereit',installing:'Installation läuft',disabled:'Deaktiviert',connecting:'Warte auf Handshake',connected:'Verbunden'};
|
||||
document.querySelector('#network-state').textContent=labels[s.state]||'Nicht verfügbar';
|
||||
const details=document.querySelector('#network-details');details.replaceChildren();
|
||||
for(const [label,value] of [['Konfiguration',s.configured?'Gespeichert':'Keine'],['Letzter Handshake',s.latest_handshake?new Date(s.latest_handshake*1000).toLocaleString('de-DE'):'Noch keiner'],['Dieser Zugang',s.ingress==='management'?'Mac / SSH-Verwaltung':s.ingress==='tunnel'?'WireGuard-Tunnel':'LAN']]){const d=document.createElement('div'),small=document.createElement('small'),strong=document.createElement('strong');small.textContent=label;strong.textContent=value;d.append(small,strong);details.append(d);}
|
||||
for(const [label,url] of [['LAN',s.lan_url],['Tunnel',s.tunnel_url]])if(url){const d=document.createElement('div'),a=document.createElement('a');a.href=url+'/#network';a.textContent=label+': '+url;a.target='_blank';a.rel='noopener';d.append(a);details.append(d);}
|
||||
document.querySelector('#network-setup').hidden=!!s.installed;
|
||||
document.querySelector('#network-config').hidden=false;
|
||||
document.querySelector('#network-file').disabled=!s.installed||s.enabled||networkBusy;
|
||||
document.querySelector('#network-access').hidden=false;
|
||||
document.querySelector('#network-mode').disabled=!s.installed||!!s.pending||networkBusy;
|
||||
document.querySelector('#network-notice').textContent=[s.error,s.job?.message,...(s.warnings||[])].filter(Boolean).join(' ');
|
||||
document.querySelector('#network-current').textContent='Aktuell: '+({lan:'Nur lokales Netzwerk',tunnel:'Nur WireGuard-Tunnel',both:'Tunnel und LAN'}[s.mode]||'Noch nicht eingerichtet');
|
||||
document.querySelector('#network-trial').hidden=!s.pending;
|
||||
if(s.pending)document.querySelector('#network-countdown').textContent=`Test aktiv · ${s.pending.seconds_remaining} Sekunden bis zur automatischen Rücknahme. Bestätigung nötig über ${s.pending.target==='lan'?'LAN':'WireGuard'}.`;
|
||||
networkButtons();
|
||||
}catch(e){if(document.querySelector('#network-message'))document.querySelector('#network-message').textContent=e.message;}
|
||||
}
|
||||
Reference in New Issue
Block a user