2022-03-24 07:10:52 +01:00
|
|
|
import ipaddress, subprocess, datetime, os, util
|
2022-04-10 15:26:54 +02:00
|
|
|
from datetime import datetime, timedelta
|
2022-04-07 02:59:23 +02:00
|
|
|
from flask import jsonify
|
2022-03-24 07:10:52 +01:00
|
|
|
from util import *
|
2022-04-21 21:11:01 +02:00
|
|
|
import configparser
|
2022-03-25 01:43:56 +01:00
|
|
|
|
2022-03-24 07:10:52 +01:00
|
|
|
notEnoughParameter = {"status": False, "reason": "Please provide all required parameters."}
|
|
|
|
good = {"status": True, "reason": ""}
|
2022-03-22 03:33:19 +01:00
|
|
|
|
2022-04-21 21:11:01 +02:00
|
|
|
def ret(status=True, reason="", data=""):
|
|
|
|
return {"status": status, "reason": reason, "data": data}
|
|
|
|
|
|
|
|
|
2022-03-25 01:43:56 +01:00
|
|
|
|
2022-03-24 07:10:52 +01:00
|
|
|
def togglePeerAccess(data, g):
|
|
|
|
checkUnlock = g.cur.execute(f"SELECT * FROM {data['config']} WHERE id='{data['peerID']}'").fetchone()
|
|
|
|
if checkUnlock:
|
2022-03-25 01:43:56 +01:00
|
|
|
moveUnlockToLock = g.cur.execute(
|
|
|
|
f"INSERT INTO {data['config']}_restrict_access SELECT * FROM {data['config']} WHERE id = '{data['peerID']}'")
|
2022-03-24 07:10:52 +01:00
|
|
|
if g.cur.rowcount == 1:
|
|
|
|
print(g.cur.rowcount)
|
|
|
|
print(util.deletePeers(data['config'], [data['peerID']], g.cur, g.db))
|
|
|
|
else:
|
2022-03-25 01:43:56 +01:00
|
|
|
moveLockToUnlock = g.cur.execute(
|
|
|
|
f"SELECT * FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'").fetchone()
|
2022-03-24 07:10:52 +01:00
|
|
|
try:
|
|
|
|
if len(moveLockToUnlock[-1]) == 0:
|
2022-03-25 01:43:56 +01:00
|
|
|
status = subprocess.check_output(
|
|
|
|
f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]}",
|
|
|
|
shell=True, stderr=subprocess.STDOUT)
|
2022-03-24 07:10:52 +01:00
|
|
|
else:
|
|
|
|
now = str(datetime.datetime.now().strftime("%m%d%Y%H%M%S"))
|
|
|
|
f_name = now + "_tmp_psk.txt"
|
|
|
|
f = open(f_name, "w+")
|
|
|
|
f.write(moveLockToUnlock[-1])
|
|
|
|
f.close()
|
2022-03-25 01:43:56 +01:00
|
|
|
subprocess.check_output(
|
|
|
|
f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]} preshared-key {f_name}",
|
|
|
|
shell=True, stderr=subprocess.STDOUT)
|
2022-03-24 07:10:52 +01:00
|
|
|
os.remove(f_name)
|
|
|
|
status = subprocess.check_output(f"wg-quick save {data['config']}", shell=True, stderr=subprocess.STDOUT)
|
2022-03-25 01:43:56 +01:00
|
|
|
g.cur.execute(
|
|
|
|
f"INSERT INTO {data['config']} SELECT * FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
2022-03-24 07:10:52 +01:00
|
|
|
if g.cur.rowcount == 1:
|
|
|
|
g.cur.execute(f"DELETE FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
2022-03-25 01:43:56 +01:00
|
|
|
|
2022-03-24 07:10:52 +01:00
|
|
|
except subprocess.CalledProcessError as exc:
|
|
|
|
return {"status": False, "reason": str(exc.output.strip())}
|
|
|
|
return good
|
|
|
|
|
2022-04-07 02:59:23 +02:00
|
|
|
class managePeer:
|
|
|
|
def getPeerDataUsage(self, data, cur):
|
2022-04-10 15:26:54 +02:00
|
|
|
now = datetime.now()
|
|
|
|
now_string = now.strftime("%d/%m/%Y %H:%M:%S")
|
2022-04-07 02:59:23 +02:00
|
|
|
interval = {
|
2022-04-10 15:26:54 +02:00
|
|
|
"30min": now - timedelta(hours=0, minutes=30),
|
|
|
|
"1h": now - timedelta(hours=1, minutes=0),
|
|
|
|
"6h": now - timedelta(hours=6, minutes=0),
|
|
|
|
"24h": now - timedelta(hours=24, minutes=0),
|
2022-04-07 02:59:23 +02:00
|
|
|
"all": ""
|
|
|
|
}
|
|
|
|
if data['interval'] not in interval.keys():
|
|
|
|
return {"status": False, "reason": "Invalid interval."}
|
|
|
|
intv = ""
|
|
|
|
if data['interval'] != "all":
|
2022-04-10 15:26:54 +02:00
|
|
|
t = interval[data['interval']].strftime("%d/%m/%Y %H:%M:%S")
|
|
|
|
intv = f" AND time >= '{t}'"
|
|
|
|
timeData = cur.execute(f"SELECT total_receive, total_sent, time FROM wg0_transfer WHERE id='{data['peerID']}' {intv} ORDER BY time DESC;")
|
2022-04-07 02:59:23 +02:00
|
|
|
chartData = []
|
|
|
|
for i in timeData:
|
|
|
|
chartData.append({
|
|
|
|
"total_receive": i[0],
|
|
|
|
"total_sent": i[1],
|
|
|
|
"time": i[2]
|
|
|
|
})
|
|
|
|
return {"status": True, "reason": "", "data": chartData}
|
2022-03-24 07:10:52 +01:00
|
|
|
|
2022-04-21 21:11:01 +02:00
|
|
|
class manageConfiguration:
|
2022-03-25 01:43:56 +01:00
|
|
|
def AddressCheck(self, data):
|
2022-03-24 07:10:52 +01:00
|
|
|
address = data['address']
|
|
|
|
address = address.replace(" ", "")
|
|
|
|
address = address.split(',')
|
|
|
|
amount = 0
|
|
|
|
for i in address:
|
|
|
|
try:
|
|
|
|
ips = ipaddress.ip_network(i, False)
|
|
|
|
amount += ips.num_addresses
|
|
|
|
except ValueError as e:
|
|
|
|
return {"status": False, "reason": str(e)}
|
|
|
|
if amount >= 1:
|
2022-03-25 01:43:56 +01:00
|
|
|
return {"status": True, "reason": "", "data": f"Total of {amount} IPs"}
|
2022-03-24 07:10:52 +01:00
|
|
|
else:
|
2022-03-25 01:43:56 +01:00
|
|
|
return {"status": True, "reason": "", "data": f"0 available IPs"}
|
|
|
|
|
|
|
|
def PortCheck(self, data, configs):
|
2022-03-24 07:10:52 +01:00
|
|
|
port = data['port']
|
|
|
|
if (not port.isdigit()) or int(port) < 1 or int(port) > 65535:
|
|
|
|
return {"status": False, "reason": f"Invalid port."}
|
|
|
|
for i in configs:
|
|
|
|
if i['port'] == port:
|
|
|
|
return {"status": False, "reason": f"{port} used by {i['conf']}."}
|
2022-03-29 21:11:50 +02:00
|
|
|
checkSystem = subprocess.run(f'ss -tulpn | grep :{port} > /dev/null', shell=True)
|
|
|
|
if checkSystem.returncode != 1:
|
|
|
|
return {"status": False, "reason": f"Port {port} used by other process in your system."}
|
2022-03-24 07:10:52 +01:00
|
|
|
return good
|
2022-03-25 01:43:56 +01:00
|
|
|
|
|
|
|
def NameCheck(self, data, configs):
|
2022-03-24 07:10:52 +01:00
|
|
|
name = data['name']
|
|
|
|
name = name.replace(" ", "")
|
|
|
|
for i in configs:
|
|
|
|
if name == i['conf']:
|
2022-03-25 01:43:56 +01:00
|
|
|
return {"status": False, "reason": f"{name} already existed."}
|
|
|
|
illegal_filename = ["(Space)", " ", ".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "com1", "com2",
|
|
|
|
"com3",
|
|
|
|
"com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4",
|
|
|
|
"lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "con", "nul", "prn"]
|
|
|
|
for i in illegal_filename:
|
|
|
|
name = name.replace(i, "")
|
|
|
|
if len(name) == 0:
|
|
|
|
return {"status": False, "reason": "Invalid name."}
|
2022-03-24 07:10:52 +01:00
|
|
|
return good
|
|
|
|
|
2022-03-25 01:43:56 +01:00
|
|
|
def addConfiguration(self, data, configs, WG_CONF_PATH):
|
2022-03-24 07:10:52 +01:00
|
|
|
output = ["[Interface]", "SaveConfig = true"]
|
2022-03-25 01:43:56 +01:00
|
|
|
required = ['addConfigurationPrivateKey', 'addConfigurationListenPort',
|
|
|
|
'addConfigurationAddress', 'addConfigurationPreUp', 'addConfigurationPreDown',
|
|
|
|
'addConfigurationPostUp', 'addConfigurationPostDown']
|
2022-03-24 07:10:52 +01:00
|
|
|
for i in required:
|
|
|
|
e = data[i]
|
|
|
|
if len(e) != 0:
|
|
|
|
key = i.replace("addConfiguration", "")
|
|
|
|
o = f"{key} = {e}"
|
|
|
|
output.append(o)
|
|
|
|
name = data['addConfigurationName']
|
2022-03-25 01:43:56 +01:00
|
|
|
illegal_filename = ["(Space)", " ", ".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "com1", "com2",
|
|
|
|
"com3",
|
|
|
|
"com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4",
|
|
|
|
"lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "con", "nul", "prn"]
|
2022-03-24 07:10:52 +01:00
|
|
|
for i in illegal_filename:
|
|
|
|
name = name.replace(i, "")
|
2022-03-25 01:43:56 +01:00
|
|
|
|
2022-03-24 07:10:52 +01:00
|
|
|
try:
|
|
|
|
newFile = open(f"{WG_CONF_PATH}/{name}.conf", "w+")
|
|
|
|
newFile.write("\n".join(output))
|
|
|
|
except Exception as e:
|
2022-03-25 01:43:56 +01:00
|
|
|
return {"status": False, "reason": str(e)}
|
|
|
|
return {"status": True, "reason": "", "data": name}
|
|
|
|
|
|
|
|
def deleteConfiguration(self, data, config, g, WG_CONF_PATH):
|
|
|
|
confs = []
|
|
|
|
for i in config:
|
|
|
|
confs.append(i['conf'])
|
|
|
|
print(confs)
|
|
|
|
if data['name'] not in confs:
|
|
|
|
return {"status": False, "reason": "Configuration does not exist", "data": ""}
|
|
|
|
for i in config:
|
|
|
|
if i['conf'] == data['name']:
|
|
|
|
if i['status'] == "running":
|
|
|
|
try:
|
|
|
|
subprocess.check_output("wg-quick down " + data['name'], shell=True, stderr=subprocess.STDOUT)
|
|
|
|
except subprocess.CalledProcessError as exc:
|
|
|
|
return {"status": False, "reason": "Can't stop peer", "data": str(exc.output.strip().decode("utf-8"))}
|
|
|
|
|
|
|
|
g.cur.execute(f'DROP TABLE {data["name"]}')
|
|
|
|
g.cur.execute(f'DROP TABLE {data["name"]}_restrict_access')
|
|
|
|
g.db.commit()
|
|
|
|
|
|
|
|
try:
|
|
|
|
os.remove(f'{WG_CONF_PATH}/{data["name"]}.conf')
|
|
|
|
except Exception as e:
|
|
|
|
return {"status": False, "reason": "Can't delete peer", "data": str(e)}
|
|
|
|
|
2022-04-21 21:11:01 +02:00
|
|
|
return good
|
|
|
|
|
|
|
|
def getConfigurationInfo(self, configName, WG_CONF_PATH):
|
2023-11-28 22:37:16 +01:00
|
|
|
conf = configparser.RawConfigParser(strict=False)
|
|
|
|
conf.optionxform = str
|
2022-04-21 21:11:01 +02:00
|
|
|
try:
|
|
|
|
with open(f'{WG_CONF_PATH}/{configName}.conf', 'r'):
|
|
|
|
conf.read(f'{WG_CONF_PATH}/{configName}.conf')
|
|
|
|
if not conf.has_section("Interface"):
|
|
|
|
return ret(status=False, reason="No [Interface] in configuration file")
|
|
|
|
return ret(data=dict(conf['Interface']))
|
|
|
|
except FileNotFoundError as err:
|
2022-04-23 06:34:11 +02:00
|
|
|
return ret(status=False, reason=str(err))
|
2023-11-28 22:37:16 +01:00
|
|
|
|
|
|
|
def saveConfiguration(self, data, WG_CONF_PATH, configs):
|
|
|
|
conf = configparser.RawConfigParser(strict=False)
|
|
|
|
conf.optionxform = str
|
|
|
|
configName = data['configurationName']
|
|
|
|
pc = manageConfiguration.PortCheck(self, {'port': data['ListenPort']}, configs)
|
|
|
|
if pc['status']:
|
|
|
|
try:
|
|
|
|
newData = []
|
|
|
|
with open(f'{WG_CONF_PATH}/{configName}.conf', 'r') as f:
|
|
|
|
conf.read(f'{WG_CONF_PATH}/{configName}.conf')
|
|
|
|
if not conf.has_section("Interface"):
|
|
|
|
return ret(status=False, reason="No [Interface] in configuration file")
|
|
|
|
l = ['ListenPort', 'PostUp', 'PostDown', 'PreUp', 'PreDown']
|
|
|
|
for i in l:
|
|
|
|
conf.set("Interface", i, data[i])
|
|
|
|
conf.remove_section("Peer")
|
|
|
|
newData = list(map(lambda x : f"{x[0]} = {x[1]}\n", list(conf.items("Interface"))))
|
|
|
|
originalData = f.readlines()
|
|
|
|
for i in range(len(originalData)):
|
|
|
|
if originalData[i] == "[Peer]\n":
|
|
|
|
originalData = originalData[i:]
|
|
|
|
break
|
|
|
|
newData.insert(0, "[Interface]\n")
|
|
|
|
newData.append("\n")
|
|
|
|
newData = newData + originalData
|
|
|
|
conf.clear()
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
check = subprocess.check_output("wg-quick down " + configName,
|
|
|
|
shell=True, stderr=subprocess.STDOUT)
|
|
|
|
except subprocess.CalledProcessError as exc:
|
|
|
|
pass
|
|
|
|
with open(f'{WG_CONF_PATH}/{configName}.conf', 'w') as f:
|
|
|
|
for i in newData:
|
|
|
|
f.write(i)
|
|
|
|
try:
|
|
|
|
check = subprocess.check_output("wg-quick up " + configName,
|
|
|
|
shell=True, stderr=subprocess.STDOUT)
|
|
|
|
except subprocess.CalledProcessError as exc:
|
|
|
|
pass
|
|
|
|
return ret()
|
|
|
|
except FileNotFoundError as err:
|
|
|
|
return ret(status=False, reason=str(err))
|
|
|
|
else:
|
|
|
|
return pc
|
|
|
|
|
|
|
|
|
2022-04-23 06:34:11 +02:00
|
|
|
|
|
|
|
|
|
|
|
class settings:
|
|
|
|
def setTheme(self, theme, config, setConfig):
|
|
|
|
themes = ['light', 'dark']
|
|
|
|
if theme not in themes:
|
|
|
|
return ret(status=False, reason="Theme does not exist")
|
|
|
|
config['Server']['dashboard_theme'] = theme
|
|
|
|
setConfig(config)
|
|
|
|
return ret()
|