mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2026-10-30 09:22:05 +00:00
Compare commits
6
Commits
main
...
development
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa13569d4b | ||
|
|
d4661a8f0f | ||
|
|
fefde651d2 | ||
|
|
e6f6201d25 | ||
|
|
c4cbbdb51b | ||
|
|
2df57f9405 |
+49
-23
@@ -945,8 +945,17 @@ def API_addPeers(configName):
|
|||||||
allowed_ips: list[str] = data.get('allowed_ips', [])
|
allowed_ips: list[str] = data.get('allowed_ips', [])
|
||||||
allowed_ips_validation: bool = data.get('allowed_ips_validation', True)
|
allowed_ips_validation: bool = data.get('allowed_ips_validation', True)
|
||||||
|
|
||||||
endpoint_allowed_ip: str = data.get('endpoint_allowed_ip', DashboardConfig.GetConfig("Peers", "peer_endpoint_allowed_ip")[1])
|
config = WireguardConfigurations.get(configName)
|
||||||
dns_addresses: str = data.get('DNS', DashboardConfig.GetConfig("Peers", "peer_global_DNS")[1])
|
overridePeerSettings = config.configurationInfo.OverridePeerSettings
|
||||||
|
|
||||||
|
endpoint_allowed_ip: str = data.get('endpoint_allowed_ip', (
|
||||||
|
overridePeerSettings.EndpointAllowedIPs
|
||||||
|
if overridePeerSettings.EndpointAllowedIPs else DashboardConfig.GetConfig("Peers", "peer_endpoint_allowed_ip")[1]
|
||||||
|
))
|
||||||
|
dns_addresses: str = data.get('DNS', (
|
||||||
|
overridePeerSettings.DNS
|
||||||
|
if overridePeerSettings.DNS else DashboardConfig.GetConfig("Peers", "peer_global_DNS")[1]
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
mtu: int = data.get('mtu', None)
|
mtu: int = data.get('mtu', None)
|
||||||
@@ -955,7 +964,10 @@ def API_addPeers(configName):
|
|||||||
preshared_key: str = data.get('preshared_key', "")
|
preshared_key: str = data.get('preshared_key', "")
|
||||||
|
|
||||||
if type(mtu) is not int or mtu < 0 or mtu > 1460:
|
if type(mtu) is not int or mtu < 0 or mtu > 1460:
|
||||||
default: str = DashboardConfig.GetConfig("Peers", "peer_mtu")[1]
|
default: str = (
|
||||||
|
str(overridePeerSettings.MTU)
|
||||||
|
if overridePeerSettings.MTU else DashboardConfig.GetConfig("Peers", "peer_mtu")[1]
|
||||||
|
)
|
||||||
if default.isnumeric():
|
if default.isnumeric():
|
||||||
try:
|
try:
|
||||||
mtu = int(default)
|
mtu = int(default)
|
||||||
@@ -964,7 +976,10 @@ def API_addPeers(configName):
|
|||||||
else:
|
else:
|
||||||
mtu = 0
|
mtu = 0
|
||||||
if type(keep_alive) is not int or keep_alive < 0:
|
if type(keep_alive) is not int or keep_alive < 0:
|
||||||
default = DashboardConfig.GetConfig("Peers", "peer_keep_alive")[1]
|
default = (
|
||||||
|
str(overridePeerSettings.PersistentKeepalive)
|
||||||
|
if overridePeerSettings.PersistentKeepalive else DashboardConfig.GetConfig("Peers", "peer_keep_alive")[1]
|
||||||
|
)
|
||||||
if default.isnumeric():
|
if default.isnumeric():
|
||||||
try:
|
try:
|
||||||
keep_alive = int(default)
|
keep_alive = int(default)
|
||||||
@@ -973,7 +988,6 @@ def API_addPeers(configName):
|
|||||||
else:
|
else:
|
||||||
keep_alive = 0
|
keep_alive = 0
|
||||||
|
|
||||||
config = WireguardConfigurations.get(configName)
|
|
||||||
if not config.getStatus():
|
if not config.getStatus():
|
||||||
config.toggleConfiguration()
|
config.toggleConfiguration()
|
||||||
ipStatus, availableIps = config.getAvailableIP(-1)
|
ipStatus, availableIps = config.getAvailableIP(-1)
|
||||||
@@ -1040,8 +1054,7 @@ def API_addPeers(configName):
|
|||||||
if ipStatus:
|
if ipStatus:
|
||||||
for subnet in availableIps.keys():
|
for subnet in availableIps.keys():
|
||||||
for ip in availableIps[subnet]:
|
for ip in availableIps[subnet]:
|
||||||
allowed_ips = [ip]
|
allowed_ips.append(ip)
|
||||||
break
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
return ResponseObject(False, "No more available IP can assign")
|
return ResponseObject(False, "No more available IP can assign")
|
||||||
@@ -1140,23 +1153,36 @@ def API_GetPeerHistoricalEndpoints():
|
|||||||
if not configurationName or not id:
|
if not configurationName or not id:
|
||||||
return ResponseObject(False, "Please provide configurationName and id")
|
return ResponseObject(False, "Please provide configurationName and id")
|
||||||
fp, p = WireguardConfigurations.get(configurationName).searchPeer(id)
|
fp, p = WireguardConfigurations.get(configurationName).searchPeer(id)
|
||||||
if fp:
|
if not fp:
|
||||||
result = p.getEndpoints()
|
|
||||||
geo = {}
|
|
||||||
try:
|
|
||||||
r = requests.post(f"http://ip-api.com/batch?fields=city,country,lat,lon,query",
|
|
||||||
data=json.dumps([x['endpoint'] for x in result]))
|
|
||||||
d = r.json()
|
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return ResponseObject(data=result, message="Failed to request IP address geolocation. " + str(e))
|
|
||||||
|
|
||||||
return ResponseObject(data={
|
|
||||||
"endpoints": p.getEndpoints(),
|
|
||||||
"geolocation": d
|
|
||||||
})
|
|
||||||
return ResponseObject(False, "Peer does not exist")
|
return ResponseObject(False, "Peer does not exist")
|
||||||
|
endpoints = p.getEndpoints()
|
||||||
|
ips = [x['endpoint'] for x in endpoints]
|
||||||
|
unique_ips = list(set(ips))
|
||||||
|
def chunks(lst, size=100):
|
||||||
|
for i in range(0, len(lst), size):
|
||||||
|
yield lst[i:i + size]
|
||||||
|
geo_cache = {}
|
||||||
|
try:
|
||||||
|
for batch in chunks(unique_ips, 100):
|
||||||
|
r = requests.post(
|
||||||
|
"http://ip-api.com/batch?fields=city,country,lat,lon,query",
|
||||||
|
data=json.dumps(batch),
|
||||||
|
timeout=5
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
data = r.json()
|
||||||
|
for item in data:
|
||||||
|
geo_cache[item["query"]] = item
|
||||||
|
geolocation = [geo_cache[ip] for ip in ips]
|
||||||
|
except Exception as e:
|
||||||
|
return ResponseObject(
|
||||||
|
data={"endpoints": endpoints},
|
||||||
|
message="Failed to request IP address geolocation. " + str(e)
|
||||||
|
)
|
||||||
|
return ResponseObject(data={
|
||||||
|
"endpoints": endpoints,
|
||||||
|
"geolocation": geolocation
|
||||||
|
})
|
||||||
|
|
||||||
@app.get(f'{APP_PREFIX}/api/getPeerSessions')
|
@app.get(f'{APP_PREFIX}/api/getPeerSessions')
|
||||||
def API_GetPeerSessions():
|
def API_GetPeerSessions():
|
||||||
|
|||||||
@@ -37,6 +37,15 @@ class AmneziaConfiguration(WireguardConfiguration):
|
|||||||
self.I3 = ""
|
self.I3 = ""
|
||||||
self.I4 = ""
|
self.I4 = ""
|
||||||
self.I5 = ""
|
self.I5 = ""
|
||||||
|
self.HeaderProtectionKey = ""
|
||||||
|
self.ContentPaddingAddition = 0
|
||||||
|
self.RekeyAfterTime = 0
|
||||||
|
self.RekeyTimeout = 0
|
||||||
|
self.RejectAfterTime = 0
|
||||||
|
self.KeepaliveTimeout = 0
|
||||||
|
self.MaxHandshakeAttempts = 0
|
||||||
|
self.RandomTrailers = 0
|
||||||
|
self.DisableCookies = 0
|
||||||
self.J1 = ""
|
self.J1 = ""
|
||||||
self.J2 = ""
|
self.J2 = ""
|
||||||
self.J3 = ""
|
self.J3 = ""
|
||||||
@@ -84,6 +93,15 @@ class AmneziaConfiguration(WireguardConfiguration):
|
|||||||
"I3": self.I3,
|
"I3": self.I3,
|
||||||
"I4": self.I4,
|
"I4": self.I4,
|
||||||
"I5": self.I5,
|
"I5": self.I5,
|
||||||
|
"HeaderProtectionKey": self.HeaderProtectionKey,
|
||||||
|
"ContentPaddingAddition": self.ContentPaddingAddition,
|
||||||
|
"RekeyAfterTime": self.RekeyAfterTime,
|
||||||
|
"RekeyTimeout": self.RekeyTimeout,
|
||||||
|
"RejectAfterTime": self.RejectAfterTime,
|
||||||
|
"KeepaliveTimeout": self.KeepaliveTimeout,
|
||||||
|
"MaxHandshakeAttempts": self.MaxHandshakeAttempts,
|
||||||
|
"RandomTrailers": self.RandomTrailers,
|
||||||
|
"DisableCookies": self.DisableCookies,
|
||||||
"J1": self.J1,
|
"J1": self.J1,
|
||||||
"J2": self.J2,
|
"J2": self.J2,
|
||||||
"J3": self.J3,
|
"J3": self.J3,
|
||||||
|
|||||||
@@ -207,6 +207,15 @@ class Peer:
|
|||||||
"I3": self.configuration.I3,
|
"I3": self.configuration.I3,
|
||||||
"I4": self.configuration.I4,
|
"I4": self.configuration.I4,
|
||||||
"I5": self.configuration.I5,
|
"I5": self.configuration.I5,
|
||||||
|
"HeaderProtectionKey": self.configuration.HeaderProtectionKey,
|
||||||
|
"ContentPaddingAddition": self.configuration.ContentPaddingAddition,
|
||||||
|
"RekeyAfterTime": self.configuration.RekeyAfterTime,
|
||||||
|
"RekeyTimeout": self.configuration.RekeyTimeout,
|
||||||
|
"RejectAfterTime": self.configuration.RejectAfterTime,
|
||||||
|
"KeepaliveTimeout": self.configuration.KeepaliveTimeout,
|
||||||
|
"MaxHandshakeAttempts": self.configuration.MaxHandshakeAttempts,
|
||||||
|
"RandomTrailers": self.configuration.RandomTrailers,
|
||||||
|
"DisableCookies": self.configuration.DisableCookies,
|
||||||
"J1": self.configuration.J1,
|
"J1": self.configuration.J1,
|
||||||
"J2": self.configuration.J2,
|
"J2": self.configuration.J2,
|
||||||
"J3": self.configuration.J3,
|
"J3": self.configuration.J3,
|
||||||
|
|||||||
@@ -126,6 +126,15 @@ class WireguardConfiguration:
|
|||||||
"I3": self.I3,
|
"I3": self.I3,
|
||||||
"I4": self.I4,
|
"I4": self.I4,
|
||||||
"I5": self.I5,
|
"I5": self.I5,
|
||||||
|
"HeaderProtectionKey": self.HeaderProtectionKey,
|
||||||
|
"ContentPaddingAddition": self.ContentPaddingAddition,
|
||||||
|
"RekeyAfterTime": self.RekeyAfterTime,
|
||||||
|
"RekeyTimeout": self.RekeyTimeout,
|
||||||
|
"RejectAfterTime": self.RejectAfterTime,
|
||||||
|
"KeepaliveTimeout": self.KeepaliveTimeout,
|
||||||
|
"MaxHandshakeAttempts": self.MaxHandshakeAttempts,
|
||||||
|
"RandomTrailers": self.RandomTrailers,
|
||||||
|
"DisableCookies": self.DisableCookies,
|
||||||
"J1": self.J1,
|
"J1": self.J1,
|
||||||
"J2": self.J2,
|
"J2": self.J2,
|
||||||
"J3": self.J3,
|
"J3": self.J3,
|
||||||
@@ -240,7 +249,7 @@ class WireguardConfiguration:
|
|||||||
self.Status = self.getStatus()
|
self.Status = self.getStatus()
|
||||||
|
|
||||||
def __dropDatabase(self):
|
def __dropDatabase(self):
|
||||||
existingTables = [self.Name, f'{self.Name}_restrict_access', f'{self.Name}_transfer', f'{self.Name}_deleted']
|
existingTables = [self.Name, f'{self.Name}_restrict_access', f'{self.Name}_transfer', f'{self.Name}_deleted', f'{self.Name}_history_endpoint']
|
||||||
try:
|
try:
|
||||||
with self.engine.begin() as conn:
|
with self.engine.begin() as conn:
|
||||||
for name in existingTables:
|
for name in existingTables:
|
||||||
@@ -315,7 +324,8 @@ class WireguardConfiguration:
|
|||||||
f'{dbName}_history_endpoint', self.metadata,
|
f'{dbName}_history_endpoint', self.metadata,
|
||||||
sqlalchemy.Column('id', sqlalchemy.String(255), nullable=False),
|
sqlalchemy.Column('id', sqlalchemy.String(255), nullable=False),
|
||||||
sqlalchemy.Column('endpoint', sqlalchemy.String(255), nullable=False),
|
sqlalchemy.Column('endpoint', sqlalchemy.String(255), nullable=False),
|
||||||
sqlalchemy.Column('time', time_col_type)
|
sqlalchemy.Column('time', time_col_type),
|
||||||
|
extend_existing=True
|
||||||
)
|
)
|
||||||
|
|
||||||
self.infoTable = sqlalchemy.Table(
|
self.infoTable = sqlalchemy.Table(
|
||||||
@@ -949,8 +959,8 @@ class WireguardConfiguration:
|
|||||||
files.sort(key=lambda x: x[1], reverse=True)
|
files.sort(key=lambda x: x[1], reverse=True)
|
||||||
|
|
||||||
for f, ct in files:
|
for f, ct in files:
|
||||||
if RegexMatch(rf"^({self.Name})_(\d+)\\.(conf)$", f):
|
if RegexMatch(rf"^({self.Name})_(\d+)\.(conf)$", f):
|
||||||
s = re.search(rf"^({self.Name})_(\d+)\\.(conf)$", f)
|
s = re.search(rf"^({self.Name})_(\d+)\.(conf)$", f)
|
||||||
date = s.group(2)
|
date = s.group(2)
|
||||||
d = {
|
d = {
|
||||||
"filename": f,
|
"filename": f,
|
||||||
@@ -991,7 +1001,11 @@ class WireguardConfiguration:
|
|||||||
if backupFileName not in backups:
|
if backupFileName not in backups:
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
os.remove(os.path.join(self.__getProtocolPath(), 'WGDashboard_Backup', backupFileName))
|
backupPath = os.path.join(self.__getProtocolPath(), 'WGDashboard_Backup')
|
||||||
|
for ext in ('.conf', '.sql'):
|
||||||
|
f = os.path.join(backupPath, os.path.splitext(backupFileName)[0] + ext)
|
||||||
|
if os.path.exists(f):
|
||||||
|
os.remove(f)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
@@ -1024,7 +1038,7 @@ class WireguardConfiguration:
|
|||||||
allowEdit = ["Address", "PreUp", "PostUp", "PreDown", "PostDown", "ListenPort", "Table"]
|
allowEdit = ["Address", "PreUp", "PostUp", "PreDown", "PostDown", "ListenPort", "Table"]
|
||||||
awgKeys = []
|
awgKeys = []
|
||||||
if self.Protocol == 'awg':
|
if self.Protocol == 'awg':
|
||||||
awgKeys = ["Jc", "Jmin", "Jmax", "S1", "S2", "S3", "S4", "H1", "H2", "H3", "H4", "I1", "I2", "I3", "I4", "I5", "J1", "J2", "J3", "Itime"]
|
awgKeys = ["Jc", "Jmin", "Jmax", "S1", "S2", "S3", "S4", "H1", "H2", "H3", "H4", "I1", "I2", "I3", "I4", "I5", "HeaderProtectionKey", "ContentPaddingAddition", "RekeyAfterTime", "RekeyTimeout", "RejectAfterTime", "KeepaliveTimeout", "MaxHandshakeAttempts", "RandomTrailers", "DisableCookies", "J1", "J2", "J3", "Itime"]
|
||||||
allowEdit += awgKeys
|
allowEdit += awgKeys
|
||||||
start = original.index("[Interface]")
|
start = original.index("[Interface]")
|
||||||
try:
|
try:
|
||||||
@@ -1092,6 +1106,7 @@ class WireguardConfiguration:
|
|||||||
doRenameStatement("_restrict_access")
|
doRenameStatement("_restrict_access")
|
||||||
doRenameStatement("_deleted")
|
doRenameStatement("_deleted")
|
||||||
doRenameStatement("_transfer")
|
doRenameStatement("_transfer")
|
||||||
|
doRenameStatement("_history_endpoint")
|
||||||
conn.execute(
|
conn.execute(
|
||||||
self.infoTable.update()
|
self.infoTable.update()
|
||||||
.where(self.infoTable.c.ID == self.Name)
|
.where(self.infoTable.c.ID == self.Name)
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ const deleteConfigurationModal = ref(false)
|
|||||||
v-model="data[key]"
|
v-model="data[key]"
|
||||||
:id="'configuration_' + key">
|
:id="'configuration_' + key">
|
||||||
</div>
|
</div>
|
||||||
<div v-for="key in ['Jc', 'Jmin', 'Jmax', 'S1', 'S2', 'S3', 'S4', 'H1', 'H2', 'H3', 'H4', 'I1', 'I2', 'I3', 'I4', 'I5']"
|
<div v-for="key in ['Jc', 'Jmin', 'Jmax', 'S1', 'S2', 'S3', 'S4', 'H1', 'H2', 'H3', 'H4', 'I1', 'I2', 'I3', 'I4', 'I5', 'HeaderProtectionKey', 'ContentPaddingAddition', 'RekeyAfterTime', 'RekeyTimeout', 'RejectAfterTime', 'KeepaliveTimeout', 'MaxHandshakeAttempts', 'RandomTrailers', 'DisableCookies']"
|
||||||
v-if="configurationInfo.Protocol === 'awg'">
|
v-if="configurationInfo.Protocol === 'awg'">
|
||||||
<label :for="'configuration_' + key" class="form-label">
|
<label :for="'configuration_' + key" class="form-label">
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
|
|||||||
@@ -49,11 +49,20 @@ export default {
|
|||||||
H2: 0,
|
H2: 0,
|
||||||
H3: 0,
|
H3: 0,
|
||||||
H4: 0,
|
H4: 0,
|
||||||
I1: "0",
|
I1: "",
|
||||||
I2: "0",
|
I2: "",
|
||||||
I3: "0",
|
I3: "",
|
||||||
I4: "0",
|
I4: "",
|
||||||
I5: "0"
|
I5: "",
|
||||||
|
HeaderProtectionKey: "",
|
||||||
|
ContentPaddingAddition: "0-64",
|
||||||
|
RekeyAfterTime: "100-140",
|
||||||
|
RekeyTimeout: "4-7",
|
||||||
|
RejectAfterTime: "160-200",
|
||||||
|
KeepaliveTimeout: "8-12",
|
||||||
|
MaxHandshakeAttempts: "14-20",
|
||||||
|
RandomTrailers: "on",
|
||||||
|
DisableCookies: "on"
|
||||||
},
|
},
|
||||||
numberOfAvailableIPs: "0",
|
numberOfAvailableIPs: "0",
|
||||||
error: false,
|
error: false,
|
||||||
@@ -72,9 +81,15 @@ export default {
|
|||||||
this.newConfiguration[key] = this.rand(1, 2**31);
|
this.newConfiguration[key] = this.rand(1, 2**31);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize I1 to I5 as "0"
|
// Initialize HeaderProtectionKey
|
||||||
['I1', 'I2', 'I3', 'I4', 'I5'].forEach(key => {
|
let headerProtectionKey = new Uint8Array(32);
|
||||||
this.newConfiguration[key] = "0";
|
window.crypto.getRandomValues(headerProtectionKey);
|
||||||
|
this.newConfiguration.HeaderProtectionKey = btoa(String.fromCharCode(...headerProtectionKey));
|
||||||
|
|
||||||
|
// S1-S4 are recommended be the same to work with RandomTrailers and must 12 or more to work with HeaderProtectionKey
|
||||||
|
let constantS = 12 + this.rand(1, 2**5);
|
||||||
|
['S1', 'S2', 'S3', 'S4'].forEach(key => {
|
||||||
|
this.newConfiguration[key] = constantS;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -388,7 +403,7 @@ export default {
|
|||||||
|
|
||||||
<div class="card rounded-3"
|
<div class="card rounded-3"
|
||||||
v-if="this.newConfiguration.Protocol === 'awg'"
|
v-if="this.newConfiguration.Protocol === 'awg'"
|
||||||
v-for="key in ['Jc', 'Jmin', 'Jmax', 'S1', 'S2', 'S3', 'S4', 'H1', 'H2', 'H3', 'H4', 'I1', 'I2', 'I3', 'I4', 'I5']">
|
v-for="key in ['Jc', 'Jmin', 'Jmax', 'S1', 'S2', 'S3', 'S4', 'H1', 'H2', 'H3', 'H4', 'I1', 'I2', 'I3', 'I4', 'I5', 'HeaderProtectionKey', 'ContentPaddingAddition', 'RekeyAfterTime', 'RekeyTimeout', 'RejectAfterTime', 'KeepaliveTimeout', 'MaxHandshakeAttempts', 'RandomTrailers', 'DisableCookies']">
|
||||||
<div class="card-header">{{ key }}</div>
|
<div class="card-header">{{ key }}</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<input type="text"
|
<input type="text"
|
||||||
|
|||||||
Reference in New Issue
Block a user