Autarch Will Control The Internet
This commit is contained in:
256
web/routes/wireguard.py
Normal file
256
web/routes/wireguard.py
Normal file
@@ -0,0 +1,256 @@
|
||||
"""WireGuard VPN Manager routes — server, clients, remote ADB, USB/IP."""
|
||||
|
||||
from flask import Blueprint, render_template, request, jsonify, Response
|
||||
from web.auth import login_required
|
||||
|
||||
wireguard_bp = Blueprint('wireguard', __name__, url_prefix='/wireguard')
|
||||
|
||||
|
||||
def _mgr():
|
||||
from core.wireguard import get_wireguard_manager
|
||||
return get_wireguard_manager()
|
||||
|
||||
|
||||
def _json():
|
||||
"""Get JSON body or empty dict."""
|
||||
return request.get_json(silent=True) or {}
|
||||
|
||||
|
||||
# ── Main Page ────────────────────────────────────────────────────────
|
||||
|
||||
@wireguard_bp.route('/')
|
||||
@login_required
|
||||
def index():
|
||||
mgr = _mgr()
|
||||
available = mgr.is_available()
|
||||
usbip = mgr.get_usbip_status()
|
||||
return render_template('wireguard.html',
|
||||
wg_available=available,
|
||||
usbip_status=usbip)
|
||||
|
||||
|
||||
# ── Server ───────────────────────────────────────────────────────────
|
||||
|
||||
@wireguard_bp.route('/server/status', methods=['POST'])
|
||||
@login_required
|
||||
def server_status():
|
||||
return jsonify(_mgr().get_server_status())
|
||||
|
||||
|
||||
@wireguard_bp.route('/server/start', methods=['POST'])
|
||||
@login_required
|
||||
def server_start():
|
||||
return jsonify(_mgr().start_interface())
|
||||
|
||||
|
||||
@wireguard_bp.route('/server/stop', methods=['POST'])
|
||||
@login_required
|
||||
def server_stop():
|
||||
return jsonify(_mgr().stop_interface())
|
||||
|
||||
|
||||
@wireguard_bp.route('/server/restart', methods=['POST'])
|
||||
@login_required
|
||||
def server_restart():
|
||||
return jsonify(_mgr().restart_interface())
|
||||
|
||||
|
||||
# ── Clients ──────────────────────────────────────────────────────────
|
||||
|
||||
@wireguard_bp.route('/clients/list', methods=['POST'])
|
||||
@login_required
|
||||
def clients_list():
|
||||
mgr = _mgr()
|
||||
clients = mgr.get_all_clients()
|
||||
peer_status = mgr.get_peer_status()
|
||||
# Merge peer status into client data
|
||||
for c in clients:
|
||||
ps = peer_status.get(c.get('public_key', ''), {})
|
||||
c['peer_status'] = ps
|
||||
hs = ps.get('latest_handshake')
|
||||
if hs is not None and hs < 180:
|
||||
c['online'] = True
|
||||
else:
|
||||
c['online'] = False
|
||||
return jsonify({'clients': clients, 'count': len(clients)})
|
||||
|
||||
|
||||
@wireguard_bp.route('/clients/create', methods=['POST'])
|
||||
@login_required
|
||||
def clients_create():
|
||||
data = _json()
|
||||
name = data.get('name', '').strip()
|
||||
if not name:
|
||||
return jsonify({'ok': False, 'error': 'Name required'})
|
||||
dns = data.get('dns', '').strip() or None
|
||||
allowed_ips = data.get('allowed_ips', '').strip() or None
|
||||
return jsonify(_mgr().create_client(name, dns=dns, allowed_ips=allowed_ips))
|
||||
|
||||
|
||||
@wireguard_bp.route('/clients/<client_id>', methods=['POST'])
|
||||
@login_required
|
||||
def clients_detail(client_id):
|
||||
mgr = _mgr()
|
||||
client = mgr.get_client(client_id)
|
||||
if not client:
|
||||
return jsonify({'error': 'Client not found'})
|
||||
peer_status = mgr.get_peer_status()
|
||||
ps = peer_status.get(client.get('public_key', ''), {})
|
||||
client['peer_status'] = ps
|
||||
hs = ps.get('latest_handshake')
|
||||
client['online'] = hs is not None and hs < 180
|
||||
return jsonify(client)
|
||||
|
||||
|
||||
@wireguard_bp.route('/clients/<client_id>/toggle', methods=['POST'])
|
||||
@login_required
|
||||
def clients_toggle(client_id):
|
||||
data = _json()
|
||||
enabled = data.get('enabled', True)
|
||||
return jsonify(_mgr().toggle_client(client_id, enabled))
|
||||
|
||||
|
||||
@wireguard_bp.route('/clients/<client_id>/delete', methods=['POST'])
|
||||
@login_required
|
||||
def clients_delete(client_id):
|
||||
return jsonify(_mgr().delete_client(client_id))
|
||||
|
||||
|
||||
@wireguard_bp.route('/clients/<client_id>/config', methods=['POST'])
|
||||
@login_required
|
||||
def clients_config(client_id):
|
||||
mgr = _mgr()
|
||||
client = mgr.get_client(client_id)
|
||||
if not client:
|
||||
return jsonify({'error': 'Client not found'})
|
||||
config_text = mgr.generate_client_config(client)
|
||||
return jsonify({'ok': True, 'config': config_text, 'name': client['name']})
|
||||
|
||||
|
||||
@wireguard_bp.route('/clients/<client_id>/download')
|
||||
@login_required
|
||||
def clients_download(client_id):
|
||||
mgr = _mgr()
|
||||
client = mgr.get_client(client_id)
|
||||
if not client:
|
||||
return 'Not found', 404
|
||||
config_text = mgr.generate_client_config(client)
|
||||
filename = f"{client['name']}.conf"
|
||||
return Response(
|
||||
config_text,
|
||||
mimetype='text/plain',
|
||||
headers={'Content-Disposition': f'attachment; filename="{filename}"'})
|
||||
|
||||
|
||||
@wireguard_bp.route('/clients/<client_id>/qr')
|
||||
@login_required
|
||||
def clients_qr(client_id):
|
||||
mgr = _mgr()
|
||||
client = mgr.get_client(client_id)
|
||||
if not client:
|
||||
return 'Not found', 404
|
||||
config_text = mgr.generate_client_config(client)
|
||||
png_bytes = mgr.generate_qr_code(config_text)
|
||||
if not png_bytes:
|
||||
return 'QR code generation failed (qrcode module missing?)', 500
|
||||
return Response(png_bytes, mimetype='image/png')
|
||||
|
||||
|
||||
@wireguard_bp.route('/clients/import', methods=['POST'])
|
||||
@login_required
|
||||
def clients_import():
|
||||
return jsonify(_mgr().import_existing_peers())
|
||||
|
||||
|
||||
# ── Remote ADB ───────────────────────────────────────────────────────
|
||||
|
||||
@wireguard_bp.route('/adb/connect', methods=['POST'])
|
||||
@login_required
|
||||
def adb_connect():
|
||||
data = _json()
|
||||
ip = data.get('ip', '').strip()
|
||||
if not ip:
|
||||
return jsonify({'ok': False, 'error': 'IP required'})
|
||||
return jsonify(_mgr().adb_connect(ip))
|
||||
|
||||
|
||||
@wireguard_bp.route('/adb/disconnect', methods=['POST'])
|
||||
@login_required
|
||||
def adb_disconnect():
|
||||
data = _json()
|
||||
ip = data.get('ip', '').strip()
|
||||
if not ip:
|
||||
return jsonify({'ok': False, 'error': 'IP required'})
|
||||
return jsonify(_mgr().adb_disconnect(ip))
|
||||
|
||||
|
||||
@wireguard_bp.route('/adb/auto-connect', methods=['POST'])
|
||||
@login_required
|
||||
def adb_auto_connect():
|
||||
return jsonify(_mgr().auto_connect_peers())
|
||||
|
||||
|
||||
@wireguard_bp.route('/adb/devices', methods=['POST'])
|
||||
@login_required
|
||||
def adb_devices():
|
||||
devices = _mgr().get_adb_remote_devices()
|
||||
return jsonify({'devices': devices, 'count': len(devices)})
|
||||
|
||||
|
||||
# ── USB/IP ───────────────────────────────────────────────────────────
|
||||
|
||||
@wireguard_bp.route('/usbip/status', methods=['POST'])
|
||||
@login_required
|
||||
def usbip_status():
|
||||
return jsonify(_mgr().get_usbip_status())
|
||||
|
||||
|
||||
@wireguard_bp.route('/usbip/load-modules', methods=['POST'])
|
||||
@login_required
|
||||
def usbip_load_modules():
|
||||
return jsonify(_mgr().load_usbip_modules())
|
||||
|
||||
|
||||
@wireguard_bp.route('/usbip/list-remote', methods=['POST'])
|
||||
@login_required
|
||||
def usbip_list_remote():
|
||||
data = _json()
|
||||
ip = data.get('ip', '').strip()
|
||||
if not ip:
|
||||
return jsonify({'ok': False, 'error': 'IP required'})
|
||||
return jsonify(_mgr().usbip_list_remote(ip))
|
||||
|
||||
|
||||
@wireguard_bp.route('/usbip/attach', methods=['POST'])
|
||||
@login_required
|
||||
def usbip_attach():
|
||||
data = _json()
|
||||
ip = data.get('ip', '').strip()
|
||||
busid = data.get('busid', '').strip()
|
||||
if not ip or not busid:
|
||||
return jsonify({'ok': False, 'error': 'IP and busid required'})
|
||||
return jsonify(_mgr().usbip_attach(ip, busid))
|
||||
|
||||
|
||||
@wireguard_bp.route('/usbip/detach', methods=['POST'])
|
||||
@login_required
|
||||
def usbip_detach():
|
||||
data = _json()
|
||||
port = data.get('port', '').strip() if isinstance(data.get('port'), str) else str(data.get('port', ''))
|
||||
if not port:
|
||||
return jsonify({'ok': False, 'error': 'Port required'})
|
||||
return jsonify(_mgr().usbip_detach(port))
|
||||
|
||||
|
||||
@wireguard_bp.route('/usbip/ports', methods=['POST'])
|
||||
@login_required
|
||||
def usbip_ports():
|
||||
return jsonify(_mgr().usbip_port_status())
|
||||
|
||||
|
||||
# ── UPnP ─────────────────────────────────────────────────────────────
|
||||
|
||||
@wireguard_bp.route('/upnp/refresh', methods=['POST'])
|
||||
@login_required
|
||||
def upnp_refresh():
|
||||
return jsonify(_mgr().refresh_upnp_mapping())
|
||||
Reference in New Issue
Block a user