mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-22 23:27:45 +01:00
Finished revamping peer edit
This commit is contained in:
parent
f1e71ecb78
commit
bcd845fd59
@ -1,4 +1,5 @@
|
|||||||
import itertools
|
import itertools
|
||||||
|
import random
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import configparser
|
import configparser
|
||||||
import hashlib
|
import hashlib
|
||||||
@ -13,6 +14,7 @@ import re
|
|||||||
import urllib.parse
|
import urllib.parse
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.error
|
import urllib.error
|
||||||
|
import uuid
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from json import JSONEncoder
|
from json import JSONEncoder
|
||||||
@ -262,7 +264,7 @@ class WireguardConfiguration:
|
|||||||
sqldb.commit()
|
sqldb.commit()
|
||||||
|
|
||||||
def __getPublicKey(self) -> str:
|
def __getPublicKey(self) -> str:
|
||||||
return subprocess.check_output(['wg', 'pubkey'], input=self.PrivateKey.encode()).decode().strip('\n')
|
return _generatePublicKey(self.PrivateKey)[1]
|
||||||
|
|
||||||
def getStatus(self) -> bool:
|
def getStatus(self) -> bool:
|
||||||
self.Status = self.Name in psutil.net_if_addrs().keys()
|
self.Status = self.Name in psutil.net_if_addrs().keys()
|
||||||
@ -333,6 +335,12 @@ class WireguardConfiguration:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def searchPeer(self, publicKey):
|
||||||
|
for i in self.Peers:
|
||||||
|
if i.id == publicKey:
|
||||||
|
return True, i
|
||||||
|
return False, None
|
||||||
|
|
||||||
def __savePeers(self):
|
def __savePeers(self):
|
||||||
for i in self.Peers:
|
for i in self.Peers:
|
||||||
d = i.toJson()
|
d = i.toJson()
|
||||||
@ -671,6 +679,56 @@ def _getConfigurationList() -> [WireguardConfiguration]:
|
|||||||
return configurations
|
return configurations
|
||||||
|
|
||||||
|
|
||||||
|
def _checkIPWithRange(ip):
|
||||||
|
ip_patterns = (
|
||||||
|
r"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|\/)){4}([0-9]{1,2})(,|$)",
|
||||||
|
r"[0-9a-fA-F]{0,4}(:([0-9a-fA-F]{0,4})){1,7}\/([0-9]{1,3})(,|$)"
|
||||||
|
)
|
||||||
|
|
||||||
|
for match_pattern in ip_patterns:
|
||||||
|
match_result = regex_match(match_pattern, ip)
|
||||||
|
if match_result:
|
||||||
|
result = match_result
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
result = None
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _checkIP(ip):
|
||||||
|
ip_patterns = (
|
||||||
|
r"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}",
|
||||||
|
r"[0-9a-fA-F]{0,4}(:([0-9a-fA-F]{0,4})){1,7}$"
|
||||||
|
)
|
||||||
|
for match_pattern in ip_patterns:
|
||||||
|
match_result = regex_match(match_pattern, ip)
|
||||||
|
if match_result:
|
||||||
|
result = match_result
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
result = None
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _checkDNS(dns):
|
||||||
|
dns = dns.replace(' ', '').split(',')
|
||||||
|
for i in dns:
|
||||||
|
if not (_checkIP(i) or regex_match(r"(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z]{0,61}[a-z]", i)):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _generatePublicKey(privateKey) -> [bool, str]:
|
||||||
|
try:
|
||||||
|
publicKey = subprocess.check_output(f"wg pubkey", input=privateKey.encode(), shell=True,
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
return True, publicKey.decode().strip('\n')
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
API Routes
|
API Routes
|
||||||
'''
|
'''
|
||||||
@ -827,6 +885,88 @@ def API_updateDashboardConfigurationItem():
|
|||||||
return ResponseObject()
|
return ResponseObject()
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/updatePeerSettings/<configName>', methods=['POST'])
|
||||||
|
def API_updatePeerSettings(configName):
|
||||||
|
data = request.get_json()
|
||||||
|
id = data['id']
|
||||||
|
|
||||||
|
if len(id) > 0 and configName in WireguardConfigurations.keys():
|
||||||
|
name = data['name']
|
||||||
|
private_key = data['private_key']
|
||||||
|
dns_addresses = data['DNS']
|
||||||
|
allowed_ip = data['allowed_ip']
|
||||||
|
endpoint_allowed_ip = data['endpoint_allowed_ip']
|
||||||
|
preshared_key = data['preshared_key']
|
||||||
|
|
||||||
|
wireguardConfig = WireguardConfigurations[configName]
|
||||||
|
foundPeer, peer = wireguardConfig.searchPeer(id)
|
||||||
|
if foundPeer:
|
||||||
|
for p in wireguardConfig.Peers:
|
||||||
|
if allowed_ip in p.allowed_ip and p.id != peer.id:
|
||||||
|
return ResponseObject(False, f"Allowed IP already taken by another peer.")
|
||||||
|
if not _checkIPWithRange(endpoint_allowed_ip):
|
||||||
|
return ResponseObject(False, f"Endpoint Allowed IPs format is incorrect.")
|
||||||
|
if not _checkDNS(dns_addresses):
|
||||||
|
return ResponseObject(False, f"DNS format is incorrect.")
|
||||||
|
if data['mtu'] < 0 or data['mtu'] > 1460:
|
||||||
|
return ResponseObject(False, "MTU format is not correct.")
|
||||||
|
if data['keepalive'] < 0:
|
||||||
|
return ResponseObject(False, "Persistent Keepalive format is not correct.")
|
||||||
|
if len(private_key) > 0:
|
||||||
|
pubKey = _generatePublicKey(private_key)
|
||||||
|
if not pubKey[0] or pubKey[1] != peer.id:
|
||||||
|
return ResponseObject(False, "Private key does not match with the public key.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
rd = random.Random()
|
||||||
|
uid = uuid.UUID(int=rd.getrandbits(128), version=4)
|
||||||
|
with open(f"{uid}", "w+") as f:
|
||||||
|
f.write(preshared_key)
|
||||||
|
updatePsk = subprocess.check_output(
|
||||||
|
f"wg set {configName} peer {peer.id} preshared-key {uid}",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
os.remove(str(uid))
|
||||||
|
if len(updatePsk.decode().strip("\n")) != 0:
|
||||||
|
return ResponseObject(False,
|
||||||
|
"Update peer failed when updating preshared key: " + updatePsk.decode().strip(
|
||||||
|
"\n"))
|
||||||
|
|
||||||
|
allowed_ip = allowed_ip.replace(" ", "")
|
||||||
|
updateAllowedIp = subprocess.check_output(
|
||||||
|
f'wg set {configName} peer {peer.id} allowed-ips "{allowed_ip}"',
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
if len(updateAllowedIp.decode().strip("\n")) != 0:
|
||||||
|
return ResponseObject(False,
|
||||||
|
"Update peer failed when updating allowed IPs: " + updateAllowedIp.decode().strip(
|
||||||
|
"\n"))
|
||||||
|
saveConfig = subprocess.check_output(f"wg-quick save {configName}",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
if f"wg showconf {configName}" not in saveConfig.decode().strip('\n'):
|
||||||
|
return ResponseObject(False,
|
||||||
|
"Update peer failed when saving the configuration." + saveConfig.decode().strip(
|
||||||
|
'\n'))
|
||||||
|
|
||||||
|
cursor.execute(
|
||||||
|
'''UPDATE %s SET name = ?, private_key = ?, DNS = ?, endpoint_allowed_ip = ?, mtu = ?,
|
||||||
|
keepalive = ?, preshared_key = ? WHERE id = ?''' % configName,
|
||||||
|
(name, private_key, dns_addresses, endpoint_allowed_ip, data["mtu"],
|
||||||
|
data["keepalive"], preshared_key, id,)
|
||||||
|
)
|
||||||
|
return ResponseObject()
|
||||||
|
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
return ResponseObject(False, exc.output.decode("UTF-8").strip())
|
||||||
|
|
||||||
|
return ResponseObject(False, "Peer does not exist")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/downloadPeer/<configName>")
|
||||||
|
def API_downloadPeer(configName):
|
||||||
|
if configName in WireguardConfigurations.keys():
|
||||||
|
pass
|
||||||
|
return ResponseObject(False)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/getWireguardConfigurationInfo', methods=["GET"])
|
@app.route('/api/getWireguardConfigurationInfo', methods=["GET"])
|
||||||
def API_getConfigurationInfo():
|
def API_getConfigurationInfo():
|
||||||
configurationName = request.args.get("configurationName")
|
configurationName = request.args.get("configurationName")
|
||||||
@ -843,6 +983,11 @@ def API_getDashboardTheme():
|
|||||||
return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1])
|
return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1])
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
Sign Up
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/isTotpEnabled')
|
@app.route('/api/isTotpEnabled')
|
||||||
def API_isTotpEnabled():
|
def API_isTotpEnabled():
|
||||||
return ResponseObject(data=DashboardConfig.GetConfig("Account", "enable_totp")[1])
|
return ResponseObject(data=DashboardConfig.GetConfig("Account", "enable_totp")[1])
|
||||||
|
@ -74,6 +74,7 @@ export default {
|
|||||||
</a>
|
</a>
|
||||||
<Transition name="slide-fade">
|
<Transition name="slide-fade">
|
||||||
<PeerSettingsDropdown
|
<PeerSettingsDropdown
|
||||||
|
@setting="this.$emit('setting')"
|
||||||
:Peer="Peer"
|
:Peer="Peer"
|
||||||
v-if="this.subMenuOpened"
|
v-if="this.subMenuOpened"
|
||||||
ref="target"
|
ref="target"
|
||||||
|
@ -33,6 +33,7 @@ import {
|
|||||||
Tooltip
|
Tooltip
|
||||||
} from 'chart.js';
|
} from 'chart.js';
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import PeerSettings from "@/components/configurationComponents/peerSettings.vue";
|
||||||
|
|
||||||
Chart.register(
|
Chart.register(
|
||||||
ArcElement,
|
ArcElement,
|
||||||
@ -62,7 +63,7 @@ Chart.register(
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "peerList",
|
name: "peerList",
|
||||||
components: {PeerSearch, Peer, Line, Bar},
|
components: {PeerSettings, PeerSearch, Peer, Line, Bar},
|
||||||
setup(){
|
setup(){
|
||||||
const dashboardConfigurationStore = DashboardConfigurationStore();
|
const dashboardConfigurationStore = DashboardConfigurationStore();
|
||||||
const wireguardConfigurationStore = WireguardConfigurationsStore();
|
const wireguardConfigurationStore = WireguardConfigurationsStore();
|
||||||
@ -100,10 +101,14 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
peerSetting: {
|
||||||
|
modalOpen: false,
|
||||||
|
selectedPeer: undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'$route.params.id': {
|
'$route.params': {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(){
|
handler(){
|
||||||
clearInterval(this.interval)
|
clearInterval(this.interval)
|
||||||
@ -430,17 +435,9 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<RouterView v-slot="{Component}">
|
|
||||||
<Transition name="fade3" mode="out-in">
|
|
||||||
<Component :is="Component"></Component>
|
|
||||||
</Transition>
|
|
||||||
</RouterView>
|
|
||||||
<div class="d-flex align-items-center gap-3 mb-2 ">
|
<div class="d-flex align-items-center gap-3 mb-2 ">
|
||||||
<h3>Peers</h3>
|
<h3>Peers</h3>
|
||||||
<RouterLink
|
<a href="#" class="text-decoration-none ms-auto"><i class="bi bi-plus-circle-fill me-2"></i>Add Peer</a>
|
||||||
to="./peer_settings"
|
|
||||||
class="ms-auto text-secondary text-decoration-none"><i class="bi bi-sliders2 me-2"></i>Peer Settings</RouterLink>
|
|
||||||
<a href="#" class="text-decoration-none"><i class="bi bi-plus-circle-fill me-2"></i>Add Peer</a>
|
|
||||||
</div>
|
</div>
|
||||||
<PeerSearch></PeerSearch>
|
<PeerSearch></PeerSearch>
|
||||||
|
|
||||||
@ -448,11 +445,17 @@ export default {
|
|||||||
<div class="col-12 col-lg-6 col-xl-4"
|
<div class="col-12 col-lg-6 col-xl-4"
|
||||||
:key="peer.id"
|
:key="peer.id"
|
||||||
v-for="peer in this.searchPeers">
|
v-for="peer in this.searchPeers">
|
||||||
<Peer :Peer="peer"></Peer>
|
<Peer :Peer="peer" @setting="peerSetting.modalOpen = true; peerSetting.selectedPeer = this.configurationPeers.find(x => x.id === peer.id)"></Peer>
|
||||||
</div>
|
</div>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<Transition name="fade">
|
||||||
|
<PeerSettings v-if="this.peerSetting.modalOpen"
|
||||||
|
:selectedPeer="this.peerSetting.selectedPeer"
|
||||||
|
@refresh="this.getPeers(this.$route.params.id)"
|
||||||
|
@close="this.peerSetting.modalOpen = false">
|
||||||
|
</PeerSettings>
|
||||||
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,21 +1,182 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import {fetchPost} from "@/utilities/fetch.js";
|
||||||
|
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "peerSettings"
|
name: "peerSettings",
|
||||||
|
props: {
|
||||||
|
selectedPeer: Object
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
data: undefined,
|
||||||
|
dataChanged: false,
|
||||||
|
showKey: false,
|
||||||
|
saving: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(){
|
||||||
|
const dashboardConfigurationStore = DashboardConfigurationStore();
|
||||||
|
return {dashboardConfigurationStore}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
reset(){
|
||||||
|
if (this.selectedPeer){
|
||||||
|
this.data = JSON.parse(JSON.stringify(this.selectedPeer))
|
||||||
|
this.dataChanged = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
savePeer(){
|
||||||
|
this.saving = true;
|
||||||
|
fetchPost(`/api/updatePeerSettings/${this.$route.params.id}`, this.data, (res) => {
|
||||||
|
this.saving = false;
|
||||||
|
if (res.status){
|
||||||
|
this.dashboardConfigurationStore.newMessage("Server", "Peer Updated!", "success")
|
||||||
|
}else{
|
||||||
|
this.dashboardConfigurationStore.newMessage("Server", res.message, "danger")
|
||||||
|
}
|
||||||
|
this.$emit("refresh")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$el.querySelectorAll("input").forEach(x => {
|
||||||
|
x.addEventListener("keyup", () => {
|
||||||
|
this.dataChanged = true;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0">
|
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0">
|
||||||
<div class="container d-flex h-100 w-100">
|
<div class="container d-flex h-100 w-100">
|
||||||
<div class="card m-auto rounded-3 w-100">
|
<div class="card m-auto rounded-3 shadow" style="width: 700px">
|
||||||
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4">
|
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4">
|
||||||
<h4 class="mb-0">Peer Settings</h4>
|
<h4 class="mb-0">Peer Settings</h4>
|
||||||
<router-link to="./" class="ms-auto btn">
|
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
|
||||||
<i class="bi bi-x-lg"></i>
|
</div>
|
||||||
</router-link>
|
<div class="card-body px-4 pb-4" v-if="this.data">
|
||||||
|
<div class="d-flex flex-column gap-2 mb-4">
|
||||||
|
<div>
|
||||||
|
<small class="text-muted">Public Key</small><br>
|
||||||
|
<small><samp>{{this.data.id}}</samp></small>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="peer_name_textbox" class="form-label">
|
||||||
|
<small class="text-muted">Name</small>
|
||||||
|
</label>
|
||||||
|
<input type="text" class="form-control form-control-sm rounded-3"
|
||||||
|
:disabled="this.saving"
|
||||||
|
v-model="this.data.name"
|
||||||
|
id="peer_name_textbox" placeholder="">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="d-flex position-relative">
|
||||||
|
<label for="peer_private_key_textbox" class="form-label">
|
||||||
|
<small class="text-muted">Private Key <code>(Required for QR Code and Download)</code></small>
|
||||||
|
</label>
|
||||||
|
<a role="button" class="ms-auto text-decoration-none toggleShowKey"
|
||||||
|
@click="this.showKey = !this.showKey"
|
||||||
|
>
|
||||||
|
<i class="bi" :class="[this.showKey ? 'bi-eye-slash-fill':'bi-eye-fill']"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<input :type="[this.showKey ? 'text':'password']" class="form-control form-control-sm rounded-3"
|
||||||
|
:disabled="this.saving"
|
||||||
|
v-model="this.data.private_key"
|
||||||
|
id="peer_private_key_textbox"
|
||||||
|
style="padding-right: 40px">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="peer_allowed_ip_textbox" class="form-label">
|
||||||
|
<small class="text-muted">Allowed IPs <code>(Required)</code></small>
|
||||||
|
</label>
|
||||||
|
<input type="text" class="form-control form-control-sm rounded-3"
|
||||||
|
:disabled="this.saving"
|
||||||
|
v-model="this.data.allowed_ip"
|
||||||
|
id="peer_allowed_ip_textbox">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="peer_DNS_textbox" class="form-label">
|
||||||
|
<small class="text-muted">DNS <code>(Required)</code></small>
|
||||||
|
</label>
|
||||||
|
<input type="text" class="form-control form-control-sm rounded-3"
|
||||||
|
:disabled="this.saving"
|
||||||
|
v-model="this.data.DNS"
|
||||||
|
id="peer_DNS_textbox">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="peer_endpoint_allowed_ips" class="form-label">
|
||||||
|
<small class="text-muted">Endpoint Allowed IPs <code>(Required)</code></small>
|
||||||
|
</label>
|
||||||
|
<input type="text" class="form-control form-control-sm rounded-3"
|
||||||
|
:disabled="this.saving"
|
||||||
|
v-model="this.data.endpoint_allowed_ip"
|
||||||
|
id="peer_endpoint_allowed_ips">
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="accordion mt-2" id="peerSettingsAccordion">
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header">
|
||||||
|
<button class="accordion-button rounded-3 collapsed" type="button"
|
||||||
|
data-bs-toggle="collapse" data-bs-target="#peerSettingsAccordionOptional">
|
||||||
|
Optional Settings
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="peerSettingsAccordionOptional" class="accordion-collapse collapse"
|
||||||
|
data-bs-parent="#peerSettingsAccordion">
|
||||||
|
<div class="accordion-body d-flex flex-column gap-2 mb-2">
|
||||||
|
<div>
|
||||||
|
<label for="peer_preshared_key_textbox" class="form-label">
|
||||||
|
<small class="text-muted">Pre-Shared Key</small>
|
||||||
|
</label>
|
||||||
|
<input type="text" class="form-control form-control-sm rounded-3"
|
||||||
|
:disabled="this.saving"
|
||||||
|
v-model="this.data.preshared_key"
|
||||||
|
id="peer_preshared_key_textbox">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="peer_mtu" class="form-label"><small class="text-muted">MTU</small></label>
|
||||||
|
<input type="number" class="form-control form-control-sm rounded-3"
|
||||||
|
:disabled="this.saving"
|
||||||
|
v-model="this.data.mtu"
|
||||||
|
id="peer_mtu">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="peer_keep_alive" class="form-label">
|
||||||
|
<small class="text-muted">Persistent Keepalive</small>
|
||||||
|
</label>
|
||||||
|
<input type="number" class="form-control form-control-sm rounded-3"
|
||||||
|
:disabled="this.saving"
|
||||||
|
v-model="this.data.keepalive"
|
||||||
|
id="peer_keep_alive">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center gap-2">
|
||||||
|
<button class="btn btn-secondary rounded-3 shadow"
|
||||||
|
@click="this.reset()"
|
||||||
|
:disabled="!this.dataChanged || this.saving">
|
||||||
|
Reset <i class="bi bi-arrow-clockwise ms-2"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="ms-auto btn btn-dark btn-brand rounded-3 px-3 py-2 shadow"
|
||||||
|
:disabled="!this.dataChanged || this.saving"
|
||||||
|
@click="this.savePeer()"
|
||||||
|
>
|
||||||
|
Save Peer<i class="bi bi-save-fill ms-2"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body p-4">
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -29,4 +190,9 @@ export default {
|
|||||||
background-color: #00000060;
|
background-color: #00000060;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
.toggleShowKey{
|
||||||
|
position: absolute;
|
||||||
|
top: 35px;
|
||||||
|
right: 12px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -21,7 +21,9 @@ export default {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item d-flex" role="button">
|
<a class="dropdown-item d-flex" role="button"
|
||||||
|
@click="this.$emit('setting')"
|
||||||
|
>
|
||||||
<i class="me-auto bi bi-pen"></i> Edit
|
<i class="me-auto bi bi-pen"></i> Edit
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -18,7 +18,7 @@ export default {
|
|||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="d-flex mb-4 ">
|
<div class="d-flex mb-4 ">
|
||||||
<h3 class="text-body">Wireguard Configurations</h3>
|
<h3 class="text-body">WireGuard Configurations</h3>
|
||||||
<RouterLink to="/new_configuration" class="btn btn-dark btn-brand rounded-3 px-3 py-2 shadow ms-auto rounded-3">
|
<RouterLink to="/new_configuration" class="btn btn-dark btn-brand rounded-3 px-3 py-2 shadow ms-auto rounded-3">
|
||||||
Configuration
|
Configuration
|
||||||
<i class="bi bi-plus-circle-fill ms-2"></i>
|
<i class="bi bi-plus-circle-fill ms-2"></i>
|
||||||
|
@ -30,34 +30,46 @@ const router = createRouter({
|
|||||||
path: '/',
|
path: '/',
|
||||||
component: Index,
|
component: Index,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
|
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: "Configuration List",
|
name: "Configuration List",
|
||||||
path: '',
|
path: '',
|
||||||
component: ConfigurationList
|
component: ConfigurationList,
|
||||||
|
meta: {
|
||||||
|
title: "WireGuard Configurations"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Settings",
|
name: "Settings",
|
||||||
path: '/settings',
|
path: '/settings',
|
||||||
component: Settings
|
component: Settings,
|
||||||
|
meta: {
|
||||||
|
title: "Settings"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "New Configuration",
|
name: "New Configuration",
|
||||||
path: '/new_configuration',
|
path: '/new_configuration',
|
||||||
component: NewConfiguration
|
component: NewConfiguration,
|
||||||
|
meta: {
|
||||||
|
title: "New Configuration"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Configuration",
|
name: "Configuration",
|
||||||
path: '/configuration/:id/',
|
path: '/configuration/:id',
|
||||||
component: Configuration,
|
component: Configuration,
|
||||||
|
meta: {
|
||||||
|
title: "Configuration"
|
||||||
|
},
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "Peer Settings",
|
name: "Peers List",
|
||||||
path: 'peer_settings',
|
path: '',
|
||||||
component: PeerSettings
|
component: PeerList
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -65,7 +77,10 @@ const router = createRouter({
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/signin', component: Signin
|
path: '/signin', component: Signin,
|
||||||
|
meta: {
|
||||||
|
title: "Sign In"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/welcome', component: Setup,
|
path: '/welcome', component: Setup,
|
||||||
@ -80,6 +95,15 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
const wireguardConfigurationsStore = WireguardConfigurationsStore();
|
const wireguardConfigurationsStore = WireguardConfigurationsStore();
|
||||||
const dashboardConfigurationStore = DashboardConfigurationStore();
|
const dashboardConfigurationStore = DashboardConfigurationStore();
|
||||||
|
|
||||||
|
if (to.meta.title){
|
||||||
|
if (to.params.id){
|
||||||
|
document.title = to.params.id + " | WGDashboard";
|
||||||
|
}else{
|
||||||
|
document.title = to.meta.title + " | WGDashboard";
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
document.title = "WGDashboard"
|
||||||
|
}
|
||||||
|
|
||||||
if (to.meta.requiresAuth){
|
if (to.meta.requiresAuth){
|
||||||
if (cookie.getCookie("authToken") && await checkAuth()){
|
if (cookie.getCookie("authToken") && await checkAuth()){
|
||||||
|
@ -71,7 +71,12 @@ export default {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mt-5 text-body">
|
<div class="mt-5 text-body">
|
||||||
<PeerList></PeerList>
|
<!-- <PeerList></PeerList>-->
|
||||||
|
<RouterView v-slot="{ Component }">
|
||||||
|
<Transition name="fade2" mode="out-in">
|
||||||
|
<Component :is="Component"></Component>
|
||||||
|
</Transition>
|
||||||
|
</RouterView>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user