Compare commits

...

19 Commits

Author SHA1 Message Date
Donald Zou
1faabd37af Merge pull request #936 from WGDashboard/fix-752
Internal merge for Fix 752
2025-10-02 07:18:09 +08:00
jinndi
c18ec5c83c Docker: Use relative paths instead of absolute ones to ensure proper namespace handling when working behind a reverse proxy. (#934)
* Docker: Use relative paths instead of absolute ones to ensure proper namespace handling when working behind a reverse proxy.

* Fix: Progress Swap Memory percent
2025-09-29 12:14:52 +02:00
Daan Selen
d8c89056cb refac: rework the variable times, mostly in ConnectionString 2025-09-23 09:08:21 +02:00
DaanSelen
8b541229d8 refac: make WGDashboard logging level configurable (#915)
* feat: init configurable logging level

* refac: correct some logging functions to debug from info. They were not that informational

* fix: logging somehow was broken due to disablement of external loggers

* refac: set default to info

---------

Co-authored-by: Daan Selen <dselen@systemec.nl>
2025-09-22 18:20:22 +02:00
Daan Selen
b7e65f7caf fix: initial run import massacre 2025-09-22 14:04:11 +02:00
Daan Selen
2eda18f18d refac: correct log output for the conditions checked 2025-09-22 13:35:53 +02:00
Daan Selen
d06709aeab Merge branch 'main' into v4.3.1-dev 2025-09-22 13:29:06 +02:00
Donald Zou
3de22ed2d6 Merge pull request #921 from WGDashboard/minor-patch-save-config 2025-09-22 17:54:40 +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
Daan Selen
a9036590a9 refac: save config before accessing it 2025-09-21 21:51:59 +02:00
dependabot[bot]
8f8843d449 Bump is-cidr from 5.1.1 to 6.0.0 in /src/static/app (#903)
Bumps [is-cidr](https://github.com/silverwind/is-cidr) from 5.1.1 to 6.0.0.
- [Release notes](https://github.com/silverwind/is-cidr/releases)
- [Commits](https://github.com/silverwind/is-cidr/compare/5.1.1...6.0.0)

---
updated-dependencies:
- dependency-name: is-cidr
  dependency-version: 6.0.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 19:52:39 +02:00
dependabot[bot]
6a21702768 Bump uuid from 11.1.0 to 13.0.0 in /src/static/app (#904)
Bumps [uuid](https://github.com/uuidjs/uuid) from 11.1.0 to 13.0.0.
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v11.1.0...v13.0.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 13.0.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 19:52:10 +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
Donald Zou
56552d0a83 Merge pull request #917 from WGDashboard/db_prefix_add
feat: add configurable database prefix
2025-09-21 02:44:48 +08:00
Daan Selen
bd17b9080a fix: issue where I accidentally did the same name twice 2025-09-19 20:56:00 +02:00
Daan Selen
bf28983229 feat: make the prefix configurable 2025-09-19 20:55:47 +02:00
24 changed files with 464 additions and 474 deletions

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ __pycache__
src/test.py src/test.py
*.db *.db
src/wg-dashboard.ini src/wg-dashboard.ini
src/ssl-tls.ini
src/static/pic.xd src/static/pic.xd
*.conf *.conf
private_key.txt private_key.txt

View File

@@ -104,6 +104,7 @@ ARG wg_port="51820"
ENV TZ="Europe/Amsterdam" \ ENV TZ="Europe/Amsterdam" \
global_dns="9.9.9.9" \ global_dns="9.9.9.9" \
wgd_port="10086" \ wgd_port="10086" \
log_level="INFO" \
public_ip="" \ public_ip="" \
WGDASH=/opt/wgdashboard WGDASH=/opt/wgdashboard
@@ -129,6 +130,15 @@ SaveConfig = true\n\
DNS = ${global_dns}" > /configs/wg0.conf.template \ DNS = ${global_dns}" > /configs/wg0.conf.template \
&& chmod 600 /configs/wg0.conf.template && chmod 600 /configs/wg0.conf.template
# Replacement of paths with relative ones for namespace handling when using a reverse proxy
RUN set -ex && \
find ${WGDASH}/src/static/dist -type f \( -name "*.html" -o -name "*.js" \) \
-exec sed -i 's|/static/dist|./static/dist|g' {} + && \
find ${WGDASH}/src/static/dist -type f -name "*.css" \
-exec sed -i 's|/static/dist/WGDashboardClient/assets/|./|g' {} + && \
find ${WGDASH}/src/static/dist -type f -name "*.css" \
-exec sed -i 's|/static/dist/WGDashboardAdmin/assets/|./|g' {} +
# Set a healthcheck to determine the container its health # Set a healthcheck to determine the container its health
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD sh -c 'pgrep gunicorn > /dev/null && pgrep tail > /dev/null' || exit 1 CMD sh -c 'pgrep gunicorn > /dev/null && pgrep tail > /dev/null' || exit 1

View File

@@ -102,6 +102,7 @@ Updating the WGDashboard container should be through 'The Docker Way' - by pulli
| `global_dns` | IPv4 and IPv6 addresses | `9.9.9.9` | `8.8.8.8`, `1.1.1.1` | Default DNS for WireGuard clients. | | `global_dns` | IPv4 and IPv6 addresses | `9.9.9.9` | `8.8.8.8`, `1.1.1.1` | Default DNS for WireGuard clients. |
| `public_ip` | Public IP address | Retrieved automatically | `253.162.134.73` | Used to generate accurate client configs. Needed if container is NATd. | | `public_ip` | Public IP address | Retrieved automatically | `253.162.134.73` | Used to generate accurate client configs. Needed if container is NATd. |
| `wgd_port` | Any port that is allowed for the process | `10086` | `443` | This port is used to set the WGDashboard web port. | | `wgd_port` | Any port that is allowed for the process | `10086` | `443` | This port is used to set the WGDashboard web port. |
| `log_level` | `DEBUG`, `INFO`, `WARNING`, `ERROR` and `CRITICAL` | `INFO` | `WARNING` | Sets the severity of the logs being displayed. |
| `username` | Any nonempty string | `-` | `admin` | Username for the WGDashboard web interface account. | | `username` | Any nonempty string | `-` | `admin` | Username for the WGDashboard web interface account. |
| `password` | Any nonempty string | `-` | `s3cr3tP@ss` | Password for the WGDashboard web interface account (stored hashed). | | `password` | Any nonempty string | `-` | `s3cr3tP@ss` | Password for the WGDashboard web interface account (stored hashed). |
| `enable_totp` | `true`, `false` | `true` | `false` | Enable TOTPbased twofactor authentication for the account. | | `enable_totp` | `true`, `false` | `true` | `false` | Enable TOTPbased twofactor authentication for the account. |

View File

@@ -12,7 +12,8 @@ services:
# Environment variables can be used to configure certain values at startup. Without having to configure it from the dashboard. # Environment variables can be used to configure certain values at startup. Without having to configure it from the dashboard.
# By default its all disabled, but uncomment the following lines to apply these. (uncommenting is removing the # character) # By default its all disabled, but uncomment the following lines to apply these. (uncommenting is removing the # character)
# Refer to the documentation on https://wgdashboard.dev/ for more info on what everything means. # Refer to the documentation on https://wgdashboard.dev/ for more info on what everything means.
#environment: environment:
- log_level=WARNING
#- tz= # <--- Set container timezone, default: Europe/Amsterdam. #- tz= # <--- Set container timezone, default: Europe/Amsterdam.
#- public_ip= # <--- Set public IP to ensure the correct one is chosen, defaulting to the IP give by ifconfig.me. #- public_ip= # <--- Set public IP to ensure the correct one is chosen, defaulting to the IP give by ifconfig.me.
#- wgd_port= # <--- Set the port WGDashboard will use for its web-server. #- wgd_port= # <--- Set the port WGDashboard will use for its web-server.

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,111 +61,112 @@ 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 Wireguard configuration file found in /etc/wireguard."
fi fi
} }
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}"
set_ini Server log_level "${log_level}"
# 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 +175,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 +190,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 +199,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 +222,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

@@ -72,7 +72,6 @@ def ResponseObject(status=True, message=None, data=None, status_code = 200) -> F
''' '''
Flask App Flask App
''' '''
app = Flask("WGDashboard", template_folder=os.path.abspath("./static/dist/WGDashboardAdmin"))
def peerInformationBackgroundThread(): def peerInformationBackgroundThread():
global WireguardConfigurations global WireguardConfigurations
@@ -120,7 +119,8 @@ def peerJobScheduleBackgroundThread():
def gunicornConfig(): def gunicornConfig():
_, app_ip = DashboardConfig.GetConfig("Server", "app_ip") _, app_ip = DashboardConfig.GetConfig("Server", "app_ip")
_, app_port = DashboardConfig.GetConfig("Server", "app_port") _, app_port = DashboardConfig.GetConfig("Server", "app_port")
return app_ip, app_port
return app_ip, app_port, log_level
def ProtocolsEnabled() -> list[str]: def ProtocolsEnabled() -> list[str]:
from shutil import which from shutil import which
@@ -172,16 +172,7 @@ def startThreads():
scheduleJobThread = threading.Thread(target=peerJobScheduleBackgroundThread, daemon=True) scheduleJobThread = threading.Thread(target=peerJobScheduleBackgroundThread, daemon=True)
scheduleJobThread.start() scheduleJobThread.start()
dictConfig({ app = Flask("WGDashboard", template_folder=os.path.abspath("./static/dist/WGDashboardAdmin"))
'version': 1,
'formatters': {'default': {
'format': '[%(asctime)s] [%(levelname)s] in [%(module)s] %(message)s',
}},
'root': {
'level': 'INFO'
}
})
WireguardConfigurations: dict[str, WireguardConfiguration] = {} WireguardConfigurations: dict[str, WireguardConfiguration] = {}
CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.') CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
@@ -189,6 +180,7 @@ CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 5206928 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 5206928
app.secret_key = secrets.token_urlsafe(32) app.secret_key = secrets.token_urlsafe(32)
app.json = CustomJsonEncoder(app) app.json = CustomJsonEncoder(app)
with app.app_context(): with app.app_context():
SystemStatus = SystemStatus() SystemStatus = SystemStatus()
DashboardConfig = DashboardConfig() DashboardConfig = DashboardConfig()
@@ -199,19 +191,44 @@ with app.app_context():
DashboardPlugins: DashboardPlugins = DashboardPlugins(app, WireguardConfigurations) DashboardPlugins: DashboardPlugins = DashboardPlugins(app, WireguardConfigurations)
DashboardWebHooks: DashboardWebHooks = DashboardWebHooks(DashboardConfig) DashboardWebHooks: DashboardWebHooks = DashboardWebHooks(DashboardConfig)
NewConfigurationTemplates: NewConfigurationTemplates = NewConfigurationTemplates() NewConfigurationTemplates: NewConfigurationTemplates = NewConfigurationTemplates()
InitWireguardConfigurationsList(startup=True) InitWireguardConfigurationsList(startup=True)
DashboardClients: 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")
_, app_ip = DashboardConfig.GetConfig("Server", "app_ip")
_, app_port = DashboardConfig.GetConfig("Server", "app_port")
_, WG_CONF_PATH = DashboardConfig.GetConfig("Server", "wg_conf_path")
_, log_level = DashboardConfig.GetConfig("Server", "log_level")
cors = CORS(app, resources={rf"{APP_PREFIX}/api/*": { cors = CORS(app, resources={rf"{APP_PREFIX}/api/*": {
"origins": "*", "origins": "*",
"methods": "DELETE, POST, GET, OPTIONS", "methods": "DELETE, POST, GET, OPTIONS",
"allow_headers": ["Content-Type", "wg-dashboard-apikey"] "allow_headers": ["Content-Type", "wg-dashboard-apikey"]
}}) }})
_, app_ip = DashboardConfig.GetConfig("Server", "app_ip")
_, app_port = DashboardConfig.GetConfig("Server", "app_port") app.logger.setLevel(getattr(logging, log_level.upper(), logging.INFO))
_, WG_CONF_PATH = DashboardConfig.GetConfig("Server", "wg_conf_path")
dictConfig({
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'default': {
'format': '[%(asctime)s] [%(levelname)s] in [%(module)s] %(message)s',
},
},
'handlers': {
'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default',
},
}
})
''' '''
API Routes API Routes

View File

@@ -1,7 +1,7 @@
import dashboard import dashboard
from datetime import datetime from datetime import datetime
global sqldb, cursor, DashboardConfig, WireguardConfigurations, AllPeerJobs, JobLogger, Dash global sqldb, cursor, DashboardConfig, WireguardConfigurations, AllPeerJobs, JobLogger, Dash
app_host, app_port = dashboard.gunicornConfig() app_host, app_port, log_level = dashboard.gunicornConfig()
date = datetime.today().strftime('%Y_%m_%d_%H_%M_%S') date = datetime.today().strftime('%Y_%m_%d_%H_%M_%S')
def post_worker_init(worker): def post_worker_init(worker):
@@ -16,7 +16,7 @@ daemon = True
pidfile = './gunicorn.pid' pidfile = './gunicorn.pid'
wsgi_app = "dashboard:app" wsgi_app = "dashboard:app"
accesslog = f"./log/access_{date}.log" accesslog = f"./log/access_{date}.log"
loglevel = "info" loglevel = f"{log_level}"
capture_output = True capture_output = True
errorlog = f"./log/error_{date}.log" errorlog = f"./log/error_{date}.log"
pythonpath = "., ./modules" pythonpath = "., ./modules"

View File

@@ -174,7 +174,7 @@ class AmneziaWireguardConfiguration(WireguardConfiguration):
def getPeers(self): def getPeers(self):
self.Peers.clear() self.Peers.clear()
current_app.logger.info(f"Refreshing {self.Name} peer list") current_app.logger.debug(f"Refreshing {self.Name} peer list")
if self.configurationFileChanged(): if self.configurationFileChanged():
with open(self.configPath, 'r') as configFile: with open(self.configPath, 'r') as configFile:
@@ -183,7 +183,7 @@ class AmneziaWireguardConfiguration(WireguardConfiguration):
content = configFile.read().split('\n') content = configFile.read().split('\n')
try: try:
if "[Peer]" not in content: if "[Peer]" not in content:
current_app.logger.info(f"{self.Name} config has no [Peer] section") current_app.logger.debug(f"{self.Name} config has no [Peer] section")
return return
peerStarts = content.index("[Peer]") peerStarts = content.index("[Peer]")

View File

@@ -1,25 +1,47 @@
# ConnectionString.py
import configparser import configparser
import os import os
from sqlalchemy_utils import database_exists, create_database from sqlalchemy_utils import database_exists, create_database
from flask import current_app
def ConnectionString(database) -> str: default_db = "wgdashboard"
default_log_db = "wgdashboard_log"
default_job_db = "wgdashboard_job"
sqlite_path = "db"
if os.path.exists(sqlite_path):
os.makedirs(sqlite_path, exist_ok=True)
def ConnectionString(database_name: str) -> str:
"""
Returns a SQLAlchemy-compatible connection string for the chosen database.
Creates the database if it doesn't exist.
"""
# Read and parse the INI file once at startup
parser = configparser.ConfigParser(strict=False) parser = configparser.ConfigParser(strict=False)
parser.read_file(open('wg-dashboard.ini', "r+")) parser.read("wg-dashboard.ini")
sqlitePath = os.path.join("db")
if not os.path.isdir(sqlitePath): db_type = parser.get("Database", "type")
os.mkdir(sqlitePath) db_prefix = parser.get("Database", "prefix")
if parser.get("Database", "type") == "postgresql": database_name = f"{db_prefix}{database_name}"
cn = f'postgresql+psycopg://{parser.get("Database", "username")}:{parser.get("Database", "password")}@{parser.get("Database", "host")}/{database}'
elif parser.get("Database", "type") == "mysql": if db_type == "postgresql":
cn = f'mysql+pymysql://{parser.get("Database", "username")}:{parser.get("Database", "password")}@{parser.get("Database", "host")}/{database}' username = parser.get("Database", "username")
password = parser.get("Database", "password")
host = parser.get("Database", "host")
cn = f"postgresql+psycopg://{username}:{password}@{host}/{database_name}"
elif db_type == "mysql":
username = parser.get("Database", "username")
password = parser.get("Database", "password")
host = parser.get("Database", "host")
cn = f"mysql+pymysql://{username}:{password}@{host}/{database_name}"
else: else:
cn = f'sqlite:///{os.path.join(sqlitePath, f"{database}.db")}' cn = f'sqlite:///{os.path.join(sqlite_path, f"{database_name}.db")}'
try: try:
if not database_exists(cn): if not database_exists(cn):
create_database(cn) create_database(cn)
except Exception as e: except Exception as e:
current_app.logger.error("Database error. Terminating...", e) current_app.logger.critical("Database error. Terminating...", e)
exit(1) exit(1)
return cn return cn

View File

@@ -8,7 +8,7 @@ import pyotp
import sqlalchemy as db import sqlalchemy as db
import requests import requests
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_db
from .DashboardClientsPeerAssignment import DashboardClientsPeerAssignment from .DashboardClientsPeerAssignment import DashboardClientsPeerAssignment
from .DashboardClientsTOTP import DashboardClientsTOTP from .DashboardClientsTOTP import DashboardClientsTOTP
from .DashboardOIDC import DashboardOIDC from .DashboardOIDC import DashboardOIDC
@@ -20,7 +20,7 @@ from flask import session
class DashboardClients: class DashboardClients:
def __init__(self, wireguardConfigurations): def __init__(self, wireguardConfigurations):
self.logger = DashboardLogger() self.logger = DashboardLogger()
self.engine = db.create_engine(ConnectionString("wgdashboard")) self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData() self.metadata = db.MetaData()
self.OIDC = DashboardOIDC("Client") self.OIDC = DashboardOIDC("Client")
@@ -32,10 +32,10 @@ class DashboardClients:
db.Column('TotpKey', db.String(500)), db.Column('TotpKey', db.String(500)),
db.Column('TotpKeyVerified', db.Integer), db.Column('TotpKeyVerified', db.Integer),
db.Column('CreatedDate', db.Column('CreatedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP), (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP),
server_default=db.func.now()), server_default=db.func.now()),
db.Column('DeletedDate', db.Column('DeletedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)), (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP)),
extend_existing=True, extend_existing=True,
) )
@@ -46,10 +46,10 @@ class DashboardClients:
db.Column('ProviderIssuer', db.String(500), nullable=False, index=True), db.Column('ProviderIssuer', db.String(500), nullable=False, index=True),
db.Column('ProviderSubject', db.String(500), nullable=False, index=True), db.Column('ProviderSubject', db.String(500), nullable=False, index=True),
db.Column('CreatedDate', db.Column('CreatedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP), (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP),
server_default=db.func.now()), server_default=db.func.now()),
db.Column('DeletedDate', db.Column('DeletedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)), (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP)),
extend_existing=True, extend_existing=True,
) )
@@ -65,10 +65,10 @@ class DashboardClients:
db.Column('ResetToken', db.String(255), nullable=False, primary_key=True), db.Column('ResetToken', db.String(255), nullable=False, primary_key=True),
db.Column('ClientID', db.String(255), nullable=False), db.Column('ClientID', db.String(255), nullable=False),
db.Column('CreatedDate', db.Column('CreatedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP), (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP),
server_default=db.func.now()), server_default=db.func.now()),
db.Column('ExpiryDate', db.Column('ExpiryDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)), (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP)),
extend_existing=True extend_existing=True
) )

View File

@@ -1,7 +1,7 @@
import datetime import datetime
import uuid import uuid
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_db
from .DashboardLogger import DashboardLogger from .DashboardLogger import DashboardLogger
import sqlalchemy as db import sqlalchemy as db
from .WireguardConfiguration import WireguardConfiguration from .WireguardConfiguration import WireguardConfiguration
@@ -31,7 +31,7 @@ class Assignment:
class DashboardClientsPeerAssignment: class DashboardClientsPeerAssignment:
def __init__(self, wireguardConfigurations: dict[str, WireguardConfiguration]): def __init__(self, wireguardConfigurations: dict[str, WireguardConfiguration]):
self.logger = DashboardLogger() self.logger = DashboardLogger()
self.engine = db.create_engine(ConnectionString("wgdashboard")) self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData() self.metadata = db.MetaData()
self.wireguardConfigurations = wireguardConfigurations self.wireguardConfigurations = wireguardConfigurations
self.dashboardClientsPeerAssignmentTable = db.Table( self.dashboardClientsPeerAssignmentTable = db.Table(
@@ -41,10 +41,10 @@ class DashboardClientsPeerAssignment:
db.Column('ConfigurationName', db.String(255)), db.Column('ConfigurationName', db.String(255)),
db.Column('PeerID', db.String(500)), db.Column('PeerID', db.String(500)),
db.Column('AssignedDate', db.Column('AssignedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP), (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP),
server_default=db.func.now()), server_default=db.func.now()),
db.Column('UnassignedDate', db.Column('UnassignedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)), (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP)),
extend_existing=True extend_existing=True
) )
self.metadata.create_all(self.engine) self.metadata.create_all(self.engine)

View File

@@ -3,19 +3,19 @@ import hashlib
import uuid import uuid
import sqlalchemy as db import sqlalchemy as db
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_db
class DashboardClientsTOTP: class DashboardClientsTOTP:
def __init__(self): def __init__(self):
self.engine = db.create_engine(ConnectionString("wgdashboard")) self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData() self.metadata = db.MetaData()
self.dashboardClientsTOTPTable = db.Table( self.dashboardClientsTOTPTable = db.Table(
'DashboardClientsTOTPTokens', self.metadata, 'DashboardClientsTOTPTokens', self.metadata,
db.Column("Token", db.String(500), primary_key=True, index=True), db.Column("Token", db.String(500), primary_key=True, index=True),
db.Column("ClientID", db.String(500), index=True), db.Column("ClientID", db.String(500), index=True),
db.Column( db.Column(
"ExpireTime", (db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP) "ExpireTime", (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP)
) )
) )
self.metadata.create_all(self.engine) self.metadata.create_all(self.engine)

View File

@@ -7,7 +7,7 @@ import sqlalchemy as db
from datetime import datetime from datetime import datetime
from typing import Any from typing import Any
from flask import current_app from flask import current_app
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_db
from .Utilities import ( from .Utilities import (
GetRemoteEndpoint, ValidateDNSAddress GetRemoteEndpoint, ValidateDNSAddress
) )
@@ -47,7 +47,8 @@ class DashboardConfig:
"dashboard_sort": "status", "dashboard_sort": "status",
"dashboard_theme": "dark", "dashboard_theme": "dark",
"dashboard_api_key": "false", "dashboard_api_key": "false",
"dashboard_language": "en-US" "dashboard_language": "en-US",
"log_level": "INFO"
}, },
"Peers": { "Peers": {
"peer_global_DNS": "1.1.1.1", "peer_global_DNS": "1.1.1.1",
@@ -65,7 +66,8 @@ class DashboardConfig:
"host": "", "host": "",
"port": "", "port": "",
"username": "", "username": "",
"password": "" "password": "",
"prefix": ""
}, },
"Email":{ "Email":{
"server": "", "server": "",
@@ -95,28 +97,14 @@ class DashboardConfig:
if not exist: if not exist:
self.SetConfig(section, key, value, True) self.SetConfig(section, key, value, True)
self.engine = db.create_engine(ConnectionString('wgdashboard')) self.SetConfig("Server", "version", DashboardConfig.DashboardVersion)
self.SaveConfig()
self.engine = db.create_engine(ConnectionString(default_db))
self.dbMetadata = db.MetaData() self.dbMetadata = db.MetaData()
self.__createAPIKeyTable() self.__createAPIKeyTable()
self.DashboardAPIKeys = self.__getAPIKeys() self.DashboardAPIKeys = self.__getAPIKeys()
self.APIAccessed = False self.APIAccessed = False
self.SetConfig("Server", "version", DashboardConfig.DashboardVersion)
def getConnectionString(self, database) -> str or None:
sqlitePath = os.path.join(DashboardConfig.ConfigurationPath, "db")
if not os.path.isdir(sqlitePath):
os.mkdir(sqlitePath)
if self.GetConfig("Database", "type")[1] == "postgresql":
cn = f'postgresql+psycopg2://{self.GetConfig("Database", "username")[1]}:{self.GetConfig("Database", "password")[1]}@{self.GetConfig("Database", "host")[1]}/{database}'
elif self.GetConfig("Database", "type")[1] == "mysql":
cn = f'mysql+mysqldb://{self.GetConfig("Database", "username")[1]}:{self.GetConfig("Database", "password")[1]}@{self.GetConfig("Database", "host")[1]}/{database}'
else:
cn = f'sqlite:///{os.path.join(sqlitePath, f"{database}.db")}'
if not database_exists(cn):
create_database(cn)
return cn
def __createAPIKeyTable(self): def __createAPIKeyTable(self):
self.apiKeyTable = db.Table('DashboardAPIKeys', self.dbMetadata, self.apiKeyTable = db.Table('DashboardAPIKeys', self.dbMetadata,

View File

@@ -4,18 +4,18 @@ Dashboard Logger Class
import uuid import uuid
import sqlalchemy as db import sqlalchemy as db
from flask import current_app from flask import current_app
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_db, default_log_db
class DashboardLogger: class DashboardLogger:
def __init__(self): def __init__(self):
self.engine = db.create_engine(ConnectionString("wgdashboard_log")) self.engine = db.create_engine(ConnectionString(default_log_db))
self.metadata = db.MetaData() self.metadata = db.MetaData()
self.dashboardLoggerTable = db.Table('DashboardLog', self.metadata, self.dashboardLoggerTable = db.Table('DashboardLog', self.metadata,
db.Column('LogID', db.String(255), nullable=False, primary_key=True), db.Column('LogID', db.String(255), nullable=False, primary_key=True),
db.Column('LogDate', db.Column('LogDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP), (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP),
server_default=db.func.now()), server_default=db.func.now()),
db.Column('URL', db.String(255)), db.Column('URL', db.String(255)),
db.Column('IP', db.String(255)), db.Column('IP', db.String(255)),

View File

@@ -8,7 +8,7 @@ from datetime import datetime, timedelta
import requests import requests
from pydantic import BaseModel, field_serializer from pydantic import BaseModel, field_serializer
import sqlalchemy as db import sqlalchemy as db
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_db
from flask import current_app from flask import current_app
WebHookActions = ['peer_created', 'peer_deleted', 'peer_updated'] WebHookActions = ['peer_created', 'peer_deleted', 'peer_updated']
@@ -40,7 +40,7 @@ class WebHookSessionLogs(BaseModel):
class DashboardWebHooks: class DashboardWebHooks:
def __init__(self, DashboardConfig): def __init__(self, DashboardConfig):
self.engine = db.create_engine(ConnectionString("wgdashboard")) self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData() self.metadata = db.MetaData()
self.webHooksTable = db.Table( self.webHooksTable = db.Table(
'DashboardWebHooks', self.metadata, 'DashboardWebHooks', self.metadata,
@@ -201,7 +201,7 @@ class DashboardWebHooks:
class WebHookSession: class WebHookSession:
def __init__(self, webHook: WebHook, data: dict[str, str]): def __init__(self, webHook: WebHook, data: dict[str, str]):
self.engine = db.create_engine(ConnectionString("wgdashboard")) self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData() self.metadata = db.MetaData()
self.webHookSessionsTable = db.Table('DashboardWebHookSessions', self.metadata, autoload_with=self.engine) self.webHookSessionsTable = db.Table('DashboardWebHookSessions', self.metadata, autoload_with=self.engine)
self.webHook = webHook self.webHook = webHook

View File

@@ -2,7 +2,7 @@ import uuid
from pydantic import BaseModel, field_serializer from pydantic import BaseModel, field_serializer
import sqlalchemy as db import sqlalchemy as db
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_db
class NewConfigurationTemplate(BaseModel): class NewConfigurationTemplate(BaseModel):
@@ -14,7 +14,7 @@ class NewConfigurationTemplate(BaseModel):
class NewConfigurationTemplates: class NewConfigurationTemplates:
def __init__(self): def __init__(self):
self.engine = db.create_engine(ConnectionString("wgdashboard")) self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData() self.metadata = db.MetaData()
self.templatesTable = db.Table( self.templatesTable = db.Table(
'NewConfigurationTemplates', self.metadata, 'NewConfigurationTemplates', self.metadata,

View File

@@ -4,12 +4,12 @@ Peer Job Logger
import uuid import uuid
import sqlalchemy as db import sqlalchemy as db
from flask import current_app from flask import current_app
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_log_db
from .Log import Log from .Log import Log
class PeerJobLogger: class PeerJobLogger:
def __init__(self, AllPeerJobs, DashboardConfig): def __init__(self, AllPeerJobs, DashboardConfig):
self.engine = db.create_engine(ConnectionString("wgdashboard_log")) self.engine = db.create_engine(ConnectionString(default_log_db))
self.metadata = db.MetaData() self.metadata = db.MetaData()
self.jobLogTable = db.Table('JobLog', self.metadata, self.jobLogTable = db.Table('JobLog', self.metadata,
db.Column('LogID', db.String(255), nullable=False, primary_key=True), db.Column('LogID', db.String(255), nullable=False, primary_key=True),

View File

@@ -1,7 +1,7 @@
""" """
Peer Jobs Peer Jobs
""" """
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_job_db
from .PeerJob import PeerJob from .PeerJob import PeerJob
from .PeerJobLogger import PeerJobLogger from .PeerJobLogger import PeerJobLogger
import sqlalchemy as db import sqlalchemy as db
@@ -11,7 +11,7 @@ from flask import current_app
class PeerJobs: class PeerJobs:
def __init__(self, DashboardConfig, WireguardConfigurations): def __init__(self, DashboardConfig, WireguardConfigurations):
self.Jobs: list[PeerJob] = [] self.Jobs: list[PeerJob] = []
self.engine = db.create_engine(ConnectionString('wgdashboard_job')) self.engine = db.create_engine(ConnectionString(default_job_db))
self.metadata = db.MetaData() self.metadata = db.MetaData()
self.peerJobTable = db.Table('PeerJobs', self.metadata, self.peerJobTable = db.Table('PeerJobs', self.metadata,
db.Column('JobID', db.String(255), nullable=False, primary_key=True), db.Column('JobID', db.String(255), nullable=False, primary_key=True),
@@ -141,7 +141,7 @@ class PeerJobs:
def runJob(self): def runJob(self):
current_app.logger.info("Running scheduled jobs") current_app.logger.debug("Running scheduled jobs")
needToDelete = [] needToDelete = []
self.__getJobs() self.__getJobs()
for job in self.Jobs: for job in self.Jobs:

View File

@@ -1,4 +1,4 @@
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_db
from .PeerShareLink import PeerShareLink from .PeerShareLink import PeerShareLink
import sqlalchemy as db import sqlalchemy as db
from datetime import datetime from datetime import datetime
@@ -10,7 +10,7 @@ Peer Share Links
class PeerShareLinks: class PeerShareLinks:
def __init__(self, DashboardConfig, WireguardConfigurations): def __init__(self, DashboardConfig, WireguardConfigurations):
self.Links: list[PeerShareLink] = [] self.Links: list[PeerShareLink] = []
self.engine = db.create_engine(ConnectionString("wgdashboard")) self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData() self.metadata = db.MetaData()
self.peerShareLinksTable = db.Table( self.peerShareLinksTable = db.Table(
'PeerShareLinks', self.metadata, 'PeerShareLinks', self.metadata,

View File

@@ -10,7 +10,7 @@ from datetime import datetime, timedelta
from itertools import islice from itertools import islice
from flask import current_app from flask import current_app
from .ConnectionString import ConnectionString from .ConnectionString import ConnectionString, default_db
from .DashboardConfig import DashboardConfig from .DashboardConfig import DashboardConfig
from .Peer import Peer from .Peer import Peer
from .PeerJobs import PeerJobs from .PeerJobs import PeerJobs
@@ -64,7 +64,7 @@ class WireguardConfiguration:
self.AllPeerShareLinks = AllPeerShareLinks self.AllPeerShareLinks = AllPeerShareLinks
self.DashboardWebHooks = DashboardWebHooks self.DashboardWebHooks = DashboardWebHooks
self.configPath = os.path.join(self.__getProtocolPath(), f'{self.Name}.conf') self.configPath = os.path.join(self.__getProtocolPath(), f'{self.Name}.conf')
self.engine: sqlalchemy.Engine = sqlalchemy.create_engine(ConnectionString("wgdashboard")) self.engine: sqlalchemy.Engine = sqlalchemy.create_engine(ConnectionString(default_db))
self.metadata: sqlalchemy.MetaData = sqlalchemy.MetaData() self.metadata: sqlalchemy.MetaData = sqlalchemy.MetaData()
self.dbType = self.DashboardConfig.GetConfig("Database", "type")[1] self.dbType = self.DashboardConfig.GetConfig("Database", "type")[1]
@@ -396,7 +396,7 @@ class WireguardConfiguration:
def getPeers(self): def getPeers(self):
tmpList = [] tmpList = []
current_app.logger.info(f"Refreshing {self.Name} peer list") current_app.logger.debug(f"Refreshing {self.Name} peer list")
if self.configurationFileChanged(): if self.configurationFileChanged():
with open(self.configPath, 'r') as configFile: with open(self.configPath, 'r') as configFile:
@@ -405,7 +405,7 @@ class WireguardConfiguration:
content = configFile.read().split('\n') content = configFile.read().split('\n')
try: try:
if "[Peer]" not in content: if "[Peer]" not in content:
current_app.logger.info(f"{self.Name} config has no [Peer] section") current_app.logger.debug(f"{self.Name} config has no [Peer] section")
return return
peerStarts = content.index("[Peer]") peerStarts = content.index("[Peer]")

File diff suppressed because it is too large Load Diff

View File

@@ -26,15 +26,15 @@
"electron-builder": "^26.0.12", "electron-builder": "^26.0.12",
"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": "^6.0.0",
"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",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"qrcodejs": "^1.0.0", "qrcodejs": "^1.0.0",
"simple-code-editor": "^2.0.9", "simple-code-editor": "^2.0.9",
"uuid": "^11.1.0", "uuid": "^13.0.0",
"vue": "^3.5.17", "vue": "^3.5.17",
"vue-chartjs": "^5.3.0", "vue-chartjs": "^5.3.0",
"vue-router": "^4.2.5" "vue-router": "^4.2.5"

View File

@@ -114,7 +114,7 @@ const data = computed(() => {
</h6> </h6>
</div> </div>
<div class="progress" role="progressbar" style="height: 6px"> <div class="progress" role="progressbar" style="height: 6px">
<div class="progress-bar bg-warning" :style="{width: `$ data?.Memory.SwapMemory.percent}%` }"></div> <div class="progress-bar bg-warning" :style="{width: `${data?.Memory.SwapMemory.percent}%` }"></div>
</div> </div>
</div> </div>
</div> </div>

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"