mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-22 07:10:09 +01:00
Kind of finished revamping add peers
Still need to clean some of the codes but overall is good :)
This commit is contained in:
parent
57c2e89f00
commit
769ca4e26d
7
src/bulkAddBash.sh
Normal file
7
src/bulkAddBash.sh
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
for ((i = 0 ; i<$1 ; i++ ))
|
||||||
|
do
|
||||||
|
privateKey=$(wg genkey)
|
||||||
|
presharedKey=$(wg genkey)
|
||||||
|
publicKey=$(wg pubkey <<< "$privateKey")
|
||||||
|
echo "$privateKey,$publicKey,$presharedKey"
|
||||||
|
done
|
@ -1240,7 +1240,7 @@ def add_peer(config_name):
|
|||||||
return "Please fill in all required box."
|
return "Please fill in all required box."
|
||||||
if not isinstance(keys, list):
|
if not isinstance(keys, list):
|
||||||
return config_name + " is not running."
|
return config_name + " is not running."
|
||||||
if public_key in keys:
|
if public_key in keys:d;lp
|
||||||
return "Public key already exist."
|
return "Public key already exist."
|
||||||
check_dup_ip = g.cur.execute(
|
check_dup_ip = g.cur.execute(
|
||||||
"SELECT COUNT(*) FROM " + config_name + " WHERE allowed_ip LIKE '" + allowed_ips + "/%'", ) \
|
"SELECT COUNT(*) FROM " + config_name + " WHERE allowed_ip LIKE '" + allowed_ips + "/%'", ) \
|
||||||
|
@ -28,7 +28,6 @@ import psutil
|
|||||||
import pyotp
|
import pyotp
|
||||||
from flask import Flask, request, render_template, redirect, url_for, session, jsonify, g
|
from flask import Flask, request, render_template, redirect, url_for, session, jsonify, g
|
||||||
from flask.json.provider import JSONProvider
|
from flask.json.provider import JSONProvider
|
||||||
from flask_qrcode import QRcode
|
|
||||||
from json import JSONEncoder
|
from json import JSONEncoder
|
||||||
|
|
||||||
from icmplib import ping, traceroute
|
from icmplib import ping, traceroute
|
||||||
@ -41,7 +40,7 @@ from sqlalchemy import FLOAT, INT, VARCHAR, select, MetaData, DATETIME
|
|||||||
from sqlalchemy import create_engine, inspect
|
from sqlalchemy import create_engine, inspect
|
||||||
from flask.json.provider import DefaultJSONProvider
|
from flask.json.provider import DefaultJSONProvider
|
||||||
|
|
||||||
DASHBOARD_VERSION = 'v3.1'
|
DASHBOARD_VERSION = 'v4.0'
|
||||||
CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
|
CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
|
||||||
DB_PATH = os.path.join(CONFIGURATION_PATH, 'db')
|
DB_PATH = os.path.join(CONFIGURATION_PATH, 'db')
|
||||||
if not os.path.isdir(DB_PATH):
|
if not os.path.isdir(DB_PATH):
|
||||||
@ -57,8 +56,6 @@ UPDATE = None
|
|||||||
app = Flask("WGDashboard")
|
app = Flask("WGDashboard")
|
||||||
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 5206928
|
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 5206928
|
||||||
app.secret_key = secrets.token_urlsafe(32)
|
app.secret_key = secrets.token_urlsafe(32)
|
||||||
# Enable QR Code Generator
|
|
||||||
QRcode(app)
|
|
||||||
|
|
||||||
|
|
||||||
class ModelEncoder(JSONEncoder):
|
class ModelEncoder(JSONEncoder):
|
||||||
@ -74,7 +71,14 @@ Classes
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
# Base = declarative_base(class_registry=dict())
|
def ResponseObject(status=True, message=None, data=None) -> Flask.response_class:
|
||||||
|
response = Flask.make_response(app, {
|
||||||
|
"status": status,
|
||||||
|
"message": message,
|
||||||
|
"data": data
|
||||||
|
})
|
||||||
|
response.content_type = "application/json"
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
class CustomJsonEncoder(DefaultJSONProvider):
|
class CustomJsonEncoder(DefaultJSONProvider):
|
||||||
@ -90,38 +94,6 @@ class CustomJsonEncoder(DefaultJSONProvider):
|
|||||||
app.json = CustomJsonEncoder(app)
|
app.json = CustomJsonEncoder(app)
|
||||||
|
|
||||||
|
|
||||||
class Peer:
|
|
||||||
def __init__(self, tableData):
|
|
||||||
# for i in range(0, len(table)):
|
|
||||||
# tableData[table.description[i][0]] = table[i]
|
|
||||||
|
|
||||||
self.id = tableData["id"]
|
|
||||||
self.private_key = tableData["private_key"]
|
|
||||||
self.DNS = tableData["DNS"]
|
|
||||||
self.endpoint_allowed_ip = tableData["endpoint_allowed_ip"]
|
|
||||||
self.name = tableData["name"]
|
|
||||||
self.total_receive = tableData["total_receive"]
|
|
||||||
self.total_sent = tableData["total_sent"]
|
|
||||||
self.total_data = tableData["total_data"]
|
|
||||||
self.endpoint = tableData["endpoint"]
|
|
||||||
self.status = tableData["status"]
|
|
||||||
self.latest_handshake = tableData["latest_handshake"]
|
|
||||||
self.allowed_ip = tableData["allowed_ip"]
|
|
||||||
self.cumu_receive = tableData["cumu_receive"]
|
|
||||||
self.cumu_sent = tableData["cumu_sent"]
|
|
||||||
self.cumu_data = tableData["cumu_data"]
|
|
||||||
self.mtu = tableData["mtu"]
|
|
||||||
self.keepalive = tableData["keepalive"]
|
|
||||||
self.remote_endpoint = tableData["remote_endpoint"]
|
|
||||||
self.preshared_key = tableData["preshared_key"]
|
|
||||||
|
|
||||||
def toJson(self):
|
|
||||||
return self.__dict__
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return str(self.toJson())
|
|
||||||
|
|
||||||
|
|
||||||
class WireguardConfiguration:
|
class WireguardConfiguration:
|
||||||
class InvalidConfigurationFileException(Exception):
|
class InvalidConfigurationFileException(Exception):
|
||||||
def __init__(self, m):
|
def __init__(self, m):
|
||||||
@ -200,7 +172,7 @@ class WireguardConfiguration:
|
|||||||
|
|
||||||
# Create tables in database
|
# Create tables in database
|
||||||
self.__createDatabase()
|
self.__createDatabase()
|
||||||
self.__getPeers()
|
self.getPeersList()
|
||||||
|
|
||||||
def __createDatabase(self):
|
def __createDatabase(self):
|
||||||
existingTables = cursor.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
|
existingTables = cursor.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
|
||||||
@ -326,12 +298,12 @@ class WireguardConfiguration:
|
|||||||
""" % self.Name
|
""" % self.Name
|
||||||
, newPeer)
|
, newPeer)
|
||||||
sqldb.commit()
|
sqldb.commit()
|
||||||
self.Peers.append(Peer(newPeer))
|
self.Peers.append(Peer(newPeer, self))
|
||||||
else:
|
else:
|
||||||
cursor.execute("UPDATE %s SET allowed_ip = ? WHERE id = ?" % self.Name,
|
cursor.execute("UPDATE %s SET allowed_ip = ? WHERE id = ?" % self.Name,
|
||||||
(i.get("AllowedIPs", "N/A"), i['PublicKey'],))
|
(i.get("AllowedIPs", "N/A"), i['PublicKey'],))
|
||||||
sqldb.commit()
|
sqldb.commit()
|
||||||
self.Peers.append(Peer(checkIfExist))
|
self.Peers.append(Peer(checkIfExist, self))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -462,7 +434,7 @@ class WireguardConfiguration:
|
|||||||
self.getStatus()
|
self.getStatus()
|
||||||
return True, None
|
return True, None
|
||||||
|
|
||||||
def getPeers(self):
|
def getPeersList(self):
|
||||||
self.__getPeers()
|
self.__getPeers()
|
||||||
return self.Peers
|
return self.Peers
|
||||||
|
|
||||||
@ -483,6 +455,94 @@ class WireguardConfiguration:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Peer:
|
||||||
|
def __init__(self, tableData, configuration: WireguardConfiguration):
|
||||||
|
self.configuration = configuration
|
||||||
|
self.id = tableData["id"]
|
||||||
|
self.private_key = tableData["private_key"]
|
||||||
|
self.DNS = tableData["DNS"]
|
||||||
|
self.endpoint_allowed_ip = tableData["endpoint_allowed_ip"]
|
||||||
|
self.name = tableData["name"]
|
||||||
|
self.total_receive = tableData["total_receive"]
|
||||||
|
self.total_sent = tableData["total_sent"]
|
||||||
|
self.total_data = tableData["total_data"]
|
||||||
|
self.endpoint = tableData["endpoint"]
|
||||||
|
self.status = tableData["status"]
|
||||||
|
self.latest_handshake = tableData["latest_handshake"]
|
||||||
|
self.allowed_ip = tableData["allowed_ip"]
|
||||||
|
self.cumu_receive = tableData["cumu_receive"]
|
||||||
|
self.cumu_sent = tableData["cumu_sent"]
|
||||||
|
self.cumu_data = tableData["cumu_data"]
|
||||||
|
self.mtu = tableData["mtu"]
|
||||||
|
self.keepalive = tableData["keepalive"]
|
||||||
|
self.remote_endpoint = tableData["remote_endpoint"]
|
||||||
|
self.preshared_key = tableData["preshared_key"]
|
||||||
|
|
||||||
|
def toJson(self):
|
||||||
|
return self.__dict__
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self.toJson())
|
||||||
|
|
||||||
|
def updatePeer(self, name: str, private_key: str,
|
||||||
|
preshared_key: str,
|
||||||
|
dns_addresses: str, allowed_ip: str, endpoint_allowed_ip: str, mtu: int,
|
||||||
|
keepalive: int) -> ResponseObject:
|
||||||
|
|
||||||
|
existingAllowedIps = [item for row in list(
|
||||||
|
map(lambda x: [q.strip() for q in x.split(',')],
|
||||||
|
map(lambda y: y.allowed_ip,
|
||||||
|
list(filter(lambda k: k.id != self.id, self.configuration.getPeersList()))))) for item in row]
|
||||||
|
|
||||||
|
if allowed_ip in existingAllowedIps:
|
||||||
|
return ResponseObject(False, "Allowed IP already taken by another peer.")
|
||||||
|
if not _checkIPWithRange(endpoint_allowed_ip):
|
||||||
|
return ResponseObject(False, f"Endpoint Allowed IPs format is incorrect.")
|
||||||
|
if len(dns_addresses) > 0 and not _checkDNS(dns_addresses):
|
||||||
|
return ResponseObject(False, f"DNS format is incorrect.")
|
||||||
|
if mtu < 0 or mtu > 1460:
|
||||||
|
return ResponseObject(False, "MTU format is not correct.")
|
||||||
|
if keepalive < 0:
|
||||||
|
return ResponseObject(False, "Persistent Keepalive format is not correct.")
|
||||||
|
if len(private_key) > 0:
|
||||||
|
pubKey = _generatePrivateKey(private_key)
|
||||||
|
if not pubKey[0] or pubKey[1] != self.id:
|
||||||
|
return ResponseObject(False, "Private key does not match with the public key.")
|
||||||
|
try:
|
||||||
|
if len(preshared_key) > 0:
|
||||||
|
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 {self.configuration.Name} peer {self.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")
|
||||||
|
updateAllowedIp = subprocess.check_output(
|
||||||
|
f'wg set {self.configuration.Name} peer {self.id} allowed-ips "{allowed_ip.replace(" ", "")}"',
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
if len(updateAllowedIp.decode().strip("\n")) != 0:
|
||||||
|
return ResponseObject(False,
|
||||||
|
"Update peer failed when updating allowed IPs")
|
||||||
|
saveConfig = subprocess.check_output(f"wg-quick save {self.configuration.Name}",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
if f"wg showconf {self.configuration.Name}" not in saveConfig.decode().strip('\n'):
|
||||||
|
return ResponseObject(False,
|
||||||
|
"Update peer failed when saving the configuration.")
|
||||||
|
cursor.execute(
|
||||||
|
'''UPDATE %s SET name = ?, private_key = ?, DNS = ?, endpoint_allowed_ip = ?, mtu = ?,
|
||||||
|
keepalive = ?, preshared_key = ? WHERE id = ?''' % self.configuration.Name,
|
||||||
|
(name, private_key, dns_addresses, endpoint_allowed_ip, mtu,
|
||||||
|
keepalive, preshared_key, self.id,)
|
||||||
|
)
|
||||||
|
return ResponseObject()
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
return ResponseObject(False, exc.output.decode("UTF-8").strip())
|
||||||
|
|
||||||
|
|
||||||
# Regex Match
|
# Regex Match
|
||||||
def regex_match(regex, text):
|
def regex_match(regex, text):
|
||||||
pattern = re.compile(regex)
|
pattern = re.compile(regex)
|
||||||
@ -498,8 +558,10 @@ def iPv46RegexCheck(ip):
|
|||||||
class DashboardConfig:
|
class DashboardConfig:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
if not os.path.exists(DASHBOARD_CONF):
|
||||||
|
open(DASHBOARD_CONF, "x")
|
||||||
self.__config = configparser.ConfigParser(strict=False)
|
self.__config = configparser.ConfigParser(strict=False)
|
||||||
self.__config.read_file(open(DASHBOARD_CONF, "w+"))
|
self.__config.read_file(open(DASHBOARD_CONF, "r+"))
|
||||||
self.hiddenAttribute = ["totp_key"]
|
self.hiddenAttribute = ["totp_key"]
|
||||||
self.__default = {
|
self.__default = {
|
||||||
"Account": {
|
"Account": {
|
||||||
@ -640,18 +702,8 @@ class DashboardConfig:
|
|||||||
return the_dict
|
return the_dict
|
||||||
|
|
||||||
|
|
||||||
def ResponseObject(status=True, message=None, data=None) -> Flask.response_class:
|
|
||||||
response = Flask.make_response(app, {
|
|
||||||
"status": status,
|
|
||||||
"message": message,
|
|
||||||
"data": data
|
|
||||||
})
|
|
||||||
response.content_type = "application/json"
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
DashboardConfig = DashboardConfig()
|
DashboardConfig = DashboardConfig()
|
||||||
WireguardConfigurations: {str: WireguardConfiguration} = {}
|
WireguardConfigurations: dict[str, WireguardConfiguration] = {}
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Private Functions
|
Private Functions
|
||||||
@ -729,7 +781,19 @@ def _generatePublicKey(privateKey) -> [bool, str]:
|
|||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
def _getWireguardConfigurationAvailableIP(configName) -> [bool, list[str]]:
|
def _generatePrivateKey() -> [bool, str]:
|
||||||
|
try:
|
||||||
|
publicKey = subprocess.check_output(f"wg genkey", shell=True,
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
return True, publicKey.decode().strip('\n')
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _getWireguardConfigurationAvailableIP(configName: str) -> tuple[bool, list[str]] | tuple[bool, None]:
|
||||||
if configName not in WireguardConfigurations.keys():
|
if configName not in WireguardConfigurations.keys():
|
||||||
return False, None
|
return False, None
|
||||||
configuration = WireguardConfigurations[configName]
|
configuration = WireguardConfigurations[configName]
|
||||||
@ -921,7 +985,6 @@ def API_updateDashboardConfigurationItem():
|
|||||||
def API_updatePeerSettings(configName):
|
def API_updatePeerSettings(configName):
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
id = data['id']
|
id = data['id']
|
||||||
|
|
||||||
if len(id) > 0 and configName in WireguardConfigurations.keys():
|
if len(id) > 0 and configName in WireguardConfigurations.keys():
|
||||||
name = data['name']
|
name = data['name']
|
||||||
private_key = data['private_key']
|
private_key = data['private_key']
|
||||||
@ -929,69 +992,80 @@ def API_updatePeerSettings(configName):
|
|||||||
allowed_ip = data['allowed_ip']
|
allowed_ip = data['allowed_ip']
|
||||||
endpoint_allowed_ip = data['endpoint_allowed_ip']
|
endpoint_allowed_ip = data['endpoint_allowed_ip']
|
||||||
preshared_key = data['preshared_key']
|
preshared_key = data['preshared_key']
|
||||||
|
mtu = data['mtu']
|
||||||
|
keepalive = data['keepalive']
|
||||||
wireguardConfig = WireguardConfigurations[configName]
|
wireguardConfig = WireguardConfigurations[configName]
|
||||||
foundPeer, peer = wireguardConfig.searchPeer(id)
|
foundPeer, peer = wireguardConfig.searchPeer(id)
|
||||||
if foundPeer:
|
if foundPeer:
|
||||||
for p in wireguardConfig.Peers:
|
return peer.updatePeer(name, private_key, preshared_key, dns_addresses,
|
||||||
if allowed_ip in p.allowed_ip and p.id != peer.id:
|
allowed_ip, endpoint_allowed_ip, mtu, keepalive)
|
||||||
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 len(dns_addresses) > 0 and _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")
|
return ResponseObject(False, "Peer does not exist")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/addPeers/<configName>', methods=['POST'])
|
||||||
|
def API_addPeers(configName):
|
||||||
|
data = request.get_json()
|
||||||
|
bulkAdd = data['bulkAdd']
|
||||||
|
bulkAddAmount = data['bulkAddAmount']
|
||||||
|
public_key = data['public_key']
|
||||||
|
allowed_ips = data['allowed_ips']
|
||||||
|
endpoint_allowed_ip = data['endpoint_allowed_ip']
|
||||||
|
dns_addresses = data['DNS']
|
||||||
|
mtu = data['mtu']
|
||||||
|
keep_alive = data['keepalive']
|
||||||
|
preshared_key = data['preshared_key']
|
||||||
|
|
||||||
|
if configName in WireguardConfigurations.keys():
|
||||||
|
config = WireguardConfigurations.get(configName)
|
||||||
|
if (not bulkAdd and (len(public_key) == 0 or len(allowed_ips) == 0)) or len(endpoint_allowed_ip) == 0:
|
||||||
|
return ResponseObject(False, "Please fill in all required box.")
|
||||||
|
if not config.getStatus():
|
||||||
|
return ResponseObject(False,
|
||||||
|
f"{configName} is not running, please turn on the configuration before adding peers.")
|
||||||
|
if bulkAdd:
|
||||||
|
if bulkAddAmount < 1:
|
||||||
|
return ResponseObject(False, "Please specify amount of peers you want to add")
|
||||||
|
availableIps = _getWireguardConfigurationAvailableIP(configName)
|
||||||
|
if not availableIps[0]:
|
||||||
|
return ResponseObject(False, "No more available IP can assign")
|
||||||
|
if bulkAddAmount > len(availableIps[1]):
|
||||||
|
return ResponseObject(False,
|
||||||
|
f"The maximum number of peers can add is {len(availableIps[1])}")
|
||||||
|
|
||||||
|
keyPairs = []
|
||||||
|
for i in range(bulkAddAmount):
|
||||||
|
key = _generatePrivateKey()[1]
|
||||||
|
keyPairs.append([key, _generatePublicKey(key), _generatePrivateKey()[1]])
|
||||||
|
if len(keyPairs) == 0:
|
||||||
|
return ResponseObject(False, "Generating key pairs by bulk failed")
|
||||||
|
|
||||||
|
print(keyPairs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
if config.searchPeer(public_key)[0] is True:
|
||||||
|
return ResponseObject(False, f"This peer already exist.")
|
||||||
|
name = data['name']
|
||||||
|
private_key = data['private_key']
|
||||||
|
subprocess.check_output(
|
||||||
|
f"wg set {config.Name} peer {public_key} allowed-ips {''.join(allowed_ips)}",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
if len(preshared_key) > 0:
|
||||||
|
subprocess.check_output(
|
||||||
|
f"wg set {config.Name} peer {public_key} preshared-key {preshared_key}",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
subprocess.check_output(
|
||||||
|
f"wg-quick save {config.Name}", shell=True, stderr=subprocess.STDOUT)
|
||||||
|
config.getPeersList()
|
||||||
|
found, peer = config.searchPeer(public_key)
|
||||||
|
if found:
|
||||||
|
return peer.updatePeer(name, private_key, preshared_key, dns_addresses, ",".join(allowed_ips),
|
||||||
|
endpoint_allowed_ip, mtu, keep_alive)
|
||||||
|
|
||||||
|
return ResponseObject(False, "Configuration does not exist")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/downloadPeer/<configName>")
|
@app.route("/api/downloadPeer/<configName>")
|
||||||
def API_downloadPeer(configName):
|
def API_downloadPeer(configName):
|
||||||
data = request.args
|
data = request.args
|
||||||
@ -1050,7 +1124,7 @@ def API_getConfigurationInfo():
|
|||||||
return ResponseObject(False, "Please provide configuration name")
|
return ResponseObject(False, "Please provide configuration name")
|
||||||
return ResponseObject(data={
|
return ResponseObject(data={
|
||||||
"configurationInfo": WireguardConfigurations[configurationName],
|
"configurationInfo": WireguardConfigurations[configurationName],
|
||||||
"configurationPeers": WireguardConfigurations[configurationName].getPeers()
|
"configurationPeers": WireguardConfigurations[configurationName].getPeersList()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -1082,7 +1156,9 @@ def API_Welcome_GetTotpLink():
|
|||||||
def API_Welcome_VerifyTotpLink():
|
def API_Welcome_VerifyTotpLink():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
if DashboardConfig.GetConfig("Other", "welcome_session")[1]:
|
if DashboardConfig.GetConfig("Other", "welcome_session")[1]:
|
||||||
return ResponseObject(pyotp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).now() == data['totp'])
|
totp = pyotp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).now()
|
||||||
|
print(totp)
|
||||||
|
return ResponseObject(totp == data['totp'])
|
||||||
return ResponseObject(False)
|
return ResponseObject(False)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Flask
|
bcrypt
|
||||||
ifcfg
|
ifcfg
|
||||||
|
psutil
|
||||||
|
pyotp
|
||||||
|
flask
|
||||||
icmplib
|
icmplib
|
||||||
flask-qrcode
|
|
||||||
gunicorn
|
|
||||||
certbot
|
|
||||||
sqlalchemy
|
sqlalchemy
|
@ -29,14 +29,14 @@ export default {
|
|||||||
searchAvailableIps(){
|
searchAvailableIps(){
|
||||||
return this.availableIpSearchString ?
|
return this.availableIpSearchString ?
|
||||||
this.availableIp.filter(x =>
|
this.availableIp.filter(x =>
|
||||||
x.includes(this.availableIpSearchString) && !this.data.allowed_ip.includes(x)) :
|
x.includes(this.availableIpSearchString) && !this.data.allowed_ips.includes(x)) :
|
||||||
this.availableIp.filter(x => !this.data.allowed_ip.includes(x))
|
this.availableIp.filter(x => !this.data.allowed_ips.includes(x))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addAllowedIp(ip){
|
addAllowedIp(ip){
|
||||||
if(this.store.checkCIDR(ip)){
|
if(this.store.checkCIDR(ip)){
|
||||||
this.data.allowed_ip.push(ip);
|
this.data.allowed_ips.push(ip);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -55,11 +55,11 @@ export default {
|
|||||||
<label for="peer_allowed_ip_textbox" class="form-label">
|
<label for="peer_allowed_ip_textbox" class="form-label">
|
||||||
<small class="text-muted">Allowed IPs <code>(Required)</code></small>
|
<small class="text-muted">Allowed IPs <code>(Required)</code></small>
|
||||||
</label>
|
</label>
|
||||||
<div class="d-flex gap-2 flex-wrap" :class="{'mb-2': this.data.allowed_ip.length > 0}">
|
<div class="d-flex gap-2 flex-wrap" :class="{'mb-2': this.data.allowed_ips.length > 0}">
|
||||||
<TransitionGroup name="list">
|
<TransitionGroup name="list">
|
||||||
<span class="badge rounded-pill text-bg-success" v-for="(ip, index) in this.data.allowed_ip" :key="ip">
|
<span class="badge rounded-pill text-bg-success" v-for="(ip, index) in this.data.allowed_ips" :key="ip">
|
||||||
{{ip}}
|
{{ip}}
|
||||||
<a role="button" @click="this.data.allowed_ip.splice(index, 1)">
|
<a role="button" @click="this.data.allowed_ips.splice(index, 1)">
|
||||||
<i class="bi bi-x-circle-fill ms-1"></i></a>
|
<i class="bi bi-x-circle-fill ms-1"></i></a>
|
||||||
</span>
|
</span>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
// import {Popover, Dropdown} from "bootstrap";
|
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
|
||||||
import {fetchGet} from "@/utilities/fetch.js";
|
|
||||||
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
|
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
|
||||||
import NameInput from "@/components/configurationComponents/newPeersComponents/nameInput.vue";
|
import NameInput from "@/components/configurationComponents/newPeersComponents/nameInput.vue";
|
||||||
import PrivatePublicKeyInput from "@/components/configurationComponents/newPeersComponents/privatePublicKeyInput.vue";
|
import PrivatePublicKeyInput from "@/components/configurationComponents/newPeersComponents/privatePublicKeyInput.vue";
|
||||||
@ -27,7 +26,7 @@ export default {
|
|||||||
bulkAdd: false,
|
bulkAdd: false,
|
||||||
bulkAddAmount: "",
|
bulkAddAmount: "",
|
||||||
name: "",
|
name: "",
|
||||||
allowed_ip: [],
|
allowed_ips: [],
|
||||||
private_key: "",
|
private_key: "",
|
||||||
public_key: "",
|
public_key: "",
|
||||||
DNS: this.dashboardStore.Configuration.Peers.peer_global_dns,
|
DNS: this.dashboardStore.Configuration.Peers.peer_global_dns,
|
||||||
@ -54,6 +53,19 @@ export default {
|
|||||||
const dashboardStore = DashboardConfigurationStore();
|
const dashboardStore = DashboardConfigurationStore();
|
||||||
return {store, dashboardStore}
|
return {store, dashboardStore}
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
peerCreate(){
|
||||||
|
fetchPost("/api/addPeers/" + this.$route.params.id, this.data, (res) => {
|
||||||
|
if (res.status){
|
||||||
|
this.$router.push(`/configuration/${this.$route.params.id}/peers`)
|
||||||
|
this.dashboardStore.newMessage("Server", "Peer create successfully", "success")
|
||||||
|
}else{
|
||||||
|
this.dashboardStore.newMessage("Server", res.message, "danger")
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
computed:{
|
computed:{
|
||||||
allRequireFieldsFilled(){
|
allRequireFieldsFilled(){
|
||||||
let status = true;
|
let status = true;
|
||||||
@ -63,8 +75,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
let requireFields =
|
let requireFields =
|
||||||
["allowed_ip", "private_key", "public_key", "endpoint_allowed_ip", "keepalive", "mtu"]
|
["allowed_ips", "private_key", "public_key", "endpoint_allowed_ip", "keepalive", "mtu"]
|
||||||
|
|
||||||
requireFields.forEach(x => {
|
requireFields.forEach(x => {
|
||||||
if (this.data[x].length === 0) status = false;
|
if (this.data[x].length === 0) status = false;
|
||||||
});
|
});
|
||||||
@ -121,6 +132,7 @@ export default {
|
|||||||
<div class="d-flex mt-2">
|
<div class="d-flex mt-2">
|
||||||
<button class="ms-auto btn btn-dark btn-brand rounded-3 px-3 py-2 shadow"
|
<button class="ms-auto btn btn-dark btn-brand rounded-3 px-3 py-2 shadow"
|
||||||
:disabled="!this.allRequireFieldsFilled"
|
:disabled="!this.allRequireFieldsFilled"
|
||||||
|
@click="this.peerCreate()"
|
||||||
>
|
>
|
||||||
<i class="bi bi-plus-circle-fill me-2"></i>Add
|
<i class="bi bi-plus-circle-fill me-2"></i>Add
|
||||||
</button>
|
</button>
|
||||||
|
17
src/static/app/src/test.py
Normal file
17
src/static/app/src/test.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def _generateKeyPairs(amount: int) -> list[list[str]] | None:
|
||||||
|
try:
|
||||||
|
pairs = subprocess.check_output(
|
||||||
|
f'''for ((i = 0 ; i<{amount} ; i++ ));do privateKey=$(wg genkey) presharedKey=$(wg genkey) publicKey=$(wg pubkey <<< "$privateKey") echo "$privateKey,$publicKey,$presharedKey"; done''', shell=True, stderr=subprocess.STDOUT
|
||||||
|
)
|
||||||
|
pairs = pairs.decode().split("\n")
|
||||||
|
print(pairs)
|
||||||
|
return [x.split(",") for x in pairs]
|
||||||
|
except subprocess.CalledProcessError as exp:
|
||||||
|
print(str(exp))
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
_generateKeyPairs(20)
|
@ -71,7 +71,7 @@ export default {
|
|||||||
{{this.errorMessage}}
|
{{this.errorMessage}}
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex flex-column gap-3">
|
<div class="d-flex flex-column gap-3">
|
||||||
<div id="createAccount">
|
<div id="createAccount" class="d-flex flex-column gap-2">
|
||||||
<div class="form-group text-body">
|
<div class="form-group text-body">
|
||||||
<label for="username" class="mb-1 text-muted">
|
<label for="username" class="mb-1 text-muted">
|
||||||
<small>Pick an username you like</small></label>
|
<small>Pick an username you like</small></label>
|
||||||
|
Loading…
Reference in New Issue
Block a user