mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2026-01-31 11:36:18 +00:00
Update peer management view and forms.
This commit is contained in:
@@ -7,43 +7,65 @@
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">{% trans 'Peer Configuration' %}</h3>
|
||||
</div>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card-body row">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<!-- Name -->
|
||||
<div class="form-group">
|
||||
<label for="{{ form.name.id_for_label }}">{{ form.name.label }}</label>
|
||||
<input type="text" class="form-control" id="{{ form.name.id_for_label }}" name="{{ form.name.html_name }}" placeholder="{% trans 'Enter Name' %}" value="{{ form.name.value|default_if_none:'' }}">
|
||||
<div class="form-group border-bottom pb-3">
|
||||
<label>{% trans 'Name' %}</label>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span>{{ current_peer.name|default:"-" }}</span>
|
||||
<a href="{% url 'wireguard_peer_edit_field' %}?peer={{ current_peer.uuid }}&group=name"
|
||||
class="btn btn-tool">
|
||||
<i class="fas fa-pen"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Persistent Keepalive -->
|
||||
<div class="form-group">
|
||||
<label for="{{ form.persistent_keepalive.id_for_label }}">{{ form.persistent_keepalive.label }}</label>
|
||||
<input type="number" class="form-control" id="{{ form.persistent_keepalive.id_for_label }}" name="{{ form.persistent_keepalive.html_name }}" placeholder="{% trans 'Persistent Keepalive' %}" value="{{ form.persistent_keepalive.value|default_if_none:'' }}" required>
|
||||
</div>
|
||||
|
||||
<!-- Public Key -->
|
||||
<div class="form-group">
|
||||
<label for="{{ form.public_key.id_for_label }}">{{ form.public_key.label }}</label>
|
||||
<input type="text" class="form-control" id="{{ form.public_key.id_for_label }}" name="{{ form.public_key.html_name }}" placeholder="{% trans 'Public Key' %}" value="{{ form.public_key.value|default_if_none:'' }}" required>
|
||||
</div>
|
||||
|
||||
<!-- Private Key -->
|
||||
<div class="form-group">
|
||||
<label for="{{ form.private_key.id_for_label }}">{{ form.private_key.label }}</label>
|
||||
<div class="input-group">
|
||||
<input type="password" class="form-control" id="{{ form.private_key.id_for_label }}" name="{{ form.private_key.html_name }}" placeholder="{% trans 'Private Key' %}" value="{{ form.private_key.value|default_if_none:'' }}">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary toggle-password" type="button"><i class="fas fa-eye"></i></button>
|
||||
</div>
|
||||
<div class="form-group border-bottom pb-3">
|
||||
<label>{% trans 'Persistent Keepalive' %}</label>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span>{{ current_peer.persistent_keepalive }}</span>
|
||||
<a href="{% url 'wireguard_peer_edit_field' %}?peer={{ current_peer.uuid }}&group=keepalive"
|
||||
class="btn btn-tool">
|
||||
<i class="fas fa-pen"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pre-Shared Key -->
|
||||
<!-- Keys Section -->
|
||||
<div class="form-group">
|
||||
<label for="{{ form.pre_shared_key.id_for_label }}">{{ form.pre_shared_key.label }}</label>
|
||||
<input type="text" class="form-control" id="{{ form.pre_shared_key.id_for_label }}" name="{{ form.pre_shared_key.html_name }}" placeholder="{% trans 'Pre-Shared Key' %}" value="{{ form.pre_shared_key.value|default_if_none:'' }}" required>
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<label class="mb-0">{% trans 'Keys' %}</label>
|
||||
<a href="{% url 'wireguard_peer_edit_field' %}?peer={{ current_peer.uuid }}&group=keys"
|
||||
class="btn btn-tool">
|
||||
<i class="fas fa-pen"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<dl>
|
||||
<dt class="small text-muted font-weight-normal">{% trans 'Public Key' %}</dt>
|
||||
<dd class="text-break">{{ current_peer.public_key }}</dd>
|
||||
|
||||
<dt class="small text-muted font-weight-normal">{% trans 'Private Key' %}</dt>
|
||||
<dd>
|
||||
{% if current_peer.private_key %}
|
||||
<code>********************************************</code>
|
||||
{% else %}
|
||||
<span class="text-muted">{% trans 'Not set' %}</span>
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt class="small text-muted font-weight-normal">{% trans 'Pre-Shared Key' %}</dt>
|
||||
<dd>
|
||||
{% if current_peer.pre_shared_key %}
|
||||
<code>********************************************</code>
|
||||
{% else %}
|
||||
<span class="text-muted">{% trans 'Not set' %}</span>
|
||||
{% endif %}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -195,47 +217,18 @@
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" class="btn btn-primary">{% trans 'Save' %}</button>
|
||||
<a href="/peer/manage_ip_address/?peer={{ current_peer.uuid }}" class="btn btn-outline-primary">{% trans 'Add IP Address' %}</a>
|
||||
<a class="btn btn-outline-secondary" href="/peer/list/?uuid={{ current_peer.wireguard_instance.uuid }}#peer-{{ current_peer.public_key }}">{% trans 'Back' %}</a>
|
||||
<a href='javascript:void(0)' class='btn btn-outline-danger' data-command='delete' onclick='openCommandDialog(this)'>{% trans 'Delete Peer' %}</a>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_page_scripts %}
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var alertShown = false;
|
||||
var fieldsToWatch = ['id_public_key', 'id_pre_shared_key', 'id_private_key'];
|
||||
function showAlert() {
|
||||
if (!alertShown) {
|
||||
$(document).Toasts('create', {
|
||||
class: 'bg-warning',
|
||||
title: '{% trans 'Action Required!' %}',
|
||||
body: '{% trans 'When manually updating the "Public Key", "Pre-Shared Key", or "Private Key", please ensure the configuration is correct.' %}',
|
||||
});
|
||||
alertShown = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fieldsToWatch.forEach(function(fieldId) {
|
||||
var field = document.getElementById(fieldId);
|
||||
if (field) {
|
||||
field.addEventListener('change', showAlert);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
function openCommandDialog(element) {
|
||||
var command = element.getAttribute('data-command');
|
||||
@@ -247,22 +240,6 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
document.querySelector('.toggle-password').addEventListener('click', function () {
|
||||
let passwordInput = document.getElementById('{{ form.private_key.id_for_label }}');
|
||||
let passStatus = passwordInput.getAttribute('type') === 'password';
|
||||
passwordInput.setAttribute('type', passStatus ? 'text' : 'password');
|
||||
this.innerHTML = passStatus ? '<i class="fas fa-eye-slash"></i>' : '<i class="fas fa-eye"></i>';
|
||||
});
|
||||
|
||||
document.getElementById('{{ form.private_key.id_for_label }}').addEventListener('keypress', function () {
|
||||
this.setAttribute('type', 'text');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
var buttons = document.querySelectorAll('.btn-group a');
|
||||
@@ -280,23 +257,4 @@ document.addEventListener('DOMContentLoaded', function(){
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var form = document.querySelector('form[method="post"]');
|
||||
if (form) {
|
||||
form.addEventListener('submit', function(e) {
|
||||
var privateKeyField = document.getElementById('{{ form.private_key.id_for_label }}');
|
||||
if (privateKeyField && privateKeyField.value.trim() === '') {
|
||||
var confirmed = confirm('{% trans "The private key is empty. The peer’s configuration file and QR code will be generated without the private key.\n It must be inserted manually when importing.\n\n Do you want to continue?" %}');
|
||||
if (!confirmed) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,21 +1,56 @@
|
||||
import ipaddress
|
||||
|
||||
from crispy_forms.bootstrap import FormActions
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Layout, Submit, Button
|
||||
from django import forms
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from wireguard.models import NETMASK_CHOICES, Peer, PeerAllowedIP
|
||||
|
||||
|
||||
class PeerForm(forms.ModelForm):
|
||||
class PeerModelForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_method = 'post'
|
||||
self.helper.layout = Layout(
|
||||
*self.Meta.fields,
|
||||
FormActions(
|
||||
Submit('save', _('Save'), css_class='btn-primary'),
|
||||
Button('cancel', _('Back'), css_class='btn-outline-secondary', onclick='window.history.back()')
|
||||
)
|
||||
)
|
||||
|
||||
class PeerNameForm(PeerModelForm):
|
||||
name = forms.CharField(label=_('Name'), required=False)
|
||||
public_key = forms.CharField(label=_('Public Key'), required=True)
|
||||
private_key = forms.CharField(label=_('Private Key'), required=False)
|
||||
pre_shared_key = forms.CharField(label=_('Pre-Shared Key'), required=True)
|
||||
persistent_keepalive = forms.IntegerField(label=_('Persistent Keepalive'), required=True)
|
||||
|
||||
class Meta:
|
||||
model = Peer
|
||||
fields = ['name', 'public_key', 'private_key', 'pre_shared_key', 'persistent_keepalive']
|
||||
fields = ['name']
|
||||
|
||||
|
||||
class PeerKeepaliveForm(PeerModelForm):
|
||||
persistent_keepalive = forms.IntegerField(
|
||||
label=_('Persistent Keepalive'),
|
||||
required=True,
|
||||
validators=[MinValueValidator(1), MaxValueValidator(3600)],
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Peer
|
||||
fields = ['persistent_keepalive']
|
||||
|
||||
|
||||
class PeerKeysForm(PeerModelForm):
|
||||
public_key = forms.CharField(label=_('Public Key'), required=True)
|
||||
private_key = forms.CharField(label=_('Private Key'), required=False)
|
||||
pre_shared_key = forms.CharField(label=_('Pre-Shared Key'), required=True)
|
||||
|
||||
class Meta:
|
||||
model = Peer
|
||||
fields = ['public_key', 'private_key', 'pre_shared_key']
|
||||
|
||||
|
||||
class PeerAllowedIPForm(forms.ModelForm):
|
||||
|
||||
@@ -14,7 +14,7 @@ from user_manager.models import UserAcl
|
||||
from wgwadmlibrary.tools import check_sort_order_conflict, deduplicate_sort_order, default_sort_peers, \
|
||||
user_allowed_instances, user_allowed_peers, user_has_access_to_instance, user_has_access_to_peer
|
||||
from wireguard.models import Peer, PeerAllowedIP, WireGuardInstance
|
||||
from wireguard_peer.forms import PeerAllowedIPForm, PeerForm
|
||||
from wireguard_peer.forms import PeerAllowedIPForm, PeerNameForm, PeerKeepaliveForm, PeerKeysForm
|
||||
|
||||
|
||||
def generate_peer_default(wireguard_instance):
|
||||
@@ -184,10 +184,6 @@ def view_wireguard_peer_create(request):
|
||||
|
||||
@login_required
|
||||
def view_wireguard_peer_manage(request):
|
||||
if request.method == 'POST':
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
|
||||
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||
else:
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=20).exists():
|
||||
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||
user_acl = get_object_or_404(UserAcl, user=request.user)
|
||||
@@ -197,6 +193,8 @@ def view_wireguard_peer_manage(request):
|
||||
raise Http404
|
||||
current_instance = current_peer.wireguard_instance
|
||||
if request.GET.get('action') == 'delete':
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
|
||||
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||
if request.GET.get('confirmation') == 'delete':
|
||||
current_peer.wireguard_instance.pending_changes = True
|
||||
current_peer.wireguard_instance.save()
|
||||
@@ -206,28 +204,62 @@ def view_wireguard_peer_manage(request):
|
||||
else:
|
||||
messages.warning(request, _('Error deleting peer|Invalid confirmation message. Type "delete" to confirm.'))
|
||||
return redirect('/peer/manage/?peer=' + str(current_peer.uuid))
|
||||
page_title = _('Update Peer: ') + str(current_peer)
|
||||
page_title = _('Peer Configuration: ') + str(current_peer)
|
||||
peer_ip_list = current_peer.peerallowedip_set.filter(config_file='server').order_by('priority')
|
||||
peer_client_ip_list = current_peer.peerallowedip_set.filter(config_file='client').order_by('priority')
|
||||
|
||||
if request.method == 'POST':
|
||||
form = PeerForm(request.POST, instance=current_peer)
|
||||
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)
|
||||
|
||||
context = {
|
||||
'page_title': page_title, 'current_instance': current_instance, 'current_peer': current_peer, 'form': form,
|
||||
'page_title': page_title, 'current_instance': current_instance, 'current_peer': current_peer,
|
||||
'peer_ip_list': peer_ip_list, 'peer_client_ip_list': peer_client_ip_list
|
||||
}
|
||||
return render(request, 'wireguard/wireguard_manage_peer.html', context)
|
||||
|
||||
|
||||
@login_required
|
||||
def view_wireguard_peer_edit_field(request):
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
|
||||
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||
user_acl = get_object_or_404(UserAcl, user=request.user)
|
||||
|
||||
current_peer = get_object_or_404(Peer, uuid=request.GET.get('peer'))
|
||||
if not user_has_access_to_peer(user_acl, current_peer):
|
||||
raise Http404
|
||||
|
||||
group = request.GET.get('group')
|
||||
form_classes = {
|
||||
'name': PeerNameForm,
|
||||
'keepalive': PeerKeepaliveForm,
|
||||
'keys': PeerKeysForm
|
||||
}
|
||||
|
||||
if group not in form_classes:
|
||||
raise Http404
|
||||
|
||||
FormClass = form_classes[group]
|
||||
|
||||
form = FormClass(request.POST or None, instance=current_peer)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
current_peer.wireguard_instance.pending_changes = True
|
||||
current_peer.wireguard_instance.save()
|
||||
messages.success(request, _('Peer updated|Peer updated successfully.'))
|
||||
return redirect('/peer/manage/?peer=' + str(current_peer.uuid))
|
||||
|
||||
page_title = _('Edit Peer')
|
||||
if group == 'name':
|
||||
page_title = _('Edit Peer Name')
|
||||
elif group == 'keepalive':
|
||||
page_title = _('Edit Keepalive')
|
||||
elif group == 'keys':
|
||||
page_title = _('Edit Keys')
|
||||
|
||||
context = {
|
||||
'page_title': page_title,
|
||||
'form': form,
|
||||
}
|
||||
return render(request, 'generic_form.html', context)
|
||||
|
||||
|
||||
def view_manage_ip_address(request):
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
|
||||
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||
|
||||
@@ -39,7 +39,7 @@ from wgrrd.views import view_rrd_graph
|
||||
from wireguard.views import view_apply_db_patches, view_wireguard_manage_instance, view_wireguard_status, \
|
||||
view_server_list, view_server_detail
|
||||
from wireguard_peer.views import view_manage_ip_address, view_wireguard_peer_list, view_wireguard_peer_manage, \
|
||||
view_wireguard_peer_sort, view_apply_route_template, view_wireguard_peer_create
|
||||
view_wireguard_peer_sort, view_apply_route_template, view_wireguard_peer_create, view_wireguard_peer_edit_field
|
||||
from wireguard_tools.views import download_config_or_qrcode, export_wireguard_configs, restart_wireguard_interfaces
|
||||
|
||||
urlpatterns = [
|
||||
@@ -57,6 +57,7 @@ urlpatterns = [
|
||||
path('peer/sort/', view_wireguard_peer_sort, name='wireguard_peer_sort'),
|
||||
path('peer/manage/', view_wireguard_peer_manage, name='wireguard_peer_manage'),
|
||||
path('peer/create/', view_wireguard_peer_create, name='wireguard_peer_create'),
|
||||
path('peer/edit/', view_wireguard_peer_edit_field, name='wireguard_peer_edit_field'),
|
||||
path('peer/apply_route_template/', view_apply_route_template, name='apply_route_template'),
|
||||
path('peer/manage_ip_address/', view_manage_ip_address, name='manage_ip_address'),
|
||||
path('rrd/graph/', view_rrd_graph, name='rrd_graph'),
|
||||
|
||||
Reference in New Issue
Block a user