From 0a141924447f2b9c379f50cf6cc23f8803e29080 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 16 Feb 2024 17:14:35 -0300 Subject: [PATCH] Pending configuration warning and reload --- console/views.py | 8 ++++++- templates/base.html | 15 ++++++++++++- templates/wireguard/welcome.html | 8 +++---- wireguard/migrations/0006_peerstatus.py | 28 +++++++++++++++++++++++++ wireguard/models.py | 15 +++++++++++++ wireguard/views.py | 17 ++++++++++++--- wireguard_peer/views.py | 17 +++++++++++++-- wireguard_tools/views.py | 7 ++++++- 8 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 wireguard/migrations/0006_peerstatus.py diff --git a/console/views.py b/console/views.py index 10f57da..5ce6a37 100644 --- a/console/views.py +++ b/console/views.py @@ -1,3 +1,4 @@ +from wireguard.models import WireGuardInstance from wgwadmlibrary.tools import is_valid_ip_or_hostname from django.shortcuts import render from django.contrib.auth.decorators import login_required @@ -7,6 +8,11 @@ import subprocess @login_required def view_console(request): page_title = 'Console' + wireguard_instances = WireGuardInstance.objects.all().order_by('instance_id') + if wireguard_instances.filter(pending_changes=True).exists(): + pending_changes_warning = True + else: + pending_changes_warning = False requested_command = request.GET.get('command') command_target = request.GET.get('target', '') if command_target: @@ -59,5 +65,5 @@ def view_console(request): command_output = e.output.decode('utf-8') command_success = False - context = {'page_title': page_title, 'command_output': command_output, 'command_success': command_success} + context = {'page_title': page_title, 'command_output': command_output, 'command_success': command_success, 'pending_changes_warning': pending_changes_warning} return render(request, 'console/console.html', context) \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 305ceea..810fa7a 100644 --- a/templates/base.html +++ b/templates/base.html @@ -168,6 +168,19 @@
+ {% if pending_changes_warning %} + + {% endif %} + + {% block content %}{% endblock %} @@ -179,7 +192,7 @@
wireguard-webadmin
- Version 0.8 beta + Version 0.8.1 beta
diff --git a/templates/wireguard/welcome.html b/templates/wireguard/welcome.html index 1083d24..19d1c6c 100644 --- a/templates/wireguard/welcome.html +++ b/templates/wireguard/welcome.html @@ -5,17 +5,15 @@

I've been working hard on it over the past week and plan to continue making corrections and finishing it in the coming days.

Currently, it's quite functional, but there's still a need to polish various aspects of the interface to enhance usability.

If you encounter any issues or have suggestions, please open an issue on GitHub so I can review it.

-

Important Points to Note:

+

TODO list

  • The peers page does not yet display data from WireGuard such as the last handshake and data transfer.
  • The verification of allowed IPs against the output of wg show has not yet been implemented. This will help detect configuration errors for crypto routing.
  • -
  • After editing a peer or server settings, go to the status page and click to update the WireGuard configurations, then restart the service. I still need to make this process more intuitive.
  • The DNS server provided to the peer is still hardcoded.
  • +
  • AllowedIPs on client configuration side.
-

Your involvement and feedback are crucial to the development of wireguard_webadmin. Together, we can refine and enhance its functionality. Thank you for being part of this journey!

+ -

Don't Forget

-

Remember to save your configuration changes and restart the service for them to take effect.

Keep checking the GitHub page, I will be updating this project very soon.

