Compare commits

..

6 Commits

Author SHA1 Message Date
Donald Zou
ca8700ac2a Update PeerJobs.py 2025-09-22 22:50:59 +08:00
Donald Zou
10a8d22efd Merge pull request #922 from WGDashboard/docker-duplicate-hotfix
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
2025-09-22 17:53:34 +08:00
Donald Zou
fc3ec61373 Merge pull request #923 from WGDashboard/remove-docker-funcs
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-09-22 05:46:38 +08:00
Daan Selen
094d1c0718 refac: remove docker functions 2025-09-21 22:04:59 +02:00
Daan Selen
0d814ec03c refac: new logic to detecting a Wireguard interface 2025-09-21 21:57:28 +02:00
dependabot[bot]
5ccfe07e12 Bump npm from 10.9.3 to 11.6.0 in /src/static/app (#901)
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Bumps [npm](https://github.com/npm/cli) from 10.9.3 to 11.6.0.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v10.9.3...v11.6.0)

---
updated-dependencies:
- dependency-name: npm
  dependency-version: 11.6.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-21 17:30:31 +02:00
7 changed files with 586 additions and 792 deletions

1
.gitignore vendored
View File

@@ -19,7 +19,6 @@ node_modules/**
*/proxy.js */proxy.js
src/static/app/proxy.js src/static/app/proxy.js
.secrets .secrets
*.pid
# Logs # Logs
logs logs

View File

@@ -13,15 +13,15 @@ hash_password() {
set_ini() { set_ini() {
local section="$1" key="$2" value="$3" local section="$1" key="$2" value="$3"
local current_value local current_value
# Add section if it doesn't exist # Add section if it doesn't exist
grep -q "^\[${section}\]" "$config_file" \ grep -q "^\[${section}\]" "$config_file" \
|| printf "\n[%s]\n" "${section}" >> "$config_file" || printf "\n[%s]\n" "${section}" >> "$config_file"
# Check current value if key exists # Check current value if key exists
if grep -q "^[[:space:]]*${key}[[:space:]]*=" "$config_file"; then if grep -q "^[[:space:]]*${key}[[:space:]]*=" "$config_file"; then
current_value=$(grep "^[[:space:]]*${key}[[:space:]]*=" "$config_file" | cut -d= -f2- | xargs) current_value=$(grep "^[[:space:]]*${key}[[:space:]]*=" "$config_file" | cut -d= -f2- | xargs)
# Don't display actual value if it's a password field # Don't display actual value if it's a password field
if [[ "$key" == *"password"* ]]; then if [[ "$key" == *"password"* ]]; then
if [ "$current_value" = "$value" ]; then if [ "$current_value" = "$value" ]; then
@@ -40,7 +40,7 @@ set_ini() {
fi fi
else else
sed -i "/^\[${section}\]/a ${key} = ${value}" "$config_file" sed -i "/^\[${section}\]/a ${key} = ${value}" "$config_file"
# Don't display actual value if it's a password field # Don't display actual value if it's a password field
if [[ "$key" == *"password"* ]]; then if [[ "$key" == *"password"* ]]; then
echo "- Added new setting $key (value hidden)" echo "- Added new setting $key (value hidden)"
@@ -61,58 +61,58 @@ echo "Starting the WGDashboard Docker container."
ensure_installation() { ensure_installation() {
echo "Quick-installing..." echo "Quick-installing..."
# Make the wgd.sh script executable. # Make the wgd.sh script executable.
chmod +x "${WGDASH}"/src/wgd.sh chmod +x "${WGDASH}"/src/wgd.sh
cd "${WGDASH}"/src || exit cd "${WGDASH}"/src || exit
# Github issue: https://github.com/donaldzou/WGDashboard/issues/723 # Github issue: https://github.com/donaldzou/WGDashboard/issues/723
echo "Checking for stale pids..." echo "Checking for stale pids..."
if [[ -f ${WGDASH}/src/gunicorn.pid ]]; then if [[ -f ${WGDASH}/src/gunicorn.pid ]]; then
echo "Found stale pid, removing..." echo "Found stale pid, removing..."
rm ${WGDASH}/src/gunicorn.pid rm ${WGDASH}/src/gunicorn.pid
fi fi
# Removing clear shell command from the wgd.sh script to enhance docker logging. # Removing clear shell command from the wgd.sh script to enhance docker logging.
echo "Removing clear command from wgd.sh for better Docker logging." echo "Removing clear command from wgd.sh for better Docker logging."
sed -i '/clear/d' ./wgd.sh sed -i '/clear/d' ./wgd.sh
# Create required directories and links # Create required directories and links
if [ ! -d "/data/db" ]; then if [ ! -d "/data/db" ]; then
echo "Creating database dir" echo "Creating database dir"
mkdir -p /data/db mkdir -p /data/db
fi fi
if [ ! -d "${WGDASH}/src/db" ]; then if [ ! -d "${WGDASH}/src/db" ]; then
ln -s /data/db "${WGDASH}/src/db" ln -s /data/db "${WGDASH}/src/db"
fi fi
if [ ! -f "${config_file}" ]; then if [ ! -f "${config_file}" ]; then
echo "Creating wg-dashboard.ini file" echo "Creating wg-dashboard.ini file"
touch "${config_file}" touch "${config_file}"
fi fi
if [ ! -f "${WGDASH}/src/wg-dashboard.ini" ]; then if [ ! -f "${WGDASH}/src/wg-dashboard.ini" ]; then
ln -s "${config_file}" "${WGDASH}/src/wg-dashboard.ini" ln -s "${config_file}" "${WGDASH}/src/wg-dashboard.ini"
fi fi
# Create the Python virtual environment. # Create the Python virtual environment.
. "${WGDASH}/src/venv/bin/activate" . "${WGDASH}/src/venv/bin/activate"
# Use the bash interpreter to install WGDashboard according to the wgd.sh script. # Use the bash interpreter to install WGDashboard according to the wgd.sh script.
/bin/bash ./wgd.sh install /bin/bash ./wgd.sh install
echo "Looks like the installation succeeded. Moving on." echo "Looks like the installation succeeded. Moving on."
# Setup WireGuard if needed # Setup WireGuard if needed
if [ ! -f "/etc/wireguard/wg0.conf" ]; then if [ -z "$(ls -A /etc/wireguard)" ]; then
cp -a "/configs/wg0.conf.template" "/etc/wireguard/wg0.conf" cp -a "/configs/wg0.conf.template" "/etc/wireguard/wg0.conf"
echo "Setting a secure private key." echo "Setting a secure private key."
local privateKey local privateKey
privateKey=$(wg genkey) privateKey=$(wg genkey)
sed -i "s|^PrivateKey *=.*$|PrivateKey = ${privateKey}|g" /etc/wireguard/wg0.conf sed -i "s|^PrivateKey *=.*$|PrivateKey = ${privateKey}|g" /etc/wireguard/wg0.conf
echo "Done setting template." echo "Done setting template."
else else
echo "Existing wg0 configuration file found, using that." echo "Existing wg0 configuration file found, using that."
@@ -121,51 +121,51 @@ ensure_installation() {
set_envvars() { set_envvars() {
printf "\n------------- SETTING ENVIRONMENT VARIABLES ----------------\n" printf "\n------------- SETTING ENVIRONMENT VARIABLES ----------------\n"
# Check if config file is empty # Check if config file is empty
if [ ! -s "${config_file}" ]; then if [ ! -s "${config_file}" ]; then
echo "Config file is empty. Creating initial structure." echo "Config file is empty. Creating initial structure."
fi fi
echo "Checking basic configuration:" echo "Checking basic configuration:"
set_ini Peers peer_global_dns "${global_dns}" set_ini Peers peer_global_dns "${global_dns}"
if [ -z "${public_ip}" ]; then if [ -z "${public_ip}" ]; then
public_ip=$(curl -s ifconfig.me) public_ip=$(curl -s ifconfig.me)
echo "Automatically detected public IP: ${public_ip}" echo "Automatically detected public IP: ${public_ip}"
fi fi
set_ini Peers remote_endpoint "${public_ip}" set_ini Peers remote_endpoint "${public_ip}"
set_ini Server app_port "${wgd_port}" set_ini Server app_port "${wgd_port}"
# Account settings - process all parameters # Account settings - process all parameters
[[ -n "$username" ]] && echo "Configuring user account:" [[ -n "$username" ]] && echo "Configuring user account:"
# Basic account variables # Basic account variables
[[ -n "$username" ]] && set_ini Account username "${username}" [[ -n "$username" ]] && set_ini Account username "${username}"
if [[ -n "$password" ]]; then if [[ -n "$password" ]]; then
echo "- Setting password" echo "- Setting password"
set_ini Account password "$(hash_password "${password}")" set_ini Account password "$(hash_password "${password}")"
fi fi
# Additional account variables # Additional account variables
[[ -n "$enable_totp" ]] && set_ini Account enable_totp "${enable_totp}" [[ -n "$enable_totp" ]] && set_ini Account enable_totp "${enable_totp}"
[[ -n "$totp_verified" ]] && set_ini Account totp_verified "${totp_verified}" [[ -n "$totp_verified" ]] && set_ini Account totp_verified "${totp_verified}"
[[ -n "$totp_key" ]] && set_ini Account totp_key "${totp_key}" [[ -n "$totp_key" ]] && set_ini Account totp_key "${totp_key}"
# Welcome session # Welcome session
[[ -n "$welcome_session" ]] && set_ini Other welcome_session "${welcome_session}" [[ -n "$welcome_session" ]] && set_ini Other welcome_session "${welcome_session}"
# If username and password are set but welcome_session isn't, disable it # If username and password are set but welcome_session isn't, disable it
if [[ -n "$username" && -n "$password" && -z "$welcome_session" ]]; then if [[ -n "$username" && -n "$password" && -z "$welcome_session" ]]; then
set_ini Other welcome_session "false" set_ini Other welcome_session "false"
fi fi
# Autostart WireGuard # Autostart WireGuard
if [[ -n "$wg_autostart" ]]; then if [[ -n "$wg_autostart" ]]; then
echo "Configuring WireGuard autostart:" echo "Configuring WireGuard autostart:"
set_ini WireGuardConfiguration autostart "${wg_autostart}" set_ini WireGuardConfiguration autostart "${wg_autostart}"
fi fi
# Email (check if any settings need to be configured) # Email (check if any settings need to be configured)
email_vars=("email_server" "email_port" "email_encryption" "email_username" "email_password" "email_from" "email_template") email_vars=("email_server" "email_port" "email_encryption" "email_username" "email_password" "email_from" "email_template")
for var in "${email_vars[@]}"; do for var in "${email_vars[@]}"; do
@@ -174,12 +174,12 @@ set_envvars() {
break break
fi fi
done done
# Email (iterate through all possible fields) # Email (iterate through all possible fields)
email_fields=("server:email_server" "port:email_port" "encryption:email_encryption" email_fields=("server:email_server" "port:email_port" "encryption:email_encryption"
"username:email_username" "email_password:email_password" "username:email_username" "email_password:email_password"
"send_from:email_from" "email_template:email_template") "send_from:email_from" "email_template:email_template")
for field_pair in "${email_fields[@]}"; do for field_pair in "${email_fields[@]}"; do
IFS=: read -r field var <<< "$field_pair" IFS=: read -r field var <<< "$field_pair"
[[ -n "${!var}" ]] && set_ini Email "$field" "${!var}" [[ -n "${!var}" ]] && set_ini Email "$field" "${!var}"
@@ -189,7 +189,7 @@ set_envvars() {
# Start service and monitor logs # Start service and monitor logs
start_and_monitor() { start_and_monitor() {
printf "\n---------------------- STARTING CORE -----------------------\n" printf "\n---------------------- STARTING CORE -----------------------\n"
# Due to some instances complaining about this, making sure its there every time. # Due to some instances complaining about this, making sure its there every time.
mkdir -p /dev/net mkdir -p /dev/net
mknod /dev/net/tun c 10 200 mknod /dev/net/tun c 10 200
@@ -198,15 +198,15 @@ start_and_monitor() {
# Actually starting WGDashboard # Actually starting WGDashboard
echo "Activating Python venv and executing the WireGuard Dashboard service." echo "Activating Python venv and executing the WireGuard Dashboard service."
bash ./wgd.sh start bash ./wgd.sh start
# Wait a second before continuing, to give the python program some time to get ready. # Wait a second before continuing, to give the python program some time to get ready.
sleep 1 sleep 1
echo -e "\nEnsuring container continuation." echo -e "\nEnsuring container continuation."
# Find and monitor log file # Find and monitor log file
local logdir="${WGDASH}/src/log" local logdir="${WGDASH}/src/log"
latestErrLog=$(find "$logdir" -name "error_*.log" -type f -print | sort -r | head -n 1) latestErrLog=$(find "$logdir" -name "error_*.log" -type f -print | sort -r | head -n 1)
# Only tail the logs if they are found # Only tail the logs if they are found
if [ -n "$latestErrLog" ]; then if [ -n "$latestErrLog" ]; then
tail -f "$latestErrLog" & tail -f "$latestErrLog" &
@@ -221,4 +221,4 @@ start_and_monitor() {
# Main execution flow # Main execution flow
ensure_installation ensure_installation
set_envvars set_envvars
start_and_monitor start_and_monitor

View File

@@ -1,45 +1,27 @@
# --- Standard library imports ---
import configparser
import hashlib
import ipaddress
import json
import logging import logging
import os import random, shutil, sqlite3, configparser, hashlib, ipaddress, json, os, secrets, subprocess
import random import time, re, uuid, bcrypt, psutil, pyotp, threading
import re
import secrets
import shutil
import sqlite3
import subprocess
import threading
import time
import traceback import traceback
import uuid
from datetime import datetime, timedelta
from itertools import islice
from uuid import uuid4 from uuid import uuid4
from zipfile import ZipFile from zipfile import ZipFile
from datetime import datetime, timedelta
# --- Third-party imports ---
import bcrypt
import psutil
import pyotp
import sqlalchemy import sqlalchemy
from flask import Flask, request, render_template, session, send_file, Response
from flask_cors import CORS
from flask.json.provider import DefaultJSONProvider
from icmplib import ping, traceroute
from jinja2 import Template from jinja2 import Template
from packaging import version from flask import Flask, request, render_template, session, send_file
from flask_cors import CORS
from icmplib import ping, traceroute
from flask.json.provider import DefaultJSONProvider
from itertools import islice
from sqlalchemy import RowMapping from sqlalchemy import RowMapping
# --- Local module imports ---
from client import createClientBlueprint
from modules.Utilities import ( from modules.Utilities import (
RegexMatch, StringToBoolean, RegexMatch, StringToBoolean,
ValidateIPAddressesWithRange, ValidateDNSAddress, ValidateIPAddressesWithRange, ValidateDNSAddress,
GenerateWireguardPublicKey, GenerateWireguardPrivateKey GenerateWireguardPublicKey, GenerateWireguardPrivateKey
) )
from packaging import version
from modules.Email import EmailSender from modules.Email import EmailSender
from modules.DashboardLogger import DashboardLogger from modules.DashboardLogger import DashboardLogger
from modules.PeerJob import PeerJob from modules.PeerJob import PeerJob
@@ -49,15 +31,16 @@ from modules.PeerJobs import PeerJobs
from modules.DashboardConfig import DashboardConfig from modules.DashboardConfig import DashboardConfig
from modules.WireguardConfiguration import WireguardConfiguration from modules.WireguardConfiguration import WireguardConfiguration
from modules.AmneziaWireguardConfiguration import AmneziaWireguardConfiguration from modules.AmneziaWireguardConfiguration import AmneziaWireguardConfiguration
from client import createClientBlueprint
from logging.config import dictConfig
from modules.DashboardClients import DashboardClients from modules.DashboardClients import DashboardClients
from modules.DashboardPlugins import DashboardPlugins from modules.DashboardPlugins import DashboardPlugins
from modules.DashboardWebHooks import DashboardWebHooks from modules.DashboardWebHooks import DashboardWebHooks
from modules.NewConfigurationTemplates import NewConfigurationTemplates from modules.NewConfigurationTemplates import NewConfigurationTemplates
# --- Logging configuration ---
from logging.config import dictConfig
class CustomJsonEncoder(DefaultJSONProvider): class CustomJsonEncoder(DefaultJSONProvider):
def __init__(self, app): def __init__(self, app):
super().__init__(app) super().__init__(app)
@@ -72,6 +55,7 @@ class CustomJsonEncoder(DefaultJSONProvider):
return super().default(self) return super().default(self)
''' '''
Response Object Response Object
''' '''
@@ -211,12 +195,12 @@ with app.app_context():
EmailSender = EmailSender(DashboardConfig) EmailSender = EmailSender(DashboardConfig)
AllPeerShareLinks: PeerShareLinks = PeerShareLinks(DashboardConfig, WireguardConfigurations) AllPeerShareLinks: PeerShareLinks = PeerShareLinks(DashboardConfig, WireguardConfigurations)
AllPeerJobs: PeerJobs = PeerJobs(DashboardConfig, WireguardConfigurations) AllPeerJobs: PeerJobs = PeerJobs(DashboardConfig, WireguardConfigurations)
DashboardLogger = DashboardLogger() DashboardLogger: DashboardLogger = DashboardLogger()
DashboardPlugins = DashboardPlugins(app, WireguardConfigurations) DashboardPlugins: DashboardPlugins = DashboardPlugins(app, WireguardConfigurations)
DashboardWebHooks = DashboardWebHooks(DashboardConfig) DashboardWebHooks: DashboardWebHooks = DashboardWebHooks(DashboardConfig)
NewConfigurationTemplates = NewConfigurationTemplates() NewConfigurationTemplates: NewConfigurationTemplates = NewConfigurationTemplates()
InitWireguardConfigurationsList(startup=True) InitWireguardConfigurationsList(startup=True)
DashboardClients = DashboardClients(WireguardConfigurations) DashboardClients: DashboardClients = DashboardClients(WireguardConfigurations)
app.register_blueprint(createClientBlueprint(WireguardConfigurations, DashboardConfig, DashboardClients)) app.register_blueprint(createClientBlueprint(WireguardConfigurations, DashboardConfig, DashboardClients))
_, APP_PREFIX = DashboardConfig.GetConfig("Server", "app_prefix") _, APP_PREFIX = DashboardConfig.GetConfig("Server", "app_prefix")
@@ -229,103 +213,32 @@ _, app_ip = DashboardConfig.GetConfig("Server", "app_ip")
_, app_port = DashboardConfig.GetConfig("Server", "app_port") _, app_port = DashboardConfig.GetConfig("Server", "app_port")
_, WG_CONF_PATH = DashboardConfig.GetConfig("Server", "wg_conf_path") _, WG_CONF_PATH = DashboardConfig.GetConfig("Server", "wg_conf_path")
''' '''
API Routes API Routes
''' '''
def _enforce_session_auth():
"""Enforce session authentication for non-API key access."""
white_list = [
'/static/',
'validateAuthentication',
'authenticate',
'getDashboardConfiguration',
'getDashboardTheme',
'getDashboardVersion',
'sharePeer/get',
'isTotpEnabled',
'locale',
'/fileDownload',
'/client'
]
path_ok = (
("username" in session and session.get("role") == "admin")
or (f"{APP_PREFIX}/" == request.path or f"{APP_PREFIX}" == request.path)
or not all(sub not in request.path for sub in white_list)
)
if not path_ok:
response = Flask.make_response(app, {
"status": False,
"message": "Unauthorized access.",
"data": None
})
response.content_type = "application/json"
response.status_code = 401
return response
def _login_with_token(key):
auth_token = hashlib.sha256(f"{key}{datetime.now()}".encode()).hexdigest()
session.update({'role': 'admin', 'username': auth_token})
session.permanent = True
resp = ResponseObject(True, DashboardConfig.GetConfig("Other", "welcome_session")[1])
resp.set_cookie("authToken", auth_token)
return resp
def _login_with_credentials(data):
username = data.get('username')
password = data.get('password')
totp_code = data.get('totp')
valid_password = bcrypt.checkpw(password.encode("utf-8"),
DashboardConfig.GetConfig("Account", "password")[1].encode("utf-8"))
totp_enabled = DashboardConfig.GetConfig("Account", "enable_totp")[1]
totp_valid = pyotp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).now() == totp_code if totp_enabled else True
if username == DashboardConfig.GetConfig("Account", "username")[1] and valid_password and totp_valid:
auth_token = hashlib.sha256(f"{username}{datetime.now()}".encode()).hexdigest()
session.update({'role': 'admin', 'username': auth_token})
session.permanent = True
DashboardLogger.log(str(request.url), str(request.remote_addr), Message=f"Login success: {username}")
resp = ResponseObject(True, DashboardConfig.GetConfig("Other", "welcome_session")[1])
resp.set_cookie("authToken", auth_token)
return resp
DashboardLogger.log(str(request.url), str(request.remote_addr), Message=f"Login failed: {username}")
msg = "Sorry, your username, password or OTP is incorrect." if totp_enabled else "Sorry, your username or password is incorrect."
return ResponseObject(False, msg)
@app.before_request @app.before_request
def auth_req(): def auth_req():
# Skip preflight requests
if request.method.lower() == 'options': if request.method.lower() == 'options':
return ResponseObject(True) return ResponseObject(True)
DashboardConfig.APIAccessed = False DashboardConfig.APIAccessed = False
# Logging
if "api" in request.path: if "api" in request.path:
log_message = str(request.args) if request.method.upper() == "GET" else f"Request Args: {str(request.args)} Body:{str(request.get_json())}" if str(request.method) == "GET":
DashboardLogger.log(str(request.url), str(request.remote_addr), Message=log_message) DashboardLogger.log(str(request.url), str(request.remote_addr), Message=str(request.args))
elif str(request.method) == "POST":
authentication_required = DashboardConfig.GetConfig("Server", "auth_req")[1] DashboardLogger.log(str(request.url), str(request.remote_addr), Message=f"Request Args: {str(request.args)} Body:{str(request.get_json())}")
headers = request.headers
if authentication_required: authenticationRequired = DashboardConfig.GetConfig("Server", "auth_req")[1]
api_key = headers.get('wg-dashboard-apikey') d = request.headers
api_key_enabled = DashboardConfig.GetConfig("Server", "dashboard_api_key")[1] if authenticationRequired:
apiKey = d.get('wg-dashboard-apikey')
# API key authentication apiKeyEnabled = DashboardConfig.GetConfig("Server", "dashboard_api_key")[1]
if api_key and api_key_enabled: if apiKey is not None and len(apiKey) > 0 and apiKeyEnabled:
api_key_exists = any(k.Key == api_key for k in DashboardConfig.DashboardAPIKeys) apiKeyExist = len(list(filter(lambda x : x.Key == apiKey, DashboardConfig.DashboardAPIKeys))) == 1
DashboardLogger.log(str(request.url), str(request.remote_addr), Message=f"API Key Access: {api_key_exists} - Key: {api_key}") DashboardLogger.log(str(request.url), str(request.remote_addr), Message=f"API Key Access: {('true' if apiKeyExist else 'false')} - Key: {apiKey}")
if not apiKeyExist:
if not api_key_exists:
DashboardConfig.APIAccessed = False DashboardConfig.APIAccessed = False
response = Flask.make_response(app, { response = Flask.make_response(app, {
"status": False, "status": False,
@@ -335,49 +248,84 @@ def auth_req():
response.content_type = "application/json" response.content_type = "application/json"
response.status_code = 401 response.status_code = 401
return response return response
DashboardConfig.APIAccessed = True DashboardConfig.APIAccessed = True
else: else:
DashboardConfig.APIAccessed = False DashboardConfig.APIAccessed = False
_enforce_session_auth() whiteList = [
'/static/', 'validateAuthentication', 'authenticate', 'getDashboardConfiguration',
'getDashboardTheme', 'getDashboardVersion', 'sharePeer/get', 'isTotpEnabled', 'locale',
'/fileDownload',
'/client'
]
if (("username" not in session or session.get("role") != "admin")
and (f"{(APP_PREFIX if len(APP_PREFIX) > 0 else '')}/" != request.path
and f"{(APP_PREFIX if len(APP_PREFIX) > 0 else '')}" != request.path)
and len(list(filter(lambda x : x not in request.path, whiteList))) == len(whiteList)
):
response = Flask.make_response(app, {
"status": False,
"message": "Unauthorized access.",
"data": None
})
response.content_type = "application/json"
response.status_code = 401
return response
@app.route(f'{APP_PREFIX}/api/handshake', methods=["GET", "OPTIONS"]) @app.route(f'{APP_PREFIX}/api/handshake', methods=["GET", "OPTIONS"])
def API_Handshake(): def API_Handshake():
return ResponseObject(True) return ResponseObject(True)
@app.get(f'{APP_PREFIX}/api/validateAuthentication') @app.get(f'{APP_PREFIX}/api/validateAuthentication')
def API_ValidateAuthentication(): def API_ValidateAuthentication():
token = request.cookies.get("authToken") token = request.cookies.get("authToken")
auth_required = DashboardConfig.GetConfig("Server", "auth_req")[1] if DashboardConfig.GetConfig("Server", "auth_req")[1]:
if token is None or token == "" or "username" not in session or session["username"] != token:
if auth_required and (not token or "username" not in session or session["username"] != token): return ResponseObject(False, "Invalid authentication.")
return ResponseObject(False, "Invalid authentication.",
status_code=401)
return ResponseObject(True) return ResponseObject(True)
@app.get(f'{APP_PREFIX}/api/requireAuthentication') @app.get(f'{APP_PREFIX}/api/requireAuthentication')
def API_RequireAuthentication(): def API_RequireAuthentication():
return ResponseObject(data=DashboardConfig.GetConfig("Server", "auth_req")[1]) return ResponseObject(data=DashboardConfig.GetConfig("Server", "auth_req")[1])
@app.post(f'{APP_PREFIX}/api/authenticate') @app.post(f'{APP_PREFIX}/api/authenticate')
def API_AuthenticateLogin(): def API_AuthenticateLogin():
data = request.get_json() data = request.get_json()
auth_req = DashboardConfig.GetConfig("Server", "auth_req")[1] if not DashboardConfig.GetConfig("Server", "auth_req")[1]:
if not auth_req:
return ResponseObject(True, DashboardConfig.GetConfig("Other", "welcome_session")[1]) return ResponseObject(True, DashboardConfig.GetConfig("Other", "welcome_session")[1])
# API key login
if DashboardConfig.APIAccessed: if DashboardConfig.APIAccessed:
return _login_with_token(request.headers.get('wg-dashboard-apikey')) authToken = hashlib.sha256(f"{request.headers.get('wg-dashboard-apikey')}{datetime.now()}".encode()).hexdigest()
session['role'] = 'admin'
session['username'] = authToken
resp = ResponseObject(True, DashboardConfig.GetConfig("Other", "welcome_session")[1])
resp.set_cookie("authToken", authToken)
session.permanent = True
return resp
valid = bcrypt.checkpw(data['password'].encode("utf-8"),
DashboardConfig.GetConfig("Account", "password")[1].encode("utf-8"))
totpEnabled = DashboardConfig.GetConfig("Account", "enable_totp")[1]
totpValid = False
if totpEnabled:
totpValid = pyotp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).now() == data['totp']
# User login if (valid
return _login_with_credentials(data) and data['username'] == DashboardConfig.GetConfig("Account", "username")[1]
and ((totpEnabled and totpValid) or not totpEnabled)
):
authToken = hashlib.sha256(f"{data['username']}{datetime.now()}".encode()).hexdigest()
session['role'] = 'admin'
session['username'] = authToken
resp = ResponseObject(True, DashboardConfig.GetConfig("Other", "welcome_session")[1])
resp.set_cookie("authToken", authToken)
session.permanent = True
DashboardLogger.log(str(request.url), str(request.remote_addr), Message=f"Login success: {data['username']}")
return resp
DashboardLogger.log(str(request.url), str(request.remote_addr), Message=f"Login failed: {data['username']}")
if totpEnabled:
return ResponseObject(False, "Sorry, your username, password or OTP is incorrect.")
else:
return ResponseObject(False, "Sorry, your username or password is incorrect.")
@app.get(f'{APP_PREFIX}/api/signout') @app.get(f'{APP_PREFIX}/api/signout')
def API_SignOut(): def API_SignOut():
@@ -389,7 +337,7 @@ def API_SignOut():
@app.get(f'{APP_PREFIX}/api/getWireguardConfigurations') @app.get(f'{APP_PREFIX}/api/getWireguardConfigurations')
def API_getWireguardConfigurations(): def API_getWireguardConfigurations():
InitWireguardConfigurationsList() InitWireguardConfigurationsList()
return ResponseObject(data=list(WireguardConfigurations.values())) return ResponseObject(data=[wc for wc in WireguardConfigurations.values()])
@app.get(f'{APP_PREFIX}/api/newConfigurationTemplates') @app.get(f'{APP_PREFIX}/api/newConfigurationTemplates')
def API_NewConfigurationTemplates(): def API_NewConfigurationTemplates():
@@ -402,255 +350,193 @@ def API_NewConfigurationTemplates_CreateTemplate():
@app.post(f'{APP_PREFIX}/api/newConfigurationTemplates/updateTemplate') @app.post(f'{APP_PREFIX}/api/newConfigurationTemplates/updateTemplate')
def API_NewConfigurationTemplates_UpdateTemplate(): def API_NewConfigurationTemplates_UpdateTemplate():
data = request.get_json() data = request.get_json()
template = data.get('Template') template = data.get('Template', None)
if not template: if not template:
return ResponseObject(False, "Please provide template", return ResponseObject(False, "Please provide template")
status_code=400)
status, msg = NewConfigurationTemplates.UpdateTemplate(template) status, msg = NewConfigurationTemplates.UpdateTemplate(template)
return ResponseObject(status, msg) return ResponseObject(status, msg)
@app.post(f'{APP_PREFIX}/api/newConfigurationTemplates/deleteTemplate') @app.post(f'{APP_PREFIX}/api/newConfigurationTemplates/deleteTemplate')
def API_NewConfigurationTemplates_DeleteTemplate(): def API_NewConfigurationTemplates_DeleteTemplate():
data = request.get_json() data = request.get_json()
template = data.get('Template') template = data.get('Template', None)
if not template: if not template:
return ResponseObject(False, "Please provide template", return ResponseObject(False, "Please provide template")
status_code=400)
status, msg = NewConfigurationTemplates.DeleteTemplate(template) status, msg = NewConfigurationTemplates.DeleteTemplate(template)
return ResponseObject(status, msg) return ResponseObject(status, msg)
@app.post(f'{APP_PREFIX}/api/addWireguardConfiguration') @app.post(f'{APP_PREFIX}/api/addWireguardConfiguration')
def API_addWireguardConfiguration(): def API_addWireguardConfiguration():
data = request.get_json() data = request.get_json()
protocol = data.get("Protocol") requiredKeys = [
"ConfigurationName", "Address", "ListenPort", "PrivateKey", "Protocol"
]
for i in requiredKeys:
if i not in data.keys():
return ResponseObject(False, "Please provide all required parameters.")
if data.get("Protocol") not in ProtocolsEnabled():
return ResponseObject(False, "Please provide a valid protocol: wg / awg.")
required_keys = {"ConfigurationName", "Address", "ListenPort", "PrivateKey", "Protocol"} # Check duplicate names, ports, address
if not required_keys.issubset(data.keys()): for i in WireguardConfigurations.values():
return ResponseObject(False, "Please provide all required parameters.", status_code=400) if i.Name == data['ConfigurationName']:
return ResponseObject(False,
f"Already have a configuration with the name \"{data['ConfigurationName']}\"",
"ConfigurationName")
if protocol not in ProtocolsEnabled(): if str(i.ListenPort) == str(data["ListenPort"]):
return ResponseObject(False, "Please provide a valid protocol: wg / awg.", status_code=400) return ResponseObject(False,
f"Already have a configuration with the port \"{data['ListenPort']}\"",
"ListenPort")
for cfg in WireguardConfigurations.values(): if i.Address == data["Address"]:
duplicates = { return ResponseObject(False,
"ConfigurationName": cfg.Name == data['ConfigurationName'], f"Already have a configuration with the address \"{data['Address']}\"",
"ListenPort": str(cfg.ListenPort) == str(data["ListenPort"]), "Address")
"Address": cfg.Address == data["Address"]
if "Backup" in data.keys():
path = {
"wg": DashboardConfig.GetConfig("Server", "wg_conf_path")[1],
"awg": DashboardConfig.GetConfig("Server", "awg_conf_path")[1]
} }
for key, is_duplicate in duplicates.items():
if is_duplicate: if (os.path.exists(os.path.join(path['wg'], 'WGDashboard_Backup', data["Backup"])) and
return ResponseObject( os.path.exists(os.path.join(path['wg'], 'WGDashboard_Backup', data["Backup"].replace('.conf', '.sql')))):
False, protocol = "wg"
f"Already have a configuration with the {key.lower()} \"{data[key]}\"", elif (os.path.exists(os.path.join(path['awg'], 'WGDashboard_Backup', data["Backup"])) and
key, os.path.exists(os.path.join(path['awg'], 'WGDashboard_Backup', data["Backup"].replace('.conf', '.sql')))):
status_code=400 protocol = "awg"
) else:
return ResponseObject(False, "Backup does not exist")
paths = {
"wg": DashboardConfig.GetConfig("Server", "wg_conf_path")[1],
"awg": DashboardConfig.GetConfig("Server", "awg_conf_path")[1]
}
if "Backup" in data:
backup_file = data["Backup"]
protocol_detected = None
for proto, base_path in paths.items():
conf_path = os.path.join(base_path, 'WGDashboard_Backup', backup_file)
sql_path = os.path.join(base_path, 'WGDashboard_Backup', backup_file.replace('.conf', '.sql'))
if os.path.exists(conf_path) and os.path.exists(sql_path):
protocol_detected = proto
break
if not protocol_detected:
return ResponseObject(False, "Backup does not exist", status_code=400)
shutil.copy( shutil.copy(
os.path.join(paths[protocol_detected], 'WGDashboard_Backup', backup_file), os.path.join(path[protocol], 'WGDashboard_Backup', data["Backup"]),
os.path.join(paths[protocol_detected], f'{data["ConfigurationName"]}.conf') os.path.join(path[protocol], f'{data["ConfigurationName"]}.conf')
) )
protocol = protocol_detected # Use backup protocol WireguardConfigurations[data['ConfigurationName']] = (
WireguardConfiguration(DashboardConfig, AllPeerJobs, AllPeerShareLinks, data=data, name=data['ConfigurationName'])) if protocol == 'wg' else (
AmneziaWireguardConfiguration(DashboardConfig, AllPeerJobs, AllPeerShareLinks, DashboardWebHooks, data=data, name=data['ConfigurationName']))
else: else:
conf_path = os.path.join(paths[protocol], f'{data["ConfigurationName"]}.conf') WireguardConfigurations[data['ConfigurationName']] = (
if not os.path.exists(conf_path): WireguardConfiguration(DashboardConfig, AllPeerJobs, AllPeerShareLinks, DashboardWebHooks, data=data)) if data.get('Protocol') == 'wg' else (
with open(conf_path, 'w') as f: AmneziaWireguardConfiguration(DashboardConfig, AllPeerJobs, AllPeerShareLinks, DashboardWebHooks, data=data))
f.write(
f"[Interface]\n"
f"Address = {data['Address']}\n"
f"ListenPort = {data['ListenPort']}\n"
f"PrivateKey = {data['PrivateKey']}\n"
)
os.chmod(conf_path, 0o600) # secure file permissions
ConfigClass = WireguardConfiguration if protocol == "wg" else AmneziaWireguardConfiguration
WireguardConfigurations[data['ConfigurationName']] = ConfigClass(
DashboardConfig, AllPeerJobs, AllPeerShareLinks, DashboardWebHooks,
data=data, name=data['ConfigurationName']
)
return ResponseObject() return ResponseObject()
@app.get(f'{APP_PREFIX}/api/toggleWireguardConfiguration') @app.get(f'{APP_PREFIX}/api/toggleWireguardConfiguration')
def API_toggleWireguardConfiguration(): def API_toggleWireguardConfiguration():
configuration_name = request.args.get('configurationName') configurationName = request.args.get('configurationName')
if configurationName is None or len(
if not configuration_name or configuration_name not in WireguardConfigurations: configurationName) == 0 or configurationName not in WireguardConfigurations.keys():
return ResponseObject(False, "Please provide a valid configuration name", return ResponseObject(False, "Please provide a valid configuration name", status_code=404)
status_code=404) toggleStatus, msg = WireguardConfigurations[configurationName].toggleConfiguration()
return ResponseObject(toggleStatus, msg, WireguardConfigurations[configurationName].Status)
target_configuration = WireguardConfigurations[configuration_name]
status, msg = target_configuration.toggleConfiguration()
configuration_status = target_configuration.Status
return ResponseObject(status, msg, configuration_status)
@app.post(f'{APP_PREFIX}/api/updateWireguardConfiguration') @app.post(f'{APP_PREFIX}/api/updateWireguardConfiguration')
def API_updateWireguardConfiguration(): def API_updateWireguardConfiguration():
data = request.get_json() or {} data = request.get_json()
requiredKeys = ["Name"]
for i in requiredKeys:
if i not in data.keys():
return ResponseObject(False, "Please provide these following field: " + ", ".join(requiredKeys))
name = data.get("Name") name = data.get("Name")
if name not in WireguardConfigurations.keys():
return ResponseObject(False, "Configuration does not exist", status_code=404)
if not name: status, msg = WireguardConfigurations[name].updateConfigurationSettings(data)
return ResponseObject(False, "Please provide the field: Name",
status_code=400)
if name not in WireguardConfigurations: return ResponseObject(status, message=msg, data=WireguardConfigurations[name])
return ResponseObject(False, "Configuration does not exist",
status_code=404)
target_configuration = WireguardConfigurations[name]
status, msg = target_configuration.updateConfigurationSettings(data)
return ResponseObject(status, msg, target_configuration)
@app.post(f'{APP_PREFIX}/api/updateWireguardConfigurationInfo') @app.post(f'{APP_PREFIX}/api/updateWireguardConfigurationInfo')
def API_updateWireguardConfigurationInfo(): def API_updateWireguardConfigurationInfo():
data = request.get_json() or {} data = request.get_json()
name = data.get('Name') name = data.get('Name')
key = data.get('Key') key = data.get('Key')
value = data.get('Value') value = data.get('Value')
if not all([data, key, name]):
if not all([name, key, value]): # Required values return ResponseObject(status=False, message="Please provide configuration name, key and value")
return ResponseObject(False, "Please provide configuration name, key, and value") if name not in WireguardConfigurations.keys():
if name not in WireguardConfigurations:
return ResponseObject(False, "Configuration does not exist", status_code=404) return ResponseObject(False, "Configuration does not exist", status_code=404)
target_configuration = WireguardConfigurations[name] status, msg, key = WireguardConfigurations[name].updateConfigurationInfo(key, value)
status, msg, key = target_configuration.updateConfigurationInfo(key, value)
return ResponseObject(status=status, message=msg, data=key)
return ResponseObject(status, msg, key)
@app.get(f'{APP_PREFIX}/api/getWireguardConfigurationRawFile') @app.get(f'{APP_PREFIX}/api/getWireguardConfigurationRawFile')
def API_getWireguardConfigurationRawFile(): def API_GetWireguardConfigurationRawFile():
configuration_name = request.args.get('configurationName') configurationName = request.args.get('configurationName')
if configurationName is None or len(
if not configuration_name or configuration_name not in WireguardConfigurations: configurationName) == 0 or configurationName not in WireguardConfigurations.keys():
return ResponseObject(False, "Please provide a valid configuration name", status_code=404) return ResponseObject(False, "Please provide a valid configuration name", status_code=404)
config = WireguardConfigurations[configuration_name]
return ResponseObject(data={ return ResponseObject(data={
"path": config.configPath, "path": WireguardConfigurations[configurationName].configPath,
"content": config.getRawConfigurationFile() "content": WireguardConfigurations[configurationName].getRawConfigurationFile()
}) })
@app.post(f'{APP_PREFIX}/api/updateWireguardConfigurationRawFile') @app.post(f'{APP_PREFIX}/api/updateWireguardConfigurationRawFile')
def API_UpdateWireguardConfigurationRawFile(): def API_UpdateWireguardConfigurationRawFile():
data = request.get_json() or {} data = request.get_json()
configuration_name = data.get('configurationName') configurationName = data.get('configurationName')
raw_configuration = data.get('rawConfiguration') rawConfiguration = data.get('rawConfiguration')
if configurationName is None or len(
if not configuration_name or configuration_name not in WireguardConfigurations: configurationName) == 0 or configurationName not in WireguardConfigurations.keys():
return ResponseObject(False, "Please provide a valid configuration name") return ResponseObject(False, "Please provide a valid configuration name")
if rawConfiguration is None or len(rawConfiguration) == 0:
if not raw_configuration:
return ResponseObject(False, "Please provide content") return ResponseObject(False, "Please provide content")
config = WireguardConfigurations[configuration_name] status, err = WireguardConfigurations[configurationName].updateRawConfigurationFile(rawConfiguration)
status, err = config.updateRawConfigurationFile(raw_configuration)
return ResponseObject(status, err) return ResponseObject(status=status, message=err)
@app.post(f'{APP_PREFIX}/api/deleteWireguardConfiguration') @app.post(f'{APP_PREFIX}/api/deleteWireguardConfiguration')
def API_deleteWireguardConfiguration(): def API_deleteWireguardConfiguration():
data = request.get_json() or {} data = request.get_json()
configuration_name = data.get("ConfigurationName") if "ConfigurationName" not in data.keys() or data.get("ConfigurationName") is None or data.get("ConfigurationName") not in WireguardConfigurations.keys():
if not configuration_name or configuration_name not in WireguardConfigurations:
return ResponseObject(False, "Please provide the configuration name you want to delete", status_code=404) return ResponseObject(False, "Please provide the configuration name you want to delete", status_code=404)
rp = WireguardConfigurations.pop(data.get("ConfigurationName"))
rp = WireguardConfigurations.pop(configuration_name)
status = rp.deleteConfiguration() status = rp.deleteConfiguration()
if not status: if not status:
WireguardConfigurations[configuration_name] = rp WireguardConfigurations[data.get("ConfigurationName")] = rp
return ResponseObject(status) return ResponseObject(status)
@app.post(f'{APP_PREFIX}/api/renameWireguardConfiguration') @app.post(f'{APP_PREFIX}/api/renameWireguardConfiguration')
def API_renameWireguardConfiguration(): def API_renameWireguardConfiguration():
data = request.get_json() or {} data = request.get_json()
keys = ["ConfigurationName", "NewConfigurationName"]
old_name = data.get("ConfigurationName") for k in keys:
new_name = data.get("NewConfigurationName") if (k not in data.keys() or data.get(k) is None or len(data.get(k)) == 0 or
(k == "ConfigurationName" and data.get(k) not in WireguardConfigurations.keys())):
if not old_name or old_name not in WireguardConfigurations: return ResponseObject(False, "Please provide the configuration name you want to rename", status_code=404)
return ResponseObject(False, "Please provide a valid configuration name to rename", status_code=404)
if not new_name: if data.get("NewConfigurationName") in WireguardConfigurations.keys():
return ResponseObject(False, "Please provide a new configuration name", status=400) return ResponseObject(False, "Configuration name already exist", status_code=400)
if new_name in WireguardConfigurations: rc = WireguardConfigurations.pop(data.get("ConfigurationName"))
return ResponseObject(False, "The configuration name already exists", status_code=400)
rc = WireguardConfigurations.pop(old_name) status, message = rc.renameConfiguration(data.get("NewConfigurationName"))
status, message = rc.renameConfiguration(new_name)
if status: if status:
if rc.Protocol == 'wg': WireguardConfigurations[data.get("NewConfigurationName")] = (WireguardConfiguration(DashboardConfig, AllPeerJobs, AllPeerShareLinks, DashboardWebHooks, data.get("NewConfigurationName")) if rc.Protocol == 'wg' else AmneziaWireguardConfiguration(DashboardConfig, AllPeerJobs, AllPeerShareLinks, DashboardWebHooks, data.get("NewConfigurationName")))
ConfigClass = WireguardConfiguration
else:
ConfigClass = AmneziaWireguardConfiguration
WireguardConfigurations[new_name] = ConfigClass(
DashboardConfig, AllPeerJobs, AllPeerShareLinks, DashboardWebHooks, new_name
)
else: else:
WireguardConfigurations[old_name] = rc WireguardConfigurations[data.get("ConfigurationName")] = rc
return ResponseObject(status, message) return ResponseObject(status, message)
@app.get(f'{APP_PREFIX}/api/getWireguardConfigurationRealtimeTraffic') @app.get(f'{APP_PREFIX}/api/getWireguardConfigurationRealtimeTraffic')
def API_getWireguardConfigurationRealtimeTraffic(): def API_getWireguardConfigurationRealtimeTraffic():
configuration_name = requests.args.get('configurationName') configurationName = request.args.get('configurationName')
if configurationName is None or configurationName not in WireguardConfigurations.keys():
if not configuration_name or configuration_name not in WireguardConfigurations:
return ResponseObject(False, "Configuration does not exist", status_code=404) return ResponseObject(False, "Configuration does not exist", status_code=404)
return ResponseObject(data=WireguardConfigurations[configurationName].getRealtimeTrafficUsage())
rt_traffic_usage = WireguardConfigurations[configuration_name]
return ResponseObject(data=rt_traffic_usage)
@app.get(f'{APP_PREFIX}/api/getWireguardConfigurationBackup') @app.get(f'{APP_PREFIX}/api/getWireguardConfigurationBackup')
def API_getWireguardConfigurationBackup(): def API_getWireguardConfigurationBackup():
configuration_name = request.args.get('configurationName') configurationName = request.args.get('configurationName')
if configurationName is None or configurationName not in WireguardConfigurations.keys():
if not configuration_name or configuration_name not in WireguardConfigurations:
return ResponseObject(False, "Configuration does not exist", status_code=404) return ResponseObject(False, "Configuration does not exist", status_code=404)
return ResponseObject(data=WireguardConfigurations[configurationName].getBackups())
target_configuration = WireguardConfigurations[configuration_name]
return ResponseObject(data=target_configuration.getBackups())
@app.get(f'{APP_PREFIX}/api/getAllWireguardConfigurationBackup') @app.get(f'{APP_PREFIX}/api/getAllWireguardConfigurationBackup')
def API_getAllWireguardConfigurationBackup(): def API_getAllWireguardConfigurationBackup():
@@ -658,86 +544,47 @@ def API_getAllWireguardConfigurationBackup():
"ExistingConfigurations": {}, "ExistingConfigurations": {},
"NonExistingConfigurations": {} "NonExistingConfigurations": {}
} }
existingConfiguration = WireguardConfigurations.keys()
existing_configurations = WireguardConfigurations.keys() for i in existingConfiguration:
b = WireguardConfigurations[i].getBackups(True)
for single_conf in existing_configurations: if len(b) > 0:
backups = WireguardConfigurations[single_conf].getBackups(True) data['ExistingConfigurations'][i] = WireguardConfigurations[i].getBackups(True)
if len(backups) > 0:
data['ExistingConfigurations'][single_conf] = WireguardConfigurations[single_conf].getBackups(True)
for protocol in ProtocolsEnabled(): for protocol in ProtocolsEnabled():
config_path_info = DashboardConfig.GetConfig("Server", f"{protocol}_conf_path") directory = os.path.join(DashboardConfig.GetConfig("Server", f"{protocol}_conf_path")[1], 'WGDashboard_Backup')
configuration_path = config_path_info[1] if os.path.exists(directory):
backup_directory = os.path.join(configuration_path, 'WGDashboard_Backup') files = [(file, os.path.getctime(os.path.join(directory, file)))
for file in os.listdir(directory) if os.path.isfile(os.path.join(directory, file))]
if not os.path.exists(backup_directory): files.sort(key=lambda x: x[1], reverse=True)
continue
for f, ct in files:
backup_files = [] if RegexMatch(r"^(.*)_(.*)\.(conf)$", f):
for file_name in os.listdir(backup_directory): s = re.search(r"^(.*)_(.*)\.(conf)$", f)
full_file_path = os.path.join(backup_directory, file_name) name = s.group(1)
if os.path.isfile(full_file_path): if name not in existingConfiguration:
creation_time = os.path.getctime(full_file_path) if name not in data['NonExistingConfigurations'].keys():
backup_files.append((file_name, creation_time)) data['NonExistingConfigurations'][name] = []
backup_files.sort(key=lambda file_info: file_info[1], reverse=True) date = s.group(2)
d = {
for file_name, creation_time in backup_files: "protocol": protocol,
pattern = r"^(.*)_(.*)\.conf$" "filename": f,
match_result = re.match(pattern, file_name) "backupDate": date,
"content": open(os.path.join(DashboardConfig.GetConfig("Server", f"{protocol}_conf_path")[1], 'WGDashboard_Backup', f), 'r').read()
if not match_result: }
continue if f.replace(".conf", ".sql") in list(os.listdir(directory)):
d['database'] = True
configuration_name = match_result.group(1) d['databaseContent'] = open(os.path.join(DashboardConfig.GetConfig("Server", f"{protocol}_conf_path")[1], 'WGDashboard_Backup', f.replace(".conf", ".sql")), 'r').read()
backup_date = match_result.group(2) data['NonExistingConfigurations'][name].append(d)
if configuration_name in existing_configurations:
continue
if 'NonExistingConfigurations' not in data:
data['NonExistingConfigurations'] = {}
if configuration_name not in data['NonExistingConfigurations']:
data['NonExistingConfigurations'][configuration_name] = []
configuration_file_path = os.path.join(backup_directory, file_name)
with open(configuration_file_path, 'r') as configuration_file:
configuration_content = configuration_file.read()
backup_data = {
"protocol": protocol,
"filename": file_name,
"backupDate": backup_date,
"content": configuration_content
}
sql_file_name = file_name.replace(".conf", ".sql")
sql_file_path = os.path.join(backup_directory, sql_file_name)
if os.path.isfile(sql_file_path):
with open(sql_file_path, 'r') as sql_file:
sql_content = sql_file.read()
backup_data["database"] = True
backup_data["databaseContent"] = sql_content
data['NonExistingConfigurations'][configuration_name].append(backup_data)
return ResponseObject(data=data) return ResponseObject(data=data)
@app.get(f'{APP_PREFIX}/api/createWireguardConfigurationBackup') @app.get(f'{APP_PREFIX}/api/createWireguardConfigurationBackup')
def API_createWireguardConfigurationBackup(): def API_createWireguardConfigurationBackup():
configuration_name = request.args.get('configurationName') configurationName = request.args.get('configurationName')
if configurationName is None or configurationName not in WireguardConfigurations.keys():
if not configuration_name or configuration_name not in WireguardConfigurations:
return ResponseObject(False, "Configuration does not exist", status_code=404) return ResponseObject(False, "Configuration does not exist", status_code=404)
return ResponseObject(status=WireguardConfigurations[configurationName].backupConfigurationFile()[0],
conf_backup_file = WireguardConfigurations[configuration_name].backupConfigurationFile()[0] data=WireguardConfigurations[configurationName].getBackups())
conf_backups = WireguardConfigurations[configuration_name].getBackups()
return ResponseObject(status=conf_backup_file,data=conf_backups)
@app.post(f'{APP_PREFIX}/api/deleteWireguardConfigurationBackup') @app.post(f'{APP_PREFIX}/api/deleteWireguardConfigurationBackup')
def API_deleteWireguardConfigurationBackup(): def API_deleteWireguardConfigurationBackup():
@@ -769,19 +616,18 @@ def API_downloadWireguardConfigurationBackup():
@app.post(f'{APP_PREFIX}/api/restoreWireguardConfigurationBackup') @app.post(f'{APP_PREFIX}/api/restoreWireguardConfigurationBackup')
def API_restoreWireguardConfigurationBackup(): def API_restoreWireguardConfigurationBackup():
data = request.get_json() data = request.get_json()
configuration_name = data['ConfigurationName']
backup_file_name = data['BackupFileName']
if ("ConfigurationName" not in data.keys() or if ("ConfigurationName" not in data.keys() or
"BackupFileName" not in data.keys() or "BackupFileName" not in data.keys() or
len(data['ConfigurationName']) == 0 or len(data['ConfigurationName']) == 0 or
len(data['BackupFileName']) == 0): len(data['BackupFileName']) == 0):
return ResponseObject(False,"Please provide ConfigurationName and BackupFileName in body", status_code=400) return ResponseObject(False,
"Please provide ConfigurationName and BackupFileName in body", status_code=400)
if configuration_name not in WireguardConfigurations.keys(): configurationName = data['ConfigurationName']
backupFileName = data['BackupFileName']
if configurationName not in WireguardConfigurations.keys():
return ResponseObject(False, "Configuration does not exist", status_code=404) return ResponseObject(False, "Configuration does not exist", status_code=404)
status = WireguardConfigurations[configuration_name].restoreBackup(backup_file_name) status = WireguardConfigurations[configurationName].restoreBackup(backupFileName)
return ResponseObject(status=status, message=(None if status else 'Restore backup failed')) return ResponseObject(status=status, message=(None if status else 'Restore backup failed'))
@app.get(f'{APP_PREFIX}/api/getDashboardConfiguration') @app.get(f'{APP_PREFIX}/api/getDashboardConfiguration')
@@ -1523,6 +1369,31 @@ def API_Welcome_Finish():
DashboardConfig.SetConfig("Other", "welcome_session", False) DashboardConfig.SetConfig("Other", "welcome_session", False)
return ResponseObject() return ResponseObject()
class Locale:
def __init__(self):
self.localePath = './static/locales/'
self.activeLanguages = {}
with open(os.path.join(f"{self.localePath}supported_locales.json"), "r") as f:
self.activeLanguages = sorted(json.loads(''.join(f.readlines())), key=lambda x : x['lang_name'])
def getLanguage(self) -> dict | None:
currentLanguage = DashboardConfig.GetConfig("Server", "dashboard_language")[1]
if currentLanguage == "en":
return None
if os.path.exists(os.path.join(f"{self.localePath}{currentLanguage}.json")):
with open(os.path.join(f"{self.localePath}{currentLanguage}.json"), "r") as f:
return dict(json.loads(''.join(f.readlines())))
else:
return None
def updateLanguage(self, lang_id):
if not os.path.exists(os.path.join(f"{self.localePath}{lang_id}.json")):
DashboardConfig.SetConfig("Server", "dashboard_language", "en-US")
else:
DashboardConfig.SetConfig("Server", "dashboard_language", lang_id)
Locale = Locale()
@app.get(f'{APP_PREFIX}/api/locale') @app.get(f'{APP_PREFIX}/api/locale')
def API_Locale_CurrentLang(): def API_Locale_CurrentLang():
return ResponseObject(data=Locale.getLanguage()) return ResponseObject(data=Locale.getLanguage())
@@ -1607,31 +1478,6 @@ def API_SystemStatus():
def API_ProtocolsEnabled(): def API_ProtocolsEnabled():
return ResponseObject(data=ProtocolsEnabled()) return ResponseObject(data=ProtocolsEnabled())
class Locale:
def __init__(self):
self.localePath = './static/locales/'
self.activeLanguages = {}
with open(os.path.join(f"{self.localePath}supported_locales.json"), "r") as f:
self.activeLanguages = sorted(json.loads(''.join(f.readlines())), key=lambda x : x['lang_name'])
def getLanguage(self) -> dict | None:
currentLanguage = DashboardConfig.GetConfig("Server", "dashboard_language")[1]
if currentLanguage == "en":
return None
if os.path.exists(os.path.join(f"{self.localePath}{currentLanguage}.json")):
with open(os.path.join(f"{self.localePath}{currentLanguage}.json"), "r") as f:
return dict(json.loads(''.join(f.readlines())))
else:
return None
def updateLanguage(self, lang_id):
if not os.path.exists(os.path.join(f"{self.localePath}{lang_id}.json")):
DashboardConfig.SetConfig("Server", "dashboard_language", "en-US")
else:
DashboardConfig.SetConfig("Server", "dashboard_language", lang_id)
Locale = Locale()
''' '''
OIDC Controller OIDC Controller
''' '''

View File

@@ -184,7 +184,7 @@ class PeerJobs:
f"Somehow can't find this peer {job.Peer} from {c.Name} failed {job.Action}ed." f"Somehow can't find this peer {job.Peer} from {c.Name} failed {job.Action}ed."
) )
else: else:
current_app.logger.warning(f"Somehow can't find this peer {job.Peer} from {c.Name} failed {job.Action}ed.") current_app.logger.warning(f"Somehow can't find this peer {job.Peer} from {job.Configuration} failed {job.Action}ed.")
self.JobLogger.log(job.JobID, False, self.JobLogger.log(job.JobID, False,
f"Somehow can't find this peer {job.Peer} from {job.Configuration} failed {job.Action}ed." f"Somehow can't find this peer {job.Peer} from {job.Configuration} failed {job.Action}ed."
) )

View File

@@ -23,7 +23,7 @@
"fuse.js": "^7.0.0", "fuse.js": "^7.0.0",
"i": "^0.3.7", "i": "^0.3.7",
"is-cidr": "^5.0.3", "is-cidr": "^5.0.3",
"npm": "^10.5.0", "npm": "^11.6.0",
"ol": "^10.2.1", "ol": "^10.2.1",
"pinia": "^3.0.3", "pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.5.0", "pinia-plugin-persistedstate": "^4.5.0",
@@ -4706,9 +4706,9 @@
} }
}, },
"node_modules/npm": { "node_modules/npm": {
"version": "10.9.3", "version": "11.6.0",
"resolved": "https://registry.npmmirror.com/npm/-/npm-10.9.3.tgz", "resolved": "https://registry.npmjs.org/npm/-/npm-11.6.0.tgz",
"integrity": "sha512-6Eh1u5Q+kIVXeA8e7l2c/HpnFFcwrkt37xDMujD5be1gloWa9p6j3Fsv3mByXXmqJHy+2cElRMML8opNT7xIJQ==", "integrity": "sha512-d/P7DbvYgYNde9Ehfeq99+13/E7E82PfZPw8uYZASr9sQ3ZhBBCA9cXSJRA1COfJ6jDLJ0K36UJnXQWhCvLXuQ==",
"bundleDependencies": [ "bundleDependencies": [
"@isaacs/string-locale-compare", "@isaacs/string-locale-compare",
"@npmcli/arborist", "@npmcli/arborist",
@@ -4739,7 +4739,6 @@
"libnpmdiff", "libnpmdiff",
"libnpmexec", "libnpmexec",
"libnpmfund", "libnpmfund",
"libnpmhook",
"libnpmorg", "libnpmorg",
"libnpmpack", "libnpmpack",
"libnpmpublish", "libnpmpublish",
@@ -4776,8 +4775,7 @@
"tiny-relative-date", "tiny-relative-date",
"treeverse", "treeverse",
"validate-npm-package-name", "validate-npm-package-name",
"which", "which"
"write-file-atomic"
], ],
"license": "Artistic-2.0", "license": "Artistic-2.0",
"workspaces": [ "workspaces": [
@@ -4789,8 +4787,8 @@
], ],
"dependencies": { "dependencies": {
"@isaacs/string-locale-compare": "^1.1.0", "@isaacs/string-locale-compare": "^1.1.0",
"@npmcli/arborist": "^8.0.1", "@npmcli/arborist": "^9.1.4",
"@npmcli/config": "^9.0.0", "@npmcli/config": "^10.4.0",
"@npmcli/fs": "^4.0.0", "@npmcli/fs": "^4.0.0",
"@npmcli/map-workspaces": "^4.0.2", "@npmcli/map-workspaces": "^4.0.2",
"@npmcli/package-json": "^6.2.0", "@npmcli/package-json": "^6.2.0",
@@ -4802,7 +4800,7 @@
"archy": "~1.0.0", "archy": "~1.0.0",
"cacache": "^19.0.1", "cacache": "^19.0.1",
"chalk": "^5.4.1", "chalk": "^5.4.1",
"ci-info": "^4.2.0", "ci-info": "^4.3.0",
"cli-columns": "^4.0.0", "cli-columns": "^4.0.0",
"fastest-levenshtein": "^1.0.16", "fastest-levenshtein": "^1.0.16",
"fs-minipass": "^3.0.3", "fs-minipass": "^3.0.3",
@@ -4810,20 +4808,19 @@
"graceful-fs": "^4.2.11", "graceful-fs": "^4.2.11",
"hosted-git-info": "^8.1.0", "hosted-git-info": "^8.1.0",
"ini": "^5.0.0", "ini": "^5.0.0",
"init-package-json": "^7.0.2", "init-package-json": "^8.2.1",
"is-cidr": "^5.1.1", "is-cidr": "^5.1.1",
"json-parse-even-better-errors": "^4.0.0", "json-parse-even-better-errors": "^4.0.0",
"libnpmaccess": "^9.0.0", "libnpmaccess": "^10.0.1",
"libnpmdiff": "^7.0.1", "libnpmdiff": "^8.0.7",
"libnpmexec": "^9.0.1", "libnpmexec": "^10.1.6",
"libnpmfund": "^6.0.1", "libnpmfund": "^7.0.7",
"libnpmhook": "^11.0.0", "libnpmorg": "^8.0.0",
"libnpmorg": "^7.0.0", "libnpmpack": "^9.0.7",
"libnpmpack": "^8.0.1", "libnpmpublish": "^11.1.0",
"libnpmpublish": "^10.0.1", "libnpmsearch": "^9.0.0",
"libnpmsearch": "^8.0.0", "libnpmteam": "^8.0.1",
"libnpmteam": "^7.0.0", "libnpmversion": "^8.0.1",
"libnpmversion": "^7.0.0",
"make-fetch-happen": "^14.0.3", "make-fetch-happen": "^14.0.3",
"minimatch": "^9.0.5", "minimatch": "^9.0.5",
"minipass": "^7.1.1", "minipass": "^7.1.1",
@@ -4831,7 +4828,7 @@
"ms": "^2.1.2", "ms": "^2.1.2",
"node-gyp": "^11.2.0", "node-gyp": "^11.2.0",
"nopt": "^8.1.0", "nopt": "^8.1.0",
"normalize-package-data": "^7.0.0", "normalize-package-data": "^7.0.1",
"npm-audit-report": "^6.0.0", "npm-audit-report": "^6.0.0",
"npm-install-checks": "^7.1.1", "npm-install-checks": "^7.1.1",
"npm-package-arg": "^12.0.2", "npm-package-arg": "^12.0.2",
@@ -4840,7 +4837,7 @@
"npm-registry-fetch": "^18.0.2", "npm-registry-fetch": "^18.0.2",
"npm-user-validate": "^3.0.0", "npm-user-validate": "^3.0.0",
"p-map": "^7.0.3", "p-map": "^7.0.3",
"pacote": "^19.0.1", "pacote": "^21.0.0",
"parse-conflict-json": "^4.0.0", "parse-conflict-json": "^4.0.0",
"proc-log": "^5.0.0", "proc-log": "^5.0.0",
"qrcode-terminal": "^0.12.0", "qrcode-terminal": "^0.12.0",
@@ -4848,21 +4845,20 @@
"semver": "^7.7.2", "semver": "^7.7.2",
"spdx-expression-parse": "^4.0.0", "spdx-expression-parse": "^4.0.0",
"ssri": "^12.0.0", "ssri": "^12.0.0",
"supports-color": "^9.4.0", "supports-color": "^10.0.0",
"tar": "^6.2.1", "tar": "^6.2.1",
"text-table": "~0.2.0", "text-table": "~0.2.0",
"tiny-relative-date": "^1.3.0", "tiny-relative-date": "^1.3.0",
"treeverse": "^3.0.0", "treeverse": "^3.0.0",
"validate-npm-package-name": "^6.0.1", "validate-npm-package-name": "^6.0.2",
"which": "^5.0.0", "which": "^5.0.0"
"write-file-atomic": "^6.0.0"
}, },
"bin": { "bin": {
"npm": "bin/npm-cli.js", "npm": "bin/npm-cli.js",
"npx": "bin/npx-cli.js" "npx": "bin/npx-cli.js"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/npm/node_modules/@isaacs/cliui": { "node_modules/npm/node_modules/@isaacs/cliui": {
@@ -4959,7 +4955,7 @@
} }
}, },
"node_modules/npm/node_modules/@npmcli/arborist": { "node_modules/npm/node_modules/@npmcli/arborist": {
"version": "8.0.1", "version": "9.1.4",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@@ -4967,7 +4963,7 @@
"@npmcli/fs": "^4.0.0", "@npmcli/fs": "^4.0.0",
"@npmcli/installed-package-contents": "^3.0.0", "@npmcli/installed-package-contents": "^3.0.0",
"@npmcli/map-workspaces": "^4.0.1", "@npmcli/map-workspaces": "^4.0.1",
"@npmcli/metavuln-calculator": "^8.0.0", "@npmcli/metavuln-calculator": "^9.0.0",
"@npmcli/name-from-folder": "^3.0.0", "@npmcli/name-from-folder": "^3.0.0",
"@npmcli/node-gyp": "^4.0.0", "@npmcli/node-gyp": "^4.0.0",
"@npmcli/package-json": "^6.0.1", "@npmcli/package-json": "^6.0.1",
@@ -4978,7 +4974,6 @@
"cacache": "^19.0.1", "cacache": "^19.0.1",
"common-ancestor-path": "^1.0.1", "common-ancestor-path": "^1.0.1",
"hosted-git-info": "^8.0.0", "hosted-git-info": "^8.0.0",
"json-parse-even-better-errors": "^4.0.0",
"json-stringify-nice": "^1.1.4", "json-stringify-nice": "^1.1.4",
"lru-cache": "^10.2.2", "lru-cache": "^10.2.2",
"minimatch": "^9.0.4", "minimatch": "^9.0.4",
@@ -4987,7 +4982,7 @@
"npm-package-arg": "^12.0.0", "npm-package-arg": "^12.0.0",
"npm-pick-manifest": "^10.0.0", "npm-pick-manifest": "^10.0.0",
"npm-registry-fetch": "^18.0.1", "npm-registry-fetch": "^18.0.1",
"pacote": "^19.0.0", "pacote": "^21.0.0",
"parse-conflict-json": "^4.0.0", "parse-conflict-json": "^4.0.0",
"proc-log": "^5.0.0", "proc-log": "^5.0.0",
"proggy": "^3.0.0", "proggy": "^3.0.0",
@@ -4997,17 +4992,17 @@
"semver": "^7.3.7", "semver": "^7.3.7",
"ssri": "^12.0.0", "ssri": "^12.0.0",
"treeverse": "^3.0.0", "treeverse": "^3.0.0",
"walk-up-path": "^3.0.1" "walk-up-path": "^4.0.0"
}, },
"bin": { "bin": {
"arborist": "bin/index.js" "arborist": "bin/index.js"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/npm/node_modules/@npmcli/config": { "node_modules/npm/node_modules/@npmcli/config": {
"version": "9.0.0", "version": "10.4.0",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@@ -5015,13 +5010,13 @@
"@npmcli/package-json": "^6.0.1", "@npmcli/package-json": "^6.0.1",
"ci-info": "^4.0.0", "ci-info": "^4.0.0",
"ini": "^5.0.0", "ini": "^5.0.0",
"nopt": "^8.0.0", "nopt": "^8.1.0",
"proc-log": "^5.0.0", "proc-log": "^5.0.0",
"semver": "^7.3.5", "semver": "^7.3.5",
"walk-up-path": "^3.0.1" "walk-up-path": "^4.0.0"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/npm/node_modules/@npmcli/fs": { "node_modules/npm/node_modules/@npmcli/fs": {
@@ -5083,48 +5078,18 @@
} }
}, },
"node_modules/npm/node_modules/@npmcli/metavuln-calculator": { "node_modules/npm/node_modules/@npmcli/metavuln-calculator": {
"version": "8.0.1", "version": "9.0.1",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"cacache": "^19.0.0", "cacache": "^19.0.0",
"json-parse-even-better-errors": "^4.0.0", "json-parse-even-better-errors": "^4.0.0",
"pacote": "^20.0.0", "pacote": "^21.0.0",
"proc-log": "^5.0.0", "proc-log": "^5.0.0",
"semver": "^7.3.5" "semver": "^7.3.5"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm/node_modules/@npmcli/metavuln-calculator/node_modules/pacote": {
"version": "20.0.0",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/git": "^6.0.0",
"@npmcli/installed-package-contents": "^3.0.0",
"@npmcli/package-json": "^6.0.0",
"@npmcli/promise-spawn": "^8.0.0",
"@npmcli/run-script": "^9.0.0",
"cacache": "^19.0.0",
"fs-minipass": "^3.0.0",
"minipass": "^7.0.2",
"npm-package-arg": "^12.0.0",
"npm-packlist": "^9.0.0",
"npm-pick-manifest": "^10.0.0",
"npm-registry-fetch": "^18.0.0",
"proc-log": "^5.0.0",
"promise-retry": "^2.0.1",
"sigstore": "^3.0.0",
"ssri": "^12.0.0",
"tar": "^6.1.11"
},
"bin": {
"pacote": "bin/index.js"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
} }
}, },
"node_modules/npm/node_modules/@npmcli/name-from-folder": { "node_modules/npm/node_modules/@npmcli/name-from-folder": {
@@ -5215,6 +5180,25 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/npm/node_modules/@sigstore/bundle": {
"version": "3.1.0",
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
"@sigstore/protobuf-specs": "^0.4.0"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/@sigstore/core": {
"version": "2.0.0",
"inBundle": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/@sigstore/protobuf-specs": { "node_modules/npm/node_modules/@sigstore/protobuf-specs": {
"version": "0.4.3", "version": "0.4.3",
"inBundle": true, "inBundle": true,
@@ -5223,6 +5207,22 @@
"node": "^18.17.0 || >=20.5.0" "node": "^18.17.0 || >=20.5.0"
} }
}, },
"node_modules/npm/node_modules/@sigstore/sign": {
"version": "3.1.0",
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
"@sigstore/bundle": "^3.1.0",
"@sigstore/core": "^2.0.0",
"@sigstore/protobuf-specs": "^0.4.0",
"make-fetch-happen": "^14.0.2",
"proc-log": "^5.0.0",
"promise-retry": "^2.0.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/@sigstore/tuf": { "node_modules/npm/node_modules/@sigstore/tuf": {
"version": "3.1.1", "version": "3.1.1",
"inBundle": true, "inBundle": true,
@@ -5235,6 +5235,19 @@
"node": "^18.17.0 || >=20.5.0" "node": "^18.17.0 || >=20.5.0"
} }
}, },
"node_modules/npm/node_modules/@sigstore/verify": {
"version": "2.1.1",
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
"@sigstore/bundle": "^3.1.0",
"@sigstore/core": "^2.0.0",
"@sigstore/protobuf-specs": "^0.4.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/@tufjs/canonical-json": { "node_modules/npm/node_modules/@tufjs/canonical-json": {
"version": "2.0.0", "version": "2.0.0",
"inBundle": true, "inBundle": true,
@@ -5243,6 +5256,18 @@
"node": "^16.14.0 || >=18.0.0" "node": "^16.14.0 || >=18.0.0"
} }
}, },
"node_modules/npm/node_modules/@tufjs/models": {
"version": "3.0.1",
"inBundle": true,
"license": "MIT",
"dependencies": {
"@tufjs/canonical-json": "2.0.0",
"minimatch": "^9.0.5"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/abbrev": { "node_modules/npm/node_modules/abbrev": {
"version": "3.0.1", "version": "3.0.1",
"inBundle": true, "inBundle": true,
@@ -5252,7 +5277,7 @@
} }
}, },
"node_modules/npm/node_modules/agent-base": { "node_modules/npm/node_modules/agent-base": {
"version": "7.1.3", "version": "7.1.4",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -5279,7 +5304,7 @@
} }
}, },
"node_modules/npm/node_modules/aproba": { "node_modules/npm/node_modules/aproba": {
"version": "2.0.0", "version": "2.1.0",
"inBundle": true, "inBundle": true,
"license": "ISC" "license": "ISC"
}, },
@@ -5309,11 +5334,11 @@
} }
}, },
"node_modules/npm/node_modules/binary-extensions": { "node_modules/npm/node_modules/binary-extensions": {
"version": "2.3.0", "version": "3.1.0",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=18.20"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
@@ -5357,6 +5382,17 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/npm/node_modules/cacache/node_modules/minizlib": {
"version": "3.0.2",
"inBundle": true,
"license": "MIT",
"dependencies": {
"minipass": "^7.1.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/npm/node_modules/cacache/node_modules/mkdirp": { "node_modules/npm/node_modules/cacache/node_modules/mkdirp": {
"version": "3.0.1", "version": "3.0.1",
"inBundle": true, "inBundle": true,
@@ -5415,7 +5451,7 @@
} }
}, },
"node_modules/npm/node_modules/ci-info": { "node_modules/npm/node_modules/ci-info": {
"version": "4.2.0", "version": "4.3.0",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -5535,7 +5571,7 @@
} }
}, },
"node_modules/npm/node_modules/diff": { "node_modules/npm/node_modules/diff": {
"version": "5.2.0", "version": "7.0.0",
"inBundle": true, "inBundle": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"engines": { "engines": {
@@ -5717,11 +5753,11 @@
} }
}, },
"node_modules/npm/node_modules/init-package-json": { "node_modules/npm/node_modules/init-package-json": {
"version": "7.0.2", "version": "8.2.1",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@npmcli/package-json": "^6.0.0", "@npmcli/package-json": "^6.1.0",
"npm-package-arg": "^12.0.0", "npm-package-arg": "^12.0.0",
"promzard": "^2.0.0", "promzard": "^2.0.0",
"read": "^4.0.0", "read": "^4.0.0",
@@ -5730,7 +5766,7 @@
"validate-npm-package-name": "^6.0.0" "validate-npm-package-name": "^6.0.0"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/npm/node_modules/ip-address": { "node_modules/npm/node_modules/ip-address": {
@@ -5834,111 +5870,100 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/npm/node_modules/libnpmaccess": { "node_modules/npm/node_modules/libnpmaccess": {
"version": "9.0.0",
"inBundle": true,
"license": "ISC",
"dependencies": {
"npm-package-arg": "^12.0.0",
"npm-registry-fetch": "^18.0.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/libnpmdiff": {
"version": "7.0.1",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/arborist": "^8.0.1",
"@npmcli/installed-package-contents": "^3.0.0",
"binary-extensions": "^2.3.0",
"diff": "^5.1.0",
"minimatch": "^9.0.4",
"npm-package-arg": "^12.0.0",
"pacote": "^19.0.0",
"tar": "^6.2.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/libnpmexec": {
"version": "9.0.1",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/arborist": "^8.0.1",
"@npmcli/run-script": "^9.0.1",
"ci-info": "^4.0.0",
"npm-package-arg": "^12.0.0",
"pacote": "^19.0.0",
"proc-log": "^5.0.0",
"read": "^4.0.0",
"read-package-json-fast": "^4.0.0",
"semver": "^7.3.7",
"walk-up-path": "^3.0.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/libnpmfund": {
"version": "6.0.1",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/arborist": "^8.0.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/libnpmhook": {
"version": "11.0.0",
"inBundle": true,
"license": "ISC",
"dependencies": {
"aproba": "^2.0.0",
"npm-registry-fetch": "^18.0.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/libnpmorg": {
"version": "7.0.0",
"inBundle": true,
"license": "ISC",
"dependencies": {
"aproba": "^2.0.0",
"npm-registry-fetch": "^18.0.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/libnpmpack": {
"version": "8.0.1",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/arborist": "^8.0.1",
"@npmcli/run-script": "^9.0.1",
"npm-package-arg": "^12.0.0",
"pacote": "^19.0.0"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/libnpmpublish": {
"version": "10.0.1", "version": "10.0.1",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"npm-package-arg": "^12.0.0",
"npm-registry-fetch": "^18.0.1"
},
"engines": {
"node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm/node_modules/libnpmdiff": {
"version": "8.0.7",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/arborist": "^9.1.4",
"@npmcli/installed-package-contents": "^3.0.0",
"binary-extensions": "^3.0.0",
"diff": "^7.0.0",
"minimatch": "^9.0.4",
"npm-package-arg": "^12.0.0",
"pacote": "^21.0.0",
"tar": "^6.2.1"
},
"engines": {
"node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm/node_modules/libnpmexec": {
"version": "10.1.6",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/arborist": "^9.1.4",
"@npmcli/package-json": "^6.1.1",
"@npmcli/run-script": "^9.0.1",
"ci-info": "^4.0.0",
"npm-package-arg": "^12.0.0",
"pacote": "^21.0.0",
"proc-log": "^5.0.0",
"read": "^4.0.0",
"read-package-json-fast": "^4.0.0",
"semver": "^7.3.7",
"walk-up-path": "^4.0.0"
},
"engines": {
"node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm/node_modules/libnpmfund": {
"version": "7.0.7",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/arborist": "^9.1.4"
},
"engines": {
"node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm/node_modules/libnpmorg": {
"version": "8.0.0",
"inBundle": true,
"license": "ISC",
"dependencies": {
"aproba": "^2.0.0",
"npm-registry-fetch": "^18.0.1"
},
"engines": {
"node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm/node_modules/libnpmpack": {
"version": "9.0.7",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/arborist": "^9.1.4",
"@npmcli/run-script": "^9.0.1",
"npm-package-arg": "^12.0.0",
"pacote": "^21.0.0"
},
"engines": {
"node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm/node_modules/libnpmpublish": {
"version": "11.1.0",
"inBundle": true,
"license": "ISC",
"dependencies": {
"@npmcli/package-json": "^6.2.0",
"ci-info": "^4.0.0", "ci-info": "^4.0.0",
"normalize-package-data": "^7.0.0",
"npm-package-arg": "^12.0.0", "npm-package-arg": "^12.0.0",
"npm-registry-fetch": "^18.0.1", "npm-registry-fetch": "^18.0.1",
"proc-log": "^5.0.0", "proc-log": "^5.0.0",
@@ -5947,22 +5972,22 @@
"ssri": "^12.0.0" "ssri": "^12.0.0"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/npm/node_modules/libnpmsearch": { "node_modules/npm/node_modules/libnpmsearch": {
"version": "8.0.0", "version": "9.0.0",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"npm-registry-fetch": "^18.0.1" "npm-registry-fetch": "^18.0.1"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/npm/node_modules/libnpmteam": { "node_modules/npm/node_modules/libnpmteam": {
"version": "7.0.0", "version": "8.0.1",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@@ -5970,11 +5995,11 @@
"npm-registry-fetch": "^18.0.1" "npm-registry-fetch": "^18.0.1"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/npm/node_modules/libnpmversion": { "node_modules/npm/node_modules/libnpmversion": {
"version": "7.0.0", "version": "8.0.1",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@@ -5985,7 +6010,7 @@
"semver": "^7.3.7" "semver": "^7.3.7"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/npm/node_modules/lru-cache": { "node_modules/npm/node_modules/lru-cache": {
@@ -6071,6 +6096,17 @@
"encoding": "^0.1.13" "encoding": "^0.1.13"
} }
}, },
"node_modules/npm/node_modules/minipass-fetch/node_modules/minizlib": {
"version": "3.0.2",
"inBundle": true,
"license": "MIT",
"dependencies": {
"minipass": "^7.1.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/npm/node_modules/minipass-flush": { "node_modules/npm/node_modules/minipass-flush": {
"version": "1.0.5", "version": "1.0.5",
"inBundle": true, "inBundle": true,
@@ -6138,14 +6174,26 @@
} }
}, },
"node_modules/npm/node_modules/minizlib": { "node_modules/npm/node_modules/minizlib": {
"version": "3.0.2", "version": "2.1.2",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"minipass": "^7.1.2" "minipass": "^3.0.0",
"yallist": "^4.0.0"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 8"
}
},
"node_modules/npm/node_modules/minizlib/node_modules/minipass": {
"version": "3.3.6",
"inBundle": true,
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=8"
} }
}, },
"node_modules/npm/node_modules/mkdirp": { "node_modules/npm/node_modules/mkdirp": {
@@ -6203,6 +6251,17 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/npm/node_modules/node-gyp/node_modules/minizlib": {
"version": "3.0.2",
"inBundle": true,
"license": "MIT",
"dependencies": {
"minipass": "^7.1.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/npm/node_modules/node-gyp/node_modules/mkdirp": { "node_modules/npm/node_modules/node-gyp/node_modules/mkdirp": {
"version": "3.0.1", "version": "3.0.1",
"inBundle": true, "inBundle": true,
@@ -6256,7 +6315,7 @@
} }
}, },
"node_modules/npm/node_modules/normalize-package-data": { "node_modules/npm/node_modules/normalize-package-data": {
"version": "7.0.0", "version": "7.0.1",
"inBundle": true, "inBundle": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
@@ -6321,14 +6380,14 @@
} }
}, },
"node_modules/npm/node_modules/npm-packlist": { "node_modules/npm/node_modules/npm-packlist": {
"version": "9.0.0", "version": "10.0.0",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"ignore-walk": "^7.0.0" "ignore-walk": "^7.0.0"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/npm/node_modules/npm-pick-manifest": { "node_modules/npm/node_modules/npm-pick-manifest": {
@@ -6375,6 +6434,17 @@
"node": "^18.17.0 || >=20.5.0" "node": "^18.17.0 || >=20.5.0"
} }
}, },
"node_modules/npm/node_modules/npm-registry-fetch/node_modules/minizlib": {
"version": "3.0.2",
"inBundle": true,
"license": "MIT",
"dependencies": {
"minipass": "^7.1.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/npm/node_modules/npm-user-validate": { "node_modules/npm/node_modules/npm-user-validate": {
"version": "3.0.0", "version": "3.0.0",
"inBundle": true, "inBundle": true,
@@ -6400,7 +6470,7 @@
"license": "BlueOak-1.0.0" "license": "BlueOak-1.0.0"
}, },
"node_modules/npm/node_modules/pacote": { "node_modules/npm/node_modules/pacote": {
"version": "19.0.1", "version": "21.0.0",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@@ -6413,7 +6483,7 @@
"fs-minipass": "^3.0.0", "fs-minipass": "^3.0.0",
"minipass": "^7.0.2", "minipass": "^7.0.2",
"npm-package-arg": "^12.0.0", "npm-package-arg": "^12.0.0",
"npm-packlist": "^9.0.0", "npm-packlist": "^10.0.0",
"npm-pick-manifest": "^10.0.0", "npm-pick-manifest": "^10.0.0",
"npm-registry-fetch": "^18.0.0", "npm-registry-fetch": "^18.0.0",
"proc-log": "^5.0.0", "proc-log": "^5.0.0",
@@ -6426,7 +6496,7 @@
"pacote": "bin/index.js" "pacote": "bin/index.js"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/npm/node_modules/parse-conflict-json": { "node_modules/npm/node_modules/parse-conflict-json": {
@@ -6641,54 +6711,6 @@
"node": "^18.17.0 || >=20.5.0" "node": "^18.17.0 || >=20.5.0"
} }
}, },
"node_modules/npm/node_modules/sigstore/node_modules/@sigstore/bundle": {
"version": "3.1.0",
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
"@sigstore/protobuf-specs": "^0.4.0"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/sigstore/node_modules/@sigstore/core": {
"version": "2.0.0",
"inBundle": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/sigstore/node_modules/@sigstore/sign": {
"version": "3.1.0",
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
"@sigstore/bundle": "^3.1.0",
"@sigstore/core": "^2.0.0",
"@sigstore/protobuf-specs": "^0.4.0",
"make-fetch-happen": "^14.0.2",
"proc-log": "^5.0.0",
"promise-retry": "^2.0.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/sigstore/node_modules/@sigstore/verify": {
"version": "2.1.1",
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
"@sigstore/bundle": "^3.1.0",
"@sigstore/core": "^2.0.0",
"@sigstore/protobuf-specs": "^0.4.1"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/smart-buffer": { "node_modules/npm/node_modules/smart-buffer": {
"version": "4.2.0", "version": "4.2.0",
"inBundle": true, "inBundle": true,
@@ -6699,7 +6721,7 @@
} }
}, },
"node_modules/npm/node_modules/socks": { "node_modules/npm/node_modules/socks": {
"version": "2.8.5", "version": "2.8.6",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -6828,11 +6850,11 @@
} }
}, },
"node_modules/npm/node_modules/supports-color": { "node_modules/npm/node_modules/supports-color": {
"version": "9.4.0", "version": "10.0.0",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=12" "node": ">=18"
}, },
"funding": { "funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1" "url": "https://github.com/chalk/supports-color?sponsor=1"
@@ -6884,29 +6906,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/npm/node_modules/tar/node_modules/minizlib": {
"version": "2.1.2",
"inBundle": true,
"license": "MIT",
"dependencies": {
"minipass": "^3.0.0",
"yallist": "^4.0.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/npm/node_modules/tar/node_modules/minizlib/node_modules/minipass": {
"version": "3.3.6",
"inBundle": true,
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/npm/node_modules/text-table": { "node_modules/npm/node_modules/text-table": {
"version": "0.2.0", "version": "0.2.0",
"inBundle": true, "inBundle": true,
@@ -6946,7 +6945,7 @@
} }
}, },
"node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { "node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.2", "version": "4.0.3",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -6965,25 +6964,13 @@
} }
}, },
"node_modules/npm/node_modules/tuf-js": { "node_modules/npm/node_modules/tuf-js": {
"version": "3.0.1", "version": "3.1.0",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tufjs/models": "3.0.1", "@tufjs/models": "3.0.1",
"debug": "^4.3.6", "debug": "^4.4.1",
"make-fetch-happen": "^14.0.1" "make-fetch-happen": "^14.0.3"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm/node_modules/tuf-js/node_modules/@tufjs/models": {
"version": "3.0.1",
"inBundle": true,
"license": "MIT",
"dependencies": {
"@tufjs/canonical-json": "2.0.0",
"minimatch": "^9.0.5"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^18.17.0 || >=20.5.0"
@@ -7035,7 +7022,7 @@
} }
}, },
"node_modules/npm/node_modules/validate-npm-package-name": { "node_modules/npm/node_modules/validate-npm-package-name": {
"version": "6.0.1", "version": "6.0.2",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"engines": { "engines": {
@@ -7043,9 +7030,12 @@
} }
}, },
"node_modules/npm/node_modules/walk-up-path": { "node_modules/npm/node_modules/walk-up-path": {
"version": "3.0.1", "version": "4.0.0",
"inBundle": true, "inBundle": true,
"license": "ISC" "license": "ISC",
"engines": {
"node": "20 || >=22"
}
}, },
"node_modules/npm/node_modules/which": { "node_modules/npm/node_modules/which": {
"version": "5.0.0", "version": "5.0.0",

View File

@@ -27,7 +27,7 @@
"fuse.js": "^7.0.0", "fuse.js": "^7.0.0",
"i": "^0.3.7", "i": "^0.3.7",
"is-cidr": "^5.0.3", "is-cidr": "^5.0.3",
"npm": "^10.5.0", "npm": "^11.6.0",
"ol": "^10.2.1", "ol": "^10.2.1",
"pinia": "^3.0.3", "pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.5.0", "pinia-plugin-persistedstate": "^4.5.0",

View File

@@ -464,47 +464,6 @@ stop_wgd() {
fi fi
} }
# ============= Docker Functions =============
startwgd_docker() {
_checkWireguard
printf "[WGDashboard][Docker] WireGuard configuration started\n"
{ date; start_core ; printf "\n\n"; } >> ./log/install.txt
gunicorn_start
}
start_core() {
# Re-assign config_files to ensure it includes any newly created configurations
local config_files=$(find /etc/wireguard -type f -name "*.conf")
# Set file permissions
find /etc/wireguard -type f -name "*.conf" -exec chmod 600 {} \;
find "$iptable_dir" -type f -name "*.sh" -exec chmod +x {} \;
# Start WireGuard for each config file
for file in $config_files; do
config_name=$(basename "$file" ".conf")
wg-quick up "$config_name"
done
}
newconf_wgd() {
local wg_port_listen=$wg_port
local wg_addr_range=$wg_net
private_key=$(wg genkey)
public_key=$(echo "$private_key" | wg pubkey)
cat <<EOF >"/etc/wireguard/wg0.conf"
[Interface]
PrivateKey = $private_key
Address = $wg_addr_range
ListenPort = $wg_port_listen
SaveConfig = true
PostUp = /opt/wireguarddashboard/src/iptable-rules/postup.sh
PreDown = /opt/wireguarddashboard/src/iptable-rules/postdown.sh
EOF
}
# ============= Docker Functions =============
start_wgd_debug() { start_wgd_debug() {
_checkWireguard _checkWireguard
printf "[WGDashboard] Starting WGDashboard in the foreground.\n" printf "[WGDashboard] Starting WGDashboard in the foreground.\n"
@@ -600,4 +559,4 @@ else
help help
fi fi
fi fi
printf "%s\n" "$dashes" printf "%s\n" "$dashes"