From bcd845fd59b5b07160c0890f4703e49bf0627809 Mon Sep 17 00:00:00 2001 From: Donald Zou Date: Sun, 24 Mar 2024 18:24:01 -0400 Subject: [PATCH] Finished revamping peer edit --- src/dashboard_new.py | 147 +++++++++++++- .../configurationComponents/peer.vue | 1 + .../configurationComponents/peerList.vue | 29 +-- .../configurationComponents/peerSettings.vue | 184 +++++++++++++++++- .../peerSettingsDropdown.vue | 4 +- .../app/src/components/configurationList.vue | 2 +- src/static/app/src/router/index.js | 44 ++++- src/static/app/src/views/configuration.vue | 7 +- 8 files changed, 382 insertions(+), 36 deletions(-) diff --git a/src/dashboard_new.py b/src/dashboard_new.py index 4808b34..c2f859f 100644 --- a/src/dashboard_new.py +++ b/src/dashboard_new.py @@ -1,4 +1,5 @@ import itertools +import random import sqlite3 import configparser import hashlib @@ -13,6 +14,7 @@ import re import urllib.parse import urllib.request import urllib.error +import uuid from dataclasses import dataclass from datetime import datetime, timedelta from json import JSONEncoder @@ -262,7 +264,7 @@ class WireguardConfiguration: sqldb.commit() def __getPublicKey(self) -> str: - return subprocess.check_output(['wg', 'pubkey'], input=self.PrivateKey.encode()).decode().strip('\n') + return _generatePublicKey(self.PrivateKey)[1] def getStatus(self) -> bool: self.Status = self.Name in psutil.net_if_addrs().keys() @@ -333,6 +335,12 @@ class WireguardConfiguration: except ValueError: pass + def searchPeer(self, publicKey): + for i in self.Peers: + if i.id == publicKey: + return True, i + return False, None + def __savePeers(self): for i in self.Peers: d = i.toJson() @@ -671,6 +679,56 @@ def _getConfigurationList() -> [WireguardConfiguration]: return configurations +def _checkIPWithRange(ip): + ip_patterns = ( + r"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|\/)){4}([0-9]{1,2})(,|$)", + r"[0-9a-fA-F]{0,4}(:([0-9a-fA-F]{0,4})){1,7}\/([0-9]{1,3})(,|$)" + ) + + for match_pattern in ip_patterns: + match_result = regex_match(match_pattern, ip) + if match_result: + result = match_result + break + else: + result = None + + return result + + +def _checkIP(ip): + ip_patterns = ( + r"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}", + r"[0-9a-fA-F]{0,4}(:([0-9a-fA-F]{0,4})){1,7}$" + ) + for match_pattern in ip_patterns: + match_result = regex_match(match_pattern, ip) + if match_result: + result = match_result + break + else: + result = None + + return result + + +def _checkDNS(dns): + dns = dns.replace(' ', '').split(',') + for i in dns: + if not (_checkIP(i) or regex_match(r"(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z]{0,61}[a-z]", i)): + return False + return True + + +def _generatePublicKey(privateKey) -> [bool, str]: + try: + publicKey = subprocess.check_output(f"wg pubkey", input=privateKey.encode(), shell=True, + stderr=subprocess.STDOUT) + return True, publicKey.decode().strip('\n') + except subprocess.CalledProcessError: + return False, None + + ''' API Routes ''' @@ -827,6 +885,88 @@ def API_updateDashboardConfigurationItem(): return ResponseObject() +@app.route('/api/updatePeerSettings/', methods=['POST']) +def API_updatePeerSettings(configName): + data = request.get_json() + id = data['id'] + + if len(id) > 0 and configName in WireguardConfigurations.keys(): + name = data['name'] + private_key = data['private_key'] + dns_addresses = data['DNS'] + allowed_ip = data['allowed_ip'] + endpoint_allowed_ip = data['endpoint_allowed_ip'] + preshared_key = data['preshared_key'] + + wireguardConfig = WireguardConfigurations[configName] + foundPeer, peer = wireguardConfig.searchPeer(id) + if foundPeer: + for p in wireguardConfig.Peers: + if allowed_ip in p.allowed_ip and p.id != peer.id: + return ResponseObject(False, f"Allowed IP already taken by another peer.") + if not _checkIPWithRange(endpoint_allowed_ip): + return ResponseObject(False, f"Endpoint Allowed IPs format is incorrect.") + if not _checkDNS(dns_addresses): + return ResponseObject(False, f"DNS format is incorrect.") + if data['mtu'] < 0 or data['mtu'] > 1460: + return ResponseObject(False, "MTU format is not correct.") + if data['keepalive'] < 0: + return ResponseObject(False, "Persistent Keepalive format is not correct.") + if len(private_key) > 0: + pubKey = _generatePublicKey(private_key) + if not pubKey[0] or pubKey[1] != peer.id: + return ResponseObject(False, "Private key does not match with the public key.") + + try: + rd = random.Random() + uid = uuid.UUID(int=rd.getrandbits(128), version=4) + with open(f"{uid}", "w+") as f: + f.write(preshared_key) + updatePsk = subprocess.check_output( + f"wg set {configName} peer {peer.id} preshared-key {uid}", + shell=True, stderr=subprocess.STDOUT) + os.remove(str(uid)) + if len(updatePsk.decode().strip("\n")) != 0: + return ResponseObject(False, + "Update peer failed when updating preshared key: " + updatePsk.decode().strip( + "\n")) + + allowed_ip = allowed_ip.replace(" ", "") + updateAllowedIp = subprocess.check_output( + f'wg set {configName} peer {peer.id} allowed-ips "{allowed_ip}"', + shell=True, stderr=subprocess.STDOUT) + if len(updateAllowedIp.decode().strip("\n")) != 0: + return ResponseObject(False, + "Update peer failed when updating allowed IPs: " + updateAllowedIp.decode().strip( + "\n")) + saveConfig = subprocess.check_output(f"wg-quick save {configName}", + shell=True, stderr=subprocess.STDOUT) + if f"wg showconf {configName}" not in saveConfig.decode().strip('\n'): + return ResponseObject(False, + "Update peer failed when saving the configuration." + saveConfig.decode().strip( + '\n')) + + cursor.execute( + '''UPDATE %s SET name = ?, private_key = ?, DNS = ?, endpoint_allowed_ip = ?, mtu = ?, + keepalive = ?, preshared_key = ? WHERE id = ?''' % configName, + (name, private_key, dns_addresses, endpoint_allowed_ip, data["mtu"], + data["keepalive"], preshared_key, id,) + ) + return ResponseObject() + + except subprocess.CalledProcessError as exc: + return ResponseObject(False, exc.output.decode("UTF-8").strip()) + + return ResponseObject(False, "Peer does not exist") + + +@app.route("/api/downloadPeer/") +def API_downloadPeer(configName): + if configName in WireguardConfigurations.keys(): + pass + return ResponseObject(False) + + @app.route('/api/getWireguardConfigurationInfo', methods=["GET"]) def API_getConfigurationInfo(): configurationName = request.args.get("configurationName") @@ -843,6 +983,11 @@ def API_getDashboardTheme(): return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1]) +''' +Sign Up +''' + + @app.route('/api/isTotpEnabled') def API_isTotpEnabled(): return ResponseObject(data=DashboardConfig.GetConfig("Account", "enable_totp")[1]) diff --git a/src/static/app/src/components/configurationComponents/peer.vue b/src/static/app/src/components/configurationComponents/peer.vue index c43af9c..171f8a1 100644 --- a/src/static/app/src/components/configurationComponents/peer.vue +++ b/src/static/app/src/components/configurationComponents/peer.vue @@ -74,6 +74,7 @@ export default {
- - - - -

Peers

- Peer Settings - Add Peer + Add Peer
@@ -448,11 +445,17 @@ export default {
- +
-
+ + + + diff --git a/src/static/app/src/components/configurationComponents/peerSettings.vue b/src/static/app/src/components/configurationComponents/peerSettings.vue index cbd93c2..dac7fae 100644 --- a/src/static/app/src/components/configurationComponents/peerSettings.vue +++ b/src/static/app/src/components/configurationComponents/peerSettings.vue @@ -1,32 +1,198 @@ \ No newline at end of file diff --git a/src/static/app/src/components/configurationComponents/peerSettingsDropdown.vue b/src/static/app/src/components/configurationComponents/peerSettingsDropdown.vue index 0fd3646..48adf8b 100644 --- a/src/static/app/src/components/configurationComponents/peerSettingsDropdown.vue +++ b/src/static/app/src/components/configurationComponents/peerSettingsDropdown.vue @@ -21,7 +21,9 @@ export default {
  • - + Edit
  • diff --git a/src/static/app/src/components/configurationList.vue b/src/static/app/src/components/configurationList.vue index 63d3f00..a761bc3 100644 --- a/src/static/app/src/components/configurationList.vue +++ b/src/static/app/src/components/configurationList.vue @@ -18,7 +18,7 @@ export default {
    -

    Wireguard Configurations

    +

    WireGuard Configurations

    Configuration diff --git a/src/static/app/src/router/index.js b/src/static/app/src/router/index.js index 565204c..c1a89ec 100644 --- a/src/static/app/src/router/index.js +++ b/src/static/app/src/router/index.js @@ -30,34 +30,46 @@ const router = createRouter({ path: '/', component: Index, meta: { - requiresAuth: true + requiresAuth: true, + }, children: [ { name: "Configuration List", path: '', - component: ConfigurationList + component: ConfigurationList, + meta: { + title: "WireGuard Configurations" + } }, { name: "Settings", path: '/settings', - component: Settings + component: Settings, + meta: { + title: "Settings" + } }, { name: "New Configuration", path: '/new_configuration', - component: NewConfiguration + component: NewConfiguration, + meta: { + title: "New Configuration" + } }, { name: "Configuration", - path: '/configuration/:id/', + path: '/configuration/:id', component: Configuration, + meta: { + title: "Configuration" + }, children: [ - { - name: "Peer Settings", - path: 'peer_settings', - component: PeerSettings + name: "Peers List", + path: '', + component: PeerList } ] }, @@ -65,7 +77,10 @@ const router = createRouter({ ] }, { - path: '/signin', component: Signin + path: '/signin', component: Signin, + meta: { + title: "Sign In" + } }, { path: '/welcome', component: Setup, @@ -80,6 +95,15 @@ router.beforeEach(async (to, from, next) => { const wireguardConfigurationsStore = WireguardConfigurationsStore(); const dashboardConfigurationStore = DashboardConfigurationStore(); + if (to.meta.title){ + if (to.params.id){ + document.title = to.params.id + " | WGDashboard"; + }else{ + document.title = to.meta.title + " | WGDashboard"; + } + }else{ + document.title = "WGDashboard" + } if (to.meta.requiresAuth){ if (cookie.getCookie("authToken") && await checkAuth()){ diff --git a/src/static/app/src/views/configuration.vue b/src/static/app/src/views/configuration.vue index 9ea269a..e2d2217 100644 --- a/src/static/app/src/views/configuration.vue +++ b/src/static/app/src/views/configuration.vue @@ -71,7 +71,12 @@ export default {