Updated indentation

This commit is contained in:
Eduardo Silva 2025-02-24 09:55:52 -03:00
parent 1a68ad1344
commit 15cb2f705a

View File

@ -1,29 +1,29 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
{% if wireguard_instances %} {% if wireguard_instances %}
<div class="card card-primary card-outline"> <div class="card card-primary card-outline">
<div class="card-body"> <div class="card-body">
<ul class="nav nav-tabs" role="tablist"> <ul class="nav nav-tabs" role="tablist">
{% for wgconf in wireguard_instances %} {% for wgconf in wireguard_instances %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if wgconf == current_instance %}active{% endif %}" href="/peer/list/?uuid={{ wgconf.uuid }}" role="tab"> <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 %} wg{{ wgconf.instance_id }} {% if wgconf.name %}({{ wgconf.name }}){% endif %}
</a> </a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
<div class="tab-content" id="custom-content-below-tabContent"> <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="tab-pane fade show active" id="custom-content-below-home" role="tabpanel" aria-labelledby="custom-content-below-home-tab">
<div class="row"> <div class="row">
{% for peer in peer_list %} {% for peer in peer_list %}
<div class="col-md-6" id="peer-{{ peer.public_key }}"> <div class="col-md-6" id="peer-{{ peer.public_key }}">
<div class="callout"> <div class="callout">
<div class="d-flex justify-content-between align-items-start"> <div class="d-flex justify-content-between align-items-start">
<h5><a href="#" onclick="openPeerModal('{{ peer.uuid }}');" style="text-decoration: none">{{ peer }}</a></h5> <h5><a href="#" onclick="openPeerModal('{{ peer.uuid }}');" style="text-decoration: none">{{ peer }}</a></h5>
<span> <span>
{% if user_acl.user_level >= 30 %} {% if user_acl.user_level >= 30 %}
<div class="d-inline-flex flex-column"> <div class="d-inline-flex flex-column">
<a href="/peer/sort/?peer={{ peer.uuid }}&direction=up" style="line-height:0px"> <a href="/peer/sort/?peer={{ peer.uuid }}&direction=up" style="line-height:0px">
<i class="fas fa-sort-up"></i> <i class="fas fa-sort-up"></i>
</a> </a>
@ -34,7 +34,7 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
<a href="javascript:void(0);" onclick="openImageLightbox('/tools/download_peer_config/?uuid={{ peer.uuid }}&format=qrcode');"> <a href="javascript:void(0);" onclick="openImageLightbox('/tools/download_peer_config/?uuid={{ peer.uuid }}&format=qrcode');">
<i class="fas fa-qrcode"></i> <i class="fas fa-qrcode"></i>
</a> </a>
<a href="/tools/download_peer_config/?uuid={{ peer.uuid }}"> <a href="/tools/download_peer_config/?uuid={{ peer.uuid }}">
@ -44,237 +44,234 @@
<i class="far fa-edit"></i> <i class="far fa-edit"></i>
</a> </a>
</span> </span>
</div> </div>
<p> <p>
<b>Transfer:</b> <span id="peer-transfer-{{ peer.public_key }}"></span><br> <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> <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 }}"> <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 %} {% if peer.peerstatus.last_handshake %}{{ peer.peerstatus.last_handshake|date:"U" }}{% else %}0{% endif %}
</span><br> </span><br>
<b>Endpoints:</b> <span id="peer-endpoints-{{ peer.public_key }}"></span><br> <b>Endpoints:</b> <span id="peer-endpoints-{{ peer.public_key }}"></span><br>
<b>Allowed IPs:</b> <b>Allowed IPs:</b>
<span id="peer-allowed-ips-{{ peer.public_key }}"> <span id="peer-allowed-ips-{{ peer.public_key }}">
{% for address in peer.peerallowedip_set.all %} {% for address in peer.peerallowedip_set.all %}
{% if address.priority == 0 and address.config_file == 'server' %} {% if address.priority == 0 and address.config_file == 'server' %}
{{ address }} {{ address }}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for address in peer.peerallowedip_set.all %} {% for address in peer.peerallowedip_set.all %}
{% if address.priority >= 1 and address.config_file == 'server' %} {% if address.priority >= 1 and address.config_file == 'server' %}
{{ address }} {{ address }}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</span> </span>
</p> </p>
</div>
</div>
{% endfor %}
</div> </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 %}
</div> </div>
{% endfor %}
</div> </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 %}
</div> </div>
</div> </div>
</div>
</div>
<!-- Peer Preview Modal --> <!-- Peer Preview Modal -->
<div class="modal fade" id="peerPreviewModal" tabindex="-1" aria-labelledby="peerPreviewModalLabel" aria-hidden="true"> <div class="modal fade" id="peerPreviewModal" tabindex="-1" aria-labelledby="peerPreviewModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg"> <div class="modal-dialog modal-lg">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="peerPreviewModalLabel">Peer Preview</h5> <h5 class="modal-title" id="peerPreviewModalLabel">Peer Preview</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<!-- Peer Information --> <!-- Peer Information -->
<h3 id="peerName">Peer Name Placeholder</h3> <h3 id="peerName">Peer Name Placeholder</h3>
<p><b>Transfer:</b> <span id="peerTransfer">--</span></p> <p><b>Transfer:</b> <span id="peerTransfer">--</span></p>
<p><b>Latest Handshake:</b> <span id="peerHandshake">--</span></p> <p><b>Latest Handshake:</b> <span id="peerHandshake">--</span></p>
<p><b>Endpoints:</b> <span id="peerEndpoints">--</span></p> <p><b>Endpoints:</b> <span id="peerEndpoints">--</span></p>
<p><b>Allowed IPs:</b> <span id="peerAllowedIPs">--</span></p> <p><b>Allowed IPs:</b> <span id="peerAllowedIPs">--</span></p>
<!-- Consumption graph placeholder --> <!-- Consumption graph placeholder -->
<div> <div>
<canvas id="peerGraph" width="400" height="200"></canvas> <canvas id="peerGraph" width="400" height="200"></canvas>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<a href="#" class="btn btn-primary" id="editPeerButton">Edit</a> <a href="#" class="btn btn-primary" id="editPeerButton">Edit</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% else %} {% else %}
<div class="alert alert-warning" role="alert"> <div class="alert alert-warning" role="alert">
<h4 class="alert-heading">No WireGuard Instances Found</h4> <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> <p>There are no WireGuard instances configured. You can add a new instance by clicking the button below.</p>
</div> </div>
<p> <p>
<a href="/server/manage/" class="btn btn-primary">Add WireGuard Instance</a> <a href="/server/manage/" class="btn btn-primary">Add WireGuard Instance</a>
</p> </p>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block custom_page_scripts %} {% block custom_page_scripts %}
<script> <script>
// Function to open the peer preview modal and fetch its details // Function to open the peer preview modal and fetch its details
function openPeerModal(uuid) { function openPeerModal(uuid) {
$.ajax({ $.ajax({
url: '/api/peer_info/', url: '/api/peer_info/',
data: { uuid: uuid }, data: { uuid: uuid },
type: 'GET', type: 'GET',
dataType: 'json', dataType: 'json',
success: function(data) { success: function(data) {
// Update modal placeholders with fetched data // Update modal placeholders with fetched data
$('#peerName').text(data.name || 'Unnamed Peer'); $('#peerName').text(data.name || 'Unnamed Peer');
if (data.transfer) { if (data.transfer) {
$('#peerTransfer').text(convertBytes(data.transfer.tx) + ' TX, ' + convertBytes(data.transfer.rx) + ' RX'); $('#peerTransfer').text(convertBytes(data.transfer.tx) + ' TX, ' + convertBytes(data.transfer.rx) + ' RX');
} else { } else {
$('#peerTransfer').text('--'); $('#peerTransfer').text('--');
}
$('#peerHandshake').text(data.latest_handshake ? new Date(parseInt(data.latest_handshake) * 1000).toLocaleString() : '--');
$('#peerEndpoints').text(data.endpoints || '--');
$('#peerAllowedIPs').text(data.allowed_ips || '--');
// Update the Edit button URL
$('#editPeerButton').attr('href', '/peer/manage/?peer=' + uuid);
// Open the modal
$('#peerPreviewModal').modal('show');
},
error: function(xhr, status, error) {
console.error("Error fetching peer info:", error);
} }
$('#peerHandshake').text(data.latest_handshake ? new Date(parseInt(data.latest_handshake) * 1000).toLocaleString() : '--'); });
$('#peerEndpoints').text(data.endpoints || '--'); }
$('#peerAllowedIPs').text(data.allowed_ips || '--'); </script>
// Update the Edit button URL <script>
$('#editPeerButton').attr('href', '/peer/manage/?peer=' + uuid); 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();
// Open the modal // if latest-handshakes is 0, use the stored value
$('#peerPreviewModal').modal('show'); for (const [interfaceName, peers] of Object.entries(data)) {
}, for (const [peerId, peerInfo] of Object.entries(peers)) {
error: function(xhr, status, error) { const peerElementId = `peer-stored-latest-handshake-${peerId}`;
console.error("Error fetching peer info:", error); const storedHandshakeElement = document.getElementById(peerElementId);
} if (peerInfo['latest-handshakes'] === '0' && storedHandshakeElement) {
}); peerInfo['latest-handshakes'] = storedHandshakeElement.textContent;
} }
</script>
<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); updateUI(data);
} catch (error) { } catch (error) {
console.error('Error fetching Wireguard status:', 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']);
}
}
} }
}; };
fetchWireguardStatus(); const updatePeerInfo = (peerDiv, peerId, peerInfo) => {
setInterval(fetchWireguardStatus, {{ current_instance.peer_list_refresh_interval }} * 1000); 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}`);
const updateUI = (data) => { transfer.textContent = `${convertBytes(peerInfo.transfer.tx)} TX, ${convertBytes(peerInfo.transfer.rx)} RX`;
for (const [interfaceName, peers] of Object.entries(data)) { latestHandshake.textContent = `${peerInfo['latest-handshakes'] !== '0' ? new Date(parseInt(peerInfo['latest-handshakes']) * 1000).toLocaleString() : '0'}`;
for (const [peerId, peerInfo] of Object.entries(peers)) { endpoints.textContent = `${peerInfo.endpoints}`;
const peerDiv = document.getElementById(`peer-${peerId}`); checkAllowedIps(allowedIps, peerInfo['allowed-ips']);
if (peerDiv) { };
updatePeerInfo(peerDiv, peerId, peerInfo);
updateCalloutClass(peerDiv, peerInfo['latest-handshakes']); 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.';
} }
}
}
};
const updatePeerInfo = (peerDiv, peerId, peerInfo) => { if (index < array.length - 1) {
const escapedPeerId = peerId.replace(/([!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g, '\\$1'); allowedIpsElement.appendChild(document.createTextNode(', '));
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`; const updateCalloutClass = (peerDiv, latestHandshake) => {
latestHandshake.textContent = `${peerInfo['latest-handshakes'] !== '0' ? new Date(parseInt(peerInfo['latest-handshakes']) * 1000).toLocaleString() : '0'}`; const calloutDiv = peerDiv.querySelector('.callout');
endpoints.textContent = `${peerInfo.endpoints}`; calloutDiv.classList.remove('callout-success', 'callout-info', 'callout-warning', 'callout-danger');
checkAllowedIps(allowedIps, peerInfo['allowed-ips']); const handshakeAge = Date.now() / 1000 - parseInt(latestHandshake);
};
const convertBytes = (bytes) => { if (latestHandshake === '0') {
if (bytes === 0) return '0 Bytes'; calloutDiv.classList.add('callout-danger');
const k = 1024; } else if (handshakeAge < 600) {
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; calloutDiv.classList.add('callout-success');
const i = Math.floor(Math.log(bytes) / Math.log(k)); } else if (handshakeAge < 1800) {
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; calloutDiv.classList.add('callout-info');
}; } else if (handshakeAge < 21600) {
calloutDiv.classList.add('callout-warning');
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) { calloutDiv.style.transition = 'all 5s';
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>
<script> <script>
function openImageLightbox(url) { function openImageLightbox(url) {
window.open(url, 'Image', 'width=500,height=500,toolbar=0,location=0,menubar=0'); window.open(url, 'Image', 'width=500,height=500,toolbar=0,location=0,menubar=0');
} }
</script> </script>
{% endblock %} {% endblock %}