From c6a312845aa8545b1373dbf3472208b0e02dd857 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Tue, 21 Nov 2023 20:13:51 +0700 Subject: [PATCH] added client management --- client/amnezia_application.cpp | 9 +- client/amnezia_application.h | 2 + client/configurators/awg_configurator.cpp | 7 +- client/configurators/awg_configurator.h | 2 +- client/configurators/openvpn_configurator.cpp | 8 +- client/configurators/openvpn_configurator.h | 2 +- client/configurators/vpn_configurator.cpp | 8 +- client/configurators/vpn_configurator.h | 14 +- .../configurators/wireguard_configurator.cpp | 4 +- client/configurators/wireguard_configurator.h | 2 +- client/ui/controllers/exportController.cpp | 73 +++- client/ui/controllers/exportController.h | 12 +- client/ui/models/clientManagementModel.cpp | 356 ++++++++++++++---- client/ui/models/clientManagementModel.h | 52 ++- client/ui/models/servers_model.cpp | 5 + client/ui/models/servers_model.h | 1 + client/ui/qml/Pages2/PageShare.qml | 266 +++++++++++-- client/vpnconnection.cpp | 7 +- client/vpnconnection.h | 2 - 19 files changed, 675 insertions(+), 157 deletions(-) diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index b1ed39ee..5c82599d 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -279,7 +279,7 @@ void AmneziaApplication::initModels() { m_containersModel.reset(new ContainersModel(m_settings, this)); m_engine->rootContext()->setContextProperty("ContainersModel", m_containersModel.get()); - connect(m_vpnConnection.get(), &VpnConnection::newVpnConfigurationCreated, m_containersModel.get(), + connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, m_containersModel.get(), &ContainersModel::updateContainersConfig); m_serversModel.reset(new ServersModel(m_settings, this)); @@ -322,6 +322,11 @@ void AmneziaApplication::initModels() m_sftpConfigModel.reset(new SftpConfigModel(this)); m_engine->rootContext()->setContextProperty("SftpConfigModel", m_sftpConfigModel.get()); + + m_clientManagementModel.reset(new ClientManagementModel(m_settings, this)); + m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get()); + connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, m_clientManagementModel.get(), + &ClientManagementModel::appendClient); } void AmneziaApplication::initControllers() @@ -347,7 +352,7 @@ void AmneziaApplication::initControllers() m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings)); m_engine->rootContext()->setContextProperty("ImportController", m_importController.get()); - m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_settings, m_configurator)); + m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_clientManagementModel, m_settings, m_configurator)); m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get()); m_settingsController.reset(new SettingsController(m_serversModel, m_containersModel, m_languageModel, m_settings)); diff --git a/client/amnezia_application.h b/client/amnezia_application.h index 32300421..2638c66f 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -39,6 +39,7 @@ #include "ui/models/servers_model.h" #include "ui/models/services/sftpConfigModel.h" #include "ui/models/sites_model.h" +#include "ui/models/clientManagementModel.h" #define amnApp (static_cast(QCoreApplication::instance())) @@ -94,6 +95,7 @@ private: QSharedPointer m_languageModel; QSharedPointer m_protocolsModel; QSharedPointer m_sitesModel; + QSharedPointer m_clientManagementModel; QScopedPointer m_openVpnConfigModel; QScopedPointer m_shadowSocksConfigModel; diff --git a/client/configurators/awg_configurator.cpp b/client/configurators/awg_configurator.cpp index c3e42258..ca6c282b 100644 --- a/client/configurators/awg_configurator.cpp +++ b/client/configurators/awg_configurator.cpp @@ -10,11 +10,10 @@ AwgConfigurator::AwgConfigurator(std::shared_ptr settings, QObject *pa { } -QString AwgConfigurator::genAwgConfig(const ServerCredentials &credentials, - DockerContainer container, - const QJsonObject &containerConfig, ErrorCode *errorCode) +QString AwgConfigurator::genAwgConfig(const ServerCredentials &credentials, DockerContainer container, + const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode) { - QString config = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, errorCode); + QString config = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, clientId, errorCode); QJsonObject jsonConfig = QJsonDocument::fromJson(config.toUtf8()).object(); QString awgConfig = jsonConfig.value(config_key::config).toString(); diff --git a/client/configurators/awg_configurator.h b/client/configurators/awg_configurator.h index cf0f2cae..ef40804c 100644 --- a/client/configurators/awg_configurator.h +++ b/client/configurators/awg_configurator.h @@ -12,7 +12,7 @@ public: AwgConfigurator(std::shared_ptr settings, QObject *parent = nullptr); QString genAwgConfig(const ServerCredentials &credentials, DockerContainer container, - const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); + const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr); }; #endif // AWGCONFIGURATOR_H diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index 8c58a376..d863fdab 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -83,7 +83,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co } QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container, - const QJsonObject &containerConfig, ErrorCode *errorCode) + const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode) { ServerController serverController(m_settings); QString config = @@ -131,13 +131,13 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig) config.append("block-ipv6\n"); } if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { - + // no redirect-gateway } if (m_settings->routeMode() == Settings::VpnAllExceptSites) { -#ifndef Q_OS_ANDROID +#ifndef Q_OS_ANDROID config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n"); -#endif +#endif // Prevent ipv6 leak config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); config.append("block-ipv6\n"); diff --git a/client/configurators/openvpn_configurator.h b/client/configurators/openvpn_configurator.h index 3b84e0a0..6d927697 100644 --- a/client/configurators/openvpn_configurator.h +++ b/client/configurators/openvpn_configurator.h @@ -24,7 +24,7 @@ public: }; QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container, - const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); + const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr); QString processConfigWithLocalSettings(QString jsonConfig); QString processConfigWithExportSettings(QString jsonConfig); diff --git a/client/configurators/vpn_configurator.cpp b/client/configurators/vpn_configurator.cpp index 6c5286c2..3018b52f 100644 --- a/client/configurators/vpn_configurator.cpp +++ b/client/configurators/vpn_configurator.cpp @@ -28,11 +28,11 @@ VpnConfigurator::VpnConfigurator(std::shared_ptr settings, QObject *pa } QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container, - const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode) + const QJsonObject &containerConfig, Proto proto, QString &clientId, ErrorCode *errorCode) { switch (proto) { case Proto::OpenVpn: - return openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, errorCode); + return openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, clientId, errorCode); case Proto::ShadowSocks: return shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, errorCode); @@ -40,10 +40,10 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia case Proto::Cloak: return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode); case Proto::WireGuard: - return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, errorCode); + return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, clientId, errorCode); case Proto::Awg: - return awgConfigurator->genAwgConfig(credentials, container, containerConfig, errorCode); + return awgConfigurator->genAwgConfig(credentials, container, containerConfig, clientId, errorCode); case Proto::Ikev2: return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode); diff --git a/client/configurators/vpn_configurator.h b/client/configurators/vpn_configurator.h index ac89b0e4..61dc2ac6 100644 --- a/client/configurators/vpn_configurator.h +++ b/client/configurators/vpn_configurator.h @@ -6,7 +6,6 @@ #include "configurator_base.h" #include "core/defs.h" - class OpenVpnConfigurator; class ShadowSocksConfigurator; class CloakConfigurator; @@ -16,14 +15,15 @@ class SshConfigurator; class AwgConfigurator; // Retrieve connection settings from server -class VpnConfigurator : ConfiguratorBase +class VpnConfigurator : public ConfiguratorBase { Q_OBJECT public: explicit VpnConfigurator(std::shared_ptr settings, QObject *parent = nullptr); QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container, - const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr); + const QJsonObject &containerConfig, Proto proto, QString &clientId, + ErrorCode *errorCode = nullptr); QPair getDnsForConfig(int serverIndex); QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config); @@ -32,8 +32,8 @@ public: QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config); // workaround for containers which is not support normal configuration - void updateContainerConfigAfterInstallation(DockerContainer container, - QJsonObject &containerConfig, const QString &stdOut); + void updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig, + const QString &stdOut); std::shared_ptr openVpnConfigurator; std::shared_ptr shadowSocksConfigurator; @@ -42,6 +42,10 @@ public: std::shared_ptr ikev2Configurator; std::shared_ptr sshConfigurator; std::shared_ptr awgConfigurator; + +signals: + void newVpnConfigCreated(const QString &clientId, const QString &clientName, const DockerContainer container, + ServerCredentials credentials); }; #endif // VPN_CONFIGURATOR_H diff --git a/client/configurators/wireguard_configurator.cpp b/client/configurators/wireguard_configurator.cpp index e22c8282..9a6651ef 100644 --- a/client/configurators/wireguard_configurator.cpp +++ b/client/configurators/wireguard_configurator.cpp @@ -177,7 +177,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon } QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials, DockerContainer container, - const QJsonObject &containerConfig, ErrorCode *errorCode) + const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode) { ServerController serverController(m_settings); QString scriptData = amnezia::scriptData(m_configTemplate, container); @@ -205,6 +205,8 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede jConfig[config_key::psk_key] = connData.pskKey; jConfig[config_key::server_pub_key] = connData.serverPubKey; + clientId = connData.clientPubKey; + return QJsonDocument(jConfig).toJson(); } diff --git a/client/configurators/wireguard_configurator.h b/client/configurators/wireguard_configurator.h index 7f8e1587..c1b4aa3c 100644 --- a/client/configurators/wireguard_configurator.h +++ b/client/configurators/wireguard_configurator.h @@ -26,7 +26,7 @@ public: }; QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container, - const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); + const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr); QString processConfigWithLocalSettings(QString config); QString processConfigWithExportSettings(QString config); diff --git a/client/ui/controllers/exportController.cpp b/client/ui/controllers/exportController.cpp index ef5cc4e3..a8be624d 100644 --- a/client/ui/controllers/exportController.cpp +++ b/client/ui/controllers/exportController.cpp @@ -8,7 +8,9 @@ #include #include +#include "configurators/cloak_configurator.h" #include "configurators/openvpn_configurator.h" +#include "configurators/shadowsocks_configurator.h" #include "configurators/wireguard_configurator.h" #include "core/errorstrings.h" #include "systemController.h" @@ -19,11 +21,13 @@ ExportController::ExportController(const QSharedPointer &serversModel, const QSharedPointer &containersModel, + const QSharedPointer &clientManagementModel, const std::shared_ptr &settings, const std::shared_ptr &configurator, QObject *parent) : QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel), + m_clientManagementModel(clientManagementModel), m_settings(settings), m_configurator(configurator) { @@ -75,13 +79,12 @@ void ExportController::generateFullAccessConfigAndroid() } #endif -void ExportController::generateConnectionConfig() +void ExportController::generateConnectionConfig(const QString &clientName) { clearPreviousConfig(); int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); - ServerCredentials credentials = - qvariant_cast(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); + ServerCredentials credentials = m_serversModel->getCurrentlyProcessedServerCredentials(); DockerContainer container = static_cast(m_containersModel->getCurrentlyProcessedContainerIndex()); QModelIndex containerModelIndex = m_containersModel->index(container); @@ -93,17 +96,25 @@ void ExportController::generateConnectionConfig() for (Proto protocol : ContainerProps::protocolsForContainer(container)) { QJsonObject protocolConfig = m_settings->protocolConfig(serverIndex, container, protocol); - QString vpnConfig = - m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol, &errorCode); + QString clientId; + QString vpnConfig = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol, + clientId, &errorCode); if (errorCode) { emit exportErrorOccurred(errorString(errorCode)); return; } protocolConfig.insert(config_key::last_config, vpnConfig); containerConfig.insert(ProtocolProps::protoToString(protocol), protocolConfig); + if (protocol == Proto::OpenVpn || protocol == Proto::Awg || protocol == Proto::WireGuard) { + errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials); + if (errorCode) { + emit exportErrorOccurred(errorString(errorCode)); + return; + } + } } - QJsonObject config = m_settings->server(serverIndex); + QJsonObject config = m_settings->server(serverIndex); // todo change to servers_model if (!errorCode) { config.remove(config_key::userName); config.remove(config_key::password); @@ -126,13 +137,12 @@ void ExportController::generateConnectionConfig() emit exportConfigChanged(); } -void ExportController::generateOpenVpnConfig() +void ExportController::generateOpenVpnConfig(const QString &clientName) { clearPreviousConfig(); int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); - ServerCredentials credentials = - qvariant_cast(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); + ServerCredentials credentials = m_serversModel->getCurrentlyProcessedServerCredentials(); DockerContainer container = static_cast(m_containersModel->getCurrentlyProcessedContainerIndex()); QModelIndex containerModelIndex = m_containersModel->index(container); @@ -141,8 +151,9 @@ void ExportController::generateOpenVpnConfig() containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); ErrorCode errorCode = ErrorCode::NoError; - QString config = - m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, &errorCode); + QString clientId; + QString config = m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, + clientId, &errorCode); if (errorCode) { emit exportErrorOccurred(errorString(errorCode)); return; @@ -155,16 +166,23 @@ void ExportController::generateOpenVpnConfig() m_config.append(line + "\n"); } + m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); + + errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials); + if (errorCode) { + emit exportErrorOccurred(errorString(errorCode)); + return; + } + emit exportConfigChanged(); } -void ExportController::generateWireGuardConfig() +void ExportController::generateWireGuardConfig(const QString &clientName) { clearPreviousConfig(); int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); - ServerCredentials credentials = - qvariant_cast(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); + ServerCredentials credentials = m_serversModel->getCurrentlyProcessedServerCredentials(); DockerContainer container = static_cast(m_containersModel->getCurrentlyProcessedContainerIndex()); QModelIndex containerModelIndex = m_containersModel->index(container); @@ -172,9 +190,10 @@ void ExportController::generateWireGuardConfig() qvariant_cast(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole)); containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); + QString clientId; ErrorCode errorCode = ErrorCode::NoError; QString config = m_configurator->wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, - &errorCode); + clientId, &errorCode); if (errorCode) { emit exportErrorOccurred(errorString(errorCode)); return; @@ -187,6 +206,14 @@ void ExportController::generateWireGuardConfig() m_config.append(line + "\n"); } + m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); + + errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials); + if (errorCode) { + emit exportErrorOccurred(errorString(errorCode)); + return; + } + emit exportConfigChanged(); } @@ -205,6 +232,22 @@ void ExportController::exportConfig(const QString &fileName) SystemController::saveFile(fileName, m_config); } +void ExportController::revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials) +{ + ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials); + if (errorCode != ErrorCode::NoError) { + emit exportErrorOccurred(errorString(errorCode)); + } +} + +void ExportController::renameClient(const int row, const QString &clientName, const DockerContainer container, ServerCredentials credentials) +{ + ErrorCode errorCode = m_clientManagementModel->renameClient(row, clientName, container, credentials); + if (errorCode != ErrorCode::NoError) { + emit exportErrorOccurred(errorString(errorCode)); + } +} + QList ExportController::generateQrCodeImageSeries(const QByteArray &data) { double k = 850; diff --git a/client/ui/controllers/exportController.h b/client/ui/controllers/exportController.h index 24eaa5c8..b34a05bc 100644 --- a/client/ui/controllers/exportController.h +++ b/client/ui/controllers/exportController.h @@ -6,6 +6,7 @@ #include "configurators/vpn_configurator.h" #include "ui/models/containers_model.h" #include "ui/models/servers_model.h" +#include "ui/models/clientManagementModel.h" #ifdef Q_OS_ANDROID #include "platforms/android/authResultReceiver.h" #endif @@ -16,6 +17,7 @@ class ExportController : public QObject public: explicit ExportController(const QSharedPointer &serversModel, const QSharedPointer &containersModel, + const QSharedPointer &clientManagementModel, const std::shared_ptr &settings, const std::shared_ptr &configurator, QObject *parent = nullptr); @@ -28,15 +30,18 @@ public slots: #if defined(Q_OS_ANDROID) void generateFullAccessConfigAndroid(); #endif - void generateConnectionConfig(); - void generateOpenVpnConfig(); - void generateWireGuardConfig(); + void generateConnectionConfig(const QString &clientName); + void generateOpenVpnConfig(const QString &clientName); + void generateWireGuardConfig(const QString &clientName); QString getConfig(); QList getQrCodes(); void exportConfig(const QString &fileName); + void revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials); + void renameClient(const int row, const QString &clientName, const DockerContainer container, ServerCredentials credentials); + signals: void generateConfig(int type); void exportErrorOccurred(const QString &errorMessage); @@ -55,6 +60,7 @@ private: QSharedPointer m_serversModel; QSharedPointer m_containersModel; + QSharedPointer m_clientManagementModel; std::shared_ptr m_settings; std::shared_ptr m_configurator; diff --git a/client/ui/models/clientManagementModel.cpp b/client/ui/models/clientManagementModel.cpp index 87652ff2..c4c4fb7a 100644 --- a/client/ui/models/clientManagementModel.cpp +++ b/client/ui/models/clientManagementModel.cpp @@ -1,104 +1,330 @@ #include "clientManagementModel.h" +#include #include -ClientManagementModel::ClientManagementModel(QObject *parent) : QAbstractListModel(parent) -{ +#include "core/servercontroller.h" -} - -void ClientManagementModel::clearData() +ClientManagementModel::ClientManagementModel(std::shared_ptr settings, QObject *parent) + : m_settings(settings), QAbstractListModel(parent) { - beginResetModel(); - m_content.clear(); - endResetModel(); -} - -void ClientManagementModel::setContent(const QVector &data) -{ - beginResetModel(); - m_content = data; - endResetModel(); -} - -QJsonObject ClientManagementModel::getContent(amnezia::Proto protocol) -{ - QJsonObject clientsTable; - for (const auto &item : m_content) { - if (protocol == amnezia::Proto::OpenVpn) { - clientsTable[item.toJsonObject()["openvpnCertId"].toString()] = item.toJsonObject(); - } else if (protocol == amnezia::Proto::WireGuard) { - clientsTable[item.toJsonObject()["wireguardPublicKey"].toString()] = item.toJsonObject(); - } - } - return clientsTable; } int ClientManagementModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); - return static_cast(m_content.size()); + return static_cast(m_clientsTable.size()); } QVariant ClientManagementModel::data(const QModelIndex &index, int role) const { - if (!index.isValid() || index.row() < 0 - || index.row() >= static_cast(m_content.size())) { + if (!index.isValid() || index.row() < 0 || index.row() >= static_cast(m_clientsTable.size())) { return QVariant(); } - if (role == NameRole) { - return m_content[index.row()].toJsonObject()["clientName"].toString(); - } else if (role == OpenVpnCertIdRole) { - return m_content[index.row()].toJsonObject()["openvpnCertId"].toString(); - } else if (role == OpenVpnCertDataRole) { - return m_content[index.row()].toJsonObject()["openvpnCertData"].toString(); - } else if (role == WireGuardPublicKey) { - return m_content[index.row()].toJsonObject()["wireguardPublicKey"].toString(); + auto client = m_clientsTable.at(index.row()).toObject(); + auto userData = client.value("userData").toObject(); + + switch (role) { + case UserNameRole: return userData.value("clientName").toString(); + case ContainerNameRole: + return ContainerProps::containerHumanNames().value( + static_cast(userData.value("container").toInt())); } return QVariant(); } -void ClientManagementModel::setData(const QModelIndex &index, QVariant data, int role) +ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCredentials credentials) { - if (!index.isValid() || index.row() < 0 - || index.row() >= static_cast(m_content.size())) { - return; + ServerController serverController(m_settings); + + ErrorCode error = ErrorCode::NoError; + QString stdOut; + auto cbReadStdOut = [&](const QString &data, libssh::Client &) { + stdOut += data + "\n"; + return ErrorCode::NoError; + }; + + const QString clientsTableFile = + QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container)); + const QByteArray clientsTableString = + serverController.getTextFileFromContainer(container, credentials, clientsTableFile, &error); + if (error != ErrorCode::NoError) { + return error; } - auto client = m_content[index.row()].toJsonObject(); - if (role == NameRole) { - client["clientName"] = data.toString(); - } else if (role == OpenVpnCertIdRole) { - client["openvpnCertId"] = data.toString(); - } else if (role == OpenVpnCertDataRole) { - client["openvpnCertData"] = data.toString(); - } else if (role == WireGuardPublicKey) { - client["wireguardPublicKey"] = data.toString(); - } else { - return; - } - if (m_content[index.row()] != client) { - m_content[index.row()] = client; - emit dataChanged(index, index); + beginResetModel(); + m_clientsTable = QJsonDocument::fromJson(clientsTableString).array(); + + if (m_clientsTable.isEmpty()) { + int count = 0; + + if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks + || container == DockerContainer::Cloak) { + const QString getOpenVpnClientsList = + "sudo docker exec -i $CONTAINER_NAME bash -c 'ls /opt/amnezia/openvpn/pki/issued'"; + QString script = serverController.replaceVars(getOpenVpnClientsList, + serverController.genVarsForScript(credentials, container)); + error = serverController.runScript(credentials, script, cbReadStdOut); + if (error != ErrorCode::NoError) { + return error; + } + + if (!stdOut.isEmpty()) { + QStringList certsIds = stdOut.split("\n", Qt::SkipEmptyParts); + certsIds.removeAll("AmneziaReq.crt"); + + for (auto &openvpnCertId : certsIds) { + openvpnCertId.replace(".crt", ""); + if (!isClientExists(openvpnCertId)) { + QJsonObject client; + client["userId"] = openvpnCertId; + + QJsonObject userData; + userData["clientName"] = QString("Client %1").arg(count); + userData["container"] = container; + client["userData"] = userData; + + m_clientsTable.push_back(client); + + count++; + } + } + } + } else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) { + const QString wireGuardConfigFile = + QString("opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg"); + const QString wireguardConfigString = + serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error); + if (error != ErrorCode::NoError) { + return error; + } + + auto configLines = wireguardConfigString.split("\n", Qt::SkipEmptyParts); + QStringList wireguardKeys; + for (const auto &line : configLines) { + auto configPair = line.split(" = ", Qt::SkipEmptyParts); + if (configPair.front() == "PublicKey") { + wireguardKeys.push_back(configPair.back()); + } + } + + for (auto &wireguardKey : wireguardKeys) { + if (!isClientExists(wireguardKey)) { + QJsonObject client; + client["userId"] = wireguardKey; + + QJsonObject userData; + userData["clientName"] = QString("Client %1").arg(count); + userData["container"] = container; + client["userData"] = userData; + + m_clientsTable.push_back(client); + + count++; + } + } + } + + const QByteArray newClientsTableString = QJsonDocument(m_clientsTable).toJson(); + if (clientsTableString != newClientsTableString) { + error = serverController.uploadTextFileToContainer(container, credentials, newClientsTableString, + clientsTableFile); + } } + + endResetModel(); + return error; } -bool ClientManagementModel::removeRows(int row) +bool ClientManagementModel::isClientExists(const QString &clientId) { + for (const QJsonValue &value : qAsConst(m_clientsTable)) { + if (value.isObject()) { + QJsonObject obj = value.toObject(); + if (obj.contains("userId") && obj["userId"].toString() == clientId) { + return true; + } + } + } + return false; +} + +ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QString &clientName, + const DockerContainer container, ServerCredentials credentials) +{ + ErrorCode error; + if (m_clientsTable.empty()) { + error = updateModel(container, credentials); + if (error != ErrorCode::NoError) { + return error; + } + + for (int i = 0; i < m_clientsTable.size(); i++) { + if (m_clientsTable.at(i).toObject().value("userId") == (clientId)) { + error = renameClient(i, clientName, container, credentials); + if (error != ErrorCode::NoError) { + return error; + } + } + } + } else { + beginResetModel(); + QJsonObject client; + client["userId"] = clientId; + + QJsonObject userData; + userData["clientName"] = clientName; + userData["container"] = container; + client["userData"] = userData; + m_clientsTable.push_back(client); + endResetModel(); + + const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson(); + + ServerController serverController(m_settings); + const QString clientsTableFile = + QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container)); + + error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile); + } + + return error; +} + +ErrorCode ClientManagementModel::renameClient(const int row, const QString &clientName, const DockerContainer container, + ServerCredentials credentials) +{ + auto client = m_clientsTable.at(row).toObject(); + auto userData = client["userData"].toObject(); + userData["clientName"] = clientName; + client["userData"] = userData; + + m_clientsTable.replace(row, client); + emit dataChanged(index(row, 0), index(row, 0)); + + const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson(); + + ServerController serverController(m_settings); + const QString clientsTableFile = + QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container)); + + ErrorCode error = + serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile); + + return error; +} + +ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container, + ServerCredentials credentials) +{ + if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks + || container == DockerContainer::Cloak) { + return revokeOpenVpn(row, container, credentials); + } else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) { + return revokeWireGuard(row, container, credentials); + } + return ErrorCode::NoError; +} + +ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContainer container, + ServerCredentials credentials) +{ + auto client = m_clientsTable.at(row).toObject(); + QString clientId = client.value("userId").toString(); + + const QString getOpenVpnCertData = QString("sudo docker exec -i $CONTAINER_NAME bash -c '" + "cd /opt/amnezia/openvpn ;\\" + "easyrsa revoke %1 ;\\" + "easyrsa gen-crl ;\\" + "cp pki/crl.pem .'") + .arg(clientId); + + ServerController serverController(m_settings); + const QString script = + serverController.replaceVars(getOpenVpnCertData, serverController.genVarsForScript(credentials, container)); + ErrorCode error = serverController.runScript(credentials, script); + if (error != ErrorCode::NoError) { + return error; + } + beginRemoveRows(QModelIndex(), row, row); - m_content.removeAt(row); + m_clientsTable.removeAt(row); endRemoveRows(); - return true; + + const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson(); + + const QString clientsTableFile = + QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container)); + error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile); + if (error != ErrorCode::NoError) { + return error; + } + + return ErrorCode::NoError; +} + +ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerContainer container, + ServerCredentials credentials) +{ + ErrorCode error; + ServerController serverController(m_settings); + + const QString wireGuardConfigFile = + QString("/opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg"); + const QString wireguardConfigString = + serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error); + if (error != ErrorCode::NoError) { + return error; + } + + auto client = m_clientsTable.at(row).toObject(); + QString clientId = client.value("userId").toString(); + + auto configSections = wireguardConfigString.split("[", Qt::SkipEmptyParts); + for (auto §ion : configSections) { + if (section.contains(clientId)) { + configSections.removeOne(section); + break; + } + } + QString newWireGuardConfig = configSections.join("["); + newWireGuardConfig.insert(0, "["); + error = serverController.uploadTextFileToContainer(container, credentials, newWireGuardConfig, wireGuardConfigFile); + if (error != ErrorCode::NoError) { + return error; + } + + beginRemoveRows(QModelIndex(), row, row); + m_clientsTable.removeAt(row); + endRemoveRows(); + + const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson(); + + const QString clientsTableFile = + QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container)); + error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile); + if (error != ErrorCode::NoError) { + return error; + } + + const QString script = "sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'"; + error = serverController.runScript( + credentials, + serverController.replaceVars(script.arg(wireGuardConfigFile), + serverController.genVarsForScript(credentials, container))); + if (error != ErrorCode::NoError) { + return error; + } + + return ErrorCode::NoError; } QHash ClientManagementModel::roleNames() const { QHash roles; - roles[NameRole] = "clientName"; - roles[OpenVpnCertIdRole] = "openvpnCertId"; - roles[OpenVpnCertDataRole] = "openvpnCertData"; - roles[WireGuardPublicKey] = "wireguardPublicKey"; + roles[UserNameRole] = "userName"; + roles[ContainerNameRole] = "containerName"; return roles; } diff --git a/client/ui/models/clientManagementModel.h b/client/ui/models/clientManagementModel.h index 5230c337..c51ce816 100644 --- a/client/ui/models/clientManagementModel.h +++ b/client/ui/models/clientManagementModel.h @@ -2,36 +2,62 @@ #define CLIENTMANAGEMENTMODEL_H #include +#include #include "protocols/protocols_defs.h" +#include "settings.h" class ClientManagementModel : public QAbstractListModel { Q_OBJECT -public: - enum ClientRoles { - NameRole = Qt::UserRole + 1, - OpenVpnCertIdRole, - OpenVpnCertDataRole, - WireGuardPublicKey, + struct ClientManagementData + { + QString userId; + QJsonObject userData; + + bool operator==(const ClientManagementData &r) const + { + return userId == r.userId; + } + + bool operator==(const QString &otherUserId) const + { + return userId == otherUserId; + } }; - ClientManagementModel(QObject *parent = nullptr); +public: + enum Roles { + UserNameRole = Qt::UserRole + 1, + ContainerNameRole, + }; + + ClientManagementModel(std::shared_ptr settings, QObject *parent = nullptr); - void clearData(); - void setContent(const QVector &data); - QJsonObject getContent(amnezia::Proto protocol); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - void setData(const QModelIndex &index, QVariant data, int role = Qt::DisplayRole); - bool removeRows(int row); + +public slots: + ErrorCode updateModel(DockerContainer container, ServerCredentials credentials); + ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container, + ServerCredentials credentials); + ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container, + ServerCredentials credentials); + ErrorCode revokeClient(const int index, const DockerContainer container, ServerCredentials credentials); protected: QHash roleNames() const override; private: - QVector m_content; + bool isClientExists(const QString &clientId); + + ErrorCode revokeOpenVpn(const int row, const DockerContainer container, ServerCredentials credentials); + ErrorCode revokeWireGuard(const int row, const DockerContainer container, ServerCredentials credentials); + + QJsonArray m_clientsTable; + + std::shared_ptr m_settings; }; #endif // CLIENTMANAGEMENTMODEL_H diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp index a2a28630..69a4f9d9 100644 --- a/client/ui/models/servers_model.cpp +++ b/client/ui/models/servers_model.cpp @@ -145,6 +145,11 @@ QString ServersModel::getCurrentlyProcessedServerHostName() return qvariant_cast(data(m_currentlyProcessedServerIndex, HostNameRole)); } +const ServerCredentials ServersModel::getCurrentlyProcessedServerCredentials() +{ + return serverCredentials(m_currentlyProcessedServerIndex); +} + bool ServersModel::isDefaultServerCurrentlyProcessed() { return m_defaultServerIndex == m_currentlyProcessedServerIndex; diff --git a/client/ui/models/servers_model.h b/client/ui/models/servers_model.h index ad1d5a83..3010632a 100644 --- a/client/ui/models/servers_model.h +++ b/client/ui/models/servers_model.h @@ -53,6 +53,7 @@ public slots: int getCurrentlyProcessedServerIndex(); QString getCurrentlyProcessedServerHostName(); + const ServerCredentials getCurrentlyProcessedServerCredentials(); void addServer(const QJsonObject &server); void removeServer(); diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index ced7a5ff..01813703 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -23,10 +23,22 @@ PageType { WireGuard } + signal revokeConfig(int index) + onRevokeConfig: function(index) { + PageController.showBusyIndicator(true) + ExportController.revokeConfig(index, + ContainersModel.getCurrentlyProcessedContainerIndex(), + ServersModel.getCurrentlyProcessedServerCredentials()) + PageController.showBusyIndicator(false) + } + Connections { target: ExportController function onGenerateConfig(type) { + shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text + shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text + shareConnectionDrawer.needCloseButton = false shareConnectionDrawer.open() @@ -34,7 +46,7 @@ PageType { PageController.showBusyIndicator(true) switch (type) { - case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(); break; + case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(userNameTextField.textFieldText); break; case PageShare.ConfigType.AmneziaFullAccess: { if (Qt.platform.os === "android") { ExportController.generateFullAccessConfigAndroid(); @@ -44,14 +56,14 @@ PageType { break; } case PageShare.ConfigType.OpenVpn: { - ExportController.generateOpenVpnConfig(); + ExportController.generateOpenVpnConfig(userNameTextField.textFieldText) shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config") shareConnectionDrawer.configExtension = ".ovpn" shareConnectionDrawer.configFileName = "amnezia_for_openvpn" break; } case PageShare.ConfigType.WireGuard: { - ExportController.generateWireGuardConfig(); + ExportController.generateWireGuardConfig(userNameTextField.textFieldText) shareConnectionDrawer.configCaption = qsTr("Save WireGuard config") shareConnectionDrawer.configExtension = ".conf" shareConnectionDrawer.configFileName = "amnezia_for_wireguard" @@ -73,8 +85,6 @@ PageType { } } - property string fullConfigServerSelectorText - property string connectionServerSelectorText property bool showContent: false property bool shareButtonEnabled: true property list connectionTypesModel: [ @@ -147,20 +157,21 @@ PageType { onClicked: { accessTypeSelector.currentIndex = 0 - serverSelector.text = root.connectionServerSelectorText } } HorizontalRadioButton { - checked: root.currentIndex === 1 + checked: accessTypeSelector.currentIndex === 1 implicitWidth: (root.width - 32) / 2 - text: qsTr("Full access") + text: qsTr("Users") onClicked: { accessTypeSelector.currentIndex = 1 - serverSelector.text = root.fullConfigServerSelectorText - root.shareButtonEnabled = true + PageController.showBusyIndicator(true) + ClientManagementModel.updateModel(ContainersModel.getCurrentlyProcessedContainerIndex(), + ServersModel.getCurrentlyProcessedServerCredentials()) + PageController.showBusyIndicator(false) } } } @@ -171,11 +182,25 @@ PageType { Layout.topMargin: 24 Layout.bottomMargin: 24 - text: accessTypeSelector.currentIndex === 0 ? qsTr("Share VPN access without the ability to manage the server") : - qsTr("Share access to server management. The user with whom you share full access to the server will be able to add and remove any protocols and services to the server, as well as change settings.") + visible: accessTypeSelector.currentIndex === 0 + + text: qsTr("Share VPN access without the ability to manage the server") color: "#878B91" } + TextFieldWithHeaderType { + id: userNameTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + visible: accessTypeSelector.currentIndex === 0 + + headerText: qsTr("User name") + textFieldText: "New client" + + checkEmptyText: true + } + DropDownType { id: serverSelector @@ -217,10 +242,11 @@ PageType { serverSelector.severSelectorIndexChanged() } - if (accessTypeSelector.currentIndex !== 0) { - shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text - shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text - } + //full access label +// if (accessTypeSelector.currentIndex !== 0) { +// shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text +// shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text +// } serverSelector.menuVisible = false } @@ -231,8 +257,6 @@ PageType { function handler() { serverSelector.text = selectedText - root.fullConfigServerSelectorText = selectedText - root.connectionServerSelectorText = selectedText ServersModel.currentlyProcessedIndex = proxyServersModel.mapToSource(currentIndex) } } @@ -241,8 +265,6 @@ PageType { DropDownType { id: protocolSelector - visible: accessTypeSelector.currentIndex === 0 - Layout.fillWidth: true Layout.topMargin: 16 @@ -280,12 +302,6 @@ PageType { protocolSelector.menuVisible = false } - Component.onCompleted: { - if (accessTypeSelector.currentIndex === 0) { - handler() - } - } - Connections { target: serverSelector @@ -304,13 +320,17 @@ PageType { } protocolSelector.text = selectedText - root.connectionServerSelectorText = serverSelector.text - shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text - shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(currentIndex)) - fillConnectionTypeModel() + if (accessTypeSelector.currentIndex === 0) { + fillConnectionTypeModel() + } else { + PageController.showBusyIndicator(true) + ClientManagementModel.updateModel(ContainersModel.getCurrentlyProcessedContainerIndex(), + ServersModel.getCurrentlyProcessedServerCredentials()) + PageController.showBusyIndicator(false) + } } function fillConnectionTypeModel() { @@ -378,18 +398,196 @@ PageType { Layout.topMargin: 40 enabled: shareButtonEnabled + visible: accessTypeSelector.currentIndex === 0 text: qsTr("Share") imageSource: "qrc:/images/controls/share-2.svg" onClicked: { - if (accessTypeSelector.currentIndex === 0) { - ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type) - } else { - ExportController.generateConfig(PageShare.ConfigType.AmneziaFullAccess) + ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type) + } + } + + Header2Type { + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 16 + + visible: accessTypeSelector.currentIndex === 1 + + headerText: qsTr("Users") + } + + ListView { + id: usersListView + Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + + visible: accessTypeSelector.currentIndex === 1 + + model: ClientManagementModel + + clip: true + interactive: false + + delegate: Item { + implicitWidth: usersListView.width + implicitHeight: delegateContent.implicitHeight + + ColumnLayout { + id: delegateContent + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + anchors.rightMargin: -16 + anchors.leftMargin: -16 + + LabelWithButtonType { + Layout.fillWidth: true + + text: userName + descriptionText: containerName + rightImageSource: "qrc:/images/controls/chevron-right.svg" + + clickedFunction: function() { + userInfoDrower.open() + } + } + + DividerType {} + + DrawerType { + id: userInfoDrower + + width: root.width + height: root.height * 0.45 + + ColumnLayout { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 16 + anchors.leftMargin: 16 + anchors.rightMargin: 16 + + spacing: 8 + + Header2Type { + Layout.fillWidth: true + Layout.bottomMargin: 24 + + headerText: userName + descriptionText: serverSelector.text + ", " + containerName + } + + BasicButtonType { + Layout.fillWidth: true + Layout.topMargin: 24 + + defaultColor: "transparent" + hoveredColor: Qt.rgba(1, 1, 1, 0.08) + pressedColor: Qt.rgba(1, 1, 1, 0.12) + disabledColor: "#878B91" + textColor: "#D7D8DB" + borderWidth: 1 + + text: qsTr("Rename") + + onClicked: function() { + clientNameEditDrawer.open() + } + + DrawerType { + id: clientNameEditDrawer + + width: root.width + height: root.height * 0.35 + + onVisibleChanged: { + if (clientNameEditDrawer.visible) { + clientName.textField.forceActiveFocus() + } + } + + ColumnLayout { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 16 + anchors.leftMargin: 16 + anchors.rightMargin: 16 + + TextFieldWithHeaderType { + id: clientName + + Layout.fillWidth: true + headerText: qsTr("Client name") + textFieldText: userName + } + + BasicButtonType { + Layout.fillWidth: true + + text: qsTr("Save") + + onClicked: { + if (clientName.textFieldText !== userName) { + PageController.showBusyIndicator(true) + ExportController.renameClient(index, + clientName.textFieldText, + ContainersModel.getCurrentlyProcessedContainerIndex(), + ServersModel.getCurrentlyProcessedServerCredentials()) + PageController.showBusyIndicator(false) + clientNameEditDrawer.close() + } + } + } + } + } + } + + BasicButtonType { + Layout.fillWidth: true + + defaultColor: "transparent" + hoveredColor: Qt.rgba(1, 1, 1, 0.08) + pressedColor: Qt.rgba(1, 1, 1, 0.12) + disabledColor: "#878B91" + textColor: "#D7D8DB" + borderWidth: 1 + + text: qsTr("Revoke") + + onClicked: function() { + questionDrawer.headerText = qsTr("Revoke the config for a user - ") + userName + "?" + questionDrawer.descriptionText = qsTr("The user will no longer be able to connect to your server.") + questionDrawer.yesButtonText = qsTr("Continue") + questionDrawer.noButtonText = qsTr("Cancel") + + questionDrawer.yesButtonFunction = function() { + questionDrawer.close() + userInfoDrower.close() + root.revokeConfig(index) + } + questionDrawer.noButtonFunction = function() { + questionDrawer.close() + } + questionDrawer.open() + + + + } + } + } + } } } } + QuestionDrawer { + id: questionDrawer + } } } } diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index dea40f24..af278276 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -227,12 +227,15 @@ QString VpnConnection::createVpnConfigurationForProto(int serverIndex, const Ser configData = lastVpnConfig.value(proto); configData = m_configurator->processConfigWithLocalSettings(serverIndex, container, proto, configData); } else { - configData = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, proto, errorCode); + QString clientId; + configData = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, proto, clientId, errorCode); if (errorCode && *errorCode) { return ""; } + emit m_configurator->newVpnConfigCreated(clientId, "unnamed client", container, credentials); + QString configDataBeforeLocalProcessing = configData; configData = m_configurator->processConfigWithLocalSettings(serverIndex, container, proto, configData); @@ -323,7 +326,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede ErrorCode e = ErrorCode::NoError; m_vpnConfiguration = createVpnConfiguration(serverIndex, credentials, container, containerConfig, &e); - emit newVpnConfigurationCreated(); + if (e) { emit connectionStateChanged(Vpn::ConnectionState::Error); return; diff --git a/client/vpnconnection.h b/client/vpnconnection.h index 45582de5..ebc0b80e 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -79,8 +79,6 @@ signals: void serviceIsNotReady(); - void newVpnConfigurationCreated(); - protected slots: void onBytesChanged(quint64 receivedBytes, quint64 sentBytes); void onConnectionStateChanged(Vpn::ConnectionState state);