mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
- Any changes done directly using 'wg' command need to be redone after a reboot and disable/enable sequence. Let that duty be handled by network manager. - Handle (none) values for keys and 0 values for latest handshake from 'wg' dump command output. - Don't store public/private keys for wireguard in /var/lib. Let Network Manager deal with the storage of secrets. - Create client connections in the 'external' zone. - Show allowed IPs for each client in the main page. - Show server connection public key only for clients. We use different key pairs when connecting to each of the servers. - Separate out configuration information and status information in the show page. - Allocate IP addresses to each of the clients. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
280 lines
9.7 KiB
Python
280 lines
9.7 KiB
Python
#
|
|
# This file is part of FreedomBox.
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
"""
|
|
Views for WireGuard application.
|
|
"""
|
|
|
|
import urllib.parse
|
|
|
|
from django.contrib import messages
|
|
from django.contrib.messages.views import SuccessMessageMixin
|
|
from django.http import Http404
|
|
from django.shortcuts import redirect
|
|
from django.urls import reverse_lazy
|
|
from django.utils.translation import ugettext as _
|
|
from django.views.generic import FormView, TemplateView
|
|
|
|
import plinth.modules.wireguard as wireguard
|
|
from plinth import network
|
|
from plinth.modules.names.components import DomainName
|
|
from plinth.views import AppView
|
|
|
|
from . import forms, utils
|
|
|
|
|
|
class WireguardView(AppView):
|
|
"""Serve configuration page."""
|
|
app_id = 'wireguard'
|
|
clients = wireguard.clients
|
|
name = wireguard.name
|
|
description = wireguard.description
|
|
diagnostics_module_name = 'wireguard'
|
|
show_status_block = False
|
|
template_name = 'wireguard.html'
|
|
port_forwarding_info = wireguard.port_forwarding_info
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Return additional context for rendering the template."""
|
|
context = super().get_context_data(**kwargs)
|
|
info = utils.get_info()
|
|
context['server'] = info['my_server']
|
|
context['client_peers'] = info['my_client']['servers']
|
|
return context
|
|
|
|
|
|
class AddClientView(SuccessMessageMixin, FormView):
|
|
"""View to add a client."""
|
|
form_class = forms.AddClientForm
|
|
template_name = 'wireguard_add_client.html'
|
|
success_url = reverse_lazy('wireguard:index')
|
|
success_message = _('Added new client.')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Return additional context for rendering the template."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['title'] = _('Add Client')
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
"""Add the client."""
|
|
public_key = form.cleaned_data.get('public_key')
|
|
try:
|
|
utils.add_client(public_key)
|
|
except ValueError:
|
|
messages.warning(self.request,
|
|
_('Client with public key already exists'))
|
|
return redirect('wireguard:index')
|
|
|
|
return super().form_valid(form)
|
|
|
|
|
|
class ShowClientView(SuccessMessageMixin, TemplateView):
|
|
"""View to show a client's details."""
|
|
template_name = 'wireguard_show_client.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Return additional context data for rendering the template."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['title'] = _('Show Client')
|
|
|
|
public_key = urllib.parse.unquote(self.kwargs['public_key'])
|
|
server_info = utils.get_info()['my_server']
|
|
if not server_info or public_key not in server_info['peers']:
|
|
raise Http404
|
|
|
|
domains = DomainName.list_names(filter_for_service='wireguard')
|
|
context['server'] = server_info
|
|
context['client'] = server_info['peers'][public_key]
|
|
context['endpoints'] = [
|
|
domain + ':' + str(server_info['listen_port'])
|
|
for domain in domains
|
|
]
|
|
return context
|
|
|
|
|
|
class EditClientView(SuccessMessageMixin, FormView):
|
|
"""View to modify a client."""
|
|
form_class = forms.AddClientForm
|
|
template_name = 'wireguard_edit_client.html'
|
|
success_url = reverse_lazy('wireguard:index')
|
|
success_message = _('Updated client.')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Return additional context for rendering the template."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['title'] = _('Modify Client')
|
|
return context
|
|
|
|
def get_initial(self):
|
|
"""Get initial form data."""
|
|
initial = super().get_initial()
|
|
initial['public_key'] = urllib.parse.unquote(self.kwargs['public_key'])
|
|
return initial
|
|
|
|
def form_valid(self, form):
|
|
"""Update the client."""
|
|
old_public_key = form.initial['public_key']
|
|
public_key = form.cleaned_data.get('public_key')
|
|
|
|
if old_public_key != public_key:
|
|
try:
|
|
utils.add_client(public_key)
|
|
except ValueError:
|
|
messages.warning(self.request,
|
|
_('Client with public key already exists'))
|
|
|
|
utils.remove_client(old_public_key)
|
|
|
|
return super().form_valid(form)
|
|
|
|
|
|
class DeleteClientView(SuccessMessageMixin, TemplateView):
|
|
"""View to delete a client."""
|
|
template_name = 'wireguard_delete_client.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Return additional context data for rendering the template."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['title'] = _('Delete Client')
|
|
context['public_key'] = urllib.parse.unquote(self.kwargs['public_key'])
|
|
return context
|
|
|
|
def post(self, request, public_key):
|
|
"""Delete the client."""
|
|
public_key = urllib.parse.unquote(public_key)
|
|
try:
|
|
utils.remove_client(public_key)
|
|
messages.success(request, _('Client deleted.'))
|
|
except KeyError:
|
|
messages.error(request, _('Client not found'))
|
|
|
|
return redirect('wireguard:index')
|
|
|
|
|
|
class AddServerView(SuccessMessageMixin, FormView):
|
|
"""View to add a server."""
|
|
form_class = forms.AddServerForm
|
|
template_name = 'wireguard_add_server.html'
|
|
success_url = reverse_lazy('wireguard:index')
|
|
success_message = _('Added new server.')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Return additional context for rendering the template."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['title'] = _('Add Server')
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
"""Add the server."""
|
|
utils.add_server(form.get_settings())
|
|
return super().form_valid(form)
|
|
|
|
|
|
class ShowServerView(SuccessMessageMixin, TemplateView):
|
|
"""View to show a server's details."""
|
|
template_name = 'wireguard_show_server.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Return additional context data for rendering the template."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['title'] = _('Server Information')
|
|
|
|
interface = self.kwargs['interface']
|
|
info = utils.get_info()
|
|
server = info['my_client']['servers'].get(interface)
|
|
if not server:
|
|
raise Http404
|
|
|
|
context['interface'] = interface
|
|
context['server'] = server
|
|
return context
|
|
|
|
|
|
class EditServerView(SuccessMessageMixin, FormView):
|
|
"""View to modify a server."""
|
|
form_class = forms.AddServerForm
|
|
template_name = 'wireguard_edit_server.html'
|
|
success_url = reverse_lazy('wireguard:index')
|
|
success_message = _('Updated server.')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Return additional context for rendering the template."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['title'] = _('Modify Server')
|
|
return context
|
|
|
|
def get_initial(self):
|
|
"""Get initial form data."""
|
|
initial = super().get_initial()
|
|
interface = self.kwargs['interface']
|
|
info = utils.get_nm_info()
|
|
server = info.get(interface)
|
|
if not server:
|
|
raise Http404
|
|
|
|
initial['ip_address'] = server.get('ip_address')
|
|
if server['peers']:
|
|
peer = next(peer for peer in server['peers'].values())
|
|
initial['peer_endpoint'] = peer['endpoint']
|
|
initial['peer_public_key'] = peer['public_key']
|
|
initial['private_key'] = server['private_key']
|
|
initial['preshared_key'] = peer['preshared_key']
|
|
initial['default_route'] = server['default_route']
|
|
|
|
return initial
|
|
|
|
def form_valid(self, form):
|
|
"""Update the server."""
|
|
settings = form.get_settings()
|
|
interface = self.kwargs['interface']
|
|
settings['common']['interface'] = interface
|
|
settings['common']['name'] = 'WireGuard-Client-' + interface
|
|
connection = network.get_connection_by_interface_name(interface)
|
|
network.edit_connection(connection, settings)
|
|
return super().form_valid(form)
|
|
|
|
|
|
class DeleteServerView(SuccessMessageMixin, TemplateView):
|
|
"""View to delete a server."""
|
|
template_name = 'wireguard_delete_server.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
"""Return additional context data for rendering the template."""
|
|
context = super().get_context_data(**kwargs)
|
|
context['title'] = _('Delete Server')
|
|
|
|
interface = self.kwargs['interface']
|
|
info = utils.get_nm_info()
|
|
server = info.get(interface)
|
|
if not server:
|
|
raise Http404
|
|
|
|
context['interface'] = interface
|
|
if server['peers']:
|
|
peer = next(peer for peer in server['peers'].values())
|
|
context['peer_endpoint'] = peer['endpoint']
|
|
context['peer_public_key'] = peer['public_key']
|
|
|
|
return context
|
|
|
|
def post(self, request, interface):
|
|
"""Delete the server."""
|
|
connection = network.get_connection_by_interface_name(interface)
|
|
network.delete_connection(connection.get_uuid())
|
|
messages.success(request, _('Server deleted.'))
|
|
return redirect('wireguard:index')
|