From 41bf9b8baa52626eac9d5f20cf79512c77ab29e0 Mon Sep 17 00:00:00 2001 From: Donald Zou Date: Thu, 5 Jun 2025 15:57:17 +0800 Subject: [PATCH] Update --- src/client.py | 8 ++-- src/modules/DashboardClients.py | 6 ++- src/modules/DashboardClientsPeerAssignment.py | 46 +++++++++++++++++++ .../client/src/components/SignIn/qrcode.vue | 22 +++++++++ .../src/components/SignIn/signInForm.vue | 19 ++++---- .../client/src/components/SignIn/totpForm.vue | 22 ++++----- src/static/client/src/router/router.js | 12 +++-- src/static/client/src/utilities/request.js | 21 +++++++++ 8 files changed, 123 insertions(+), 33 deletions(-) create mode 100644 src/modules/DashboardClientsPeerAssignment.py create mode 100644 src/static/client/src/components/SignIn/qrcode.vue diff --git a/src/client.py b/src/client.py index e752ec8..9d9ef76 100644 --- a/src/client.py +++ b/src/client.py @@ -55,9 +55,9 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration], @client.get(f'{prefix}/api/signout') def ClientAPI_SignOut(): - session.pop('username') - session.pop('role') - session.pop('totpVerified') + session['username'] = None + session['role'] = None + session['totpVerified'] = None return ResponseObject(True) @client.get(f'{prefix}/api/signin/totp') @@ -81,7 +81,7 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration], if session.get('username') is None: return ResponseObject(False, "Sign in status is invalid", status_code=401) session['totpVerified'] = True - # return ResponseObject(True, data=) + return ResponseObject(True) return ResponseObject(status, msg) @client.get(prefix) diff --git a/src/modules/DashboardClients.py b/src/modules/DashboardClients.py index 5b50dbf..3131e9c 100644 --- a/src/modules/DashboardClients.py +++ b/src/modules/DashboardClients.py @@ -6,6 +6,7 @@ import pyotp import sqlalchemy as db from .ConnectionString import ConnectionString +from .DashboardClientsPeerAssignment import DashboardClientsPeerAssignment from .DashboardClientsTOTP import DashboardClientsTOTP from .Utilities import ValidatePasswordStrength from .DashboardLogger import DashboardLogger @@ -18,7 +19,6 @@ class DashboardClients: self.engine = db.create_engine(ConnectionString("wgdashboard")) self.metadata = db.MetaData() - self.dashboardClientsTable = db.Table( 'DashboardClients', self.metadata, db.Column('ClientID', db.String(255), nullable=False, primary_key=True), @@ -46,6 +46,7 @@ class DashboardClients: self.Clients = [] self.__getClients() self.DashboardClientsTOTP = DashboardClientsTOTP() + self.DashboardClientsPeerAssignment = DashboardClientsPeerAssignment() def __getClients(self): with self.engine.connect() as conn: @@ -76,6 +77,7 @@ class DashboardClients: def SignIn_GetTotp(self, Token: str, UserProvidedTotp: str = None) -> tuple[bool, str] or tuple[bool, None, str]: status, data = self.DashboardClientsTOTP.GetTotp(Token) + if not status: return False, "TOTP Token is invalid" if UserProvidedTotp is None: @@ -83,7 +85,7 @@ class DashboardClients: return True, pyotp.totp.TOTP(data.get('TotpKey')).provisioning_uri(name=data.get('Email'), issuer_name="WGDashboard Client") else: - totpMatched = pyotp.TOTP(data.get('TotpKey')).verify(UserProvidedTotp) + totpMatched = pyotp.totp.TOTP(data.get('TotpKey')).verify(UserProvidedTotp) if not totpMatched: return False, "TOTP is does not match" else: diff --git a/src/modules/DashboardClientsPeerAssignment.py b/src/modules/DashboardClientsPeerAssignment.py new file mode 100644 index 0000000..9e1a74f --- /dev/null +++ b/src/modules/DashboardClientsPeerAssignment.py @@ -0,0 +1,46 @@ +from .ConnectionString import ConnectionString +from .DashboardLogger import DashboardLogger +import sqlalchemy as db + + +class DashboardClientsPeerAssignment: + def __init__(self): + self.logger = DashboardLogger() + self.engine = db.create_engine(ConnectionString("wgdashboard")) + self.metadata = db.MetaData() + + self.dashboardClientsPeerAssignmentTable = db.Table( + 'DashboardClientsPeerAssignment', self.metadata, + db.Column('AssignmentID', db.String(255), nullable=False, primary_key=True), + db.Column('ClientID', db.String(255), nullable=False, index=True), + db.Column('ConfigurationName', db.String(255)), + db.Column('PeerID', db.String(500)), + db.Column('AssignedDate', + (db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP), + server_default=db.func.now()), + db.Column('UnassignedDate', + (db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)), + extend_existing=True + ) + self.metadata.create_all(self.engine) + self.assignments = [] + + def __getAssignments(self): + with self.engine.connect() as conn: + self.assignments = conn.execute( + self.dashboardClientsPeerAssignmentTable.select().where( + self.dashboardClientsPeerAssignmentTable.c.UnassignedDate is None + ) + ).mappings().fetchall() + + def AssignClient(self, ClientID, ConfigurationName, PeerID): + pass + + def UnassignClient(self, AssignmentID): + pass + + def GetAssignedClient(self, ConfigurationName, PeerID): + pass + + def GetAssignedPeers(self, ClientID): + pass \ No newline at end of file diff --git a/src/static/client/src/components/SignIn/qrcode.vue b/src/static/client/src/components/SignIn/qrcode.vue new file mode 100644 index 0000000..b478e41 --- /dev/null +++ b/src/static/client/src/components/SignIn/qrcode.vue @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/src/static/client/src/components/SignIn/signInForm.vue b/src/static/client/src/components/SignIn/signInForm.vue index 3244424..dd8e75c 100644 --- a/src/static/client/src/components/SignIn/signInForm.vue +++ b/src/static/client/src/components/SignIn/signInForm.vue @@ -2,7 +2,7 @@ import {computed, reactive, ref} from "vue"; import {clientStore} from "@/stores/clientStore.js"; import axios from "axios"; -import {requestURl} from "@/utilities/request.js"; +import {axiosPost, requestURl} from "@/utilities/request.js"; import {useRoute, useRouter} from "vue-router"; const loading = ref(false) const formData = reactive({ @@ -20,15 +20,14 @@ const signIn = async (e) => { return; } loading.value = true; - await axios.post(requestURl("/api/signin"), formData).then(res => { - let data = res.data; - if (!data.status){ - store.newNotification(data.message, "danger") - loading.value = false; - }else{ - emits("totpToken", data.message) - } - }) + + const data = await axiosPost("/api/signin", formData) + if (!data.status){ + store.newNotification(data.message, "danger") + loading.value = false; + }else{ + emits("totpToken", data.message) + } } const formFilled = computed(() => { diff --git a/src/static/client/src/components/SignIn/totpForm.vue b/src/static/client/src/components/SignIn/totpForm.vue index 3850336..1903ec0 100644 --- a/src/static/client/src/components/SignIn/totpForm.vue +++ b/src/static/client/src/components/SignIn/totpForm.vue @@ -1,10 +1,10 @@ @@ -88,7 +86,7 @@ const verify = async (e) => {

