mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2025-04-17 07:55:12 +00:00
230 lines
11 KiB
HTML
230 lines
11 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block content %}
|
|
{% if wireguard_instances %}
|
|
<div class="card card-primary card-outline">
|
|
|
|
<div class="card-body">
|
|
<ul class="nav nav-tabs" role="tablist">
|
|
{% for wgconf in wireguard_instances %}
|
|
<li class="nav-item">
|
|
<a class="nav-link {%if wgconf == current_instance%}active{%endif%}" href="/peer/list/?uuid={{wgconf.uuid}}" role="tab" >
|
|
wg{{wgconf.instance_id}} {%if wgconf.name %}({{wgconf.name}}){%endif%}
|
|
</a>
|
|
</li>
|
|
{% endfor %}
|
|
|
|
</ul>
|
|
<div class="tab-content" id="custom-content-below-tabContent">
|
|
<div class="tab-pane fade show active" id="custom-content-below-home" role="tabpanel" aria-labelledby="custom-content-below-home-tab">
|
|
<div class="row">
|
|
{% for peer in peer_list %}
|
|
<div class="col-md-6" id="peer-{{ peer.public_key }}">
|
|
<div class="callout">
|
|
<div class="d-flex justify-content-between align-items-start">
|
|
<h5>
|
|
{% if peer.name %}
|
|
{{ peer.name}}
|
|
{% else %}
|
|
{{ peer.public_key|slice:":16" }}{% if peer.public_key|length > 16 %}...{% endif %}
|
|
{% endif %}
|
|
</h5>
|
|
<span>
|
|
{% if user_acl.user_level >= 30 %}
|
|
<div class="d-inline-flex flex-column">
|
|
<a href="/peer/sort/?peer={{ peer.uuid }}&direction=up" style="line-height:0px"><i class="fas fa-sort-up"></i></a>
|
|
<div style="overflow:hidden;margin-top: -9px">
|
|
<a href="/peer/sort/?peer={{ peer.uuid }}&direction=down" style="position:relative;top:-11px"><i class="fas fa-sort-down"></i></a>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
<a href="javascript:void(0);" onclick="openImageLightbox('/tools/download_peer_config/?uuid={{ peer.uuid }}&format=qrcode');"><i class="fas fa-qrcode"></i></a>
|
|
<a href="/tools/download_peer_config/?uuid={{ peer.uuid }}"><i class="fas fa-download"></i></a>
|
|
<a href="/peer/manage/?peer={{ peer.uuid }}"><i class="far fa-edit"></i></a>
|
|
</span>
|
|
|
|
</div>
|
|
{% comment %}This needs to be improved{% endcomment %}
|
|
<p>
|
|
<b>Transfer:</b> <span id="peer-transfer-{{ peer.public_key }}"></span><br>
|
|
<b>Latest Handshake:</b> <span id="peer-latest-handshake-{{ peer.public_key }}"></span> <span style="display: none;" id="peer-stored-latest-handshake-{{ peer.public_key }}">{% if peer.peerstatus.last_handshake %}{{ peer.peerstatus.last_handshake|date:"U" }}{% else %}0{% endif %}</span><br>
|
|
<b>Endpoints:</b> <span id="peer-endpoints-{{ peer.public_key }}"></span><br>
|
|
<b>Allowed IPs: </b><span id="peer-allowed-ips-{{ peer.public_key }}">
|
|
{% for address in peer.peerallowedip_set.all %}
|
|
{% if address.priority == 0 and address.config_file == 'server' %}{{ address }}{% endif %}
|
|
{% endfor %}
|
|
{% for address in peer.peerallowedip_set.all %}
|
|
{% if address.priority >= 1 and address.config_file == 'server' %}{{ address }}{% endif %}
|
|
{% endfor %}
|
|
</span>
|
|
</p>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
{% endfor %}
|
|
|
|
</div>
|
|
|
|
{% if add_peer_enabled %}
|
|
<a class="btn btn-primary" href="/peer/manage/?instance={{ current_instance.uuid}}">Create Peer</a>
|
|
{% else %}
|
|
<a class="btn btn-primary disabled" href="">Create Peer</a>
|
|
{% endif %}
|
|
{% comment %}<a class="btn btn-outline-primary disabled" href="/peer/import_peers/?instance={{ current_instance.uuid}}" title='teste'>Import peers</a>{% endcomment %}
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<script>
|
|
function openCommandDialog(element) {
|
|
var command = element.getAttribute('data-command');
|
|
var confirmation = prompt("Please type 'delete wg{{ current_instance.instance_id }}' to remove the configuration.");
|
|
if (confirmation) {
|
|
var url = "?uuid={{current_instance.uuid}}&action=delete&confirmation=" + encodeURIComponent(confirmation);
|
|
window.location.href = url;
|
|
}
|
|
}
|
|
</script>
|
|
{% else %}
|
|
|
|
<div class="alert alert-warning" role="alert">
|
|
<h4 class="alert-heading">No WireGuard Instances Found</h4>
|
|
<p>There are no WireGuard instances configured. You can add a new instance by clicking the button below.</p>
|
|
</div>
|
|
<p>
|
|
<a href="/server/manage/" class="btn btn-primary">Add WireGuard Instance</a>
|
|
</p>
|
|
{% endif %}
|
|
|
|
|
|
|
|
{% endblock %}
|
|
|
|
|
|
{% block custom_page_scripts %}
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
//const fetchWireguardStatus = async () => {
|
|
// try {
|
|
// const response = await fetch('/api/wireguard_status/');
|
|
// const data = await response.json();
|
|
// updateUI(data);
|
|
// } catch (error) {
|
|
// console.error('Error fetching Wireguard status:', error);
|
|
// }
|
|
//};
|
|
const fetchWireguardStatus = async () => {
|
|
try {
|
|
const response = await fetch('/api/wireguard_status/');
|
|
let data = await response.json();
|
|
|
|
// if latest-handshakes is 0, use the stored value
|
|
for (const [interfaceName, peers] of Object.entries(data)) {
|
|
for (const [peerId, peerInfo] of Object.entries(peers)) {
|
|
const peerElementId = `peer-stored-latest-handshake-${peerId}`;
|
|
const storedHandshakeElement = document.getElementById(peerElementId);
|
|
if (peerInfo['latest-handshakes'] === '0' && storedHandshakeElement) {
|
|
peerInfo['latest-handshakes'] = storedHandshakeElement.textContent;
|
|
}
|
|
}
|
|
}
|
|
|
|
updateUI(data);
|
|
} catch (error) {
|
|
console.error('Error fetching Wireguard status:', error);
|
|
}
|
|
};
|
|
|
|
fetchWireguardStatus();
|
|
setInterval(fetchWireguardStatus, {{ current_instance.peer_list_refresh_interval }} * 1000);
|
|
});
|
|
|
|
const updateUI = (data) => {
|
|
for (const [interfaceName, peers] of Object.entries(data)) {
|
|
for (const [peerId, peerInfo] of Object.entries(peers)) {
|
|
const peerDiv = document.getElementById(`peer-${peerId}`);
|
|
if (peerDiv) {
|
|
updatePeerInfo(peerDiv, peerId, peerInfo);
|
|
updateCalloutClass(peerDiv, peerInfo['latest-handshakes']);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const updatePeerInfo = (peerDiv, peerId, peerInfo) => {
|
|
const escapedPeerId = peerId.replace(/([!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g, '\\$1');
|
|
const transfer = peerDiv.querySelector(`#peer-transfer-${escapedPeerId}`);
|
|
const latestHandshake = peerDiv.querySelector(`#peer-latest-handshake-${escapedPeerId}`);
|
|
const endpoints = peerDiv.querySelector(`#peer-endpoints-${escapedPeerId}`);
|
|
const allowedIps = peerDiv.querySelector(`#peer-allowed-ips-${escapedPeerId}`);
|
|
|
|
transfer.textContent = `${convertBytes(peerInfo.transfer.tx)} TX, ${convertBytes(peerInfo.transfer.rx)} RX`;
|
|
latestHandshake.textContent = `${peerInfo['latest-handshakes'] !== '0' ? new Date(parseInt(peerInfo['latest-handshakes']) * 1000).toLocaleString() : '0'}`;
|
|
endpoints.textContent = `${peerInfo.endpoints}`;
|
|
checkAllowedIps(allowedIps, peerInfo['allowed-ips']);
|
|
};
|
|
|
|
const convertBytes = (bytes) => {
|
|
if (bytes === 0) return '0 Bytes';
|
|
const k = 1024;
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
};
|
|
|
|
const checkAllowedIps = (allowedIpsElement, allowedIpsApiResponse) => {
|
|
const apiIps = allowedIpsApiResponse[0].split(' ');
|
|
const htmlIpsText = allowedIpsElement.textContent.trim();
|
|
const htmlIpsArray = htmlIpsText.match(/\b(?:\d{1,3}\.){3}\d{1,3}\/\d{1,2}\b/g);
|
|
|
|
allowedIpsElement.innerHTML = '';
|
|
htmlIpsArray.forEach((ip, index, array) => {
|
|
const ipSpan = document.createElement('span');
|
|
ipSpan.textContent = ip;
|
|
allowedIpsElement.appendChild(ipSpan);
|
|
|
|
if (!apiIps.includes(ip)) {
|
|
ipSpan.style.color = 'red';
|
|
ipSpan.style.textDecoration = 'underline';
|
|
ipSpan.title = 'This address does not appear in the wg show command output, likely indicating that another peer has an IP overlapping this network or that the configuration file is outdated.';
|
|
}
|
|
|
|
if (index < array.length - 1) {
|
|
allowedIpsElement.appendChild(document.createTextNode(', '));
|
|
}
|
|
});
|
|
};
|
|
|
|
const updateCalloutClass = (peerDiv, latestHandshake) => {
|
|
const calloutDiv = peerDiv.querySelector('.callout');
|
|
calloutDiv.classList.remove('callout-success', 'callout-info', 'callout-warning', 'callout-danger');
|
|
const handshakeAge = Date.now() / 1000 - parseInt(latestHandshake);
|
|
|
|
if (latestHandshake === '0') {
|
|
calloutDiv.classList.add('callout-danger');
|
|
} else if (handshakeAge < 600) {
|
|
calloutDiv.classList.add('callout-success');
|
|
} else if (handshakeAge < 1800) {
|
|
calloutDiv.classList.add('callout-info');
|
|
} else if (handshakeAge < 21600) {
|
|
calloutDiv.classList.add('callout-warning');
|
|
}
|
|
|
|
calloutDiv.style.transition = 'all 5s';
|
|
};
|
|
</script>
|
|
|
|
<script>
|
|
function openImageLightbox(url) {
|
|
window.open(url, 'Image', 'width=500,height=500,toolbar=0,location=0,menubar=0');
|
|
}
|
|
</script>
|
|
|
|
|
|
|
|
|
|
{% endblock %} |