mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-06 16:00:28 +01:00
Adjusted some UI and finished the Ping function
This commit is contained in:
parent
eb18857ecc
commit
f0f486da9e
@ -631,6 +631,39 @@ class Peer:
|
|||||||
except subprocess.CalledProcessError as exc:
|
except subprocess.CalledProcessError as exc:
|
||||||
return ResponseObject(False, exc.output.decode("UTF-8").strip())
|
return ResponseObject(False, exc.output.decode("UTF-8").strip())
|
||||||
|
|
||||||
|
def downloadPeer(self) -> dict[str, str]:
|
||||||
|
filename = self.name
|
||||||
|
if len(filename) == 0:
|
||||||
|
filename = "UntitledPeer"
|
||||||
|
filename = "".join(filename.split(' '))
|
||||||
|
filename = f"{filename}_{self.configuration.Name}"
|
||||||
|
illegal_filename = [".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "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:
|
||||||
|
filename = filename.replace(i, "")
|
||||||
|
|
||||||
|
peerConfiguration = f'''[Interface]
|
||||||
|
PrivateKey = {self.private_key}
|
||||||
|
Address = {self.allowed_ip}
|
||||||
|
MTU = {str(self.mtu)}
|
||||||
|
'''
|
||||||
|
if len(self.DNS) > 0:
|
||||||
|
peerConfiguration += f"DNS = {self.DNS}\n"
|
||||||
|
peerConfiguration += f'''
|
||||||
|
[Peer]
|
||||||
|
PublicKey = {self.configuration.PublicKey}
|
||||||
|
AllowedIPs = {self.endpoint_allowed_ip}
|
||||||
|
Endpoint = {DashboardConfig.GetConfig("Peers", "remote_endpoint")[1]}:{self.configuration.ListenPort}
|
||||||
|
PersistentKeepalive = {str(self.keepalive)}
|
||||||
|
'''
|
||||||
|
if len(self.preshared_key) > 0:
|
||||||
|
peerConfiguration += f"PresharedKey = {self.preshared_key}\n"
|
||||||
|
return {
|
||||||
|
"fileName": filename,
|
||||||
|
"file": peerConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Regex Match
|
# Regex Match
|
||||||
def regex_match(regex, text):
|
def regex_match(regex, text):
|
||||||
@ -1218,40 +1251,23 @@ def API_downloadPeer(configName):
|
|||||||
peerFound, peer = configuration.searchPeer(data['id'])
|
peerFound, peer = configuration.searchPeer(data['id'])
|
||||||
if len(data['id']) == 0 or not peerFound:
|
if len(data['id']) == 0 or not peerFound:
|
||||||
return ResponseObject(False, "Configuration or peer does not exist")
|
return ResponseObject(False, "Configuration or peer does not exist")
|
||||||
|
return ResponseObject(data=peer.downloadPeer())
|
||||||
filename = peer.name
|
|
||||||
if len(filename) == 0:
|
|
||||||
filename = "UntitledPeer"
|
|
||||||
filename = "".join(filename.split(' '))
|
|
||||||
filename = f"{filename}_{configuration.Name}"
|
|
||||||
illegal_filename = [".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "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:
|
|
||||||
filename = filename.replace(i, "")
|
|
||||||
|
|
||||||
peerConfiguration = f'''[Interface]
|
|
||||||
PrivateKey = {peer.private_key}
|
|
||||||
Address = {peer.allowed_ip}
|
|
||||||
MTU = {str(peer.mtu)}
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
@app.route("/api/downloadAllPeers/<configName>")
|
||||||
if len(peer.DNS) > 0:
|
def API_downloadAllPeers(configName):
|
||||||
peerConfiguration += f"DNS = {peer.DNS}\n"
|
if configName not in WireguardConfigurations.keys():
|
||||||
peerConfiguration += f'''
|
return ResponseObject(False, "Configuration or peer does not exist")
|
||||||
[Peer]
|
configuration = WireguardConfigurations[configName]
|
||||||
PublicKey = {configuration.PublicKey}
|
peerData = []
|
||||||
AllowedIPs = {peer.endpoint_allowed_ip}
|
untitledPeer = 0
|
||||||
Endpoint = {DashboardConfig.GetConfig("Peers", "remote_endpoint")[1]}:{configuration.ListenPort}
|
for i in configuration.Peers:
|
||||||
PersistentKeepalive = {str(peer.keepalive)}
|
file = i.downloadPeer()
|
||||||
'''
|
if file["fileName"] == "UntitledPeer_" + configName:
|
||||||
if len(peer.preshared_key) > 0:
|
file["fileName"] = str(untitledPeer) + "_" + file["fileName"]
|
||||||
peerConfiguration += f"PresharedKey = {peer.preshared_key}\n"
|
untitledPeer += 1
|
||||||
return ResponseObject(data={
|
peerData.append(file)
|
||||||
"fileName": filename,
|
return ResponseObject(data=peerData)
|
||||||
"file": peerConfiguration
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/getAvailableIPs/<configName>")
|
@app.route("/api/getAvailableIPs/<configName>")
|
||||||
@ -1277,6 +1293,59 @@ def API_getDashboardTheme():
|
|||||||
return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1])
|
return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1])
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/ping/getAllPeersIpAddress')
|
||||||
|
def API_ping_getAllPeersIpAddress():
|
||||||
|
ips = {}
|
||||||
|
for c in WireguardConfigurations.values():
|
||||||
|
cips = {}
|
||||||
|
for p in c.Peers:
|
||||||
|
allowed_ip = p.allowed_ip.replace(" ", "").split(",")
|
||||||
|
parsed = []
|
||||||
|
for x in allowed_ip:
|
||||||
|
ip = ipaddress.ip_network(x, strict=False)
|
||||||
|
if len(list(ip.hosts())) == 1:
|
||||||
|
parsed.append(str(ip.hosts()[0]))
|
||||||
|
endpoint = p.endpoint.replace(" ", "").replace("(none)", "")
|
||||||
|
if len(p.name) > 0:
|
||||||
|
cips[f"{p.name} - {p.id}"] = {
|
||||||
|
"allowed_ips": parsed,
|
||||||
|
"endpoint": endpoint
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
cips[f"{p.id}"] = {
|
||||||
|
"allowed_ips": parsed,
|
||||||
|
"endpoint": endpoint
|
||||||
|
}
|
||||||
|
ips[c.Name] = cips
|
||||||
|
return ResponseObject(data=ips)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/ping/execute')
|
||||||
|
def API_ping_execute():
|
||||||
|
if "ipAddress" in request.args.keys() and "count" in request.args.keys():
|
||||||
|
ip = request.args['ipAddress']
|
||||||
|
count = request.args['count']
|
||||||
|
try:
|
||||||
|
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)
|
||||||
|
|
||||||
|
return ResponseObject(data={
|
||||||
|
"address": result.address,
|
||||||
|
"is_alive": result.is_alive,
|
||||||
|
"min_rtt": result.min_rtt,
|
||||||
|
"avg_rtt": result.avg_rtt,
|
||||||
|
"max_rtt": result.max_rtt,
|
||||||
|
"package_sent": result.packets_sent,
|
||||||
|
"package_received": result.packets_received,
|
||||||
|
"package_loss": result.packet_loss
|
||||||
|
})
|
||||||
|
|
||||||
|
return ResponseObject(False, "Please specify an IP Address (v4/v6)")
|
||||||
|
except Exception as exp:
|
||||||
|
return ResponseObject(False, exp)
|
||||||
|
return ResponseObject(False, "Please provide ipAddress and count")
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Sign Up
|
Sign Up
|
||||||
'''
|
'''
|
||||||
|
@ -1,942 +0,0 @@
|
|||||||
body {
|
|
||||||
font-size: .875rem;
|
|
||||||
/*font-family: 'Poppins', sans-serif;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.codeFont{
|
|
||||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feather {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
vertical-align: text-bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboardLogo{
|
|
||||||
background: -webkit-linear-gradient(#178bff, #ff4a00);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sidebar
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*.sidebar {*/
|
|
||||||
/* position: fixed;*/
|
|
||||||
/* top: 0;*/
|
|
||||||
/* bottom: 0;*/
|
|
||||||
/* left: 0;*/
|
|
||||||
/* z-index: 100;*/
|
|
||||||
/* !* Behind the navbar *!*/
|
|
||||||
/* padding: 48px 0 0;*/
|
|
||||||
/* !* Height of navbar *!*/
|
|
||||||
/* box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
/*.sidebar-sticky {*/
|
|
||||||
/* position: relative;*/
|
|
||||||
/* top: 0;*/
|
|
||||||
/* height: calc(100vh - 48px);*/
|
|
||||||
/* padding-top: .5rem;*/
|
|
||||||
/* overflow-x: hidden;*/
|
|
||||||
/* overflow-y: auto;*/
|
|
||||||
/* !* Scrollable contents if viewport is shorter than content. *!*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
/*@supports ((position: -webkit-sticky) or (position: sticky)) {*/
|
|
||||||
/* .sidebar-sticky {*/
|
|
||||||
/* position: -webkit-sticky;*/
|
|
||||||
/* position: sticky;*/
|
|
||||||
/* }*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
.sidebar .nav-link, .bottomNavContainer .nav-link{
|
|
||||||
font-weight: 500;
|
|
||||||
color: #333;
|
|
||||||
transition: 0.2s cubic-bezier(0.82, -0.07, 0, 1.01);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-link:hover {
|
|
||||||
padding-left: 30px;
|
|
||||||
background-color: #dfdfdf;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-link .feather {
|
|
||||||
margin-right: 4px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-link.active, .bottomNavContainer .nav-link.active {
|
|
||||||
color: #007bff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-link:hover .feather,
|
|
||||||
.sidebar .nav-link.active .feather {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-heading {
|
|
||||||
font-size: .75rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Navbar
|
|
||||||
*/
|
|
||||||
|
|
||||||
.navbar-brand {
|
|
||||||
padding-top: .75rem;
|
|
||||||
padding-bottom: .75rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
/*background-color: rgba(0, 0, 0, .25);*/
|
|
||||||
/*box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar .navbar-toggler {
|
|
||||||
top: .25rem;
|
|
||||||
right: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control {
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control:disabled {
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar .form-control {
|
|
||||||
padding: .75rem 1rem;
|
|
||||||
border-width: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control-dark {
|
|
||||||
color: #fff;
|
|
||||||
background-color: rgba(255, 255, 255, .1);
|
|
||||||
border-color: rgba(255, 255, 255, .1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control-dark:focus {
|
|
||||||
border-color: transparent;
|
|
||||||
box-shadow: 0 0 0 3px rgba(255, 255, 255, .25);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dot {
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
border-radius: 50px;
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dot-running {
|
|
||||||
background-color: #28a745!important;
|
|
||||||
box-shadow: 0 0 0 0.2rem #28a74545;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h6-dot-running {
|
|
||||||
margin-left: 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dot-stopped {
|
|
||||||
background-color: #6c757d!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-running {
|
|
||||||
border-color: #28a745;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info h6 {
|
|
||||||
line-break: anywhere;
|
|
||||||
transition: all 0.4s cubic-bezier(0.96, -0.07, 0.34, 1.01);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info .row .col-sm {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info .row .col-sm small {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info .row .col-sm small strong:last-child(1) {
|
|
||||||
margin-left: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-control {
|
|
||||||
border: none !important;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0 1rem 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-control:hover{
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-control:active,
|
|
||||||
.btn-control:focus {
|
|
||||||
background-color: transparent !important;
|
|
||||||
border: none !important;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-qrcode-peer {
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-qrcode-peer:active,
|
|
||||||
.btn-qrcode-peer:hover {
|
|
||||||
transform: scale(0.9) rotate(180deg);
|
|
||||||
border: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-download-peer:active,
|
|
||||||
.btn-download-peer:hover {
|
|
||||||
color: #17a2b8 !important;
|
|
||||||
transform: translateY(5px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.share_peer_btn_group .btn-control {
|
|
||||||
margin: 0 0 0 1rem;
|
|
||||||
padding: 0 !important;
|
|
||||||
transition: all 0.4s cubic-bezier(1, -0.43, 0, 1.37);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-control:hover {
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-delete-peer:hover {
|
|
||||||
color: #dc3545;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-lock-peer:hover {
|
|
||||||
color: #28a745;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-lock-peer.lock{
|
|
||||||
color: #6c757d
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-lock-peer.lock:hover{
|
|
||||||
color: #6c757d
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-control.btn-outline-primary:hover{
|
|
||||||
color: #007bff
|
|
||||||
}
|
|
||||||
|
|
||||||
/* .btn-setting-peer:hover {
|
|
||||||
color: #007bff
|
|
||||||
} */
|
|
||||||
|
|
||||||
.btn-download-peer:hover {
|
|
||||||
color: #17a2b8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-container {
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
|
||||||
.card-col {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch {
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch:hover {
|
|
||||||
text-decoration: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-group-label:hover {
|
|
||||||
color: #007bff;
|
|
||||||
border-color: #007bff;
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peer_data_group {
|
|
||||||
text-align: right;
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 0.5rem
|
|
||||||
}
|
|
||||||
|
|
||||||
.peer_data_group p {
|
|
||||||
text-transform: uppercase;
|
|
||||||
margin-bottom: 0;
|
|
||||||
margin-right: 1rem
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.peer_data_group {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.index-switch {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
margin-bottom: 3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peer_list {
|
|
||||||
margin-bottom: 7rem
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.add_btn {
|
|
||||||
bottom: 1.5rem !important;
|
|
||||||
}
|
|
||||||
.peer_list {
|
|
||||||
margin-bottom: 7rem !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-manage-group {
|
|
||||||
z-index: 99;
|
|
||||||
position: fixed;
|
|
||||||
bottom: 3rem;
|
|
||||||
right: 2rem;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-manage-group .setting_btn_menu {
|
|
||||||
position: absolute;
|
|
||||||
top: -124px;
|
|
||||||
background-color: white;
|
|
||||||
padding: 1rem 0;
|
|
||||||
right: 0;
|
|
||||||
box-shadow: 0 10px 20px rgb(0 0 0 / 19%), 0 6px 6px rgb(0 0 0 / 23%);
|
|
||||||
border-radius: 10px;
|
|
||||||
min-width: 250px;
|
|
||||||
display: none;
|
|
||||||
transform: translateY(-30px);
|
|
||||||
opacity: 0;
|
|
||||||
transition: all 0.3s cubic-bezier(0.58, 0.03, 0.05, 1.28);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-manage-group .setting_btn_menu.show {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting_btn_menu.showing {
|
|
||||||
transform: translateY(0px);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting_btn_menu a {
|
|
||||||
display: flex;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
transition: all 0.1s ease-in-out;
|
|
||||||
font-size: 1rem;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting_btn_menu a:hover {
|
|
||||||
background-color: #efefef;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting_btn_menu a i {
|
|
||||||
margin-right: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add_btn {
|
|
||||||
height: 54px;
|
|
||||||
z-index: 99;
|
|
||||||
border-radius: 100px !important;
|
|
||||||
padding: 0 14px;
|
|
||||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
|
|
||||||
margin-right: 1rem;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting_btn {
|
|
||||||
height: 54px;
|
|
||||||
z-index: 99;
|
|
||||||
border-radius: 100px !important;
|
|
||||||
padding: 0 14px;
|
|
||||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes rotating
|
|
||||||
/* Safari and Chrome */
|
|
||||||
|
|
||||||
{
|
|
||||||
from {
|
|
||||||
-webkit-transform: rotate(0deg);
|
|
||||||
-o-transform: rotate(0deg);
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
-webkit-transform: rotate(360deg);
|
|
||||||
-o-transform: rotate(360deg);
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotating {
|
|
||||||
from {
|
|
||||||
-ms-transform: rotate(0deg);
|
|
||||||
-moz-transform: rotate(0deg);
|
|
||||||
-webkit-transform: rotate(0deg);
|
|
||||||
-o-transform: rotate(0deg);
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
-ms-transform: rotate(360deg);
|
|
||||||
-moz-transform: rotate(360deg);
|
|
||||||
-webkit-transform: rotate(360deg);
|
|
||||||
-o-transform: rotate(360deg);
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.rotating::before {
|
|
||||||
-webkit-animation: rotating 0.75s linear infinite;
|
|
||||||
-moz-animation: rotating 0.75s linear infinite;
|
|
||||||
-ms-animation: rotating 0.75s linear infinite;
|
|
||||||
-o-animation: rotating 0.75s linear infinite;
|
|
||||||
animation: rotating 0.75s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peer_private_key_textbox_switch {
|
|
||||||
position: absolute;
|
|
||||||
right: 2rem;
|
|
||||||
transform: translateY(-28px);
|
|
||||||
font-size: 1.2rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#peer_private_key_textbox,
|
|
||||||
#private_key,
|
|
||||||
#public_key,
|
|
||||||
#peer_preshared_key_textbox {
|
|
||||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar {
|
|
||||||
transition: 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.key {
|
|
||||||
transition: 0.2s ease-in-out;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.key:hover {
|
|
||||||
color: #007bff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peer_list .card .button-group {
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
border-radius: 8px;
|
|
||||||
/*padding: 0.6rem 0.9em;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-box #username,
|
|
||||||
.login-box #password {
|
|
||||||
padding: 0.6rem calc( 0.9rem + 32px);
|
|
||||||
height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-box label[for="username"],
|
|
||||||
.login-box label[for="password"] {
|
|
||||||
font-size: 1rem;
|
|
||||||
margin: 0 !important;
|
|
||||||
transform: translateY(2.1rem) translateX(1rem);
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*label[for="password"]{*/
|
|
||||||
|
|
||||||
|
|
||||||
/* transform: translateY(32px) translateX(16px);*/
|
|
||||||
|
|
||||||
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip-inner {
|
|
||||||
font-size: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes loading {
|
|
||||||
0% {
|
|
||||||
background-color: #dfdfdf;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
background-color: #adadad;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background-color: #dfdfdf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-moz-keyframes loading {
|
|
||||||
0% {
|
|
||||||
background-color: #dfdfdf;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
background-color: #adadad;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background-color: #dfdfdf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.conf_card {
|
|
||||||
transition: 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conf_card:hover {
|
|
||||||
border-color: #007bff;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info_loading {
|
|
||||||
/* animation: loading 2s infinite ease-in-out;
|
|
||||||
/* border-radius: 5px; */
|
|
||||||
height: 19.19px;
|
|
||||||
/* transition: 0.3s ease-in-out; */
|
|
||||||
|
|
||||||
/* transform: translateX(40px); */
|
|
||||||
opacity: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#conf_status_btn {
|
|
||||||
transition: 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#conf_status_btn.info_loading {
|
|
||||||
height: 38px;
|
|
||||||
border-radius: 5px;
|
|
||||||
animation: loading 3s infinite ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#qrcode_img img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#selected_ip_list .badge,
|
|
||||||
#selected_peer_list .badge {
|
|
||||||
margin: 0.1rem
|
|
||||||
}
|
|
||||||
|
|
||||||
#add_modal.ip_modal_open {
|
|
||||||
transition: filter 0.2s ease-in-out;
|
|
||||||
filter: brightness(0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#delete_bulk_modal .list-group a.active {
|
|
||||||
background-color: #dc3545;
|
|
||||||
border-color: #dc3545;
|
|
||||||
}
|
|
||||||
|
|
||||||
#selected_peer_list {
|
|
||||||
max-height: 80px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-response {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
position: fixed;
|
|
||||||
background: #000000ba;
|
|
||||||
z-index: 10000;
|
|
||||||
display: none;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
opacity: 0;
|
|
||||||
transition: all 1s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-response.active {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-response.active.show {
|
|
||||||
opacity: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-response .container>* {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-responding {
|
|
||||||
transition: all 1s ease-in-out;
|
|
||||||
filter: blur(10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
pre.index-alert {
|
|
||||||
margin-bottom: 0;
|
|
||||||
padding: 1rem;
|
|
||||||
background-color: #343a40;
|
|
||||||
border: 1px solid rgba(0, 0, 0, .125);
|
|
||||||
border-radius: .25rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peerNameCol {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 0.2rem
|
|
||||||
}
|
|
||||||
|
|
||||||
.peerName {
|
|
||||||
margin: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peerLightContainer {
|
|
||||||
text-transform: uppercase;
|
|
||||||
margin: 0;
|
|
||||||
margin-left: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conf_card .dot,
|
|
||||||
.info .dot {
|
|
||||||
transform: translateX(10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
#config_body {
|
|
||||||
transition: 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#config_body.firstLoading {
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chartTitle {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chartControl {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chartTitle h6 {
|
|
||||||
margin-bottom: 0;
|
|
||||||
line-height: 1;
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chartContainer.fullScreen {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 9999;
|
|
||||||
background-color: white;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: calc( 100% + 15px);
|
|
||||||
height: 100%;
|
|
||||||
padding: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chartContainer.fullScreen .col-sm {
|
|
||||||
padding-right: 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chartContainer.fullScreen .chartCanvasContainer {
|
|
||||||
width: 100%;
|
|
||||||
height: calc( 100% - 47px) !important;
|
|
||||||
max-height: calc( 100% - 47px) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#switch{
|
|
||||||
transition: all 200ms ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle--switch{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggleLabel{
|
|
||||||
width: 64px;
|
|
||||||
height: 32px;
|
|
||||||
background-color: #6c757d17;
|
|
||||||
display: flex;
|
|
||||||
position: relative;
|
|
||||||
border: 2px solid #6c757d8c;
|
|
||||||
border-radius: 100px;
|
|
||||||
transition: all 200ms ease-in;
|
|
||||||
cursor: pointer;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle--switch.waiting + .toggleLabel{
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggleLabel::before{
|
|
||||||
background-color: #6c757d;
|
|
||||||
height: 26px;
|
|
||||||
width: 26px;
|
|
||||||
content: "";
|
|
||||||
border-radius: 100px;
|
|
||||||
margin: 1px;
|
|
||||||
position: absolute;
|
|
||||||
animation-name: off;
|
|
||||||
animation-duration: 350ms;
|
|
||||||
animation-fill-mode: forwards;
|
|
||||||
transition: all 200ms ease-in;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggleLabel:hover::before{
|
|
||||||
filter: brightness(1.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.toggle--switch:checked + .toggleLabel{
|
|
||||||
background-color: #007bff17 !important;
|
|
||||||
border: 2px solid #007bff8c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle--switch:checked + .toggleLabel::before{
|
|
||||||
background-color: #007bff;
|
|
||||||
animation-name: on;
|
|
||||||
animation-duration: 350ms;
|
|
||||||
animation-fill-mode: forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes on {
|
|
||||||
0%{
|
|
||||||
left: 0px;
|
|
||||||
}
|
|
||||||
60%{
|
|
||||||
left: 0px;
|
|
||||||
width: 40px;
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
left: 32px;
|
|
||||||
width: 26px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes off {
|
|
||||||
0%{
|
|
||||||
left: 32px;
|
|
||||||
}
|
|
||||||
60%{
|
|
||||||
left: 18px;
|
|
||||||
width: 40px;
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
left: 0px;
|
|
||||||
width: 26px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.toastContainer{
|
|
||||||
z-index: 99999 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toast{
|
|
||||||
min-width: 300px;
|
|
||||||
background-color: rgba(255,255,255,1);
|
|
||||||
z-index: 99999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toast-header{
|
|
||||||
background-color: rgba(255,255,255);
|
|
||||||
}
|
|
||||||
|
|
||||||
.toast-progressbar{
|
|
||||||
width: 100%;
|
|
||||||
height: 4px;
|
|
||||||
background-color: #007bff;
|
|
||||||
border-bottom-left-radius: .25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.addConfigurationAvailableIPs{
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-feedback{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#addConfigurationModal label{
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#addConfigurationModal label a{
|
|
||||||
margin-left: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#reGeneratePrivateKey{
|
|
||||||
border-top-right-radius: 10px;
|
|
||||||
border-bottom-right-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.addConfigurationToggleStatus.waiting{
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*.conf_card .card-body .row .card-col{*/
|
|
||||||
/* margin-bottom: 0.5rem;*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
.peerDataUsageChartContainer{
|
|
||||||
min-height: 50vh;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peerDataUsageChartControl{
|
|
||||||
display: block !important;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peerDataUsageChartControl .switchUnit{
|
|
||||||
width: 33.3%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peerDataUsageChartControl .switchTimePeriod{
|
|
||||||
width: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1200px){
|
|
||||||
#peerDataUsage .modal-xl {
|
|
||||||
max-width: 95vw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 768px){
|
|
||||||
.bottom{
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-manage-group{
|
|
||||||
bottom: calc( 3rem + 40px + env(safe-area-inset-bottom, 5px));
|
|
||||||
}
|
|
||||||
|
|
||||||
main{
|
|
||||||
padding-bottom: calc( 3rem + 40px + env(safe-area-inset-bottom, 5px));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.bottomNavContainer{
|
|
||||||
display: flex;
|
|
||||||
color: #333;
|
|
||||||
padding-bottom: env(safe-area-inset-bottom, 5px);
|
|
||||||
box-shadow: inset 0 1px 0 rgb(0 0 0 / 10%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottomNavButton{
|
|
||||||
width: 25vw;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
margin: 0.7rem 0;
|
|
||||||
color: rgba(51, 51, 51, 0.5);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all ease-in 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottomNavButton.active{
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottomNavButton i{
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottomNavButton .subNav{
|
|
||||||
width: 100vw;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 10000;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background-color: #272b30;
|
|
||||||
display: none;
|
|
||||||
animation-duration: 400ms;
|
|
||||||
padding-bottom: env(safe-area-inset-bottom, 5px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottomNavButton .subNav.active{
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.bottomNavButton .subNav .nav .nav-item .nav-link{
|
|
||||||
padding: 0.7rem 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottomNavWrapper{
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #000000a1;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 1030;
|
|
||||||
display: none;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottomNavWrapper.active{
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sb-update-url .dot-running{
|
|
||||||
transform: translateX(10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-group-item{
|
|
||||||
transition: all 0.1s ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-switch-btn{
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-item.disabled, .dropdown-item:disabled{
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
@ -476,8 +476,9 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div class="row gx-2 gy-2 mb-3">
|
<div class="row gx-2 gy-2 mb-3">
|
||||||
<div class="col-12 col-lg-6">
|
<div class="col-12 col-lg-6">
|
||||||
<div class="card rounded-3 bg-transparent shadow-sm" style="height: 270px">
|
<div class="card rounded-3 bg-transparent shadow-sm" style="height: 270px">
|
||||||
<div class="card-header bg-transparent border-0"><small class="text-muted">Peers Total Data Usage</small></div>
|
<div class="card-header bg-transparent border-0">
|
||||||
|
<small class="text-muted">Peers Total Data Usage</small></div>
|
||||||
<div class="card-body pt-1">
|
<div class="card-body pt-1">
|
||||||
<Bar
|
<Bar
|
||||||
:data="individualDataUsage"
|
:data="individualDataUsage"
|
||||||
@ -515,7 +516,7 @@ export default {
|
|||||||
<!-- <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>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<PeerSearch></PeerSearch>
|
<PeerSearch :configuration="this.configurationInfo"></PeerSearch>
|
||||||
<TransitionGroup name="list" tag="div" class="row gx-2 gy-2 z-0">
|
<TransitionGroup name="list" tag="div" class="row gx-2 gy-2 z-0">
|
||||||
<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"
|
||||||
@ -553,25 +554,5 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-move, /* apply transition to moving elements */
|
|
||||||
.list-enter-active,
|
|
||||||
.list-leave-active {
|
|
||||||
transition: all 0.4s cubic-bezier(0.82, 0.58, 0.17, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-leave-active{
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-enter-from,
|
|
||||||
.list-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(30px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ensure leaving items are taken out of layout flow so that moving
|
|
||||||
animations can be calculated correctly. */
|
|
||||||
.list-leave-active {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -1,8 +1,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||||
import {fetchPost} from "@/utilities/fetch.js";
|
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
|
||||||
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
|
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "peerSearch",
|
name: "peerSearch",
|
||||||
setup(){
|
setup(){
|
||||||
@ -11,7 +12,8 @@ export default {
|
|||||||
return {store, wireguardConfigurationStore}
|
return {store, wireguardConfigurationStore}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
searchString: String
|
searchString: String,
|
||||||
|
configuration: Object
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
@ -51,6 +53,12 @@ export default {
|
|||||||
this.store.getConfiguration();
|
this.store.getConfiguration();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
downloadAllPeer(){
|
||||||
|
fetchGet(`/api/downloadAllPeers/${this.configuration.Name}`, {}, (res) => {
|
||||||
|
console.log(res);
|
||||||
|
window.wireguard.generateZipFiles(res, this.configuration.Name)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -62,13 +70,12 @@ export default {
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="d-flex gap-2 mb-3 z-3">
|
<div class="d-flex gap-2 mb-3 z-3">
|
||||||
<!-- <h4 class="mb-0">Peers</h4>-->
|
|
||||||
<RouterLink
|
<RouterLink
|
||||||
to="create"
|
to="create"
|
||||||
class="text-decoration-none btn btn-primary rounded-3 btn-sm">
|
class="text-decoration-none btn btn-primary rounded-3 btn-sm">
|
||||||
<i class="bi bi-plus-lg me-2"></i>Peers
|
<i class="bi bi-plus-lg me-2"></i>Peers
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
<button class="btn btn-sm btn-info rounded-3">
|
<button class="btn btn-sm btn-info rounded-3" @click="this.downloadAllPeer()">
|
||||||
<i class="bi bi-download me-2"></i> Download All
|
<i class="bi bi-download me-2"></i> Download All
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export default {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div class="mt-4">
|
<div class="mt-5">
|
||||||
<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>
|
||||||
@ -39,7 +39,6 @@ export default {
|
|||||||
<p class="text-muted" v-if="this.wireguardConfigurationsStore.Configurations.length === 0">
|
<p class="text-muted" v-if="this.wireguardConfigurationsStore.Configurations.length === 0">
|
||||||
You don't have any WireGuard configurations yet. Please check the configuration folder or change it in "Settings". By default the folder is "/etc/wireguard".
|
You don't have any WireGuard configurations yet. Please check the configuration folder or change it in "Settings". By default the folder is "/etc/wireguard".
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="d-flex gap-3 flex-column" v-else>
|
<div class="d-flex gap-3 flex-column" v-else>
|
||||||
<ConfigurationCard v-for="c in this.wireguardConfigurationsStore.Configurations" :key="c.Name" :c="c"></ConfigurationCard>
|
<ConfigurationCard v-for="c in this.wireguardConfigurationsStore.Configurations" :key="c.Name" :c="c"></ConfigurationCard>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,7 +21,8 @@ export default {
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<RouterLink class="nav-link" to="/" exact-active-class="active">Home</RouterLink></li>
|
<RouterLink class="nav-link" to="/" exact-active-class="active">Home</RouterLink></li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<RouterLink class="nav-link" to="/settings" exact-active-class="active">Settings</RouterLink></li>
|
<RouterLink class="nav-link" to="/settings"
|
||||||
|
exact-active-class="active">Settings</RouterLink></li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr>
|
<hr>
|
||||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||||
@ -29,7 +30,9 @@ export default {
|
|||||||
</h6>
|
</h6>
|
||||||
<ul class="nav flex-column">
|
<ul class="nav flex-column">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<RouterLink :to="'/configuration/'+c.Name + '/peers'" class="nav-link nav-conf-link"
|
<RouterLink :to="'/configuration/'+c.Name + '/peers'" class="nav-link nav-conf-link"
|
||||||
|
active-class="active"
|
||||||
|
|
||||||
v-for="c in this.wireguardConfigurationsStore.Configurations">
|
v-for="c in this.wireguardConfigurationsStore.Configurations">
|
||||||
<samp>{{c.Name}}</samp>
|
<samp>{{c.Name}}</samp>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
@ -40,7 +43,8 @@ export default {
|
|||||||
<span>Tools</span>
|
<span>Tools</span>
|
||||||
</h6>
|
</h6>
|
||||||
<ul class="nav flex-column">
|
<ul class="nav flex-column">
|
||||||
<li class="nav-item"><a class="nav-link" data-toggle="modal" data-target="#ping_modal" href="#">Ping</a></li>
|
<li class="nav-item">
|
||||||
|
<RouterLink to="/ping" class="nav-link">Ping</RouterLink></li>
|
||||||
<li class="nav-item"><a class="nav-link" data-toggle="modal" data-target="#traceroute_modal" href="#">Traceroute</a></li>
|
<li class="nav-item"><a class="nav-link" data-toggle="modal" data-target="#traceroute_modal" href="#">Traceroute</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -15,6 +15,7 @@ import PeerSettings from "@/components/configurationComponents/peerSettings.vue"
|
|||||||
import PeerList from "@/components/configurationComponents/peerList.vue";
|
import PeerList from "@/components/configurationComponents/peerList.vue";
|
||||||
import PeerCreate from "@/components/configurationComponents/peerCreate.vue";
|
import PeerCreate from "@/components/configurationComponents/peerCreate.vue";
|
||||||
import RestrictedPeers from "@/components/configurationComponents/restrictedPeers.vue";
|
import RestrictedPeers from "@/components/configurationComponents/restrictedPeers.vue";
|
||||||
|
import Ping from "@/views/ping.vue";
|
||||||
|
|
||||||
const checkAuth = async () => {
|
const checkAuth = async () => {
|
||||||
let result = false
|
let result = false
|
||||||
@ -33,7 +34,6 @@ const router = createRouter({
|
|||||||
component: Index,
|
component: Index,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
|
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -52,6 +52,11 @@ const router = createRouter({
|
|||||||
title: "Settings"
|
title: "Settings"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/ping',
|
||||||
|
name: "Ping",
|
||||||
|
component: Ping,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "New Configuration",
|
name: "New Configuration",
|
||||||
path: '/new_configuration',
|
path: '/new_configuration',
|
||||||
|
@ -230,8 +230,8 @@
|
|||||||
var offset = 0;
|
var offset = 0;
|
||||||
|
|
||||||
for (var i = 0; i < files.length; ++i) {
|
for (var i = 0; i < files.length; ++i) {
|
||||||
var name = encodeString(files[i].filename);
|
var name = encodeString(files[i].fileName);
|
||||||
var contents = encodeString(files[i].content);
|
var contents = encodeString(files[i].file);
|
||||||
var crc = crc32(contents);
|
var crc = crc32(contents);
|
||||||
|
|
||||||
putU32(b, 0x04034b50); /* signature */
|
putU32(b, 0x04034b50); /* signature */
|
||||||
@ -297,12 +297,12 @@
|
|||||||
return keyToBase64(generatePublicKey(privateKey));
|
return keyToBase64(generatePublicKey(privateKey));
|
||||||
},
|
},
|
||||||
|
|
||||||
generateZipFiles: function(res){
|
generateZipFiles: function(res, zipFileName){
|
||||||
var files = res.peers;
|
var files = res.data;
|
||||||
var zipFile = createZipFile(files);
|
var zipFile = createZipFile(files);
|
||||||
var blob = new Blob([zipFile], { type: "application/zip" });
|
var blob = new Blob([zipFile], { type: "application/zip" });
|
||||||
var a = document.createElement("a");
|
var a = document.createElement("a");
|
||||||
a.download = res.filename;
|
a.download = zipFileName;
|
||||||
a.href = URL.createObjectURL(blob);
|
a.href = URL.createObjectURL(blob);
|
||||||
a.style.display = "none";
|
a.style.display = "none";
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
|
197
src/static/app/src/views/ping.vue
Normal file
197
src/static/app/src/views/ping.vue
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
<script>
|
||||||
|
import {fetchGet} from "@/utilities/fetch.js";
|
||||||
|
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ping",
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
cips: {},
|
||||||
|
selectedConfiguration: undefined,
|
||||||
|
selectedPeer: undefined,
|
||||||
|
selectedIp: undefined,
|
||||||
|
count: 4,
|
||||||
|
pingResult: undefined,
|
||||||
|
pinging: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(){
|
||||||
|
const store = DashboardConfigurationStore();
|
||||||
|
return {store}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
fetchGet("/api/ping/getAllPeersIpAddress", {}, (res)=> {
|
||||||
|
if (res.status){
|
||||||
|
this.loading = true;
|
||||||
|
this.cips = res.data;
|
||||||
|
console.log(this.cips)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
execute(){
|
||||||
|
if (this.selectedIp){
|
||||||
|
this.pinging = true;
|
||||||
|
this.pingResult = undefined
|
||||||
|
fetchGet("/api/ping/execute", {
|
||||||
|
ipAddress: this.selectedIp,
|
||||||
|
count: this.count
|
||||||
|
}, (res) => {
|
||||||
|
if (res.status){
|
||||||
|
this.pingResult = res.data
|
||||||
|
}else{
|
||||||
|
this.store.newMessage("Server", res.message, "danger")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
{} }
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selectedConfiguration(){
|
||||||
|
this.selectedPeer = undefined;
|
||||||
|
this.selectedIp = undefined;
|
||||||
|
},
|
||||||
|
selectedPeer(){
|
||||||
|
this.selectedIp = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="mt-5 text-body">
|
||||||
|
<div class="container">
|
||||||
|
<h3 class="mb-3 text-body">Ping</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-4 d-flex gap-2 flex-column">
|
||||||
|
<div>
|
||||||
|
<label class="mb-1 text-muted" for="configuration">
|
||||||
|
<small>Configuration</small></label>
|
||||||
|
<select class="form-select" v-model="this.selectedConfiguration">
|
||||||
|
<option disabled selected :value="undefined">Select a Configuration...</option>
|
||||||
|
<option :value="key" v-for="(val, key) in this.cips">
|
||||||
|
{{key}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="mb-1 text-muted" for="peer">
|
||||||
|
<small>Peer</small></label>
|
||||||
|
<select id="peer" class="form-select" v-model="this.selectedPeer" :disabled="this.selectedConfiguration === undefined">
|
||||||
|
<option disabled selected :value="undefined">Select a Peer...</option>
|
||||||
|
<option v-if="this.selectedConfiguration !== undefined" :value="key" v-for="(peer, key) in
|
||||||
|
this.cips[this.selectedConfiguration]">
|
||||||
|
{{key}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="mb-1 text-muted" for="ip">
|
||||||
|
<small>IP Address</small></label>
|
||||||
|
<select id="ip" class="form-select" v-model="this.selectedIp" :disabled="this.selectedPeer === undefined">
|
||||||
|
<option disabled selected :value="undefined">Select a IP...</option>
|
||||||
|
<option
|
||||||
|
v-if="this.selectedPeer !== undefined"
|
||||||
|
v-for="ip in this.cips[this.selectedConfiguration][this.selectedPeer].allowed_ips">
|
||||||
|
{{ip}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="mb-1 text-muted" for="count">
|
||||||
|
<small>Ping Count</small></label>
|
||||||
|
<input class="form-control" type="number"
|
||||||
|
v-model="this.count"
|
||||||
|
min="1" id="count" placeholder="How many times you want to ping?">
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary rounded-3 mt-3"
|
||||||
|
:disabled="!this.selectedIp"
|
||||||
|
@click="this.execute()">
|
||||||
|
<i class="bi bi-person-walking me-2"></i>Go!
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<TransitionGroup name="ping">
|
||||||
|
<div v-if="!this.pingResult" key="pingPlaceholder">
|
||||||
|
<div class="pingPlaceholder bg-dark rounded-3 mb-3"
|
||||||
|
:class="{'animate__animated animate__flash animate__slower animate__infinite': this.pinging}"
|
||||||
|
:style="{'animation-delay': `${x*0.15}s`}"
|
||||||
|
v-for="x in 4" ></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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-body">
|
||||||
|
<p class="mb-0 text-muted"><small>Address</small></p>
|
||||||
|
{{this.pingResult.address}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.3s">
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="mb-0 text-muted"><small>Is Alive</small></p>
|
||||||
|
<span :class="[this.pingResult.is_alive ? 'text-success':'text-danger']">
|
||||||
|
<i class="bi me-1"
|
||||||
|
:class="[this.pingResult.is_alive ? 'bi-check-circle-fill' : 'bi-x-circle-fill']"></i>
|
||||||
|
{{this.pingResult.is_alive ? "Yes": "No"}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.45s">
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="mb-0 text-muted"><small>Average / Min / Max Round Trip Time</small></p>
|
||||||
|
<samp>{{this.pingResult.avg_rtt}}ms /
|
||||||
|
{{this.pingResult.min_rtt}}ms /
|
||||||
|
{{this.pingResult.max_rtt}}ms
|
||||||
|
</samp>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card rounded-3 bg-transparent shadow-sm animate__animated animate__fadeIn" style="animation-delay: 0.6s">
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="mb-0 text-muted"><small>Sent / Received / Lost Package</small></p>
|
||||||
|
<samp>{{this.pingResult.package_sent}} /
|
||||||
|
{{this.pingResult.package_received}} /
|
||||||
|
{{this.pingResult.package_loss}}
|
||||||
|
</samp>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</TransitionGroup>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.pingPlaceholder{
|
||||||
|
width: 100%;
|
||||||
|
height: 79.98px;
|
||||||
|
}
|
||||||
|
.ping-move, /* apply transition to moving elements */
|
||||||
|
.ping-enter-active,
|
||||||
|
.ping-leave-active {
|
||||||
|
transition: all 0.4s cubic-bezier(0.82, 0.58, 0.17, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ping-leave-active{
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ping-enter-from,
|
||||||
|
.ping-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
//transform: scale(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ensure leaving items are taken out of layout flow so that moving
|
||||||
|
animations can be calculated correctly. */
|
||||||
|
.ping-leave-active {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
@ -35,7 +35,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mt-4">
|
<div class="mt-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h3 class="mb-3 text-body">Settings</h3>
|
<h3 class="mb-3 text-body">Settings</h3>
|
||||||
<DashboardTheme></DashboardTheme>
|
<DashboardTheme></DashboardTheme>
|
||||||
|
@ -1092,4 +1092,26 @@ pre.index-alert {
|
|||||||
.fade3-leave-to {
|
.fade3-leave-to {
|
||||||
transform: scale(0.8);
|
transform: scale(0.8);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-move, /* apply transition to moving elements */
|
||||||
|
.list-enter-active,
|
||||||
|
.list-leave-active {
|
||||||
|
transition: all 0.4s cubic-bezier(0.82, 0.58, 0.17, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-leave-active{
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-enter-from,
|
||||||
|
.list-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ensure leaving items are taken out of layout flow so that moving
|
||||||
|
animations can be calculated correctly. */
|
||||||
|
.list-leave-active {
|
||||||
|
position: absolute;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user