Add peer info API endpoint and modal preview

This commit is contained in:
Eduardo Silva 2025-02-24 09:28:42 -03:00
parent d8c6bee57a
commit 1a68ad1344
3 changed files with 120 additions and 51 deletions

View file

@ -1,6 +1,8 @@
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib import auth
from django.http import JsonResponse
from django.core.exceptions import PermissionDenied
from django.http import JsonResponse, Http404
from django.shortcuts import get_object_or_404, redirect
from django.views.decorators.http import require_http_methods
from django.http import HttpResponseForbidden
@ -10,7 +12,7 @@ from django.utils import timezone
from user_manager.models import UserAcl, AuthenticationToken
from wireguard.models import WebadminSettings, Peer, PeerStatus, WireGuardInstance
from wgwadmlibrary.tools import user_allowed_peers
from wgwadmlibrary.tools import user_allowed_peers, user_has_access_to_peer
import requests
import subprocess
import datetime
@ -112,6 +114,22 @@ def routerfleet_get_user_token(request):
return JsonResponse(data)
@login_required
def peer_info(request):
peer = get_object_or_404(Peer, uuid=request.GET.get('uuid'))
user_acl = get_object_or_404(UserAcl, user=request.user)
if not user_has_access_to_peer(user_acl, peer):
raise PermissionDenied
data = {
'name': str(peer),
'public_key': str(peer.public_key),
'uuid': str(peer.uuid),
}
return JsonResponse(data)
@require_http_methods(["GET"])
def wireguard_status(request):
user_acl = None

View file

@ -3,17 +3,15 @@
{% 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 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">
@ -22,74 +20,96 @@
<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>
<h5><a href="#" onclick="openPeerModal('{{ peer.uuid }}');" style="text-decoration: none">{{ peer }}</a></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>
<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>
<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>
<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>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 }}">
<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 %}
{% 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 %}
{% 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>
<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 %}
<!-- Peer Preview Modal -->
<div class="modal fade" id="peerPreviewModal" tabindex="-1" aria-labelledby="peerPreviewModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="peerPreviewModalLabel">Peer Preview</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<!-- Peer Information -->
<h3 id="peerName">Peer Name Placeholder</h3>
<p><b>Transfer:</b> <span id="peerTransfer">--</span></p>
<p><b>Latest Handshake:</b> <span id="peerHandshake">--</span></p>
<p><b>Endpoints:</b> <span id="peerEndpoints">--</span></p>
<p><b>Allowed IPs:</b> <span id="peerAllowedIPs">--</span></p>
<!-- Consumption graph placeholder -->
<div>
<canvas id="peerGraph" width="400" height="200"></canvas>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<a href="#" class="btn btn-primary" id="editPeerButton">Edit</a>
</div>
</div>
</div>
</div>
{% 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>
@ -98,14 +118,44 @@
<a href="/server/manage/" class="btn btn-primary">Add WireGuard Instance</a>
</p>
{% endif %}
{% endblock %}
{% block custom_page_scripts %}
<script>
// Function to open the peer preview modal and fetch its details
function openPeerModal(uuid) {
$.ajax({
url: '/api/peer_info/',
data: { uuid: uuid },
type: 'GET',
dataType: 'json',
success: function(data) {
// Update modal placeholders with fetched data
$('#peerName').text(data.name || 'Unnamed Peer');
if (data.transfer) {
$('#peerTransfer').text(convertBytes(data.transfer.tx) + ' TX, ' + convertBytes(data.transfer.rx) + ' RX');
} else {
$('#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);
}
});
}
</script>
<script>
document.addEventListener('DOMContentLoaded', function() {
//const fetchWireguardStatus = async () => {

View file

@ -22,7 +22,7 @@ from console.views import view_console
from user_manager.views import view_user_list, view_manage_user, view_peer_group_list, view_peer_group_manage
from accounts.views import view_create_first_user, view_login, view_logout
from wireguard_tools.views import export_wireguard_configs, download_config_or_qrcode, restart_wireguard_interfaces
from api.views import wireguard_status, cron_check_updates, cron_update_peer_latest_handshake, routerfleet_get_user_token, routerfleet_authenticate_session
from api.views import wireguard_status, cron_check_updates, cron_update_peer_latest_handshake, routerfleet_get_user_token, routerfleet_authenticate_session, peer_info
from firewall.views import view_redirect_rule_list, manage_redirect_rule, view_firewall_rule_list, manage_firewall_rule, view_manage_firewall_settings, view_generate_iptables_script, view_reset_firewall, view_firewall_migration_required
from dns.views import view_static_host_list, view_manage_static_host, view_manage_dns_settings, view_apply_dns_config
from wgrrd.views import view_rrd_graph
@ -55,6 +55,7 @@ urlpatterns = [
path('accounts/routerfleet_authenticate_session/', routerfleet_authenticate_session, name='routerfleet_authenticate_session'),
path('api/routerfleet_get_user_token/', routerfleet_get_user_token, name='routerfleet_get_user_token'),
path('api/wireguard_status/', wireguard_status, name='api_wireguard_status'),
path('api/peer_info/', peer_info, name='api_peer_info'),
path('api/cron_check_updates/', cron_check_updates, name='cron_check_updates'),
path('api/cron_update_peer_latest_handshake/', cron_update_peer_latest_handshake, name='cron_update_peer_latest_handshake'),
path('firewall/port_forward/', view_redirect_rule_list, name='redirect_rule_list'),