diff --git a/libs/editor/settings/wireguardinterfacewidget.cpp b/libs/editor/settings/wireguardinterfacewidget.cpp index 13ed2f4f..dc148ee0 100644 --- a/libs/editor/settings/wireguardinterfacewidget.cpp +++ b/libs/editor/settings/wireguardinterfacewidget.cpp @@ -1,639 +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 = new QIntValidator; 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 = new QIntValidator(); 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); + WireGuardKeyValidator keyValidator; 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); + SimpleIpListValidator validator(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/libs/editor/settings/wireguardpeerwidget.cpp b/libs/editor/settings/wireguardpeerwidget.cpp index c1177498..ee45bfcd 100644 --- a/libs/editor/settings/wireguardpeerwidget.cpp +++ b/libs/editor/settings/wireguardpeerwidget.cpp @@ -1,375 +1,374 @@ /* 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); +static WireGuardKeyValidator keyValidator; +static SimpleIpListValidator allowedIPsValidator(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); + static SimpleIpV4AddressValidator ipv4Validator; + static SimpleIpV6AddressValidator ipv6Validator; 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/libs/editor/settings/wireguardtabwidget.cpp b/libs/editor/settings/wireguardtabwidget.cpp index b6a550cd..1e5d7a71 100644 --- a/libs/editor/settings/wireguardtabwidget.cpp +++ b/libs/editor/settings/wireguardtabwidget.cpp @@ -1,178 +1,177 @@ /* 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); +static WireGuardKeyValidator keyValidator(); +static SimpleIpListValidator allowedIPsValidator(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/libs/editor/simpleiplistvalidator.cpp b/libs/editor/simpleiplistvalidator.cpp index 6663aaa1..f818e79d 100644 --- a/libs/editor/simpleiplistvalidator.cpp +++ b/libs/editor/simpleiplistvalidator.cpp @@ -1,108 +1,106 @@ /* Copyright 2018 Bruce Anderson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "simpleiplistvalidator.h" #include #include -SimpleIpListValidator::SimpleIpListValidator(QObject *parent, - AddressStyle style, - AddressType type) +SimpleIpListValidator::SimpleIpListValidator(AddressStyle style, AddressType type, QObject *parent) : QValidator(parent) , m_ipv6Validator(nullptr) , m_ipv4Validator(nullptr) { if (type == Ipv4 || type == Both) { SimpleIpV4AddressValidator::AddressStyle ipv4Style; if (style == Base) ipv4Style = SimpleIpV4AddressValidator::AddressStyle::Base; else if (style == WithCidr) ipv4Style = SimpleIpV4AddressValidator::AddressStyle::WithCidr; else ipv4Style = SimpleIpV4AddressValidator::AddressStyle::WithPort; - m_ipv4Validator = new SimpleIpV4AddressValidator(this, ipv4Style); + m_ipv4Validator = new SimpleIpV4AddressValidator(ipv4Style, this); } if (type == Ipv6 || type == Both) { SimpleIpV6AddressValidator::AddressStyle ipv6Style; if (style == Base) ipv6Style = SimpleIpV6AddressValidator::AddressStyle::Base; else if (style == WithCidr) ipv6Style = SimpleIpV6AddressValidator::AddressStyle::WithCidr; else ipv6Style = SimpleIpV6AddressValidator::AddressStyle::WithPort; - m_ipv6Validator = new SimpleIpV6AddressValidator(this, ipv6Style); + m_ipv6Validator = new SimpleIpV6AddressValidator(ipv6Style, this); } } SimpleIpListValidator::~SimpleIpListValidator() { } QValidator::State SimpleIpListValidator::validate(QString &address, int &pos) const { Q_UNUSED(pos) // Split the incoming address on commas possibly with spaces on either side QStringList addressList = address.split(","); // Use a local variable for position in the validators so it doesn't screw // up the position of the cursor when we return int localPos = 0; QValidator::State result = QValidator::Acceptable; for (QString &rawAddr : addressList) { QValidator::State ipv4Result = QValidator::Acceptable; QValidator::State ipv6Result = QValidator::Acceptable; QString addr = rawAddr.trimmed(); // If we are starting a new address and all the previous addresses // are not Acceptable then the previous addresses need to be completed // before a new one is started if (result != QValidator::Acceptable) return QValidator::Invalid; // See if it is an IPv4 address. If we are not testing for IPv4 // then by definition IPv4 is Invalid if (m_ipv4Validator != nullptr) ipv4Result = m_ipv4Validator->validate(addr, localPos); else ipv4Result = QValidator::Invalid; // See if it is an IPv6 address. If we are not testing for IPv6 // then by definition IPv6 is Invalid if (m_ipv6Validator != nullptr) ipv6Result = m_ipv6Validator->validate(addr, localPos); else ipv6Result = QValidator::Invalid; // If this address is not at least an Intermediate then get out because the list is Invalid if (ipv6Result == QValidator::Invalid && ipv4Result == QValidator::Invalid) return QValidator::Invalid; // If either validator judged this address to be Intermediate then that's the best the // final result can be for the whole list. No need to test for Acceptable because // that's the default set on entry and we only downgrade it from there. if (ipv4Result == QValidator::Intermediate || ipv6Result == QValidator::Intermediate) result = QValidator::Intermediate; } return result; } diff --git a/libs/editor/simpleiplistvalidator.h b/libs/editor/simpleiplistvalidator.h index fa027c52..bc249fa0 100644 --- a/libs/editor/simpleiplistvalidator.h +++ b/libs/editor/simpleiplistvalidator.h @@ -1,46 +1,45 @@ /* 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 SIMPLEIPLISTVALIDATOR_H #define SIMPLEIPLISTVALIDATOR_H #include #include "simpleipv4addressvalidator.h" #include "simpleipv6addressvalidator.h" class Q_DECL_EXPORT SimpleIpListValidator : public QValidator { public: enum AddressType {Ipv4, Ipv6, Both}; enum AddressStyle {Base, WithCidr, WithPort}; - explicit SimpleIpListValidator(QObject *parent, - AddressStyle style = AddressStyle::Base, - AddressType allow = AddressType::Both); + explicit SimpleIpListValidator(AddressStyle style = AddressStyle::Base, + AddressType allow = AddressType::Both, QObject *parent = nullptr); ~SimpleIpListValidator() override; State validate(QString &, int &) const override; private: SimpleIpV6AddressValidator *m_ipv6Validator; SimpleIpV4AddressValidator *m_ipv4Validator; }; #endif // SIMPLEIPV4ADDRESSVALIDATOR_H diff --git a/libs/editor/simpleipv4addressvalidator.cpp b/libs/editor/simpleipv4addressvalidator.cpp index 235b7ec5..0fa2617a 100644 --- a/libs/editor/simpleipv4addressvalidator.cpp +++ b/libs/editor/simpleipv4addressvalidator.cpp @@ -1,169 +1,169 @@ /* Copyright 2009 Paul Marchouk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "simpleipv4addressvalidator.h" #include #include -SimpleIpV4AddressValidator::SimpleIpV4AddressValidator(QObject *parent, AddressStyle style) +SimpleIpV4AddressValidator::SimpleIpV4AddressValidator(AddressStyle style, QObject *parent) : QValidator(parent) , m_addressStyle(style) { switch (style) { case Base: m_validator.setRegularExpression(QRegularExpression(QLatin1String("[0-9, ]{1,3}\\.[0-9, ]{1,3}\\.[0-9, ]{1,3}\\.[0-9, ]{1,3}"))); break; case WithCidr: m_validator.setRegularExpression(QRegularExpression(QLatin1String("([0-9]{1,3}\\.){3,3}[0-9]{1,3}/[0-9]{1,2}"))); break; case WithPort: m_validator.setRegularExpression(QRegularExpression(QLatin1String("([0-9]{1,3}\\.){3,3}[0-9]{1,3}:[0-9]{1,5}"))); break; } } SimpleIpV4AddressValidator::~SimpleIpV4AddressValidator() { } QValidator::State SimpleIpV4AddressValidator::validate(QString &address, int &pos) const { QValidator::State maskResult = checkWithInputMask(address, pos); if (QValidator::Invalid == maskResult) { return QValidator::Invalid; } // this list will be filled with tetrad values. It can be used to make // some additional correctness checks on the last validation step. QList tetrads; QValidator::State tetradResult = checkTetradsRanges(address, tetrads); if (QValidator::Invalid == tetradResult) return QValidator::Invalid; else if (QValidator::Intermediate == tetradResult || QValidator::Intermediate == maskResult) return QValidator::Intermediate; else return QValidator::Acceptable; } QValidator::State SimpleIpV4AddressValidator::checkWithInputMask(QString &value, int &pos) const { return m_validator.validate(value, pos); } QValidator::State SimpleIpV4AddressValidator::checkTetradsRanges(QString &value, QList &tetrads) const { QStringList temp; QVector addrParts; QStringList cidrParts; QStringList portParts; switch (m_addressStyle) { case Base: addrParts = value.splitRef(QLatin1Char('.')); break; case WithCidr: cidrParts = value.split(QLatin1Char('/')); addrParts = cidrParts[0].splitRef(QLatin1Char('.')); break; case WithPort: portParts = value.split(QLatin1Char(':')); addrParts = portParts[0].splitRef(QLatin1Char('.')); break; } int i = 0; // fill in the list with invalid values tetrads << -1 << -1 << -1 << -1; // lets check address parts for (const QStringRef &part : addrParts) { if (part.isEmpty()) { if (i != (addrParts.size() - 1)) { // qCDebug(PLASMA_NM) << "part.isEmpty()"; return QValidator::Invalid; } // the last tetrad can be empty, continue... return QValidator::Intermediate; } tetrads[i] = part.toInt(); if (tetrads[i] > 255) { // qCDebug(PLASMA_NM) << "tetrads[i] > 255"; return QValidator::Invalid; } // correct tetrad value: for example, 001 -> 1 temp.append(QString::number(tetrads[i])); i++; } // replace input string with the corrected version value = temp.join(QLatin1String(".")); if (i < 4) { // not all tetrads are filled... continue // qCDebug(PLASMA_NM) << "QValidator::Intermediate"; return QValidator::Intermediate; } else { if (m_addressStyle == WithCidr) { if (cidrParts.size() > 1) { value += QLatin1String("/"); if (!cidrParts[1].isEmpty()) { int cidrValue = cidrParts[1].toInt(); if (cidrValue > 32) { return QValidator::Invalid; } else { value += cidrParts[1]; return QValidator::Acceptable; } } else { return QValidator::Intermediate; } } } else if (m_addressStyle == WithPort) { if (portParts.size() > 1) { value += QLatin1String(":"); if (!portParts[1].isEmpty()) { int portValue = portParts[1].toInt(); if (portValue > 65535) { return QValidator::Invalid; } else { value += portParts[1]; return QValidator::Acceptable; } } else { return QValidator::Intermediate; } } } // qCDebug(PLASMA_NM) << "QValidator::Acceptable"; return QValidator::Acceptable; } } diff --git a/libs/editor/simpleipv4addressvalidator.h b/libs/editor/simpleipv4addressvalidator.h index 3645995a..86ffe59b 100644 --- a/libs/editor/simpleipv4addressvalidator.h +++ b/libs/editor/simpleipv4addressvalidator.h @@ -1,48 +1,48 @@ /* Copyright 2009 Paul Marchouk 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 SIMPLEIPV4ADDRESSVALIDATOR_H #define SIMPLEIPV4ADDRESSVALIDATOR_H #include class Q_DECL_EXPORT SimpleIpV4AddressValidator : public QValidator { public: enum AddressStyle {Base, WithCidr, WithPort}; - explicit SimpleIpV4AddressValidator(QObject *parent, AddressStyle style = AddressStyle::Base); + explicit SimpleIpV4AddressValidator(AddressStyle style = AddressStyle::Base, QObject *parent = nullptr); ~SimpleIpV4AddressValidator() override; State validate(QString &, int &) const override; /** Check input value with a regular expression describing simple input mask. */ QValidator::State checkWithInputMask(QString &, int &) const; /** Function split intput string into tetrads and check them for valid values. * In the tetrads are placed into QList. Input string may be changed. */ QValidator::State checkTetradsRanges(QString &, QList&) const; private: AddressStyle m_addressStyle; QRegularExpressionValidator m_validator; }; #endif // SIMPLEIPV4ADDRESSVALIDATOR_H diff --git a/libs/editor/simpleipv6addressvalidator.cpp b/libs/editor/simpleipv6addressvalidator.cpp index 93cf464c..b6f2a78b 100644 --- a/libs/editor/simpleipv6addressvalidator.cpp +++ b/libs/editor/simpleipv6addressvalidator.cpp @@ -1,187 +1,187 @@ /* Copyright 2011 Ilia Kats , based on work by Paul Marchouk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "simpleipv6addressvalidator.h" #include #include -SimpleIpV6AddressValidator::SimpleIpV6AddressValidator(QObject *parent, AddressStyle style) +SimpleIpV6AddressValidator::SimpleIpV6AddressValidator(AddressStyle style, QObject *parent) : QValidator(parent) , m_addressStyle(style) { switch (style) { case Base: m_validator.setRegularExpression(QRegularExpression(QLatin1String("([0-9a-fA-F]{1,4}|:)+"))); break; case WithCidr: m_validator.setRegularExpression(QRegularExpression(QLatin1String("([0-9a-fA-F]{1,4}|:){2,15}/[0-9]{1,3}"))); break; case WithPort: m_validator.setRegularExpression(QRegularExpression(QLatin1String("\\[([0-9a-fA-F]{1,4}|:)+\\]:[0-9]{1,5}"))); } } SimpleIpV6AddressValidator::~SimpleIpV6AddressValidator() { } QValidator::State SimpleIpV6AddressValidator::validate(QString &address, int &pos) const { if (QValidator::Invalid == checkWithInputMask(address, pos)) { return QValidator::Invalid; } return checkTetradsRanges(address); } QValidator::State SimpleIpV6AddressValidator::checkWithInputMask(QString &value, int &pos) const { return m_validator.validate(value, pos); } QValidator::State SimpleIpV6AddressValidator::checkTetradsRanges(QString &value) const { QStringList addrParts; QStringList cidrParts; QStringList portParts; bool foundBracket = false; QValidator::State result = QValidator::Acceptable; switch (m_addressStyle) { case Base: addrParts = value.split(QLatin1Char(':')); break; case WithCidr: cidrParts = value.split(QLatin1Char('/')); addrParts = cidrParts[0].split(QLatin1Char(':')); break; case WithPort: if (value.isEmpty()) return QValidator::Intermediate; if (value[0] != '[') { return QValidator::Invalid; } else { // Input: "[1:2:3:4:5:6:7:8]:123" // bracketParts: "[1:2:3:4:5:6:7:8" , ":123" // addrParts: "" , "1:2:3:4:5:6:7:8" // portParts: "", "123" QStringList bracketParts = value.split(QLatin1Char(']')); if (bracketParts.size() < 2) portParts = QStringList(); else { foundBracket = true; if (!bracketParts[1].isEmpty() && bracketParts[1][0] != ':') return QValidator::Invalid; else portParts = bracketParts[1].split(QLatin1Char(':')); } addrParts = bracketParts[0].split(QLatin1Char('['))[1].split(QLatin1Char(':')); } } int number = addrParts.size(); // There is no case where can be more than 8 colons (9 parts) // and only one unusual case where there are 8 colons (1:2:3:4:5:6:7::) if (number > 9) return QValidator::Invalid; else if (number == 9 && (!addrParts[7].isEmpty() || !addrParts[8].isEmpty())) return QValidator::Invalid; // lets check address parts bool emptypresent = false; int i = 1; for (QString part : addrParts) { if (part.isEmpty() && i < number) { // There is only one case where you can have 3 empty parts // and that is when you have the string: "::" which is valid // and useful and of course it can also be extended to ::123 for // instance. Anywhere other than the beginning though, having 3 empty // parts indicates either a run of 3 colons ("1:::6")" or two sets of // 2 colons ("1:2::3:4::") which are always invalid if (emptypresent && i != 2) { // qCDebug(PLASMA_NM) << "part.isEmpty()"; return QValidator::Invalid; } else { // If this is an empty part then set it to zero to not fail // the next test part.setNum(0,16); emptypresent = true; } } i++; bool ok; if (part.toInt(&ok, 16) > 65535) { return QValidator::Invalid; } } // A special case: a single colon needs to be Intermediate not Acceptable if (number == 2 && addrParts[0].isEmpty() && addrParts[1].isEmpty()) result = QValidator::Intermediate; // Another special case: a single colon followed by something (i.e. ":123" // is invalid else if (number > 1 && addrParts[0].isEmpty() && !addrParts[1].isEmpty()) result = QValidator::Invalid; // If we don't have 8 parts yet and none of them are empty we aren't done yet else if (number < 8 && !emptypresent) result = QValidator::Intermediate; // If we have 8 parts but the last one is empty we aren't done yet else if (number == 8 && addrParts[7].isEmpty()) result = QValidator::Intermediate; if (m_addressStyle == WithCidr) { int cidrSize = cidrParts.size(); // If we have a '/' and the basic address portion is not // yet complete (i.e. Intermediate) then the whole thing is Invalid if (cidrSize == 2 && result == QValidator::Intermediate) return QValidator::Invalid; if (cidrSize == 1 || (cidrSize == 2 && cidrParts[1].isEmpty())) return QValidator::Intermediate; int cidrValue = cidrParts[1].toInt(); if (cidrValue > 128) return QValidator::Invalid; } else if (m_addressStyle == WithPort) { int portSize = portParts.size(); // If we have a ']' and the basic address portion is not // yet complete (i.e. Intermediate) then the whole thing is Invalid if (foundBracket && result == QValidator::Intermediate) return QValidator::Invalid; if (portSize < 2 || (portSize == 2 && portParts[1].isEmpty())) { return QValidator::Intermediate; } else { int portValue = portParts[1].toInt(); if (portValue > 65535) return QValidator::Invalid; } } return result; } diff --git a/libs/editor/simpleipv6addressvalidator.h b/libs/editor/simpleipv6addressvalidator.h index 0767e46f..cfc74cef 100644 --- a/libs/editor/simpleipv6addressvalidator.h +++ b/libs/editor/simpleipv6addressvalidator.h @@ -1,48 +1,48 @@ /* Copyright 2011 Ilia Kats , based on work by Paul Marchouk 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 SIMPLEIPV6ADDRESSVALIDATOR_H #define SIMPLEIPV6ADDRESSVALIDATOR_H #include class Q_DECL_EXPORT SimpleIpV6AddressValidator : public QValidator { public: enum AddressStyle {Base, WithCidr, WithPort}; - explicit SimpleIpV6AddressValidator(QObject *parent, AddressStyle style = AddressStyle::Base); + explicit SimpleIpV6AddressValidator(AddressStyle style = AddressStyle::Base, QObject *parent = nullptr); ~SimpleIpV6AddressValidator() override; State validate(QString &, int &) const override; /** Check input value with a regular expression describing simple input mask. */ QValidator::State checkWithInputMask(QString &, int &) const; /** Function split intput string into tetrads and check them for valid values. * In the tetrads are placed into QList. Input string may be changed. */ QValidator::State checkTetradsRanges(QString &) const; private: AddressStyle m_addressStyle; QRegularExpressionValidator m_validator; }; #endif // SIMPLEIPV6ADDRESSVALIDATOR_H diff --git a/libs/editor/widgets/ipv4delegate.cpp b/libs/editor/widgets/ipv4delegate.cpp index 8cde3c6d..8b47e8a8 100644 --- a/libs/editor/widgets/ipv4delegate.cpp +++ b/libs/editor/widgets/ipv4delegate.cpp @@ -1,36 +1,36 @@ /* Copyright 2011 Ilia Kats 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 "ipv4delegate.h" #include #include "simpleipv4addressvalidator.h" IpV4Delegate::IpV4Delegate(QObject * parent) : Delegate(parent) {} IpV4Delegate::~IpV4Delegate() {} QWidget * IpV4Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { QLineEdit *editor = new QLineEdit(parent); - editor->setValidator(new SimpleIpV4AddressValidator(editor)); + editor->setValidator(new SimpleIpV4AddressValidator(SimpleIpV4AddressValidator::Base, editor)); return editor; } diff --git a/libs/editor/widgets/ipv6delegate.cpp b/libs/editor/widgets/ipv6delegate.cpp index 9e3d286b..89064eed 100644 --- a/libs/editor/widgets/ipv6delegate.cpp +++ b/libs/editor/widgets/ipv6delegate.cpp @@ -1,36 +1,36 @@ /* Copyright 2011 Ilia Kats 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 "ipv6delegate.h" #include #include "simpleipv6addressvalidator.h" IpV6Delegate::IpV6Delegate(QObject * parent) : Delegate(parent) {} IpV6Delegate::~IpV6Delegate() {} QWidget * IpV6Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { QLineEdit *editor = new QLineEdit(parent); - editor->setValidator(new SimpleIpV6AddressValidator(editor)); + editor->setValidator(new SimpleIpV6AddressValidator(SimpleIpV6AddressValidator::Base, editor)); return editor; } diff --git a/libs/editor/wireguardkeyvalidator.h b/libs/editor/wireguardkeyvalidator.h index b099dd11..b3786468 100644 --- a/libs/editor/wireguardkeyvalidator.h +++ b/libs/editor/wireguardkeyvalidator.h @@ -1,38 +1,38 @@ /* 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 WIREGUARDKEYVALIDATOR_H #define WIREGUARDKEYVALIDATOR_H #include class WireGuardKeyValidator : public QValidator { public: - explicit WireGuardKeyValidator(QObject *parent); + explicit WireGuardKeyValidator(QObject *parent = nullptr); ~WireGuardKeyValidator() override; QValidator::State validate(QString &, int &) const override; private: QRegularExpressionValidator *m_validator; }; #endif // SIMPLEIPV4ADDRESSVALIDATOR_H diff --git a/vpn/ssh/sshwidget.cpp b/vpn/ssh/sshwidget.cpp index 027a058a..9399a038 100644 --- a/vpn/ssh/sshwidget.cpp +++ b/vpn/ssh/sshwidget.cpp @@ -1,394 +1,394 @@ /* Copyright 2015 Jan Grulich 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 "sshwidget.h" #include "ui_sshwidget.h" #include "ui_sshadvanced.h" #include "simpleipv4addressvalidator.h" #include "simpleipv6addressvalidator.h" #include #include #include #include "nm-ssh-service.h" class SshSettingWidgetPrivate { public: Ui_SshWidget ui; Ui_SshAdvanced advUi; NetworkManager::VpnSetting::Ptr setting; QDialog *advancedDlg; QWidget *advancedWid; }; SshSettingWidget::SshSettingWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent) : SettingWidget(setting, parent) , d_ptr(new SshSettingWidgetPrivate) { Q_D(SshSettingWidget); d->ui.setupUi(this); d->setting = setting; d->ui.le_password->setPasswordOptionsEnabled(true); connect(d->ui.cmb_authType, QOverload::of(&QComboBox::currentIndexChanged), this, &SshSettingWidget::authTypeChanged); connect(d->ui.btn_advancedOption, &QPushButton::clicked, this, &SshSettingWidget::doAdvancedDialog); d->advancedDlg = new QDialog(this); d->advancedDlg->setModal(true); d->advancedWid = new QWidget(this); d->advUi.setupUi(d->advancedWid); QVBoxLayout *layout = new QVBoxLayout(d->advancedDlg); layout->addWidget(d->advancedWid); d->advancedDlg->setLayout(layout); QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, d->advancedDlg); connect(buttons, &QDialogButtonBox::accepted, d->advancedDlg, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, d->advancedDlg, &QDialog::reject); layout->addWidget(buttons); // Connect for setting check watchChangedSetting(); // Connect for validity check connect(d->ui.le_gateway, &QLineEdit::textChanged, this, &SshSettingWidget::slotWidgetChanged); connect(d->ui.le_localIp, &QLineEdit::textChanged, this, &SshSettingWidget::slotWidgetChanged); connect(d->ui.le_netmask, &QLineEdit::textChanged, this, &SshSettingWidget::slotWidgetChanged); connect(d->ui.le_remoteIp, &QLineEdit::textChanged, this, &SshSettingWidget::slotWidgetChanged); - SimpleIpV4AddressValidator *ipv4Validator = new SimpleIpV4AddressValidator(this); + SimpleIpV4AddressValidator *ipv4Validator = new SimpleIpV4AddressValidator(SimpleIpV4AddressValidator::Base, this); d->ui.le_localIp->setValidator(ipv4Validator); d->ui.le_remoteIp->setValidator(ipv4Validator); d->ui.le_netmask->setValidator(ipv4Validator); - SimpleIpV6AddressValidator *ipv6Validator = new SimpleIpV6AddressValidator(this); + SimpleIpV6AddressValidator *ipv6Validator = new SimpleIpV6AddressValidator(SimpleIpV6AddressValidator::Base, this); d->ui.le_localIpv6->setValidator(ipv6Validator); d->ui.le_remoteIpv6->setValidator(ipv6Validator); d->ui.passwordWidget->setVisible(false); d->advUi.sb_useCustomGatewayPort->setValue(NM_SSH_DEFAULT_PORT); d->advUi.sb_useCustomTunnelMtu->setValue(NM_SSH_DEFAULT_MTU); d->advUi.le_extraSshOptions->setText(QLatin1String(NM_SSH_DEFAULT_EXTRA_OPTS)); d->advUi.sb_remoteDeviceNumber->setValue(NM_SSH_DEFAULT_REMOTE_DEV); d->advUi.le_remoteUsername->setText(QLatin1String(NM_SSH_DEFAULT_REMOTE_USERNAME)); KAcceleratorManager::manage(this); if (d->setting && !d->setting->isNull()) { loadConfig(d->setting); } } SshSettingWidget::~SshSettingWidget() { delete d_ptr; } void SshSettingWidget::loadConfig(const NetworkManager::Setting::Ptr &setting) { Q_D(SshSettingWidget); Q_UNUSED(setting) const NMStringMap dataMap = d->setting->data(); // General const QString gateway = dataMap[QLatin1String(NM_SSH_KEY_REMOTE)]; if (!gateway.isEmpty()) { d->ui.le_gateway->setText(gateway); } // Network settings const QString remoteIp = dataMap[QLatin1String(NM_SSH_KEY_REMOTE_IP)]; if (!remoteIp.isEmpty()) { d->ui.le_remoteIp->setText(remoteIp); } const QString localIp = dataMap[QLatin1String(NM_SSH_KEY_LOCAL_IP)]; if (!localIp.isEmpty()) { d->ui.le_localIp->setText(localIp); } const QString netmask = dataMap[QLatin1String(NM_SSH_KEY_NETMASK)]; if (!netmask.isEmpty()) { d->ui.le_netmask->setText(netmask); } // IPv6 network settings const bool ipv6Enabled = dataMap[QLatin1String(NM_SSH_KEY_IP_6)] == QLatin1String("yes"); d->ui.chk_useIpv6->setChecked(ipv6Enabled); if (ipv6Enabled) { const QString remoteIpv6 = dataMap[QLatin1String(NM_SSH_KEY_REMOTE_IP_6)]; if (!remoteIpv6.isEmpty()) { d->ui.le_remoteIpv6->setText(remoteIpv6); } const QString localIpv6 = dataMap[QLatin1String(NM_SSH_KEY_LOCAL_IP_6)]; if (!localIpv6.isEmpty()) { d->ui.le_localIpv6->setText(localIpv6); } const QString netmaskIpv6 = dataMap[QLatin1String(NM_SSH_KEY_NETMASK_6)]; if (!netmaskIpv6.isEmpty()) { d->ui.le_netmaskIpv6->setText(netmaskIpv6); } } // Authentication const QString sshAuthType = dataMap[QLatin1String(NM_SSH_KEY_AUTH_TYPE)]; if (sshAuthType == QLatin1String(NM_SSH_AUTH_TYPE_SSH_AGENT)) { d->ui.cmb_authType->setCurrentIndex(0); } else if (sshAuthType == QLatin1String(NM_SSH_AUTH_TYPE_PASSWORD)) { d->ui.cmb_authType->setCurrentIndex(1); const NetworkManager::Setting::SecretFlags type = (NetworkManager::Setting::SecretFlags)dataMap[NM_SSH_KEY_PASSWORD"-flags"].toInt(); fillOnePasswordCombo(d->ui.le_password, type); } else if (sshAuthType == QLatin1String(NM_SSH_AUTH_TYPE_KEY)) { d->ui.cmb_authType->setCurrentIndex(2); d->ui.kurl_sshKeyFile->setUrl(QUrl::fromLocalFile(dataMap[QLatin1String(NM_SSH_KEY_KEY_FILE)])); } // Options below is belongs to "Advanced" dialog const QString customGatewayPort = dataMap[QLatin1String(NM_SSH_KEY_PORT)]; if (!customGatewayPort.isEmpty()) { d->advUi.chk_useCustomGatewayPort->setChecked(true); d->advUi.sb_useCustomGatewayPort->setValue(customGatewayPort.toInt()); } const QString customMtu = dataMap[QLatin1String(NM_SSH_KEY_TUNNEL_MTU)]; if (!customMtu.isEmpty()) { d->advUi.chk_useCustomTunnelMtu->setChecked(true); d->advUi.sb_useCustomTunnelMtu->setValue(customMtu.toInt()); } const QString extraSshOptions = dataMap[QLatin1String(NM_SSH_KEY_EXTRA_OPTS)]; if (!extraSshOptions.isEmpty()) { d->advUi.chk_extraSshOptions->setChecked(true); d->advUi.le_extraSshOptions->setText(extraSshOptions); } const QString remoteDeviceNumber = dataMap[QLatin1String(NM_SSH_KEY_REMOTE_DEV)]; if (!remoteDeviceNumber.isEmpty()) { d->advUi.chk_remoteDeviceNumber->setChecked(true); d->advUi.sb_remoteDeviceNumber->setValue(remoteDeviceNumber.toInt()); } const QString useTapDevice = dataMap[QLatin1String(NM_SSH_KEY_TAP_DEV)]; if (!useTapDevice.isEmpty()) { if (useTapDevice == QLatin1String("yes")) { d->advUi.chk_useTapDevice->setChecked(true); } } const QString remoteUsername = dataMap[QLatin1String(NM_SSH_KEY_REMOTE_USERNAME)]; if (!remoteUsername.isEmpty()) { d->advUi.chk_remoteUsername->setChecked(true); d->advUi.le_remoteUsername->setText(remoteUsername); } const QString doNotReplaceDefaultRoute = dataMap[QLatin1String(NM_SSH_KEY_NO_DEFAULT_ROUTE)]; if (!doNotReplaceDefaultRoute.isEmpty()) { if (doNotReplaceDefaultRoute == QLatin1String("yes")) { d->advUi.chk_doNotReplaceDefaultRoute->setChecked(true); } } loadSecrets(setting); } void SshSettingWidget::loadSecrets(const NetworkManager::Setting::Ptr &setting) { Q_D(SshSettingWidget); NetworkManager::VpnSetting::Ptr vpnSetting = setting.staticCast(); if (vpnSetting) { const NMStringMap secrets = vpnSetting->secrets(); const QString keyPassword = secrets.value(NM_SSH_KEY_PASSWORD); if (!keyPassword.isEmpty()) { d->ui.le_password->setText(keyPassword); } } } QVariantMap SshSettingWidget::setting() const { Q_D(const SshSettingWidget); NetworkManager::VpnSetting setting; setting.setServiceType(QLatin1String(NM_DBUS_SERVICE_SSH)); NMStringMap data; NMStringMap secretData; data.insert(QLatin1String(NM_SSH_KEY_REMOTE), d->ui.le_gateway->text()); if (!d->ui.le_remoteIp->text().isEmpty()) { data.insert(QLatin1String(NM_SSH_KEY_REMOTE_IP), d->ui.le_remoteIp->text()); } if (!d->ui.le_localIp->text().isEmpty()) { data.insert(QLatin1String(NM_SSH_KEY_LOCAL_IP), d->ui.le_localIp->text()); } if (!d->ui.le_netmask->text().isEmpty()) { data.insert(QLatin1String(NM_SSH_KEY_NETMASK), d->ui.le_netmask->text()); } if (d->ui.chk_useIpv6->isChecked()) { data.insert(QLatin1String(NM_SSH_KEY_IP_6), QLatin1String("yes")); if (!d->ui.le_remoteIpv6->text().isEmpty()) { data.insert(QLatin1String(NM_SSH_KEY_REMOTE_IP_6), d->ui.le_remoteIpv6->text()); } if (!d->ui.le_localIpv6->text().isEmpty()) { data.insert(QLatin1String(NM_SSH_KEY_LOCAL_IP_6), d->ui.le_localIpv6->text()); } if (!d->ui.le_netmaskIpv6->text().isEmpty()) { data.insert(QLatin1String(NM_SSH_KEY_NETMASK_6), d->ui.le_netmaskIpv6->text()); } } switch (d->ui.cmb_authType->currentIndex()) { case 0: data.insert(QLatin1String(NM_SSH_KEY_AUTH_TYPE), QLatin1String(NM_SSH_AUTH_TYPE_SSH_AGENT)); break; case 1: data.insert(QLatin1String(NM_SSH_KEY_AUTH_TYPE), QLatin1String(NM_SSH_AUTH_TYPE_PASSWORD)); if (!d->ui.le_password->text().isEmpty()) { secretData.insert(QLatin1String(NM_SSH_KEY_PASSWORD), d->ui.le_password->text()); } handleOnePasswordType(d->ui.le_password, NM_SSH_KEY_PASSWORD"-flags", data); break; case 2: data.insert(QLatin1String(NM_SSH_KEY_AUTH_TYPE), QLatin1String(NM_SSH_AUTH_TYPE_KEY)); if (!d->ui.kurl_sshKeyFile->url().isEmpty()) { data.insert(QLatin1String(NM_SSH_KEY_KEY_FILE), d->ui.kurl_sshKeyFile->url().toLocalFile()); } break; } if (d->advUi.chk_useCustomGatewayPort->isChecked()) { data.insert(QLatin1String(NM_SSH_KEY_PORT), QString::number(d->advUi.sb_useCustomGatewayPort->value())); } if (d->advUi.chk_useCustomTunnelMtu->isChecked()) { data.insert(QLatin1String(NM_SSH_KEY_TUNNEL_MTU), QString::number(d->advUi.sb_useCustomTunnelMtu->value())); } if (d->advUi.chk_extraSshOptions->isChecked()) { data.insert(QLatin1String(NM_SSH_KEY_EXTRA_OPTS), d->advUi.le_extraSshOptions->text()); } if (d->advUi.chk_remoteDeviceNumber->isChecked()) { data.insert(QLatin1String(NM_SSH_KEY_REMOTE_DEV), QString::number(d->advUi.sb_remoteDeviceNumber->value())); } if (d->advUi.chk_useTapDevice->isChecked()) { data.insert(QLatin1String(NM_SSH_KEY_TAP_DEV), QLatin1String("yes")); } if (d->advUi.chk_remoteUsername->isChecked()) { data.insert(QLatin1String(NM_SSH_KEY_REMOTE_USERNAME), d->advUi.le_remoteUsername->text()); } if (d->advUi.chk_doNotReplaceDefaultRoute->isChecked()) { data.insert(QLatin1String(NM_SSH_KEY_NO_DEFAULT_ROUTE), QLatin1String("yes")); } // save it all setting.setData(data); setting.setSecrets(secretData); return setting.toMap(); } void SshSettingWidget::authTypeChanged(int index) { Q_D(SshSettingWidget); if (index == 0) { d->ui.stackedWidget->setCurrentIndex(0); d->ui.passwordWidget->setVisible(false); } else if (index == 1) { d->ui.stackedWidget->setCurrentIndex(0); d->ui.passwordWidget->setVisible(true); } else { d->ui.stackedWidget->setCurrentIndex(1); } } void SshSettingWidget::doAdvancedDialog() { Q_D(SshSettingWidget); d->advancedDlg->show(); } void SshSettingWidget::passwordTypeChanged(int index) { Q_D(SshSettingWidget); d->ui.le_password->setEnabled(index == SettingWidget::EnumPasswordStorageType::Store); } void SshSettingWidget::fillOnePasswordCombo(PasswordField *passwordField, NetworkManager::Setting::SecretFlags type) { if (type.testFlag(NetworkManager::Setting::None)) { passwordField->setPasswordOption(PasswordField::StoreForAllUsers); } else if (type.testFlag(NetworkManager::Setting::AgentOwned)) { passwordField->setPasswordOption(PasswordField::StoreForUser); } else if (type.testFlag(NetworkManager::Setting::NotSaved)) { passwordField->setPasswordOption(PasswordField::AlwaysAsk); } else { passwordField->setPasswordOption(PasswordField::PasswordField::NotRequired); } } void SshSettingWidget::handleOnePasswordType(const PasswordField *passwordField, const QString &key, NMStringMap &data) const { const PasswordField::PasswordOption option = passwordField->passwordOption(); switch (option) { case PasswordField::StoreForAllUsers: data.insert(key, QString::number(NetworkManager::Setting::None)); break; case PasswordField::StoreForUser: data.insert(key, QString::number(NetworkManager::Setting::AgentOwned)); break; case PasswordField::AlwaysAsk: data.insert(key, QString::number(NetworkManager::Setting::NotSaved)); break; case PasswordField::NotRequired: data.insert(key, QString::number(NetworkManager::Setting::NotRequired)); break; } } bool SshSettingWidget::isValid() const { Q_D(const SshSettingWidget); return !d->ui.le_gateway->text().isEmpty() && !d->ui.le_localIp->text().isEmpty() && !d->ui.le_remoteIp->text().isEmpty() && !d->ui.le_netmask->text().isEmpty(); }