diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ Network Quick Widgets + Test ) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED @@ -95,5 +96,6 @@ add_subdirectory(kcm) add_subdirectory(libs) add_subdirectory(vpn) +add_subdirectory(tests) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) 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,29 @@ 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, WithPort}; + + 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: + SimpleIpV6AddressValidator *m_ipv6Validator; + SimpleIpV4AddressValidator *m_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,107 @@ +/* +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, + AddressStyle style, + AddressType type) + : QValidator(parent) +{ + if (type == Ipv4 || type == Both) { + SimpleIpV4AddressValidator::AddressStyle ipv4Style; + if (style == Base) + ipv4Style = SimpleIpV4AddressValidator::AddressStyle::Base; + else if (style == WithCidr) + ipv4Style = SimpleIpV4AddressValidator::AddressStyle::WithCidr; + else + ipv4Style = SimpleIpV4AddressValidator::AddressStyle::WithPort; + m_ipv4Validator = new SimpleIpV4AddressValidator(this, ipv4Style); + } + if (type == Ipv6 || type == Both) { + SimpleIpV6AddressValidator::AddressStyle ipv6Style; + if (style == Base) + ipv6Style = SimpleIpV6AddressValidator::AddressStyle::Base; + else if (style == WithCidr) + ipv6Style = SimpleIpV6AddressValidator::AddressStyle::WithCidr; + else + ipv6Style = SimpleIpV6AddressValidator::AddressStyle::WithPort; + m_ipv6Validator = new SimpleIpV6AddressValidator(this, ipv6Style); + } +} + +SimpleIpListValidator::~SimpleIpListValidator() +{ +} + +QValidator::State SimpleIpListValidator::validate(QString &address, int &pos) const +{ + Q_UNUSED(pos) + + // Split the incoming address on commas possibly with spaces on either side + QStringList addressList = address.split(QRegularExpression("\\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 result = QValidator::Acceptable; + + for (QString &addr : addressList) { + QValidator::State ipv4Result = QValidator::Acceptable; + QValidator::State ipv6Result = QValidator::Acceptable; + + // If we are starting a new address and all the previous addressess + // ar not Acceptable then the previous addresses need to be completed + // before a new one is started + if (result != QValidator::Acceptable) + return QValidator::Invalid; + + // See if it is an IPv4 address. If we are not testing for IPv4 + // then by definition IPv4 is Invalid + if (m_ipv4Validator != nullptr) + ipv4Result = m_ipv4Validator->validate(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 (m_ipv6Validator != nullptr) + ipv6Result = m_ipv6Validator->validate(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) + return QValidator::Invalid; + + // 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 (result != QValidator::Invalid + && (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,9 @@ * In the tetrads are placed into QList. Input string may be changed. */ QValidator::State checkTetradsRanges(QString &, QList&) const; +private: + AddressStyle m_addressStyle; + QRegularExpressionValidator m_validator; }; #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,21 @@ #include #include -SimpleIpV4AddressValidator::SimpleIpV4AddressValidator(QObject *parent) +SimpleIpV4AddressValidator::SimpleIpV4AddressValidator(QObject *parent, AddressStyle style) : QValidator(parent) + , m_addressStyle(style) { + switch (style) { + case Base: + m_validator.setRegularExpression(QRegularExpression(QLatin1String("[0-9, ]{1,3}\\.[0-9, ]{1,3}\\.[0-9, ]{1,3}\\.[0-9, ]{1,3}"))); + break; + case WithCidr: + m_validator.setRegularExpression(QRegularExpression(QLatin1String("([0-9, ]{1,3}\\.){3,3}[0-9, ]{1,3}/[0-9]{1,2}"))); + break; + case WithPort: + m_validator.setRegularExpression(QRegularExpression(QLatin1String("([0-9, ]{1,3}\\.){3,3}[0-9, ]{1,3}:[0-9]{1,5}"))); + break; + } } SimpleIpV4AddressValidator::~SimpleIpV4AddressValidator() @@ -47,21 +59,38 @@ 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); - - return v.validate(value, pos); + return m_validator.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 (m_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; // lets check address parts - Q_FOREACH (const QStringRef &part, addrParts) { + for (const QStringRef &part : addrParts) { if (part.isEmpty()) { if (i != (addrParts.size() - 1)) { // qCDebug(PLASMA_NM) << "part.isEmpty()"; @@ -93,6 +122,40 @@ return QValidator::Intermediate; } else { + if (m_addressStyle == WithCidr) { + if (cidrParts.size() > 1) { + value += QLatin1String("/"); + if (!cidrParts[1].isEmpty()) { + int cidrValue = cidrParts[1].toInt(); + if (cidrValue > 32) { + return QValidator::Invalid; + } else { + value += cidrParts[1]; + return QValidator::Acceptable; + } + } + else { + return QValidator::Intermediate; + } + } + } else if (m_addressStyle == WithPort) { + if (portParts.size() > 1) { + value += QLatin1String(":"); + if (!portParts[1].isEmpty()) { + int portValue = portParts[1].toInt(); + if (portValue > 65535) { + return QValidator::Invalid; + } else { + value += portParts[1]; + return QValidator::Acceptable; + } + } + else { + return QValidator::Intermediate; + } + } + } + // 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,51 +21,108 @@ #include "simpleipv6addressvalidator.h" #include +#include -SimpleIpV6AddressValidator::SimpleIpV6AddressValidator(QObject *parent) +SimpleIpV6AddressValidator::SimpleIpV6AddressValidator(QObject *parent, AddressStyle style) : QValidator(parent) + , m_addressStyle(style) { + switch (style) { + case Base: + m_validator.setRegularExpression(QRegularExpression(QLatin1String("([0-9a-fA-F]{1,4}|:)+"))); + break; + case WithCidr: + m_validator.setRegularExpression(QRegularExpression(QLatin1String("([0-9a-fA-F]{1,4}|:){2,15}/[0-9]{1,3}"))); + break; + case WithPort: + m_validator.setRegularExpression(QRegularExpression(QLatin1String("\\[([0-9a-fA-F]{1,4}|:)+\\]:[0-9]{1,5}"))); + } } SimpleIpV6AddressValidator::~SimpleIpV6AddressValidator() { } QValidator::State SimpleIpV6AddressValidator::validate(QString &address, int &pos) const { - if (QValidator::Invalid == checkWithInputMask(address, pos)) { + if (QValidator::Invalid == checkWithInputMask(address, pos)) return QValidator::Invalid; - } return checkTetradsRanges(address); } QValidator::State SimpleIpV6AddressValidator::checkWithInputMask(QString &value, int &pos) const { - QRegExpValidator v(QRegExp(QLatin1String("([0-9a-fA-F]{1,4}|:)+")), nullptr); - - return v.validate(value, pos); + return m_validator.validate(value, pos); } QValidator::State SimpleIpV6AddressValidator::checkTetradsRanges(QString &value) const { - const QStringList addrParts = value.split(QLatin1Char(':')); + QStringList addrParts; + QStringList cidrParts; + QStringList portParts; + bool foundBracket = false; + QValidator::State result = QValidator::Acceptable; + + switch (m_addressStyle) { + case Base: + addrParts = value.split(QLatin1Char(':')); + break; + + case WithCidr: + cidrParts = value.split(QLatin1Char('/')); + addrParts = cidrParts[0].split(QLatin1Char(':')); + break; + + case WithPort: + if (value.isEmpty()) + return QValidator::Intermediate; + if (value[0] != '[') { + return QValidator::Invalid; + } else { + // Input: "[1:2:3:4:5:6:7:8]:123" + // bracketParts: "[1:2:3:4:5:6:7:8" , ":123" + // addrParts: "" , "1:2:3:4:5:6:7:8" + // portParts: "", "123" + QStringList bracketParts = value.split(QLatin1Char(']')); + if (bracketParts.size() < 2) + portParts = QStringList(); + else { + foundBracket = true; + if (!bracketParts[1].isEmpty() && bracketParts[1][0] != ':') + return QValidator::Invalid; + else + portParts = bracketParts[1].split(QLatin1Char(':')); + } + addrParts = bracketParts[0].split(QLatin1Char('['))[1].split(QLatin1Char(':')); + } + } + int number = addrParts.size(); - if (number > 8) { + // There is no case where can be more than 8 colons (9 parts) + // and only one unusual case where there are 8 colons (1:2:3:4:5:6:7::) + if (number > 9) + return QValidator::Invalid; + else if (number == 9 && (!addrParts[7].isEmpty() || !addrParts[8].isEmpty())) return QValidator::Invalid; - } // lets check address parts bool emptypresent = false; int i = 1; - Q_FOREACH (QString part, addrParts) { // krazy:exclude=Q_FOREACH + for (QString part : addrParts) { // krazy:exclude=Q_FOREACH if (part.isEmpty() && i < number) { - if (emptypresent) { + // There is only one case where you can have 3 empty parts + // and that is when you have the string: "::" which is valid + // and useful and of course it can also be extended to ::123 for + // instance. Anywhere other than the beginning though, having 3 empty + // parts indicates either a run of 3 colons ("1:::6")" or two sets of + // 2 colons ("1:2::3:4::") which are always invalid + if (emptypresent && i != 2) { // qCDebug(PLASMA_NM) << "part.isEmpty()"; return QValidator::Invalid; - } - else if (!emptypresent) - { + } else { + // If this is an empty part then set it to zero to not fail + // the next test part.setNum(0,16); emptypresent = true; } @@ -78,8 +135,52 @@ } } - if (number < 8 && !emptypresent) - return QValidator::Intermediate; + // A special case: a single colon needs to be Intermediate not Acceptable + if (number == 2 && addrParts[0].isEmpty() && addrParts[1].isEmpty()) + result = QValidator::Intermediate; + + // Another special case: a single colon followed by something (i.e. ":123" + // is invalid + else if (number > 1 && addrParts[0].isEmpty() && !addrParts[1].isEmpty()) + result = QValidator::Invalid; + + // If we don't have 8 parts yet and none of them are empty we aren't done yet + else if (number < 8 && !emptypresent) + result = QValidator::Intermediate; + + // If we have 8 parts but the last one is empty we aren't done yet + else if (number == 8 && addrParts[7].isEmpty()) + result = QValidator::Intermediate; - return QValidator::Acceptable; + if (m_addressStyle == WithCidr) { + int cidrSize = cidrParts.size(); + + // If we have a '/' and the basic address portion is not + // yet complete (i.e. Intermediate) then the whole thing is Invalid + if (cidrSize == 2 && result == QValidator::Intermediate) + return QValidator::Invalid; + + if (cidrSize == 1 || (cidrSize == 2 && cidrParts[1].isEmpty())) + return QValidator::Intermediate; + + int cidrValue = cidrParts[1].toInt(); + if (cidrValue > 128) + return QValidator::Invalid; + } else if (m_addressStyle == WithPort) { + int portSize = portParts.size(); + + // If we have a ']' and the basic address portion is not + // yet complete (i.e. Intermediate) then the whole thing is Invalid + if (foundBracket && result == QValidator::Intermediate) + return QValidator::Invalid; + + if (portSize < 2 || (portSize == 2 && portParts[1].isEmpty())) { + return QValidator::Intermediate; + } else { + int portValue = portParts[1].toInt(); + if (portValue > 65535) + return QValidator::Invalid; + } + } + return result; } 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/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,51 @@ +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) + +include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +########### next target ############### + +include(ECMAddTests) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -ggdb") + +set(simpleipv6test_SRCS simpleipv6test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../libs/editor/simpleipv6addressvalidator.cpp ) + +add_executable(simpleipv6test ${simpleipv6test_SRCS}) +add_test(simpleipv6 simpleipv6test) +ecm_mark_as_test(simpleipv6test) + +target_link_libraries(simpleipv6test + Qt5::Test + Qt5::Widgets + KF5::ConfigCore + KF5::CoreAddons) +add_library(simpleipv6test_SRCS) + +set(simpleipv4test_SRCS simpleipv4test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../libs/editor/simpleipv4addressvalidator.cpp ) + +add_executable(simpleipv4test ${simpleipv4test_SRCS}) +add_test(simpleipv4 simpleipv4test) +ecm_mark_as_test(simpleipv4test) + +target_link_libraries(simpleipv4test + Qt5::Test + Qt5::Widgets + KF5::ConfigCore + KF5::CoreAddons) +add_library(simpleipv4test_SRCS) + +set(simpleiplisttest_SRCS simpleiplisttest.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/editor/simpleipv4addressvalidator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/editor/simpleipv6addressvalidator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/editor/simpleiplistvalidator.cpp ) + +add_executable(simpleiplisttest ${simpleiplisttest_SRCS}) +add_test(simpleiplist simpleiplisttest) +ecm_mark_as_test(simpleiplisttest) + +target_link_libraries(simpleiplisttest + Qt5::Test + Qt5::Widgets + KF5::ConfigCore + KF5::CoreAddons) +add_library(simpleiplisttest_SRCS) diff --git a/tests/simpleiplisttest.cpp b/tests/simpleiplisttest.cpp new file mode 100644 --- /dev/null +++ b/tests/simpleiplisttest.cpp @@ -0,0 +1,152 @@ +/* +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 + +class SimpleipListTest : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void baseTest(); + void cidrTest(); + void portTest(); + +private: + SimpleIpListValidator* vb; + SimpleIpListValidator* vc; + SimpleIpListValidator* vp; +}; + +void SimpleipListTest::initTestCase() +{ + vb = new SimpleIpListValidator(nullptr, SimpleIpListValidator::AddressStyle::Base); + vc = new SimpleIpListValidator(nullptr, SimpleIpListValidator::AddressStyle::WithCidr); + vp = new SimpleIpListValidator(nullptr, SimpleIpListValidator::AddressStyle::WithPort); +} + +void SimpleipListTest::baseTest() +{ + int pos = 0; + // Null string is intermediate because it's waiting for input + QString tstr(""); + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.12.2"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.12.2,"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "123.45.22.9"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "123.45.22.9,"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.45.22.9, "; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.45.22,"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "123.45.22.9, BBEf:0112"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.45.22.9, BBEf:0112::1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "123.45.22.9, BBEf:0112:,"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "123.45.22.9, BBEf:0112::1,"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.45.22.9, BBEf:0112::1/123,"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "123.45.22.9, BBEf:0112::1,1.2.3.4"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); +} + +void SimpleipListTest::cidrTest() +{ + int pos = 0; + + QString tstr("10.77.18.4/32"); + QVERIFY(vc->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "10.77.18.4/32,"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "10.77.18.4/32,Be00:e00:0:"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "10.77.18.4/32,Be00:e00:0:21/3"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); + + tstr = "10.77.18.4/32,Be00:e00::0:21/128"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "10.77.18.4/32,Be00:e00::0:21/129"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); +} + +void SimpleipListTest::portTest() +{ + int pos = 0; + + QString tstr("10.77.18.4:32"); + QVERIFY(vp->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "10.77.18.4:,"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); + + tstr = "10.77.18.4:234, 1"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "10.77.18.4:234, 1b"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); + + tstr = "10.77.18.4:234, [1b"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "10.77.18.4:234, [10:33:22::1"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "10.77.18.4:234, [10:33:22::1]"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "10.77.18.4:234, [10:33:22::1]:"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "10.77.18.4:234, [10:33:22::1]:22"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "10.77.18.4:234, [10:33:22::1]:22,12.23.34.45:65535"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Acceptable); +} + +QTEST_GUILESS_MAIN(SimpleipListTest) + +#include "simpleiplisttest.moc" diff --git a/tests/simpleipv4test.cpp b/tests/simpleipv4test.cpp new file mode 100644 --- /dev/null +++ b/tests/simpleipv4test.cpp @@ -0,0 +1,193 @@ +/* +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 "simpleipv4addressvalidator.h" +#include +#include + +class SimpleIpv4Test : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void baseTest(); + void cidrTest(); + void portTest(); + +private: + SimpleIpV4AddressValidator* vb; + SimpleIpV4AddressValidator* vc; + SimpleIpV4AddressValidator* vp; +}; + +void SimpleIpv4Test::initTestCase() +{ + vb = new SimpleIpV4AddressValidator(nullptr, SimpleIpV4AddressValidator::AddressStyle::Base); + vc = new SimpleIpV4AddressValidator(nullptr, SimpleIpV4AddressValidator::AddressStyle::WithCidr); + vp = new SimpleIpV4AddressValidator(nullptr, SimpleIpV4AddressValidator::AddressStyle::WithPort); +} + +void SimpleIpv4Test::baseTest() +{ + int pos = 0; + // Null string is intermediate because it's waiting for input + QString tstr(""); + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + // Verify that all acceptable characters pass + tstr = "123.12.2"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.45.22.9"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + // Verify various lengths + tstr = "1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "12"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123."; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.4"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.54"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.54."; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.255"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.255."; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.123.9"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.34.99"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123.22.233"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "255.255.255."; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1.1.1.7"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "12a"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "255"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "256"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "255.255.255.255"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "256.255.255.255"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "255.256.255.255"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "255.255.256.255"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "255.255.255.256"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "1.1.1.1."; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); +} + +void SimpleIpv4Test::cidrTest() +{ + int pos = 0; + + QString tstr("10.77.18.4/32"); + QVERIFY(vc->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "10.77.18.4/33"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); + + tstr = "10.77.13/"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); + + tstr = "33.22.55.44/"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "11.23.45./"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); + + tstr = "0.0.0.0/0"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1.2.3.4/28/"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); + + tstr = "1.2.3.4//"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); +} + +void SimpleIpv4Test::portTest() +{ + int pos = 0; + + QString tstr("10.77.18.4:32"); + QVERIFY(vp->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "10.77.18.4:65536"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); + + tstr = "10.77.13:"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); + + tstr = "33.22.55.44:"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "11.23.45.:"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); + + tstr = "0.0.0.0:65535"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1.2.3.4:0:"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); + + tstr = "1.2.3.4::"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); +} + +QTEST_GUILESS_MAIN(SimpleIpv4Test) + +#include "simpleipv4test.moc" diff --git a/tests/simpleipv6test.cpp b/tests/simpleipv6test.cpp new file mode 100644 --- /dev/null +++ b/tests/simpleipv6test.cpp @@ -0,0 +1,316 @@ +/* +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 "simpleipv6addressvalidator.h" +#include +#include + +class SimpleIpv6Test : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void baseTest(); + void cidrTest(); + void portTest(); + +private: + SimpleIpV6AddressValidator* vb; + SimpleIpV6AddressValidator* vc; + SimpleIpV6AddressValidator* vp; +}; + +void SimpleIpv6Test::initTestCase() +{ + vb = new SimpleIpV6AddressValidator(nullptr, SimpleIpV6AddressValidator::AddressStyle::Base); + vc = new SimpleIpV6AddressValidator(nullptr, SimpleIpV6AddressValidator::AddressStyle::WithCidr); + vp = new SimpleIpV6AddressValidator(nullptr, SimpleIpV6AddressValidator::AddressStyle::WithPort); +} + +void SimpleIpv6Test::baseTest() +{ + int pos = 0; + // Null string is intermediate because it's waiting for input + QString tstr(""); + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + // Verify that all acceptable characters pass + tstr = "0123:4567:89ab:cdef"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "0123:4567:89ab:cdef:0123:4567:89ab:cdef"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + // Verify various lengths + tstr = "1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "12"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "123"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:12"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:123"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:12"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:123"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:12"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:123"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:12"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:123"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:12"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:123"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:1234"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:1234:"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:1234:1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:1234:12"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:1234:123"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:1234:1234"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:1234:1234:1234:1234:1234:1234:"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate);; + + tstr = "1234:1234:1234:1234:1234:1234:1234:1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1234:1234:1234:1234:1234:1234:1234:12"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1234:1234:1234:1234:1234:1234:1234:123"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1234:1234:1234:1234:1234:1234:1234:1234"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + // verify a few :: cases + tstr = ":"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "::"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "::1:2:3:4"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1::2:3:4"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1:2345::6:7"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1:2:3::1:1:1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1:2:3:4::1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1:2:3:4:5::1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1:2:3:4:5:6::1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1:2:3:4:5:6:7::"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1::"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "::1:2:3:4"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "::1:2:3::4"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "1:2::3:4:5:6:7:"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "1:2::3:4:5:6:7:8"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = ":1"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + // Verify some invalid characters + tstr = "0123:4567:89ab:cdef:0123:4567:89ab:cdeg"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "0123:4567:89ab:cdef:0123:4567:89ab:cde."; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "0123:4567:89ab:cdef:0123:4567:89ab:cden"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + + tstr = "0n"; + QVERIFY(vb->validate(tstr, pos) == QValidator::Invalid); + +} + +void SimpleIpv6Test::cidrTest() +{ + int pos = 0; + + QString tstr("1234:2345:3456:4567:5678:6789:789A:89ab/128"); + QVERIFY(vc->validate(tstr, pos) == QValidator::Acceptable); + + tstr = ""; + QVERIFY(vc->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:2345::6789:789A:89ab/28"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1234:2345:3456:4567:5678:6789:789A:89ab/129"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); + + tstr = "1234:2345:3456:4567:5678:6789:789A:89ab/"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1234:2345:3456:4567:5678:6789:789A/"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); + + tstr = "1234:2345:/"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); + + tstr = "::/0"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "1234:2345::6789:789A:89ab/28/"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); + + tstr = "1234:2345::6789:789A:89ab//"; + QVERIFY(vc->validate(tstr, pos) == QValidator::Invalid); +} + +void SimpleIpv6Test::portTest() +{ + int pos = 0; + + QString tstr(""); + QVERIFY(vp->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "1"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); + + tstr = "[1"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "[1123:22:44:11]"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); + + tstr = "[1234:2345::6789:789A:89ab]"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "[1234:2345::6789:789A:89ab]:"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Intermediate); + + tstr = "[1234:2345::6789:789A:89ab]:a"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); + + tstr = "[1234:2345::6789:789A:89ab]:12"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "[1234:2345::6789:789A:89ab]:65535"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Acceptable); + + tstr = "[1234:2345::6789:789A:89ab]:65536"; + QVERIFY(vp->validate(tstr, pos) == QValidator::Invalid); +} + +QTEST_GUILESS_MAIN(SimpleIpv6Test) + +#include "simpleipv6test.moc" 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,331 @@ +/* + 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 "wireguardkeyvalidator.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("Config file needs both [Peer] and [Interface]"); + return result; + } + + const QString connectionName = QFileInfo(fileName).completeBaseName(); + NMStringMap dataMap; + QVariantMap ipv4Data; + + QString value; + QStringList valueList; + int 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.isEmpty()) { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("No address in config file"); + return result; + } + + for (const QString &address :valueList) { + const QPair addressIn = QHostAddress::parseSubnet(address.trimmed()); + if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) { + dataMap.insert(QLatin1String(NM_WG_KEY_ADDR_IP4), address); + } else if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv6Protocol) { + dataMap.insert(QLatin1String(NM_WG_KEY_ADDR_IP6), address); + } else { // Error condition + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("No valid address in config file"); + return result; + } + } + + WireGuardKeyValidator keyValidator(this); + int keyPos = 0; + + // Private Key + value = interfaceGroup.readEntry(NMV_WG_TAG_PRIVATE_KEY); + if (!value.isEmpty()) { + if (keyValidator.validate(value, keyPos) == QValidator::State::Acceptable) { + dataMap.insert(QLatin1String(NM_WG_KEY_PRIVATE_KEY), value); + } else { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("No valid Private Key in config file"); + return result; + } + } else { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("No Private Key in config file"); + return result; + } + + // Public Key + value = peerGroup.readEntry(NMV_WG_TAG_PUBLIC_KEY); + if (!value.isEmpty()) { + if (keyValidator.validate(value, keyPos) == QValidator::State::Acceptable) { + dataMap.insert(QLatin1String(NM_WG_KEY_PUBLIC_KEY), value); + } else { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("No valid Public Key in config file"); + return result; + } + } else { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("No Public Key in config file"); + return result; + } + + // Allowed IPs + value = peerGroup.readEntry(NMV_WG_TAG_ALLOWED_IPS); + if (!value.isEmpty()) { + int pos = 0; + SimpleIpListValidator validator(this, + SimpleIpListValidator::WithCidr, + SimpleIpListValidator::Both); + + if (validator.validate(value, pos) != QValidator::State::Invalid) { + dataMap.insert(QLatin1String(NM_WG_KEY_ALLOWED_IPS), value); + } else { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("Invalid Allowed IP in config file"); + return result; + } + } else { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("No Allowed IPs in config file"); + 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 { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("Invalid Listen Port in config file"); + return result; + } + } + + // DNS + value = interfaceGroup.readEntry(NMV_WG_TAG_DNS); + if (!value.isEmpty()) { + const QHostAddress testAddress(value); + if (testAddress.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol + || testAddress.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv6Protocol) { + dataMap.insert(QLatin1String(NM_WG_KEY_DNS), value); + } else { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("Invalid DNS in config file"); + return result; + } + } + + // MTU + intValue = interfaceGroup.readEntry(NMV_WG_TAG_MTU, 0); + if (intValue > 0) + dataMap.insert(QLatin1String(NM_WG_KEY_LISTEN_PORT), QString::number(intValue)); + + // 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()) { + if (keyValidator.validate(value, keyPos) == QValidator::State::Acceptable) { + dataMap.insert(QLatin1String(NM_WG_KEY_PRESHARED_KEY), value); + } else { + mError = VpnUiPlugin::Error; + mErrorMessage = i18n("Invalid Preshared Key in config file"); + 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) +{ + NetworkManager::VpnSetting::Ptr vpnSetting = connection->setting(NetworkManager::Setting::Vpn).dynamicCast(); + NMStringMap 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_IP6))) + || !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); + + QStringList outputList; + + if (dataMap.contains(QLatin1String(NM_WG_KEY_ADDR_IP4))) + outputList.append(dataMap[NM_WG_KEY_ADDR_IP4]); + if (dataMap.contains(QLatin1String(NM_WG_KEY_ADDR_IP6))) + outputList.append(dataMap[NM_WG_KEY_ADDR_IP6]); + interfaceGroup.writeEntry(NMV_WG_TAG_ADDRESS, outputList); + + // 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,55 @@ +/* + 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 + +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, const QLatin1String &key, const QString &value) const; + void setOrClear(NMStringMap &data, const QLatin1String &key, const int 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,136 @@ +/* + 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(nullptr); + fwMarkValidator->setBottom(0); + 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(QString()); +} + +void WireGuardAdvancedWidget::setOrClear(NMStringMap &data, const QLatin1String &key, const QString &value) const +{ + if (!value.isEmpty()) + data.insert(key, value); + else + data.remove(key); +} + +void WireGuardAdvancedWidget::setOrClear(NMStringMap &data, const QLatin1String &key, const int value) const +{ + if (value > 0) + data.insert(key, QString::number(value)); + else + data.remove(key); +} + +NetworkManager::VpnSetting::Ptr WireGuardAdvancedWidget::setting() const +{ + NMStringMap data; + long intVal; + QString stringVal; + + intVal = m_ui->listenPortSpinBox->value(); + setOrClear(data, QLatin1String(NM_WG_KEY_LISTEN_PORT), intVal); + + intVal = m_ui->mtuSpinBox->value(); + setOrClear(data, QLatin1String(NM_WG_KEY_MTU), intVal); + + 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,55 @@ +/* + 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/libs/editor/simpleipv4addressvalidator.h b/vpn/wireguard/wireguardkeyvalidator.h copy from libs/editor/simpleipv4addressvalidator.h copy to vpn/wireguard/wireguardkeyvalidator.h --- a/libs/editor/simpleipv4addressvalidator.h +++ b/vpn/wireguard/wireguardkeyvalidator.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,21 @@ along with this program. If not, see . */ -#ifndef SIMPLEIPV4ADDRESSVALIDATOR_H -#define SIMPLEIPV4ADDRESSVALIDATOR_H +#ifndef WIREGUARDKEYVALIDATOR_H +#define WIREGUARDKEYVALIDATOR_H #include -class Q_DECL_EXPORT SimpleIpV4AddressValidator : public QValidator +class Q_DECL_EXPORT WireGuardKeyValidator : public QValidator { public: - explicit SimpleIpV4AddressValidator(QObject *parent); - ~SimpleIpV4AddressValidator() 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; + explicit WireGuardKeyValidator(QObject *parent); + ~WireGuardKeyValidator() override; + + QValidator::State validate(QString &, int &) const override; + +private: + QRegularExpressionValidator *m_validator; }; #endif // SIMPLEIPV4ADDRESSVALIDATOR_H diff --git a/vpn/wireguard/wireguardkeyvalidator.cpp b/vpn/wireguard/wireguardkeyvalidator.cpp new file mode 100644 --- /dev/null +++ b/vpn/wireguard/wireguardkeyvalidator.cpp @@ -0,0 +1,42 @@ +/* +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 "wireguardkeyvalidator.h" + +#include +#include + +WireGuardKeyValidator::WireGuardKeyValidator(QObject *parent) + : QValidator(parent) +{ + m_validator = new QRegularExpressionValidator(this); + // A WireGuard key is Base64 encoded and in human readable form consistes + // of 43 Alpha-numeric or '+' or '/' with a 44th character of an equal sign. + m_validator->setRegularExpression(QRegularExpression(QLatin1String("[0-9a-zA-Z\\+/]{43,43}="))); +} + +WireGuardKeyValidator::~WireGuardKeyValidator() +{ +} + +QValidator::State WireGuardKeyValidator::validate(QString &address, int &pos) const +{ + return m_validator->validate(address, pos); +} 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,53 @@ +/* + 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 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,187 @@ +/* + 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 "wireguardkeyvalidator.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); + + WireGuardKeyValidator *keyValidator = new WireGuardKeyValidator(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 + Q_UNUSED(setting) +} + +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()); +} +