Add isolated WireGuard module with guarded access modes and server setup

This commit is contained in:
Mikei386
2026-09-28 14:50:02 +02:00
parent b7b2506272
commit e86e540ae4
21 changed files with 1278 additions and 8 deletions
+94
View File
@@ -0,0 +1,94 @@
"""Local management via fixed SSH target or container-private Unix RPC."""
import base64
import hashlib
import json
import os
from pathlib import Path
import secrets
import subprocess
import threading
import time
ROOT = Path(__file__).resolve().parent.parent
SSH = ['ssh', '-i', str(Path.home()/'.ssh/athena_key'), '-o', 'BatchMode=yes', '-o', 'ConnectTimeout=5', '-o', 'StrictHostKeyChecking=yes', 'root@192.168.1.212']
class NetworkClient:
def __init__(self):
self.local = os.environ.get('DECK_NETWORK_SOCKET') == '1'
self.job = None
self.lock = threading.Lock()
self.cached = None
self.cached_at = 0
def call(self, action, values=None, ingress='management'):
data = dict(values or {}, action=action)
if self.local:
from network.rpc import request
data.update(ingress=ingress, proxy_token=os.environ.get('DECK_PROXY_TOKEN', ''))
return request(data)
result = subprocess.run(SSH + ['docker exec -i athena-deck-network python3 -m network.rpc'], input=json.dumps(data), text=True, capture_output=True, timeout=35)
try:
value = json.loads(result.stdout)
except ValueError:
raise ValueError('Deck-Netzwerkmodul auf Athena nicht erreichbar oder noch nicht installiert.') from None
if result.returncode or ('error' in value and 'installed' not in value):
raise ValueError(value.get('error', 'Netzwerkaktion fehlgeschlagen.'))
self.cached = None
return value
def status(self, ingress='management'):
with self.lock:
if self.job and self.job['state'] == 'running':
return dict(installed=False, state='installing', job=self.job.copy(), ingress=ingress)
if self.cached is not None and time.monotonic()-self.cached_at < 3:
return dict(self.cached, ingress=ingress, job=self.job)
try:
result = self.call('status', ingress=ingress)
result['reachable'] = True
except (ValueError, OSError, subprocess.SubprocessError):
result = dict(installed=False, reachable=False, state='unavailable', error='Netzwerkmodul noch nicht installiert oder Athena nicht erreichbar.')
self.cached = result
self.cached_at = time.monotonic()
return dict(result, ingress=ingress, job=self.job)
def install(self, password):
if self.local:
raise ValueError('Die Server-Instanz ist bereits installiert.')
if not isinstance(password, str) or not 16 <= len(password) <= 256:
raise ValueError('Bitte ein eigenes Deck-Passwort mit mindestens 16 Zeichen setzen.')
with self.lock:
if self.job and self.job['state'] == 'running':
raise ValueError('Installation läuft bereits.')
salt = secrets.token_bytes(16)
auth = dict(salt=salt.hex(), hash=hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 600000).hex())
self.job = dict(state='running', message='Eigener Deck-Container wird gebaut und gestartet. Das kann mehrere Minuten dauern.')
threading.Thread(target=self._install, args=(auth,), daemon=True).start()
return dict(job=self.job.copy())
def _install(self, auth):
try:
# Import the source allowlist without executing the installer entrypoint.
from network.install_remote import FILES
payload = dict(auth=auth, files={name:base64.b64encode((ROOT/name).read_bytes()).decode() for name in FILES})
script = (ROOT/'network/install_remote.py').read_text()
# Remote command contains only fixed trusted program text, never user input.
import shlex
command = 'python3 -c ' + shlex.quote(script)
result = subprocess.run(SSH+[command], input=json.dumps(payload), text=True, capture_output=True, timeout=900)
value = json.loads(result.stdout)
if result.returncode or ('error' in value and 'installed' not in value):
raise ValueError(value.get('error', 'Installation fehlgeschlagen.'))
# Confirm helper readiness; don't report a successful installation from docker run alone.
for _ in range(20):
try:
self.call('status')
break
except (ValueError, OSError, subprocess.SubprocessError):
time.sleep(1)
else:
raise ValueError('Container angelegt, aber Netzwerk-Helper nicht bereit. Installation prüfen.')
self.job = dict(state='complete', message='Netzwerkmodul installiert. Jetzt eine eigene WireGuard-Konfiguration importieren.')
except Exception as exc:
self.job = dict(state='failed', message=str(exc) if isinstance(exc, ValueError) and not isinstance(exc, json.JSONDecodeError) else 'Installation fehlgeschlagen; SSH und Docker prüfen.')
finally:
self.cached = None