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,199 @@ + + + WireGuardProp + + + + 0 + 0 + 495 + 454 + + + + WireGuard Settings + + + + + + Interface + + + + + + Address (IPv4): + + + + + + + IPv4 Internet address with possible +CIDR (example: 10.22.13.123/32) +assigned to the local interface. +IPv4 or IPv6 address (or both) required + + + + + + + Address (IPv6): + + + + + + + IPv6 Internet address with possible +CIDR assigned to the local interface. +(example: fc00:aaaa:aaaa:aa03::1bc9/128) +IPv4 or IPv6 address (or both) required + + + + + + + Private key: + + + + + + + Required. +A base64 private key generated by wg genkey. + + + + + + + DNS: + + + + + + + Optional. +IPv4 or IPv6 address to set the interface's DNS server. + + + + + + + + + + Peer + + + + + + Public key: + + + + + + + Required. +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. + + + + + + + Allowed IPs: + + + + + + + Required. +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. + + + + + + + Endpoint: + + + + + + + Optional. +An endpoint IP followed by a colon, and then a port number. + + + + + + + + + + + + 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,167 @@ + + + WireGuardAdvancedWidget + + + + 0 + 0 + 398 + 380 + + + + WireGuard Advanced + + + + + + Interface + + + + + + Listen port: + + + + + + + Listen port number. Chosen randomly if left as 'Automatic'. + + + Automatic + + + 65535 + + + + + + + MTU: + + + + + + + Table: + + + + + + + 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 + + + + + + + FwMark: + + + + + + + Optional. +An fwmark for outgoing packets. If set to 0 or 'off', this +option is disabled. May be specified in hexadecimal by +prepending '0x'. + + + + + + + Optional. +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 and to override this automatic discovery, +this value may be specified explicitly. + + + Automatic + + + 65535 + + + + + + + + + + Peer + + + + + + Preshared key: + + + + + + + Optional. +A base64 preshared key generated by wg genpsk. +This option adds an additional layer of symmetric-key +cryptography to be mixed into the already existing +public-key cryptography, for post-quantum resistance. + + + + + + + + + + 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())); +} +