From 674fea706378b9e72d425e6a94b065b4b9b84907 Mon Sep 17 00:00:00 2001 From: Donald Zou Date: Thu, 24 Jul 2025 23:12:51 +0800 Subject: [PATCH] Added generate reset client password link --- src/dashboard.py | 11 +++ src/modules/DashboardClients.py | 41 ++++++++- .../clientComponents/clientResetPassword.vue | 87 ++++++++++++------- src/static/locales/supported_locales.json | 24 ----- 4 files changed, 108 insertions(+), 55 deletions(-) diff --git a/src/dashboard.py b/src/dashboard.py index 9065461..8bbd8cb 100644 --- a/src/dashboard.py +++ b/src/dashboard.py @@ -1282,6 +1282,17 @@ def API_Clients_AssignedPeers(): return ResponseObject(False, "Client does not exist") return ResponseObject(data=d) +@app.post(f'{APP_PREFIX}/api/clients/generatePasswordResetLink') +def API_Clients_GeneratePasswordResetLink(): + data = request.get_json() + clientId = data.get("ClientID") + if not clientId: + return ResponseObject(False, "Please provide ClientID") + + token = DashboardClients.GenerateClientPasswordResetLink(clientId) + if token: + return ResponseObject(data=token) + return ResponseObject(False, "Failed to generate link") ''' Index Page diff --git a/src/modules/DashboardClients.py b/src/modules/DashboardClients.py index 8ca770a..991d5d1 100644 --- a/src/modules/DashboardClients.py +++ b/src/modules/DashboardClients.py @@ -1,3 +1,4 @@ +import datetime import hashlib import uuid @@ -57,6 +58,18 @@ class DashboardClients: db.Column('Name', db.String(500)), extend_existing=True, ) + + self.dashboardClientsPasswordResetLinkTable = db.Table( + 'DashboardClientsPasswordResetLinks', self.metadata, + db.Column('ResetToken', db.String(255), nullable=False, primary_key=True), + db.Column('ClientID', db.String(255), nullable=False), + db.Column('CreatedDate', + (db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP), + server_default=db.func.now()), + db.Column('ExpiryDate', + (db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)), + extend_existing=True + ) self.metadata.create_all(self.engine) self.Clients = {} @@ -112,7 +125,6 @@ class DashboardClients: return self.ClientsRaw def GetClient(self, ClientID) -> dict[str, str] | None: - self.__getClients() c = filter(lambda x: x['ClientID'] == ClientID, self.ClientsRaw) client = next((dict(client) for client in c), None) if client is not None: @@ -322,6 +334,33 @@ class DashboardClients: ''' For WGDashboard Admin to Manage Clients ''' + + def GenerateClientPasswordResetLink(self, ClientID) -> bool | str: + c = self.GetClient(ClientID) + if c is None: + return False + + newToken = str(uuid.uuid4()) + with self.engine.begin() as conn: + conn.execute( + self.dashboardClientsPasswordResetLinkTable.update().values({ + "ExpiryDate": db.func.now() + }).where( + self.dashboardClientsPasswordResetLinkTable.c.ClientID == ClientID + ) + ) + conn.execute( + self.dashboardClientsPasswordResetLinkTable.insert().values({ + "ResetToken": newToken, + "ClientID": ClientID, + "ExpiryDate": datetime.datetime.now() + datetime.timedelta(minutes=30) + }) + ) + + return newToken + + + def GetAssignedPeerClients(self, ConfigurationName, PeerID): c = self.DashboardClientsPeerAssignment.GetAssignedClients(ConfigurationName, PeerID) for a in c: diff --git a/src/static/app/src/components/clientComponents/clientResetPassword.vue b/src/static/app/src/components/clientComponents/clientResetPassword.vue index 7b47cf6..c353afb 100644 --- a/src/static/app/src/components/clientComponents/clientResetPassword.vue +++ b/src/static/app/src/components/clientComponents/clientResetPassword.vue @@ -1,38 +1,65 @@ diff --git a/src/static/locales/supported_locales.json b/src/static/locales/supported_locales.json index e90b48b..aefaa0a 100644 --- a/src/static/locales/supported_locales.json +++ b/src/static/locales/supported_locales.json @@ -1,54 +1,45 @@ [ { - "flag": "🇺🇸", "lang_id": "en-US", "lang_name": "English (United States)", "lang_name_localized": "English (United States)" }, { - "flag": "🇸🇦", "lang_id": "ar-SA", "lang_name": "Arabic (Saudi Arabia)", "lang_name_localized": "العربية (السعودية)" }, { - "flag": "🇧🇾", "lang_id": "be-BY", "lang_name": "Belarusian (Belarus)", "lang_name_localized": "Беларуская (Беларусь)" }, { - "flag": "🏴󠁥󠁳󠁣󠁴󠁿", "lang_id": "ca-ES", "lang_name": "Catalan (Spain)", "lang_name_localized": "Català (Espanya)" }, { - "flag": "🇨🇿", "lang_id": "cs-CZ", "lang_name": "Czech (Czech Republic)", "lang_name_localized": "Česky (Česká republika)" }, { - "flag": "🇩🇪", "lang_id": "de-DE", "lang_name": "German (Germany)", "lang_name_localized": "Deutsch (Deutschland)" }, { - "flag": "🇪🇸", "lang_id": "es-ES", "lang_name": "Spanish (Spain)", "lang_name_localized": "Español (España)" }, { - "flag": "🇮🇷", "lang_id": "fa-IR", "lang_name": "Persian (Iran)", "lang_name_localized": "فارسی (ایران)" }, { - "flag": "🇨🇦", "lang_id": "fr-CA", "lang_name": "French (Canada)", "lang_name_localized": "Français (Canada)" @@ -60,91 +51,76 @@ "lang_name_localized": "Français (France)" }, { - "flag": "🇭🇺", "lang_id": "hu-HU", "lang_name": "Hungarian (Hungary)", "lang_name_localized": "Magyar (Magyarország)" }, { - "flag": "🇮🇩", "lang_id": "id-ID", "lang_name": "Indonesian (Indonesia)", "lang_name_localized": "Bahasa Indonesia (Indonesia)" }, { - "flag": "🇮🇹", "lang_id": "it-IT", "lang_name": "Italian (Italy)", "lang_name_localized": "Italiano (Italia)" }, { - "flag": "🇯🇵", "lang_id": "ja-JP", "lang_name": "Japanese (Japan)", "lang_name_localized": "日本語 (日本)" }, { - "flag": "🇰🇷", "lang_id": "ko-KR", "lang_name": "Korean (South Korea)", "lang_name_localized": "한국어 (대한민국)" }, { - "flag": "🇳🇱", "lang_id": "nl-NL", "lang_name": "Dutch (Netherlands)", "lang_name_localized": "Nederlands (Nederland)" }, { - "flag": "🇵🇱", "lang_id": "pl-PL", "lang_name": "Polish (Poland)", "lang_name_localized": "Polski (Polska)" }, { - "flag": "🇵🇹", "lang_id": "pt-BR", "lang_name": "Portuguese (Brazil)", "lang_name_localized": "Português (Brasil)" }, { - "flag": "🇷🇺", "lang_id": "ru-RU", "lang_name": "Russian (Russia)", "lang_name_localized": "Русский (Россия)" }, { - "flag": "🇸🇪", "lang_id": "sv-SE", "lang_name": "Swedish (Sweden)", "lang_name_localized": "Svenska (Sverige)" }, { - "flag": "🇹🇭", "lang_id": "th-TH", "lang_name": "Thai (Thailand)", "lang_name_localized": "ภาษาไทย (ประเทศไทย)" }, { - "flag": "🇹🇷", "lang_id": "tr-TR", "lang_name": "Turkish (Turkey)", "lang_name_localized": "Türkçe (Türkiye)" }, { - "flag": "🇺🇦", "lang_id": "uk-UA", "lang_name": "Ukrainian (Ukraine)", "lang_name_localized": "Українська (Україна)" }, { - "flag": "🇨🇳", "lang_id": "zh-CN", "lang_name": "Chinese (Simplified, China)", "lang_name_localized": "中文(简体,中国)" }, { - "flag": "🇭🇰", "lang_id": "zh-HK", "lang_name": "Chinese (Traditional, Hong Kong)", "lang_name_localized": "中文(繁體,香港)"