feat: start working on Flask

This commit is contained in:
DaanSelen
2026-03-03 11:15:59 +01:00
parent b95074d994
commit 992baa2afc
11 changed files with 199 additions and 13 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ dashboard_refresh_interval = 60000
dashboard_peer_list_display = grid dashboard_peer_list_display = grid
dashboard_sort = status dashboard_sort = status
dashboard_theme = dark dashboard_theme = dark
dashboard_api_key = false wgdashboard_apikey = false
dashboard_language = en-US dashboard_language = en-US
[Account] [Account]
+17 -2
View File
@@ -2,20 +2,35 @@
import logging as log import logging as log
import flask
import json import json
import os
from modules.config.reader import reader from modules.config.reader import reader
from modules.database.database import database from modules.database.database import database
from modules.utilities.utilities import utilities as util from modules.utilities.utilities import utilities as util
from modules.routes.routes import routes
if __name__ == '__main__': if __name__ == '__main__':
log.basicConfig(level=log.DEBUG) log.basicConfig(level=log.DEBUG)
config_contents = reader.read_config() ok, config_contents = reader.read_config()
if not ok:
exit(1)
found, config_database = util.filter_config(config_contents, 'DATABASE') found, config_database = util.filter_config(config_contents, 'DATABASE')
if not found: if not found:
exit(1) exit(1)
ok, engine, session = database.create_session(config_database) ok, engine, session = database.create_session(config_database)
ok = database.verify_contents(engine) ok = database.ensure_contents(engine)
app = flask.Flask("WGDashboard", template_folder=os.path.abspath("./static/dist/WGDashboardAdmin"))
app.register_blueprint(routes)
app.wgdashboard_config = config_contents
app.engine = engine
app.db_session = session
app.run(debug=True, use_reloader=False)
+4 -4
View File
@@ -6,19 +6,19 @@ from .utilities import checks
class reader(): class reader():
@staticmethod @staticmethod
def read_config() -> dict: def read_config() -> tuple[bool, dict]:
''' '''
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 = checks.search_known_paths() ok, candidate_path = checks.search_known_paths()
if not ok: if not ok:
return {} return False, {}
ok, config_contents = checks.verify_contents(candidate_path) ok, config_contents = checks.verify_contents(candidate_path)
if not ok: if not ok:
return {} return False, {}
return config_contents return True, config_contents
@staticmethod @staticmethod
def refresh_config(config_contents: dict) -> dict: def refresh_config(config_contents: dict) -> dict:
+1 -1
View File
@@ -55,7 +55,7 @@ class checks():
log.debug(f'checking integrity of section: {section}') log.debug(f'checking integrity of section: {section}')
if len(config.items(section)) == 0: if len(config.items(section)) == 0:
log.warn('empty section, removing for runtime due to irrelevance') log.warn(f'empty section: {section}, removing at runtime due to irrelevance')
config.remove_section(section) config.remove_section(section)
config_dict = {} config_dict = {}
+1 -3
View File
@@ -15,8 +15,6 @@ class database():
if not ok: if not ok:
return False, None, None return False, None, None
log.info(connection_string)
try: try:
engine = sqlalchemy.create_engine(connection_string, echo=False) engine = sqlalchemy.create_engine(connection_string, echo=False)
@@ -30,7 +28,7 @@ class database():
return False, None, None return False, None, None
@staticmethod @staticmethod
def verify_contents(engine) -> bool: def ensure_contents(engine) -> bool:
try: try:
log.info('checking if all tables are present, and creating them if they are not') log.info('checking if all tables are present, and creating them if they are not')
+16
View File
@@ -0,0 +1,16 @@
#!/bin/env python3
from datetime import datetime
import sqlalchemy.orm
from .schema import Base
from .schema import Apikeys
class functions():
def retrieve_api_keys(session: sqlalchemy.orm.Session) -> dict:
time_now = datetime.now()
api_keys = session.query(Apikeys).all()
print(api_keys)
return {}
+86 -1
View File
@@ -21,5 +21,90 @@ class User(Base):
email = sqlalchemy.Column(sqlalchemy.String) email = sqlalchemy.Column(sqlalchemy.String)
class Apikeys(Base):
__tablename__ = 'apikeys'
apikey_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, index=True)
apikey_data = sqlalchemy.Column(sqlalchemy.String)
apikey_creation = sqlalchemy.Column(sqlalchemy.String)
apikey_expiration = sqlalchemy.Column(sqlalchemy.String)
class Wireguard(Base): class Wireguard(Base):
__tablename__ = 'wireguard_interfaces' __tablename__ = 'wireguard_interfaces'
iface_status = sqlalchemy.Column(sqlalchemy.String)
iface_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, index=True)
iface_name = sqlalchemy.Column(sqlalchemy.String, unique=True)
iface_notes = sqlalchemy.Column(sqlalchemy.String)
iface_privkey = sqlalchemy.Column(sqlalchemy.String, unique=True)
iface_pubkey = sqlalchemy.Column(sqlalchemy.String, unique=True)
iface_address = sqlalchemy.Column(sqlalchemy.String)
iface_listen_port = sqlalchemy.Column(sqlalchemy.Integer, unique=True)
iface_mtu = sqlalchemy.Column(sqlalchemy.Integer)
iface_preup = sqlalchemy.Column(sqlalchemy.String)
iface_predown = sqlalchemy.Column(sqlalchemy.String)
iface_postup = sqlalchemy.Column(sqlalchemy.String)
iface_predown = sqlalchemy.Column(sqlalchemy.String)
iface_save_config = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
iface_total_rx = sqlalchemy.Column(sqlalchemy.Float)
iface_total_tx = sqlalchemy.Column(sqlalchemy.Float)
iface_total_data = sqlalchemy.Column(sqlalchemy.Float)
class Amnezia(Base):
__tablename__ = 'amnezia_interfaces'
iface_status = sqlalchemy.Column(sqlalchemy.String)
iface_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, index=True)
iface_name = sqlalchemy.Column(sqlalchemy.String, unique=True)
iface_notes = sqlalchemy.Column(sqlalchemy.String)
iface_privkey = sqlalchemy.Column(sqlalchemy.String, unique=True)
iface_pubkey = sqlalchemy.Column(sqlalchemy.String, unique=True)
iface_address = sqlalchemy.Column(sqlalchemy.String)
iface_listen_port = sqlalchemy.Column(sqlalchemy.Integer, unique=True)
iface_mtu = sqlalchemy.Column(sqlalchemy.Integer)
iface_preup = sqlalchemy.Column(sqlalchemy.String)
iface_predown = sqlalchemy.Column(sqlalchemy.String)
iface_postup = sqlalchemy.Column(sqlalchemy.String)
iface_predown = sqlalchemy.Column(sqlalchemy.String)
iface_jc = sqlalchemy.Column(sqlalchemy.Integer)
iface_jmin = sqlalchemy.Column(sqlalchemy.Integer)
iface_jmax = sqlalchemy.Column(sqlalchemy.Integer)
iface_s1 = sqlalchemy.Column(sqlalchemy.Integer)
iface_s2 = sqlalchemy.Column(sqlalchemy.Integer)
iface_s3 = sqlalchemy.Column(sqlalchemy.Integer)
iface_s4 = sqlalchemy.Column(sqlalchemy.Integer)
iface_h1 = sqlalchemy.Column(sqlalchemy.String)
iface_h2 = sqlalchemy.Column(sqlalchemy.String)
iface_h3 = sqlalchemy.Column(sqlalchemy.String)
iface_h4 = sqlalchemy.Column(sqlalchemy.String)
iface_i1 = sqlalchemy.Column(sqlalchemy.String)
iface_i2 = sqlalchemy.Column(sqlalchemy.String)
iface_i3 = sqlalchemy.Column(sqlalchemy.String)
iface_i4 = sqlalchemy.Column(sqlalchemy.String)
iface_i5 = sqlalchemy.Column(sqlalchemy.String)
iface_save_config = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
iface_total_rx = sqlalchemy.Column(sqlalchemy.Float)
iface_total_tx = sqlalchemy.Column(sqlalchemy.Float)
iface_total_data = sqlalchemy.Column(sqlalchemy.Float)
class Peers(Base):
__tablename__ = 'interface_peers'
peer_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, index=True)
assigned_iface = sqlalchemy.Column(sqlalchemy.String)
+13
View File
@@ -0,0 +1,13 @@
#!/bin/env python3
import flask
def make_resp_obj(success: bool = True, message: str = "", data: dict = {}, http_code: int = 200) -> flask.wrappers.Response:
response = flask.make_response({
"status": success,
"message": message,
"data": data
}, http_code
)
return response
+57
View File
@@ -0,0 +1,57 @@
#!/bin/env python3
import flask
from .response import make_resp_obj
from ..database.functions import functions
from ..utilities.utilities import utilities
routes = flask.Blueprint("routes", __name__)
@routes.before_request
def auth_required():
if flask.request.method.lower() == "options":
return make_resp_obj(True, "", flask.jsonify({"status": True}), 200)
ok, config_server = utilities.filter_config(flask.current_app.wgdashboard_config, 'SERVER')
if not ok:
return make_resp_obj(False, "Internal Error", {}, 500)
auth_required = config_server.get('auth_req', True) # Set to true for a safe default
if not auth_required:
return
whiteList = [
'/client',
'/static/',
'/fileDownload',
'validateAuthentication',
'authenticate',
'getDashboardConfiguration',
'getDashboardTheme',
'getDashboardVersion',
'sharePeer/get',
'isTotpEnabled',
'locale'
]
request_path = flask.request.path
http_headers = flask.request.headers
api_key = http_headers.get("wgdashboard-apikey")
api_key_enabled = config_server.get("wgdashboard_apikey", False)
registered_api_keys = functions.retrieve_api_keys(flask.current_app.db_session)
if not api_key:
response = make_resp_obj()
return response
@routes.route("/")
def index():
return make_resp_obj(True, "/ Endpoint", flask.jsonify({"message": "Hello from routes file!"}), 200)
@routes.route("/health")
@routes.route("/healthz")
def health():
return make_resp_obj(True, "Health Endpoint", flask.jsonify({"status": "ok"}), 200)
+2 -1
View File
@@ -1 +1,2 @@
#!/bin/env python3 #!/bin/env python3
+1
View File
@@ -1,2 +1,3 @@
configparser==7.2.0 configparser==7.2.0
Flask==3.1.3
sqlalchemy==2.0.47 sqlalchemy==2.0.47