chore: make the config lowercase and add new routes

This commit is contained in:
DaanSelen
2026-03-16 16:52:00 +01:00
parent f898f8ae3c
commit 799b8bd2d2
47 changed files with 237 additions and 346 deletions
+36 -36
View File
@@ -1,4 +1,4 @@
[Peers] [peers]
remote_endpoint = 89.20.90.254 remote_endpoint = 89.20.90.254
peer_global_dns = 9.9.9.9 peer_global_dns = 9.9.9.9
peer_endpoint_allowed_ip = 0.0.0.0/0 peer_endpoint_allowed_ip = 0.0.0.0/0
@@ -6,59 +6,59 @@ peer_display_mode = grid
peer_mtu = 1420 peer_mtu = 1420
peer_keep_alive = 21 peer_keep_alive = 21
[Server] [server]
hostname = 0.0.0.0 hostname = 0.0.0.0
port = 10086 port = 10086
debug_enabled = True debug_enabled = True
wg_conf_path = /etc/wireguard wg_conf_path = /etc/wireguard
awg_conf_path = /etc/amnezia/amneziawg awg_conf_path = /etc/amnezia/amneziawg
app_prefix = app_prefix =
authentication_required = True authentication_required = True
version = v5.0.0 version = v5.0.0
wgdashboard_refresh_interval = 60000 wgdashboard_refresh_interval = 60000
wgdashboard_peer_list_display = grid wgdashboard_peer_list_display = grid
wgdashboard_sort = status wgdashboard_sort = status
wgdashboard_theme = dark wgdashboard_theme = dark
wgdashboard_apikey = true wgdashboard_apikey = True
#wgdashboard_language = nl-NL
wgdashboard_language = en-US wgdashboard_language = en-US
log_level = DEBUG log_level = DEBUG
[Account] [account]
username = admin username = dselen
password = $2b$12$1VN62Q7CS/BJcAahHAWsA.3CD6zPqWTmE/HN/AJqwP0zds2l25Fqe password = $2b$12$bUcVL2v0OoJnraXtx.mHsOKFRnKEf/kmewqKXHOebitDZcJviPusm
enable_totp = false enable_totp = False
totp_verified = false totp_verified = False
totp_key = ZSI2Z4QHSGVAK6TFVMZXORFDWKHDN4TQ totp_key = CEBHHGL4HLYUDYXKTLIL34SVLXYPVHIO
[Other] [other]
welcome_session = false welcome_session = False
[Database] [database]
type = sqlite type = sqlite
host = host =
port = port =
username = username =
password = password =
[Email] [email]
server = server =
port = port =
encryption = encryption =
username = username =
email_password = email_password =
authentication_required = true authentication_required = True
send_from = send_from =
email_template = email_template =
[OIDC] [oidc]
admin_enable = false admin_enable = False
client_enable = false client_enable = False
[Clients] [clients]
enable = true enable = True
sign_up = true sign_up = True
[wireguardconfiguration]
autostart =
peer_tracking = False
[WireGuardConfiguration]
autostart =
peer_tracking = false
+7 -5
View File
@@ -15,20 +15,21 @@ from modules.utilities.utilities import utilities as util
from modules.utilities.logger import setup_logger from modules.utilities.logger import setup_logger
from modules.routes.routes import routes from modules.routes.routes import routes
from modules.routes.routes_welcome import routes_welcome
if __name__ == '__main__': if __name__ == '__main__':
# Read the config file (ini) # Read the config file (ini)
ok, config_contents = config.read() ok, config_data = config.read()
if not ok: if not ok:
exit(1) exit(1)
found, config_server = config.filter(config_contents, 'SERVER') found, config_server = config.filter(config_data, 'SERVER')
# Configure the loglevel of WGDashboard # Configure the loglevel of WGDashboard
wanted_loglevel = config_server.get('log_level', 'DEBUG').upper() wanted_loglevel = config_server.get('log_level', 'DEBUG').upper()
setup_logger(wanted_loglevel) setup_logger(wanted_loglevel)
# Get the database configuration from thee config # Get the database configuration from thee config
found, config_database = config.filter(config_contents, 'DATABASE') found, config_database = config.filter(config_data, 'DATABASE')
if not found: if not found:
exit(1) exit(1)
@@ -40,13 +41,14 @@ if __name__ == '__main__':
# Configure the Flask app # Configure the Flask app
app = flask.Flask("WGDashboard", app = flask.Flask("WGDashboard",
static_url_path="", static_url_path=prefix,
template_folder=os.path.abspath("./static/dist/WGDashboardAdmin"), template_folder=os.path.abspath("./static/dist/WGDashboardAdmin"),
static_folder=os.path.abspath("./static/dist/WGDashboardAdmin") static_folder=os.path.abspath("./static/dist/WGDashboardAdmin")
) )
app.register_blueprint(routes, url_prefix=prefix) app.register_blueprint(routes, url_prefix=prefix)
app.register_blueprint(routes_welcome, url_prefix=prefix)
app.wgd_config = config_contents app.wgd_config = config_data
app.locale_path = './static/locales/' app.locale_path = './static/locales/'
app.secret_key = secrets.token_urlsafe(64) app.secret_key = secrets.token_urlsafe(64)
+37 -12
View File
@@ -1,19 +1,24 @@
#!/bin/env python3 #!/bin/env python3
import logging as log import logging as log
import flask
from .utilities import config_utilities from .config_utils import config_utils
class config(): class config():
@staticmethod @staticmethod
def filter(config_contents: dict, filter_keyword: str) -> tuple[bool, dict]: def filter(config_data: dict, filter_keyword: str) -> tuple[bool, dict]:
''' '''
Helper function to grab a specific part of the config Helper function to grab a specific part of the config
''' '''
for section_name, section_values in config_contents.items(): lower_filter_keyword = filter_keyword.lower()
if str(section_name).lower() == filter_keyword.lower():
for section_name, section_values in config_data.items():
if str(section_name).lower() == lower_filter_keyword:
if isinstance(section_values, dict): if isinstance(section_values, dict):
return True, dict(section_values) return True, dict(section_values)
log.error("failed to properly filter the config")
return False, {} return False, {}
@staticmethod @staticmethod
@@ -22,17 +27,37 @@ class config():
check some basic things and then return the dict containing the config data check some basic things and then return the dict containing the config data
''' '''
ok, candidate_path = config_utilities.search_known_paths() ok, candidate_path = config_utils.search_known_paths()
if not ok: if not ok:
log.error("failed to retrieve a valid path for the config")
return False, {} return False, {}
ok, config_contents = config_utilities.verify_contents(candidate_path)
ok, config_data = config_utils.read_data(candidate_path)
if not ok: if not ok:
return False, {} return False, {}
return True, config_contents return True, config_data
@staticmethod @staticmethod
def update(section: str, key: str, value: str) -> bool: def update(target_section: str, target_key: str, new_value) -> bool:
print(config_utilities.search_known_paths()) lower_target_section = target_section.lower()
print(section, key, value) lower_target_key = target_key.lower()
return True
ok, config_data = config.read()
if not ok:
log.error("failed to read the config succesfully")
return False
if not config_utils.find_section(config_data, lower_target_section):
log.error("failed to find the given section")
return False
if not config_utils.find_key(config_data, lower_target_section, lower_target_key):
log.error("failed to find the given key in the given section")
return False
ok = config_utils.write_key(config_data, lower_target_section, lower_target_key, new_value)
if not ok:
log.error("failed to write the key to the file")
return False
return True
-69
View File
@@ -1,69 +0,0 @@
#!/bin/env python3
import logging as log
import configparser as cp
import os
class config_utilities():
@staticmethod
def search_known_paths() -> tuple[bool, str]:
'''
Look at predefined paths on the filesystem for a config file
'''
possible_config_locations = [
"./config.ini",
f"{os.getenv('HOME')}/.config/wgdashboard/config.ini",
"/etc/wgdashboard/config.ini",
]
try:
for path in possible_config_locations:
if os.path.exists(path):
return True, path
else:
continue
return False, ''
except Exception as err:
return False, ''
@staticmethod
def verify_contents(config_path: str) -> tuple[bool, dict]:
'''
Check the existing config file for contents
'''
config = cp.ConfigParser()
try:
config.read(config_path)
if len(config.sections()) == 0:
return False, {}
for section in config.sections():
if len(config.items(section)) == 0:
config.remove_section(section)
config_dict = {}
for section in config.sections():
items = dict(config.items(section))
for key, value in items.items():
if value.strip().lower() == 'true':
items[key] = True
elif value.strip().lower() == 'false':
items[key] = False
else:
items[key] = value
config_dict[section] = items
return True, config_dict
except cp.ParsingError as err:
return False, {}
except Exception as err:
return False, {}
+2 -2
View File
@@ -6,12 +6,12 @@ import sqlalchemy
import sqlalchemy.orm import sqlalchemy.orm
from .schema import Base from .schema import Base
from .utilities import checks from .database_utils import database_utils
class database(): class database():
@staticmethod @staticmethod
def create_session(database_config: dict) -> tuple[bool, sqlalchemy.engine.Engine | None, sqlalchemy.orm.Session | None]: def create_session(database_config: dict) -> tuple[bool, sqlalchemy.engine.Engine | None, sqlalchemy.orm.Session | None]:
ok, connection_string = checks.generate_connection_string(database_config) ok, connection_string = database_utils.generate_connection_string(database_config)
if not ok: if not ok:
return False, None, None return False, None, None
+6 -3
View File
@@ -6,7 +6,7 @@ import sqlalchemy.orm
import json import json
from .schema import Base from .schema import Base
from .schema import Apikeys from .schema import Apikeys, User
class functions(): class functions():
@staticmethod @staticmethod
@@ -63,5 +63,8 @@ class functions():
return valid_keys, expired_keys return valid_keys, expired_keys
@staticmethod @staticmethod
def retrieve_users(session: sqlalchemy.orm.Session): def retrieve_user_objects(session: sqlalchemy.orm.Session) -> list[dict]:
print("Wanting to check users") stored_users = session.query(User).all()
for user in stored_users:
print(user)
+1 -1
View File
@@ -17,7 +17,7 @@ class User(Base):
totp_enabled = sqlalchemy.Column(sqlalchemy.Boolean, default=False) totp_enabled = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
totp_verified = sqlalchemy.Column(sqlalchemy.Boolean, default=False) totp_verified = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
totp_key = sqlalchemy.Column(sqlalchemy.String) totp_secret = sqlalchemy.Column(sqlalchemy.String)
email = sqlalchemy.Column(sqlalchemy.String) email = sqlalchemy.Column(sqlalchemy.String)
-45
View File
@@ -1,45 +0,0 @@
#!/bin/env python3
import logging as log
import os
from urllib.parse import quote_plus
from modules.utilities.utilities import utilities as util
class checks():
'''
This class functions as a collection of function to prepare a connection to a database.
'''
@staticmethod
def generate_connection_string(database_config: dict) -> tuple[bool, str]:
if not 'type' in database_config:
return False, ''
username = quote_plus(database_config.get('username', ''))
password = quote_plus(database_config.get('password', ''))
match database_config['type']:
case 'sqlite':
local_database_path = os.path.abspath("./database")
exists = util.ensure_directory(local_database_path)
if exists:
connection_string = f'sqlite:///{local_database_path}/wgdashboard.db'
else:
return False, ''
case 'postgresql' | 'postgres':
connection_string = f'postgresql+psycopg://{username}:{password}@{database_config.get('host', 'localhost')}:{database_config.get('port', '5432')}'
case 'mariadb':
connection_string = f'mariadb+mariadbconnector://{username}:{password}@{database_config.get('host', 'localhost')}:{database_config.get('port', '3306')}'
case 'mysql':
connection_string = f'mysql+pymysql://{username}:{password}@{database_config.get('host', 'localhost')}:{database_config.get('port', '3306')}'
case _:
return False, ''
return True, connection_string
+34 -31
View File
@@ -11,7 +11,7 @@ import werkzeug
from datetime import datetime from datetime import datetime
from .response import make_resp_obj from .response import make_resp_obj
from .utilities import helpers from .routes_utils import routes_utils
from .locale import localeman from .locale import localeman
from ..database.functions import functions from ..database.functions import functions
@@ -20,19 +20,10 @@ from ..config.config import config
routes = flask.Blueprint("routes", __name__) routes = flask.Blueprint("routes", __name__)
white_list = [ white_list = [
"/", # we need to whitelist / "/", "/client", "/static/", "/fileDownload",
"/client", "/api/authenticate", "/api/locale", "getDashboardConfiguration",
"/static/", "getDashboardTheme", "getDashboardVersion", "sharePeer/get",
"/fileDownload", "isTotpEnabled", "validateAuthentication", "favicon.ico",
"/api/authenticate",
"/api/locale",
"getDashboardConfiguration",
"getDashboardTheme",
"getDashboardVersion",
"sharePeer/get",
"isTotpEnabled",
"validateAuthentication",
"favicon.ico",
] ]
@routes.before_request @routes.before_request
@@ -42,6 +33,7 @@ def authentication_required():
ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER')
if not ok: if not ok:
log.error("failed to filter the config in-memory")
return make_resp_obj(False, "Internal error", {}, 500) return make_resp_obj(False, "Internal error", {}, 500)
auth_required_flag = config_server.get('auth_req', True) auth_required_flag = config_server.get('auth_req', True)
@@ -54,7 +46,7 @@ def authentication_required():
api_key = flask.request.headers.get("wgdashboard-apikey") api_key = flask.request.headers.get("wgdashboard-apikey")
if api_key and api_key_enabled: if api_key and api_key_enabled:
if helpers.is_valid_api_key(api_key): if routes_utils.is_valid_api_key(api_key):
return return
else: else:
return make_resp_obj(False, "WGDashboard API-key does not exist or is invalid/expired", {}, 401) return make_resp_obj(False, "WGDashboard API-key does not exist or is invalid/expired", {}, 401)
@@ -62,7 +54,7 @@ def authentication_required():
if flask.session.get("role") == "admin": if flask.session.get("role") == "admin":
return return
if helpers.is_path_allowed(path, white_list, flask.session): if routes_utils.is_path_allowed(path, white_list, flask.session):
return return
return make_resp_obj(False, "Unauthorized access", {}, 401) return make_resp_obj(False, "Unauthorized access", {}, 401)
@@ -71,6 +63,7 @@ def authentication_required():
def api_authenticate(): def api_authenticate():
ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER')
if not ok: if not ok:
log.error("failed to filter the config in-memory")
return make_resp_obj(False, "Internal error", {}, 500) return make_resp_obj(False, "Internal error", {}, 500)
auth_required_flag = config_server.get('authentication_required', True) auth_required_flag = config_server.get('authentication_required', True)
@@ -79,23 +72,25 @@ def api_authenticate():
if not auth_required_flag: if not auth_required_flag:
ok, config_other = config.filter(flask.current_app.wgd_config, 'OTHER') ok, config_other = config.filter(flask.current_app.wgd_config, 'OTHER')
if not ok: if not ok:
log.error("failed to filter the config in-memory")
return make_resp_obj(False, "Internal error", {}, 500) return make_resp_obj(False, "Internal error", {}, 500)
return make_resp_obj(True, "Login successful, no authentication required", {"welcome_session": config_other.get("welcome_session", False)}, 200) welcome_session_enabled = config_other.get("welcome_session", False)
return make_resp_obj(True, "Login successful, no authentication required", {"welcome_session": welcome_session_enabled}, 200)
# API key authentication # API key authentication
api_key = flask.request.headers.get("wgdashboard-apikey") given_api_key = flask.request.headers.get("wgdashboard-apikey")
api_key_enabled = config_server.get("wgdashboard_apikey", False) api_key_enabled = config_server.get("wgdashboard_apikey", False)
if api_key and api_key_enabled: if given_api_key and api_key_enabled:
if helpers.is_valid_api_key(api_key): if routes_utils.is_valid_api_key(given_api_key):
auth_token = hashlib.sha256(f"{api_key}{datetime.now()}".encode()).hexdigest() authentication_token = hashlib.sha256(f"{given_api_key}{datetime.now()}".encode()).hexdigest()
flask.session['role'] = 'admin' flask.session['role'] = 'admin'
flask.session['username'] = auth_token flask.session['username'] = authentication_token
resp = make_resp_obj(True,"Login successful", {}, 200) resp = make_resp_obj(True,"Login successful", {}, 200)
resp.set_cookie("authToken", auth_token) resp.set_cookie("authToken", authentication_token)
flask.session.permanent = True flask.session.permanent = True
return resp return resp
else: else:
@@ -104,15 +99,19 @@ def api_authenticate():
# Load account config # Load account config
ok, config_account = config.filter(flask.current_app.wgd_config, 'ACCOUNT') ok, config_account = config.filter(flask.current_app.wgd_config, 'ACCOUNT')
if not ok: if not ok:
log.error("failed to filter the config in-memory")
return make_resp_obj(False, "Internal error", {}, 500) return make_resp_obj(False, "Internal error", {}, 500)
data = flask.request.get_json() req_data = flask.request.get_json()
if not data: if not req_data:
return make_resp_obj(False, "Invalid request body", {}, 400) return make_resp_obj(False, "Invalid request body", {}, 400)
username = data.get("username") username = req_data.get("username")
password = data.get("password") password = req_data.get("password")
totp_code = data.get("totp") totp_code = req_data.get("totp")
#stored_user_objects = functions.retrieve_user_objects(flask.current_app.db_session)
#print(stored_user_objects)
stored_username = config_account.get("username") stored_username = config_account.get("username")
stored_password = config_account.get("password") stored_password = config_account.get("password")
@@ -136,10 +135,10 @@ def api_authenticate():
and ((totp_enabled and totp_valid) or not totp_enabled) and ((totp_enabled and totp_valid) or not totp_enabled)
): ):
# Generate a session token # Generate a session token
auth_token = hashlib.sha256(f"{username}{datetime.now()}".encode()).hexdigest() authentication_token = hashlib.sha256(f"{username}{datetime.now()}".encode()).hexdigest()
flask.session['role'] = 'admin' flask.session['role'] = 'admin'
flask.session['username'] = auth_token flask.session['username'] = authentication_token
flask.session.permanent = True flask.session.permanent = True
# Log success via your helper if available # Log success via your helper if available
@@ -149,7 +148,7 @@ def api_authenticate():
welcome_msg = config_other.get("welcome_session", "Welcome back!") if ok else "Welcome!" welcome_msg = config_other.get("welcome_session", "Welcome back!") if ok else "Welcome!"
resp = make_resp_obj(True, {"status": True}, 200) resp = make_resp_obj(True, {"status": True}, 200)
resp.set_cookie("authToken", auth_token, httponly=True, samesite='Lax') resp.set_cookie("authToken", authentication_token, httponly=True, samesite='Lax')
return resp return resp
# Log failure # Log failure
@@ -188,6 +187,7 @@ def api_locale_handler():
def api_validate_auth(): def api_validate_auth():
ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER')
if not ok: if not ok:
log.error("failed to filter the config in-memory")
return make_resp_obj(False, 'Internal error', {}, 500) return make_resp_obj(False, 'Internal error', {}, 500)
auth_required_flag = config_server.get('auth_req', True) auth_required_flag = config_server.get('auth_req', True)
@@ -202,6 +202,7 @@ def api_validate_auth():
def api_retrieve_dashboard_version(): def api_retrieve_dashboard_version():
ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER')
if not ok: if not ok:
log.error("failed to filter the config in-memory")
return make_resp_obj(False, 'Internal error', {}, 500) return make_resp_obj(False, 'Internal error', {}, 500)
return make_resp_obj(True, "", config_server.get("version")) return make_resp_obj(True, "", config_server.get("version"))
@@ -210,6 +211,7 @@ def api_retrieve_dashboard_version():
def api_retrieve_dashboard_theme(): def api_retrieve_dashboard_theme():
ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER')
if not ok: if not ok:
log.error("failed to filter the config in-memory")
return make_resp_obj(False, 'Internal error', {}, 500) return make_resp_obj(False, 'Internal error', {}, 500)
return make_resp_obj(True, "", config_server.get("wgdashboard_theme"), 200) return make_resp_obj(True, "", config_server.get("wgdashboard_theme"), 200)
@@ -222,6 +224,7 @@ def api_retrieve_dashboard_config():
def api_totp_status(): def api_totp_status():
ok, config_account = config.filter(flask.current_app.wgd_config, 'ACCOUNT') ok, config_account = config.filter(flask.current_app.wgd_config, 'ACCOUNT')
if not ok: if not ok:
log.error("failed to filter the config in-memory")
return make_resp_obj(False, 'Internal error', {}, 500) return make_resp_obj(False, 'Internal error', {}, 500)
data = config_account.get('enable_totp') and config_account.get('totp_verified') data = config_account.get('enable_totp') and config_account.get('totp_verified')
-27
View File
@@ -1,27 +0,0 @@
#!/bin/env python3
import flask
from ..database.functions import functions
class helpers():
@staticmethod
def is_valid_api_key(api_key: str) -> bool:
valid_keys, _ = functions.retrieve_api_keys(flask.current_app.db_session)
valid_key_strings = []
for key in valid_keys:
valid_key_strings.append(key["key"])
return api_key in valid_key_strings
@staticmethod
def is_path_allowed(path: str, white_list: list[str], session_data: dict) -> bool:
# Allow if session has admin role
if session_data.get("role") == "admin" and "username" in session_data:
return True
# Check white list
for p in white_list:
if p in path:
return True
return False
-2
View File
@@ -1,2 +0,0 @@
#!/bin/env python3
+2 -1
View File
@@ -3,4 +3,5 @@ configparser==7.2.0
gunicorn==25.1.0 gunicorn==25.1.0
sqlalchemy==2.0.48 sqlalchemy==2.0.48
Flask==3.1.3 Flask==3.1.3
Werkzeug==3.1.6 Werkzeug==3.1.6
pyotp==2.9.0
+1 -1
View File
@@ -29,7 +29,7 @@ const route = useRoute()
</script> </script>
<template> <template>
<div class="h-100 bg-body" :data-bs-theme="store.Configuration?.Server.wgdashboard_theme"> <div class="h-100 bg-body" :data-bs-theme="store.Configuration?.server?.wgdashboard_theme ?? 'light'">
<div style="z-index: 9999; height: 5px" class="position-absolute loadingBar top-0 start-0"></div> <div style="z-index: 9999; height: 5px" class="position-absolute loadingBar top-0 start-0"></div>
<nav class="navbar bg-dark sticky-top" data-bs-theme="dark" v-if="!route.meta.hideTopNav"> <nav class="navbar bg-dark sticky-top" data-bs-theme="dark" v-if="!route.meta.hideTopNav">
<div class="container-fluid d-flex text-body align-items-center"> <div class="container-fluid d-flex text-body align-items-center">
@@ -8,7 +8,7 @@ import { DashboardConfigurationStore } from "@/stores/DashboardConfigurationStor
const dashboardConfigurationStore = DashboardConfigurationStore() const dashboardConfigurationStore = DashboardConfigurationStore()
const loading = ref(false) const loading = ref(false)
const values = reactive({ const values = reactive({
enableClients: dashboardConfigurationStore.Configuration.Clients.enable enableClients: dashboardConfigurationStore.Configuration.clients.enable
}) })
const toggling = ref(false) const toggling = ref(false)
@@ -17,7 +17,7 @@ const updateSettings = async (key: string) => {
await fetchPost("/api/updateDashboardConfigurationItem", { await fetchPost("/api/updateDashboardConfigurationItem", {
section: "Clients", section: "Clients",
key: key, key: key,
value: dashboardConfigurationStore.Configuration.Clients[key] value: dashboardConfigurationStore.Configuration.clients[key]
}, async (res) => { }, async (res) => {
await dashboardConfigurationStore.getConfiguration() await dashboardConfigurationStore.getConfiguration()
toggling.value = false toggling.value = false
@@ -41,11 +41,11 @@ const updateSettings = async (key: string) => {
</h6> </h6>
<div class="form-check form-switch ms-auto"> <div class="form-check form-switch ms-auto">
<label class="form-check-label" for="oidc_switch"> <label class="form-check-label" for="oidc_switch">
<LocaleText :t="dashboardConfigurationStore.Configuration.Clients.enable ? 'Enabled':'Disabled'"></LocaleText> <LocaleText :t="dashboardConfigurationStore.Configuration.clients.enable ? 'Enabled':'Disabled'"></LocaleText>
</label> </label>
<input <input
:disabled="toggling" :disabled="toggling"
v-model="dashboardConfigurationStore.Configuration.Clients.enable" v-model="dashboardConfigurationStore.Configuration.clients.enable"
@change="updateSettings('enable')" @change="updateSettings('enable')"
class="form-check-input" type="checkbox" role="switch" id="oidc_switch"> class="form-check-input" type="checkbox" role="switch" id="oidc_switch">
</div> </div>
@@ -58,11 +58,11 @@ const updateSettings = async (key: string) => {
</h6> </h6>
<div class="form-check form-switch ms-auto"> <div class="form-check form-switch ms-auto">
<label class="form-check-label" for="sign_up_switch"> <label class="form-check-label" for="sign_up_switch">
<LocaleText :t="dashboardConfigurationStore.Configuration.Clients.sign_up ? 'Enabled':'Disabled'"></LocaleText> <LocaleText :t="dashboardConfigurationStore.Configuration.clients.sign_up ? 'Enabled':'Disabled'"></LocaleText>
</label> </label>
<input <input
:disabled="toggling" :disabled="toggling"
v-model="dashboardConfigurationStore.Configuration.Clients.sign_up" v-model="dashboardConfigurationStore.Configuration.clients.sign_up"
@change="updateSettings('sign_up')" @change="updateSettings('sign_up')"
class="form-check-input" type="checkbox" role="switch" id="sign_up_switch"> class="form-check-input" type="checkbox" role="switch" id="sign_up_switch">
</div> </div>
@@ -70,7 +70,7 @@ const saveRaw = async () => {
:disabled="true" :disabled="true"
:read-only="saving" :read-only="saving"
v-model="content" v-model="content"
:theme="dashboardStore.Configuration.Server.wgdashboard_theme === 'dark' ? 'github-dark':'github'" :theme="dashboardStore.Configuration.server.wgdashboard_theme === 'dark' ? 'github-dark':'github'"
:languages="[['ini', path]]" :languages="[['ini', path]]"
width="100%" height="600px"> width="100%" height="600px">
</CodeEditor> </CodeEditor>
@@ -50,7 +50,7 @@ export default {
<div <div
style="font-size: 0.8rem; color: #28a745" style="font-size: 0.8rem; color: #28a745"
class="d-flex align-items-center" class="d-flex align-items-center"
v-if="dashboardStore.Configuration.Server.wgdashboard_peer_list_display === 'list' && Peer.status === 'running'"> v-if="dashboardStore.Configuration.server.wgdashboard_peer_list_display === 'list' && Peer.status === 'running'">
<i class="bi bi-box-arrow-in-right me-2"></i> <i class="bi bi-box-arrow-in-right me-2"></i>
<span> <span>
{{ Peer.endpoint }} {{ Peer.endpoint }}
@@ -84,8 +84,8 @@ export default {
{{Peer.name ? Peer.name : GetLocale('Untitled Peer')}} {{Peer.name ? Peer.name : GetLocale('Untitled Peer')}}
</h6> </h6>
<div class="d-flex" <div class="d-flex"
:class="[dashboardStore.Configuration.Server.wgdashboard_peer_list_display === 'grid' ? 'gap-1 flex-column' : 'flex-row gap-3']"> :class="[dashboardStore.Configuration.server.wgdashboard_peer_list_display === 'grid' ? 'gap-1 flex-column' : 'flex-row gap-3']">
<div :class="{'d-flex gap-2 align-items-center' : dashboardStore.Configuration.Server.wgdashboard_peer_list_display === 'list'}"> <div :class="{'d-flex gap-2 align-items-center' : dashboardStore.Configuration.server.wgdashboard_peer_list_display === 'list'}">
<small class="text-muted"> <small class="text-muted">
<LocaleText t="Public Key"></LocaleText> <LocaleText t="Public Key"></LocaleText>
</small> </small>
@@ -93,7 +93,7 @@ export default {
<samp>{{Peer.id}}</samp> <samp>{{Peer.id}}</samp>
</small> </small>
</div> </div>
<div :class="{'d-flex gap-2 align-items-center' : dashboardStore.Configuration.Server.wgdashboard_peer_list_display === 'list'}"> <div :class="{'d-flex gap-2 align-items-center' : dashboardStore.Configuration.server.wgdashboard_peer_list_display === 'list'}">
<small class="text-muted"> <small class="text-muted">
<LocaleText t="Allowed IPs"></LocaleText> <LocaleText t="Allowed IPs"></LocaleText>
</small> </small>
@@ -102,7 +102,7 @@ export default {
</small> </small>
</div> </div>
<div class="d-flex align-items-center gap-1" <div class="d-flex align-items-center gap-1"
:class="{'ms-auto': dashboardStore.Configuration.Server.wgdashboard_peer_list_display === 'list'}" :class="{'ms-auto': dashboardStore.Configuration.server.wgdashboard_peer_list_display === 'list'}"
> >
<PeerTagBadge :BackgroundColor="group.BackgroundColor" :GroupName="group.GroupName" :Icon="'bi-' + group.Icon" <PeerTagBadge :BackgroundColor="group.BackgroundColor" :GroupName="group.GroupName" :Icon="'bi-' + group.Icon"
v-for="group in Object.values(ConfigurationInfo.Info.PeerGroups).filter(x => x.Peers.includes(Peer.id))" v-for="group in Object.values(ConfigurationInfo.Info.PeerGroups).filter(x => x.Peers.includes(Peer.id))"
@@ -26,11 +26,11 @@ const peerData = ref({
allowed_ips: [], allowed_ips: [],
private_key: "", private_key: "",
public_key: "", public_key: "",
DNS: dashboardStore.Configuration.Peers.peer_global_dns, DNS: dashboardStore.Configuration.peers.peer_global_dns,
endpoint_allowed_ip: dashboardStore.Configuration.Peers.peer_endpoint_allowed_ip, endpoint_allowed_ip: dashboardStore.Configuration.peers.peer_endpoint_allowed_ip,
notes: "", notes: "",
keepalive: parseInt(dashboardStore.Configuration.Peers.peer_keep_alive), keepalive: parseInt(dashboardStore.Configuration.peers.peer_keep_alive),
mtu: parseInt(dashboardStore.Configuration.Peers.peer_mtu), mtu: parseInt(dashboardStore.Configuration.peers.peer_mtu),
preshared_key: "", preshared_key: "",
preshared_key_bulkAdd: false, preshared_key_bulkAdd: false,
allowed_ips_validation: true, allowed_ips_validation: true,
@@ -31,10 +31,10 @@ export default {
allowed_ips: [], allowed_ips: [],
private_key: "", private_key: "",
public_key: "", public_key: "",
DNS: this.dashboardStore.Configuration.Peers.peer_global_dns, DNS: this.dashboardStore.Configuration.peers.peer_global_dns,
endpoint_allowed_ip: this.dashboardStore.Configuration.Peers.peer_endpoint_allowed_ip, endpoint_allowed_ip: this.dashboardStore.Configuration.peers.peer_endpoint_allowed_ip,
keepalive: parseInt(this.dashboardStore.Configuration.Peers.peer_keep_alive), keepalive: parseInt(this.dashboardStore.Configuration.peers.peer_keep_alive),
mtu: parseInt(this.dashboardStore.Configuration.Peers.peer_mtu), mtu: parseInt(this.dashboardStore.Configuration.peers.peer_mtu),
preshared_key: "", preshared_key: "",
preshared_key_bulkAdd: false, preshared_key_bulkAdd: false,
}, },
@@ -186,7 +186,7 @@ export default {
} }
} }
}, },
'dashboardConfigurationStore.Configuration.Server.wgdashboard_refresh_interval'(){ 'dashboardConfigurationStore.Configuration.server.wgdashboard_refresh_interval'(){
clearInterval(this.dashboardConfigurationStore.Peers.RefreshInterval); clearInterval(this.dashboardConfigurationStore.Peers.RefreshInterval);
this.setPeerInterval(); this.setPeerInterval();
} }
@@ -282,7 +282,7 @@ export default {
setPeerInterval(){ setPeerInterval(){
this.dashboardConfigurationStore.Peers.RefreshInterval = setInterval(() => { this.dashboardConfigurationStore.Peers.RefreshInterval = setInterval(() => {
this.getPeers() this.getPeers()
}, parseInt(this.dashboardConfigurationStore.Configuration.Server.wgdashboard_refresh_interval)) }, parseInt(this.dashboardConfigurationStore.Configuration.server.wgdashboard_refresh_interval))
}, },
}, },
computed: { computed: {
@@ -405,14 +405,14 @@ export default {
x.allowed_ip.includes(this.wireguardConfigurationStore.searchString) x.allowed_ip.includes(this.wireguardConfigurationStore.searchString)
}) : this.configurationPeers; }) : this.configurationPeers;
if (this.dashboardConfigurationStore.Configuration.Server.wgdashboard_sort === "restricted"){ if (this.dashboardConfigurationStore.Configuration.server.wgdashboard_sort === "restricted"){
return result.sort((a, b) => { return result.sort((a, b) => {
if ( a[this.dashboardConfigurationStore.Configuration.Server.wgdashboard_sort] if ( a[this.dashboardConfigurationStore.Configuration.server.wgdashboard_sort]
< b[this.dashboardConfigurationStore.Configuration.Server.wgdashboard_sort] ){ < b[this.dashboardConfigurationStore.Configuration.server.wgdashboard_sort] ){
return 1; return 1;
} }
if ( a[this.dashboardConfigurationStore.Configuration.Server.wgdashboard_sort] if ( a[this.dashboardConfigurationStore.Configuration.server.wgdashboard_sort]
> b[this.dashboardConfigurationStore.Configuration.Server.wgdashboard_sort]){ > b[this.dashboardConfigurationStore.Configuration.server.wgdashboard_sort]){
return -1; return -1;
} }
return 0; return 0;
@@ -420,12 +420,12 @@ export default {
} }
return result.sort((a, b) => { return result.sort((a, b) => {
if ( a[this.dashboardConfigurationStore.Configuration.Server.wgdashboard_sort] if ( a[this.dashboardConfigurationStore.Configuration.server.wgdashboard_sort]
< b[this.dashboardConfigurationStore.Configuration.Server.wgdashboard_sort] ){ < b[this.dashboardConfigurationStore.Configuration.server.wgdashboard_sort] ){
return -1; return -1;
} }
if ( a[this.dashboardConfigurationStore.Configuration.Server.wgdashboard_sort] if ( a[this.dashboardConfigurationStore.Configuration.server.wgdashboard_sort]
> b[this.dashboardConfigurationStore.Configuration.Server.wgdashboard_sort]){ > b[this.dashboardConfigurationStore.Configuration.server.wgdashboard_sort]){
return 1; return 1;
} }
return 0; return 0;
@@ -108,7 +108,7 @@ const setFetchPeerListInterval = () => {
clearInterval(fetchPeerListInterval.value) clearInterval(fetchPeerListInterval.value)
fetchPeerListInterval.value = setInterval(async () => { fetchPeerListInterval.value = setInterval(async () => {
await fetchPeerList() await fetchPeerList()
}, parseInt(dashboardStore.Configuration.Server.wgdashboard_refresh_interval)) }, parseInt(dashboardStore.Configuration.server.wgdashboard_refresh_interval))
} }
setFetchPeerListInterval() setFetchPeerListInterval()
onBeforeUnmount(() => { onBeforeUnmount(() => {
@@ -118,7 +118,7 @@ onBeforeUnmount(() => {
}) })
watch(() => { watch(() => {
return dashboardStore.Configuration.Server.wgdashboard_refresh_interval return dashboardStore.Configuration.server.wgdashboard_refresh_interval
}, () => { }, () => {
setFetchPeerListInterval() setFetchPeerListInterval()
}) })
@@ -191,14 +191,14 @@ const searchPeers = computed(() => {
wireguardConfigurationStore.Filter.ShowAllPeersWhenHiddenTags || (!wireguardConfigurationStore.Filter.ShowAllPeersWhenHiddenTags && taggedPeers.value.includes(x.id)) wireguardConfigurationStore.Filter.ShowAllPeersWhenHiddenTags || (!wireguardConfigurationStore.Filter.ShowAllPeersWhenHiddenTags && taggedPeers.value.includes(x.id))
)); ));
if (dashboardStore.Configuration.Server.wgdashboard_sort === "restricted"){ if (dashboardStore.Configuration.server.wgdashboard_sort === "restricted"){
return result.sort((a, b) => { return result.sort((a, b) => {
if ( a[dashboardStore.Configuration.Server.wgdashboard_sort] if ( a[dashboardStore.Configuration.server.wgdashboard_sort]
< b[dashboardStore.Configuration.Server.wgdashboard_sort] ){ < b[dashboardStore.Configuration.server.wgdashboard_sort] ){
return 1; return 1;
} }
if ( a[dashboardStore.Configuration.Server.wgdashboard_sort] if ( a[dashboardStore.Configuration.server.wgdashboard_sort]
> b[dashboardStore.Configuration.Server.wgdashboard_sort]){ > b[dashboardStore.Configuration.server.wgdashboard_sort]){
return -1; return -1;
} }
return 0; return 0;
@@ -207,26 +207,26 @@ const searchPeers = computed(() => {
let re = [] let re = []
if (dashboardStore.Configuration.Server.wgdashboard_sort === 'allowed_ip'){ if (dashboardStore.Configuration.server.wgdashboard_sort === 'allowed_ip'){
re = result.sort((a, b) => { re = result.sort((a, b) => {
if ( firstAllowedIPCount(a[dashboardStore.Configuration.Server.wgdashboard_sort]) if ( firstAllowedIPCount(a[dashboardStore.Configuration.server.wgdashboard_sort])
< firstAllowedIPCount(b[dashboardStore.Configuration.Server.wgdashboard_sort]) ){ < firstAllowedIPCount(b[dashboardStore.Configuration.server.wgdashboard_sort]) ){
return -1; return -1;
} }
if ( firstAllowedIPCount(a[dashboardStore.Configuration.Server.wgdashboard_sort]) if ( firstAllowedIPCount(a[dashboardStore.Configuration.server.wgdashboard_sort])
> firstAllowedIPCount(b[dashboardStore.Configuration.Server.wgdashboard_sort])){ > firstAllowedIPCount(b[dashboardStore.Configuration.server.wgdashboard_sort])){
return 1; return 1;
} }
return 0; return 0;
}).slice(0, showPeersCount.value) }).slice(0, showPeersCount.value)
}else{ }else{
re = result.sort((a, b) => { re = result.sort((a, b) => {
if ( a[dashboardStore.Configuration.Server.wgdashboard_sort] if ( a[dashboardStore.Configuration.server.wgdashboard_sort]
< b[dashboardStore.Configuration.Server.wgdashboard_sort] ){ < b[dashboardStore.Configuration.server.wgdashboard_sort] ){
return -1; return -1;
} }
if ( a[dashboardStore.Configuration.Server.wgdashboard_sort] if ( a[dashboardStore.Configuration.server.wgdashboard_sort]
> b[dashboardStore.Configuration.Server.wgdashboard_sort]){ > b[dashboardStore.Configuration.server.wgdashboard_sort]){
return 1; return 1;
} }
return 0; return 0;
@@ -411,7 +411,7 @@ watch(() => route.query.id, (newValue) => {
</PeerSearch> </PeerSearch>
<TransitionGroup name="peerList" tag="div" class="row gx-2 gy-2 z-0 position-relative"> <TransitionGroup name="peerList" tag="div" class="row gx-2 gy-2 z-0 position-relative">
<div class="col-12" <div class="col-12"
:class="{'col-lg-6 col-xl-4': dashboardStore.Configuration.Server.wgdashboard_peer_list_display === 'grid'}" :class="{'col-lg-6 col-xl-4': dashboardStore.Configuration.server.wgdashboard_peer_list_display === 'grid'}"
:key="peer.id" :key="peer.id"
v-for="(peer, order) in searchPeers"> v-for="(peer, order) in searchPeers">
<Peer :Peer="peer" <Peer :Peer="peer"
@@ -80,7 +80,7 @@ const toggleFetchRealtimeTraffic = () => {
if (props.configurationInfo.Status){ if (props.configurationInfo.Status){
fetchRealtimeTrafficInterval.value = setInterval(() => { fetchRealtimeTrafficInterval.value = setInterval(() => {
fetchRealtimeTraffic() fetchRealtimeTraffic()
}, parseInt(dashboardStore.Configuration.Server.wgdashboard_refresh_interval)) }, parseInt(dashboardStore.Configuration.server.wgdashboard_refresh_interval))
} }
} }
@@ -92,7 +92,7 @@ watch(() => props.configurationInfo.Status, () => {
toggleFetchRealtimeTraffic() toggleFetchRealtimeTraffic()
}) })
watch(() => dashboardStore.Configuration.Server.wgdashboard_refresh_interval, () => { watch(() => dashboardStore.Configuration.server.wgdashboard_refresh_interval, () => {
toggleFetchRealtimeTraffic() toggleFetchRealtimeTraffic()
}) })
@@ -40,7 +40,7 @@ export default {
], ],
defaultContainer: "amnezia-awg", defaultContainer: "amnezia-awg",
description: this.selectedPeer.name, description: this.selectedPeer.name,
hostName: this.dashboardStore.Configuration.Peers.remote_endpoint hostName: this.dashboardStore.Configuration.peers.remote_endpoint
} }
QRCode.toCanvas( QRCode.toCanvas(
document.querySelector("#awg_vpn_qrcode"), btoa(JSON.stringify(awgQRCodeObject)), (error) => { document.querySelector("#awg_vpn_qrcode"), btoa(JSON.stringify(awgQRCodeObject)), (error) => {
@@ -151,7 +151,7 @@ export default {
:clearable="false" :clearable="false"
:disabled="!edit" :disabled="!edit"
v-if="this.job.Field === 'date'" v-if="this.job.Field === 'date'"
:dark="this.store.Configuration.Server.wgdashboard_theme === 'dark'" :dark="this.store.Configuration.server.wgdashboard_theme === 'dark'"
/> />
<input class="form-control form-control-sm form-control-dark rounded-3 flex-grow-1" <input class="form-control form-control-sm form-control-dark rounded-3 flex-grow-1"
@@ -98,7 +98,7 @@ export default {
class="btn w-100 btn-sm text-primary-emphasis bg-primary-subtle rounded-3 border-1 border-primary-subtle position-relative"> class="btn w-100 btn-sm text-primary-emphasis bg-primary-subtle rounded-3 border-1 border-primary-subtle position-relative">
<i class="bi bi-sort-up me-2"></i> <i class="bi bi-sort-up me-2"></i>
<LocaleText t="Sort By"></LocaleText> <LocaleText t="Sort By"></LocaleText>
<span class="badge text-bg-primary ms-2">{{this.sort[store.Configuration.Server.wgdashboard_sort]}}</span> <span class="badge text-bg-primary ms-2">{{this.sort[store.Configuration.server.wgdashboard_sort]}}</span>
</button> </button>
<ul class="dropdown-menu rounded-3"> <ul class="dropdown-menu rounded-3">
<li v-for="(value, key) in this.sort" > <li v-for="(value, key) in this.sort" >
@@ -108,7 +108,7 @@ export default {
</small> </small>
<small class="ms-auto"> <small class="ms-auto">
<i class="bi bi-check-circle-fill" <i class="bi bi-check-circle-fill"
v-if="store.Configuration.Server.wgdashboard_sort === key"></i> v-if="store.Configuration.server.wgdashboard_sort === key"></i>
</small> </small>
</button> </button>
</li> </li>
@@ -120,7 +120,7 @@ export default {
class="btn btn-sm w-100 text-primary-emphasis bg-primary-subtle rounded-3 border-1 border-primary-subtle position-relative"> class="btn btn-sm w-100 text-primary-emphasis bg-primary-subtle rounded-3 border-1 border-primary-subtle position-relative">
<i class="bi bi-arrow-repeat me-2"></i> <i class="bi bi-arrow-repeat me-2"></i>
<LocaleText t="Refresh Interval"></LocaleText> <LocaleText t="Refresh Interval"></LocaleText>
<span class="badge text-bg-primary ms-2">{{this.interval[store.Configuration.Server.wgdashboard_refresh_interval]}}</span> <span class="badge text-bg-primary ms-2">{{this.interval[store.Configuration.server.wgdashboard_refresh_interval]}}</span>
</button> </button>
<ul class="dropdown-menu rounded-3"> <ul class="dropdown-menu rounded-3">
<li v-for="(value, key) in this.interval" > <li v-for="(value, key) in this.interval" >
@@ -130,7 +130,7 @@ export default {
</small> </small>
<small class="ms-auto"> <small class="ms-auto">
<i class="bi bi-check-circle-fill" <i class="bi bi-check-circle-fill"
v-if="store.Configuration.Server.wgdashboard_refresh_interval === key"></i> v-if="store.Configuration.server.wgdashboard_refresh_interval === key"></i>
</small> </small>
</button> </button>
</li> </li>
@@ -140,9 +140,9 @@ export default {
<button <button
data-bs-toggle="dropdown" data-bs-toggle="dropdown"
class="btn btn-sm w-100 text-primary-emphasis bg-primary-subtle rounded-3 border-1 border-primary-subtle position-relative"> class="btn btn-sm w-100 text-primary-emphasis bg-primary-subtle rounded-3 border-1 border-primary-subtle position-relative">
<i class="bi me-2" :class="'bi-' + store.Configuration.Server.wgdashboard_peer_list_display"></i> <i class="bi me-2" :class="'bi-' + store.Configuration.server.wgdashboard_peer_list_display"></i>
<LocaleText t="Display"></LocaleText> <LocaleText t="Display"></LocaleText>
<span class="badge text-bg-primary ms-2">{{this.display[store.Configuration.Server.wgdashboard_peer_list_display]}}</span> <span class="badge text-bg-primary ms-2">{{this.display[store.Configuration.server.wgdashboard_peer_list_display]}}</span>
</button> </button>
<ul class="dropdown-menu rounded-3"> <ul class="dropdown-menu rounded-3">
<li v-for="(value, key) in this.display" > <li v-for="(value, key) in this.display" >
@@ -152,7 +152,7 @@ export default {
</small> </small>
<small class="ms-auto"> <small class="ms-auto">
<i class="bi bi-check-circle-fill" <i class="bi bi-check-circle-fill"
v-if="store.Configuration.Server.wgdashboard_peer_list_display === key"></i> v-if="store.Configuration.server.wgdashboard_peer_list_display === key"></i>
</small> </small>
</button> </button>
</li> </li>
@@ -14,7 +14,7 @@ await fetchGet("/api/email/ready", {}, (res) => {
const store = DashboardConfigurationStore() const store = DashboardConfigurationStore()
const email = reactive({ const email = reactive({
Receiver: "", Receiver: "",
Body: store.Configuration.Email.email_template, Body: store.Configuration.email.email_template,
Subject: "", Subject: "",
IncludeAttachment: false, IncludeAttachment: false,
ConfigurationName: props.selectedPeer.configuration.Name, ConfigurationName: props.selectedPeer.configuration.Name,
@@ -155,7 +155,7 @@ export default {
format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd HH:mm:ss"
preview-format="yyyy-MM-dd HH:mm:ss" preview-format="yyyy-MM-dd HH:mm:ss"
:dark="this.store.Configuration.Server.wgdashboard_theme === 'dark'" :dark="this.store.Configuration.server.wgdashboard_theme === 'dark'"
/> />
</div> </div>
<div class="d-flex gap-2 flex-column flex-sm-row"> <div class="d-flex gap-2 flex-column flex-sm-row">
+4 -4
View File
@@ -27,7 +27,7 @@ export default {
computed: { computed: {
getActiveCrossServer(){ getActiveCrossServer(){
if (this.dashboardConfigurationStore.ActiveServerConfiguration){ if (this.dashboardConfigurationStore.ActiveServerConfiguration){
return new URL(this.dashboardConfigurationStore.CrossServerConfiguration.ServerList return new URL(this.dashboardConfigurationStore.CrossServerConfiguration.serverList
[this.dashboardConfigurationStore.ActiveServerConfiguration].host) [this.dashboardConfigurationStore.ActiveServerConfiguration].host)
} }
return undefined return undefined
@@ -57,7 +57,7 @@ export default {
<template> <template>
<div class="col-md-3 col-lg-2 d-md-block p-2 navbar-container bg-transparent" <div class="col-md-3 col-lg-2 d-md-block p-2 navbar-container bg-transparent"
:class="{active: this.dashboardConfigurationStore.ShowNavBar}" :class="{active: this.dashboardConfigurationStore.ShowNavBar}"
:data-bs-theme="dashboardConfigurationStore.Configuration.Server.wgdashboard_theme" :data-bs-theme="dashboardConfigurationStore.Configuration.server.wgdashboard_theme"
> >
<nav id="sidebarMenu" class=" bg-body-tertiary sidebar border h-100 rounded-3 shadow overflow-y-scroll" > <nav id="sidebarMenu" class=" bg-body-tertiary sidebar border h-100 rounded-3 shadow overflow-y-scroll" >
<div class="sidebar-sticky "> <div class="sidebar-sticky ">
@@ -152,12 +152,12 @@ export default {
<a :href="this.updateUrl" v-if="this.updateAvailable" class="text-decoration-none rounded-3" target="_blank"> <a :href="this.updateUrl" v-if="this.updateAvailable" class="text-decoration-none rounded-3" target="_blank">
<small class="nav-link text-muted rounded-3" > <small class="nav-link text-muted rounded-3" >
<LocaleText :t="this.updateMessage"></LocaleText> <LocaleText :t="this.updateMessage"></LocaleText>
(<LocaleText t="Current Version:"></LocaleText> {{ dashboardConfigurationStore.Configuration.Server.version }}) (<LocaleText t="Current Version:"></LocaleText> {{ dashboardConfigurationStore.Configuration.server.version }})
</small> </small>
</a> </a>
<small class="nav-link text-muted rounded-3" v-else> <small class="nav-link text-muted rounded-3" v-else>
<LocaleText :t="this.updateMessage"></LocaleText> <LocaleText :t="this.updateMessage"></LocaleText>
({{ dashboardConfigurationStore.Configuration.Server.version }}) ({{ dashboardConfigurationStore.Configuration.server.version }})
</small> </small>
</li> </li>
</ul> </ul>
@@ -112,7 +112,7 @@ const uploadReady = computed(() => {
:read-only="true" :read-only="true"
:display-language="true" :display-language="true"
v-model="uploadFiles[t].content" v-model="uploadFiles[t].content"
:theme="dashboardStore.Configuration.Server.wgdashboard_theme === 'dark' ? 'github-dark':'github'" :theme="dashboardStore.Configuration.server.wgdashboard_theme === 'dark' ? 'github-dark':'github'"
:languages="[[t, uploadFiles[t].filename]]" :languages="[[t, uploadFiles[t].filename]]"
width="100%" height="500px"> width="100%" height="500px">
</CodeEditor> </CodeEditor>
@@ -42,7 +42,7 @@ export default {
if (res.status){ if (res.status){
this.isValid = true; this.isValid = true;
this.showInvalidFeedback = false; this.showInvalidFeedback = false;
this.store.Configuration.Account[this.targetData] = this.value this.store.Configuration.account[this.targetData] = this.value
clearTimeout(this.timeout) clearTimeout(this.timeout)
this.timeout = setTimeout(() => { this.timeout = setTimeout(() => {
this.isValid = false; this.isValid = false;
@@ -28,7 +28,7 @@ export default {
} }
}, },
mounted() { mounted() {
this.value = this.store.Configuration.Account[this.targetData]; this.value = this.store.Configuration.account[this.targetData];
}, },
methods:{ methods:{
async useValidation(e){ async useValidation(e){
@@ -43,7 +43,7 @@ export default {
if (res.status){ if (res.status){
this.isValid = true; this.isValid = true;
this.showInvalidFeedback = false; this.showInvalidFeedback = false;
this.store.Configuration.Account[this.targetData] = this.value this.store.Configuration.account[this.targetData] = this.value
clearTimeout(this.timeout) clearTimeout(this.timeout)
this.timeout = setTimeout(() => this.isValid = false, 5000); this.timeout = setTimeout(() => this.isValid = false, 5000);
}else{ }else{
@@ -18,7 +18,7 @@ export default {
} }
}, },
mounted() { mounted() {
this.status = this.store.Configuration.Account["enable_totp"] this.status = this.store.Configuration.account["enable_totp"]
}, },
methods: { methods: {
async resetMFA(){ async resetMFA(){
@@ -59,7 +59,7 @@ export default {
<button class="btn bg-warning-subtle text-warning-emphasis border-1 border-warning-subtle ms-auto rounded-3 shadow-sm" <button class="btn bg-warning-subtle text-warning-emphasis border-1 border-warning-subtle ms-auto rounded-3 shadow-sm"
v-if="this.status" @click="this.resetMFA()"> v-if="this.status" @click="this.resetMFA()">
<i class="bi bi-shield-lock-fill me-2"></i> <i class="bi bi-shield-lock-fill me-2"></i>
<LocaleText t="Reset" v-if='this.store.Configuration.Account["totp_verified"]'></LocaleText> <LocaleText t="Reset" v-if='this.store.Configuration.account["totp_verified"]'></LocaleText>
<LocaleText t="Setup" v-else></LocaleText> <LocaleText t="Setup" v-else></LocaleText>
MFA MFA
</button> </button>
@@ -15,7 +15,7 @@ export default {
}, },
data(){ data(){
return { return {
value: this.store.Configuration.Server.wgdashboard_apikey, value: this.store.Configuration.server.wgdashboard_apikey,
apiKeys: [], apiKeys: [],
newDashboardAPIKey: false newDashboardAPIKey: false
} }
@@ -28,11 +28,11 @@ export default {
value: this.value value: this.value
}, (res) => { }, (res) => {
if (res.status){ if (res.status){
this.store.Configuration.Peers[this.targetData] = this.value; this.store.Configuration.peers[this.targetData] = this.value;
this.store.newMessage("Server", this.store.newMessage("Server",
`API Keys function is successfully ${this.value ? 'enabled':'disabled'}`, "success") `API Keys function is successfully ${this.value ? 'enabled':'disabled'}`, "success")
}else{ }else{
this.value = this.store.Configuration.Peers[this.targetData]; this.value = this.store.Configuration.peers[this.targetData];
this.store.newMessage("Server", this.store.newMessage("Server",
`API Keys function is failed to ${this.value ? 'enabled':'disabled'}`, "danger") `API Keys function is failed to ${this.value ? 'enabled':'disabled'}`, "danger")
} }
@@ -79,7 +79,7 @@ export default {
preview-format="yyyy-MM-dd HH:mm:ss" preview-format="yyyy-MM-dd HH:mm:ss"
:clearable="false" :clearable="false"
:disabled="this.newKeyData.NeverExpire || this.submitting" :disabled="this.newKeyData.NeverExpire || this.submitting"
:dark="this.store.Configuration.Server.wgdashboard_theme === 'dark'" :dark="this.store.Configuration.server.wgdashboard_theme === 'dark'"
/> />
</div> </div>
<div class="form-check"> <div class="form-check">
@@ -13,7 +13,7 @@ onMounted(() => {
await fetchPost("/api/updateDashboardConfigurationItem", { await fetchPost("/api/updateDashboardConfigurationItem", {
section: "Email", section: "Email",
key: id, key: id,
value: store.Configuration.Email[id] value: store.Configuration.email[id]
}, (res) => { }, (res) => {
if (res.status){ if (res.status){
x.classList.remove('is-invalid') x.classList.remove('is-invalid')
@@ -74,7 +74,7 @@ const sendTestEmail = async () => {
<div class="col-12"> <div class="col-12">
<div class="form-check mb-2 form-switch"> <div class="form-check mb-2 form-switch">
<input class="form-check-input" type="checkbox" role="switch" <input class="form-check-input" type="checkbox" role="switch"
v-model="store.Configuration.Email.authentication_required" v-model="store.Configuration.email.authentication_required"
id="authentication_required"> id="authentication_required">
<label class="form-check-label" for="authentication_required"> <label class="form-check-label" for="authentication_required">
<LocaleText t="Require SMTP Authentication"></LocaleText> <LocaleText t="Require SMTP Authentication"></LocaleText>
@@ -89,7 +89,7 @@ const sendTestEmail = async () => {
</small></strong> </small></strong>
</label> </label>
<input id="server" <input id="server"
v-model="store.Configuration.Email.server" v-model="store.Configuration.email.server"
type="text" class="form-control rounded-3"> type="text" class="form-control rounded-3">
</div> </div>
</div> </div>
@@ -101,7 +101,7 @@ const sendTestEmail = async () => {
</small></strong> </small></strong>
</label> </label>
<input id="port" <input id="port"
v-model="store.Configuration.Email.port" v-model="store.Configuration.email.port"
type="text" class="form-control rounded-3"> type="text" class="form-control rounded-3">
</div> </div>
</div> </div>
@@ -113,7 +113,7 @@ const sendTestEmail = async () => {
</small></strong> </small></strong>
</label> </label>
<select class="form-select rounded-3" <select class="form-select rounded-3"
v-model="store.Configuration.Email.encryption" v-model="store.Configuration.email.encryption"
id="encryption"> id="encryption">
<option value="IMPLICITTLS"> <option value="IMPLICITTLS">
IMPLICIT TLS IMPLICIT TLS
@@ -127,7 +127,7 @@ const sendTestEmail = async () => {
</select> </select>
</div> </div>
</div> </div>
<div class="col-12 col-lg-4" v-if="store.Configuration.Email.authentication_required"> <div class="col-12 col-lg-4" v-if="store.Configuration.email.authentication_required">
<div class="form-group"> <div class="form-group">
<label for="username" class="text-muted mb-1"> <label for="username" class="text-muted mb-1">
<strong><small> <strong><small>
@@ -135,11 +135,11 @@ const sendTestEmail = async () => {
</small></strong> </small></strong>
</label> </label>
<input id="username" <input id="username"
v-model="store.Configuration.Email.username" v-model="store.Configuration.email.username"
type="text" class="form-control rounded-3"> type="text" class="form-control rounded-3">
</div> </div>
</div> </div>
<div class="col-12 col-lg-4" v-if="store.Configuration.Email.authentication_required"> <div class="col-12 col-lg-4" v-if="store.Configuration.email.authentication_required">
<div class="form-group"> <div class="form-group">
<label for="email_password" class="text-muted mb-1"> <label for="email_password" class="text-muted mb-1">
<strong><small> <strong><small>
@@ -147,7 +147,7 @@ const sendTestEmail = async () => {
</small></strong> </small></strong>
</label> </label>
<input id="email_password" <input id="email_password"
v-model="store.Configuration.Email.email_password" v-model="store.Configuration.email.email_password"
type="password" class="form-control rounded-3"> type="password" class="form-control rounded-3">
</div> </div>
</div> </div>
@@ -160,7 +160,7 @@ const sendTestEmail = async () => {
</small></strong> </small></strong>
</label> </label>
<input id="send_from" <input id="send_from"
v-model="store.Configuration.Email.send_from" v-model="store.Configuration.email.send_from"
type="text" class="form-control rounded-3"> type="text" class="form-control rounded-3">
</div> </div>
</div> </div>
@@ -201,7 +201,7 @@ const sendTestEmail = async () => {
</small> </small>
</label> </label>
<textarea class="form-control rounded-3 font-monospace" <textarea class="form-control rounded-3 font-monospace"
v-model="store.Configuration.Email.email_template" v-model="store.Configuration.email.email_template"
id="email_template" id="email_template"
style="min-height: 400px"></textarea> style="min-height: 400px"></textarea>
</div> </div>
@@ -23,8 +23,8 @@ export default {
} }
}, },
mounted() { mounted() {
this.ipAddress = this.store.Configuration.Server.app_ip this.ipAddress = this.store.Configuration.server.app_ip
this.port = this.store.Configuration.Server.app_port this.port = this.store.Configuration.server.app_port
}, },
methods: { methods: {
async useValidation(e, targetData, value){ async useValidation(e, targetData, value){
@@ -38,7 +38,7 @@ export default {
if (res.status){ if (res.status){
e.target.classList.add("is-valid") e.target.classList.add("is-valid")
this.showInvalidFeedback = false; this.showInvalidFeedback = false;
this.store.Configuration.Server[targetData] = value this.store.Configuration.server[targetData] = value
clearTimeout(this.timeout) clearTimeout(this.timeout)
this.timeout = setTimeout(() => { this.timeout = setTimeout(() => {
e.target.classList.remove("is-valid") e.target.classList.remove("is-valid")
@@ -26,7 +26,7 @@ export default {
lang_id: lang_id lang_id: lang_id
}, (res) => { }, (res) => {
if (res.status){ if (res.status){
this.store.Configuration.Server.wgdashboard_language = lang_id; this.store.Configuration.server.wgdashboard_language = lang_id;
this.store.Locale = res.data this.store.Locale = res.data
}else{ }else{
this.store.newMessage("Server", "WGDashboard language update failed", "danger") this.store.newMessage("Server", "WGDashboard language update failed", "danger")
@@ -36,7 +36,7 @@ export default {
}, },
computed:{ computed:{
currentLanguage(){ currentLanguage(){
let lang = this.store.Configuration.Server.wgdashboard_language; let lang = this.store.Configuration.server.wgdashboard_language;
return this.languages.find(x => x.lang_id === lang) return this.languages.find(x => x.lang_id === lang)
} }
} }
@@ -29,8 +29,8 @@ export default {
} }
}, },
mounted() { mounted() {
this.app_ip = this.store.Configuration.Server.app_ip; this.app_ip = this.store.Configuration.server.app_ip;
this.app_port = this.store.Configuration.Server.app_port; this.app_port = this.store.Configuration.server.app_port;
}, },
methods:{ methods:{
async useValidation(){ async useValidation(){
@@ -43,7 +43,7 @@ export default {
if (res.status){ if (res.status){
this.isValid = true; this.isValid = true;
this.showInvalidFeedback = false; this.showInvalidFeedback = false;
this.store.Configuration.Account[this.targetData] = this.value this.store.Configuration.account[this.targetData] = this.value
clearTimeout(this.timeout) clearTimeout(this.timeout)
this.timeout = setTimeout(() => this.isValid = false, 5000); this.timeout = setTimeout(() => this.isValid = false, 5000);
}else{ }else{
@@ -32,7 +32,7 @@ export default {
} }
}, },
mounted() { mounted() {
this.value = this.store.Configuration.Server[this.targetData]; this.value = this.store.Configuration.server[this.targetData];
}, },
methods:{ methods:{
async useValidation(){ async useValidation(){
@@ -46,7 +46,7 @@ export default {
if (res.status){ if (res.status){
this.isValid = true; this.isValid = true;
this.showInvalidFeedback = false; this.showInvalidFeedback = false;
this.store.Configuration.Account[this.targetData] = this.value this.store.Configuration.account[this.targetData] = this.value
clearTimeout(this.timeout) clearTimeout(this.timeout)
this.timeout = setTimeout(() => this.isValid = false, 5000); this.timeout = setTimeout(() => this.isValid = false, 5000);
this.WireguardConfigurationStore.getConfigurations() this.WireguardConfigurationStore.getConfigurations()
@@ -6,7 +6,7 @@ import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStor
import {fetchPost} from "@/utilities/fetch.js"; import {fetchPost} from "@/utilities/fetch.js";
const store = DashboardConfigurationStore() const store = DashboardConfigurationStore()
const wireguardConfigurationStore = WireguardConfigurationsStore() const wireguardConfigurationStore = WireguardConfigurationsStore()
const data = ref(store.Configuration.WireGuardConfiguration.autostart) const data = ref(store.Configuration.wireguardconfiguration.autostart)
const configurations = computed(() => { const configurations = computed(() => {
return wireguardConfigurationStore.Configurations.map(x => x.Name) return wireguardConfigurationStore.Configurations.map(x => x.Name)
@@ -18,7 +18,7 @@ export default {
value: value value: value
}, (res) => { }, (res) => {
if (res.status){ if (res.status){
this.dashboardConfigurationStore.Configuration.Server.wgdashboard_theme = value; this.dashboardConfigurationStore.Configuration.server.wgdashboard_theme = value;
} }
}); });
} }
@@ -36,13 +36,13 @@ export default {
<div class="d-flex gap-1"> <div class="d-flex gap-1">
<button class="btn bg-primary-subtle text-primary-emphasis flex-grow-1" <button class="btn bg-primary-subtle text-primary-emphasis flex-grow-1"
@click="this.switchTheme('light')" @click="this.switchTheme('light')"
:class="{active: this.dashboardConfigurationStore.Configuration.Server.wgdashboard_theme === 'light'}"> :class="{active: this.dashboardConfigurationStore.Configuration.server.wgdashboard_theme === 'light'}">
<i class="bi bi-sun-fill me-2"></i> <i class="bi bi-sun-fill me-2"></i>
<LocaleText t="Light"></LocaleText> <LocaleText t="Light"></LocaleText>
</button> </button>
<button class="btn bg-primary-subtle text-primary-emphasis flex-grow-1" <button class="btn bg-primary-subtle text-primary-emphasis flex-grow-1"
@click="this.switchTheme('dark')" @click="this.switchTheme('dark')"
:class="{active: this.dashboardConfigurationStore.Configuration.Server.wgdashboard_theme === 'dark'}"> :class="{active: this.dashboardConfigurationStore.Configuration.server.wgdashboard_theme === 'dark'}">
<i class="bi bi-moon-fill me-2"></i> <i class="bi bi-moon-fill me-2"></i>
<LocaleText t="Dark"></LocaleText> <LocaleText t="Dark"></LocaleText>
</button> </button>
@@ -10,7 +10,7 @@ import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.
const store = WireguardConfigurationsStore() const store = WireguardConfigurationsStore()
const dashboardStore = DashboardConfigurationStore() const dashboardStore = DashboardConfigurationStore()
const peerTrackingStatus = ref(dashboardStore.Configuration.WireGuardConfiguration.peer_tracking) const peerTrackingStatus = ref(dashboardStore.Configuration.wireguardconfiguration.peer_tracking)
const loaded = ref(false) const loaded = ref(false)
const trackingData = ref({}) const trackingData = ref({})
onMounted(async () => { onMounted(async () => {
@@ -29,7 +29,7 @@ export default {
} }
}, },
mounted() { mounted() {
this.value = this.store.Configuration.Peers[this.targetData]; this.value = this.store.Configuration.peers[this.targetData];
}, },
methods:{ methods:{
async useValidation(){ async useValidation(){
@@ -42,7 +42,7 @@ export default {
if (res.status){ if (res.status){
this.isValid = true; this.isValid = true;
this.showInvalidFeedback = false; this.showInvalidFeedback = false;
this.store.Configuration.Peers[this.targetData] = this.value this.store.Configuration.peers[this.targetData] = this.value
clearTimeout(this.timeout) clearTimeout(this.timeout)
this.timeout = setTimeout(() => this.isValid = false, 5000); this.timeout = setTimeout(() => this.isValid = false, 5000);
@@ -63,7 +63,7 @@ export default {
<template> <template>
<div class="container-fluid login-container-fluid d-flex main pt-5 overflow-scroll" <div class="container-fluid login-container-fluid d-flex main pt-5 overflow-scroll"
:data-bs-theme="this.store.Configuration.Server.wgdashboard_theme"> :data-bs-theme="this.store.Configuration.server.wgdashboard_theme">
<div class="m-auto text-body" style="width: 500px"> <div class="m-auto text-body" style="width: 500px">
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<div> <div>
@@ -28,12 +28,12 @@ export default {
</div> </div>
<div class="w-100 d-flex gap-3 flex-column p-3 border border-1 border-secondary-subtle rounded-3" <div class="w-100 d-flex gap-3 flex-column p-3 border border-1 border-secondary-subtle rounded-3"
style="height: 400px; overflow-y: scroll"> style="height: 400px; overflow-y: scroll">
<RemoteServer v-for="(server, key) in this.store.CrossServerConfiguration.ServerList" <RemoteServer v-for="(server, key) in this.store.CrossServerConfiguration.serverList"
@setActiveServer="this.store.setActiveCrossServer(key)" @setActiveServer="this.store.setActiveCrossServer(key)"
@delete="this.store.deleteCrossServerConfiguration(key)" @delete="this.store.deleteCrossServerConfiguration(key)"
:key="key" :key="key"
:server="server"></RemoteServer> :server="server"></RemoteServer>
<h6 class="text-muted m-auto" v-if="Object.keys(this.store.CrossServerConfiguration.ServerList).length === 0"> <h6 class="text-muted m-auto" v-if="Object.keys(this.store.CrossServerConfiguration.serverList).length === 0">
<LocaleText t="Click"></LocaleText> <LocaleText t="Click"></LocaleText>
<i class="bi bi-plus-circle-fill mx-1"></i> <i class="bi bi-plus-circle-fill mx-1"></i>
<LocaleText t="to add your server"></LocaleText> <LocaleText t="to add your server"></LocaleText>
@@ -41,19 +41,19 @@ export const DashboardConfigurationStore = defineStore('DashboardConfigurationSt
window.localStorage.setItem('CrossServerConfiguration', JSON.stringify(this.CrossServerConfiguration)) window.localStorage.setItem('CrossServerConfiguration', JSON.stringify(this.CrossServerConfiguration))
}, },
addCrossServerConfiguration(){ addCrossServerConfiguration(){
this.CrossServerConfiguration.ServerList[v4().toString()] = { this.CrossServerConfiguration.serverList[v4().toString()] = {
host: "", host: "",
apiKey: "", apiKey: "",
active: false active: false
} }
}, },
deleteCrossServerConfiguration(key){ deleteCrossServerConfiguration(key){
delete this.CrossServerConfiguration.ServerList[key]; delete this.CrossServerConfiguration.serverList[key];
}, },
getActiveCrossServer(){ getActiveCrossServer(){
const key = localStorage.getItem('ActiveCrossServerConfiguration'); const key = localStorage.getItem('ActiveCrossServerConfiguration');
if (key !== null){ if (key !== null){
return this.CrossServerConfiguration.ServerList[key] return this.CrossServerConfiguration.serverList[key]
} }
return undefined return undefined
}, },
+1 -1
View File
@@ -19,7 +19,7 @@ export default {
</script> </script>
<template> <template>
<div class="container-fluid flex-grow-1 main" :data-bs-theme="this.dashboardConfigurationStore.Configuration.Server.wgdashboard_theme"> <div class="container-fluid flex-grow-1 main" :data-bs-theme="this.dashboardConfigurationStore.Configuration.server.wgdashboard_theme">
<div class="row h-100"> <div class="row h-100">
<Navbar></Navbar> <Navbar></Navbar>
<main class="col-md-9 col-lg-10 overflow-y-scroll mb-0 pt-2"> <main class="col-md-9 col-lg-10 overflow-y-scroll mb-0 pt-2">
+1 -1
View File
@@ -56,7 +56,7 @@ export default {
<template> <template>
<div class="container-fluid login-container-fluid d-flex main pt-5 overflow-scroll" <div class="container-fluid login-container-fluid d-flex main pt-5 overflow-scroll"
:data-bs-theme="this.store.Configuration.Server.wgdashboard_theme"> :data-bs-theme="this.store.Configuration.server.wgdashboard_theme">
<div class="m-auto text-body" style="width: 500px"> <div class="m-auto text-body" style="width: 500px">
<span class="dashboardLogo display-4"> <span class="dashboardLogo display-4">
<LocaleText t="Nice to meet you!"></LocaleText> <LocaleText t="Nice to meet you!"></LocaleText>