diff --git a/src/main.py b/src/main.py index 23fe8b9..bdfc145 100644 --- a/src/main.py +++ b/src/main.py @@ -14,7 +14,7 @@ from modules.database.database import database from modules.utilities.utilities import utilities as util from modules.utilities.logger import setup_logger -from modules.routes.routes import routes +from modules.routes.routes_general import routes_general from modules.routes.routes_welcome import routes_welcome if __name__ == '__main__': @@ -46,7 +46,7 @@ if __name__ == '__main__': template_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_general, url_prefix=prefix) app.register_blueprint(routes_welcome, url_prefix=prefix) app.wgd_config = config_data diff --git a/src/modules/routes/routes.py b/src/modules/routes/routes_general.py similarity index 83% rename from src/modules/routes/routes.py rename to src/modules/routes/routes_general.py index 5668ce4..841afa1 100644 --- a/src/modules/routes/routes.py +++ b/src/modules/routes/routes_general.py @@ -20,7 +20,7 @@ from ..config.config import config from ..utilities.utilities import utilities from ..utilities.statistics import statistics -routes = flask.Blueprint("routes", __name__) +routes_general = flask.Blueprint("routes_general", __name__) white_list = [ "/", @@ -37,7 +37,7 @@ white_list = [ "sharePeer/get", ] -@routes.before_request +@routes_general.before_request def authentication_required(): if flask.request.method.lower() == "options": return make_resp_obj(True, "", {"status": True}, 200) @@ -70,11 +70,7 @@ def authentication_required(): return make_resp_obj(False, "Unauthorized access", {}, 401) -@routes.route('/', methods=["GET"]) -def index_handler(): - return flask.render_template("index.html") - -@routes.route('/api/auth', methods=["POST"]) +@routes_general.route('/api/authenticate', methods=["POST"]) def api_authenticate(): ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') if not ok: @@ -177,7 +173,18 @@ def api_authenticate(): else: return make_resp_obj(False, "Sorry, your username or password is incorrect.", {}, 401) -@routes.route('/api/auth/validate', methods=["GET"]) +@routes_general.route('/') +def index_handler(): + return flask.render_template("index.html") + +@routes_general.route('/api/locale') +def api_locale_handler(): + locale_manager = localeman() + locale_data = locale_manager.get_language() + + return make_resp_obj(True, "", locale_data, 200) + +@routes_general.route('/api/validateAuthentication') def api_validate_auth(): ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') if not ok: @@ -192,36 +199,8 @@ def api_validate_auth(): return make_resp_obj(False, "Invalid authentication", {}, 200) return make_resp_obj() -@routes.route('/api/dashboard/locale', methods=["GET"]) -def api_retrieve_locale(): - locale_manager = localeman() - locale_data = locale_manager.get_language() - - return make_resp_obj(True, "", locale_data, 200) - -@routes.route('/api/dashboard/locale', methods=["PATCH"]) -def api_locale_update(): - req_data = flask.request.get_json() - if "lang_id" not in req_data.keys(): - return make_resp_obj(False, "Please specify a language id: lang_id") - - language_id = req_data.get("lang_id") - - locale_manager = localeman - ok = locale_manager.update_language(language_id) - if not ok: - return make_resp_obj(False, "Failed to update the language id") - - locale_data = locale_manager.get_language() - return make_resp_obj(True, "", locale_data) - -@routes.route('/api/dashboard/locale/available', methods=["GET"]) -def api_retrieve_available_locales(): - locale_manager = localeman() - - -@routes.route('/api/dashboard/version', methods=["GET"]) -def api_retrieve_version(): +@routes_general.route('/api/getDashboardVersion') +def api_retrieve_dashboard_version(): ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') if not ok: log.error("failed to filter the config in-memory") @@ -229,8 +208,8 @@ def api_retrieve_version(): return make_resp_obj(True, "", config_server.get("version")) -@routes.route('/api/dashboard/theme', methods=["GET"]) -def api_retrieve_theme(): +@routes_general.route('/api/getDashboardTheme') +def api_retrieve_dashboard_theme(): ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') if not ok: log.error("failed to filter the config in-memory") @@ -238,16 +217,26 @@ def api_retrieve_theme(): return make_resp_obj(True, "", config_server.get("wgdashboard_theme"), 200) -@routes.route('/api/dashboard/updatestatus', methods=["GET"]) -def api_retrieve_update_status(): - utilities.update_available() - return make_resp_obj() +@routes_general.route('/api/getDashboardUpdate') +def api_retrieve_dashboard_update(): + ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') + if not ok: + log.error("failed to filter the config in-memory") + return make_resp_obj(False, "Internal error", {}, 500) -@routes.route('/api/dashboard/configuration', methods=["GET"]) -def api_retrieve_config(): + ok, upgradable, latest_version_link = utilities.update_info(config_server.get("version")) + if ok and upgradable: + return make_resp_obj(True, 'There is an update available for this instance', data=latest_version_link) + elif ok and not upgradable: + return make_resp_obj(True, 'This instance is running the latest version') + else: + return make_resp_obj(False) + +@routes_general.route('/api/getDashboardConfiguration') +def api_retrieve_dashboard_config(): return make_resp_obj(data=flask.current_app.wgd_config) -@routes.route('/api/dashboard/totp', methods=["GET"]) +@routes_general.route('/api/isTotpEnabled') def api_totp_status(): ok, config_account = config.filter(flask.current_app.wgd_config, 'ACCOUNT') if not ok: @@ -258,7 +247,7 @@ def api_totp_status(): return make_resp_obj(True, "", data, 200) -@routes.route('/api/dashboard/wireguard/interfaces', methods=["GET"]) +@routes_general.route('/api/getWireguardConfigurations') def api_retrieve_wireguard_configurations(): ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER') if not ok: @@ -277,12 +266,12 @@ def api_retrieve_wireguard_configurations(): return make_resp_obj(True, 'Wireguard', {}, 200) -@routes.route('/api/dashboard/statistics', methods=["GET"]) +@routes_general.route('/api/systemStatus') def api_system_status(): status = statistics() return make_resp_obj(True, "", status.to_json(), 200) -@routes.route('/health', methods=["GET"]) -@routes.route('/healthz', methods=["GET"]) +@routes_general.route('/health', methods=["GET"]) +@routes_general.route('/healthz', methods=["GET"]) def health_handler(): return make_resp_obj(True, "Health Endpoint", {"status": "ok"}, 200) \ No newline at end of file diff --git a/src/modules/utilities/statistics.py b/src/modules/utilities/statistics.py index 67c56fd..7965057 100644 --- a/src/modules/utilities/statistics.py +++ b/src/modules/utilities/statistics.py @@ -4,7 +4,6 @@ import psutil import shutil import subprocess import time -import flask import psutil, shutil, subprocess, time from flask import current_app @@ -33,19 +32,19 @@ class statistics: def retrieve_memory_stats(self): try: - v = psutil.virtual_memory() - s = psutil.swap_memory() + virtmem = psutil.virtual_memory() + swapmem = psutil.swap_memory() return { "VirtualMemory": { - "total": v.total, - "available": v.available, - "percent": v.percent + "total": virtmem.total, + "available": virtmem.available, + "percent": virtmem.percent }, "SwapMemory": { - "total": s.total, - "available": s.free, - "percent": s.percent + "total": swapmem.total, + "available": swapmem.free, + "percent": swapmem.percent } } except Exception as e: @@ -56,14 +55,14 @@ class statistics: disks = [] try: for p in psutil.disk_partitions(): - d = psutil.disk_usage(p.mountpoint) + diskuse = psutil.disk_usage(p.mountpoint) disks.append({ "mountPoint": p.mountpoint, - "total": d.total, - "used": d.used, - "free": d.free, - "percent": d.percent + "total": diskuse.total, + "used": diskuse.used, + "free": diskuse.free, + "percent": diskuse.percent }) except Exception as e: current_app.logger.error("Disk error %s", e) diff --git a/src/modules/utilities/utilities.py b/src/modules/utilities/utilities.py index bf482b0..3d6e776 100644 --- a/src/modules/utilities/utilities.py +++ b/src/modules/utilities/utilities.py @@ -2,9 +2,11 @@ import logging as log +import json import os import urllib.request -import json + +from packaging import version class utilities(): @staticmethod @@ -25,11 +27,22 @@ class utilities(): return False @staticmethod - def update_available() -> bool: + def update_info(running_version: str) -> tuple[bool, bool, str]: request = urllib.request.urlopen("https://api.github.com/repos/WGDashboard/WGDashboard/releases/latest", timeout=5).read() data = json.loads(request) - log.info(data) + latest_version = data.get('tag_name') + latest_version_link = data.get('html_url') + + try: + if version.parse(latest_version) > version.parse(running_version): + log.info('there is an update available for this instance') + return True, True, latest_version_link + else: + log.info('this instance is running the latest version') + return True, False, latest_version_link + except: + return False, False, '' @staticmethod def ProtocolsEnabled() -> list[str]: diff --git a/src/requirements.txt b/src/requirements.txt index 441f413..961136b 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -4,5 +4,6 @@ gunicorn==25.3.0 sqlalchemy==2.0.48 Flask==3.1.3 Werkzeug==3.1.7 +packaging==26.2 pyotp==2.9.0 psutil==7.2.2 \ No newline at end of file diff --git a/src/static/admin/src/views/signin.vue b/src/static/admin/src/views/signin.vue index 93fcb42..d0296f3 100644 --- a/src/static/admin/src/views/signin.vue +++ b/src/static/admin/src/views/signin.vue @@ -39,7 +39,6 @@ export default { password: "", totp: "", }, - loginError: false, loginErrorMessage: "", loading: false } @@ -57,6 +56,7 @@ export default { }, methods: { GetLocale, +<<<<<<< HEAD async auth(){ if (this.formValid){ this.loading = true @@ -72,27 +72,41 @@ export default { }else{ this.$router.push('/') } +======= + async auth() { + if (!this.formValid) { + return; + } + + this.loading = true; + + try { + await fetchPost("/api/authenticate", this.data, (response) => { + if (response.status) { + this.$refs.signInBtn.classList.add("signedIn"); + + if (response.message) { + this.$router.push("/welcome"); + } else if (this.store.Redirect) { + this.$router.push(this.store.Redirect); + } else { + this.$router.push("/"); +>>>>>>> b5c0236 (chore: rework update checking and minor changes in files) } - }else{ - this.store.newMessage("Server", response.message, "danger") - document.querySelectorAll("input[required]").forEach(x => { - x.classList.remove("is-valid") - x.classList.add("is-invalid") - }); - this.loading = false - } - - }) - }else{ - document.querySelectorAll("input[required]").forEach(x => { - if (x.value.length === 0){ - x.classList.remove("is-valid") - x.classList.add("is-invalid") - }else{ - x.classList.remove("is-invalid") - x.classList.add("is-valid") + } else { + this.store.newMessage("Server", "Failed to authenticate", "danger"); } }); + } catch (err) { + this.store.newMessage( + "Server", + "Unable to contact the server.", + "danger" + ); + + console.error(err); + } finally { + this.loading = false; } } }