diff --git a/libs/editor/CMakeLists.txt b/libs/editor/CMakeLists.txt --- a/libs/editor/CMakeLists.txt +++ b/libs/editor/CMakeLists.txt @@ -1,109 +1,110 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/widgets) - -set(plasmanm_editor_SRCS - settings/bondwidget.cpp - settings/bridgewidget.cpp - settings/btwidget.cpp - settings/cdmawidget.cpp - settings/connectionwidget.cpp - settings/gsmwidget.cpp - settings/infinibandwidget.cpp - settings/ipv4widget.cpp - settings/ipv6widget.cpp - settings/pppoewidget.cpp - settings/pppwidget.cpp - settings/security802-1x.cpp - settings/teamwidget.cpp - settings/vlanwidget.cpp - settings/wificonnectionwidget.cpp - settings/wifisecurity.cpp - settings/wiredconnectionwidget.cpp - settings/wiredsecurity.cpp - - widgets/advancedpermissionswidget.cpp - widgets/bssidcombobox.cpp - widgets/delegate.cpp - widgets/editlistdialog.cpp - widgets/hwaddrcombobox.cpp - widgets/intdelegate.cpp - widgets/ipv4delegate.cpp - widgets/ipv4routeswidget.cpp - widgets/ipv6delegate.cpp - widgets/ipv6routeswidget.cpp - widgets/passwordfield.cpp - widgets/settingwidget.cpp - widgets/ssidcombobox.cpp - - connectioneditorbase.cpp - connectioneditordialog.cpp - connectioneditortabwidget.cpp - listvalidator.cpp - simpleipv4addressvalidator.cpp - simpleipv6addressvalidator.cpp - vpnuiplugin.cpp - - ../configuration.cpp - ../debug.cpp - ../uiutils.cpp -) - -if (WITH_MODEMMANAGER_SUPPORT) - set(plasmanm_editor_SRCS - ${plasmanm_editor_SRCS} - widgets/mobileconnectionwizard.cpp - mobileproviders.cpp) -endif() - -ki18n_wrap_ui(plasmanm_editor_SRCS - settings/ui/802-1x.ui - settings/ui/bond.ui - settings/ui/bridge.ui - settings/ui/bt.ui - settings/ui/cdma.ui - settings/ui/connectionwidget.ui - settings/ui/gsm.ui - settings/ui/infiniband.ui - settings/ui/ipv4.ui - settings/ui/ipv6.ui - settings/ui/ppp.ui - settings/ui/pppoe.ui - settings/ui/team.ui - settings/ui/vlan.ui - settings/ui/team.ui - settings/ui/wificonnectionwidget.ui - settings/ui/wifisecurity.ui - settings/ui/wiredconnectionwidget.ui - settings/ui/wiredsecurity.ui - - widgets/ui/advancedpermissionswidget.ui - widgets/ui/ipv4routes.ui - widgets/ui/ipv6routes.ui - - connectioneditortabwidget.ui -) - -add_library(plasmanm_editor SHARED ${plasmanm_editor_SRCS}) -target_link_libraries(plasmanm_editor -PUBLIC - KF5::NetworkManagerQt - KF5::WidgetsAddons - KF5::Completion - Qt5::Widgets -PRIVATE - Qt5::Network - Qt5::DBus - qca-qt5 - KF5::I18n - KF5::KIOWidgets - KF5::IconThemes - KF5::Notifications - KF5::Wallet - KF5::Solid -) - -if (WITH_MODEMMANAGER_SUPPORT) - target_link_libraries(plasmanm_editor PUBLIC KF5::ModemManagerQt) -endif() - -install(TARGETS plasmanm_editor ${INSTALL_TARGETS_DEFAULT_ARGS}) -install(FILES plasma-networkmanagement-vpnuiplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) + + set(plasmanm_editor_SRCS + settings/bondwidget.cpp + settings/bridgewidget.cpp + settings/btwidget.cpp + settings/cdmawidget.cpp + settings/connectionwidget.cpp + settings/gsmwidget.cpp + settings/infinibandwidget.cpp + settings/ipv4widget.cpp + settings/ipv6widget.cpp + settings/pppoewidget.cpp + settings/pppwidget.cpp + settings/security802-1x.cpp + settings/teamwidget.cpp + settings/vlanwidget.cpp + settings/wificonnectionwidget.cpp + settings/wifisecurity.cpp + settings/wiredconnectionwidget.cpp + settings/wiredsecurity.cpp + + widgets/advancedpermissionswidget.cpp + widgets/bssidcombobox.cpp + widgets/delegate.cpp + widgets/editlistdialog.cpp + widgets/hwaddrcombobox.cpp + widgets/intdelegate.cpp + widgets/ipv4delegate.cpp + widgets/ipv4routeswidget.cpp + widgets/ipv6delegate.cpp + widgets/ipv6routeswidget.cpp + widgets/passwordfield.cpp + widgets/settingwidget.cpp + widgets/ssidcombobox.cpp + + connectioneditorbase.cpp + connectioneditordialog.cpp + connectioneditortabwidget.cpp + listvalidator.cpp + simpleipv4addressvalidator.cpp + simpleipv6addressvalidator.cpp + simpleiplistvalidator.cpp + vpnuiplugin.cpp + + ../configuration.cpp + ../debug.cpp + ../uiutils.cpp + ) + + if (WITH_MODEMMANAGER_SUPPORT) + set(plasmanm_editor_SRCS + ${plasmanm_editor_SRCS} + widgets/mobileconnectionwizard.cpp + mobileproviders.cpp) + endif() + + ki18n_wrap_ui(plasmanm_editor_SRCS + settings/ui/802-1x.ui + settings/ui/bond.ui + settings/ui/bridge.ui + settings/ui/bt.ui + settings/ui/cdma.ui + settings/ui/connectionwidget.ui + settings/ui/gsm.ui + settings/ui/infiniband.ui + settings/ui/ipv4.ui + settings/ui/ipv6.ui + settings/ui/ppp.ui + settings/ui/pppoe.ui + settings/ui/team.ui + settings/ui/vlan.ui + settings/ui/team.ui + settings/ui/wificonnectionwidget.ui + settings/ui/wifisecurity.ui + settings/ui/wiredconnectionwidget.ui + settings/ui/wiredsecurity.ui + + widgets/ui/advancedpermissionswidget.ui + widgets/ui/ipv4routes.ui + widgets/ui/ipv6routes.ui + + connectioneditortabwidget.ui + ) + + add_library(plasmanm_editor SHARED ${plasmanm_editor_SRCS}) + target_link_libraries(plasmanm_editor + PUBLIC + KF5::NetworkManagerQt + KF5::WidgetsAddons + KF5::Completion + Qt5::Widgets + PRIVATE + Qt5::Network + Qt5::DBus + qca-qt5 + KF5::I18n + KF5::KIOWidgets + KF5::IconThemes + KF5::Notifications + KF5::Wallet + KF5::Solid + ) + + if (WITH_MODEMMANAGER_SUPPORT) + target_link_libraries(plasmanm_editor PUBLIC KF5::ModemManagerQt) + endif() + + install(TARGETS plasmanm_editor ${INSTALL_TARGETS_DEFAULT_ARGS}) + install(FILES plasma-networkmanagement-vpnuiplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) diff --git a/libs/editor/simpleipv4addressvalidator.h b/libs/editor/simpleiplistvalidator.h copy from libs/editor/simpleipv4addressvalidator.h copy to libs/editor/simpleiplistvalidator.h --- a/libs/editor/simpleipv4addressvalidator.h +++ b/libs/editor/simpleiplistvalidator.h @@ -1,5 +1,5 @@ /* -Copyright 2009 Paul Marchouk +Copyright 2018 Bruce Anderson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -18,26 +18,31 @@ along with this program. If not, see . */ -#ifndef SIMPLEIPV4ADDRESSVALIDATOR_H -#define SIMPLEIPV4ADDRESSVALIDATOR_H +#ifndef SIMPLEIPLISTVALIDATOR_H +#define SIMPLEIPLISTVALIDATOR_H #include +#include "simpleipv4addressvalidator.h" +#include "simpleipv6addressvalidator.h" -class Q_DECL_EXPORT SimpleIpV4AddressValidator : public QValidator +class Q_DECL_EXPORT SimpleIpListValidator : public QValidator { public: - explicit SimpleIpV4AddressValidator(QObject *parent); - ~SimpleIpV4AddressValidator() override; + enum AddressType {Ipv4, Ipv6, Both}; + enum AddressStyle {Base, WithCidr}; + + explicit SimpleIpListValidator(QObject *parent, + AddressStyle style = AddressStyle::Base, + AddressType allow = AddressType::Both); + ~SimpleIpListValidator() override; State validate(QString &, int &) const override; - /** Check input value with a regular expression describing simple input mask. - */ - QValidator::State checkWithInputMask(QString &, int &) const; - /** Function split intput string into tetrads and check them for valid values. - * In the tetrads are placed into QList. Input string may be changed. - */ - QValidator::State checkTetradsRanges(QString &, QList&) const; +private: + AddressStyle addressStyle; + AddressType addressType; + SimpleIpV6AddressValidator *ipv6Validator; + SimpleIpV4AddressValidator *ipv4Validator; }; #endif // SIMPLEIPV4ADDRESSVALIDATOR_H diff --git a/libs/editor/simpleiplistvalidator.cpp b/libs/editor/simpleiplistvalidator.cpp new file mode 100644 --- /dev/null +++ b/libs/editor/simpleiplistvalidator.cpp @@ -0,0 +1,102 @@ +/* +Copyright 2018 Bruce Anderson + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of +the License or (at your option) version 3 or any later version +accepted by the membership of KDE e.V. (or its successor approved +by the membership of KDE e.V.), which shall act as a proxy +defined in Section 14 of version 3 of the license. + +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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "simpleiplistvalidator.h" + +#include +#include + +SimpleIpListValidator::SimpleIpListValidator(QObject *parent, + enum AddressStyle style, + enum AddressType type) + : QValidator(parent) +{ + addressStyle = style; + addressType = type; + ipv4Validator = nullptr; + ipv6Validator = nullptr; + + if (type == Ipv4 || type == Both) { + SimpleIpV4AddressValidator::AddressStyle ipv4Style; + if (style == Base) + ipv4Style = SimpleIpV4AddressValidator::AddressStyle::Base; + else + ipv4Style = SimpleIpV4AddressValidator::AddressStyle::WithCidr; + ipv4Validator = new SimpleIpV4AddressValidator(nullptr, ipv4Style); + } + if (type == Ipv6 || type == Both) { + SimpleIpV6AddressValidator::AddressStyle ipv6Style; + if (style == Base) + ipv6Style = SimpleIpV6AddressValidator::AddressStyle::Base; + else + ipv6Style = SimpleIpV6AddressValidator::AddressStyle::WithCidr; + ipv6Validator = new SimpleIpV6AddressValidator(nullptr, ipv6Style); + } +} + +SimpleIpListValidator::~SimpleIpListValidator() +{ +} + +QValidator::State SimpleIpListValidator::validate(QString &address, int &pos) const +{ + // Split the incoming address on commas possibly with spaces on either side + QStringList addressList = address.split(QRegExp("\\s*,\\s*")); + + // Use a local variable for position in the validators so it doesn't screw + // up the position of the cursor when we return + int localPos = 0; + int i = 0; + QValidator::State ipv4Result = QValidator::Acceptable; + QValidator::State ipv6Result = QValidator::Acceptable; + QValidator::State result = QValidator::Acceptable; + + Q_FOREACH (const QString &addr, addressList) { + ipv4Result = QValidator::Acceptable; + ipv6Result = QValidator::Acceptable; + + // See if it is an IPv4 address. If we are not testing for IPv4 + // then by definition IPv4 is Invalid + if (ipv4Validator != nullptr) + ipv4Result = ipv4Validator->validate(const_cast(addr), localPos); + else + ipv4Result = QValidator::Invalid; + + // See if it is an IPv6 address. If we are not testing for IPv6 + // then by definition IPv6 is Invalid + if (ipv6Validator != nullptr) + ipv6Result = ipv6Validator->validate(const_cast(addr), localPos); + else + ipv6Result = QValidator::Invalid; + + // If this address is not at least an Intermediate then get out because the list is Invalid + if (ipv6Result == QValidator::Invalid && ipv4Result == QValidator::Invalid) { + result = QValidator::Invalid; + break; + } + // If either validator judged this address to be Intermediate then that's the best the + // final result can be for the whole list. No need to test for Acceptable because + // that's the default set on entry and we only downgrade it from there. + if (ipv4Result == QValidator::Intermediate || ipv6Result == QValidator::Intermediate) + result = QValidator::Intermediate; + i++; + } + return result; +} diff --git a/libs/editor/simpleipv4addressvalidator.h b/libs/editor/simpleipv4addressvalidator.h --- a/libs/editor/simpleipv4addressvalidator.h +++ b/libs/editor/simpleipv4addressvalidator.h @@ -26,7 +26,9 @@ class Q_DECL_EXPORT SimpleIpV4AddressValidator : public QValidator { public: - explicit SimpleIpV4AddressValidator(QObject *parent); + enum AddressStyle {Base, WithCidr, WithPort}; + + explicit SimpleIpV4AddressValidator(QObject *parent, AddressStyle style = AddressStyle::Base); ~SimpleIpV4AddressValidator() override; State validate(QString &, int &) const override; @@ -38,6 +40,8 @@ * In the tetrads are placed into QList. Input string may be changed. */ QValidator::State checkTetradsRanges(QString &, QList&) const; +private: + AddressStyle addressStyle; }; #endif // SIMPLEIPV4ADDRESSVALIDATOR_H diff --git a/libs/editor/simpleipv4addressvalidator.cpp b/libs/editor/simpleipv4addressvalidator.cpp --- a/libs/editor/simpleipv4addressvalidator.cpp +++ b/libs/editor/simpleipv4addressvalidator.cpp @@ -23,9 +23,10 @@ #include #include -SimpleIpV4AddressValidator::SimpleIpV4AddressValidator(QObject *parent) +SimpleIpV4AddressValidator::SimpleIpV4AddressValidator(QObject *parent, enum AddressStyle style) : QValidator(parent) { + addressStyle = style; } SimpleIpV4AddressValidator::~SimpleIpV4AddressValidator() @@ -47,15 +48,47 @@ QValidator::State SimpleIpV4AddressValidator::checkWithInputMask(QString &value, int &pos) const { - QRegExpValidator v(QRegExp(QLatin1String("[0-9, ]{1,3}\\.[0-9, ]{1,3}\\.[0-9, ]{1,3}\\.[0-9, ]{1,3}")), nullptr); + QRegExpValidator *v; - return v.validate(value, pos); + switch (addressStyle) { + case Base: + v = new QRegExpValidator(QRegExp(QLatin1String("[0-9, ]{1,3}\\.[0-9, ]{1,3}\\.[0-9, ]{1,3}\\.[0-9, ]{1,3}")), 0); + break; + + case WithCidr: + v = new QRegExpValidator(QRegExp(QLatin1String("([0-9, ]{1,3}\\.){3,3}[0-9, ]{1,3}/[0-9]{1,2}")), 0); + break; + + case WithPort: + v = new QRegExpValidator(QRegExp(QLatin1String("([0-9, ]{1,3}\\.){3,3}[0-9, ]{1,3}:[0-9]{1,5}")), 0); + break; + } + return v->validate(value, pos); } QValidator::State SimpleIpV4AddressValidator::checkTetradsRanges(QString &value, QList &tetrads) const { QStringList temp; - const QVector addrParts = value.splitRef(QLatin1Char('.')); + QVector addrParts; + QStringList cidrParts; + QStringList portParts; + + switch (addressStyle) { + case Base: + addrParts = value.splitRef(QLatin1Char('.')); + break; + + case WithCidr: + cidrParts = value.split(QLatin1Char('/')); + addrParts = cidrParts[0].splitRef(QLatin1Char('.')); + break; + + case WithPort: + portParts = value.split(QLatin1Char(':')); + addrParts = portParts[0].splitRef(QLatin1Char('.')); + break; + } + int i = 0; // fill in the list with invalid values tetrads << -1 << -1 << -1 << -1; @@ -84,6 +117,7 @@ i++; } + // replace input string with the corrected version value = temp.join(QLatin1String(".")); @@ -93,6 +127,30 @@ return QValidator::Intermediate; } else { + if (addressStyle == WithCidr && cidrParts.size() > 1) { + value += QLatin1String("/"); + if (!cidrParts[1].isEmpty()) { + int cidrValue = cidrParts[1].toInt(); + if (cidrValue > 32) { + return QValidator::Invalid; + } else { + value += QString::number(cidrValue); + return QValidator::Acceptable; + } + } + } else if (addressStyle == WithPort && portParts.size() > 1) { + value += QLatin1String(":"); + if (!portParts[1].isEmpty()) { + int portValue = portParts[1].toInt(); + if (portValue > 65535) { + return QValidator::Invalid; + } else { + value += QString::number(portValue); + return QValidator::Acceptable; + } + } + } + // qCDebug(PLASMA_NM) << "QValidator::Acceptable"; return QValidator::Acceptable; } diff --git a/libs/editor/simpleipv6addressvalidator.h b/libs/editor/simpleipv6addressvalidator.h --- a/libs/editor/simpleipv6addressvalidator.h +++ b/libs/editor/simpleipv6addressvalidator.h @@ -26,7 +26,9 @@ class Q_DECL_EXPORT SimpleIpV6AddressValidator : public QValidator { public: - explicit SimpleIpV6AddressValidator(QObject *parent); + enum AddressStyle {Base, WithCidr}; + + explicit SimpleIpV6AddressValidator(QObject *parent, AddressStyle style = AddressStyle::Base); ~SimpleIpV6AddressValidator() override; State validate(QString &, int &) const override; @@ -38,6 +40,8 @@ * In the tetrads are placed into QList. Input string may be changed. */ QValidator::State checkTetradsRanges(QString &) const; +private: + AddressStyle addressStyle; }; #endif // SIMPLEIPV6ADDRESSVALIDATOR_H diff --git a/libs/editor/simpleipv6addressvalidator.cpp b/libs/editor/simpleipv6addressvalidator.cpp --- a/libs/editor/simpleipv6addressvalidator.cpp +++ b/libs/editor/simpleipv6addressvalidator.cpp @@ -21,10 +21,12 @@ #include "simpleipv6addressvalidator.h" #include +#include -SimpleIpV6AddressValidator::SimpleIpV6AddressValidator(QObject *parent) +SimpleIpV6AddressValidator::SimpleIpV6AddressValidator(QObject *parent, enum AddressStyle style) : QValidator(parent) { + addressStyle = style; } SimpleIpV6AddressValidator::~SimpleIpV6AddressValidator() @@ -42,14 +44,37 @@ QValidator::State SimpleIpV6AddressValidator::checkWithInputMask(QString &value, int &pos) const { - QRegExpValidator v(QRegExp(QLatin1String("([0-9a-fA-F]{1,4}|:)+")), nullptr); + QRegExpValidator *v; - return v.validate(value, pos); + switch (addressStyle) { + case Base: + v = new QRegExpValidator(QRegExp(QLatin1String("([0-9a-fA-F]{1,4}|:)+")), nullptr); + break; + + case WithCidr: + v = new QRegExpValidator(QRegExp(QLatin1String("([0-9a-fA-F]{1,4}|:)+/[0-9]{1,3}")), nullptr); + break; + } + + return v->validate(value, pos); } QValidator::State SimpleIpV6AddressValidator::checkTetradsRanges(QString &value) const { - const QStringList addrParts = value.split(QLatin1Char(':')); + QStringList addrParts; + QStringList cidrParts; + + switch (addressStyle) { + case Base: + addrParts = value.split(QLatin1Char(':')); + break; + + case WithCidr: + cidrParts = value.split(QLatin1Char('/')); + addrParts = cidrParts[0].split(QLatin1Char(':')); + break; + } + int number = addrParts.size(); if (number > 8) { return QValidator::Invalid; @@ -60,7 +85,7 @@ int i = 1; Q_FOREACH (QString part, addrParts) { // krazy:exclude=Q_FOREACH if (part.isEmpty() && i < number) { - if (emptypresent) { + if (emptypresent && i != 2) { // qCDebug(PLASMA_NM) << "part.isEmpty()"; return QValidator::Invalid; } @@ -78,8 +103,17 @@ } } - if (number < 8 && !emptypresent) + if (number < 8 && !emptypresent) { return QValidator::Intermediate; + } + else if (addressStyle == WithCidr && cidrParts.size() > 1) { + if (cidrParts[1].isEmpty()) + return QValidator::Intermediate; + + int cidrValue = cidrParts[1].toInt(); + if (cidrValue > 128) + return QValidator::Invalid; + } return QValidator::Acceptable; } diff --git a/libs/models/kcmidentitymodel.cpp b/libs/models/kcmidentitymodel.cpp --- a/libs/models/kcmidentitymodel.cpp +++ b/libs/models/kcmidentitymodel.cpp @@ -90,7 +90,9 @@ return tooltip; } else if (role == KcmVpnConnectionExportable) { if (type == NetworkManager::ConnectionSettings::Vpn && vpnSetting) { - return (vpnSetting->serviceType().endsWith(QLatin1String("vpnc")) || vpnSetting->serviceType().endsWith(QLatin1String("openvpn"))); + return (vpnSetting->serviceType().endsWith(QLatin1String("vpnc")) || + vpnSetting->serviceType().endsWith(QLatin1String("openvpn")) || + vpnSetting->serviceType().endsWith(QLatin1String("wireguard"))); } return false; } else { diff --git a/vpn/CMakeLists.txt b/vpn/CMakeLists.txt --- a/vpn/CMakeLists.txt +++ b/vpn/CMakeLists.txt @@ -11,4 +11,5 @@ add_subdirectory(sstp) add_subdirectory(strongswan) add_subdirectory(vpnc) +add_subdirectory(wireguard) diff --git a/vpn/wireguard/CMakeLists.txt b/vpn/wireguard/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/vpn/wireguard/CMakeLists.txt @@ -0,0 +1,34 @@ +add_definitions(-DTRANSLATION_DOMAIN=\"plasmanetworkmanagement_wireguardui\") + +set(wireguard_SRCS + ../../libs/debug.cpp + wireguard.cpp + wireguardwidget.cpp + wireguardauth.cpp + wireguardadvancedwidget.cpp +) + +ki18n_wrap_ui(wireguard_SRCS wireguard.ui wireguardadvanced.ui wireguardauth.ui) + +add_library(plasmanetworkmanagement_wireguardui ${wireguard_SRCS}) + +kcoreaddons_desktop_to_json(plasmanetworkmanagement_wireguardui plasmanetworkmanagement_wireguardui.desktop) + +target_link_libraries(plasmanetworkmanagement_wireguardui + plasmanm_internal + plasmanm_editor + Qt5::Widgets + Qt5::Network + Qt5::DBus + KF5::NetworkManagerQt + KF5::Service + KF5::Completion + KF5::I18n + KF5::WidgetsAddons + KF5::KIOWidgets + KF5::CoreAddons +) + +install(TARGETS plasmanetworkmanagement_wireguardui DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES plasmanetworkmanagement_wireguardui.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/vpn/wireguard/nm-wireguard-service.h b/vpn/wireguard/nm-wireguard-service.h new file mode 100644 --- /dev/null +++ b/vpn/wireguard/nm-wireguard-service.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-wireguard-service - WireGuard integration with NetworkManager + * + * Copyright 2018 Bruce Anderson + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef NM_WIREGUARD_SERVICE_H +#define NM_WIREGUARD_SERVICE_H + +#define NM_DBUS_SERVICE_WIREGUARD "org.freedesktop.NetworkManager.wireguard" +#define NM_DBUS_INTERFACE_WIREGUARD "org.freedesktop.NetworkManager.wireguard" +#define NM_DBUS_PATH_WIREGUARD "/org/freedesktop/NetworkManager/wireguard" + +#define NM_WG_KEY_ADDR_IP4 "local-ip4" +#define NM_WG_KEY_ADDR_IP6 "local-ip6" +#define NM_WG_KEY_LISTEN_PORT "local-listen-port" +#define NM_WG_KEY_PRIVATE_KEY "local-private-key" +#define NM_WG_KEY_DNS "connection-dns" +#define NM_WG_KEY_MTU "connection-mtu" +#define NM_WG_KEY_TABLE "connection_table" +#define NM_WG_KEY_PUBLIC_KEY "peer-public-key" +#define NM_WG_KEY_ALLOWED_IPS "peer-allowed-ips" +#define NM_WG_KEY_ENDPOINT "peer-endpoint" +#define NM_WG_KEY_PRESHARED_KEY "peer-preshared-key" +#define NM_WG_KEY_FWMARK "fwmark" + +#endif /* NM_WIREGUARD_SERVICE_H */ diff --git a/vpn/wireguard/plasmanetworkmanagement_wireguardui.desktop b/vpn/wireguard/plasmanetworkmanagement_wireguardui.desktop new file mode 100644 --- /dev/null +++ b/vpn/wireguard/plasmanetworkmanagement_wireguardui.desktop @@ -0,0 +1,17 @@ +[Desktop Entry] +Type=Service +Icon= +ServiceTypes=PlasmaNetworkManagement/VpnUiPlugin +X-KDE-Library=plasmanetworkmanagement_wireguardui +X-NetworkManager-Services=org.freedesktop.NetworkManager.wireguard +X-KDE-PluginInfo-Author=Bruce Anderson +X-KDE-PluginInfo-Email=banderson19com@san.rr.com +X-KDE-PluginInfo-Name=plasmanetworkmanagement_wireguardui +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category=VPNService +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=false +Name=WireGuard based VPN +Comment=Compatible with WireGuard VPN servers diff --git a/vpn/wireguard/wireguard.h b/vpn/wireguard/wireguard.h new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguard.h @@ -0,0 +1,44 @@ +/* + Copyright 2018 Bruce Anderson + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PLASMANM_WIREGUARD_H +#define PLASMANM_WIREGUARD_H + +#include "vpnuiplugin.h" + +#include +#include + +class Q_DECL_EXPORT WireGuardUiPlugin : public VpnUiPlugin +{ +Q_OBJECT +public: + explicit WireGuardUiPlugin(QObject *parent = nullptr, const QVariantList& = QVariantList()); + ~WireGuardUiPlugin() override; + SettingWidget *widget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent = nullptr) override; + SettingWidget *askUser(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent = nullptr) override; + + QString suggestedFileName(const NetworkManager::ConnectionSettings::Ptr &connection) const override; + QString supportedFileExtensions() const override; + NMVariantMapMap importConnectionSettings(const QString &fileName) override; + bool exportConnectionSettings(const NetworkManager::ConnectionSettings::Ptr &connection, const QString &fileName) override; +}; + +#endif // PLASMANM_WIREGUARD_H diff --git a/vpn/wireguard/wireguard.cpp b/vpn/wireguard/wireguard.cpp new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguard.cpp @@ -0,0 +1,308 @@ +/* + Copyright 2018 Bruce Anderson + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "wireguard.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wireguardwidget.h" +#include "wireguardauth.h" +#include "simpleipv4addressvalidator.h" +#include "simpleipv6addressvalidator.h" +#include "simpleiplistvalidator.h" + +#include "nm-wireguard-service.h" + +K_PLUGIN_FACTORY_WITH_JSON(WireGuardUiPluginFactory, "plasmanetworkmanagement_wireguardui.json", registerPlugin();) + +#define NMV_WG_TAG_INTERFACE "Interface" +#define NMV_WG_TAG_PRIVATE_KEY "PrivateKey" +#define NMV_WG_TAG_LISTEN_PORT "ListenPort" +#define NMV_WG_TAG_ADDRESS "Address" +#define NMV_WG_TAG_DNS "DNS" +#define NMV_WG_TAG_MTU "MTU" +#define NMV_WG_TAG_TABLE "Table" +#define NMV_WG_TAG_PRE_UP "PreUp" +#define NMV_WG_TAG_POST_UP "PostUp" +#define NMV_WG_TAG_PRE_DOWN "PreDown" +#define NMV_WG_TAG_POST_DOWN "PostDown" +#define NMV_WG_TAG_FWMARK "FwMark" + +#define NMV_WG_TAG_PEER "Peer" +#define NMV_WG_TAG_PUBLIC_KEY "PublicKey" +#define NMV_WG_TAG_ALLOWED_IPS "AllowedIPs" +#define NMV_WG_TAG_ENDPOINT "Endpoint" +#define NMV_WG_TAG_PRESHARED_KEY "PresharedKey" + + +WireGuardUiPlugin::WireGuardUiPlugin(QObject *parent, const QVariantList &) : VpnUiPlugin(parent) +{ +} + +WireGuardUiPlugin::~WireGuardUiPlugin() +{ +} + +SettingWidget *WireGuardUiPlugin::widget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent) +{ + return new WireGuardSettingWidget(setting, parent); +} + +SettingWidget *WireGuardUiPlugin::askUser(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent) +{ + return new WireGuardAuthWidget(setting, parent); +} + +QString WireGuardUiPlugin::suggestedFileName(const NetworkManager::ConnectionSettings::Ptr &connection) const +{ + return connection->id() + "_wireguard.conf"; +} + +QString WireGuardUiPlugin::supportedFileExtensions() const +{ + return "*.conf"; +} + +NMVariantMapMap WireGuardUiPlugin::importConnectionSettings(const QString &fileName) +{ + NMVariantMapMap result; + + const KConfig importFile(fileName, KConfig::NoGlobals); + const KConfigGroup interfaceGroup = importFile.group(NMV_WG_TAG_INTERFACE); + const KConfigGroup peerGroup = importFile.group(NMV_WG_TAG_PEER); + + // The config file must have both [Interface] and [Peer] sections + if (!interfaceGroup.exists() + || !peerGroup.exists()) { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("Invalid config file"); + return result; + } + + const QString connectionName = QFileInfo(fileName).completeBaseName(); + NMStringMap dataMap; + QVariantMap ipv4Data; + + QString value; + QStringList valueList; + quint32 intValue; + + // Do the required fields first and fail (i.e. return an empty result) if not present + + // Addresses + valueList = interfaceGroup.readEntry(NMV_WG_TAG_ADDRESS, QStringList()); + if (valueList.size() == 0) + return result; + for (int i = 0; i < valueList.size(); i++) { + QPair addressIn = QHostAddress::parseSubnet(valueList[i].trimmed()); + if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) + dataMap.insert(QLatin1String(NM_WG_KEY_ADDR_IP4), valueList[i]); + else if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv6Protocol) + dataMap.insert(QLatin1String(NM_WG_KEY_ADDR_IP6), valueList[i]); + else // Error condition + return result; + } + + // Private Key + value = interfaceGroup.readEntry(NMV_WG_TAG_PRIVATE_KEY); + if (!value.isEmpty()) { + QRegExp validatorRegex("[0-9a-zA-Z\\+/]{43,43}="); + if (validatorRegex.exactMatch(value)) + dataMap.insert(QLatin1String(NM_WG_KEY_PRIVATE_KEY), value); + else + return result; + } else { + return result; + } + + // Public Key + value = peerGroup.readEntry(NMV_WG_TAG_PUBLIC_KEY); + if (!value.isEmpty()) { + QRegExp validatorRegex("[0-9a-zA-Z\\+/]{43,43}="); + if (validatorRegex.exactMatch(value)) + dataMap.insert(QLatin1String(NM_WG_KEY_PUBLIC_KEY), value); + else + return result; + } else { + return result; + } + + // Allowed IPs + value = peerGroup.readEntry(NMV_WG_TAG_ALLOWED_IPS); + if (!value.isEmpty()) { + int pos = 0; + SimpleIpListValidator *validator = new SimpleIpListValidator(this, + SimpleIpListValidator::WithCidr, + SimpleIpListValidator::Both); + + if (validator->validate(value, pos) != QValidator::State::Invalid) + dataMap.insert(QLatin1String(NM_WG_KEY_ALLOWED_IPS), value); + else + return result; + } else { + return result; + } + + // Now the optional ones + + // Listen Port + intValue = interfaceGroup.readEntry(NMV_WG_TAG_LISTEN_PORT, 0); + if (intValue > 0) { + if (intValue < 65536) + dataMap.insert(QLatin1String(NM_WG_KEY_LISTEN_PORT), QString::number(intValue)); + else + return result; + } + + // DNS + value = interfaceGroup.readEntry(NMV_WG_TAG_DNS); + if (!value.isEmpty()) { + QHostAddress testAddress(value); + if (testAddress.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) + dataMap.insert(QLatin1String(NM_WG_KEY_DNS), value); + else + return result; + } + + // MTU + intValue = interfaceGroup.readEntry(NMV_WG_TAG_MTU, 0); + if (intValue > 0) { + if (intValue < 65536) + dataMap.insert(QLatin1String(NM_WG_KEY_LISTEN_PORT), QString::number(intValue)); + else + return result; + } + + // Table + value = interfaceGroup.readEntry(NMV_WG_TAG_TABLE); + if (!value.isEmpty()) { + dataMap.insert(QLatin1String(NM_WG_KEY_TABLE), value); + } + + // Endpoint + value = peerGroup.readEntry(NMV_WG_TAG_ENDPOINT); + if (!value.isEmpty()) + dataMap.insert(QLatin1String(NM_WG_KEY_ENDPOINT), value); + + // Preshared Key + value = peerGroup.readEntry(NMV_WG_TAG_PRESHARED_KEY); + if (!value.isEmpty()) { + QRegExp validatorRegex("[0-9a-zA-Z\\+/]{43,43}="); + QRegExpValidator validator(validatorRegex); + int pos = 0; + if (validator.validate(value, pos) != QValidator::State::Invalid) + dataMap.insert(QLatin1String(NM_WG_KEY_PRESHARED_KEY), value); + else + return result; + } + + NetworkManager::VpnSetting setting; + setting.setServiceType(QLatin1String(NM_DBUS_SERVICE_WIREGUARD)); + setting.setData(dataMap); + + QVariantMap conn; + conn.insert("id", connectionName); + conn.insert("type", "vpn"); + result.insert("connection", conn); + result.insert("vpn", setting.toMap()); + + return result; +} + +bool WireGuardUiPlugin::exportConnectionSettings(const NetworkManager::ConnectionSettings::Ptr &connection, const QString &fileName) +{ + NMStringMap dataMap; + NetworkManager::VpnSetting::Ptr vpnSetting = connection->setting(NetworkManager::Setting::Vpn).dynamicCast(); + dataMap = vpnSetting->data(); + + // Make sure all the required fields are present + if (!(dataMap.contains(QLatin1String(NM_WG_KEY_ADDR_IP4)) + || dataMap.contains(QLatin1String(NM_WG_KEY_ADDR_IP4))) + || !dataMap.contains(QLatin1String(NM_WG_KEY_PRIVATE_KEY)) + || !dataMap.contains(QLatin1String(NM_WG_KEY_PUBLIC_KEY)) + || !dataMap.contains(QLatin1String(NM_WG_KEY_ALLOWED_IPS))) + return false; + + // Open the output file + KConfig exportFile(fileName, KConfig::NoGlobals); + KConfigGroup interfaceGroup = exportFile.group(NMV_WG_TAG_INTERFACE); + KConfigGroup peerGroup = exportFile.group(NMV_WG_TAG_PEER); + + QString value; + + if (dataMap.contains(QLatin1String(NM_WG_KEY_ADDR_IP4))) { + value = dataMap[NM_WG_KEY_ADDR_IP4]; + if (dataMap.contains(QLatin1String(NM_WG_KEY_ADDR_IP6))) + value += "," + dataMap[NM_WG_KEY_ADDR_IP6]; + } else if (dataMap.contains(QLatin1String(NM_WG_KEY_ADDR_IP4))) { + value = dataMap[NM_WG_KEY_ADDR_IP4]; + } + interfaceGroup.writeEntry(NMV_WG_TAG_ADDRESS, value); + + // Do Private Key + interfaceGroup.writeEntry(NMV_WG_TAG_PRIVATE_KEY, dataMap[NM_WG_KEY_PRIVATE_KEY]); + + // Do DNS (Not required) + if (dataMap.contains(QLatin1String(NM_WG_KEY_DNS))) + interfaceGroup.writeEntry(NMV_WG_TAG_DNS, dataMap[NM_WG_KEY_DNS]); + + // Do MTU (Not required) + if (dataMap.contains(QLatin1String(NM_WG_KEY_MTU))) + interfaceGroup.writeEntry(NMV_WG_TAG_MTU, dataMap[NM_WG_KEY_MTU]); + + // Do Table number (Not required) + if (dataMap.contains(QLatin1String(NM_WG_KEY_TABLE))) + interfaceGroup.writeEntry(NMV_WG_TAG_TABLE, dataMap[NM_WG_KEY_TABLE]); + + // Do Listen Port (Not required) + if (dataMap.contains(QLatin1String(NM_WG_KEY_LISTEN_PORT))) + interfaceGroup.writeEntry(NMV_WG_TAG_LISTEN_PORT, dataMap[NM_WG_KEY_LISTEN_PORT]); + + // Do FwMark (Not required) + if (dataMap.contains(QLatin1String(NM_WG_KEY_FWMARK))) + interfaceGroup.writeEntry(NMV_WG_TAG_FWMARK, dataMap[NM_WG_KEY_FWMARK]); + + // Do Pupblic key (required) + peerGroup.writeEntry(NMV_WG_TAG_PUBLIC_KEY, dataMap[NM_WG_KEY_PUBLIC_KEY]); + + // Do Allowed IP list (Required) + peerGroup.writeEntry(NMV_WG_TAG_ALLOWED_IPS, dataMap[NM_WG_KEY_ALLOWED_IPS]); + + // Do Endpoint (Not required) + if (dataMap.contains(QLatin1String(NM_WG_KEY_ENDPOINT))) + peerGroup.writeEntry(NMV_WG_TAG_ENDPOINT, dataMap[NM_WG_KEY_ENDPOINT]); + + // Do Preshared Key (Not required) + if (dataMap.contains(QLatin1String(NM_WG_KEY_PRESHARED_KEY))) + peerGroup.writeEntry(NMV_WG_TAG_PRESHARED_KEY, dataMap[NM_WG_KEY_PRESHARED_KEY]); + + exportFile.sync(); + return true; +} + +#include "wireguard.moc" diff --git a/vpn/wireguard/wireguard.ui b/vpn/wireguard/wireguard.ui new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguard.ui @@ -0,0 +1,182 @@ + + + WireGuardProp + + + + 0 + 0 + 495 + 454 + + + + WireGuard Settings + + + + + + Interface + + + + + + Address (IPv4): + + + + + + + <html><head/><body><p>IPv4 Internet address assigned to the local interface. IPv4 or IPv6 address (or both) required</p></body></html> + + + + + + + Address (IPv6): + + + + + + + IPv6 Internet address assigned to the local interface. IPv4 or IPv6 address (or both) required + + + + + + + Private Key: + + + + + + + <html><head/><body><p>A base64 private key generated by wg genkey. Required.</p></body></html> + + + + + + + DNS: + + + + + + + <html><head/><body><p>IPv4 or IPv6 address to set and the interface's DNS server. Optional.</p></body></html> + + + + + + + + + + Peer + + + + + + Public Key: + + + + + + + <html><head/><body><p>A base64 public key calculated + by wg pubkey from a private key, and usually transmitted out of band to the author of the configuration file. Required.</p></body></html> + + + + + + + Allowed IPs: + + + + + + + <html><head/><body><p>A comma-separated list of IP (v4 or v6) addresses with CIDR masks from which incoming traffic for this peer is allowed and to which outgoing traffic for this peer is directed. The catch-all 0.0.0.0/0 may be specified for matching all IPv4 addresses, and ::/0 may be specified for matching all IPv6 addresses.</p></body></html> + + + + + + + Endpoint: + + + + + + + <html><head/><body><p>An endpoint IP followed by a colon, and then a port number. Optional.</p></body></html> + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Advanced... + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + PasswordField + QLineEdit +
passwordfield.h
+
+
+ + +
diff --git a/vpn/wireguard/wireguardadvanced.ui b/vpn/wireguard/wireguardadvanced.ui new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguardadvanced.ui @@ -0,0 +1,151 @@ + + + WireGuardAdvancedWidget + + + + 0 + 0 + 398 + 380 + + + + WireGuard Advanced + + + + + + Interface + + + + + + Listen Port: + + + + + + + <html><head/><body><p>Listen port number. Optional; if not specified, chosen randomly.</p></body></html> + + + Automatic + + + 65535 + + + + + + + MTU: + + + + + + + Table: + + + + + + + <html><head/><body><p>Controls the routing table to which routes are added. There are two special values: `off' disables the creation of routes altogether, and `auto' (the default) adds routes to the default table and enables special handling of default routes</p></body></html> + + + + + + + FwMark: + + + + + + + <html><head/><body><p>A 32-bit fwmark for outgoing packets. If set to 0 or &quot;off&quot;, this option is disabled. May be specified in hexadecimal by prepending &quot;0x&quot;. Optional.</p></body></html> + + + + + + + <html><head/><body><p>If not specified, the MTU is automatically determined from the endpoint addresses or the system default route, which is usually a sane choice. However, to manually specify an MTU to override this automatic discovery, this value may be specified explicitly.</p></body></html> + + + Automatic + + + 65535 + + + + + + + + + + Peer + + + + + + Preshared Key: + + + + + + + <html><head/><body><p>A base64 preshared key generated by wg genpsk. Optional. </p><p>This option adds an additional layer of symmetric-key cryptography to be mixed into the already existing public-key cryptography, for post-quantum resistance.</p></body></html>o + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + PasswordField + QLineEdit +
passwordfield.h
+
+
+ + +
diff --git a/vpn/wireguard/wireguardadvancedwidget.h b/vpn/wireguard/wireguardadvancedwidget.h new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguardadvancedwidget.h @@ -0,0 +1,62 @@ +/* + Copyright 2018 Bruce Anderson + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef PLASMA_NM_OPENVPN_ADVANCED_WIDGET_H +#define PLASMA_NM_OPENVPN_ADVANCED_WIDGET_H + +#include "passwordfield.h" + +#include +#include + +#include + +namespace Ui +{ +class WireGuardAdvancedWidget; +} + +class QLineEdit; +class WireGuardAdvancedWidget : public QDialog +{ + Q_OBJECT + + enum CertCheckType { + DontVerify = 0, + VerifyWholeSubjectExactly, + VerifyNameExactly, + VerifyNameByPrefix, + VerifySubjectPartially + }; + +public: + explicit WireGuardAdvancedWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent = 0); + ~WireGuardAdvancedWidget() override; + NetworkManager::VpnSetting::Ptr setting() const; + +private: + void loadConfig(); + void setOrClear(NMStringMap &data, QLatin1String key, QString value) const; + Ui::WireGuardAdvancedWidget *m_ui; + class Private; + Private *const d; +}; + +#endif // PLASMA_NM_OPENVPN_ADVANCED_WIDGET_H diff --git a/vpn/wireguard/wireguardadvancedwidget.cpp b/vpn/wireguard/wireguardadvancedwidget.cpp new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguardadvancedwidget.cpp @@ -0,0 +1,129 @@ +/* + Copyright 2018 Bruce Anderson + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#include "wireguardadvancedwidget.h" +#include "ui_wireguardadvanced.h" +#include "nm-wireguard-service.h" +#include "settingwidget.h" + +#include +#include +#include + +#include +#include +#include + +class WireGuardAdvancedWidget::Private { +public: + NetworkManager::VpnSetting::Ptr setting; +}; + +WireGuardAdvancedWidget::WireGuardAdvancedWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent) + : QDialog(parent) + , m_ui(new Ui::WireGuardAdvancedWidget) + , d(new Private) +{ + m_ui->setupUi(this); + + setWindowTitle(i18nc("@title: window advanced wireguard properties", "Advanced WireGuard properties")); + + d->setting = setting; + + connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &WireGuardAdvancedWidget::accept); + connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &WireGuardAdvancedWidget::reject); + + m_ui->presharedKeyLineEdit->setPasswordModeEnabled(true); + + QIntValidator *fwMarkValidator = new QIntValidator(0, 4294967295, nullptr); + m_ui->fwMarkLineEdit->setValidator(fwMarkValidator); + + KAcceleratorManager::manage(this); + + if (d->setting) { + loadConfig(); + } +} + +WireGuardAdvancedWidget::~WireGuardAdvancedWidget() +{ + delete d; +} + +void WireGuardAdvancedWidget::loadConfig() +{ + const NMStringMap dataMap = d->setting->data(); + + if (dataMap.contains(QLatin1String(NM_WG_KEY_LISTEN_PORT))) + m_ui->listenPortSpinBox->setValue(dataMap[NM_WG_KEY_LISTEN_PORT].toUInt()); + else + m_ui->listenPortSpinBox->setValue(0); + + if (dataMap.contains(QLatin1String(NM_WG_KEY_MTU))) + m_ui->mtuSpinBox->setValue(dataMap[NM_WG_KEY_MTU].toUInt()); + else + m_ui->mtuSpinBox->setValue(0); + + if (dataMap.contains(QLatin1String(NM_WG_KEY_TABLE))) + m_ui->tableLineEdit->setText(dataMap[NM_WG_KEY_TABLE]); + else + m_ui->tableLineEdit->clear(); + + if (dataMap.contains(QLatin1String(NM_WG_KEY_FWMARK))) + m_ui->fwMarkLineEdit->setText(dataMap[NM_WG_KEY_FWMARK]); + else + m_ui->fwMarkLineEdit->clear(); + + if (dataMap.contains(QLatin1String(NM_WG_KEY_PRESHARED_KEY))) + m_ui->presharedKeyLineEdit->setText(dataMap[NM_WG_KEY_PRESHARED_KEY]); + else + m_ui->presharedKeyLineEdit->setText(""); +} + +void WireGuardAdvancedWidget::setOrClear(NMStringMap &data, QLatin1String key, QString value) const +{ + if (!value.isEmpty()) + data.insert(key, value); + else + data.remove(key); +} + +NetworkManager::VpnSetting::Ptr WireGuardAdvancedWidget::setting() const +{ + NMStringMap data; + long intVal; + QString stringVal; + + intVal = m_ui->listenPortSpinBox->value(); + stringVal = (intVal > 0) ? QString::number(intVal) : QString(""); + setOrClear(data, QLatin1String(NM_WG_KEY_LISTEN_PORT), stringVal); + + intVal = m_ui->mtuSpinBox->value(); + stringVal = (intVal > 0) ? QString::number(intVal) : QString(""); + setOrClear(data, QLatin1String(NM_WG_KEY_MTU), stringVal); + + setOrClear(data, QLatin1String(NM_WG_KEY_TABLE), m_ui->tableLineEdit->displayText()); + setOrClear(data, QLatin1String(NM_WG_KEY_FWMARK), m_ui->fwMarkLineEdit->displayText()); + setOrClear(data, QLatin1String(NM_WG_KEY_PRESHARED_KEY), m_ui->presharedKeyLineEdit->text()); + + d->setting->setData(data); + + return d->setting; +} diff --git a/vpn/wireguard/wireguardauth.h b/vpn/wireguard/wireguardauth.h new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguardauth.h @@ -0,0 +1,43 @@ +/* + Copyright 2018 Bruce Anderson + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef WIREGUARDAUTH_H +#define WIREGUARDAUTH_H + +#include + +#include "settingwidget.h" + +class WireGuardAuthWidgetPrivate; + +class WireGuardAuthWidget : public SettingWidget +{ + Q_OBJECT + Q_DECLARE_PRIVATE(WireGuardAuthWidget) +public: + explicit WireGuardAuthWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent = 0); + ~WireGuardAuthWidget() override; + virtual QVariantMap setting() const override; + +private: + WireGuardAuthWidgetPrivate *const d_ptr; +}; + +#endif // WIREGUARDAUTH_H diff --git a/vpn/wireguard/wireguardauth.cpp b/vpn/wireguard/wireguardauth.cpp new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguardauth.cpp @@ -0,0 +1,57 @@ +/* + Copyright 2018 Bruce Anderson + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "wireguardauth.h" +#include "ui_wireguardauth.h" + +#include + +class WireGuardAuthWidgetPrivate +{ +public: + Ui_WireGuardAuth ui; + NetworkManager::VpnSetting::Ptr setting; +}; + +WireGuardAuthWidget::WireGuardAuthWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent) + : SettingWidget(setting, parent) + , d_ptr(new WireGuardAuthWidgetPrivate) +{ + Q_D(WireGuardAuthWidget); + d->ui.setupUi(this); + d->setting = setting; + + KAcceleratorManager::manage(this); +} + +WireGuardAuthWidget::~WireGuardAuthWidget() +{ + delete d_ptr; +} + + + +QVariantMap WireGuardAuthWidget::setting() const +{ + Q_D(const WireGuardAuthWidget); + + QVariantMap result; + return result; +} diff --git a/vpn/wireguard/wireguardauth.ui b/vpn/wireguard/wireguardauth.ui new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguardauth.ui @@ -0,0 +1,31 @@ + + + WireGuardAuth + + + + 0 + 0 + 263 + 51 + + + + + 6 + + + + + No WireGuard Secrets currently + + + false + + + + + + + + diff --git a/vpn/wireguard/wireguardwidget.h b/vpn/wireguard/wireguardwidget.h new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguardwidget.h @@ -0,0 +1,56 @@ +/* + Copyright 2018 Bruce Anderson + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef WIREGUARDWIDGET_H +#define WIREGUARDWIDGET_H + +#include "settingwidget.h" +#include "ui_wireguard.h" + +#include + +class QUrl; +class QLineEdit; + +class WireGuardSettingWidget : public SettingWidget +{ + Q_OBJECT +public: + explicit WireGuardSettingWidget(const NetworkManager::VpnSetting::Ptr &setting, + QWidget *parent = 0); + ~WireGuardSettingWidget() override; + + void loadConfig(const NetworkManager::Setting::Ptr &setting) override; + void loadSecrets(const NetworkManager::Setting::Ptr &setting) override; + + QVariantMap setting() const override; + + virtual bool isValid() const override; + +private Q_SLOTS: + void showAdvanced(); + +private: + class Private; + Private *d; + void setOrClear(NMStringMap &data, const QLatin1String &key, const QString &value) const; +}; + +#endif // WIREGUARDWIDGET_H diff --git a/vpn/wireguard/wireguardwidget.cpp b/vpn/wireguard/wireguardwidget.cpp new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguardwidget.cpp @@ -0,0 +1,188 @@ +/* + Copyright 2018 Bruce Anderson + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "debug.h" +#include "wireguardwidget.h" +#include "wireguardadvancedwidget.h" +#include "simpleipv4addressvalidator.h" +#include "simpleiplistvalidator.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "nm-wireguard-service.h" + +class WireGuardSettingWidget::Private +{ +public: + Ui_WireGuardProp ui; + NetworkManager::VpnSetting::Ptr setting; +}; + + +WireGuardSettingWidget::WireGuardSettingWidget(const NetworkManager::VpnSetting::Ptr &setting, + QWidget *parent) + : SettingWidget(setting, parent) + , d(new Private) +{ + qDBusRegisterMetaType(); + + d->ui.setupUi(this); + d->setting = setting; + + connect(d->ui.addressIPv4LineEdit, &QLineEdit::textChanged, this, &WireGuardSettingWidget::slotWidgetChanged); + connect(d->ui.addressIPv6LineEdit, &QLineEdit::textChanged, this, &WireGuardSettingWidget::slotWidgetChanged); + connect(d->ui.privateKeyLineEdit, &PasswordField::textChanged, this, &WireGuardSettingWidget::slotWidgetChanged); + connect(d->ui.publicKeyLineEdit, &QLineEdit::textChanged, this, &WireGuardSettingWidget::slotWidgetChanged); + connect(d->ui.allowedIPsLineEdit, &QLineEdit::textChanged, this, &WireGuardSettingWidget::slotWidgetChanged); + + d->ui.privateKeyLineEdit->setPasswordModeEnabled(true); + + connect(d->ui.btnAdvanced, &QPushButton::clicked, this, &WireGuardSettingWidget::showAdvanced); + + SimpleIpV4AddressValidator *ip4WithCidrValidator = new SimpleIpV4AddressValidator(this, SimpleIpV4AddressValidator::AddressStyle::WithCidr); + d->ui.addressIPv4LineEdit->setValidator(ip4WithCidrValidator); + + // Create a validator for the IPv6 address line edit + // Address must be a valid IP address with a CIDR suffix + SimpleIpV6AddressValidator *ip6WithCidrValidator = new SimpleIpV6AddressValidator(this, SimpleIpV6AddressValidator::AddressStyle::WithCidr); + + d->ui.addressIPv6LineEdit->setValidator(ip6WithCidrValidator); + + // Create a validator for the key lineEdits. + // Key is 43 Alpha-numeric or '+' or '/' followed by '=' + QRegExp keyRegex ("[0-9a-zA-Z\\+/]{43,43}="); + QRegExpValidator *keyValidator = new QRegExpValidator(keyRegex, this); + d->ui.publicKeyLineEdit->setValidator(keyValidator); + + // Create validator for DNS + SimpleIpV4AddressValidator *dnsValidator = new SimpleIpV4AddressValidator(this); + d->ui.dNSLineEdit->setValidator(dnsValidator); + + // Create validator for Endpoint + SimpleIpV4AddressValidator *endpointValidator = new SimpleIpV4AddressValidator(this, SimpleIpV4AddressValidator::AddressStyle::WithPort); + d->ui.endpointLineEdit->setValidator(endpointValidator); + + // Create validator for AllowedIPs + SimpleIpListValidator *allowedIPsValidator = new SimpleIpListValidator(this, + SimpleIpListValidator::WithCidr, + SimpleIpListValidator::Both); + d->ui.allowedIPsLineEdit->setValidator(allowedIPsValidator); + + // Connect for setting check + watchChangedSetting(); + + KAcceleratorManager::manage(this); + + if (setting && !setting->isNull()) { + loadConfig(d->setting); + } +} + +WireGuardSettingWidget::~WireGuardSettingWidget() +{ + delete d; +} + +void WireGuardSettingWidget::loadConfig(const NetworkManager::Setting::Ptr &setting) +{ + Q_UNUSED(setting) + // General settings + const NMStringMap dataMap = d->setting->data(); + + d->ui.addressIPv4LineEdit->setText(dataMap[NM_WG_KEY_ADDR_IP4]); + d->ui.addressIPv6LineEdit->setText(dataMap[NM_WG_KEY_ADDR_IP6]); + d->ui.privateKeyLineEdit->setText(dataMap[NM_WG_KEY_PRIVATE_KEY]); + d->ui.dNSLineEdit->setText(dataMap[NM_WG_KEY_DNS]); + d->ui.publicKeyLineEdit->setText(dataMap[NM_WG_KEY_PUBLIC_KEY]); + d->ui.allowedIPsLineEdit->setText(dataMap[NM_WG_KEY_ALLOWED_IPS]); + d->ui.endpointLineEdit->setText(dataMap[NM_WG_KEY_ENDPOINT]); +} + +void WireGuardSettingWidget::loadSecrets(const NetworkManager::Setting::Ptr &setting) +{ + // Currently WireGuard does not have any secrets +} + +QVariantMap WireGuardSettingWidget::setting() const +{ + NMStringMap data = d->setting->data(); + NetworkManager::VpnSetting setting; + setting.setServiceType(QLatin1String(NM_DBUS_SERVICE_WIREGUARD)); + + // required settings + + setOrClear(data, QLatin1String(NM_WG_KEY_ADDR_IP4), d->ui.addressIPv4LineEdit->displayText()); + setOrClear(data, QLatin1String(NM_WG_KEY_ADDR_IP6), d->ui.addressIPv6LineEdit->displayText()); + setOrClear(data, QLatin1String(NM_WG_KEY_PRIVATE_KEY), d->ui.privateKeyLineEdit->text()); + setOrClear(data, QLatin1String(NM_WG_KEY_PUBLIC_KEY), d->ui.publicKeyLineEdit->displayText()); + setOrClear(data, QLatin1String(NM_WG_KEY_ALLOWED_IPS), d->ui.allowedIPsLineEdit->displayText()); + setOrClear(data, QLatin1String(NM_WG_KEY_DNS), d->ui.dNSLineEdit->displayText()); + setOrClear(data, QLatin1String(NM_WG_KEY_ENDPOINT), d->ui.endpointLineEdit->displayText()); + + setting.setData(data); + + return setting.toMap(); +} + +void WireGuardSettingWidget::setOrClear(NMStringMap &data, const QLatin1String &key, const QString &value) const +{ + if (!value.isEmpty()) + data.insert(key, value); + else + data.remove(key); +} + +void WireGuardSettingWidget::showAdvanced() +{ + QPointer adv = new WireGuardAdvancedWidget(d->setting, this); + + connect(adv.data(), &WireGuardAdvancedWidget::accepted, + [adv, this] () { + NetworkManager::VpnSetting::Ptr advData = adv->setting(); + if (!advData.isNull()) { + d->setting->setData(advData->data()); + } + }); + connect(adv.data(), &WireGuardAdvancedWidget::finished, + [adv] () { + if (adv) { + adv->deleteLater(); + } + }); + adv->setModal(true); + adv->show(); +} + +bool WireGuardSettingWidget::isValid() const +{ + return ( (!d->ui.addressIPv4LineEdit->displayText().isEmpty() + || !d->ui.addressIPv6LineEdit->displayText().isEmpty()) + && (!d->ui.privateKeyLineEdit->text().isEmpty()) + && (!d->ui.publicKeyLineEdit->displayText().isEmpty()) + && (!d->ui.allowedIPsLineEdit->displayText().isEmpty())); +} +