{% endblock %} diff --git a/wireguard/migrations/0006_peerstatus.py b/wireguard/migrations/0006_peerstatus.py new file mode 100644 index 0000000..b6a8fa2 --- /dev/null +++ b/wireguard/migrations/0006_peerstatus.py @@ -0,0 +1,28 @@ +# Generated by Django 5.0.1 on 2024-02-16 19:01 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wireguard', '0005_wireguardinstance_pending_changes'), + ] + + operations = [ + migrations.CreateModel( + name='PeerStatus', + fields=[ + ('last_handshake', models.DateTimeField(blank=True, null=True)), + ('transfer_rx', models.BigIntegerField(default=0)), + ('transfer_tx', models.BigIntegerField(default=0)), + ('latest_config', models.TextField(blank=True, null=True)), + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('peer', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='wireguard.peer')), + ], + ), + ] diff --git a/wireguard/models.py b/wireguard/models.py index 0e8552f..dbc6c72 100644 --- a/wireguard/models.py +++ b/wireguard/models.py @@ -73,6 +73,21 @@ class Peer(models.Model): return self.public_key +class PeerStatus(models.Model): + peer = models.OneToOneField(Peer, on_delete=models.CASCADE) + last_handshake = models.DateTimeField(blank=True, null=True) + transfer_rx = models.BigIntegerField(default=0) + transfer_tx = models.BigIntegerField(default=0) + latest_config = models.TextField(blank=True, null=True) + + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4) + + def __str__(self): + return str(self.peer) + + class PeerAllowedIP(models.Model): peer = models.ForeignKey(Peer, on_delete=models.CASCADE) priority = models.PositiveBigIntegerField(default=1) diff --git a/wireguard/views.py b/wireguard/views.py index 79964b9..62a1f5e 100644 --- a/wireguard/views.py +++ b/wireguard/views.py @@ -75,6 +75,11 @@ def view_welcome(request): @login_required def view_wireguard_status(request): page_title = 'WireGuard Status' + wireguard_instances = WireGuardInstance.objects.all().order_by('instance_id') + if wireguard_instances.filter(pending_changes=True).exists(): + pending_changes_warning = True + else: + pending_changes_warning = False bash_command = ['bash', '-c', 'wg show'] try: command_output = subprocess.check_output(bash_command, stderr=subprocess.STDOUT).decode('utf-8') @@ -83,7 +88,7 @@ def view_wireguard_status(request): command_output = e.output.decode('utf-8') command_success = False - context = {'page_title': page_title, 'command_output': command_output, 'command_success': command_success} + context = {'page_title': page_title, 'command_output': command_output, 'command_success': command_success, 'pending_changes_warning': pending_changes_warning, 'wireguard_instances': wireguard_instances} return render(request, 'wireguard/wireguard_status.html', context) @@ -92,6 +97,10 @@ def view_wireguard_manage_instance(request): if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists(): return render(request, 'access_denied.html', {'page_title': 'Access Denied'}) wireguard_instances = WireGuardInstance.objects.all().order_by('instance_id') + if wireguard_instances.filter(pending_changes=True).exists(): + pending_changes_warning = True + else: + pending_changes_warning = False if request.GET.get('uuid'): current_instance = get_object_or_404(WireGuardInstance, uuid=request.GET.get('uuid')) else: @@ -124,7 +133,9 @@ def view_wireguard_manage_instance(request): if request.method == 'POST': form = WireGuardInstanceForm(request.POST, instance=current_instance) if form.is_valid(): - form.save() + this_form = form.save(commit=False) + this_form.pending_changes = True + this_form.save() messages.success(request, message_title + '|WireGuard instance wg' + str(form.instance.instance_id) + ' saved successfully.') return redirect('/server/manage/?uuid=' + str(form.instance.uuid)) else: @@ -132,5 +143,5 @@ def view_wireguard_manage_instance(request): form = WireGuardInstanceForm(initial=generate_instance_defaults()) else: form = WireGuardInstanceForm(instance=current_instance) - context = {'page_title': page_title, 'wireguard_instances': wireguard_instances, 'current_instance': current_instance, 'form': form} + context = {'page_title': page_title, 'wireguard_instances': wireguard_instances, 'current_instance': current_instance, 'form': form, 'pending_changes_warning': pending_changes_warning} return render(request, 'wireguard/wireguard_manage_server.html', context) \ No newline at end of file diff --git a/wireguard_peer/views.py b/wireguard_peer/views.py index 5cb11c2..c976eb5 100644 --- a/wireguard_peer/views.py +++ b/wireguard_peer/views.py @@ -45,6 +45,10 @@ def generate_peer_default(wireguard_instance): def view_wireguard_peer_list(request): page_title = 'WireGuard Peer List' wireguard_instances = WireGuardInstance.objects.all().order_by('instance_id') + if wireguard_instances.filter(pending_changes=True).exists(): + pending_changes_warning = True + else: + pending_changes_warning = False if wireguard_instances: if request.GET.get('uuid'): current_instance = get_object_or_404(WireGuardInstance, uuid=request.GET.get('uuid')) @@ -55,7 +59,7 @@ def view_wireguard_peer_list(request): current_instance = None peer_list = None - context = {'page_title': page_title, 'wireguard_instances': wireguard_instances, 'current_instance': current_instance, 'peer_list': peer_list} + context = {'page_title': page_title, 'wireguard_instances': wireguard_instances, 'current_instance': current_instance, 'peer_list': peer_list, 'pending_changes_warning': pending_changes_warning} return render(request, 'wireguard/wireguard_peer_list.html', context) @@ -90,6 +94,8 @@ def view_wireguard_peer_manage(request): netmask=32, ) messages.success(request, 'Peer created|Peer for instance wg' + str(current_instance.instance_id) + ' created successfully with IP ' + new_peer_data['allowed_ip'] + '/32.') + new_peer.wireguard_instance.pending_changes = True + new_peer.wireguard_instance.save() return redirect('/peer/manage/?peer=' + str(new_peer.uuid)) else: messages.warning(request, 'Error creating peer|No available IP address found for peer creation.') @@ -100,6 +106,8 @@ def view_wireguard_peer_manage(request): current_instance = current_peer.wireguard_instance if request.GET.get('action') == 'delete': if request.GET.get('confirmation') == 'delete': + current_peer.wireguard_instance.pending_changes = True + current_peer.wireguard_instance.save() current_peer.delete() messages.success(request, 'Peer deleted|Peer deleted successfully.') return redirect('/peer/list/?uuid=' + str(current_instance.uuid)) @@ -117,6 +125,8 @@ def view_wireguard_peer_manage(request): if form.is_valid(): form.save() messages.success(request, 'Peer updated|Peer updated successfully.') + current_peer.wireguard_instance.pending_changes = True + current_peer.wireguard_instance.save() return redirect('/peer/list/?uuid=' + str(current_peer.wireguard_instance.uuid)) else: form = PeerForm(instance=current_peer) @@ -152,6 +162,8 @@ def view_manage_ip_address(request): if request.GET.get('confirmation') == 'delete': current_ip.delete() messages.success(request, 'IP address deleted|IP address deleted successfully.') + current_peer.wireguard_instance.pending_changes = True + current_peer.wireguard_instance.save() return redirect('/peer/manage/?peer=' + str(current_peer.uuid)) else: messages.warning(request, 'Error deleting IP address|Invalid confirmation message. Type "delete" to confirm.') @@ -164,7 +176,8 @@ def view_manage_ip_address(request): if not current_ip: this_form.peer = current_peer this_form.save() - form.save() + current_peer.wireguard_instance.pending_changes = True + current_peer.wireguard_instance.save() if current_ip: messages.success(request, 'IP address updated|IP address updated successfully.') else: diff --git a/wireguard_tools/views.py b/wireguard_tools/views.py index cfc5704..6fd857a 100644 --- a/wireguard_tools/views.py +++ b/wireguard_tools/views.py @@ -88,6 +88,8 @@ def export_wireguard_configs(request): with open(config_path, "w") as config_file: config_file.write(config_content) messages.success(request, "Export successful!|WireGuard configuration files have been exported to /etc/wireguard/. Don't forget to restart the interfaces.") + if request.GET.get('action') == 'update_and_restart': + return redirect('/tools/restart_wireguard/?action=dismiss_warning') return redirect('/status/') @@ -159,6 +161,9 @@ def restart_wireguard_interfaces(request): if interface_count == 0 and error_count == 0: messages.info(request, "No interfaces found|No WireGuard interfaces were found to restart.") - + if request.GET.get('action') == 'dismiss_warning': + for wireguard_instancee in WireGuardInstance.objects.filter(pending_changes=True): + wireguard_instancee.pending_changes = False + wireguard_instancee.save() return redirect("/status/")