Initial Setup

Please scan the following QR Code to generate TOTP with your choice of authenticator

- +

Or you can click the link below:

diff --git a/src/static/client/src/router/router.js b/src/static/client/src/router/router.js index 0969875..b12939c 100644 --- a/src/static/client/src/router/router.js +++ b/src/static/client/src/router/router.js @@ -3,7 +3,7 @@ import Index from "@/views/index.vue"; import SignIn from "@/views/signin.vue"; import SignUp from "@/views/signup.vue"; import axios from "axios"; -import {requestURl} from "@/utilities/request.js"; +import {axiosGet, requestURl} from "@/utilities/request.js"; import {clientStore} from "@/stores/clientStore.js"; const router = createRouter({ @@ -37,6 +37,8 @@ router.beforeEach(async (to, from, next) => { const store = clientStore() if (to.path === '/signout'){ + + await axios.get(requestURl('/api/signout')).then(() => { next('/signin') }).catch(() => { @@ -45,13 +47,13 @@ router.beforeEach(async (to, from, next) => { store.newNotification("Sign in session ended, please sign in again", "warning") }else{ if (to.meta.auth){ - await axios.get(requestURl('/api/validateAuthentication')).then(res => { + const status = await axiosGet('/api/validateAuthentication') + if (status){ next() - }).catch(() => { - + }else{ store.newNotification("Sign in session ended, please sign in again", "warning") next('/signin') - }) + } }else{ next() } diff --git a/src/static/client/src/utilities/request.js b/src/static/client/src/utilities/request.js index 4fc1d1d..7c4042d 100644 --- a/src/static/client/src/utilities/request.js +++ b/src/static/client/src/utilities/request.js @@ -1,5 +1,26 @@ +import axios from "axios"; + export const requestURl = (url) => { return import.meta.env.MODE === 'development' ? '/client' + url : `${window.location.protocol}//${(window.location.host + window.location.pathname + url).replace(/\/\//g, '/')}` } +export const axiosPost = async (URL, body = {}) => { + try{ + const res = await axios.post(requestURl(URL), body) + return res.data + } catch (error){ + console.log(error) + return undefined + } +} + +export const axiosGet = async (URL, query = {}) => { + try{ + const res = await axios.get(requestURl(URL), query) + return res.data + } catch (error){ + console.log(error) + return undefined + } +} \ No newline at end of file