mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-22 07:10:09 +01:00
Added OpenStreetMap for Ping and Traceroute
This commit is contained in:
parent
7fe4889b6e
commit
ff0147bebb
179
src/dashboard.py
179
src/dashboard.py
@ -1781,73 +1781,95 @@ def API_allowAccessPeers(configName: str) -> ResponseObject:
|
|||||||
|
|
||||||
@app.post(f'{APP_PREFIX}/api/addPeers/<configName>')
|
@app.post(f'{APP_PREFIX}/api/addPeers/<configName>')
|
||||||
def API_addPeers(configName):
|
def API_addPeers(configName):
|
||||||
data: dict = 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']
|
|
||||||
preshared_key_bulkAdd: bool = data['preshared_key_bulkAdd']
|
|
||||||
|
|
||||||
if configName in WireguardConfigurations.keys():
|
if configName in WireguardConfigurations.keys():
|
||||||
config = WireguardConfigurations.get(configName)
|
try:
|
||||||
if (not bulkAdd and (len(public_key) == 0 or len(allowed_ips) == 0)) or len(endpoint_allowed_ip) == 0:
|
data: dict = request.get_json()
|
||||||
return ResponseObject(False, "Please fill in all required box")
|
|
||||||
if not config.getStatus():
|
|
||||||
config.toggleConfiguration()
|
|
||||||
|
|
||||||
availableIps = _getWireguardConfigurationAvailableIP(configName)
|
bulkAdd: bool = data.get("bulkAdd", False)
|
||||||
|
bulkAddAmount: int = data.get('bulkAddAmount', 0)
|
||||||
if bulkAdd:
|
preshared_key_bulkAdd: bool = data.get('preshared_key_bulkAdd', False)
|
||||||
if bulkAddAmount < 1:
|
|
||||||
return ResponseObject(False, "Please specify amount of peers you want to add")
|
|
||||||
if not availableIps[0]:
|
public_key: str = data.get('public_key', "")
|
||||||
return ResponseObject(False, "No more available IP can assign")
|
allowed_ips: list[str] = data.get('allowed_ips', "")
|
||||||
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):
|
|
||||||
newPrivateKey = _generatePrivateKey()[1]
|
|
||||||
keyPairs.append({
|
|
||||||
"private_key": newPrivateKey,
|
|
||||||
"id": _generatePublicKey(newPrivateKey)[1],
|
|
||||||
"preshared_key": (_generatePrivateKey()[1] if preshared_key_bulkAdd else ""),
|
|
||||||
"allowed_ip": availableIps[1][i],
|
|
||||||
"name": f"BulkPeer #{(i + 1)}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
|
||||||
})
|
|
||||||
if len(keyPairs) == 0:
|
|
||||||
return ResponseObject(False, "Generating key pairs by bulk failed")
|
|
||||||
config.addPeers(keyPairs)
|
|
||||||
|
|
||||||
for kp in keyPairs:
|
endpoint_allowed_ip: str = data.get('endpoint_allowed_ip', DashboardConfig.GetConfig("Peers", "peer_endpoint_allowed_ip")[1])
|
||||||
found, peer = config.searchPeer(kp['id'])
|
dns_addresses: str = data.get('DNS', DashboardConfig.GetConfig("Peers", "peer_global_DNS")[1])
|
||||||
|
mtu: int = data.get('mtu', int(DashboardConfig.GetConfig("Peers", "peer_MTU")[1]))
|
||||||
|
keep_alive: int = data.get('keepalive', int(DashboardConfig.GetConfig("Peers", "peer_keep_alive")[1]))
|
||||||
|
preshared_key: str = data.get('preshared_key', "")
|
||||||
|
|
||||||
|
|
||||||
|
if type(mtu) is not int or mtu < 0 or mtu > 1460:
|
||||||
|
mtu = int(DashboardConfig.GetConfig("Peers", "peer_MTU")[1])
|
||||||
|
if type(keep_alive) is not int or keep_alive < 0:
|
||||||
|
keep_alive = int(DashboardConfig.GetConfig("Peers", "peer_keep_alive")[1])
|
||||||
|
if len(dns_addresses) == 0:
|
||||||
|
dns_addresses = DashboardConfig.GetConfig("Peers", "peer_global_DNS")[1]
|
||||||
|
if len(endpoint_allowed_ip) == 0:
|
||||||
|
endpoint_allowed_ip = DashboardConfig.GetConfig("Peers", "peer_endpoint_allowed_ip")[1]
|
||||||
|
|
||||||
|
|
||||||
|
config = WireguardConfigurations.get(configName)
|
||||||
|
if not bulkAdd and (len(public_key) == 0 or len(allowed_ips) == 0):
|
||||||
|
return ResponseObject(False, "Please provide at lease public_key and allowed_ips")
|
||||||
|
if not config.getStatus():
|
||||||
|
config.toggleConfiguration()
|
||||||
|
|
||||||
|
availableIps = _getWireguardConfigurationAvailableIP(configName)
|
||||||
|
|
||||||
|
if bulkAdd:
|
||||||
|
if type(preshared_key_bulkAdd) is not bool:
|
||||||
|
preshared_key_bulkAdd = False
|
||||||
|
|
||||||
|
if type(bulkAddAmount) is not int or bulkAddAmount < 1:
|
||||||
|
return ResponseObject(False, "Please specify amount of peers you want to add")
|
||||||
|
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):
|
||||||
|
newPrivateKey = _generatePrivateKey()[1]
|
||||||
|
keyPairs.append({
|
||||||
|
"private_key": newPrivateKey,
|
||||||
|
"id": _generatePublicKey(newPrivateKey)[1],
|
||||||
|
"preshared_key": (_generatePrivateKey()[1] if preshared_key_bulkAdd else ""),
|
||||||
|
"allowed_ip": availableIps[1][i],
|
||||||
|
"name": f"BulkPeer #{(i + 1)}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
||||||
|
})
|
||||||
|
if len(keyPairs) == 0:
|
||||||
|
return ResponseObject(False, "Generating key pairs by bulk failed")
|
||||||
|
config.addPeers(keyPairs)
|
||||||
|
|
||||||
|
for kp in keyPairs:
|
||||||
|
found, peer = config.searchPeer(kp['id'])
|
||||||
|
if found:
|
||||||
|
if not peer.updatePeer(kp['name'], kp['private_key'], kp['preshared_key'], dns_addresses,
|
||||||
|
kp['allowed_ip'], endpoint_allowed_ip, mtu, keep_alive):
|
||||||
|
return ResponseObject(False, "Failed to add peers in bulk")
|
||||||
|
return ResponseObject()
|
||||||
|
|
||||||
|
else:
|
||||||
|
if config.searchPeer(public_key)[0] is True:
|
||||||
|
return ResponseObject(False, f"This peer already exist")
|
||||||
|
name = data.get("name", "")
|
||||||
|
private_key = data.get("private_key", "")
|
||||||
|
|
||||||
|
for i in allowed_ips:
|
||||||
|
if i not in availableIps[1]:
|
||||||
|
return ResponseObject(False, f"This IP is not available: {i}")
|
||||||
|
|
||||||
|
config.addPeers([{"id": public_key, "allowed_ip": ','.join(allowed_ips)}])
|
||||||
|
found, peer = config.searchPeer(public_key)
|
||||||
if found:
|
if found:
|
||||||
if not peer.updatePeer(kp['name'], kp['private_key'], kp['preshared_key'], dns_addresses,
|
return peer.updatePeer(name, private_key, preshared_key, dns_addresses, ",".join(allowed_ips),
|
||||||
kp['allowed_ip'], endpoint_allowed_ip, mtu, keep_alive):
|
endpoint_allowed_ip, mtu, keep_alive)
|
||||||
return ResponseObject(False, "Failed to add peers in bulk")
|
except Exception as e:
|
||||||
return ResponseObject()
|
print(e)
|
||||||
|
return ResponseObject(False, "Add peers failed. Please see data for specific issue")
|
||||||
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']
|
|
||||||
|
|
||||||
for i in allowed_ips:
|
|
||||||
if i not in availableIps[1]:
|
|
||||||
return ResponseObject(False, f"This IP is not available: {i}")
|
|
||||||
|
|
||||||
config.addPeers([{"id": public_key, "allowed_ip": ','.join(allowed_ips)}])
|
|
||||||
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")
|
return ResponseObject(False, "Configuration does not exist")
|
||||||
|
|
||||||
@ -1992,6 +2014,7 @@ def API_ping_getAllPeersIpAddress():
|
|||||||
ips[c.Name] = cips
|
ips[c.Name] = cips
|
||||||
return ResponseObject(data=ips)
|
return ResponseObject(data=ips)
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
@app.get(f'{APP_PREFIX}/api/ping/execute')
|
@app.get(f'{APP_PREFIX}/api/ping/execute')
|
||||||
def API_ping_execute():
|
def API_ping_execute():
|
||||||
@ -2001,8 +2024,8 @@ def API_ping_execute():
|
|||||||
try:
|
try:
|
||||||
if ip is not None and len(ip) > 0 and count is not None and count.isnumeric():
|
if ip is not None and len(ip) > 0 and count is not None and count.isnumeric():
|
||||||
result = ping(ip, count=int(count), source=None)
|
result = ping(ip, count=int(count), source=None)
|
||||||
|
|
||||||
return ResponseObject(data={
|
data = {
|
||||||
"address": result.address,
|
"address": result.address,
|
||||||
"is_alive": result.is_alive,
|
"is_alive": result.is_alive,
|
||||||
"min_rtt": result.min_rtt,
|
"min_rtt": result.min_rtt,
|
||||||
@ -2010,9 +2033,17 @@ def API_ping_execute():
|
|||||||
"max_rtt": result.max_rtt,
|
"max_rtt": result.max_rtt,
|
||||||
"package_sent": result.packets_sent,
|
"package_sent": result.packets_sent,
|
||||||
"package_received": result.packets_received,
|
"package_received": result.packets_received,
|
||||||
"package_loss": result.packet_loss
|
"package_loss": result.packet_loss,
|
||||||
})
|
"geo": None
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
r = requests.get(f"http://ip-api.com/json/{result.address}?field=city")
|
||||||
|
data['geo'] = r.json()
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
return ResponseObject(data=data)
|
||||||
return ResponseObject(False, "Please specify an IP Address (v4/v6)")
|
return ResponseObject(False, "Please specify an IP Address (v4/v6)")
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
return ResponseObject(False, exp)
|
return ResponseObject(False, exp)
|
||||||
@ -2024,7 +2055,7 @@ def API_traceroute_execute():
|
|||||||
if "ipAddress" in request.args.keys() and len(request.args.get("ipAddress")) > 0:
|
if "ipAddress" in request.args.keys() and len(request.args.get("ipAddress")) > 0:
|
||||||
ipAddress = request.args.get('ipAddress')
|
ipAddress = request.args.get('ipAddress')
|
||||||
try:
|
try:
|
||||||
tracerouteResult = traceroute(ipAddress)
|
tracerouteResult = traceroute(ipAddress, timeout=1, max_hops=64)
|
||||||
result = []
|
result = []
|
||||||
for hop in tracerouteResult:
|
for hop in tracerouteResult:
|
||||||
if len(result) > 1:
|
if len(result) > 1:
|
||||||
@ -2049,6 +2080,15 @@ def API_traceroute_execute():
|
|||||||
"min_rtt": hop.min_rtt,
|
"min_rtt": hop.min_rtt,
|
||||||
"max_rtt": hop.max_rtt
|
"max_rtt": hop.max_rtt
|
||||||
})
|
})
|
||||||
|
try:
|
||||||
|
r = requests.post(f"http://ip-api.com/batch?fields=city,country,lat,lon,query",
|
||||||
|
data=json.dumps([x['ip'] for x in result]))
|
||||||
|
d = r.json()
|
||||||
|
for i in range(len(result)):
|
||||||
|
result[i]['geo'] = d[i]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
return ResponseObject(data=result)
|
return ResponseObject(data=result)
|
||||||
except Exception as exp:
|
except Exception as exp:
|
||||||
return ResponseObject(False, exp)
|
return ResponseObject(False, exp)
|
||||||
@ -2077,7 +2117,6 @@ def API_getDashboardUpdate():
|
|||||||
Sign Up
|
Sign Up
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
@app.get(f'{APP_PREFIX}/api/isTotpEnabled')
|
@app.get(f'{APP_PREFIX}/api/isTotpEnabled')
|
||||||
def API_isTotpEnabled():
|
def API_isTotpEnabled():
|
||||||
return (
|
return (
|
||||||
|
@ -5,4 +5,5 @@ pyotp
|
|||||||
Flask
|
Flask
|
||||||
flask-cors
|
flask-cors
|
||||||
icmplib
|
icmplib
|
||||||
gunicorn
|
gunicorn
|
||||||
|
requests
|
164
src/static/app/package-lock.json
generated
164
src/static/app/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "app",
|
"name": "app",
|
||||||
"version": "4.0.2",
|
"version": "4.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "app",
|
"name": "app",
|
||||||
"version": "4.0.2",
|
"version": "4.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vuepic/vue-datepicker": "^9.0.1",
|
"@vuepic/vue-datepicker": "^9.0.1",
|
||||||
"@vueuse/core": "^10.9.0",
|
"@vueuse/core": "^10.9.0",
|
||||||
@ -21,6 +21,7 @@
|
|||||||
"i": "^0.3.7",
|
"i": "^0.3.7",
|
||||||
"is-cidr": "^5.0.3",
|
"is-cidr": "^5.0.3",
|
||||||
"npm": "^10.5.0",
|
"npm": "^10.5.0",
|
||||||
|
"ol": "^10.2.1",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"qrcodejs": "^1.0.0",
|
"qrcodejs": "^1.0.0",
|
||||||
@ -723,6 +724,11 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@petamoriken/float16": {
|
||||||
|
"version": "3.8.7",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@petamoriken/float16/-/float16-3.8.7.tgz",
|
||||||
|
"integrity": "sha512-/Ri4xDDpe12NT6Ex/DRgHzLlobiQXEW/hmG08w1wj/YU7hLemk97c+zHQFp0iZQ9r7YqgLEXZR2sls4HxBf9NA=="
|
||||||
|
},
|
||||||
"node_modules/@pkgjs/parseargs": {
|
"node_modules/@pkgjs/parseargs": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||||
@ -964,6 +970,11 @@
|
|||||||
"xmlbuilder": ">=11.0.1"
|
"xmlbuilder": ">=11.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/rbush": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/rbush/-/rbush-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-lX55lR0iYCgapxD3IrgujpQA1zDxwZI5qMRelKvmKAsSMplFVr7wmMpG7/6+Op2tjrgEex8o3vjg8CRDrRNYxg=="
|
||||||
|
},
|
||||||
"node_modules/@types/verror": {
|
"node_modules/@types/verror": {
|
||||||
"version": "1.10.10",
|
"version": "1.10.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.10.tgz",
|
||||||
@ -1717,6 +1728,36 @@
|
|||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/color-parse": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/color-parse/-/color-parse-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-eCtOz5w5ttWIUcaKLiktF+DxZO1R9KLNY/xhbV6CkhM7sR3GhVghmt6X6yOnzeaM24po+Z9/S1apbXMwA3Iepw==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-parse/node_modules/color-name": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-SbtvAMWvASO5TE2QP07jHBMXKafgdZz8Vrsrn96fiL+O92/FN/PLARzUW5sKt013fjAprK2d2iCn2hk2Xb5oow==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-rgba": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/color-rgba/-/color-rgba-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-PPwZYkEY3M2THEHHV6Y95sGUie77S7X8v+h1r6LSAPF3/LL2xJ8duUXSrkic31Nzc4odPwHgUbiX/XuTYzQHQg==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-parse": "^2.0.0",
|
||||||
|
"color-space": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-space": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/color-space/-/color-space-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-nKqUYlo0vZATVOFHY810BSYjmCARrG7e5R3UE3CQlyjJTvv5kSSmPG1kzm/oDyyqjehM+lW1RnEt9It9GNa5JA=="
|
||||||
|
},
|
||||||
"node_modules/combined-stream": {
|
"node_modules/combined-stream": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
@ -2005,6 +2046,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
|
||||||
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
|
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/earcut": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/earcut/-/earcut-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg=="
|
||||||
|
},
|
||||||
"node_modules/eastasianwidth": {
|
"node_modules/eastasianwidth": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||||
@ -2358,6 +2404,24 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/geotiff": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/geotiff/-/geotiff-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-PT6uoF5a1+kbC3tHmZSUsLHBp2QJlHasxxxxPW47QIY1VBKpFB+FcDvX+MxER6UzgLQZ0xDzJ9s48B9JbOCTqA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@petamoriken/float16": "^3.4.7",
|
||||||
|
"lerc": "^3.0.0",
|
||||||
|
"pako": "^2.0.4",
|
||||||
|
"parse-headers": "^2.0.2",
|
||||||
|
"quick-lru": "^6.1.1",
|
||||||
|
"web-worker": "^1.2.0",
|
||||||
|
"xml-utils": "^1.0.2",
|
||||||
|
"zstddec": "^0.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-caller-file": {
|
"node_modules/get-caller-file": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
@ -2731,6 +2795,11 @@
|
|||||||
"safe-buffer": "~5.1.0"
|
"safe-buffer": "~5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lerc": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/lerc/-/lerc-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww=="
|
||||||
|
},
|
||||||
"node_modules/locate-path": {
|
"node_modules/locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
@ -5476,6 +5545,24 @@
|
|||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/ol": {
|
||||||
|
"version": "10.2.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ol/-/ol-10.2.1.tgz",
|
||||||
|
"integrity": "sha512-2bB/y2vEnmzjqynP0NA7Cp8k86No3Psn63Dueicep3E3i09axWRVIG5IS/bylEAGfWQx0QXD/uljkyFoY60Wig==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/rbush": "3.0.3",
|
||||||
|
"color-rgba": "^3.0.0",
|
||||||
|
"color-space": "^2.0.1",
|
||||||
|
"earcut": "^3.0.0",
|
||||||
|
"geotiff": "^2.0.7",
|
||||||
|
"pbf": "4.0.1",
|
||||||
|
"rbush": "^4.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/openlayers"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/once": {
|
"node_modules/once": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
@ -5522,6 +5609,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
|
||||||
"integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw=="
|
"integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/pako": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/pako/-/pako-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
|
||||||
|
},
|
||||||
|
"node_modules/parse-headers": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/parse-headers/-/parse-headers-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA=="
|
||||||
|
},
|
||||||
"node_modules/path-exists": {
|
"node_modules/path-exists": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
@ -5566,6 +5663,17 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/pbf": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/pbf/-/pbf-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==",
|
||||||
|
"dependencies": {
|
||||||
|
"resolve-protobuf-schema": "^2.1.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"pbf": "bin/pbf"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||||
@ -5687,6 +5795,11 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/protocol-buffers-schema": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw=="
|
||||||
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
@ -5717,6 +5830,30 @@
|
|||||||
"resolved": "https://registry.npmjs.org/qrcodejs/-/qrcodejs-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/qrcodejs/-/qrcodejs-1.0.0.tgz",
|
||||||
"integrity": "sha512-67rj3mMBhSBepaD57qENnltO+r8rSYlqM7HGThks/BiyDAkc86sLvkKqjkqPS5v13f7tvnt6dbEf3qt7zq+BCg=="
|
"integrity": "sha512-67rj3mMBhSBepaD57qENnltO+r8rSYlqM7HGThks/BiyDAkc86sLvkKqjkqPS5v13f7tvnt6dbEf3qt7zq+BCg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/quick-lru": {
|
||||||
|
"version": "6.1.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/quick-lru/-/quick-lru-6.1.2.tgz",
|
||||||
|
"integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/quickselect": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/quickselect/-/quickselect-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g=="
|
||||||
|
},
|
||||||
|
"node_modules/rbush": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/rbush/-/rbush-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-IP0UpfeWQujYC8Jg162rMNc01Rf0gWMMAb2Uxus/Q0qOFw4lCcq6ZnQEZwUoJqWyUGJ9th7JjwI4yIWo+uvoAQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"quickselect": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-config-file": {
|
"node_modules/read-config-file": {
|
||||||
"version": "6.3.2",
|
"version": "6.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.3.2.tgz",
|
||||||
@ -5769,6 +5906,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/resolve-protobuf-schema": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"protocol-buffers-schema": "^3.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/retry": {
|
"node_modules/retry": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||||
@ -6264,6 +6409,11 @@
|
|||||||
"vue": "^3.2.0"
|
"vue": "^3.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/web-worker": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/web-worker/-/web-worker-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA=="
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
@ -6318,6 +6468,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/xml-utils": {
|
||||||
|
"version": "1.10.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/xml-utils/-/xml-utils-1.10.1.tgz",
|
||||||
|
"integrity": "sha512-Dn6vJ1Z9v1tepSjvnCpwk5QqwIPcEFKdgnjqfYOABv1ngSofuAhtlugcUC3ehS1OHdgDWSG6C5mvj+Qm15udTQ=="
|
||||||
|
},
|
||||||
"node_modules/xmlbuilder": {
|
"node_modules/xmlbuilder": {
|
||||||
"version": "15.1.1",
|
"version": "15.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
|
||||||
@ -6403,6 +6558,11 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zstddec": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/zstddec/-/zstddec-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-w2NTI8+3l3eeltKAdK8QpiLo/flRAr2p8AGeakfMZOXBxOg9HIu4LVDxBi81sYgVhFhdJjv1OrB5ssI8uFPoLg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"i": "^0.3.7",
|
"i": "^0.3.7",
|
||||||
"is-cidr": "^5.0.3",
|
"is-cidr": "^5.0.3",
|
||||||
"npm": "^10.5.0",
|
"npm": "^10.5.0",
|
||||||
|
"ol": "^10.2.1",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"qrcodejs": "^1.0.0",
|
"qrcodejs": "^1.0.0",
|
||||||
|
@ -19,6 +19,7 @@ export default {
|
|||||||
<input type="number" class="form-control form-control-sm rounded-3"
|
<input type="number" class="form-control form-control-sm rounded-3"
|
||||||
:disabled="this.saving"
|
:disabled="this.saving"
|
||||||
v-model="this.data.mtu"
|
v-model="this.data.mtu"
|
||||||
|
min="0"
|
||||||
id="peer_mtu">
|
id="peer_mtu">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -26,7 +26,7 @@ export default {
|
|||||||
return{
|
return{
|
||||||
data: {
|
data: {
|
||||||
bulkAdd: false,
|
bulkAdd: false,
|
||||||
bulkAddAmount: "",
|
bulkAddAmount: 0,
|
||||||
name: "",
|
name: "",
|
||||||
allowed_ips: [],
|
allowed_ips: [],
|
||||||
private_key: "",
|
private_key: "",
|
||||||
|
113
src/static/app/src/components/map/map.vue
Normal file
113
src/static/app/src/components/map/map.vue
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<script>
|
||||||
|
import "ol/ol.css"
|
||||||
|
import Map from 'ol/Map.js';
|
||||||
|
import OSM from 'ol/source/OSM.js';
|
||||||
|
import TileLayer from 'ol/layer/Tile.js';
|
||||||
|
import View from 'ol/View.js';
|
||||||
|
import {Feature} from "ol";
|
||||||
|
import {fromLonLat} from "ol/proj"
|
||||||
|
import {LineString, Point} from "ol/geom"
|
||||||
|
import {Circle, Fill, Stroke, Style, Text} from "ol/style.js";
|
||||||
|
import {Vector} from "ol/layer"
|
||||||
|
import {Vector as SourceVector} from "ol/source"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "map",
|
||||||
|
props: {
|
||||||
|
type: "",
|
||||||
|
d: Object || Array
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getLastLonLat(){
|
||||||
|
if (this.type === 'traceroute'){
|
||||||
|
const k = this.d.findLast(data => data.geo && data.geo.lat && data.geo.lon)
|
||||||
|
if (k){
|
||||||
|
return [k.geo.lon, k.geo.lat]
|
||||||
|
}
|
||||||
|
return [0,0]
|
||||||
|
}
|
||||||
|
return [this.d.geo.lon, this.d.geo.lat]
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
const map = new Map({
|
||||||
|
target: 'map',
|
||||||
|
layers: [
|
||||||
|
new TileLayer({
|
||||||
|
source: new OSM(),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
view: new View({
|
||||||
|
center: fromLonLat(this.getLastLonLat()),
|
||||||
|
zoom: this.type === 'traceroute' ? 3:10,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const coordinates = [];
|
||||||
|
const vectorSource = new SourceVector();
|
||||||
|
if (this.type === 'traceroute'){
|
||||||
|
console.log(this.getLastLonLat())
|
||||||
|
this.d.forEach(data => {
|
||||||
|
if (data.geo && data.geo.lat && data.geo.lon) {
|
||||||
|
const coordinate = fromLonLat([data.geo.lon, data.geo.lat]);
|
||||||
|
coordinates.push(coordinate);
|
||||||
|
const l = this.getLastLonLat();
|
||||||
|
|
||||||
|
console.log(data.geo.lon, data.geo.lat)
|
||||||
|
console.log( data.geo.lon === l[0] && data.geo.lat === l[1])
|
||||||
|
const marker = new Feature({
|
||||||
|
geometry: new Point(coordinate),
|
||||||
|
last: data.geo.lon === l[0] && data.geo.lat === l[1]
|
||||||
|
});
|
||||||
|
vectorSource.addFeature(marker);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
const coordinate = fromLonLat([this.d.geo.lon, this.d.geo.lat])
|
||||||
|
coordinates.push(coordinate);
|
||||||
|
const marker = new Feature({
|
||||||
|
geometry: new Point(coordinate)
|
||||||
|
});
|
||||||
|
// Add marker to the vector source
|
||||||
|
vectorSource.addFeature(marker);
|
||||||
|
}
|
||||||
|
const lineString = new LineString(coordinates);
|
||||||
|
const lineFeature = new Feature({
|
||||||
|
geometry: lineString
|
||||||
|
});
|
||||||
|
vectorSource.addFeature(lineFeature);
|
||||||
|
const vectorLayer = new Vector({
|
||||||
|
source: vectorSource,
|
||||||
|
style: function(feature) {
|
||||||
|
if (feature.getGeometry().getType() === 'Point') {
|
||||||
|
return new Style({
|
||||||
|
image: new Circle({
|
||||||
|
radius: 10,
|
||||||
|
fill: new Fill({ color: feature.get("last") ? '#dc3545':'#0d6efd' }),
|
||||||
|
stroke: new Stroke({ color: 'white', width: 5 }),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} else if (feature.getGeometry().getType() === 'LineString') {
|
||||||
|
return new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: '#0d6efd', // Line color
|
||||||
|
width: 2 // Line width
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
map.addLayer(vectorLayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="map" class="w-100 rounded-3" style="height: 300px"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.ol-layer canvas{
|
||||||
|
border-radius: var(--bs-border-radius-lg) !important;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,9 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import {fetchGet} from "@/utilities/fetch.js";
|
import {fetchGet} from "@/utilities/fetch.js";
|
||||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||||
|
import LocaleText from "@/components/text/localeText.vue";
|
||||||
|
import Map from "@/components/map/map.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ping",
|
name: "ping",
|
||||||
|
components: {Map, LocaleText},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
@ -67,9 +70,11 @@ export default {
|
|||||||
<div class="col-sm-4 d-flex gap-2 flex-column">
|
<div class="col-sm-4 d-flex gap-2 flex-column">
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1 text-muted" for="configuration">
|
<label class="mb-1 text-muted" for="configuration">
|
||||||
<small>Configuration</small></label>
|
<small>
|
||||||
|
<LocaleText t="Configuration"></LocaleText>
|
||||||
|
</small></label>
|
||||||
<select class="form-select" v-model="this.selectedConfiguration">
|
<select class="form-select" v-model="this.selectedConfiguration">
|
||||||
<option disabled selected :value="undefined">Select a Configuration...</option>
|
<option disabled selected :value="undefined"></option>
|
||||||
<option :value="key" v-for="(val, key) in this.cips">
|
<option :value="key" v-for="(val, key) in this.cips">
|
||||||
{{key}}
|
{{key}}
|
||||||
</option>
|
</option>
|
||||||
@ -77,9 +82,11 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1 text-muted" for="peer">
|
<label class="mb-1 text-muted" for="peer">
|
||||||
<small>Peer</small></label>
|
<small>
|
||||||
|
<LocaleText t="Peer"></LocaleText>
|
||||||
|
</small></label>
|
||||||
<select id="peer" class="form-select" v-model="this.selectedPeer" :disabled="this.selectedConfiguration === undefined">
|
<select id="peer" class="form-select" v-model="this.selectedPeer" :disabled="this.selectedConfiguration === undefined">
|
||||||
<option disabled selected :value="undefined">Select a Peer...</option>
|
<option disabled selected :value="undefined"></option>
|
||||||
<option v-if="this.selectedConfiguration !== undefined" :value="key" v-for="(peer, key) in
|
<option v-if="this.selectedConfiguration !== undefined" :value="key" v-for="(peer, key) in
|
||||||
this.cips[this.selectedConfiguration]">
|
this.cips[this.selectedConfiguration]">
|
||||||
{{key}}
|
{{key}}
|
||||||
@ -88,9 +95,11 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1 text-muted" for="ip">
|
<label class="mb-1 text-muted" for="ip">
|
||||||
<small>IP Address</small></label>
|
<small>
|
||||||
|
<LocaleText t="IP Address"></LocaleText>
|
||||||
|
</small></label>
|
||||||
<select id="ip" class="form-select" v-model="this.selectedIp" :disabled="this.selectedPeer === undefined">
|
<select id="ip" class="form-select" v-model="this.selectedIp" :disabled="this.selectedPeer === undefined">
|
||||||
<option disabled selected :value="undefined">Select a IP...</option>
|
<option disabled selected :value="undefined"></option>
|
||||||
<option
|
<option
|
||||||
v-if="this.selectedPeer !== undefined"
|
v-if="this.selectedPeer !== undefined"
|
||||||
v-for="ip in this.cips[this.selectedConfiguration][this.selectedPeer].allowed_ips">
|
v-for="ip in this.cips[this.selectedConfiguration][this.selectedPeer].allowed_ips">
|
||||||
@ -98,17 +107,50 @@ export default {
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="d-flex align-items-center gap-2">
|
||||||
|
<div class="flex-grow-1 border-top"></div>
|
||||||
|
<small class="text-muted">
|
||||||
|
<LocaleText t="OR"></LocaleText>
|
||||||
|
</small>
|
||||||
|
<div class="flex-grow-1 border-top"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="mb-1 text-muted" for="ipAddress">
|
||||||
|
<small>
|
||||||
|
<LocaleText t="Enter IP Address / Hostname"></LocaleText>
|
||||||
|
</small></label>
|
||||||
|
<input class="form-control" type="text"
|
||||||
|
id="ipAddress"
|
||||||
|
v-model="this.selectedIp">
|
||||||
|
</div>
|
||||||
|
<div class="w-100 border-top my-2"></div>
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-1 text-muted" for="count">
|
<label class="mb-1 text-muted" for="count">
|
||||||
<small>Ping Count</small></label>
|
<small>
|
||||||
<input class="form-control" type="number"
|
<LocaleText t="Count"></LocaleText>
|
||||||
v-model="this.count"
|
</small></label>
|
||||||
min="1" id="count" placeholder="How many times you want to ping?">
|
|
||||||
|
<div class="d-flex gap-3 align-items-center">
|
||||||
|
<button @click="this.count--"
|
||||||
|
:disabled="this.count === 1"
|
||||||
|
class="btn btn-sm bg-secondary-subtle text-secondary-emphasis">
|
||||||
|
<i class="bi bi-dash-lg"></i>
|
||||||
|
</button>
|
||||||
|
<strong>{{this.count}}</strong>
|
||||||
|
<button role="button" @click="this.count++" class="btn btn-sm bg-secondary-subtle text-secondary-emphasis">
|
||||||
|
<i class="bi bi-plus-lg"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <input class="form-control" type="number" -->
|
||||||
|
<!-- v-model="this.count"-->
|
||||||
|
<!-- min="1" id="count" placeholder="How many times you want to ping?">-->
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary rounded-3 mt-3"
|
<button class="btn btn-primary rounded-3 mt-3"
|
||||||
:disabled="!this.selectedIp"
|
:disabled="!this.selectedIp"
|
||||||
@click="this.execute()">
|
@click="this.execute()">
|
||||||
<i class="bi bi-person-walking me-2"></i>Go!
|
<i class="bi bi-person-walking me-2"></i>Ping!
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -123,9 +165,23 @@ export default {
|
|||||||
|
|
||||||
<div v-else key="pingResult" class="d-flex flex-column gap-2 w-100">
|
<div v-else key="pingResult" class="d-flex flex-column gap-2 w-100">
|
||||||
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.15s">
|
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.15s">
|
||||||
<div class="card-body">
|
<div class="card-body row">
|
||||||
<p class="mb-0 text-muted"><small>Address</small></p>
|
<div class="col-sm">
|
||||||
{{this.pingResult.address}}
|
<p class="mb-0 text-muted">
|
||||||
|
<small>
|
||||||
|
<LocaleText t="IP Address"></LocaleText>
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
{{this.pingResult.address}}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm" v-if="this.pingResult.geo && this.pingResult.geo.status === 'success'">
|
||||||
|
<p class="mb-0 text-muted">
|
||||||
|
<small>
|
||||||
|
<LocaleText t="Geolocation"></LocaleText>
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
{{this.pingResult.geo.city}}, {{this.pingResult.geo.country}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.3s">
|
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.3s">
|
||||||
@ -140,7 +196,9 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.45s">
|
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.45s">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="mb-0 text-muted"><small>Average / Min / Max Round Trip Time</small></p>
|
<p class="mb-0 text-muted"><small>
|
||||||
|
<LocaleText t="Average / Min / Max Round Trip Time"></LocaleText>
|
||||||
|
</small></p>
|
||||||
<samp>{{this.pingResult.avg_rtt}}ms /
|
<samp>{{this.pingResult.avg_rtt}}ms /
|
||||||
{{this.pingResult.min_rtt}}ms /
|
{{this.pingResult.min_rtt}}ms /
|
||||||
{{this.pingResult.max_rtt}}ms
|
{{this.pingResult.max_rtt}}ms
|
||||||
@ -149,14 +207,16 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.6s">
|
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.6s">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="mb-0 text-muted"><small>Sent / Received / Lost Package</small></p>
|
<p class="mb-0 text-muted"><small>
|
||||||
|
<LocaleText t="Sent / Received / Lost Package"></LocaleText>
|
||||||
|
</small></p>
|
||||||
<samp>{{this.pingResult.package_sent}} /
|
<samp>{{this.pingResult.package_sent}} /
|
||||||
{{this.pingResult.package_received}} /
|
{{this.pingResult.package_received}} /
|
||||||
{{this.pingResult.package_loss}}
|
{{this.pingResult.package_loss}}
|
||||||
</samp>
|
</samp>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Map :d="this.pingResult" v-if="this.pingResult.geo && this.pingResult.geo.status === 'success'"></Map>
|
||||||
</div>
|
</div>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import {fetchGet} from "@/utilities/fetch.js";
|
import {fetchGet} from "@/utilities/fetch.js";
|
||||||
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
|
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
|
||||||
|
import Map from "@/components/map/map.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "traceroute",
|
name: "traceroute",
|
||||||
|
components: {Map},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
tracing: false,
|
tracing: false,
|
||||||
@ -41,55 +43,75 @@ export default {
|
|||||||
<div class="mt-md-5 mt-3 text-body">
|
<div class="mt-md-5 mt-3 text-body">
|
||||||
<div class="container-md">
|
<div class="container-md">
|
||||||
<h3 class="mb-3 text-body">Traceroute</h3>
|
<h3 class="mb-3 text-body">Traceroute</h3>
|
||||||
<div class="row">
|
<div class="d-flex gap-2 flex-column mb-5">
|
||||||
<div class="col-sm-4 d-flex gap-2 flex-column">
|
<div>
|
||||||
<div>
|
<label class="mb-1 text-muted" for="ipAddress">
|
||||||
<label class="mb-1 text-muted" for="ipAddress">
|
<small>IP Address</small></label>
|
||||||
<small>IP Address</small></label>
|
<input
|
||||||
<input
|
id="ipAddress"
|
||||||
id="ipAddress"
|
class="form-control"
|
||||||
class="form-control"
|
v-model="this.ipAddress"
|
||||||
v-model="this.ipAddress"
|
@keyup.enter="this.execute()"
|
||||||
type="text" placeholder="Enter an IP Address you want to trace :)">
|
type="text" placeholder="Enter an IP Address you want to trace :)">
|
||||||
</div>
|
|
||||||
<button class="btn btn-primary rounded-3 mt-3"
|
|
||||||
:disabled="!this.store.regexCheckIP(this.ipAddress) || this.tracing"
|
|
||||||
@click="this.execute()">
|
|
||||||
<i class="bi bi-bullseye me-2"></i> {{this.tracing ? "Tracing...":"Trace It!"}}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-8 position-relative">
|
<button class="btn btn-primary rounded-3 mt-3"
|
||||||
<TransitionGroup name="ping">
|
:disabled="this.tracing"
|
||||||
<div v-if="!this.tracerouteResult" key="pingPlaceholder">
|
@click="this.execute()">
|
||||||
<div class="pingPlaceholder bg-body-secondary rounded-3 mb-3"
|
<i class="bi bi-bullseye me-2"></i> {{this.tracing ? "Tracing...":"Trace It!"}}
|
||||||
:class="{'animate__animated animate__flash animate__slower animate__infinite': this.tracing}"
|
</button>
|
||||||
:style="{'animation-delay': `${x*0.05}s`}"
|
</div>
|
||||||
v-for="x in 10" ></div>
|
<div class="position-relative">
|
||||||
</div>
|
<TransitionGroup name="ping">
|
||||||
<div v-else key="table" class="w-100">
|
<div v-if="!this.tracerouteResult" key="pingPlaceholder">
|
||||||
<table class="table table-borderless rounded-3 w-100">
|
<div class="pingPlaceholder bg-body-secondary rounded-3 mb-3"
|
||||||
|
:class="{'animate__animated animate__flash animate__slower animate__infinite': this.tracing}"
|
||||||
|
:style="{'animation-delay': `${x*0.05}s`}"
|
||||||
|
v-for="x in 5" ></div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<Map :d="this.tracerouteResult" type="traceroute"></Map>
|
||||||
|
|
||||||
|
<div key="table" class="w-100 mt-2">
|
||||||
|
<table class="table table-sm rounded-3 w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">Hop</th>
|
<th scope="col">Hop</th>
|
||||||
<th scope="col">IP Address</th>
|
<th scope="col">IP Address</th>
|
||||||
<th scope="col">Average / Min / Max Round Trip Time</th>
|
<th scope="col">Average RTT (ms)</th>
|
||||||
|
<th scope="col">Min RTT (ms)</th>
|
||||||
|
<th scope="col">Max RTT (ms)</th>
|
||||||
|
<th scope="col">Geolocation</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(hop, key) in this.tracerouteResult"
|
<tr v-for="(hop, key) in this.tracerouteResult">
|
||||||
class="animate__fadeInUp animate__animated"
|
<td>
|
||||||
:style="{'animation-delay': `${key * 0.05}s`}"
|
<small>{{hop.hop}}</small>
|
||||||
>
|
</td>
|
||||||
<td>{{hop.hop}}</td>
|
<td>
|
||||||
<td>{{hop.ip}}</td>
|
<small>{{hop.ip}}</small>
|
||||||
<td>{{hop.avg_rtt}} / {{hop.min_rtt}} / {{hop.max_rtt}}</td>
|
</td>
|
||||||
</tr>
|
<td>
|
||||||
|
<small>{{hop.avg_rtt}}</small>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<small>{{hop.min_rtt}}</small>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<small>{{hop.max_rtt}}</small>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="hop.geo.city && hop.geo.country">
|
||||||
|
<small>{{hop.geo.city}}, {{hop.geo.country}}</small>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</TransitionGroup>
|
</div>
|
||||||
</div>
|
</TransitionGroup>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -123,11 +145,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
table th, table td{
|
table th, table td{
|
||||||
padding: 0.9rem;
|
padding: 0.5rem;
|
||||||
}
|
|
||||||
|
|
||||||
table tbody{
|
|
||||||
border-top: 1em solid transparent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.table > :not(caption) > * > *{
|
.table > :not(caption) > * > *{
|
||||||
|
Loading…
Reference in New Issue
Block a user