diff --git a/applet/contents/ui/ConnectionItem.qml b/applet/contents/ui/ConnectionItem.qml --- a/applet/contents/ui/ConnectionItem.qml +++ b/applet/contents/ui/ConnectionItem.qml @@ -345,6 +345,9 @@ } } + /* This generates the formatted text under the connection name + in the popup where the connections can be "Connect"ed and + "Disconnect"ed. */ function itemText() { if (ConnectionState == PlasmaNM.Enums.Activating) { if (Type == PlasmaNM.Enums.Vpn) diff --git a/kcm/kcm.cpp b/kcm/kcm.cpp --- a/kcm/kcm.cpp +++ b/kcm/kcm.cpp @@ -25,6 +25,7 @@ #include "mobileconnectionwizard.h" #include "uiutils.h" #include "vpnuiplugin.h" +#include "settings/wireguardinterfacewidget.h" // KDE #include @@ -39,12 +40,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include // Qt #include @@ -349,6 +352,14 @@ connectionSettings->setAutoconnect(false); } } + if (type == NetworkManager::ConnectionSettings::WireGuard) { + NetworkManager::WireGuardSetting::Ptr wireguardSetting = connectionSettings->setting(NetworkManager::Setting::WireGuard).dynamicCast(); + NetworkManager::Ipv4Setting::Ptr ipv4Setting = connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast(); + NetworkManager::Ipv6Setting::Ptr ipv6Setting = connectionSettings->setting(NetworkManager::Setting::Ipv6).dynamicCast(); + connectionSettings->setAutoconnect(false); + ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Disabled); + ipv6Setting->setMethod(NetworkManager::Ipv6Setting::Ignored); + } // Generate new UUID connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); addConnection(connectionSettings); @@ -501,6 +512,22 @@ const QString ext = QStringLiteral("*.") % fi.suffix(); qCDebug(PLASMA_NM) << "Importing VPN connection " << filename << "extension:" << ext; + // Handle WireGuard separately because it is different than all the other VPNs + if (WireGuardInterfaceWidget::supportedFileExtensions().contains(ext)) { + NMVariantMapMap connection = WireGuardInterfaceWidget::importConnectionSettings(filename); + NetworkManager::ConnectionSettings connectionSettings; + connectionSettings.fromMap(connection); + connectionSettings.setUuid(NetworkManager::ConnectionSettings::createNewUuid()); + + // qCDebug(PLASMA_NM) << "Converted connection:" << connectionSettings; + + m_handler->addConnection(connectionSettings.toMap()); + // qCDebug(PLASMA_NM) << "Adding imported connection under id:" << conId; + + if (!connection.isEmpty()) { + return; // get out if the import produced at least some output + } + } for (const KService::Ptr &service : services) { VpnUiPlugin * vpnPlugin = service->createInstance(this); if (vpnPlugin && vpnPlugin->supportedFileExtensions().contains(ext)) { diff --git a/kcm/qml/ConnectionItem.qml b/kcm/qml/ConnectionItem.qml --- a/kcm/qml/ConnectionItem.qml +++ b/kcm/qml/ConnectionItem.qml @@ -154,6 +154,8 @@ } } + /* This generates the status description under each connection + in the list at the left side of the applet. */ function itemText() { if (ConnectionState == PlasmaNM.Enums.Activated) { return i18n("Connected") diff --git a/kded/notification.cpp b/kded/notification.cpp --- a/kded/notification.cpp +++ b/kded/notification.cpp @@ -400,6 +400,9 @@ case NetworkManager::ConnectionSettings::Wired: iconName = QStringLiteral("network-wired-activated"); break; + case NetworkManager::ConnectionSettings::WireGuard: + iconName = QStringLiteral("network-vpn"); + break; default: // silence warning break; } diff --git a/kded/secretagent.cpp b/kded/secretagent.cpp --- a/kded/secretagent.cpp +++ b/kded/secretagent.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -92,7 +93,6 @@ m_calls << request; processNext(); - return NMVariantMapMap(); } @@ -360,6 +360,7 @@ const bool userRequested = request.flags & UserRequested; const bool allowInteraction = request.flags & AllowInteraction; const bool isVpn = (setting->type() == NetworkManager::Setting::Vpn); + const bool isWireGuard = (setting->type() == NetworkManager::Setting::WireGuard); if (isVpn) { NetworkManager::VpnSetting::Ptr vpnSetting = connectionSettings->setting(NetworkManager::Setting::Vpn).dynamicCast(); @@ -399,7 +400,7 @@ if (!secretsMap.isEmpty()) { setting->secretsFromStringMap(secretsMap); - if (!isVpn && setting->needSecrets(requestNew).isEmpty()) { + if (!(isVpn || isWireGuard) && setting->needSecrets(requestNew).isEmpty()) { // Enough secrets were retrieved from storage request.connection[request.setting_name] = setting->secretsToMap(); sendSecrets(request.connection, request.message); @@ -411,7 +412,25 @@ sendError(SecretAgent::NoSecrets, "Cannot authenticate", request.message); emit secretsError(request.connection_path.path(), i18n("Authentication to %1 failed. Wrong password?", request.connection.value("connection").value("id").toString())); return true; + } else if (isWireGuard && userRequested) { // Just return what we have + NMVariantMapMap result; + NetworkManager::WireGuardSetting::Ptr wireGuardSetting; + wireGuardSetting = connectionSettings->setting(NetworkManager::Setting::WireGuard).dynamicCast(); + //FIXME workaround when NM is asking for secrets which should be system-stored, if we send an empty map it + // won't ask for additional secrets with AllowInteraction flag which would display the authentication dialog + if (wireGuardSetting->secretsToMap().isEmpty()) { + // Insert an empty secrets map as it was before I fixed it in NetworkManagerQt to make sure NM will ask again + // with flags we need + QVariantMap secretsMap; + secretsMap.insert(QLatin1String("secrets"), QVariant::fromValue(NMStringMap())); + result.insert("wireguard", secretsMap); + } else { + result.insert("wireguard", wireGuardSetting->secretsToMap()); + } + sendSecrets(result, request.message); + return true; } else if (requestNew || (allowInteraction && !setting->needSecrets(requestNew).isEmpty()) || (allowInteraction && userRequested) || (isVpn && allowInteraction)) { + m_dialog = new PasswordDialog(connectionSettings, request.flags, request.setting_name); connect(m_dialog, &PasswordDialog::accepted, this, &SecretAgent::dialogAccepted); connect(m_dialog, &PasswordDialog::rejected, this, &SecretAgent::dialogRejected); diff --git a/libs/declarative/connectionicon.cpp b/libs/declarative/connectionicon.cpp --- a/libs/declarative/connectionicon.cpp +++ b/libs/declarative/connectionicon.cpp @@ -282,6 +282,9 @@ if (activeConnection->state() == NetworkManager::ActiveConnection::Activating && UiUtils::isConnectionTypeSupported(activeConnection->type())) { connecting = true; } + if (activeConnection->type() == NetworkManager::ConnectionSettings::ConnectionType::WireGuard) { + vpn = true; + } } else { if (vpnConnection->state() == NetworkManager::VpnConnection::Activated) { vpn = true; @@ -341,8 +344,11 @@ } } else if (type == NetworkManager::ConnectionSettings::Vpn) { connection = activeConnection; + } else if (type == NetworkManager::ConnectionSettings::WireGuard) { + connection = activeConnection; } else if (type == NetworkManager::ConnectionSettings::Wired) { - if (connection && connection->type() != NetworkManager::ConnectionSettings::Vpn) { + if (connection && (connection->type() != NetworkManager::ConnectionSettings::Vpn + || connection->type() != NetworkManager::ConnectionSettings::WireGuard)) { connection = activeConnection; } } else if (type == NetworkManager::ConnectionSettings::Wireless) { @@ -394,6 +400,11 @@ setConnectionTooltipIcon("preferences-system-bluetooth"); } } + } else if (type == 29) { // TODO change to WireGuard enum value once it is added + // WireGuard is a VPN but is not implemented + // in NetworkManager as a VPN, so we don't want to + // do anything just because it has a device + // associated with it. } else { // Ignore other devices (bond/bridge/team etc.) setDisconnectedIcon(); diff --git a/libs/declarative/networkstatus.h b/libs/declarative/networkstatus.h --- a/libs/declarative/networkstatus.h +++ b/libs/declarative/networkstatus.h @@ -47,6 +47,7 @@ Infiniband, OLPCMesh, Bluetooth, + Wireguard, Vpn, Other }; diff --git a/libs/declarative/networkstatus.cpp b/libs/declarative/networkstatus.cpp --- a/libs/declarative/networkstatus.cpp +++ b/libs/declarative/networkstatus.cpp @@ -20,7 +20,6 @@ #include "networkstatus.h" #include "uiutils.h" - #include #include @@ -61,6 +60,9 @@ case NetworkManager::ConnectionSettings::Wireless: return NetworkStatus::Wireless; break; + case NetworkManager::ConnectionSettings::WireGuard: + return NetworkStatus::Wireguard; + break; default: return NetworkStatus::Other; break; @@ -169,7 +171,8 @@ if (!active->devices().isEmpty() && UiUtils::isConnectionTypeSupported(active->type())) { NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(active->devices().first()); - if (device && device->type() != NetworkManager::Device::Generic && device->type() <= NetworkManager::Device::Team) { + if (device && ((device->type() != NetworkManager::Device::Generic && device->type() <= NetworkManager::Device::Team) + || device->type() == 29)) { // TODO: Change to WireGuard enum value when it is added bool connecting = false; bool connected = false; QString conType; @@ -198,6 +201,11 @@ } } + if (active->type() == NetworkManager::ConnectionSettings::ConnectionType::WireGuard) { + conType = i18n("WireGuard"); + connected = true; + } + NetworkManager::Connection::Ptr connection = active->connection(); if (connecting) { status = i18n("Connecting to %1", connection->name()); diff --git a/libs/editor/CMakeLists.txt b/libs/editor/CMakeLists.txt --- a/libs/editor/CMakeLists.txt +++ b/libs/editor/CMakeLists.txt @@ -19,6 +19,9 @@ settings/wifisecurity.cpp settings/wiredconnectionwidget.cpp settings/wiredsecurity.cpp + settings/wireguardinterfacewidget.cpp + settings/wireguardtabwidget.cpp + settings/wireguardpeerwidget.cpp widgets/advancedpermissionswidget.cpp widgets/bssidcombobox.cpp @@ -41,6 +44,7 @@ simpleipv4addressvalidator.cpp simpleipv6addressvalidator.cpp simpleiplistvalidator.cpp + wireguardkeyvalidator.cpp vpnuiplugin.cpp ../configuration.cpp @@ -75,6 +79,9 @@ settings/ui/wifisecurity.ui settings/ui/wiredconnectionwidget.ui settings/ui/wiredsecurity.ui + settings/ui/wireguardinterfacewidget.ui + settings/ui/wireguardtabwidget.ui + settings/ui/wireguardpeerwidget.ui widgets/ui/advancedpermissionswidget.ui widgets/ui/ipv4routes.ui @@ -89,6 +96,7 @@ KF5::NetworkManagerQt KF5::WidgetsAddons KF5::Completion + KF5::ConfigWidgets Qt5::Widgets PRIVATE Qt5::Network diff --git a/libs/editor/connectioneditorbase.cpp b/libs/editor/connectioneditorbase.cpp --- a/libs/editor/connectioneditorbase.cpp +++ b/libs/editor/connectioneditorbase.cpp @@ -39,6 +39,7 @@ #include "settings/wifisecurity.h" #include "settings/wiredconnectionwidget.h" #include "settings/wiredsecurity.h" +#include "settings/wireguardinterfacewidget.h" #include "vpnuiplugin.h" #include @@ -132,6 +133,8 @@ connectionSettings->fromMap(settings); connectionSettings->setId(connectionName()); + if (connectionSettings->connectionType() == NetworkManager::ConnectionSettings::WireGuard) + connectionSettings->setInterfaceName(connectionName()); connectionSettings->setUuid(m_connection->uuid()); if (connectionSettings->connectionType() == NetworkManager::ConnectionSettings::Wireless) { @@ -144,7 +147,6 @@ } } } - return connectionSettings->toMap(); } @@ -240,6 +242,9 @@ } else if (type == NetworkManager::ConnectionSettings::Team) { // Team TeamWidget *teamWidget = new TeamWidget(m_connection->uuid(), m_connection->setting(NetworkManager::Setting::Team), this); addSettingWidget(teamWidget, i18n("Team")); + } else if (type == NetworkManager::ConnectionSettings::WireGuard) { // WireGuard + WireGuardInterfaceWidget *wireGuardInterfaceWidget = new WireGuardInterfaceWidget(m_connection->setting(NetworkManager::Setting::WireGuard), this); + addSettingWidget(wireGuardInterfaceWidget, i18n("WireGuard Interface")); } else if (type == NetworkManager::ConnectionSettings::Vpn) { // VPN QString error; VpnUiPlugin *vpnPlugin = nullptr; @@ -284,8 +289,8 @@ || type == NetworkManager::ConnectionSettings::Bond || type == NetworkManager::ConnectionSettings::Bridge || type == NetworkManager::ConnectionSettings::Vlan - || (type == NetworkManager::ConnectionSettings::Vpn && serviceType == QLatin1String("org.freedesktop.NetworkManager.openvpn")) - || (type == NetworkManager::ConnectionSettings::Vpn && serviceType == QLatin1String("org.freedesktop.NetworkManager.wireguard"))) && !m_connection->isSlave()) { + || type == NetworkManager::ConnectionSettings::WireGuard + || (type == NetworkManager::ConnectionSettings::Vpn && serviceType == QLatin1String("org.freedesktop.NetworkManager.openvpn"))) && !m_connection->isSlave()) { IPv6Widget *ipv6Widget = new IPv6Widget(m_connection->setting(NetworkManager::Setting::Ipv6), this); addSettingWidget(ipv6Widget, i18n("IPv6")); } @@ -353,6 +358,13 @@ setting = securitySetting->toMap(); settingName = QLatin1String("802-1x"); } + } else if (m_connection->connectionType() == NetworkManager::ConnectionSettings::WireGuard) { + NetworkManager::WireGuardSetting::Ptr securitySetting = connection->settings()->setting(NetworkManager::Setting::WireGuard).staticCast(); + if (securitySetting && !securitySetting->needSecrets().isEmpty()) { + requiredSecrets = securitySetting->needSecrets(); + setting = securitySetting->toMap(); + settingName = QLatin1String("wireguard"); + } } else if (m_connection->connectionType() == NetworkManager::ConnectionSettings::Wireless) { NetworkManager::WirelessSecuritySetting::Ptr wifiSecuritySetting = connection->settings()->setting(NetworkManager::Setting::WirelessSecurity).staticCast(); if (wifiSecuritySetting && diff --git a/libs/editor/settings/connectionwidget.cpp b/libs/editor/settings/connectionwidget.cpp --- a/libs/editor/settings/connectionwidget.cpp +++ b/libs/editor/settings/connectionwidget.cpp @@ -29,7 +29,6 @@ #include #include #include - #include #include #include @@ -179,7 +178,8 @@ for (const NetworkManager::Connection::Ptr &conn : list) { NetworkManager::ConnectionSettings::Ptr conSet = conn->settings(); - if (conSet->connectionType() == NetworkManager::ConnectionSettings::Vpn) { + if (conSet->connectionType() == NetworkManager::ConnectionSettings::Vpn + || conSet->connectionType() == NetworkManager::ConnectionSettings::WireGuard) { // qCDebug(PLASMA_NM) << "Found VPN" << conSet->id() << conSet->uuid(); result.insert(conSet->uuid(), conSet->id()); } diff --git a/vpn/wireguard/wireguard.ui b/libs/editor/settings/ui/wireguardinterfacewidget.ui rename from vpn/wireguard/wireguard.ui rename to libs/editor/settings/ui/wireguardinterfacewidget.ui --- a/vpn/wireguard/wireguard.ui +++ b/libs/editor/settings/ui/wireguardinterfacewidget.ui @@ -1,6 +1,6 @@ - WireGuardProp + WireGuardInterfaceProp @@ -21,136 +21,90 @@ - - - Address (IPv4): - - - - - - - IPv4 Internet address with -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 -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. - - - - - - - Peer - - - - + + - Public key: + Listen port: - - + + - 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. + Optional. +Listen port number. Chosen randomly if left as 'Automatic'. - - + + + - Allowed IPs: + fwmark: - - + + - 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. + Optional. +An fwmark for outgoing packets. If set to 0 or 'off', this +option is disabled. May be specified in hexadecimal by +prepending '0x'. - - + + - Endpoint Address: + MTU: - - + + Optional. -An endpoint IP address or name. +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. - - + + - Endpoint Port: + Autoroute peers: - - + + - Optional. -An endpoint port number. + Whether to automatically add routes for the AllowedIPs ranges +of the peers. - - - @@ -167,14 +121,16 @@ - + - Advanced... + Peers... + + diff --git a/libs/editor/settings/ui/wireguardpeerwidget.ui b/libs/editor/settings/ui/wireguardpeerwidget.ui new file mode 100644 --- /dev/null +++ b/libs/editor/settings/ui/wireguardpeerwidget.ui @@ -0,0 +1,142 @@ + + + WireGuardPeersProp + + + + 0 + 0 + 495 + 454 + + + + + + + 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 address: + + + + + + + Optional. + An endpoint for the connection. Can be an + IPv4 address, IPv6 address, or FQDN (fully + qualified domain name such as abc.com). If + present, Endpoint port must also be set. + + + + + + + + Endpoint port: + + + + + + + Optional. + The port number of an endpoint. If present Endpoint + Address must also be set. + + + + + + + + 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. + + + + + + + Persistent keepalive: + + + + + + + Optional. + A seconds interval, between 1 and 65535 inclusive, of + how often to send an authenticated empty packet to + the peer for the purpose of keeping a stateful firewall + or NAT mapping valid persistently. For example, if the + interface very rarely sends traffic, but it might at + anytime receive traffic from a peer, and it is behind + NAT, the interface might benefit from having a + persistent keepalive interval of 25 seconds. If set to + 0 or "off", this option is disabled. By default or + when unspecified, this option is off. Most users will not + need this. + + + + + + + + PasswordField + QLineEdit +
passwordfield.h
+
+
+ + +
diff --git a/libs/editor/settings/ui/wireguardtabwidget.ui b/libs/editor/settings/ui/wireguardtabwidget.ui new file mode 100644 --- /dev/null +++ b/libs/editor/settings/ui/wireguardtabwidget.ui @@ -0,0 +1,76 @@ + + + WireGuardTabWidget + + + + 0 + 0 + 498 + 427 + + + + + + + 0 + + + Qt::ElideRight + + + + + + + + + + + + Add new Peer + + + + + + + Remove this Peer + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + diff --git a/libs/editor/settings/wireguardinterfacewidget.h b/libs/editor/settings/wireguardinterfacewidget.h new file mode 100644 --- /dev/null +++ b/libs/editor/settings/wireguardinterfacewidget.h @@ -0,0 +1,59 @@ +/* + Copyright 2019 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_WIREGUARD_INTERFACE_WIDGET_H +#define PLASMA_NM_WIREGUARD_INTERFACE_WIDGET_H + +#include + +#include "settingwidget.h" +#include +#include "ui_wireguardinterfacewidget.h" + +class Q_DECL_EXPORT WireGuardInterfaceWidget : public SettingWidget +{ +Q_OBJECT + +public: + explicit WireGuardInterfaceWidget(const NetworkManager::Setting::Ptr &setting, QWidget *parent = nullptr, Qt::WindowFlags f = {}); + ~WireGuardInterfaceWidget() override; + + void loadConfig(const NetworkManager::Setting::Ptr &setting) override; + void loadSecrets(const NetworkManager::Setting::Ptr &setting) override; + + QVariantMap setting() const override; + + bool isValid() const override; + static QString supportedFileExtensions(); + static NMVariantMapMap importConnectionSettings(const QString &fileName); + +private Q_SLOTS: + void showPeers(); + +private: + void setBackground(QWidget *w, bool result) const; + void checkPrivateKeyValid(); + void checkFwmarkValid(); + void checkListenPortValid(); + class Private; + Private *d; +}; + +#endif // PLASMA_NM_WIREGUARD_INTERFACE_WIDGET_H diff --git a/libs/editor/settings/wireguardinterfacewidget.cpp b/libs/editor/settings/wireguardinterfacewidget.cpp new file mode 100644 --- /dev/null +++ b/libs/editor/settings/wireguardinterfacewidget.cpp @@ -0,0 +1,639 @@ +/* + Copyright 2019 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 "debug.h" +#include "wireguardinterfacewidget.h" +#include "wireguardtabwidget.h" +#include "ui_wireguardinterfacewidget.h" +#include "uiutils.h" +#include "simpleipv4addressvalidator.h" +#include "simpleiplistvalidator.h" +#include "wireguardkeyvalidator.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +// Tags used in a WireGuard .conf file - Used for importing +#define PNM_WG_CONF_TAG_INTERFACE "[Interface]" +#define PNM_WG_CONF_TAG_ADDRESS "Address" +#define PNM_WG_CONF_TAG_LISTEN_PORT "ListenPort" +#define PNM_WG_CONF_TAG_MTU "MTU" +#define PNM_WG_CONF_TAG_DNS "DNS" +#define PNM_WG_CONF_TAG_FWMARK "FwMark" +#define PNM_WG_CONF_TAG_PRIVATE_KEY "PrivateKey" +#define PNM_WG_CONF_TAG_PEER "[Peer]" +#define PNM_WG_CONF_TAG_PUBLIC_KEY "PublicKey" +#define PNM_WG_CONF_TAG_PRESHARED_KEY "PresharedKey" +#define PNM_WG_CONF_TAG_ALLOWED_IPS "AllowedIPs" +#define PNM_WG_CONF_TAG_ENDPOINT "Endpoint" +#define PNM_WG_CONF_TAG_PERSISTENT_KEEPALIVE "PersistentKeepalive" +#define PNM_WG_CONF_TAG_TABLE "Table" +#define PNM_WG_CONF_TAG_PRE_UP "PreUp" +#define PNM_WG_CONF_TAG_POST_UP "PostUp" +#define PNM_WG_CONF_TAG_PRE_DOWN "PreDown" +#define PNM_WG_CONF_TAG_POST_DOWN "PostDown" + +#define PNM_WG_KEY_PEERS "peers" +#define PNM_WG_KEY_MTU "mtu" +#define PNM_WG_KEY_PEER_ROUTES "peer-routes" +#define PNM_WG_PEER_KEY_ALLOWED_IPS "allowed-ips" +#define PNM_WG_PEER_KEY_ENDPOINT "endpoint" +#define PNM_WG_PEER_KEY_PERSISTENT_KEEPALIVE "persistent-keepalive" +#define PNM_WG_PEER_KEY_PRESHARED_KEY "preshared-key" +#define PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS "preshared-key-flags" +#define PNM_WG_PEER_KEY_PUBLIC_KEY "public-key" + +// Keys for the NetworkManager configuration +#define PNM_SETTING_WIREGUARD_SETTING_NAME "wireguard" + +#define PNM_WG_KEY_FWMARK "fwmark" +#define PNM_WG_KEY_LISTEN_PORT "listen-port" +#define PNM_WG_KEY_PRIVATE_KEY "private-key" +#define PNM_WG_KEY_PRIVATE_KEY_FLAGS "private-key-flags" + +class WireGuardInterfaceWidget::Private +{ +public: + Private(); + ~Private(); + + Ui_WireGuardInterfaceProp ui; + NetworkManager::WireGuardSetting::Ptr setting; + KSharedConfigPtr config; + QPalette warningPalette; + QPalette normalPalette; + WireGuardKeyValidator *keyValidator; + QRegularExpressionValidator *fwmarkValidator; + QIntValidator *mtuValidator; + QIntValidator *portValidator; + bool privateKeyValid; + bool fwmarkValid; + bool listenPortValid; + bool peersValid; + NMVariantMapList peers; +}; + +WireGuardInterfaceWidget::Private::Private(void) + : privateKeyValid(false) + , fwmarkValid(true) + , listenPortValid(true) + , peersValid(false) +{ +} + +WireGuardInterfaceWidget::Private::~Private() +{ + delete keyValidator; + delete fwmarkValidator; + delete mtuValidator; + delete portValidator; +} + +WireGuardInterfaceWidget::WireGuardInterfaceWidget(const NetworkManager::Setting::Ptr &setting, QWidget *parent, Qt::WindowFlags f) + : SettingWidget(setting, parent, f) + , d(new Private) +{ + d->ui.setupUi(this); + d->setting = setting.staticCast(); + d->config = KSharedConfig::openConfig(); + d->warningPalette = KColorScheme::createApplicationPalette(d->config); + d->normalPalette = KColorScheme::createApplicationPalette(d->config); + KColorScheme::adjustBackground(d->warningPalette, KColorScheme::NegativeBackground, QPalette::Base, + KColorScheme::ColorSet::View, d->config); + + KColorScheme::adjustBackground(d->normalPalette, KColorScheme::NormalBackground, QPalette::Base, + KColorScheme::ColorSet::View, d->config); + + connect(d->ui.privateKeyLineEdit, &PasswordField::textChanged, this, &WireGuardInterfaceWidget::checkPrivateKeyValid); + connect(d->ui.privateKeyLineEdit, &PasswordField::passwordOptionChanged, this, &WireGuardInterfaceWidget::checkPrivateKeyValid); + connect(d->ui.fwmarkLineEdit, &QLineEdit::textChanged, this, &WireGuardInterfaceWidget::checkFwmarkValid); + connect(d->ui.listenPortLineEdit, &QLineEdit::textChanged, this, &WireGuardInterfaceWidget::checkListenPortValid); + connect(d->ui.btnPeers, &QPushButton::clicked, this, &WireGuardInterfaceWidget::showPeers); + + d->ui.privateKeyLineEdit->setPasswordModeEnabled(true); + d->ui.privateKeyLineEdit->setPasswordOptionsEnabled(true); + d->ui.privateKeyLineEdit->setPasswordNotSavedEnabled(false); + + // This is done as a private variable rather than a local variable so it can be + // used both here and to validate the private key later + d->keyValidator = new WireGuardKeyValidator(this); + + // Create validator for listen port + d->portValidator = new QIntValidator(nullptr); + d->portValidator->setBottom(0); + d->portValidator->setTop(65535); + + // Create a validator for the fwmark input. Acceptable + // inputs are: "off" and numbers in either decimal + // or hex (with 0x prefix) + d->fwmarkValidator = new QRegularExpressionValidator(QRegularExpression("(off)|([0-9]{0,10})|(0x[0-9a-fA-F]{1,8})")); + d->ui.fwmarkLineEdit->setValidator(d->fwmarkValidator); + + // Create a validator for the MTU field. + d->mtuValidator = new QIntValidator(nullptr); + d->mtuValidator->setBottom(0); + d->ui.mtuLineEdit->setValidator(d->mtuValidator); + + // Default Peer Routes to true + d->ui.peerRouteCheckBox->setChecked(true); + + // Connect for setting check + watchChangedSetting(); + + KAcceleratorManager::manage(this); + + if (setting && !setting->isNull()) { + loadConfig(d->setting); + } + + // Set the initial backgrounds on all the widgets + checkPrivateKeyValid(); +} + +WireGuardInterfaceWidget::~WireGuardInterfaceWidget() +{ + delete d; +} + +void WireGuardInterfaceWidget::loadConfig(const NetworkManager::Setting::Ptr &setting) +{ + NetworkManager::WireGuardSetting::Ptr wireGuardSetting = setting.staticCast(); + d->ui.privateKeyLineEdit->setText(wireGuardSetting->privateKey()); + + if (wireGuardSetting->listenPort() != 0) + d->ui.listenPortLineEdit->setText(QString::number(wireGuardSetting->listenPort())); + else + d->ui.listenPortLineEdit->clear(); + + if (wireGuardSetting->fwmark() != 0) + d->ui.fwmarkLineEdit->setText(QString::number(wireGuardSetting->fwmark())); + else + d->ui.fwmarkLineEdit->clear(); + + if (wireGuardSetting->mtu() != 0) + d->ui.mtuLineEdit->setText(QString::number(wireGuardSetting->mtu())); + else + d->ui.mtuLineEdit->clear(); + + d->ui.peerRouteCheckBox->setChecked(wireGuardSetting->peerRoutes()); + + NetworkManager::Setting::SecretFlags type = wireGuardSetting->privateKeyFlags(); + switch (type) { + case NetworkManager::Setting::AgentOwned: + d->ui.privateKeyLineEdit->setPasswordOption(PasswordField::StoreForUser); + break; + case NetworkManager::Setting::None: + d->ui.privateKeyLineEdit->setPasswordOption(PasswordField::StoreForAllUsers); + break; + // Not saved is not a valid option for the private key so set it to StoreForUser instead + case NetworkManager::Setting::NotSaved: + d->ui.privateKeyLineEdit->setPasswordOption(PasswordField::StoreForUser); + break; + case NetworkManager::Setting::NotRequired: + d->ui.privateKeyLineEdit->setPasswordOption(PasswordField::NotRequired); + break; + } + + d->peers = wireGuardSetting->peers(); + loadSecrets(setting); +} + +void WireGuardInterfaceWidget::loadSecrets(const NetworkManager::Setting::Ptr &setting) +{ + NetworkManager::WireGuardSetting::Ptr wireGuardSetting = setting.staticCast(); + if (wireGuardSetting) { + const QString key = wireGuardSetting->privateKey(); + if (!key.isEmpty()) + d->ui.privateKeyLineEdit->setText(key); + + const NMVariantMapList peers = wireGuardSetting->peers(); + if (!peers.isEmpty()) { + // For each of the peers returned, see if it contains a preshared key + for (QList::const_iterator i = peers.cbegin(); i != peers.cend(); i++) { + if (i->contains(PNM_WG_PEER_KEY_PRESHARED_KEY)) { + // We have a preshared key so find the matching public key in the local peer list + QString currentPublicKey = (*i)[PNM_WG_PEER_KEY_PUBLIC_KEY].toString(); + if (!currentPublicKey.isEmpty()) { + for (QList::iterator j = d->peers.begin(); j != d->peers.end(); j++) { + if ((*j)[PNM_WG_PEER_KEY_PUBLIC_KEY].toString() == currentPublicKey) { + (*j)[PNM_WG_PEER_KEY_PRESHARED_KEY] = (*i)[PNM_WG_PEER_KEY_PRESHARED_KEY].toString(); + break; + } + } + } + } + } + } + } + // On the assumption that a saved configuration is valid (because how could it be saved if it + // wasn't valid) then the peers section is valid unless it didn't get a preshared key if one + // is required, so a simple minded "validity" check is done here. Real validity checks are done + // when the peers widget is open which is the only time changes which might be invalid are + // possible. + d->peersValid = true; + for (QList::iterator j = d->peers.begin(); j != d->peers.end(); j++) { + if ((*j).contains(PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS) + && (*j)[PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS] != NetworkManager::Setting::NotRequired + && (!(*j).contains(PNM_WG_PEER_KEY_PRESHARED_KEY) + || (*j)[PNM_WG_PEER_KEY_PRESHARED_KEY].toString().isEmpty())) { + d->peersValid = false; + break; + } + } +} + +QVariantMap WireGuardInterfaceWidget::setting() const +{ + NetworkManager::WireGuardSetting wgSetting; + QString val = d->ui.fwmarkLineEdit->displayText(); + + if (!val.isEmpty()) + wgSetting.setFwmark(val.toUInt()); + + val = d->ui.listenPortLineEdit->displayText(); + if (!val.isEmpty()) + wgSetting.setListenPort(val.toUInt()); + + val = d->ui.mtuLineEdit->displayText(); + if (!val.isEmpty()) + wgSetting.setMtu(val.toUInt()); + + val = d->ui.privateKeyLineEdit->text(); + if (!val.isEmpty()) + wgSetting.setPrivateKey(val); + + wgSetting.setPeerRoutes(d->ui.peerRouteCheckBox->isChecked()); + + PasswordField::PasswordOption option = d->ui.privateKeyLineEdit->passwordOption(); + switch (option) { + case PasswordField::StoreForUser: + wgSetting.setPrivateKeyFlags(NetworkManager::Setting::AgentOwned); + break; + case PasswordField::StoreForAllUsers: + wgSetting.setPrivateKeyFlags(NetworkManager::Setting::None); + break; + // Always Ask is not a valid option for the private key so set it to AgentOwned instead + case PasswordField::AlwaysAsk: + wgSetting.setPrivateKeyFlags(NetworkManager::Setting::AgentOwned); + break; + case PasswordField::NotRequired: + wgSetting.setPrivateKeyFlags(NetworkManager::Setting::NotRequired); + break; + } + wgSetting.setPeers(d->peers); + return wgSetting.toMap(); +} + +bool WireGuardInterfaceWidget::isValid() const +{ + return d->privateKeyValid + && d->fwmarkValid + && d->listenPortValid + && d->peersValid; +} + +void WireGuardInterfaceWidget::checkPrivateKeyValid() +{ + int pos = 0; + PasswordField *widget = d->ui.privateKeyLineEdit; + QString value = widget->text(); + bool valid = (QValidator::Acceptable == d->keyValidator->validate(value, pos)); + d->privateKeyValid = valid; + setBackground(widget, valid); + slotWidgetChanged(); +} +void WireGuardInterfaceWidget::checkFwmarkValid() +{ + int pos = 0; + QLineEdit *widget = d->ui.fwmarkLineEdit; + QString value = widget->displayText(); + d->fwmarkValid = QValidator::Acceptable == widget->validator()->validate(value, pos) + || value.isEmpty(); + setBackground(widget, d->fwmarkValid); + slotWidgetChanged(); +} + +void WireGuardInterfaceWidget::checkListenPortValid() +{ + int pos = 0; + QLineEdit *widget = d->ui.listenPortLineEdit; + QString value = widget->displayText(); + d->listenPortValid = QValidator::Acceptable == d->portValidator->validate(value, pos) + || value.isEmpty(); + setBackground(widget, d->listenPortValid); + slotWidgetChanged(); +} + +void WireGuardInterfaceWidget::setBackground(QWidget *w, bool result) const +{ + if (result) + w->setPalette(d->normalPalette); + else + w->setPalette(d->warningPalette); +} + +QString WireGuardInterfaceWidget::supportedFileExtensions() +{ + return "*.conf"; +} + +void WireGuardInterfaceWidget::showPeers() +{ + QPointer peers = new WireGuardTabWidget(d->peers, this); + + connect(peers.data(), &WireGuardTabWidget::accepted, + [peers, this] () { + NMVariantMapList peersData = peers->setting(); + if (!peersData.isEmpty()) { + d->peers = peersData; + // The peers widget won't allow "OK" to be hit + // unless all the peers are valid so no need to check + d->peersValid = true; + slotWidgetChanged(); + } + }); + connect(peers.data(), &WireGuardTabWidget::finished, + [peers] () { + if (peers) { + peers->deleteLater(); + } + }); + peers->setModal(true); + peers->show(); +} + +NMVariantMapMap WireGuardInterfaceWidget::importConnectionSettings(const QString &fileName) +{ + NMVariantMapMap result; + + QFile impFile(fileName); + QList ipv4AddressList; + QList ipv6AddressList; + + if (!impFile.open(QFile::ReadOnly|QFile::Text)) { + return result; + } + + const QString connectionName = QFileInfo(fileName).completeBaseName(); + NMStringMap dataMap; + NMVariantMapList peers; + QVariantMap ipv4Data; + QVariantMap *currentPeer = nullptr; + WireGuardKeyValidator keyValidator(nullptr); + NetworkManager::Ipv4Setting ipv4Setting; + NetworkManager::Ipv6Setting ipv6Setting; + NetworkManager::WireGuardSetting wgSetting; + + QString proxyType; + QString proxyUser; + QString proxyPasswd; + bool havePrivateKey = false; + bool haveIpv4Setting = false; + bool haveIpv6Setting = false; + // Set the "PEER" elements true because they + // need to be true to allocate the + // first [Peer] section below + bool havePublicKey = true; + bool haveAllowedIps = true; + int pos = 0; + + QTextStream in(&impFile); + enum {IDLE, INTERFACE_SECTION, PEER_SECTION} currentState = IDLE; + + ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Disabled); + ipv6Setting.setMethod(NetworkManager::Ipv6Setting::Ignored); + + while (!in.atEnd()) { + QStringList keyValue; + QString line = in.readLine(); + + // Remove comments starting with '#' + if (int index = line.indexOf('#') > 0) + line.truncate(index); + + // Ignore blank lines + if (line.isEmpty()) + continue; + + keyValue.clear(); + keyValue << line.split('='); + + if (keyValue[0] == PNM_WG_CONF_TAG_INTERFACE) { + currentState = INTERFACE_SECTION; + continue; + } else if (keyValue[0] == PNM_WG_CONF_TAG_PEER) { + // Check to make sure the previous PEER section has + // all the required elements. If not it's an error + // so just return the empty result. + if (!havePublicKey || !haveAllowedIps) { + return result; + } else { + havePublicKey = false; + haveAllowedIps = false; + currentState = PEER_SECTION; + peers.append(*(new QVariantMap)); + currentPeer = &peers[peers.size() - 1]; + continue; + } + } + + // If we didn't get an '=' sign in the line, it's probably an error but + // we're going to treat it as a comment and ignore it + if (keyValue.length() < 2) + continue; + + QString key = keyValue[0].trimmed(); + + // If we are in the [Interface] section look for the possible tags + if (currentState == INTERFACE_SECTION) { + // Address + if (key == PNM_WG_CONF_TAG_ADDRESS) { + QStringList valueList = keyValue[1].split(','); + if (valueList.isEmpty()) + return result; + + for (const QString &address : valueList) { + const QPair addressIn = QHostAddress::parseSubnet(address.trimmed()); + NetworkManager::IpAddress *addr = new NetworkManager::IpAddress; + addr->setIp(addressIn.first); + addr->setPrefixLength(addressIn.second); + if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) { + ipv4AddressList.append(*addr); + } else if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv6Protocol) { + ipv6AddressList.append(*addr); + } else { // Error condition + return result; + } + } + if (!ipv4AddressList.isEmpty()) { + ipv4Setting.setAddresses(ipv4AddressList); + ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Manual); + haveIpv4Setting = true; + } + if (!ipv6AddressList.isEmpty()) { + ipv6Setting.setAddresses(ipv6AddressList); + ipv6Setting.setMethod(NetworkManager::Ipv6Setting::Manual); + haveIpv6Setting = true; + } + } + + // Listen Port + else if (key == PNM_WG_CONF_TAG_LISTEN_PORT) { + uint val = keyValue[1].toUInt(); + if (val <= 65535) + wgSetting.setListenPort(val); + } else if (key == PNM_WG_CONF_TAG_PRIVATE_KEY) { + QString val = keyValue[1].trimmed(); + // WireGuard keys present a slight problem because they + // must end in '=' which is removed during the 'split' above + // so if there are 3 parts and the 3 is empty, there must + // have been an '=' so add it back on + if (keyValue.size() == 3 && keyValue[2].isEmpty()) + val += "="; + if (QValidator::Acceptable == keyValidator.validate(val, pos)) { + wgSetting.setPrivateKey(val); + havePrivateKey = true; + } + } else if (key == PNM_WG_CONF_TAG_DNS) { + QStringList addressList = keyValue[1].split(','); + QList ipv4DnsList; + QList ipv6DnsList; + if (!addressList.isEmpty()) { + for (const QString &address : addressList) { + const QPair addressIn = QHostAddress::parseSubnet(address.trimmed()); + if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) { + ipv4DnsList.append(addressIn.first); + } else if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv6Protocol) { + ipv6DnsList.append(addressIn.first); + } else { // Error condition + return result; + } + } + } + + // If there are any addresses put them on the correct tab and set the "method" to + // "Automatic (Only addresses)" by setting "ignore-auto-dns=true" + if (!ipv4DnsList.isEmpty()) { + if (ipv4Setting.method() == NetworkManager::Ipv4Setting::Disabled) + ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Automatic); + ipv4Setting.setIgnoreAutoDns(true); + ipv4Setting.setDns(ipv4DnsList); + haveIpv4Setting = true; + } + + if (!ipv6DnsList.isEmpty()) { + ipv6Setting.setMethod(NetworkManager::Ipv6Setting::Automatic); + ipv6Setting.setIgnoreAutoDns(true); + ipv6Setting.setDns(ipv6DnsList); + haveIpv6Setting = true; + } + } else if (key == PNM_WG_CONF_TAG_MTU) { + uint val = keyValue[1].toUInt(); + if (val > 0) + wgSetting.setMtu(val); + } else if (key == PNM_WG_CONF_TAG_FWMARK) { + uint val; + if (keyValue[1].trimmed().toLower() == QLatin1String("off")) + val = 0; + else + val = keyValue[1].toUInt(); + wgSetting.setFwmark(val); + } else if (key == PNM_WG_CONF_TAG_TABLE + || key == PNM_WG_CONF_TAG_PRE_UP + || key == PNM_WG_CONF_TAG_POST_UP + || key == PNM_WG_CONF_TAG_PRE_DOWN + || key == PNM_WG_CONF_TAG_POST_DOWN) { + // plasma-nm does not handle these items + } else { + // We got a wrong field in the Interface section so it + // is an error + break; + } + } else if (currentState == PEER_SECTION) { + // Public Key + if (key == PNM_WG_CONF_TAG_PUBLIC_KEY) { + QString val = keyValue[1].trimmed(); + // WireGuard keys present a slight problem because they + // must end in '=' which is removed during the 'split' above + // so if there are 3 parts and the 3 is empty, there must + // have been an '=' so add it back on + if (keyValue.size() == 3 && keyValue[2].isEmpty()) + val += "="; + + if (QValidator::Acceptable == keyValidator.validate(val, pos)) { + currentPeer->insert(PNM_WG_PEER_KEY_PUBLIC_KEY, val); + havePublicKey = true; + } + } else if (key == PNM_WG_CONF_TAG_ALLOWED_IPS) { + SimpleIpListValidator validator(nullptr, SimpleIpListValidator::WithCidr, SimpleIpListValidator::Both); + QString val = keyValue[1].trimmed(); + if (QValidator::Acceptable == validator.validate(val, pos)) + { + QStringList valList = val.split(','); + for (QString& str : valList) + str = str.trimmed(); + currentPeer->insert(PNM_WG_PEER_KEY_ALLOWED_IPS, valList); + haveAllowedIps = true; + } + } else if (key == PNM_WG_CONF_TAG_ENDPOINT) { + if (keyValue[1].length() > 0) + currentPeer->insert(PNM_WG_PEER_KEY_ENDPOINT, keyValue[1].trimmed()); + } else if (key == PNM_WG_CONF_TAG_PRESHARED_KEY) { + QString val = keyValue[1].trimmed(); + // WireGuard keys present a slight problem because they + // must end in '=' which is removed during the 'split' above + // so if there are 3 parts and the 3 is empty, there must + // have been an '=' so add it back on + if (keyValue.size() == 3 && keyValue[2].isEmpty()) + val += "="; + + if (QValidator::Acceptable == keyValidator.validate(val, pos)) { + currentPeer->insert(PNM_WG_PEER_KEY_PRESHARED_KEY, val); + } + } + } else { + return result; + } + } + if (!havePrivateKey || !haveAllowedIps || !havePublicKey || !haveAllowedIps) + return result; + + QVariantMap conn; + wgSetting.setPeers(peers); + conn.insert("id", connectionName); + conn.insert("interface-name", connectionName); + conn.insert("type", "wireguard"); + conn.insert("autoconnect", "false"); + result.insert("connection", conn); + result.insert("wireguard", wgSetting.toMap()); + if (haveIpv4Setting) + result.insert("ipv4", ipv4Setting.toMap()); + if (haveIpv6Setting) + result.insert("ipv6", ipv6Setting.toMap()); + + impFile.close(); + return result; +} diff --git a/vpn/wireguard/wireguardadvancedwidget.h b/libs/editor/settings/wireguardpeerwidget.h rename from vpn/wireguard/wireguardadvancedwidget.h rename to libs/editor/settings/wireguardpeerwidget.h --- a/vpn/wireguard/wireguardadvancedwidget.h +++ b/libs/editor/settings/wireguardpeerwidget.h @@ -1,5 +1,5 @@ /* - Copyright 2018 Bruce Anderson + Copyright 2019 Bruce Anderson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,41 +18,43 @@ License along with this library. If not, see . */ -#ifndef PLASMA_NM_WIREGUARD_ADVANCED_WIDGET_H -#define PLASMA_NM_WIREGUARD_ADVANCED_WIDGET_H - -#include "passwordfield.h" +#ifndef PLASMA_NM_WIREGUARD_PEER_WIDGET_H +#define PLASMA_NM_WIREGUARD_PEER_WIDGET_H #include -#include - -namespace Ui -{ -class WireGuardAdvancedWidget; -} +#include "settingwidget.h" +#include -class QLineEdit; -class WireGuardAdvancedWidget : public QDialog +class Q_DECL_EXPORT WireGuardPeerWidget : public QDialog { - Q_OBJECT +Q_OBJECT public: - explicit WireGuardAdvancedWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent = nullptr); - ~WireGuardAdvancedWidget() override; - NetworkManager::VpnSetting::Ptr setting() const; + explicit WireGuardPeerWidget(const QVariantMap &peerData, QWidget *parent = nullptr, Qt::WindowFlags f = {}); + ~WireGuardPeerWidget() override; + + QVariantMap setting() const; + bool isValid(); + enum EndPointValid {BothValid, AddressValid, PortValid, BothInvalid}; + static WireGuardPeerWidget::EndPointValid isEndpointValid(QString&, QString&); + +Q_SIGNALS: + void notifyValid(); private: - void loadConfig(); - void setProperty(NMStringMap &data, const QLatin1String &key, const QString &value) const; - void setProperty(NMStringMap &data, const QLatin1String &key, const int value) const; - void checkPresharedKey(); - void checkTable(); - void checkFwMark(); void setBackground(QWidget *w, bool result) const; + void checkPublicKeyValid(); + void checkPresharedKeyValid(); + void checkAllowedIpsValid(); + void checkEndpointValid(); + void updatePeerWidgets(); + void saveKeepAlive(); + void saveKeyFlags(); void slotWidgetChanged(); + class Private; - Private *const d; + Private *d; }; -#endif // PLASMA_NM_WIREGUARD_ADVANCED_WIDGET_H +#endif // PLASMA_NM_WIREGUARD_PEER_WIDGET_H diff --git a/libs/editor/settings/wireguardpeerwidget.cpp b/libs/editor/settings/wireguardpeerwidget.cpp new file mode 100644 --- /dev/null +++ b/libs/editor/settings/wireguardpeerwidget.cpp @@ -0,0 +1,375 @@ +/* + Copyright 2019 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 "debug.h" +#include "wireguardpeerwidget.h" +#include "wireguardtabwidget.h" +#include "ui_wireguardpeerwidget.h" +#include "uiutils.h" +#include "simpleipv4addressvalidator.h" +#include "simpleiplistvalidator.h" +#include "wireguardkeyvalidator.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +// Keys for the NetworkManager configuration +#define PNM_SETTING_WIREGUARD_SETTING_NAME "wireguard" + +#define PNM_WG_KEY_PEERS "peers" +#define PNM_WG_KEY_MTU "mtu" +#define PNM_WG_KEY_PEER_ROUTES "peer-routes" +#define PNM_WG_PEER_KEY_ALLOWED_IPS "allowed-ips" +#define PNM_WG_PEER_KEY_ENDPOINT "endpoint" +#define PNM_WG_PEER_KEY_PERSISTENT_KEEPALIVE "persistent-keepalive" +#define PNM_WG_PEER_KEY_PRESHARED_KEY "preshared-key" +#define PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS "preshared-key-flags" +#define PNM_WG_PEER_KEY_PUBLIC_KEY "public-key" + +static WireGuardKeyValidator keyValidator(nullptr); +static SimpleIpListValidator allowedIPsValidator(nullptr, SimpleIpListValidator::WithCidr, + SimpleIpListValidator::Both); + +class WireGuardPeerWidget::Private +{ +public: + Private(); + ~Private(); + + Ui_WireGuardPeersProp ui; + NetworkManager::WireGuardSetting::Ptr setting; + KSharedConfigPtr config; + QPalette warningPalette; + QPalette normalPalette; + QVariantMap peerData; + bool publicKeyValid; + bool allowedIPsValid; + bool endpointValid; + bool presharedKeyValid; +}; + +WireGuardPeerWidget::Private::Private(void) + : publicKeyValid(false) + , allowedIPsValid(false) + , endpointValid(true) + , presharedKeyValid(true) +{ +} + +WireGuardPeerWidget::Private::~Private() +{ +} + +WireGuardPeerWidget::WireGuardPeerWidget(const QVariantMap &peerData, QWidget *parent, Qt::WindowFlags f) + : QDialog(parent, f) + , d(new Private) +{ + d->ui.setupUi(this); + d->peerData = peerData; + + d->config = KSharedConfig::openConfig(); + d->warningPalette = KColorScheme::createApplicationPalette(d->config); + d->normalPalette = KColorScheme::createApplicationPalette(d->config); + KColorScheme::adjustBackground(d->warningPalette, KColorScheme::NegativeBackground, QPalette::Base, + KColorScheme::ColorSet::View, d->config); + + KColorScheme::adjustBackground(d->normalPalette, KColorScheme::NormalBackground, QPalette::Base, + KColorScheme::ColorSet::View, d->config); + + setWindowTitle(i18nc("@title: window wireguard peers properties", + "WireGuard peers properties")); + connect(d->ui.publicKeyLineEdit, &QLineEdit::textChanged, this, &WireGuardPeerWidget::checkPublicKeyValid); + connect(d->ui.allowedIPsLineEdit, &QLineEdit::textChanged, this, &WireGuardPeerWidget::checkAllowedIpsValid); + connect(d->ui.endpointAddressLineEdit, &QLineEdit::textChanged, this, &WireGuardPeerWidget::checkEndpointValid); + connect(d->ui.endpointPortLineEdit, &QLineEdit::textChanged, this, &WireGuardPeerWidget::checkEndpointValid); + connect(d->ui.presharedKeyLineEdit, &PasswordField::textChanged, this, &WireGuardPeerWidget::checkPresharedKeyValid); + connect(d->ui.presharedKeyLineEdit, &PasswordField::passwordOptionChanged, this, &WireGuardPeerWidget::saveKeyFlags); + connect(d->ui.keepaliveLineEdit, &QLineEdit::textChanged, this, &WireGuardPeerWidget::saveKeepAlive); + + d->ui.presharedKeyLineEdit->setPasswordModeEnabled(true); + d->ui.presharedKeyLineEdit->setPasswordOptionsEnabled(true); + d->ui.presharedKeyLineEdit->setPasswordNotRequiredEnabled(true); + d->ui.presharedKeyLineEdit->setPasswordNotSavedEnabled(false); + + // Create validator for endpoint port + QIntValidator *portValidator = new QIntValidator(this); + portValidator->setBottom(0); + portValidator->setTop(65535); + d->ui.endpointPortLineEdit->setValidator(portValidator); + + // Reuse the port validator for the persistent keepalive. + // It is not a "port" but has the same limits + d->ui.keepaliveLineEdit->setValidator(portValidator); + + KAcceleratorManager::manage(this); + updatePeerWidgets(); + + // Set the initial backgrounds on all the widgets + checkPublicKeyValid(); + checkAllowedIpsValid(); + checkEndpointValid(); +} + +WireGuardPeerWidget::~WireGuardPeerWidget() +{ + delete d; +} + +QVariantMap WireGuardPeerWidget::setting() const +{ + return d->peerData; +} + +void WireGuardPeerWidget::checkPublicKeyValid() +{ + int pos = 0; + QLineEdit *widget = d->ui.publicKeyLineEdit; + QString value = widget->displayText(); + bool valid = QValidator::Acceptable == keyValidator.validate(value, pos); + setBackground(widget, valid); + d->peerData[PNM_WG_PEER_KEY_PUBLIC_KEY] = value; + if (valid != d->publicKeyValid) { + d->publicKeyValid = valid; + slotWidgetChanged(); + } +} + +void WireGuardPeerWidget::checkPresharedKeyValid() +{ + int pos = 0; + PasswordField *widget = d->ui.presharedKeyLineEdit; + QString value = widget->text(); + + // The value in the preshared key field is ignored if the type + // of password is set to "Ask every time" or "Not Required" so + // it is valid if it is set to "Store for user only" + // or "Store for all users" even if the password is bad + PasswordField::PasswordOption option = d->ui.presharedKeyLineEdit->passwordOption(); + bool valid = (QValidator::Acceptable == keyValidator.validate(value, pos) + || option == PasswordField::NotRequired); + setBackground(widget, valid); + if (value.isEmpty()) + d->peerData.remove(PNM_WG_PEER_KEY_PRESHARED_KEY); + else + d->peerData[PNM_WG_PEER_KEY_PRESHARED_KEY] = value; + if (valid != d->presharedKeyValid) { + d->presharedKeyValid = valid; + slotWidgetChanged(); + } +} + +void WireGuardPeerWidget::checkAllowedIpsValid() +{ + int pos = 0; + QLineEdit *widget = d->ui.allowedIPsLineEdit; + QString ipString = widget->displayText(); + QStringList ipList = ipString.split(','); + + bool valid = QValidator::Acceptable == allowedIPsValidator.validate(ipString, pos); + setBackground(widget, valid); + d->peerData[PNM_WG_PEER_KEY_ALLOWED_IPS] = ipList; + if (valid != d->allowedIPsValid) { + d->allowedIPsValid = valid; + slotWidgetChanged(); + } +} + +WireGuardPeerWidget::EndPointValid WireGuardPeerWidget::isEndpointValid(QString &address, QString &port) +{ + // Create a Reg Expression validator to do simple check for a valid qualified domain name + // which checks to see that there are between 2 and 63 strings of at least 2 characters each + // separated by '.', so "ab.cc" is valid but "a.cc" is not. The full string must also be less + // than 255 characters long. + static QRegExpValidator fqdnValidator(QRegExp(QLatin1String("(?=.{5,254}$)([a-zA-Z0-9][a-zA-Z0-9-]{1,62}\\.){1,63}[a-zA-Z]{2,63}")), nullptr); + static SimpleIpV4AddressValidator ipv4Validator(nullptr); + static SimpleIpV6AddressValidator ipv6Validator(nullptr); + int pos = 0; + + bool addressValid = QValidator::Acceptable == fqdnValidator.validate(address, pos) + || QValidator::Acceptable == ipv4Validator.validate(address, pos) + || QValidator::Acceptable == ipv6Validator.validate(address, pos); + bool bothEmpty = address.isEmpty() && port.isEmpty(); + // Because of the validator, if the port is non-empty, it is valid + bool portValid = !port.isEmpty(); + + if ((portValid && addressValid) || bothEmpty) + return WireGuardPeerWidget::BothValid; + else if (portValid) + return WireGuardPeerWidget::PortValid; + else if (addressValid) + return WireGuardPeerWidget::AddressValid; + else + return WireGuardPeerWidget::BothInvalid; +} + +void WireGuardPeerWidget::checkEndpointValid() +{ + QLineEdit *addressWidget = d->ui.endpointAddressLineEdit; + QLineEdit *portWidget = d->ui.endpointPortLineEdit; + QString addressString = addressWidget->displayText(); + QString portString = portWidget->displayText(); + + QUrl temp; + WireGuardPeerWidget::EndPointValid valid = isEndpointValid(addressString, portString); + + setBackground(addressWidget, WireGuardPeerWidget::BothValid == valid || WireGuardPeerWidget::AddressValid == valid); + setBackground(portWidget, WireGuardPeerWidget::BothValid == valid || WireGuardPeerWidget::PortValid == valid); + + // If there is a ':' in the address string then it is an IPv6 address and + // the output needs to be formatted as '[1:2:3:4:5:6:7:8]:123' otherwhise + // it is formatted as '1.2.3.4:123' or 'ab.com:123' + QString stringToStore; + if (addressString.contains(":")) + stringToStore = "[" + addressString.trimmed() + "]:" + portString.trimmed(); + else + stringToStore = addressString.trimmed() + ":" + portString.trimmed(); + + if (addressString.isEmpty() && portString.isEmpty()) + d->peerData.remove(PNM_WG_PEER_KEY_ENDPOINT); + else + d->peerData[PNM_WG_PEER_KEY_ENDPOINT] = stringToStore; + + if ((valid == WireGuardPeerWidget::BothValid) != d->endpointValid) { + d->endpointValid = (valid == WireGuardPeerWidget::BothValid); + slotWidgetChanged(); + } +} + +bool WireGuardPeerWidget::isValid() +{ + return d->publicKeyValid + && d->allowedIPsValid + && d->endpointValid + && d->presharedKeyValid; +} + +void WireGuardPeerWidget::saveKeepAlive() +{ + QLineEdit *widget = d->ui.keepaliveLineEdit; + QString value = widget->displayText(); + + if (value.isEmpty()) + d->peerData.remove(PNM_WG_PEER_KEY_PERSISTENT_KEEPALIVE); + else + d->peerData[PNM_WG_PEER_KEY_PERSISTENT_KEEPALIVE] = value; +} + +void WireGuardPeerWidget::saveKeyFlags() +{ + PasswordField::PasswordOption option = d->ui.presharedKeyLineEdit->passwordOption(); + switch (option) { + case PasswordField::StoreForUser: + d->peerData[PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS] = NetworkManager::Setting::AgentOwned; + break; + case PasswordField::StoreForAllUsers: + d->peerData[PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS] = NetworkManager::Setting::None; + break; + // Always Ask is not a valid option for the preshared key so set it to AgentOwned instead + case PasswordField::AlwaysAsk: + d->peerData[PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS] = NetworkManager::Setting::AgentOwned; + break; + case PasswordField::NotRequired: + d->peerData[PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS] = NetworkManager::Setting::NotRequired; + break; + } + checkPresharedKeyValid(); +} + +void WireGuardPeerWidget::setBackground(QWidget *w, bool result) const +{ + if (result) + w->setPalette(d->normalPalette); + else + w->setPalette(d->warningPalette); +} + +void WireGuardPeerWidget::updatePeerWidgets() +{ + d->ui.presharedKeyLineEdit->setPasswordModeEnabled(true); + + if (d->peerData.contains(PNM_WG_PEER_KEY_PUBLIC_KEY)) + d->ui.publicKeyLineEdit->setText(d->peerData[PNM_WG_PEER_KEY_PUBLIC_KEY].toString()); + else + d->ui.publicKeyLineEdit->clear(); + + if (d->peerData.contains(PNM_WG_PEER_KEY_ALLOWED_IPS)) { + QStringList allowedIps = d->peerData[PNM_WG_PEER_KEY_ALLOWED_IPS].toStringList(); + d->ui.allowedIPsLineEdit->setText(allowedIps.join(",")); + } else { + d->ui.allowedIPsLineEdit->clear(); + } + + if (d->peerData.contains(PNM_WG_PEER_KEY_PERSISTENT_KEEPALIVE)) + d->ui.keepaliveLineEdit->setText(d->peerData[PNM_WG_PEER_KEY_PERSISTENT_KEEPALIVE].toString()); + else + d->ui.keepaliveLineEdit->clear(); + + // An endpoint is stored as : + if (d->peerData.contains(PNM_WG_PEER_KEY_ENDPOINT)) { + QString storedEndpoint = d->peerData[PNM_WG_PEER_KEY_ENDPOINT].toString(); + QStringList endpointList = storedEndpoint.contains("]:") ? + d->peerData[PNM_WG_PEER_KEY_ENDPOINT].toString().split("]:") : + d->peerData[PNM_WG_PEER_KEY_ENDPOINT].toString().split(":"); + + d->ui.endpointAddressLineEdit->setText(endpointList[0].remove("[")); + d->ui.endpointPortLineEdit->setText(endpointList[1]); + } else { + d->ui.endpointAddressLineEdit->clear(); + d->ui.endpointPortLineEdit->clear(); + } + if (d->peerData.contains(PNM_WG_PEER_KEY_PRESHARED_KEY)) + d->ui.presharedKeyLineEdit->setText(d->peerData[PNM_WG_PEER_KEY_PRESHARED_KEY].toString()); + else + d->ui.presharedKeyLineEdit->setText(""); + + if (d->peerData.contains(PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS)) { + NetworkManager::Setting::SecretFlags type = static_cast(d->peerData[PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS].toUInt()); + switch (type) { + case NetworkManager::Setting::AgentOwned: + d->ui.presharedKeyLineEdit->setPasswordOption(PasswordField::StoreForUser); + break; + case NetworkManager::Setting::None: + d->ui.presharedKeyLineEdit->setPasswordOption(PasswordField::StoreForAllUsers); + break; + // Not saved is not a valid option for the private key so set it to StoreForUser instead + case NetworkManager::Setting::NotSaved: + d->ui.presharedKeyLineEdit->setPasswordOption(PasswordField::StoreForUser); + break; + case NetworkManager::Setting::NotRequired: + d->ui.presharedKeyLineEdit->setPasswordOption(PasswordField::NotRequired); + break; + } + } else { + d->ui.presharedKeyLineEdit->setPasswordOption(PasswordField::NotRequired); + } + + slotWidgetChanged(); +} + +void WireGuardPeerWidget::slotWidgetChanged() +{ + Q_EMIT notifyValid(); +} diff --git a/vpn/wireguard/wireguardadvancedwidget.h b/libs/editor/settings/wireguardtabwidget.h rename from vpn/wireguard/wireguardadvancedwidget.h rename to libs/editor/settings/wireguardtabwidget.h --- a/vpn/wireguard/wireguardadvancedwidget.h +++ b/libs/editor/settings/wireguardtabwidget.h @@ -1,5 +1,5 @@ /* - Copyright 2018 Bruce Anderson + Copyright 2019 Bruce Anderson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,41 +18,37 @@ License along with this library. If not, see . */ -#ifndef PLASMA_NM_WIREGUARD_ADVANCED_WIDGET_H -#define PLASMA_NM_WIREGUARD_ADVANCED_WIDGET_H - -#include "passwordfield.h" +#ifndef PLASMA_NM_WIREGUARD_PEERS_TAB_WIDGET_H +#define PLASMA_NM_WIREGUARD_PEERS_TAB_WIDGET_H #include -#include - -namespace Ui -{ -class WireGuardAdvancedWidget; -} +#include "settingwidget.h" +#include -class QLineEdit; -class WireGuardAdvancedWidget : public QDialog +class Q_DECL_EXPORT WireGuardTabWidget : public QDialog { - Q_OBJECT +Q_OBJECT public: - explicit WireGuardAdvancedWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent = nullptr); - ~WireGuardAdvancedWidget() override; - NetworkManager::VpnSetting::Ptr setting() const; + explicit WireGuardTabWidget(const NMVariantMapList &peerData, QWidget *parent = nullptr, Qt::WindowFlags f = {}); + ~WireGuardTabWidget() override; + + enum EndPointValid {BothValid, AddressValid, PortValid, BothInvalid}; + + void loadConfig(const NMVariantMapList &peerData); + + NMVariantMapList setting() const; + + void slotAddPeer(); + void slotAddPeerWithData(const QVariantMap &peerData); + void slotRemovePeer(); private: - void loadConfig(); - void setProperty(NMStringMap &data, const QLatin1String &key, const QString &value) const; - void setProperty(NMStringMap &data, const QLatin1String &key, const int value) const; - void checkPresharedKey(); - void checkTable(); - void checkFwMark(); - void setBackground(QWidget *w, bool result) const; void slotWidgetChanged(); + class Private; - Private *const d; + Private *d; }; -#endif // PLASMA_NM_WIREGUARD_ADVANCED_WIDGET_H +#endif // PLASMA_NM_WIREGUARD_PEERS_TABS_WIDGET_H diff --git a/libs/editor/settings/wireguardtabwidget.cpp b/libs/editor/settings/wireguardtabwidget.cpp new file mode 100644 --- /dev/null +++ b/libs/editor/settings/wireguardtabwidget.cpp @@ -0,0 +1,178 @@ +/* + Copyright 2019 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 "debug.h" +#include "wireguardtabwidget.h" +#include "wireguardpeerwidget.h" +#include "ui_wireguardtabwidget.h" +#include "ui_wireguardpeerwidget.h" +#include "uiutils.h" +#include "simpleipv4addressvalidator.h" +#include "simpleiplistvalidator.h" +#include "wireguardkeyvalidator.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +// Keys for the NetworkManager configuration +#define PNM_SETTING_WIREGUARD_SETTING_NAME "wireguard" + +#define PNM_WG_KEY_PEERS "peers" +#define PNM_WG_KEY_MTU "mtu" +#define PNM_WG_KEY_PEER_ROUTES "peer-routes" +#define PNM_WG_PEER_KEY_ALLOWED_IPS "allowed-ips" +#define PNM_WG_PEER_KEY_ENDPOINT "endpoint" +#define PNM_WG_PEER_KEY_PERSISTENT_KEEPALIVE "persistent-keepalive" +#define PNM_WG_PEER_KEY_PRESHARED_KEY "preshared-key" +#define PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS "preshared-key-flags" +#define PNM_WG_PEER_KEY_PUBLIC_KEY "public-key" + +static WireGuardKeyValidator keyValidator(nullptr); +static SimpleIpListValidator allowedIPsValidator(nullptr, SimpleIpListValidator::WithCidr, + SimpleIpListValidator::Both); + +class WireGuardTabWidget::Private +{ +public: + Private(); + ~Private(); + + Ui_WireGuardTabWidget ui; + NetworkManager::WireGuardSetting::Ptr setting; + KSharedConfigPtr config; + NMVariantMapList peers; + int currentIndex; + bool currentPeerValid; + bool otherPeersValid; +}; + +WireGuardTabWidget::Private::Private(void) +{ +} + +WireGuardTabWidget::Private::~Private() +{ +} + +WireGuardTabWidget::WireGuardTabWidget(const NMVariantMapList &peerData, QWidget *parent, Qt::WindowFlags f) + : QDialog(parent, f) + , d(new Private) +{ + d->ui.setupUi(this); + + d->config = KSharedConfig::openConfig(); + setWindowTitle(i18nc("@title: window wireguard peers properties", + "WireGuard peers properties")); + connect(d->ui.btnAdd, &QPushButton::clicked, this, &WireGuardTabWidget::slotAddPeer); + connect(d->ui.btnRemove, &QPushButton::clicked, this, &WireGuardTabWidget::slotRemovePeer); + connect(d->ui.buttonBox, &QDialogButtonBox::accepted, this, &WireGuardTabWidget::accept); + connect(d->ui.buttonBox, &QDialogButtonBox::rejected, this, &WireGuardTabWidget::reject); + + KAcceleratorManager::manage(this); + + loadConfig(peerData); + + if (peerData.isEmpty()) + slotAddPeer(); +} + +WireGuardTabWidget::~WireGuardTabWidget() +{ + delete d; +} + +void WireGuardTabWidget::loadConfig(const NMVariantMapList &peerData) +{ + d->peers = peerData; + int numIncomingPeers = d->peers.size(); + + // If there weren't any peers in the incoming setting, create + // the required first element + if (d->peers.isEmpty()) + d->peers.append(*(new QVariantMap())); + + for (int i = 0; i < numIncomingPeers; i++) { + slotAddPeerWithData(peerData[i]); + } + d->ui.tabWidget->setCurrentIndex(0); +} + +NMVariantMapList WireGuardTabWidget::setting() const +{ + d->peers.clear(); + for (int i = 0; i < d->ui.tabWidget->count(); i++) + d->peers.append(static_cast(d->ui.tabWidget->widget(i))->setting()); + return d->peers; +} + +void WireGuardTabWidget::slotAddPeer() +{ + QVariantMap *newItem = new QVariantMap; + int numPeers = d->ui.tabWidget->count() + 1; + WireGuardPeerWidget *newTab = new WireGuardPeerWidget(*newItem); + connect(newTab, &WireGuardPeerWidget::notifyValid, this, &WireGuardTabWidget::slotWidgetChanged); + d->ui.tabWidget->addTab(newTab, QString("Peer %1").arg(QString::number(numPeers))); + d->peers.append(*newItem); + d->ui.tabWidget->setCurrentIndex(numPeers - 1); + slotWidgetChanged(); +} + +void WireGuardTabWidget::slotAddPeerWithData(const QVariantMap &peerData) +{ + int numPeers = d->ui.tabWidget->count() + 1; + WireGuardPeerWidget *newTab = new WireGuardPeerWidget(peerData); + d->ui.tabWidget->addTab(newTab, QString("Peer %1").arg(QString::number(numPeers))); + connect(newTab, &WireGuardPeerWidget::notifyValid, this, &WireGuardTabWidget::slotWidgetChanged); + d->peers.append(peerData); + d->ui.tabWidget->setCurrentIndex(numPeers - 1); + slotWidgetChanged(); +} + +void WireGuardTabWidget::slotRemovePeer() +{ + int numPeers = d->ui.tabWidget->count() - 1; + d->ui.tabWidget->removeTab(d->ui.tabWidget->currentIndex()); + if (numPeers == 0) { + slotAddPeer(); + numPeers = 1; + } + + // Retitle the tabs to reflect the current numbers + for (int i = 0; i < numPeers; i++) + d->ui.tabWidget->setTabText(i, QString("Peer %1").arg(QString::number(i + 1))); +} + +void WireGuardTabWidget::slotWidgetChanged() +{ + bool valid = true; + for (int i = 0; i < d->ui.tabWidget->count(); i++) { + if (!static_cast(d->ui.tabWidget->widget(i))->isValid()) { + valid = false; + break; + } + } + d->ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); +} diff --git a/vpn/wireguard/wireguardkeyvalidator.h b/libs/editor/wireguardkeyvalidator.h rename from vpn/wireguard/wireguardkeyvalidator.h rename to libs/editor/wireguardkeyvalidator.h diff --git a/vpn/wireguard/wireguardkeyvalidator.cpp b/libs/editor/wireguardkeyvalidator.cpp rename from vpn/wireguard/wireguardkeyvalidator.cpp rename to libs/editor/wireguardkeyvalidator.cpp --- a/vpn/wireguard/wireguardkeyvalidator.cpp +++ b/libs/editor/wireguardkeyvalidator.cpp @@ -26,7 +26,9 @@ m_validator = new QRegularExpressionValidator(this); // A WireGuard key is Base64 encoded and in human readable form consists // 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}="))); + // The 43rd character is limited such that the converted character zeroes in + // the 2 LSB. + m_validator->setRegularExpression(QRegularExpression(QLatin1String("[0-9a-zA-Z\\+/]{42,42}[AEIMQUYcgkosw048]="))); } WireGuardKeyValidator::~WireGuardKeyValidator() diff --git a/libs/models/creatableconnectionsmodel.cpp b/libs/models/creatableconnectionsmodel.cpp --- a/libs/models/creatableconnectionsmodel.cpp +++ b/libs/models/creatableconnectionsmodel.cpp @@ -175,6 +175,15 @@ QString(), QString(), true); // VpnType and SpecificType are empty m_list << connectionItem; + // WireGuard changed from VPN plugin to primary device in version 1.16 of NetworkManager + if (NetworkManager::checkVersion(1, 16, 0)) { + connectionItem = new CreatableConnectionItem(i18n("WireGuard"), i18n("VPN connections"), + i18n("WireGuard"), QStringLiteral("network-vpn"), + NetworkManager::ConnectionSettings::WireGuard, + QStringLiteral("WireGuard"), QString(), true); // VpnType and SpecificType are empty + m_list << connectionItem; + } + if (Configuration::manageVirtualConnections()) { connectionItem = new CreatableConnectionItem(i18n("Bond"), i18n("Virtual connections"), i18n("Some bond description"), QStringLiteral("network-wired"), @@ -199,6 +208,7 @@ NetworkManager::ConnectionSettings::Vlan, QString(), QString(), true); // VpnType and SpecificType are empty m_list << connectionItem; + } KService::List services = KServiceTypeTrader::self()->query("PlasmaNetworkManagement/VpnUiPlugin"); diff --git a/libs/models/networkmodelitem.cpp b/libs/models/networkmodelitem.cpp --- a/libs/models/networkmodelitem.cpp +++ b/libs/models/networkmodelitem.cpp @@ -17,7 +17,6 @@ You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ - #include "networkmodelitem.h" #include "uiutils.h" @@ -205,6 +204,7 @@ case NetworkManager::ConnectionSettings::Vlan: break; case NetworkManager::ConnectionSettings::Vpn: + case NetworkManager::ConnectionSettings::WireGuard: return QStringLiteral("network-vpn"); break; case NetworkManager::ConnectionSettings::Wired: @@ -252,7 +252,7 @@ m_type == NetworkManager::ConnectionSettings::Team || ((NetworkManager::status() == NetworkManager::Connected || NetworkManager::status() == NetworkManager::ConnectedLinkLocal || - NetworkManager::status() == NetworkManager::ConnectedSiteOnly) && m_type == NetworkManager::ConnectionSettings::Vpn)) { + NetworkManager::status() == NetworkManager::ConnectedSiteOnly) && (m_type == NetworkManager::ConnectionSettings::Vpn || m_type == NetworkManager::ConnectionSettings::WireGuard))) { if (m_connectionPath.isEmpty() && m_type == NetworkManager::ConnectionSettings::Wireless) { return NetworkModelItem::AvailableAccessPoint; } else { @@ -477,7 +477,6 @@ } } } - if (m_type == NetworkManager::ConnectionSettings::Wired) { NetworkManager::WiredDevice::Ptr wiredDevice = device.objectCast(); if (wiredDevice) { diff --git a/libs/uiutils.h b/libs/uiutils.h --- a/libs/uiutils.h +++ b/libs/uiutils.h @@ -52,6 +52,7 @@ Infiniband, OLPCMesh, Bluetooth, + Wireguard, Vpn, Vlan, Bridge, diff --git a/libs/uiutils.cpp b/libs/uiutils.cpp --- a/libs/uiutils.cpp +++ b/libs/uiutils.cpp @@ -102,6 +102,9 @@ case NetworkManager::ConnectionSettings::Wireless: return UiUtils::Wireless; break; + case NetworkManager::ConnectionSettings::WireGuard: + return UiUtils::Wireguard; + break; default: return UiUtils::Unknown; break; @@ -247,6 +250,10 @@ case ConnectionSettings::Team: text = i18n("Team"); break; + case ConnectionSettings::WireGuard: + text = i18n("WireGuard VPN"); + icon = QStringLiteral("network-vpn"); + break; default: text = i18n("Unknown connection type"); break; diff --git a/vpn/CMakeLists.txt b/vpn/CMakeLists.txt --- a/vpn/CMakeLists.txt +++ b/vpn/CMakeLists.txt @@ -11,5 +11,3 @@ add_subdirectory(sstp) add_subdirectory(strongswan) add_subdirectory(vpnc) -add_subdirectory(wireguard) - diff --git a/vpn/wireguard/CMakeLists.txt b/vpn/wireguard/CMakeLists.txt deleted file mode 100644 --- a/vpn/wireguard/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -add_definitions(-DTRANSLATION_DOMAIN=\"plasmanetworkmanagement_wireguardui\") - -set(wireguard_SRCS - ../../libs/debug.cpp - wireguard.cpp - wireguardwidget.cpp - wireguardauth.cpp - wireguardadvancedwidget.cpp - wireguardkeyvalidator.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 - KF5::ConfigCore - KF5::CoreAddons - KF5::I18n - KF5::KIOWidgets - KF5::WidgetsAddons - KF5::ConfigWidgets -) - -install(TARGETS plasmanetworkmanagement_wireguardui DESTINATION ${PLUGIN_INSTALL_DIR}) - -install(FILES plasmanetworkmanagement_wireguardui.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/vpn/wireguard/Messages.sh b/vpn/wireguard/Messages.sh deleted file mode 100644 --- a/vpn/wireguard/Messages.sh +++ /dev/null @@ -1,3 +0,0 @@ -#! /usr/bin/env bash -$EXTRACTRC `find . -name "*.ui" -o -name "*.rc"` >> rc.cpp -$XGETTEXT `find . -name "*.cpp"` -o $podir/plasmanetworkmanagement_wireguardui.pot diff --git a/vpn/wireguard/nm-wireguard-service.h b/vpn/wireguard/nm-wireguard-service.h deleted file mode 100644 --- a/vpn/wireguard/nm-wireguard-service.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- 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" -#define NM_WG_KEY_PRE_UP "script-pre-up" -#define NM_WG_KEY_POST_UP "script-post-up" -#define NM_WG_KEY_PRE_DOWN "script-pre-down" -#define NM_WG_KEY_POST_DOWN "script-post-down" -#define NM_WG_KEY_PERSISTENT_KEEPALIVE "peer-persistent-keep-alive" - -#endif /* NM_WIREGUARD_SERVICE_H */ diff --git a/vpn/wireguard/plasmanetworkmanagement_wireguardui.desktop b/vpn/wireguard/plasmanetworkmanagement_wireguardui.desktop deleted file mode 100644 --- a/vpn/wireguard/plasmanetworkmanagement_wireguardui.desktop +++ /dev/null @@ -1,61 +0,0 @@ -[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 -Name[ca]=VPN basada en WireGuard -Name[ca@valencia]=VPN basada en WireGuard -Name[de]=VPN basierend auf WireGuard -Name[en_GB]=WireGuard based VPN -Name[es]=VPN basada en WireGuard -Name[fi]=WireGuard-pohjainen VPN -Name[fr]=VPN reposant sur WireGuard -Name[gl]=VPN baseada en WireGuard -Name[id]=VPN berbasis WireGuard -Name[it]=VPN basata su WireGuard -Name[nl]=Op WireGuard gebaseerde VPN -Name[nn]=WireGuard-basert VPN -Name[pl]=VPN oparte na WireGuard -Name[pt]=VPN baseada no WireGuard -Name[pt_BR]=VPN baseada no WireGuard -Name[ru]=VPN на основе WireGuard -Name[sk]=VPN pomocou WireGuard -Name[sv]=WireGuard-baserad VPN -Name[uk]=WireGuard на основі VPN -Name[x-test]=xxWireGuard based VPNxx -Name[zh_CN]=基于 WireGuard 的 VPN -Name[zh_TW]=基於 VPN 的 WireGuard -Comment=Compatible with WireGuard VPN servers -Comment[ca]=Compatible amb els servidors VPN del WireGuard -Comment[ca@valencia]=Compatible amb els servidors VPN del WireGuard -Comment[de]=Mit WireGuard-VPN-Servern kompatibel -Comment[en_GB]=Compatible with WireGuard VPN servers -Comment[es]=Compatible con servidores VPN WireGuard -Comment[fi]=Yhteensopiva WireGuard-VPN-palvelinten kanssa -Comment[fr]=Compatible avec les serveurs VPN WireGuard -Comment[gl]=Compatíbel con servidores de VPN que usen WireGuard. -Comment[id]=Kompatibel dengan server-server VPN WireGuard -Comment[it]=Compatibile con i server VPN WireGuard -Comment[nl]=Compatibel met WireGuard VPN-servers -Comment[nn]=Kompatibel med WireGuard VPN-tenarar -Comment[pl]=Zgodny z serwerami VPN WireGuard -Comment[pt]=Compatível com os servidores de VPN da WireGuard -Comment[pt_BR]=Compatível com os servidores VPN do WireGuard -Comment[ru]=Совместимая с серверами VPN на основе WireGuard -Comment[sk]=Kompatibilné s Wireguard VPN servermi -Comment[sv]=Kompatibel med WireGuard VPN-servrar -Comment[uk]=Сумісні з WireGuard сервери VPN -Comment[x-test]=xxCompatible with WireGuard VPN serversxx -Comment[zh_CN]=兼容 WireGuard VPN 服务器 -Comment[zh_TW]=相容 WireGuard VPN 伺服器 diff --git a/vpn/wireguard/wireguard.h b/vpn/wireguard/wireguard.h deleted file mode 100644 --- a/vpn/wireguard/wireguard.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - 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" - -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 deleted file mode 100644 --- a/vpn/wireguard/wireguard.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/* - 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 - -#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_CLASS_WITH_JSON(WireGuardUiPlugin, "plasmanetworkmanagement_wireguardui.json") - -#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" -#define NMV_WG_TAG_PERSISTENT_KEEPALIVE "PersistentKeepalive" - - -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; - QVariantMap ipv6Data; - - QString value; - QStringList valueList; - QList ipv4List; - QList ipv6List; - int intValue; - - NetworkManager::Ipv4Setting ipv4Setting; - NetworkManager::Ipv6Setting ipv6Setting; - - // 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(nullptr); - int pos = 0; - - // Private Key - value = interfaceGroup.readEntry(NMV_WG_TAG_PRIVATE_KEY); - if (!value.isEmpty()) { - if (keyValidator.validate(value, pos) == 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, pos) == 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()) { - 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 servers are added slightly differently in that they are not added - // to the [vpn] section of the setup but to the [ipv4] and/or [ipv6] - // sections. - valueList = interfaceGroup.readEntry(NMV_WG_TAG_DNS, QStringList()); - if (!valueList.isEmpty()) { - for (const QString &address : valueList) { - const QPair addressIn = QHostAddress::parseSubnet(address.trimmed()); - if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) { - ipv4List.append(addressIn.first); - } else if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv6Protocol) { - ipv6List.append(addressIn.first); - } else { // Error condition - mError = VpnUiPlugin::Error; - mErrorMessage = i18n("No valid address in config file"); - return result; - } - } - - // If there are any addresses put them on the correct tab and set the "method" to - // "Automatic (Only addresses)" by setting "ignore-auto-dns=true" - if (!ipv4List.isEmpty()) { - ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Automatic); - ipv4Setting.setIgnoreAutoDns(true); - ipv4Setting.setDns(ipv4List); - } - - if (!ipv6List.isEmpty()) { - ipv6Setting.setMethod(NetworkManager::Ipv6Setting::Automatic); - ipv6Setting.setIgnoreAutoDns(true); - ipv6Setting.setDns(ipv6List); - } - } - - // 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); - - // PreUp - value = interfaceGroup.readEntry(NMV_WG_TAG_PRE_UP); - if (!value.isEmpty()) - dataMap.insert(QLatin1String(NM_WG_KEY_PRE_UP), value); - - // PostUp - value = interfaceGroup.readEntry(NMV_WG_TAG_POST_UP); - if (!value.isEmpty()) - dataMap.insert(QLatin1String(NM_WG_KEY_POST_UP), value); - - // PreDown - value = interfaceGroup.readEntry(NMV_WG_TAG_PRE_DOWN); - if (!value.isEmpty()) - dataMap.insert(QLatin1String(NM_WG_KEY_PRE_DOWN), value); - - // PostDown - value = interfaceGroup.readEntry(NMV_WG_TAG_POST_DOWN); - if (!value.isEmpty()) - dataMap.insert(QLatin1String(NM_WG_KEY_POST_DOWN), 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, pos) == 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; - } - } - - // Persistent Keepalive - intValue = peerGroup.readEntry(NMV_WG_TAG_PERSISTENT_KEEPALIVE, -1); - if (intValue > -1) - dataMap.insert(QLatin1String(NM_WG_KEY_PERSISTENT_KEEPALIVE), QString::number(intValue)); - - 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()); - if (!ipv4List.isEmpty()) { - result.insert("ipv4", ipv4Setting.toMap()); - } - if (!ipv6List.isEmpty()) { - result.insert("ipv6", ipv6Setting.toMap()); - } - - return result; -} - -bool WireGuardUiPlugin::exportConnectionSettings(const NetworkManager::ConnectionSettings::Ptr &connection, - const QString &fileName) -{ - NetworkManager::VpnSetting::Ptr vpnSetting = connection->setting( - NetworkManager::Setting::Vpn).dynamicCast(); - NetworkManager::Ipv4Setting::Ptr ipv4Setting = connection->setting( - NetworkManager::Setting::Ipv4).dynamicCast(); - NetworkManager::Ipv6Setting::Ptr ipv6Setting = connection->setting( - NetworkManager::Setting::Ipv6).dynamicCast(); - QList ipv4Dns = ipv4Setting->dns(); - QList ipv6Dns = ipv6Setting->dns(); - 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) - // DNS is a little complicated because the first version of plasma-nm-wireguard included - // the DNS key in the VPN settings but this was changed in a later version such that it - // uses DNS from the IPv4 and IPv6 tabs instead, so here we check to see if the IPv4 and/or - // the IPv6 tabs contain DNS entries and if so use those. Otherwise see if we have an - // old style VPN setting with DNS in it and if so use that. - if (ipv4Dns.count() > 0 || ipv6Dns.count() > 0) { - QStringList dnsList; - for (QHostAddress addr : ipv4Dns) - dnsList.append(addr.toString()); - for (QHostAddress addr : ipv6Dns) - dnsList.append(addr.toString()); - interfaceGroup.writeEntry(NMV_WG_TAG_DNS, dnsList); - } else 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 PreUp (Not required) - if (dataMap.contains(QLatin1String(NM_WG_KEY_PRE_UP))) - interfaceGroup.writeEntry(NMV_WG_TAG_PRE_UP, dataMap[NM_WG_KEY_PRE_UP]); - - // Do PostUp (Not required) - if (dataMap.contains(QLatin1String(NM_WG_KEY_POST_UP))) - interfaceGroup.writeEntry(NMV_WG_TAG_POST_UP, dataMap[NM_WG_KEY_POST_UP]); - - // Do PreDown (Not required) - if (dataMap.contains(QLatin1String(NM_WG_KEY_PRE_DOWN))) - interfaceGroup.writeEntry(NMV_WG_TAG_PRE_DOWN, dataMap[NM_WG_KEY_PRE_DOWN]); - - // Do PostDown (Not required) - if (dataMap.contains(QLatin1String(NM_WG_KEY_POST_DOWN))) - interfaceGroup.writeEntry(NMV_WG_TAG_POST_DOWN, dataMap[NM_WG_KEY_POST_DOWN]); - - // Do Public 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]); - - // Do Persistent Keepalive (Not required) - if (dataMap.contains(QLatin1String(NM_WG_KEY_PERSISTENT_KEEPALIVE))) - peerGroup.writeEntry(NMV_WG_TAG_PERSISTENT_KEEPALIVE, dataMap[NM_WG_KEY_PERSISTENT_KEEPALIVE]); - - exportFile.sync(); - return true; -} - -#include "wireguard.moc" diff --git a/vpn/wireguard/wireguardadvanced.ui b/vpn/wireguard/wireguardadvanced.ui deleted file mode 100644 --- a/vpn/wireguard/wireguardadvanced.ui +++ /dev/null @@ -1,252 +0,0 @@ - - - WireGuardAdvancedWidget - - - - 0 - 0 - 398 - 380 - - - - WireGuard Advanced - - - - - - Interface - - - - - - Listen port: - - - - - - - Listen port number. Chosen randomly if left as 'Automatic'. - - - - - - - MTU: - - - - - - - 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. - - - - - - - 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'. - - - - - - - Pre-up command: - - - - - - - Optional. -Script snippet which will be executed by bash(1) -before setting up the interface. Most commonly used -to configure custom DNS options or firewall rules. -The special string `%i' is expanded to INTERFACE. - - - - - - - Post-up command: - - - - - - - Optional. -Script snippet which will be executed by bash(1) -after setting up the interface. Most commonly used -to configure custom DNS options or firewall rules. -The special string `%i' is expanded to INTERFACE. - - - - - - - Pre-down command: - - - - - - - Optional. -Script snippet which will be executed by bash(1) -before tearing down the interface. Most commonly used -to configure custom DNS options or firewall rules. -The special string `%i' is expanded to INTERFACE. - - - - - - - Post-down command: - - - - - - - Optional. -Script snippet which will be executed by bash(1) -after tearing down the interface. Most commonly used -to configure custom DNS options or firewall rules. -The special string `%i' is expanded to INTERFACE. - - - - - - - - - - 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. - - - - - - - Persistent Keepalive: - - - - - - - Optional. -A seconds interval, between 1 and 65535 inclusive, of -how often to send an authenticated empty packet to -the peer for the purpose of keeping a stateful firewall -or NAT mapping valid persistently. For example, if the -interface very rarely sends traffic, but it might at -anytime receive traffic from a peer, and it is behind -NAT, the interface might benefit from having a -persistent keepalive interval of 25 seconds. If set to -0 or "off", this option is disabled. By default or -when unspecified, this option is off. Most users will not -need this. - - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - PasswordField - QLineEdit -
passwordfield.h
-
-
- - -
diff --git a/vpn/wireguard/wireguardadvancedwidget.cpp b/vpn/wireguard/wireguardadvancedwidget.cpp deleted file mode 100644 --- a/vpn/wireguard/wireguardadvancedwidget.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/* - 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 -#include -#include "ui_wireguardadvanced.h" -#include "nm-wireguard-service.h" -#include "settingwidget.h" -#include "wireguardkeyvalidator.h" - -class WireGuardAdvancedWidget::Private -{ -public: - ~Private(); - Private(); - - NetworkManager::VpnSetting::Ptr setting; - Ui::WireGuardAdvancedWidget ui; - QPalette warningPalette; - QPalette normalPalette; - WireGuardKeyValidator *keyValidator; - QIntValidator *listenPortValidator; - QIntValidator *mtuValidator; - QRegularExpressionValidator *fwMarkValidator; - QIntValidator *persistentKeepaliveValidator; - QRegularExpressionValidator *tableValidator; - bool fwMarkValid; - bool presharedKeyValid; - bool tableValid; -}; - -WireGuardAdvancedWidget::Private::Private() - : fwMarkValid(true) - , presharedKeyValid(true) - , tableValid(true) -{ -} - -WireGuardAdvancedWidget::Private::~Private() -{ - delete keyValidator; - delete listenPortValidator; - delete mtuValidator; - delete fwMarkValidator; - delete persistentKeepaliveValidator; - delete tableValidator; -} - -WireGuardAdvancedWidget::WireGuardAdvancedWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent) - : QDialog(parent) - , d(new Private) -{ - KSharedConfigPtr config = KSharedConfig::openConfig(); - d->warningPalette = KColorScheme::createApplicationPalette(config); - d->normalPalette = KColorScheme::createApplicationPalette(config); - KColorScheme::adjustBackground(d->warningPalette, - KColorScheme::NegativeBackground, - QPalette::Base, - KColorScheme::ColorSet::View, - config); - - KColorScheme::adjustBackground(d->normalPalette, - KColorScheme::NormalBackground, - QPalette::Base, - KColorScheme::ColorSet::View, - config); - - d->keyValidator = new WireGuardKeyValidator(this); - d->ui.setupUi(this); - - setWindowTitle(i18nc("@title: window advanced wireguard properties", - "Advanced WireGuard properties")); - - d->setting = setting; - - connect(d->ui.buttonBox, &QDialogButtonBox::accepted, this, &WireGuardAdvancedWidget::accept); - connect(d->ui.buttonBox, &QDialogButtonBox::rejected, this, &WireGuardAdvancedWidget::reject); - connect(d->ui.presharedKeyLineEdit, &PasswordField::textChanged, this, &WireGuardAdvancedWidget::checkPresharedKey); - connect(d->ui.tableLineEdit, &QLineEdit::textChanged, this, &WireGuardAdvancedWidget::checkTable); - connect(d->ui.fwMarkLineEdit, &QLineEdit::textChanged, this, &WireGuardAdvancedWidget::checkFwMark); - d->ui.presharedKeyLineEdit->setPasswordModeEnabled(true); - - d->listenPortValidator = new QIntValidator(0, 65535, nullptr); - d->ui.listenPortLineEdit->setValidator(d->listenPortValidator); - - d->persistentKeepaliveValidator = new QIntValidator(0, 65535, nullptr); - d->ui.persistentKeepaliveLineEdit->setValidator(d->persistentKeepaliveValidator); - - d->mtuValidator = new QIntValidator(nullptr); - d->mtuValidator->setBottom(0); - d->ui.mtuLineEdit->setValidator(d->mtuValidator); - - d->fwMarkValidator = new QRegularExpressionValidator(QRegularExpression("(off)|([0-9]{0,10})|(0x[0-9a-fA-F]{1,8})")); - d->ui.fwMarkLineEdit->setValidator(d->fwMarkValidator); - - d->tableValidator = new QRegularExpressionValidator(QRegularExpression("(off)|(auto)|([0-9]*)")); - d->ui.tableLineEdit->setValidator(d->tableValidator); - - KAcceleratorManager::manage(this); - - if (d->setting) { - loadConfig(); - } - checkPresharedKey(); - checkFwMark(); - checkTable(); -} - -WireGuardAdvancedWidget::~WireGuardAdvancedWidget() -{ - delete d; -} - -void WireGuardAdvancedWidget::loadConfig() -{ - const NMStringMap dataMap = d->setting->data(); - - if (dataMap.contains(QLatin1String(NM_WG_KEY_LISTEN_PORT))) - d->ui.listenPortLineEdit->setText(dataMap[NM_WG_KEY_LISTEN_PORT]); - else - d->ui.listenPortLineEdit->clear(); - - if (dataMap.contains(QLatin1String(NM_WG_KEY_PERSISTENT_KEEPALIVE))) - d->ui.persistentKeepaliveLineEdit->setText(dataMap[NM_WG_KEY_PERSISTENT_KEEPALIVE]); - else - d->ui.persistentKeepaliveLineEdit->clear(); - - if (dataMap.contains(QLatin1String(NM_WG_KEY_MTU))) - d->ui.mtuLineEdit->setText(dataMap[NM_WG_KEY_MTU]); - else - d->ui.mtuLineEdit->clear(); - - if (dataMap.contains(QLatin1String(NM_WG_KEY_TABLE))) - d->ui.tableLineEdit->setText(dataMap[NM_WG_KEY_TABLE]); - else - d->ui.tableLineEdit->clear(); - - if (dataMap.contains(QLatin1String(NM_WG_KEY_FWMARK))) - d->ui.fwMarkLineEdit->setText(dataMap[NM_WG_KEY_FWMARK]); - else - d->ui.fwMarkLineEdit->clear(); - - if (dataMap.contains(QLatin1String(NM_WG_KEY_PRESHARED_KEY))) - d->ui.presharedKeyLineEdit->setText(dataMap[NM_WG_KEY_PRESHARED_KEY]); - else - d->ui.presharedKeyLineEdit->setText(QString()); - - if (dataMap.contains(QLatin1String(NM_WG_KEY_PRE_UP))) - d->ui.preUpLineEdit->setText(dataMap[NM_WG_KEY_PRE_UP]); - else - d->ui.preUpLineEdit->setText(QString()); - - if (dataMap.contains(QLatin1String(NM_WG_KEY_POST_UP))) - d->ui.postUpLineEdit->setText(dataMap[NM_WG_KEY_POST_UP]); - else - d->ui.postUpLineEdit->setText(QString()); - - if (dataMap.contains(QLatin1String(NM_WG_KEY_PRE_DOWN))) - d->ui.preDownLineEdit->setText(dataMap[NM_WG_KEY_PRE_DOWN]); - else - d->ui.preDownLineEdit->setText(QString()); - - if (dataMap.contains(QLatin1String(NM_WG_KEY_POST_DOWN))) - d->ui.postDownLineEdit->setText(dataMap[NM_WG_KEY_POST_DOWN]); - else - d->ui.postDownLineEdit->setText(QString()); -} - -void WireGuardAdvancedWidget::setProperty(NMStringMap &data, const QLatin1String &key, - const QString &value) const -{ - if (!value.isEmpty()) - data.insert(key, value); -} - -NetworkManager::VpnSetting::Ptr WireGuardAdvancedWidget::setting() const -{ - NMStringMap data; - QString stringVal; - - setProperty(data, QLatin1String(NM_WG_KEY_LISTEN_PORT), d->ui.listenPortLineEdit->displayText()); - setProperty(data, QLatin1String(NM_WG_KEY_PERSISTENT_KEEPALIVE), d->ui.persistentKeepaliveLineEdit->displayText()); - setProperty(data, QLatin1String(NM_WG_KEY_MTU), d->ui.mtuLineEdit->displayText()); - setProperty(data, QLatin1String(NM_WG_KEY_TABLE), d->ui.tableLineEdit->displayText()); - setProperty(data, QLatin1String(NM_WG_KEY_FWMARK), d->ui.fwMarkLineEdit->displayText()); - setProperty(data, QLatin1String(NM_WG_KEY_PRESHARED_KEY), d->ui.presharedKeyLineEdit->text()); - setProperty(data, QLatin1String(NM_WG_KEY_PRE_UP), d->ui.preUpLineEdit->text()); - setProperty(data, QLatin1String(NM_WG_KEY_POST_UP), d->ui.postUpLineEdit->text()); - setProperty(data, QLatin1String(NM_WG_KEY_PRE_DOWN), d->ui.preDownLineEdit->text()); - setProperty(data, QLatin1String(NM_WG_KEY_POST_DOWN), d->ui.postDownLineEdit->text()); - - d->setting->setData(data); - - return d->setting; -} - -void WireGuardAdvancedWidget::checkPresharedKey() -{ - int pos = 0; - PasswordField *widget = d->ui.presharedKeyLineEdit; - QString value = widget->text(); - d->presharedKeyValid = QValidator::Acceptable == d->keyValidator->validate(value, pos) - || value.isEmpty(); - setBackground(widget, d->presharedKeyValid); - slotWidgetChanged(); -} - -void WireGuardAdvancedWidget::checkTable() -{ - int pos = 0; - QLineEdit *widget = d->ui.tableLineEdit; - QString value = widget->displayText(); - d->tableValid = QValidator::Acceptable == widget->validator()->validate(value, pos) - || value.isEmpty(); - setBackground(widget, d->tableValid); - slotWidgetChanged(); -} - -void WireGuardAdvancedWidget::checkFwMark() -{ - int pos = 0; - QLineEdit *widget = d->ui.fwMarkLineEdit; - QString value = widget->displayText(); - d->fwMarkValid = QValidator::Acceptable == widget->validator()->validate(value, pos) - || value.isEmpty(); - setBackground(widget, d->fwMarkValid); - slotWidgetChanged(); -} - -void WireGuardAdvancedWidget::setBackground(QWidget *w, bool result) const -{ - if (result) - w->setPalette(d->normalPalette); - else - w->setPalette(d->warningPalette); -} - -void WireGuardAdvancedWidget::slotWidgetChanged() -{ - if (d->tableValid && d->fwMarkValid && d->presharedKeyValid) - d->ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); - else - d->ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); -} diff --git a/vpn/wireguard/wireguardauth.h b/vpn/wireguard/wireguardauth.h deleted file mode 100644 --- a/vpn/wireguard/wireguardauth.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - 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 = nullptr); - ~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 deleted file mode 100644 --- a/vpn/wireguard/wireguardauth.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - 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 deleted file mode 100644 --- a/vpn/wireguard/wireguardauth.ui +++ /dev/null @@ -1,31 +0,0 @@ - - - WireGuardAuth - - - - 0 - 0 - 263 - 51 - - - - - 6 - - - - - No WireGuard Secrets currently - - - false - - - - - - - - diff --git a/vpn/wireguard/wireguardwidget.h b/vpn/wireguard/wireguardwidget.h deleted file mode 100644 --- a/vpn/wireguard/wireguardwidget.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - 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 = nullptr); - ~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: - void setProperty(NMStringMap &data, const QLatin1String &key, const QString &value) const; - void setBackground(QWidget *w, bool result) const; - void checkAddressValid(); - void checkPrivateKeyValid(); - void checkPublicKeyValid(); - void checkAllowedIpsValid(); - void checkEndpointValid(); - - class Private; - Private *d; -}; - -#endif // WIREGUARDWIDGET_H diff --git a/vpn/wireguard/wireguardwidget.cpp b/vpn/wireguard/wireguardwidget.cpp deleted file mode 100644 --- a/vpn/wireguard/wireguardwidget.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/* - 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 "nm-wireguard-service.h" - -class WireGuardSettingWidget::Private -{ -public: - Private(); - - Ui_WireGuardProp ui; - NetworkManager::VpnSetting::Ptr setting; - KSharedConfigPtr config; - QPalette warningPalette; - QPalette normalPalette; - WireGuardKeyValidator *keyValidator; - bool addressValid; - bool privateKeyValid; - bool publicKeyValid; - bool allowedIpsValid; - bool endpointValid; -}; - -WireGuardSettingWidget::Private::Private(void) - : addressValid(false) - , privateKeyValid(false) - , publicKeyValid(false) - , allowedIpsValid(false) - , endpointValid(true) // optional so blank is valid -{ -} - -WireGuardSettingWidget::WireGuardSettingWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent) - : SettingWidget(setting, parent) - , d(new Private) -{ - qDBusRegisterMetaType(); - - d->ui.setupUi(this); - d->setting = setting; - - d->config = KSharedConfig::openConfig(); - d->warningPalette = KColorScheme::createApplicationPalette(d->config); - d->normalPalette = KColorScheme::createApplicationPalette(d->config); - KColorScheme::adjustBackground(d->warningPalette, KColorScheme::NegativeBackground, QPalette::Base, - KColorScheme::ColorSet::View, d->config); - - KColorScheme::adjustBackground(d->normalPalette, KColorScheme::NormalBackground, QPalette::Base, - KColorScheme::ColorSet::View, d->config); - - - connect(d->ui.addressIPv4LineEdit, &QLineEdit::textChanged, this, &WireGuardSettingWidget::checkAddressValid); - connect(d->ui.addressIPv6LineEdit, &QLineEdit::textChanged, this, &WireGuardSettingWidget::checkAddressValid); - connect(d->ui.privateKeyLineEdit, &PasswordField::textChanged, this, &WireGuardSettingWidget::checkPrivateKeyValid); - connect(d->ui.publicKeyLineEdit, &QLineEdit::textChanged, this, &WireGuardSettingWidget::checkPublicKeyValid); - connect(d->ui.allowedIPsLineEdit, &QLineEdit::textChanged, this, &WireGuardSettingWidget::checkAllowedIpsValid); - connect(d->ui.endpointAddressLineEdit, &QLineEdit::textChanged, this, &WireGuardSettingWidget::checkEndpointValid); - connect(d->ui.endpointPortLineEdit, &QLineEdit::textChanged, this, &WireGuardSettingWidget::checkEndpointValid); - - 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); - - // This is done as a private variable rather than a local variable so it can be - // used both here and to validate the private key later - d->keyValidator = new WireGuardKeyValidator(this); - d->ui.publicKeyLineEdit->setValidator(d->keyValidator); - - // Create validator for AllowedIPs - SimpleIpListValidator *allowedIPsValidator = new SimpleIpListValidator(this, SimpleIpListValidator::WithCidr, - SimpleIpListValidator::Both); - d->ui.allowedIPsLineEdit->setValidator(allowedIPsValidator); - - // Create validator for endpoint port - QIntValidator *portValidator = new QIntValidator(this); - portValidator->setBottom(0); - portValidator->setTop(65535); - d->ui.endpointPortLineEdit->setValidator(portValidator); - - // Connect for setting check - watchChangedSetting(); - - KAcceleratorManager::manage(this); - - if (setting && !setting->isNull()) { - loadConfig(d->setting); - } - - // Set the initial backgrounds on all the widgets - checkAddressValid(); - checkPrivateKeyValid(); - checkPublicKeyValid(); - checkAllowedIpsValid(); - checkEndpointValid(); - -} - -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.publicKeyLineEdit->setText(dataMap[NM_WG_KEY_PUBLIC_KEY]); - d->ui.allowedIPsLineEdit->setText(dataMap[NM_WG_KEY_ALLOWED_IPS]); - - // An endpoint is stored as : - QString storedEndpoint = dataMap[NM_WG_KEY_ENDPOINT]; - QStringList endpointList = storedEndpoint.contains("]:") ? - dataMap[NM_WG_KEY_ENDPOINT].split("]:") : - dataMap[NM_WG_KEY_ENDPOINT].split(":"); - - d->ui.endpointAddressLineEdit->setText(endpointList[0].remove("[")); - d->ui.endpointPortLineEdit->setText(endpointList[1]); -} - -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 - setProperty(data, QLatin1String(NM_WG_KEY_ADDR_IP4), d->ui.addressIPv4LineEdit->displayText()); - setProperty(data, QLatin1String(NM_WG_KEY_ADDR_IP6), d->ui.addressIPv6LineEdit->displayText()); - setProperty(data, QLatin1String(NM_WG_KEY_PRIVATE_KEY), d->ui.privateKeyLineEdit->text()); - setProperty(data, QLatin1String(NM_WG_KEY_PUBLIC_KEY), d->ui.publicKeyLineEdit->displayText()); - setProperty(data, QLatin1String(NM_WG_KEY_ALLOWED_IPS), d->ui.allowedIPsLineEdit->displayText()); - - // Endpoint isn't required and is created from
: - QString addressString = d->ui.endpointAddressLineEdit->displayText(); - if (!addressString.isEmpty()) { - // If there is a ':' in the address string then it is an IPv6 address and - // the output needs to be formatted as '[1:2:3:4:5:6:7:8]:123' otherwhise - // it is formatted as '1.2.3.4:123' or 'ab.com:123' - if (addressString.contains(":")) - setProperty(data, QLatin1String(NM_WG_KEY_ENDPOINT), - "[" + - d->ui.endpointAddressLineEdit->displayText().trimmed() + - "]:" + - d->ui.endpointPortLineEdit->displayText().trimmed()); - else - setProperty(data, QLatin1String(NM_WG_KEY_ENDPOINT), - d->ui.endpointAddressLineEdit->displayText().trimmed() + - ":" + - d->ui.endpointPortLineEdit->displayText().trimmed()); - } - - setting.setData(data); - - return setting.toMap(); -} - -void WireGuardSettingWidget::setProperty(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->addressValid - && d->privateKeyValid - && d->publicKeyValid - && d->allowedIpsValid - && d->endpointValid; -} - -void WireGuardSettingWidget::checkAddressValid() -{ - int pos = 0; - QLineEdit *widget = d->ui.addressIPv4LineEdit; - QString value(widget->displayText()); - bool ip4valid = (widget->validator()->validate(value, pos) == QValidator::Acceptable); - bool ip4present = !widget->displayText().isEmpty(); - - widget = d->ui.addressIPv6LineEdit; - value = widget->displayText(); - bool ip6valid = QValidator::Acceptable == widget->validator()->validate(value, pos); - bool ip6present = !widget->displayText().isEmpty(); - - d->addressValid = (ip4valid && ip6valid) || (ip4valid && !ip6present) || (!ip4present && ip6valid); - - setBackground(d->ui.addressIPv4LineEdit, d->addressValid); - setBackground(d->ui.addressIPv6LineEdit, d->addressValid); - - slotWidgetChanged(); -} - -void WireGuardSettingWidget::checkPrivateKeyValid() -{ - int pos = 0; - PasswordField *widget = d->ui.privateKeyLineEdit; - QString value = widget->text(); - d->privateKeyValid = QValidator::Acceptable == d->keyValidator->validate(value, pos); - setBackground(widget, d->privateKeyValid); - slotWidgetChanged(); -} - -void WireGuardSettingWidget::checkPublicKeyValid() -{ - int pos = 0; - QLineEdit *widget = d->ui.publicKeyLineEdit; - QString value = widget->displayText(); - d->publicKeyValid = QValidator::Acceptable == widget->validator()->validate(value, pos); - setBackground(widget, d->publicKeyValid); - slotWidgetChanged(); -} - -void WireGuardSettingWidget::checkAllowedIpsValid() -{ - int pos = 0; - QLineEdit *widget = d->ui.allowedIPsLineEdit; - QString value = widget->displayText(); - d->allowedIpsValid = QValidator::Acceptable == widget->validator()->validate(value, pos); - setBackground(widget, d->allowedIpsValid); - slotWidgetChanged(); -} - -void WireGuardSettingWidget::checkEndpointValid() -{ - int pos = 0; - QLineEdit *addressWidget = d->ui.endpointAddressLineEdit; - QLineEdit *portWidget = d->ui.endpointPortLineEdit; - QString addressValue = addressWidget->displayText(); - QString portString = portWidget->displayText(); - - QUrl temp; - static QRegExpValidator fqdnValidator(QRegExp(QLatin1String("(?=.{5,254}$)([a-zA-Z0-9][a-zA-Z0-9-]{1,62}\\.){1,63}[a-zA-Z]{2,63}")), 0); - static SimpleIpV4AddressValidator ipv4Validator(0); - static SimpleIpV6AddressValidator ipv6Validator(0); - - bool addressValid = QValidator::Acceptable == fqdnValidator.validate(addressValue, pos) - || QValidator::Acceptable == ipv4Validator.validate(addressValue, pos) - || QValidator::Acceptable == ipv6Validator.validate(addressValue, pos); - bool bothEmpty = addressValue.isEmpty() && portString.isEmpty(); - // Because of the validator, if the port is non-empty, it is valid - bool portValid = !portString.isEmpty(); - d->endpointValid = bothEmpty || (addressValid && portValid); - setBackground(addressWidget, bothEmpty || addressValid); - setBackground(portWidget, bothEmpty || portValid); - - slotWidgetChanged(); -} - -void WireGuardSettingWidget::setBackground(QWidget *w, bool result) const -{ - if (result) - w->setPalette(d->normalPalette); - else - w->setPalette(d->warningPalette); -}