mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2026-01-17 13:06:18 +00:00
add server selection to VPN invite
This commit is contained in:
@@ -57,6 +57,10 @@ class Worker(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def server_address(self):
|
||||||
|
return self.hostname or self.ip_address or ''
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def display_name(self):
|
def display_name(self):
|
||||||
cluster_settings = ClusterSettings.objects.first()
|
cluster_settings = ClusterSettings.objects.first()
|
||||||
@@ -98,7 +102,6 @@ class Worker(models.Model):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WorkerStatus(models.Model):
|
class WorkerStatus(models.Model):
|
||||||
worker = models.OneToOneField(Worker, on_delete=models.CASCADE)
|
worker = models.OneToOneField(Worker, on_delete=models.CASCADE)
|
||||||
last_seen = models.DateTimeField(auto_now=True)
|
last_seen = models.DateTimeField(auto_now=True)
|
||||||
|
|||||||
@@ -129,6 +129,16 @@
|
|||||||
<a href="{{ invite_settings.download_5_url }}" target="_blank">{{ invite_settings.download_5_label }}</a>
|
<a href="{{ invite_settings.download_5_url }}" target="_blank">{{ invite_settings.download_5_label }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if cluster_settings and servers|length > 1 %}
|
||||||
|
<div style="text-align: center; margin-bottom: 15px;">
|
||||||
|
<label for="server_select">Server:</label>
|
||||||
|
<select id="server_select" style="padding: 5px; border-radius: 4px; border: 1px solid #ccc;">
|
||||||
|
{% for server in servers %}
|
||||||
|
<option value="{{ server.address }}">{{ server.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="button-group">
|
<div class="button-group">
|
||||||
<a href="/invite/download_config/?token={{ peer_invite.uuid }}&password={{ password }}" target="_blank" class="btn btn-primary" id="downloadConfigButton">Download Config</a>
|
<a href="/invite/download_config/?token={{ peer_invite.uuid }}&password={{ password }}" target="_blank" class="btn btn-primary" id="downloadConfigButton">Download Config</a>
|
||||||
<a href="#" id="viewQrButton" class="btn btn-secondary"{% if not peer_invite.peer.private_key %} style="opacity: 0.5; cursor: not-allowed;"{% endif %}>View QR Code</a>
|
<a href="#" id="viewQrButton" class="btn btn-secondary"{% if not peer_invite.peer.private_key %} style="opacity: 0.5; cursor: not-allowed;"{% endif %}>View QR Code</a>
|
||||||
@@ -159,12 +169,19 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (qrCodeContainer.style.display === "none" || qrCodeContainer.style.display === "") {
|
if (qrCodeContainer.style.display === "none" || qrCodeContainer.style.display === "") {
|
||||||
if (qrCodeContainer.getElementsByTagName("img").length === 0) {
|
// Always refresh image on click to ensure current server selection is respected
|
||||||
|
qrCodeContainer.innerHTML = '';
|
||||||
|
|
||||||
var img = document.createElement("img");
|
var img = document.createElement("img");
|
||||||
img.src = "/invite/download_config/?token={{ peer_invite.uuid }}&password={{ password }}&format=qrcode";
|
var server = document.getElementById("server_select") ? document.getElementById("server_select").value : "";
|
||||||
|
var url = "/invite/download_config/?token={{ peer_invite.uuid }}&password={{ password }}&format=qrcode";
|
||||||
|
if (server) {
|
||||||
|
url += "&server=" + encodeURIComponent(server);
|
||||||
|
}
|
||||||
|
img.src = url;
|
||||||
img.alt = "QR Code";
|
img.alt = "QR Code";
|
||||||
qrCodeContainer.appendChild(img);
|
qrCodeContainer.appendChild(img);
|
||||||
}
|
|
||||||
qrCodeContainer.style.display = "block";
|
qrCodeContainer.style.display = "block";
|
||||||
} else {
|
} else {
|
||||||
qrCodeContainer.style.display = "none";
|
qrCodeContainer.style.display = "none";
|
||||||
@@ -178,7 +195,32 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var server = document.getElementById("server_select") ? document.getElementById("server_select").value : "";
|
||||||
|
var url = "/invite/download_config/?token={{ peer_invite.uuid }}&password={{ password }}";
|
||||||
|
if (server) {
|
||||||
|
url += "&server=" + encodeURIComponent(server);
|
||||||
|
}
|
||||||
|
this.href = url;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update href immediately if dropdown changes (optional, but good for UX)
|
||||||
|
var serverSelect = document.getElementById("server_select");
|
||||||
|
if (serverSelect) {
|
||||||
|
serverSelect.addEventListener("change", function () {
|
||||||
|
var server = this.value;
|
||||||
|
var url = "/invite/download_config/?token={{ peer_invite.uuid }}&password={{ password }}";
|
||||||
|
if (server) {
|
||||||
|
url += "&server=" + encodeURIComponent(server);
|
||||||
|
}
|
||||||
|
downloadConfigButton.href = url;
|
||||||
|
|
||||||
|
// If QR code is visible, reload it
|
||||||
|
if (qrCodeContainer.style.display === "block") {
|
||||||
|
viewQrButton.click(); // Hide
|
||||||
|
setTimeout(function () { viewQrButton.click(); }, 100); // Show again
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -190,6 +190,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
{% if cluster_settings and servers|length > 1 %}
|
||||||
|
<div class="mr-auto form-inline">
|
||||||
|
<label class="mr-2" for="server_select">{% trans 'Server' %}:</label>
|
||||||
|
<select class="form-control" id="server_select">
|
||||||
|
{% for server in servers %}
|
||||||
|
<option value="{{ server.address }}">{{ server.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><i class="fas fa-times"></i> {% trans 'Close' %}</button>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal"><i class="fas fa-times"></i> {% trans 'Close' %}</button>
|
||||||
<a href="#" class="btn btn-info" id="downloadConfigButton"><i class="fas fa-download"></i> {% trans 'Config' %}</a>
|
<a href="#" class="btn btn-info" id="downloadConfigButton"><i class="fas fa-download"></i> {% trans 'Config' %}</a>
|
||||||
<a href="#" class="btn btn-info" id="qrcodeButton"><i class="fas fa-qrcode"></i> {% trans 'QR Code' %}</a>
|
<a href="#" class="btn btn-info" id="qrcodeButton"><i class="fas fa-qrcode"></i> {% trans 'QR Code' %}</a>
|
||||||
@@ -287,12 +297,37 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var uuid = $("#peerPreviewModal").data("peer-uuid");
|
var uuid = $("#peerPreviewModal").data("peer-uuid");
|
||||||
$("#qrCodeImg").attr("src", "/tools/download_peer_config/?uuid=" + uuid + "&format=qrcode");
|
var server = $('#server_select').val(); // Get selected server
|
||||||
|
var url = "/tools/download_peer_config/?uuid=" + uuid + "&format=qrcode";
|
||||||
|
if (server) {
|
||||||
|
url += "&server=" + encodeURIComponent(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#qrCodeImg").attr("src", url);
|
||||||
$(".info-content").hide();
|
$(".info-content").hide();
|
||||||
$(".invite-content").hide();
|
$(".invite-content").hide();
|
||||||
$(".qr-code-content").show();
|
$(".qr-code-content").show();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#server_select").on("change", function () {
|
||||||
|
var uuid = $('#peerPreviewModal').data('peer-uuid');
|
||||||
|
var server = $(this).val();
|
||||||
|
|
||||||
|
// Update download config button
|
||||||
|
var downloadUrl = '/tools/download_peer_config/?uuid=' + uuid;
|
||||||
|
if (server) {
|
||||||
|
downloadUrl += '&server=' + encodeURIComponent(server);
|
||||||
|
}
|
||||||
|
$('#downloadConfigButton').attr('href', downloadUrl);
|
||||||
|
|
||||||
|
// Update QR code button (href is used for storing base url, actual action is click)
|
||||||
|
var qrUrl = '/tools/download_peer_config/?uuid=' + uuid + '&format=qrcode';
|
||||||
|
if (server) {
|
||||||
|
qrUrl += '&server=' + encodeURIComponent(server);
|
||||||
|
}
|
||||||
|
$('#qrcodeButton').attr('href', qrUrl);
|
||||||
|
});
|
||||||
|
|
||||||
$("#backButton").on("click", function (e) {
|
$("#backButton").on("click", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$(".qr-code-content").hide();
|
$(".qr-code-content").hide();
|
||||||
@@ -338,8 +373,18 @@
|
|||||||
$('#peerLocation').text(peerLocation);
|
$('#peerLocation').text(peerLocation);
|
||||||
$('#peerAllowedIPs').html(peerAllowedIPs);
|
$('#peerAllowedIPs').html(peerAllowedIPs);
|
||||||
$('#editPeerButton').attr('href', '/peer/manage/?peer=' + uuid);
|
$('#editPeerButton').attr('href', '/peer/manage/?peer=' + uuid);
|
||||||
$('#downloadConfigButton').attr('href', '/tools/download_peer_config/?uuid=' + uuid);
|
|
||||||
$('#qrcodeButton').attr('href', '/tools/download_peer_config/?uuid=' + uuid + '&format=qrcode');
|
var server = $('#server_select').val();
|
||||||
|
var downloadUrl = '/tools/download_peer_config/?uuid=' + uuid;
|
||||||
|
var qrUrl = '/tools/download_peer_config/?uuid=' + uuid + '&format=qrcode';
|
||||||
|
|
||||||
|
if (server) {
|
||||||
|
downloadUrl += '&server=' + encodeURIComponent(server);
|
||||||
|
qrUrl += '&server=' + encodeURIComponent(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#downloadConfigButton').attr('href', downloadUrl);
|
||||||
|
$('#qrcodeButton').attr('href', qrUrl);
|
||||||
$('#graphImg').attr('src', '/rrd/graph/?peer=' + uuid).show();
|
$('#graphImg').attr('src', '/rrd/graph/?peer=' + uuid).show();
|
||||||
$('#peerPreviewModal').data('peer-uuid', uuid);
|
$('#peerPreviewModal').data('peer-uuid', uuid);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from django.http import Http404
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from cluster.models import ClusterSettings, Worker
|
||||||
from vpn_invite.models import PeerInvite, InviteSettings
|
from vpn_invite.models import PeerInvite, InviteSettings
|
||||||
|
|
||||||
|
|
||||||
@@ -13,12 +14,24 @@ def view_public_vpn_invite(request):
|
|||||||
except:
|
except:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
# Initialize context with default values
|
cluster_settings = ClusterSettings.objects.filter(name='cluster_settings', enabled=True).first()
|
||||||
|
servers = []
|
||||||
|
if cluster_settings:
|
||||||
|
if cluster_settings.primary_enable_wireguard:
|
||||||
|
servers.append({'name': 'Primary Server', 'address': ''})
|
||||||
|
|
||||||
|
for worker in Worker.objects.filter(enabled=True):
|
||||||
|
listen_port = peer_invite.peer.wireguard_instance.listen_port
|
||||||
|
worker_address = f"{worker.server_address}:{listen_port}"
|
||||||
|
servers.append({'name': worker.display_name, 'address': worker_address})
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'peer_invite': peer_invite,
|
'peer_invite': peer_invite,
|
||||||
'invite_settings': invite_settings,
|
'invite_settings': invite_settings,
|
||||||
'authenticated': False,
|
'authenticated': False,
|
||||||
'error': ''
|
'error': '',
|
||||||
|
'cluster_settings': cluster_settings,
|
||||||
|
'servers': servers
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ def clean_command_field(command_field):
|
|||||||
return cleaned_field
|
return cleaned_field
|
||||||
|
|
||||||
|
|
||||||
def generate_peer_config(peer_uuid):
|
def generate_peer_config(peer_uuid, server_address=None):
|
||||||
peer = get_object_or_404(Peer, uuid=peer_uuid)
|
peer = get_object_or_404(Peer, uuid=peer_uuid)
|
||||||
wg_instance = peer.wireguard_instance
|
wg_instance = peer.wireguard_instance
|
||||||
|
|
||||||
@@ -46,6 +46,11 @@ def generate_peer_config(peer_uuid):
|
|||||||
dns_entries = [wg_instance.dns_primary, wg_instance.dns_secondary]
|
dns_entries = [wg_instance.dns_primary, wg_instance.dns_secondary]
|
||||||
dns_line = ", ".join(filter(None, dns_entries))
|
dns_line = ", ".join(filter(None, dns_entries))
|
||||||
|
|
||||||
|
if server_address:
|
||||||
|
endpoint = server_address
|
||||||
|
else:
|
||||||
|
endpoint = f"{wg_instance.hostname}:{wg_instance.listen_port}"
|
||||||
|
|
||||||
config_lines = [
|
config_lines = [
|
||||||
"[Interface]",
|
"[Interface]",
|
||||||
f"PrivateKey = {peer.private_key}",
|
f"PrivateKey = {peer.private_key}",
|
||||||
@@ -53,7 +58,7 @@ def generate_peer_config(peer_uuid):
|
|||||||
f"DNS = {dns_line}" if dns_line else "",
|
f"DNS = {dns_line}" if dns_line else "",
|
||||||
"\n[Peer]",
|
"\n[Peer]",
|
||||||
f"PublicKey = {wg_instance.public_key}",
|
f"PublicKey = {wg_instance.public_key}",
|
||||||
f"Endpoint = {wg_instance.hostname}:{wg_instance.listen_port}",
|
f"Endpoint = {endpoint}",
|
||||||
f"AllowedIPs = {allowed_ips_line}",
|
f"AllowedIPs = {allowed_ips_line}",
|
||||||
f"PresharedKey = {peer.pre_shared_key}" if peer.pre_shared_key else "",
|
f"PresharedKey = {peer.pre_shared_key}" if peer.pre_shared_key else "",
|
||||||
f"PersistentKeepalive = {peer.persistent_keepalive}",
|
f"PersistentKeepalive = {peer.persistent_keepalive}",
|
||||||
@@ -194,8 +199,9 @@ def download_config_or_qrcode(request):
|
|||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
format_type = request.GET.get('format', 'conf')
|
format_type = request.GET.get('format', 'conf')
|
||||||
|
server_address = request.GET.get('server')
|
||||||
|
|
||||||
config_content = generate_peer_config(peer.uuid)
|
config_content = generate_peer_config(peer.uuid, server_address=server_address)
|
||||||
|
|
||||||
if format_type == 'qrcode':
|
if format_type == 'qrcode':
|
||||||
qr = qrcode.QRCode(
|
qr = qrcode.QRCode(
|
||||||
|
|||||||
Reference in New Issue
Block a user