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.auth.models import User
from django.contrib import auth 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.shortcuts import get_object_or_404, redirect
from django.views.decorators.http import require_http_methods from django.views.decorators.http import require_http_methods
from django.http import HttpResponseForbidden from django.http import HttpResponseForbidden
@ -10,7 +12,7 @@ from django.utils import timezone
from user_manager.models import UserAcl, AuthenticationToken from user_manager.models import UserAcl, AuthenticationToken
from wireguard.models import WebadminSettings, Peer, PeerStatus, WireGuardInstance 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 requests
import subprocess import subprocess
import datetime import datetime
@ -112,6 +114,22 @@ def routerfleet_get_user_token(request):
return JsonResponse(data) 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"]) @require_http_methods(["GET"])
def wireguard_status(request): def wireguard_status(request):
user_acl = None user_acl = None

View file

@ -3,17 +3,15 @@
{% 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">
@ -22,74 +20,96 @@
<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> <h5><a href="#" onclick="openPeerModal('{{ peer.uuid }}');" style="text-decoration: none">{{ peer }}</a></h5>
{% if peer.name %}
{{ peer.name}}
{% else %}
{{ peer.public_key|slice:":16" }}{% if peer.public_key|length > 16 %}...{% endif %}
{% endif %}
</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"><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"> <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>
</div> </div>
{% endif %} {% 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="javascript:void(0);" onclick="openImageLightbox('/tools/download_peer_config/?uuid={{ peer.uuid }}&format=qrcode');">
<a href="/tools/download_peer_config/?uuid={{ peer.uuid }}"><i class="fas fa-download"></i></a> <i class="fas fa-qrcode"></i>
<a href="/peer/manage/?peer={{ peer.uuid }}"><i class="far fa-edit"></i></a> </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> </span>
</div> </div>
{% comment %}This needs to be improved{% endcomment %}
<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> <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>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 %} {% 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 %} {% endfor %}
{% for address in peer.peerallowedip_set.all %} {% 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 %} {% endfor %}
</span> </span>
</p> </p>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
{% if add_peer_enabled %} {% 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 %} {% else %}
<a class="btn btn-primary disabled" href="">Create Peer</a> <a class="btn btn-primary disabled" href="">Create Peer</a>
{% endif %} {% 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>
</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"> <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>
@ -98,14 +118,44 @@
<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>
// 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> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
//const fetchWireguardStatus = async () => { //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 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 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 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 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 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 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('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/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/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_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('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'), path('firewall/port_forward/', view_redirect_rule_list, name='redirect_rule_list'),