From caad670dbfa4f21b74bb8563f9673550909132b0 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Tue, 28 Feb 2023 17:16:38 +0300 Subject: [PATCH 01/43] added wireguard connection implementation for Linux --- client/protocols/wireguardprotocol.cpp | 107 ++++++++++++++++++------- client/protocols/wireguardprotocol.h | 4 +- client/utilities.cpp | 2 +- ipc/ipc.h | 7 +- ipc/ipc_interface.rep | 3 + ipc/ipcserver.cpp | 45 +++++++++++ ipc/ipcserver.h | 2 + 7 files changed, 133 insertions(+), 37 deletions(-) diff --git a/client/protocols/wireguardprotocol.cpp b/client/protocols/wireguardprotocol.cpp index 224d5176..b348e816 100644 --- a/client/protocols/wireguardprotocol.cpp +++ b/client/protocols/wireguardprotocol.cpp @@ -9,7 +9,7 @@ #include "utilities.h" WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject* parent) : - VpnProtocol(configuration, parent) + VpnProtocol(configuration, parent) { m_configFile.setFileName(QDir::tempPath() + QDir::separator() + serviceName() + ".conf"); writeWireguardConfiguration(configuration); @@ -47,11 +47,8 @@ void WireguardProtocol::stop() m_wireguardStopProcess->setProgram(PermittedProcess::Wireguard); - - QStringList arguments({"--remove", configPath()}); - m_wireguardStopProcess->setArguments(arguments); - - qDebug() << arguments.join(" "); + m_wireguardStopProcess->setArguments(stopArgs()); + qDebug() << stopArgs().join(" "); connect(m_wireguardStopProcess.data(), &PrivilegedProcess::errorOccurred, this, [this](QProcess::ProcessError error) { qDebug() << "WireguardProtocol::WireguardProtocol Stop errorOccurred" << error; @@ -62,12 +59,25 @@ void WireguardProtocol::stop() qDebug() << "WireguardProtocol::WireguardProtocol Stop stateChanged" << newState; }); +#ifdef Q_OS_LINUX + if (IpcClient::Interface()) { + QRemoteObjectPendingReply result = IpcClient::Interface()->isWireguardRunning(); + if (result.returnValue()) { + setConnectionState(VpnProtocol::Disconnected); + return; + } + } else { + qCritical() << "IPC client not initialized"; + setConnectionState(VpnProtocol::Disconnected); + return; + } +#endif + m_wireguardStopProcess->start(); m_wireguardStopProcess->waitForFinished(10000); setConnectionState(VpnProtocol::Disconnected); #endif - } void WireguardProtocol::writeWireguardConfiguration(const QJsonObject &configuration) @@ -79,13 +89,28 @@ void WireguardProtocol::writeWireguardConfiguration(const QJsonObject &configura return; } - m_isConfigLoaded = true; - m_configFile.write(jConfig.value(config_key::config).toString().toUtf8()); m_configFile.close(); - m_configFileName = m_configFile.fileName(); - qDebug().noquote() << QString("Set config data") << m_configFileName; +#ifdef Q_OS_LINUX + if (IpcClient::Interface()) { + QRemoteObjectPendingReply result = IpcClient::Interface()->copyWireguardConfig(m_configFile.fileName()); + if (result.returnValue()) { + qCritical() << "Failed to copy wireguard config"; + return; + } + } else { + qCritical() << "IPC client not initialized"; + return; + } + m_configFileName = "/etc/wireguard/wg99.conf"; +#else + m_configFileName = m_configFile.fileName(); +#endif + + m_isConfigLoaded = true; + + qDebug().noquote() << QString("Set config data") << configPath(); qDebug().noquote() << QString("Set config data") << configuration.value(ProtocolProps::key_proto_config_data(Proto::WireGuard)).toString().toUtf8(); } @@ -120,10 +145,10 @@ ErrorCode WireguardProtocol::start() return lastError(); } - if (!QFileInfo::exists(configPath())) { - setLastError(ErrorCode::ConfigMissing); - return lastError(); - } + // if (!QFileInfo::exists(configPath())) { + // setLastError(ErrorCode::ConfigMissing); + // return lastError(); + // } setConnectionState(VpnConnectionState::Connecting); @@ -143,11 +168,8 @@ ErrorCode WireguardProtocol::start() m_wireguardStartProcess->setProgram(PermittedProcess::Wireguard); - - QStringList arguments({"--add", configPath()}); - m_wireguardStartProcess->setArguments(arguments); - - qDebug() << arguments.join(" "); + m_wireguardStartProcess->setArguments(startArgs()); + qDebug() << startArgs().join(" "); connect(m_wireguardStartProcess.data(), &PrivilegedProcess::errorOccurred, this, [this](QProcess::ProcessError error) { qDebug() << "WireguardProtocol::WireguardProtocol errorOccurred" << error; @@ -191,19 +213,19 @@ ErrorCode WireguardProtocol::start() void WireguardProtocol::updateVpnGateway(const QString &line) { -// // line looks like -// // PUSH: Received control message: 'PUSH_REPLY,route 10.8.0.1,topology net30,ping 10,ping-restart 120,ifconfig 10.8.0.6 10.8.0.5,peer-id 0,cipher AES-256-GCM' + // // line looks like + // // PUSH: Received control message: 'PUSH_REPLY,route 10.8.0.1,topology net30,ping 10,ping-restart 120,ifconfig 10.8.0.6 10.8.0.5,peer-id 0,cipher AES-256-GCM' -// QStringList params = line.split(","); -// for (const QString &l : params) { -// if (l.contains("ifconfig")) { -// if (l.split(" ").size() == 3) { -// m_vpnLocalAddress = l.split(" ").at(1); -// m_vpnGateway = l.split(" ").at(2); + // QStringList params = line.split(","); + // for (const QString &l : params) { + // if (l.contains("ifconfig")) { + // if (l.split(" ").size() == 3) { + // m_vpnLocalAddress = l.split(" ").at(1); + // m_vpnGateway = l.split(" ").at(2); -// qDebug() << QString("Set vpn local address %1, gw %2").arg(m_vpnLocalAddress).arg(vpnGateway()); -// } -// } + // qDebug() << QString("Set vpn local address %1, gw %2").arg(m_vpnLocalAddress).arg(vpnGateway()); + // } + // } // } } @@ -211,3 +233,26 @@ QString WireguardProtocol::serviceName() const { return "AmneziaVPN.WireGuard0"; } + +QStringList WireguardProtocol::stopArgs() +{ +#ifdef Q_OS_WIN + return {"--remove", configPath()}; +#elif defined Q_OS_LINUX + return {"down", "wg99"}; +#else + return {"--remove", configPath()}; +#endif +} + +QStringList WireguardProtocol::startArgs() +{ +#ifdef Q_OS_WIN + return {"--add", configPath()}; +#elif defined Q_OS_LINUX + return {"up", "wg99"}; +#else + return {"--add", configPath()}; +#endif +} + diff --git a/client/protocols/wireguardprotocol.h b/client/protocols/wireguardprotocol.h index 7a50b0d3..59fa39fa 100644 --- a/client/protocols/wireguardprotocol.h +++ b/client/protocols/wireguardprotocol.h @@ -28,7 +28,8 @@ private: void updateRouteGateway(QString line); void updateVpnGateway(const QString &line); QString serviceName() const; - + QStringList stopArgs(); + QStringList startArgs(); private: QString m_configFileName; @@ -36,6 +37,7 @@ private: QSharedPointer m_wireguardStartProcess; QSharedPointer m_wireguardStopProcess; + IpcClient *m_ipcClient; bool m_isConfigLoaded = false; diff --git a/client/utilities.cpp b/client/utilities.cpp index dc17e33f..0d582059 100644 --- a/client/utilities.cpp +++ b/client/utilities.cpp @@ -231,7 +231,7 @@ QString Utils::wireguardExecPath() #ifdef Q_OS_WIN return Utils::executable("wireguard/wireguard-service", true); #elif defined Q_OS_LINUX - return Utils::usrExecutable("wg"); + return Utils::usrExecutable("wg-quick"); #else return Utils::executable("/wireguard", true); #endif diff --git a/ipc/ipc.h b/ipc/ipc.h index e867c063..cb6a1088 100644 --- a/ipc/ipc.h +++ b/ipc/ipc.h @@ -20,13 +20,12 @@ inline QString permittedProcessPath(PermittedProcess pid) { if (pid == PermittedProcess::OpenVPN) { return Utils::openVpnExecPath(); - } - if (pid == PermittedProcess::Wireguard) { + } else if (pid == PermittedProcess::Wireguard) { return Utils::wireguardExecPath(); - } - else if (pid == PermittedProcess::CertUtil) { + } else if (pid == PermittedProcess::CertUtil) { return Utils::certUtilPath(); } + return ""; } diff --git a/ipc/ipc_interface.rep b/ipc/ipc_interface.rep index 2c9f4746..826cd7f8 100644 --- a/ipc/ipc_interface.rep +++ b/ipc/ipc_interface.rep @@ -18,5 +18,8 @@ class IpcInterface SLOT( void cleanUp() ); SLOT( void setLogsEnabled(bool enabled) ); + + SLOT( bool copyWireguardConfig(const QString &sourcePath) ); + SLOT( bool isWireguardRunning() ); }; diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index 3d248b84..de5ed582 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -124,3 +124,48 @@ void IpcServer::setLogsEnabled(bool enabled) Logger::deinit(); } } + +bool IpcServer::copyWireguardConfig(const QString &sourcePath) +{ +#ifdef Q_OS_LINUX + QProcess copyWireguardConfigProcess; + + bool errorOccurred = false; + + connect(©WireguardConfigProcess, &QProcess::errorOccurred, this, [&errorOccurred](QProcess::ProcessError error) { + qDebug() << "WireguardProtocol::WireguardProtocol error occured while copying wireguard config: " << error; + errorOccurred = true; + }); + + copyWireguardConfigProcess.setProgram("/bin/cp"); + copyWireguardConfigProcess.setArguments(QStringList{sourcePath, "/etc/wireguard/wg99.conf"}); + copyWireguardConfigProcess.start(); + copyWireguardConfigProcess.waitForFinished(10000); + return errorOccurred; +#else + return false; +#endif +} + +bool IpcServer::isWireguardRunning() +{ +#ifdef Q_OS_LINUX + QProcess checkWireguardStatusProcess; + + connect(&checkWireguardStatusProcess, &QProcess::errorOccurred, this, [](QProcess::ProcessError error) { + qDebug() << "WireguardProtocol::WireguardProtocol error occured while checking wireguard status: " << error; + }); + + checkWireguardStatusProcess.setProgram("/bin/wg"); + checkWireguardStatusProcess.setArguments(QStringList{"show"}); + checkWireguardStatusProcess.start(); + checkWireguardStatusProcess.waitForFinished(10000); + QString output = checkWireguardStatusProcess.readAllStandardOutput(); + if (!output.isEmpty()) { + return true; + } + return false; +#else + return false; +#endif +} diff --git a/ipc/ipcserver.h b/ipc/ipcserver.h index a5b52ed1..d4ad139c 100644 --- a/ipc/ipcserver.h +++ b/ipc/ipcserver.h @@ -25,6 +25,8 @@ public: virtual QStringList getTapList() override; virtual void cleanUp() override; virtual void setLogsEnabled(bool enabled) override; + virtual bool copyWireguardConfig(const QString &sourcePath) override; + virtual bool isWireguardRunning() override; private: int m_localpid = 0; From 8f189337136bf5cf3a3ed7986f56a90a7599b300 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Thu, 2 Mar 2023 16:19:20 +0300 Subject: [PATCH 02/43] moved the function of checking the availability of wireguard config to ipc client --- client/protocols/wireguardprotocol.cpp | 44 +++++++++++++++----------- ipc/ipc_interface.rep | 1 + ipc/ipcserver.cpp | 6 ++++ ipc/ipcserver.h | 1 + 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/client/protocols/wireguardprotocol.cpp b/client/protocols/wireguardprotocol.cpp index b348e816..666bf80d 100644 --- a/client/protocols/wireguardprotocol.cpp +++ b/client/protocols/wireguardprotocol.cpp @@ -8,8 +8,7 @@ #include "wireguardprotocol.h" #include "utilities.h" -WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject* parent) : - VpnProtocol(configuration, parent) +WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject* parent) : VpnProtocol(configuration, parent) { m_configFile.setFileName(QDir::tempPath() + QDir::separator() + serviceName() + ".conf"); writeWireguardConfiguration(configuration); @@ -145,10 +144,17 @@ ErrorCode WireguardProtocol::start() return lastError(); } - // if (!QFileInfo::exists(configPath())) { - // setLastError(ErrorCode::ConfigMissing); - // return lastError(); - // } + if (IpcClient::Interface()) { + QRemoteObjectPendingReply result = IpcClient::Interface()->isWireguardConfigExists(configPath()); + if (result.returnValue()) { + setLastError(ErrorCode::ConfigMissing); + return lastError(); + } + } else { + qCritical() << "IPC client not initialized"; + setLastError(ErrorCode::InternalError); + return lastError(); + } setConnectionState(VpnConnectionState::Connecting); @@ -198,7 +204,7 @@ ErrorCode WireguardProtocol::start() connect(m_wireguardStartProcess.data(), &PrivilegedProcess::readyReadStandardError, this, [this]() { QRemoteObjectPendingReply reply = m_wireguardStartProcess->readAllStandardError(); - reply.waitForFinished(1000); + reply.waitForFinished(10); qDebug() << "WireguardProtocol::WireguardProtocol readAllStandardError" << reply.returnValue(); }); @@ -213,20 +219,20 @@ ErrorCode WireguardProtocol::start() void WireguardProtocol::updateVpnGateway(const QString &line) { - // // line looks like - // // PUSH: Received control message: 'PUSH_REPLY,route 10.8.0.1,topology net30,ping 10,ping-restart 120,ifconfig 10.8.0.6 10.8.0.5,peer-id 0,cipher AES-256-GCM' +// // line looks like +// // PUSH: Received control message: 'PUSH_REPLY,route 10.8.0.1,topology net30,ping 10,ping-restart 120,ifconfig 10.8.0.6 10.8.0.5,peer-id 0,cipher AES-256-GCM' - // QStringList params = line.split(","); - // for (const QString &l : params) { - // if (l.contains("ifconfig")) { - // if (l.split(" ").size() == 3) { - // m_vpnLocalAddress = l.split(" ").at(1); - // m_vpnGateway = l.split(" ").at(2); +// QStringList params = line.split(","); +// for (const QString &l : params) { +// if (l.contains("ifconfig")) { +// if (l.split(" ").size() == 3) { +// m_vpnLocalAddress = l.split(" ").at(1); +// m_vpnGateway = l.split(" ").at(2); - // qDebug() << QString("Set vpn local address %1, gw %2").arg(m_vpnLocalAddress).arg(vpnGateway()); - // } - // } - // } +// qDebug() << QString("Set vpn local address %1, gw %2").arg(m_vpnLocalAddress).arg(vpnGateway()); +// } +// } +// } } QString WireguardProtocol::serviceName() const diff --git a/ipc/ipc_interface.rep b/ipc/ipc_interface.rep index 826cd7f8..8970f7c8 100644 --- a/ipc/ipc_interface.rep +++ b/ipc/ipc_interface.rep @@ -21,5 +21,6 @@ class IpcInterface SLOT( bool copyWireguardConfig(const QString &sourcePath) ); SLOT( bool isWireguardRunning() ); + SLOT( bool isWireguardConfigExists(const QString &configPath) ); }; diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index de5ed582..c872e6ab 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "router.h" #include "logger.h" @@ -169,3 +170,8 @@ bool IpcServer::isWireguardRunning() return false; #endif } + +bool IpcServer::isWireguardConfigExists(const QString &configPath) +{ + return QFileInfo::exists(configPath); +} diff --git a/ipc/ipcserver.h b/ipc/ipcserver.h index d4ad139c..d5706784 100644 --- a/ipc/ipcserver.h +++ b/ipc/ipcserver.h @@ -27,6 +27,7 @@ public: virtual void setLogsEnabled(bool enabled) override; virtual bool copyWireguardConfig(const QString &sourcePath) override; virtual bool isWireguardRunning() override; + virtual bool isWireguardConfigExists(const QString &configPath) override; private: int m_localpid = 0; From 9962bac50bba714e9f37591edeb2756efd7708c8 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Sun, 19 Mar 2023 17:05:48 +0300 Subject: [PATCH 03/43] changed using cp to QFile to copy wireguard config --- client/protocols/wireguardprotocol.h | 1 - ipc/ipcserver.cpp | 23 ++++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/client/protocols/wireguardprotocol.h b/client/protocols/wireguardprotocol.h index 59fa39fa..880417b4 100644 --- a/client/protocols/wireguardprotocol.h +++ b/client/protocols/wireguardprotocol.h @@ -37,7 +37,6 @@ private: QSharedPointer m_wireguardStartProcess; QSharedPointer m_wireguardStopProcess; - IpcClient *m_ipcClient; bool m_isConfigLoaded = false; diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index c872e6ab..ddbc646c 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -129,20 +129,17 @@ void IpcServer::setLogsEnabled(bool enabled) bool IpcServer::copyWireguardConfig(const QString &sourcePath) { #ifdef Q_OS_LINUX - QProcess copyWireguardConfigProcess; + const QString wireguardConfigPath = "/etc/wireguard/wg99.conf"; + if (QFile::exists(wireguardConfigPath)) + { + QFile::remove(wireguardConfigPath); + } - bool errorOccurred = false; - - connect(©WireguardConfigProcess, &QProcess::errorOccurred, this, [&errorOccurred](QProcess::ProcessError error) { - qDebug() << "WireguardProtocol::WireguardProtocol error occured while copying wireguard config: " << error; - errorOccurred = true; - }); - - copyWireguardConfigProcess.setProgram("/bin/cp"); - copyWireguardConfigProcess.setArguments(QStringList{sourcePath, "/etc/wireguard/wg99.conf"}); - copyWireguardConfigProcess.start(); - copyWireguardConfigProcess.waitForFinished(10000); - return errorOccurred; + if (!QFile::copy(sourcePath, wireguardConfigPath)) { + qDebug() << "WireguardProtocol::WireguardProtocol error occured while copying wireguard config:"; + return false; + } + return true; #else return false; #endif From 5641db0026eff4f0e5286015ac7f8f99ea90be5f Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Mon, 20 Mar 2023 05:45:53 +0300 Subject: [PATCH 04/43] uncommented static link for qtkeychain --- client/cmake/3rdparty.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmake/3rdparty.cmake b/client/cmake/3rdparty.cmake index 99aee113..d159f8f5 100644 --- a/client/cmake/3rdparty.cmake +++ b/client/cmake/3rdparty.cmake @@ -74,7 +74,7 @@ add_subdirectory(${CLIENT_ROOT_DIR}/3rd/libssh) add_compile_definitions(_WINSOCKAPI_) set(LIBS ${LIBS} ssh) -# set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) set(BUILD_WITH_QT6 ON) add_subdirectory(${CLIENT_ROOT_DIR}/3rd/qtkeychain) set(LIBS ${LIBS} qt6keychain) From 084ac9b916ace12671be29d20c06fcb389dcb045 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Mon, 20 Mar 2023 08:46:07 +0300 Subject: [PATCH 05/43] added a default port if it is not in the config when scanning the server for busy ports --- client/core/servercontroller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index c0f6adae..4c87d1b8 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -878,8 +878,8 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential QStringList fixedPorts = ContainerProps::fixedPortsForContainer(container); - QString port = containerConfig.value(config_key::port).toString(); - QString transportProto = containerConfig.value(config_key::transport_proto).toString(); + QString port = containerConfig.value(config_key::port).toString(protocols::openvpn::defaultPort); + QString transportProto = containerConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto); QString script = QString("sudo lsof -i -P -n | grep -E ':%1").arg(port); for (auto &port : fixedPorts) { From 564187481198b37bc9cd02b61d59f395aa1a5a10 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Mon, 20 Mar 2023 17:29:23 +0300 Subject: [PATCH 06/43] added skip port busy check for DNS container. - added script execution error check when checking ports busy --- client/core/servercontroller.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index c0f6adae..43a04777 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -865,6 +865,10 @@ QString ServerController::replaceVars(const QString &script, const Vars &vars) ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config) { + if (container == DockerContainer::Dns) { + return ErrorCode::NoError; + } + QString stdOut; auto cbReadStdOut = [&](const QString &data, QSharedPointer proc) { stdOut += data + "\n"; @@ -881,13 +885,16 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential QString port = containerConfig.value(config_key::port).toString(); QString transportProto = containerConfig.value(config_key::transport_proto).toString(); - QString script = QString("sudo lsof -i -P -n | grep -E ':%1").arg(port); + QString script = QString("sudo lsof -i -P -n | grep -E ':%1 ").arg(port); for (auto &port : fixedPorts) { script = script.append("|:%1").arg(port); } script = script.append("' | grep -i %1").arg(transportProto); - runScript(credentials, + ErrorCode errorCode = runScript(credentials, replaceVars(script, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr); + if (errorCode != ErrorCode::NoError) { + return errorCode; + } if (!stdOut.isEmpty()) { return ErrorCode::ServerPortAlreadyAllocatedError; From 698dfb67d11982defa2dc18a607a3ee63663bf34 Mon Sep 17 00:00:00 2001 From: bakhtiyork Date: Fri, 24 Mar 2023 11:25:00 +0500 Subject: [PATCH 07/43] iOS - libssh with mbedtls build --- .gitmodules | 3 ++ client/3rd/mbedtls | 1 + client/CMakeLists.txt | 1 - client/cmake/3rdparty.cmake | 103 ++++++++++++++++++++++-------------- 4 files changed, 66 insertions(+), 42 deletions(-) create mode 160000 client/3rd/mbedtls diff --git a/.gitmodules b/.gitmodules index ae336344..5ef4a9b1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,3 +37,6 @@ [submodule "client/3rd/SortFilterProxyModel"] path = client/3rd/SortFilterProxyModel url = https://github.com/mitchcurtis/SortFilterProxyModel.git +[submodule "client/3rd/mbedtls"] + path = client/3rd/mbedtls + url = https://github.com/Mbed-TLS/mbedtls.git diff --git a/client/3rd/mbedtls b/client/3rd/mbedtls new file mode 160000 index 00000000..8c892249 --- /dev/null +++ b/client/3rd/mbedtls @@ -0,0 +1 @@ +Subproject commit 8c89224991adff88d53cd380f42a2baa36f91454 diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 55c0deda..6d5a8752 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -481,7 +481,6 @@ if(IOS) set_target_properties("networkextension" PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual) set_target_properties("networkextension" PROPERTIES XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "match AppStore org.amnezia.AmneziaVPN.network-extension") set_target_properties("networkextension" PROPERTIES XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "match Development org.amnezia.AmneziaVPN.network-extension") - endif() if(ANDROID) diff --git a/client/cmake/3rdparty.cmake b/client/cmake/3rdparty.cmake index d159f8f5..a3b460a5 100644 --- a/client/cmake/3rdparty.cmake +++ b/client/cmake/3rdparty.cmake @@ -21,52 +21,73 @@ set(ZLIB_INCLUDE_DIR "${CLIENT_ROOT_DIR}/3rd/zlib" "${CMAKE_CURRENT_BINARY_DIR}/ link_directories(${CMAKE_CURRENT_BINARY_DIR}/3rd/zlib) link_libraries(${ZLIB_LIBRARY}) -if(NOT LINUX) - set(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}/3rd/OpenSSL") - set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include") - set(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib") - set(OPENSSL_LIBRARIES "ssl" "crypto") +if(IOS) + add_subdirectory(${CLIENT_ROOT_DIR}/3rd/mbedtls) + set(WITH_MBEDTLS ON CACHE BOOL "" FORCE) + set(WITH_GCRYPT OFF CACHE BOOL "" FORCE) + set(WITH_EXAMPLES OFF CACHE BOOL "" FORCE) + set(ENABLE_PROGRAMS OFF CACHE BOOL "" FORCE) + set(ENABLE_TESTING OFF CACHE BOOL "" FORCE) + set(HAVE_LIBCRYPTO OFF CACHE BOOL "" FORCE) + set(MBEDTLS_ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}/3rd/mbedtls" CACHE PATH "" FORCE) + set(MBEDTLS_INCLUDE_DIR "${CLIENT_ROOT_DIR}/3rd/mbedtls/include" CACHE PATH "" FORCE) + set(MBEDTLS_LIBRARIES "mbedtls" "mbedx509" "mbedcrypto" CACHE STRING "" FORCE) + set(MBEDTLS_FOUND TRUE CACHE BOOL "" FORCE) + set(MBEDTLS_CRYPTO_LIBRARY "mbedcrypto" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBEDTLS_ALLOW_PRIVATE_ACCESS") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBEDTLS_ALLOW_PRIVATE_ACCESS") + set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) + set(WITH_STATIC_LIB ON CACHE BOOL "" FORCE) - set(OPENSSL_PATH "${CLIENT_ROOT_DIR}/3rd/OpenSSL") - if(WIN32) - if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") - set(OPENSSL_LIB_SSL_PATH "${OPENSSL_PATH}/lib/windows/x86_64/libssl.lib") - set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_PATH}/lib/windows/x86_64/libcrypto.lib") - else() - set(OPENSSL_LIB_SSL_PATH "${OPENSSL_PATH}/lib/windows/x86/libssl.lib") - set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_PATH}/lib/windows/x86/libcrypto.lib") + include_directories(${CLIENT_ROOT_DIR}/3rd/mbedtls/include) +else(IOS) + if(NOT LINUX) + set(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}/3rd/OpenSSL") + set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include") + set(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib") + set(OPENSSL_LIBRARIES "ssl" "crypto") + + set(OPENSSL_PATH "${CLIENT_ROOT_DIR}/3rd/OpenSSL") + if(WIN32) + if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set(OPENSSL_LIB_SSL_PATH "${OPENSSL_PATH}/lib/windows/x86_64/libssl.lib") + set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_PATH}/lib/windows/x86_64/libcrypto.lib") + else() + set(OPENSSL_LIB_SSL_PATH "${OPENSSL_PATH}/lib/windows/x86/libssl.lib") + set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_PATH}/lib/windows/x86/libcrypto.lib") + endif() + elseif(APPLE AND NOT IOS) + set(OPENSSL_LIB_SSL_PATH "${OPENSSL_PATH}/lib/macos/x86_64/libssl.a") + set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_PATH}/lib/macos/x86_64/libcrypto.a") + elseif(IOS) + set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_LIBRARIES_DIR}/libcrypto.a") + set(OPENSSL_SSL_LIBRARY "${OPENSSL_LIBRARIES_DIR}/libssl.a") + set(OPENSSL_LIB_SSL_PATH "${OPENSSL_PATH}/lib/ios/iphone/libssl.a") + set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_PATH}/lib/ios/iphone/libcrypto.a") + elseif(ANDROID) + set(abi ${CMAKE_ANDROID_ARCH_ABI}) + + set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_LIBRARIES_DIR}/android/${abi}/libcrypto.a") + set(OPENSSL_SSL_LIBRARY "${OPENSSL_LIBRARIES_DIR}/android/${abi}/libssl.a") + set(OPENSSL_LIB_SSL_PATH "${OPENSSL_PATH}/lib/android/${abi}/libssl.a") + set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_PATH}/lib/android/${abi}/libcrypto.a") + + set(OPENSSL_LIBRARIES_DIR "${OPENSSL_LIBRARIES_DIR}/android/${abi}") endif() - elseif(APPLE AND NOT IOS) - set(OPENSSL_LIB_SSL_PATH "${OPENSSL_PATH}/lib/macos/x86_64/libssl.a") - set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_PATH}/lib/macos/x86_64/libcrypto.a") - elseif(IOS) - set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_LIBRARIES_DIR}/libcrypto.a") - set(OPENSSL_SSL_LIBRARY "${OPENSSL_LIBRARIES_DIR}/libssl.a") - set(OPENSSL_LIB_SSL_PATH "${OPENSSL_PATH}/lib/ios/iphone/libssl.a") - set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_PATH}/lib/ios/iphone/libcrypto.a") - elseif(ANDROID) - set(abi ${CMAKE_ANDROID_ARCH_ABI}) - set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_LIBRARIES_DIR}/android/${abi}/libcrypto.a") - set(OPENSSL_SSL_LIBRARY "${OPENSSL_LIBRARIES_DIR}/android/${abi}/libssl.a") - set(OPENSSL_LIB_SSL_PATH "${OPENSSL_PATH}/lib/android/${abi}/libssl.a") - set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_PATH}/lib/android/${abi}/libcrypto.a") - - set(OPENSSL_LIBRARIES_DIR "${OPENSSL_LIBRARIES_DIR}/android/${abi}") + file(COPY ${OPENSSL_LIB_SSL_PATH} ${OPENSSL_LIB_CRYPTO_PATH} + DESTINATION ${OPENSSL_LIBRARIES_DIR}) + file(COPY "${OPENSSL_PATH}/include" + DESTINATION ${OPENSSL_ROOT_DIR}) endif() - file(COPY ${OPENSSL_LIB_SSL_PATH} ${OPENSSL_LIB_CRYPTO_PATH} - DESTINATION ${OPENSSL_LIBRARIES_DIR}) - file(COPY "${OPENSSL_PATH}/include" - DESTINATION ${OPENSSL_ROOT_DIR}) -endif() - -set(OPENSSL_USE_STATIC_LIBS TRUE) -find_package(OpenSSL REQUIRED) -set(LIBS ${LIBS} - OpenSSL::Crypto - OpenSSL::SSL -) + set(OPENSSL_USE_STATIC_LIBS TRUE) + find_package(OpenSSL REQUIRED) + set(LIBS ${LIBS} + OpenSSL::Crypto + OpenSSL::SSL + ) +endif(IOS) set(WITH_GSSAPI OFF CACHE BOOL "" FORCE) set(WITH_EXAMPLES OFF CACHE BOOL "" FORCE) From b5aa940701d1c25ede85a3d10846774122777adc Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Sat, 25 Mar 2023 15:50:12 +0300 Subject: [PATCH 08/43] added removal of stopped containers --- client/server_scripts/remove_all_containers.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/server_scripts/remove_all_containers.sh b/client/server_scripts/remove_all_containers.sh index bae7cc3d..a560ade7 100644 --- a/client/server_scripts/remove_all_containers.sh +++ b/client/server_scripts/remove_all_containers.sh @@ -1,3 +1,3 @@ -sudo docker ps | grep amnezia | awk '{print $1}' | xargs sudo docker stop -sudo docker ps | grep amnezia | awk '{print $1}' | xargs sudo docker rm +sudo docker ps -a | grep amnezia | awk '{print $1}' | xargs sudo docker stop +sudo docker ps -a | grep amnezia | awk '{print $1}' | xargs sudo docker rm sudo docker images -a | grep amnezia | awk '{print $3}' | xargs sudo docker rmi From 8d9594ba360b4cf68cdb8d168c370cea09a022fb Mon Sep 17 00:00:00 2001 From: cyberta Date: Sat, 25 Mar 2023 16:56:17 +0100 Subject: [PATCH 09/43] add auto-focus to CameraActivity --- .../src/org/amnezia/vpn/qt/CameraActivity.kt | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/client/android/src/org/amnezia/vpn/qt/CameraActivity.kt b/client/android/src/org/amnezia/vpn/qt/CameraActivity.kt index 8416d97c..8733efa5 100644 --- a/client/android/src/org/amnezia/vpn/qt/CameraActivity.kt +++ b/client/android/src/org/amnezia/vpn/qt/CameraActivity.kt @@ -2,11 +2,11 @@ package org.amnezia.vpn.qt import android.Manifest import android.annotation.SuppressLint -import android.app.Activity -import android.content.Intent import android.content.pm.PackageManager import android.os.Bundle import android.util.Log +import android.view.MotionEvent +import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.camera.core.* @@ -17,9 +17,9 @@ import com.google.mlkit.vision.barcode.BarcodeScannerOptions import com.google.mlkit.vision.barcode.BarcodeScanning import com.google.mlkit.vision.barcode.common.Barcode import com.google.mlkit.vision.common.InputImage +import org.amnezia.vpn.R import java.util.concurrent.ExecutorService import java.util.concurrent.Executors -import org.amnezia.vpn.R class CameraActivity : AppCompatActivity() { @@ -78,7 +78,7 @@ class CameraActivity : AppCompatActivity() { } } - @SuppressLint("UnsafeOptInUsageError") + @SuppressLint("UnsafeOptInUsageError", "ClickableViewAccessibility") private fun configureVideoPreview() { val cameraProviderFuture = ProcessCameraProvider.getInstance(this) val imageCapture = ImageCapture.Builder().build() @@ -101,7 +101,20 @@ class CameraActivity : AppCompatActivity() { try { preview.setSurfaceProvider(viewFinder.surfaceProvider) cameraProvider.unbindAll() - cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, analysisUseCase) + val camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, analysisUseCase) + viewFinder.setOnTouchListener(View.OnTouchListener { view: View, motionEvent: MotionEvent -> + when (motionEvent.action) { + MotionEvent.ACTION_DOWN -> return@OnTouchListener true + MotionEvent.ACTION_UP -> { + val factory = viewFinder.meteringPointFactory + val point = factory.createPoint(motionEvent.x, motionEvent.y) + val action = FocusMeteringAction.Builder(point).build() + camera.cameraControl.startFocusAndMetering(action) + return@OnTouchListener true + } + else -> return@OnTouchListener false + } + }) } catch(exc: Exception) { Log.e("WUTT", "Use case binding failed", exc) } @@ -146,7 +159,6 @@ class CameraActivity : AppCompatActivity() { } } } - imageProxy.close() } .addOnFailureListener { From 85025695dff2503b4b128205e077bc5802dddd74 Mon Sep 17 00:00:00 2001 From: cyberta Date: Sun, 26 Mar 2023 13:47:25 +0200 Subject: [PATCH 10/43] add a section about how to get started for Android developers --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index 6797cd9a..c183de36 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,31 @@ Build might fail with "source files not found" error the first time you try it, dependencies in parallel, and some dependencies end up being built after the ones that require them. In this case simply restart the build. +## How to build the Android app +_tested on Mac OS_ + +The Android app has the following requirements: +* JDK 11 +* Android platform SDK 33 +* cmake 3.25.0 + +After you have installed QT, QT Creator and Android Studio installed, you need to configure QT Creator correctly. Click in the top menu bar on `QT Creator` -> `Preferences` -> `Devices` and select the tab `Android`. + * set path to jdk 11 + * set path to Android SDK ($ANDROID_HOME) + +In case you get errors regarding missing SDK or 'sdkmanager not running', you cannot fix them by correcting the paths and you have some spare GBs on your disk, you can let QT Creator install all requirements by choosing an empty folder for `Android SDK location` and click on `Set Up SDK`. Be aware: This will install a second Android SDK and NDK on your machine! + +Double check that the right cmake version is configured: Click on `QT Creator` -> `Preferences` and click on the side menu on `Kits`. Under the center content view's `Kits` tab you'll find an entry `CMake Tool`. If the default selected CMake version is lower than 3.25.0, install on your system CMake >= 3.25.0 and choose `System CMake at ` from the drop down list. If this entry is missing, you either have not installed CMake yet or QT Creator hasn't found the path to it. In that case click in the preferences window on the side menu item `CMake`, then on the tab `Tools`in the center content view and finally on the Button `Add` to set the path to your installed CMake. + +Please make sure that you have selected Android Platform SDK 33 for your project: click in the main view's side menu on on `Projects`, on the left you'll see a section `Build & Run` showing different Android build targets. You can select any of them, Amnezia VPN's project setup is designed in a way that always all Android targets will be build. Click on the targets submenu item `Build` and scroll in the center content view to `Build Steps`. Click on `Details` at the end of the headline `Build Android APK` (The `Details` button might be hidden in case QT Creator Window is not running in full screen!). Here we are: choose `android-33` as `Android Build platfrom SDK`. + +That's it you should be ready to compile the project from QT Creator! + +### Development flow +After you've hit the build button, QT-Creator copies the whole project to a folder in the repositories parent directory. The folder should look something like `build-amnezia-client-Android_Qt__Clang_-`. +If you want to develop Amnezia VPNs Android components written in Kotlin, such as components using system APIs, you need to import the generated project in Android Studio with `build-amnezia-client-Android_Qt__Clang_-/client/android-build` as the projects root directory. While you should be able to compile the generated project from Android Studio, you cannot work directly in the repository's Android project. So whenever you are confident with your work in the generated proejct, you'll need to copy and paste the affected files to the corresponding path in the repositories Android project so that you can add and commit your changes! + +You may face compiling issues in QT Creator after you've worked in Android Studio on the generated project. Just do a `./gradlew clean` in the geneated project's root directory (`/client/android-build/.`) and you should be good to continue. ## License GPL v.3 From c319c3f52074734dd30e8cc13bd32e1941b8ee24 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Mon, 27 Mar 2023 08:16:35 +0300 Subject: [PATCH 11/43] changed the way to get QSsh::SshConnection, now all resources are cleaned up after use, but the disconnectFromHost function becomes useless --- client/core/servercontroller.cpp | 22 +++++++++++----------- client/core/servercontroller.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index a0df4dc0..132cb18c 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -38,7 +38,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr const std::function)> &cbReadStdOut, const std::function)> &cbReadStdErr) { - SshConnection *client = connectToHost(sshParams(credentials)); + QSharedPointer client = connectToHost(sshParams(credentials)); if (client->state() == SshConnection::State::Connecting) { qDebug() << "ServerController::runScript aborted, connectToHost in progress"; return ErrorCode::SshTimeoutError; @@ -229,7 +229,7 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container, qDebug().noquote() << "Copy file from container\n" << script; - SshConnection *client = connectToHost(sshParams(credentials)); + QSharedPointer client = connectToHost(sshParams(credentials)); if (client->state() != SshConnection::State::Connected) { if (errorCode) *errorCode = fromSshConnectionErrorCode(client->errorState()); return {}; @@ -288,7 +288,7 @@ ErrorCode ServerController::checkOpenVpnServer(DockerContainer container, const ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath, QSsh::SftpOverwriteMode overwriteMode) { - SshConnection *client = connectToHost(sshParams(credentials)); + QSharedPointer client = connectToHost(sshParams(credentials)); if (client->state() != SshConnection::State::Connected) { return fromSshConnectionErrorCode(client->errorState()); } @@ -780,23 +780,23 @@ QString ServerController::checkSshConnection(const ServerCredentials &credential return stdOut; } -SshConnection *ServerController::connectToHost(const SshConnectionParameters &sshParams) +QSharedPointer ServerController::connectToHost(const SshConnectionParameters &sshParams) { - SshConnection *client = acquireConnection(sshParams); - if (!client) return nullptr; + QSharedPointer client(new SshConnection(sshParams)); + if (!client.get()) return nullptr; QEventLoop waitssh; - QObject::connect(client, &SshConnection::connected, &waitssh, [&]() { + QObject::connect(client.get(), &SshConnection::connected, &waitssh, [&]() { qDebug() << "Server connected by ssh"; waitssh.quit(); }); - QObject::connect(client, &SshConnection::disconnected, &waitssh, [&]() { + QObject::connect(client.get(), &SshConnection::disconnected, &waitssh, [&]() { qDebug() << "Server disconnected by ssh"; waitssh.quit(); }); - QObject::connect(client, &SshConnection::error, &waitssh, [&](QSsh::SshError error) { + QObject::connect(client.get(), &SshConnection::error, &waitssh, [&](QSsh::SshError error) { qCritical() << "Ssh error:" << error << client->errorString(); waitssh.quit(); }); @@ -841,8 +841,8 @@ void ServerController::setCancelInstallation(const bool cancel) void ServerController::disconnectFromHost(const ServerCredentials &credentials) { - SshConnection *client = acquireConnection(sshParams(credentials)); - if (client) client->disconnectFromHost(); +// SshConnection *client = acquireConnection(sshParams(credentials)); +// if (client) client->disconnectFromHost(); } ErrorCode ServerController::setupServerFirewall(const ServerCredentials &credentials) diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h index 94ab4efc..b13f3ebf 100644 --- a/client/core/servercontroller.h +++ b/client/core/servercontroller.h @@ -72,7 +72,7 @@ public: Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject()); QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr); - QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams); + QSharedPointer connectToHost(const QSsh::SshConnectionParameters &sshParams); void setCancelInstallation(const bool cancel); ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap &installedContainers); From 20846c8effae90a8f5fdbb745abe8cd2ee636e78 Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Tue, 14 Mar 2023 16:49:06 +0300 Subject: [PATCH 12/43] * correct behavior of back button on Android * removing of annoying debug logs on Android --- .../src/org/amnezia/vpn/VPNServiceBinder.kt | 1 - .../android/src/org/amnezia/vpn/qt/VPNActivity.kt | 10 ---------- client/ui/qml/main.qml | 4 ++++ client/ui/uilogic.cpp | 15 +++++++++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/client/android/src/org/amnezia/vpn/VPNServiceBinder.kt b/client/android/src/org/amnezia/vpn/VPNServiceBinder.kt index 239269a5..e4c6d1c0 100644 --- a/client/android/src/org/amnezia/vpn/VPNServiceBinder.kt +++ b/client/android/src/org/amnezia/vpn/VPNServiceBinder.kt @@ -196,7 +196,6 @@ class VPNServiceBinder(service: VPNService) : Binder() { try { mListener?.let { if (it.isBinderAlive) { - Log.i(tag, "Dispatching event: binder alive") val data = Parcel.obtain() data.writeByteArray(payload?.toByteArray(charset("UTF-8"))) it.transact(code, data, Parcel.obtain(), 0) diff --git a/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt b/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt index b5e8d5fb..1ad19a13 100644 --- a/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt +++ b/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt @@ -99,8 +99,6 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { if (!isBound) { Log.d(TAG, "dispatchParcel: not bound") return - } else { - Log.d(TAG, "dispatchParcel: bound") } val out: Parcel = Parcel.obtain() @@ -331,12 +329,4 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { onActivityMessage(UI_EVENT_QR_CODE_RECEIVED, extra) } } - - override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { - if (keyCode == KeyEvent.KEYCODE_BACK && event.repeatCount == 0) { - onBackPressed() - return true - } - return super.onKeyDown(keyCode, event) - } } diff --git a/client/ui/qml/main.qml b/client/ui/qml/main.qml index b8758384..d91c013f 100644 --- a/client/ui/qml/main.qml +++ b/client/ui/qml/main.qml @@ -61,8 +61,12 @@ Window { function close_page() { if (pageLoader.depth <= 1) { + if (GC.isMobile()) { + root.close() + } return } + pageLoader.currentItem.deactivated() pageLoader.pop() } diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 895a526c..a44f3433 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -224,9 +224,10 @@ void UiLogic::keyPressEvent(Qt::Key key) m_configurator->sshConfigurator->openSshTerminal(m_settings->serverCredentials(m_settings->defaultServerIndex())); break; case Qt::Key_Escape: - case Qt::Key_Back: if (currentPage() == Page::Vpn) break; if (currentPage() == Page::ServerConfiguringProgress) break; + case Qt::Key_Back: + // if (currentPage() == Page::Start && pagesStack.size() < 2) break; // if (currentPage() == Page::Sites && // ui->tableView_sites->selectionModel()->selection().indexes().size() > 0) { @@ -243,10 +244,16 @@ void UiLogic::keyPressEvent(Qt::Key key) void UiLogic::onCloseWindow() { - if (m_settings->serversCount() == 0) qApp->quit(); - else { - hide(); +#ifdef Q_OS_ANDROID + qApp->quit(); +#else + if (m_settings->serversCount() == 0) + { + qApp->quit(); + } else { + emit hide(); } +#endif } QString UiLogic::containerName(int container) From 7167c2f20da6392074e0b2f7a55e78b9af99d0dd Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Tue, 14 Mar 2023 17:25:28 +0300 Subject: [PATCH 13/43] Fix of "Connect" button state after restoring of an app --- client/android/src/org/amnezia/vpn/VPNService.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/android/src/org/amnezia/vpn/VPNService.kt b/client/android/src/org/amnezia/vpn/VPNService.kt index 6ca99e87..6a75b49b 100644 --- a/client/android/src/org/amnezia/vpn/VPNService.kt +++ b/client/android/src/org/amnezia/vpn/VPNService.kt @@ -287,6 +287,8 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface { } } set(value) { + field = value + if (value) { mBinder.dispatchEvent(VPNServiceBinder.EVENTS.connected, "") mConnectionTime = System.currentTimeMillis() From 8fa409d6c196aebb07b7078a6c54129dd37893fe Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Wed, 15 Mar 2023 16:46:59 +0300 Subject: [PATCH 14/43] Restoration of bandwidth meter after closing of GUI --- .../platforms/android/android_controller.cpp | 10 +++- client/ui/uilogic.cpp | 1 + client/vpnconnection.cpp | 54 ++++++++++++++----- client/vpnconnection.h | 17 ++++++ 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/client/platforms/android/android_controller.cpp b/client/platforms/android/android_controller.cpp index a86ab7ca..f1948c03 100644 --- a/client/platforms/android/android_controller.cpp +++ b/client/platforms/android/android_controller.cpp @@ -54,6 +54,10 @@ AndroidController::AndroidController() : QObject() isConnected = doc.object()["connected"].toBool(); + if (isConnected) { + emit scheduleStatusCheckSignal(); + } + emit initialized( true, isConnected, time > 0 ? QDateTime::fromMSecsSinceEpoch(time) : QDateTime()); @@ -66,9 +70,11 @@ AndroidController::AndroidController() : QObject() Q_UNUSED(parcelBody); qDebug() << "Transact: connected"; - isConnected = true; + if (!isConnected) { + emit scheduleStatusCheckSignal(); + } - emit scheduleStatusCheckSignal(); + isConnected = true; emit connectionStateChanged(VpnProtocol::Connected); }, Qt::QueuedConnection); diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index a44f3433..26e2f870 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -133,6 +133,7 @@ void UiLogic::initalizeUiLogic() connect(AndroidController::instance(), &AndroidController::initialized, [this](bool status, bool connected, const QDateTime& connectionDate) { if (connected) { pageLogic()->onConnectionStateChanged(VpnProtocol::Connected); + m_vpnConnection->restoreConnection(); } }); if (!AndroidController::instance()->initialize(pageLogic())) { diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index e01f7e61..273fd7ad 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -20,7 +20,6 @@ #ifdef Q_OS_ANDROID #include "../../platforms/android/android_controller.h" -#include "protocols/android_vpnprotocol.h" #endif #ifdef Q_OS_IOS @@ -353,10 +352,8 @@ void VpnConnection::connectToVpn(int serverIndex, } m_vpnProtocol->prepare(); #elif defined Q_OS_ANDROID - Proto proto = ContainerProps::defaultProtocol(container); - AndroidVpnProtocol *androidVpnProtocol = new AndroidVpnProtocol(proto, m_vpnConfiguration); - connect(AndroidController::instance(), &AndroidController::connectionStateChanged, androidVpnProtocol, &AndroidVpnProtocol::setConnectionState); - connect(AndroidController::instance(), &AndroidController::statusUpdated, androidVpnProtocol, &AndroidVpnProtocol::connectionDataUpdated); + androidVpnProtocol = createDefaultAndroidVpnProtocol(container); + createAndroidConnections(container); m_vpnProtocol.reset(androidVpnProtocol); #elif defined Q_OS_IOS @@ -373,9 +370,7 @@ void VpnConnection::connectToVpn(int serverIndex, m_vpnProtocol.reset(iosVpnProtocol); #endif - connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError); - connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(VpnProtocol::VpnConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::VpnConnectionState))); - connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64))); + createProtocolConnections(); m_serverController->disconnectFromHost(credentials); @@ -383,6 +378,44 @@ void VpnConnection::connectToVpn(int serverIndex, if (e) emit VpnProtocol::Error; } +void VpnConnection::restoreConnection() { + createAndroidConnections(); + + m_vpnProtocol.reset(androidVpnProtocol); + + createProtocolConnections(); +} + +void VpnConnection::createAndroidConnections() +{ + int serverIndex = m_settings->defaultServerIndex(); + DockerContainer container = m_settings->defaultContainer(serverIndex); + + createAndroidConnections(container); +} + +void VpnConnection::createAndroidConnections(DockerContainer container) +{ + androidVpnProtocol = createDefaultAndroidVpnProtocol(container); + + connect(AndroidController::instance(), &AndroidController::connectionStateChanged, androidVpnProtocol, &AndroidVpnProtocol::setConnectionState); + connect(AndroidController::instance(), &AndroidController::statusUpdated, androidVpnProtocol, &AndroidVpnProtocol::connectionDataUpdated); +} + +void VpnConnection::createProtocolConnections() { + connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError); + connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(VpnProtocol::VpnConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::VpnConnectionState))); + connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64))); +} + +AndroidVpnProtocol* VpnConnection::createDefaultAndroidVpnProtocol(DockerContainer container) +{ + Proto proto = ContainerProps::defaultProtocol(container); + AndroidVpnProtocol *androidVpnProtocol = new AndroidVpnProtocol(proto, m_vpnConfiguration); + + return androidVpnProtocol; +} + QString VpnConnection::bytesPerSecToText(quint64 bytes) { double mbps = bytes * 8 / 1e6; @@ -401,8 +434,6 @@ void VpnConnection::disconnectFromVpn() } #endif - - if (!m_vpnProtocol.data()) { emit connectionStateChanged(VpnProtocol::Disconnected); #ifdef Q_OS_ANDROID @@ -415,11 +446,8 @@ void VpnConnection::disconnectFromVpn() VpnProtocol::VpnConnectionState VpnConnection::connectionState() { - - if (!m_vpnProtocol) return VpnProtocol::Disconnected; return m_vpnProtocol->connectionState(); - } bool VpnConnection::isConnected() const diff --git a/client/vpnconnection.h b/client/vpnconnection.h index 3a0d4064..b0fff393 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -18,6 +18,10 @@ #include "core/ipcclient.h" #endif +#ifdef Q_OS_ANDROID +#include "protocols/android_vpnprotocol.h" +#endif + class VpnConfigurator; class ServerController; @@ -61,6 +65,10 @@ public: const QString &remoteAddress() const; void addSitesRoutes(const QString &gw, Settings::RouteMode mode); +#ifdef Q_OS_ANDROID + void restoreConnection(); +#endif + public slots: void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig); @@ -101,6 +109,15 @@ private: #ifdef Q_OS_IOS IOSVpnProtocol * iosVpnProtocol{nullptr}; #endif +#ifdef Q_OS_ANDROID + AndroidVpnProtocol* androidVpnProtocol = nullptr; + AndroidVpnProtocol* createDefaultAndroidVpnProtocol(DockerContainer container); + + void createAndroidConnections(); + void createAndroidConnections(DockerContainer container); +#endif + + void createProtocolConnections(); }; #endif // VPNCONNECTION_H From 5f85bf62f51ddbb5db96c7f3a04ccdb126355dcc Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Wed, 15 Mar 2023 17:46:22 +0300 Subject: [PATCH 15/43] Missing def check --- client/vpnconnection.cpp | 14 ++++++++------ client/vpnconnection.h | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 273fd7ad..6d8aa493 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -378,6 +378,13 @@ void VpnConnection::connectToVpn(int serverIndex, if (e) emit VpnProtocol::Error; } +void VpnConnection::createProtocolConnections() { + connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError); + connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(VpnProtocol::VpnConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::VpnConnectionState))); + connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64))); +} + +#ifdef Q_OS_ANDROID void VpnConnection::restoreConnection() { createAndroidConnections(); @@ -402,12 +409,6 @@ void VpnConnection::createAndroidConnections(DockerContainer container) connect(AndroidController::instance(), &AndroidController::statusUpdated, androidVpnProtocol, &AndroidVpnProtocol::connectionDataUpdated); } -void VpnConnection::createProtocolConnections() { - connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError); - connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(VpnProtocol::VpnConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::VpnConnectionState))); - connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64))); -} - AndroidVpnProtocol* VpnConnection::createDefaultAndroidVpnProtocol(DockerContainer container) { Proto proto = ContainerProps::defaultProtocol(container); @@ -415,6 +416,7 @@ AndroidVpnProtocol* VpnConnection::createDefaultAndroidVpnProtocol(DockerContain return androidVpnProtocol; } +#endif QString VpnConnection::bytesPerSecToText(quint64 bytes) { diff --git a/client/vpnconnection.h b/client/vpnconnection.h index b0fff393..ab8f2de0 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -111,8 +111,8 @@ private: #endif #ifdef Q_OS_ANDROID AndroidVpnProtocol* androidVpnProtocol = nullptr; - AndroidVpnProtocol* createDefaultAndroidVpnProtocol(DockerContainer container); + AndroidVpnProtocol* createDefaultAndroidVpnProtocol(DockerContainer container); void createAndroidConnections(); void createAndroidConnections(DockerContainer container); #endif From 8d45af2034b93106c09cf3f3b56023b9ab86c359 Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Thu, 16 Mar 2023 12:13:55 +0300 Subject: [PATCH 16/43] Files now saving with the file picker, not with the sharing mechanism --- .../android/src/org/amnezia/vpn/VPNService.kt | 41 ------------------- .../src/org/amnezia/vpn/VPNServiceBinder.kt | 15 ------- .../src/org/amnezia/vpn/qt/VPNActivity.kt | 41 +++++++++++++++++++ .../platforms/android/android_controller.cpp | 7 +--- .../platforms/android/androidvpnactivity.cpp | 12 +++++- client/platforms/android/androidvpnactivity.h | 1 + 6 files changed, 53 insertions(+), 64 deletions(-) diff --git a/client/android/src/org/amnezia/vpn/VPNService.kt b/client/android/src/org/amnezia/vpn/VPNService.kt index 6a75b49b..412b1e45 100644 --- a/client/android/src/org/amnezia/vpn/VPNService.kt +++ b/client/android/src/org/amnezia/vpn/VPNService.kt @@ -888,45 +888,4 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface { class CloseableFd(val fd: FileDescriptor) : Closeable { override fun close() = Os.close(fd) } - - fun saveAsFile(configContent: String?, suggestedFileName: String): String { - val rootDirPath = cacheDir.absolutePath - val rootDir = File(rootDirPath) - - if (!rootDir.exists()) { - rootDir.mkdirs() - } - - val fileName = if (!TextUtils.isEmpty(suggestedFileName)) suggestedFileName else "amnezia.cfg" - - val file = File(rootDir, fileName) - - try { - file.bufferedWriter().use { out -> out.write(configContent) } - return file.toString() - } catch (e: Exception) { - e.printStackTrace() - } - - return "" - } - - fun shareFile(attachmentFile: String?) { - try { - val intent = Intent(Intent.ACTION_SEND) - intent.type = "text/*" - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - - val file = File(attachmentFile) - val uri = FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.fileprovider", file) - intent.putExtra(Intent.EXTRA_STREAM, uri) - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - - val createChooser = Intent.createChooser(intent, "Config sharing") - createChooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - startActivity(createChooser) - } catch (e: Exception) { - Log.i(tag, e.message.toString()) - } - } } diff --git a/client/android/src/org/amnezia/vpn/VPNServiceBinder.kt b/client/android/src/org/amnezia/vpn/VPNServiceBinder.kt index e4c6d1c0..bc44217e 100644 --- a/client/android/src/org/amnezia/vpn/VPNServiceBinder.kt +++ b/client/android/src/org/amnezia/vpn/VPNServiceBinder.kt @@ -32,7 +32,6 @@ class VPNServiceBinder(service: VPNService) : Binder() { const val resumeActivate = 7 const val setNotificationText = 8 const val setFallBackNotification = 9 - const val shareConfig = 10 const val importConfig = 11 } @@ -139,20 +138,6 @@ class VPNServiceBinder(service: VPNService) : Binder() { return true } - ACTIONS.shareConfig -> { - val byteArray = data.createByteArray() - val json = byteArray?.let { String(it) } - val config = JSONObject(json) - val configContent = config.getString("data") - val suggestedName = config.getString("suggestedName") - - val filePath = mService.saveAsFile(configContent, suggestedName) - Log.i(tag, "save file: $filePath") - - mService.shareFile(filePath) - return true - } - ACTIONS.importConfig -> { val buffer = data.readString() diff --git a/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt b/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt index 1ad19a13..9d13b930 100644 --- a/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt +++ b/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt @@ -37,6 +37,9 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { private val STORAGE_PERMISSION_CODE = 42 private val CAMERA_ACTION_CODE = 101 + private val CREATE_FILE_ACTION_CODE = 102 + + private var tmpFileContentToSave: String = "" companion object { private lateinit var instance: VPNActivity @@ -56,6 +59,10 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { @JvmStatic fun sendToService(actionCode: Int, body: String) { VPNActivity.getInstance().dispatchParcel(actionCode, body) } + + @JvmStatic fun saveFileAs(fileContent: String, suggestedName: String) { + VPNActivity.getInstance().saveFile(fileContent, suggestedName) + } } override fun onCreate(savedInstanceState: Bundle?) { @@ -76,6 +83,18 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { startActivityForResult(intent, CAMERA_ACTION_CODE) } + private fun saveFile(fileContent: String, suggestedName: String) { + tmpFileContentToSave = fileContent + + val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "text/*" + putExtra(Intent.EXTRA_TITLE, suggestedName) + } + + startActivityForResult(intent, CREATE_FILE_ACTION_CODE) + } + override fun getSystemService(name: String): Any? { return if (Build.VERSION.SDK_INT >= 29 && name == "clipboard") { // QT will always attempt to read the clipboard if content is there. @@ -328,5 +347,27 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { val extra = data?.getStringExtra("result") ?: "" onActivityMessage(UI_EVENT_QR_CODE_RECEIVED, extra) } + + if (requestCode == CREATE_FILE_ACTION_CODE && resultCode == RESULT_OK) { + data?.data?.also { uri -> + alterDocument(uri) + } + } + } + + private fun alterDocument(uri: Uri) { + try { + applicationContext.contentResolver.openFileDescriptor(uri, "w")?.use { fd -> + FileOutputStream(fd.fileDescriptor).use { fos -> + fos.write(tmpFileContentToSave.toByteArray()) + } + } + } catch (e: FileNotFoundException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + + tmpFileContentToSave = "" } } diff --git a/client/platforms/android/android_controller.cpp b/client/platforms/android/android_controller.cpp index f1948c03..0db1bd46 100644 --- a/client/platforms/android/android_controller.cpp +++ b/client/platforms/android/android_controller.cpp @@ -209,12 +209,7 @@ void AndroidController::setNotificationText(const QString& title, } void AndroidController::shareConfig(const QString& configContent, const QString& suggestedName) { - QJsonObject rootObject; - rootObject["data"] = configContent; - rootObject["suggestedName"] = suggestedName; - QJsonDocument doc(rootObject); - - AndroidVPNActivity::sendToService(ServiceAction::ACTION_SHARE_CONFIG, doc.toJson()); + AndroidVPNActivity::saveFileAs(configContent, suggestedName); } /* diff --git a/client/platforms/android/androidvpnactivity.cpp b/client/platforms/android/androidvpnactivity.cpp index 17639023..2076280d 100644 --- a/client/platforms/android/androidvpnactivity.cpp +++ b/client/platforms/android/androidvpnactivity.cpp @@ -57,6 +57,14 @@ void AndroidVPNActivity::startQrCodeReader() QJniObject::callStaticMethod(CLASSNAME, "startQrCodeReader", "()V"); } +void AndroidVPNActivity::saveFileAs(QString fileContent, QString suggestedFilename) { + QJniObject::callStaticMethod( + CLASSNAME, + "saveFileAs", "(Ljava/lang/String;Ljava/lang/String;)V", + QJniObject::fromString(fileContent).object(), + QJniObject::fromString(suggestedFilename).object()); +} + // static AndroidVPNActivity* AndroidVPNActivity::instance() { if (s_instance == nullptr) { @@ -70,9 +78,9 @@ AndroidVPNActivity* AndroidVPNActivity::instance() { void AndroidVPNActivity::sendToService(ServiceAction type, const QString& data) { int messageType = (int)type; - QJniEnvironment env; QJniObject::callStaticMethod( - CLASSNAME, "sendToService", "(ILjava/lang/String;)V", + CLASSNAME, + "sendToService", "(ILjava/lang/String;)V", static_cast(messageType), QJniObject::fromString(data).object()); } diff --git a/client/platforms/android/androidvpnactivity.h b/client/platforms/android/androidvpnactivity.h index 1bc1a522..130bef88 100644 --- a/client/platforms/android/androidvpnactivity.h +++ b/client/platforms/android/androidvpnactivity.h @@ -75,6 +75,7 @@ public: static void sendToService(ServiceAction type, const QString& data); static void connectService(); static void startQrCodeReader(); + static void saveFileAs(QString fileContent, QString suggestedFilename); signals: void serviceConnected(); From c0bb06bf49b4691319456fe50140a45e13e65720 Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Fri, 17 Mar 2023 16:53:02 +0300 Subject: [PATCH 17/43] Fix of copying to clipboard --- .../src/org/amnezia/vpn/qt/VPNActivity.kt | 17 +++++++++++++++++ client/platforms/android/android_controller.cpp | 6 ++++++ client/platforms/android/android_controller.h | 2 +- client/platforms/android/androidvpnactivity.cpp | 8 ++++++++ client/platforms/android/androidvpnactivity.h | 1 + client/ui/uilogic.cpp | 4 ++++ 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt b/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt index 9d13b930..17888a0d 100644 --- a/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt +++ b/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt @@ -5,6 +5,8 @@ package org.amnezia.vpn.qt; import android.Manifest +import android.content.ClipData +import android.content.ClipboardManager import android.content.ComponentName import android.content.ContentResolver import android.content.Context @@ -63,6 +65,10 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { @JvmStatic fun saveFileAs(fileContent: String, suggestedName: String) { VPNActivity.getInstance().saveFile(fileContent, suggestedName) } + + @JvmStatic fun putTextToClipboard(text: String) { + VPNActivity.getInstance().putToClipboard(text) + } } override fun onCreate(savedInstanceState: Bundle?) { @@ -370,4 +376,15 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { tmpFileContentToSave = "" } + + private fun putToClipboard(text: String) { + this.runOnUiThread { + val clipboard = applicationContext.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager? + + if (clipboard != null) { + val clip: ClipData = ClipData.newPlainText("", text) + clipboard.setPrimaryClip(clip) + } + } + } } diff --git a/client/platforms/android/android_controller.cpp b/client/platforms/android/android_controller.cpp index 0db1bd46..3a93ea19 100644 --- a/client/platforms/android/android_controller.cpp +++ b/client/platforms/android/android_controller.cpp @@ -15,6 +15,7 @@ #include "private/qandroidextras_p.h" #include "ui/pages_logic/StartPageLogic.h" +#include "androidvpnactivity.h" #include "androidutils.h" namespace { @@ -267,6 +268,11 @@ void AndroidController::startQrReaderActivity() AndroidVPNActivity::instance()->startQrCodeReader(); } +void AndroidController::copyTextToClipboard(QString text) +{ + AndroidVPNActivity::instance()->copyTextToClipboard(text); +} + void AndroidController::scheduleStatusCheckSlot() { QTimer::singleShot(1000, [this]() { diff --git a/client/platforms/android/android_controller.h b/client/platforms/android/android_controller.h index 59ecd9b3..00b37225 100644 --- a/client/platforms/android/android_controller.h +++ b/client/platforms/android/android_controller.h @@ -11,7 +11,6 @@ #include "ui/pages_logic/StartPageLogic.h" #include "protocols/vpnprotocol.h" -#include "androidvpnactivity.h" using namespace amnezia; @@ -44,6 +43,7 @@ public: void setVpnConfig(const QJsonObject &newVpnConfig); void startQrReaderActivity(); + void copyTextToClipboard(QString text); signals: void connectionStateChanged(VpnProtocol::VpnConnectionState state); diff --git a/client/platforms/android/androidvpnactivity.cpp b/client/platforms/android/androidvpnactivity.cpp index 2076280d..9431597b 100644 --- a/client/platforms/android/androidvpnactivity.cpp +++ b/client/platforms/android/androidvpnactivity.cpp @@ -65,6 +65,14 @@ void AndroidVPNActivity::saveFileAs(QString fileContent, QString suggestedFilena QJniObject::fromString(suggestedFilename).object()); } +void AndroidVPNActivity::copyTextToClipboard(QString text) +{ + QJniObject::callStaticMethod( + CLASSNAME, + "putTextToClipboard", "(Ljava/lang/String;)V", + QJniObject::fromString(text).object()); +} + // static AndroidVPNActivity* AndroidVPNActivity::instance() { if (s_instance == nullptr) { diff --git a/client/platforms/android/androidvpnactivity.h b/client/platforms/android/androidvpnactivity.h index 130bef88..8eeb5598 100644 --- a/client/platforms/android/androidvpnactivity.h +++ b/client/platforms/android/androidvpnactivity.h @@ -76,6 +76,7 @@ public: static void connectService(); static void startQrCodeReader(); static void saveFileAs(QString fileContent, QString suggestedFilename); + static void copyTextToClipboard(QString text); signals: void serviceConnected(); diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 26e2f870..00cc5dd1 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -474,7 +474,11 @@ void UiLogic::saveBinaryFile(const QString &desc, QString ext, const QString &da void UiLogic::copyToClipboard(const QString &text) { +#ifdef Q_OS_ANDROID + AndroidController::instance()->copyTextToClipboard(text); +#elif qApp->clipboard()->setText(text); +#endif } void UiLogic::shareTempFile(const QString &suggestedName, QString ext, const QString& data) { From 3a5317f16a35a3b11d978589e876ab5702c29710 Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Thu, 23 Mar 2023 15:13:15 +0300 Subject: [PATCH 18/43] Implementation of "migration manager" to fix placement of config files issue appeared after moving from Qt 5 to Qt 6 --- client/CMakeLists.txt | 2 + client/main.cpp | 4 ++ client/migrations.cpp | 86 +++++++++++++++++++++++++++++++++++++++++++ client/migrations.h | 24 ++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 client/migrations.cpp create mode 100644 client/migrations.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 50d6d0f7..605a4d09 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -59,6 +59,7 @@ include_directories( ) set(HEADERS ${HEADERS} + ${CMAKE_CURRENT_LIST_DIR}/migrations.h ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc.h ${CMAKE_CURRENT_LIST_DIR}/amnezia_application.h ${CMAKE_CURRENT_LIST_DIR}/containers/containers_defs.h @@ -85,6 +86,7 @@ if(NOT IOS) endif() set(SOURCES ${SOURCES} + ${CMAKE_CURRENT_LIST_DIR}/migrations.cpp ${CMAKE_CURRENT_LIST_DIR}/amnezia_application.cpp ${CMAKE_CURRENT_LIST_DIR}/containers/containers_defs.cpp ${CMAKE_CURRENT_LIST_DIR}/core/errorstrings.cpp diff --git a/client/main.cpp b/client/main.cpp index 62685953..f20c5dd1 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -4,6 +4,7 @@ #include "amnezia_application.h" #include "defines.h" +#include "migrations.h" #ifdef Q_OS_WIN #include "Windows.h" @@ -16,6 +17,9 @@ int main(int argc, char *argv[]) { + Migrations migrationsManager; + migrationsManager.doMigrations(); + QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false")); QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); diff --git a/client/migrations.cpp b/client/migrations.cpp new file mode 100644 index 00000000..6fac6be7 --- /dev/null +++ b/client/migrations.cpp @@ -0,0 +1,86 @@ +#include "migrations.h" + +#include +#include +#include +#include + +#include "defines.h" + +Migrations::Migrations(QObject *parent) + : QObject{parent} +{ + QString version(APP_MAJOR_VERSION); + + QStringList versionDigits = version.split("."); + + if (versionDigits.size() >= 3) { + currentMajor = versionDigits[0].toInt(); + currentMinor = versionDigits[1].toInt(); + currentMicro = versionDigits[2].toInt(); + } + + if (versionDigits.size() == 4) { + currentPatch = versionDigits[3].toInt(); + } +} + +void Migrations::doMigrations() +{ + if (currentMajor == 3) { + migrateV3(); + } +} + +void Migrations::migrateV3() +{ +#ifdef Q_OS_ANDROID + qDebug() << "Migration to V3 on Android..."; + + QString packageName = "org.amnezia.vpn"; + + QDir dir("."); + QString currentDir = dir.absolutePath(); + + int packageNameIndex = currentDir.indexOf(packageName); + + if (packageNameIndex == -1) { + return; + } + + QString rootLocation = currentDir.left(packageNameIndex + packageName.size()); + + if (rootLocation.isEmpty()) { + return; + } + + QString location = rootLocation + "/files/.config/AmneziaVPN.ORG/AmneziaVPN.conf"; + + QFile oldConfig(location); + + if (oldConfig.exists()) { + QString newConfigPath = rootLocation + "/files/settings"; + + QDir newConfigDir(newConfigPath); + + newConfigPath += "/AmneziaVPN.ORG"; + + bool mkPathRes = newConfigDir.mkpath(newConfigPath); + + if (!mkPathRes) { + return; + } + + QFile newConfigFile(newConfigPath + "/AmneziaVPN.conf"); + + if (!newConfigFile.exists()) { + bool cpResult = QFile::copy(oldConfig.fileName(), newConfigFile.fileName()); + if (cpResult) { + oldConfig.remove(); + QDir oldConfigDir(rootLocation + "/files/.config"); + oldConfigDir.rmdir("AmneziaVPN.ORG"); + } + } + } +#endif +} diff --git a/client/migrations.h b/client/migrations.h new file mode 100644 index 00000000..ea6bae92 --- /dev/null +++ b/client/migrations.h @@ -0,0 +1,24 @@ +#ifndef MIGRATIONS_H +#define MIGRATIONS_H + +#include + +class Migrations : public QObject +{ + Q_OBJECT +public: + explicit Migrations(QObject *parent = nullptr); + + void doMigrations(); + +private: + void migrateV3(); + +private: + int currentMajor = 0; + int currentMinor = 0; + int currentMicro = 0; + int currentPatch = 0; +}; + +#endif // MIGRATIONS_H From 8bbc0b9e1a50ac1cd0823181750a4a2c40644b37 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Wed, 29 Mar 2023 09:05:35 +0300 Subject: [PATCH 19/43] set m_installCredentials when visiting the ServerContainers page --- client/ui/pages_logic/ServerContainersLogic.cpp | 1 + client/ui/pages_logic/ServerListLogic.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/pages_logic/ServerContainersLogic.cpp b/client/ui/pages_logic/ServerContainersLogic.cpp index aeec8161..870a10db 100644 --- a/client/ui/pages_logic/ServerContainersLogic.cpp +++ b/client/ui/pages_logic/ServerContainersLogic.cpp @@ -31,6 +31,7 @@ void ServerContainersLogic::onUpdatePage() p_model->setSelectedServerIndex(uiLogic()->m_selectedServerIndex); set_isManagedServer(m_settings->haveAuthData(uiLogic()->m_selectedServerIndex)); + uiLogic()->m_installCredentials = m_settings->serverCredentials(uiLogic()->m_selectedServerIndex); emit updatePage(); } diff --git a/client/ui/pages_logic/ServerListLogic.cpp b/client/ui/pages_logic/ServerListLogic.cpp index e91b1e33..79d13c8b 100644 --- a/client/ui/pages_logic/ServerListLogic.cpp +++ b/client/ui/pages_logic/ServerListLogic.cpp @@ -21,7 +21,6 @@ void ServerListLogic::onServerListPushbuttonDefaultClicked(int index) void ServerListLogic::onServerListPushbuttonSettingsClicked(int index) { uiLogic()->m_selectedServerIndex = index; - uiLogic()->m_installCredentials = m_settings->serverCredentials(index); uiLogic()->goToPage(Page::ServerSettings); } From 5fa6e755b206353b072d384781344d06217c340b Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Wed, 29 Mar 2023 09:03:26 +0300 Subject: [PATCH 20/43] changed the existsAnyServer value to properly display locked settings --- client/ui/pages_logic/GeneralSettingsLogic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/pages_logic/GeneralSettingsLogic.cpp b/client/ui/pages_logic/GeneralSettingsLogic.cpp index cbdf2692..0e92f8c9 100644 --- a/client/ui/pages_logic/GeneralSettingsLogic.cpp +++ b/client/ui/pages_logic/GeneralSettingsLogic.cpp @@ -13,7 +13,7 @@ GeneralSettingsLogic::GeneralSettingsLogic(UiLogic *logic, QObject *parent): void GeneralSettingsLogic::onUpdatePage() { uiLogic()->m_selectedServerIndex = m_settings->defaultServerIndex(); - set_existsAnyServer(uiLogic()->m_selectedServerIndex >= 0); + set_existsAnyServer(m_settings->serversCount() > 0); uiLogic()->m_selectedDockerContainer = m_settings->defaultContainer(m_settings->defaultServerIndex()); set_pushButtonGeneralSettingsShareConnectionEnable(m_settings->haveAuthData(m_settings->defaultServerIndex())); From c48d65525a43aed00f2e1668940aa316f3975565 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Wed, 29 Mar 2023 09:05:35 +0300 Subject: [PATCH 21/43] set m_installCredentials when visiting the ServerContainers page --- client/ui/pages_logic/ServerContainersLogic.cpp | 1 + client/ui/pages_logic/ServerListLogic.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/pages_logic/ServerContainersLogic.cpp b/client/ui/pages_logic/ServerContainersLogic.cpp index aeec8161..870a10db 100644 --- a/client/ui/pages_logic/ServerContainersLogic.cpp +++ b/client/ui/pages_logic/ServerContainersLogic.cpp @@ -31,6 +31,7 @@ void ServerContainersLogic::onUpdatePage() p_model->setSelectedServerIndex(uiLogic()->m_selectedServerIndex); set_isManagedServer(m_settings->haveAuthData(uiLogic()->m_selectedServerIndex)); + uiLogic()->m_installCredentials = m_settings->serverCredentials(uiLogic()->m_selectedServerIndex); emit updatePage(); } diff --git a/client/ui/pages_logic/ServerListLogic.cpp b/client/ui/pages_logic/ServerListLogic.cpp index e91b1e33..79d13c8b 100644 --- a/client/ui/pages_logic/ServerListLogic.cpp +++ b/client/ui/pages_logic/ServerListLogic.cpp @@ -21,7 +21,6 @@ void ServerListLogic::onServerListPushbuttonDefaultClicked(int index) void ServerListLogic::onServerListPushbuttonSettingsClicked(int index) { uiLogic()->m_selectedServerIndex = index; - uiLogic()->m_installCredentials = m_settings->serverCredentials(index); uiLogic()->goToPage(Page::ServerSettings); } From 3261c36f97054429088decaf57b2dc241f9f38f6 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Wed, 29 Mar 2023 09:03:26 +0300 Subject: [PATCH 22/43] changed the existsAnyServer value to properly display locked settings --- client/ui/pages_logic/GeneralSettingsLogic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/pages_logic/GeneralSettingsLogic.cpp b/client/ui/pages_logic/GeneralSettingsLogic.cpp index cbdf2692..0e92f8c9 100644 --- a/client/ui/pages_logic/GeneralSettingsLogic.cpp +++ b/client/ui/pages_logic/GeneralSettingsLogic.cpp @@ -13,7 +13,7 @@ GeneralSettingsLogic::GeneralSettingsLogic(UiLogic *logic, QObject *parent): void GeneralSettingsLogic::onUpdatePage() { uiLogic()->m_selectedServerIndex = m_settings->defaultServerIndex(); - set_existsAnyServer(uiLogic()->m_selectedServerIndex >= 0); + set_existsAnyServer(m_settings->serversCount() > 0); uiLogic()->m_selectedDockerContainer = m_settings->defaultContainer(m_settings->defaultServerIndex()); set_pushButtonGeneralSettingsShareConnectionEnable(m_settings->haveAuthData(m_settings->defaultServerIndex())); From 90c8fbb49598a0949d7ac7142da03847b4cd9c3e Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Wed, 29 Mar 2023 09:53:18 +0300 Subject: [PATCH 23/43] Update Room to fix build on Apple M1 --- client/android/shadowsocks/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/android/shadowsocks/build.gradle b/client/android/shadowsocks/build.gradle index 69ebd0bd..f1d738b2 100644 --- a/client/android/shadowsocks/build.gradle +++ b/client/android/shadowsocks/build.gradle @@ -35,7 +35,7 @@ androidExtensions { } //def lifecycleVersion = '2.0.0' -//def roomVersion = '2.0.0' +def roomVersion = "2.4.3" //def preferencexVersion = '1.0.0' dependencies { @@ -45,13 +45,12 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0" - implementation "androidx.core:core-ktx:1.2.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0" implementation "androidx.lifecycle:lifecycle-livedata-core-ktx:2.4.0" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" - implementation "androidx.room:room-runtime:2.2.5" // runtime + implementation "androidx.room:room-runtime:$roomVersion" // runtime implementation "androidx.preference:preference:1.1.0" implementation "androidx.work:work-runtime-ktx:2.7.1" implementation "androidx.browser:browser:1.3.0-alpha01" @@ -65,6 +64,7 @@ dependencies { // api "com.takisoft.preferencex:preferencex:1.0.0" implementation 'com.takisoft.preferencex:preferencex:1.1.0' api 'org.connectbot.jsocks:jsocks:1.0.0' - kapt "androidx.room:room-compiler:2.2.5" + + kapt "androidx.room:room-compiler:$roomVersion" kapt "androidx.lifecycle:lifecycle-compiler:2.4.0" } From 2225a735ca872151c580dd4f194f715cbc835a8b Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Wed, 29 Mar 2023 12:01:18 +0300 Subject: [PATCH 24/43] Fixed typo --- client/ui/uilogic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 00cc5dd1..cdfd1833 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -476,7 +476,7 @@ void UiLogic::copyToClipboard(const QString &text) { #ifdef Q_OS_ANDROID AndroidController::instance()->copyTextToClipboard(text); -#elif +#else qApp->clipboard()->setText(text); #endif } From 9e461ef6e131d5075b0faeda55366463363999d3 Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Wed, 29 Mar 2023 16:09:46 +0300 Subject: [PATCH 25/43] Fixed import from external applications --- client/android/AndroidManifest.xml | 98 ++++++------ client/android/build.gradle | 6 +- .../res/layout/activity_import_config.xml | 5 + .../amnezia/vpn/qt/ImportConfigActivity.kt | 140 ++++++++++++++++++ .../src/org/amnezia/vpn/qt/VPNActivity.kt | 135 +++++------------ .../platforms/android/android_controller.cpp | 3 +- client/ui/pages_logic/StartPageLogic.cpp | 21 ++- client/ui/pages_logic/StartPageLogic.h | 2 + 8 files changed, 256 insertions(+), 154 deletions(-) create mode 100644 client/android/res/layout/activity_import_config.xml create mode 100644 client/android/src/org/amnezia/vpn/qt/ImportConfigActivity.kt diff --git a/client/android/AndroidManifest.xml b/client/android/AndroidManifest.xml index 22c828fb..be67c8ba 100644 --- a/client/android/AndroidManifest.xml +++ b/client/android/AndroidManifest.xml @@ -51,50 +51,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/android/src/org/amnezia/vpn/qt/ImportConfigActivity.kt b/client/android/src/org/amnezia/vpn/qt/ImportConfigActivity.kt new file mode 100644 index 00000000..de175a98 --- /dev/null +++ b/client/android/src/org/amnezia/vpn/qt/ImportConfigActivity.kt @@ -0,0 +1,140 @@ +package org.amnezia.vpn.qt + +import android.Manifest +import android.app.Activity +import android.content.pm.PackageManager +import android.content.ContentResolver +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.provider.MediaStore +import android.widget.Toast +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat + +import java.io.* + +import org.amnezia.vpn.R + + +const val INTENT_ACTION_IMPORT_CONFIG = "org.amnezia.vpn.qt.IMPORT_CONFIG" + +class ImportConfigActivity : Activity() { + + private val STORAGE_PERMISSION_CODE = 42 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_import_config) + startReadConfig(intent) + } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + startReadConfig(intent) + } + + private fun startMainActivity(config: String?) { + + if (config == null || config.length == 0) { + return + } + + val activityIntent = Intent(applicationContext, VPNActivity::class.java) + activityIntent.action = INTENT_ACTION_IMPORT_CONFIG + activityIntent.addCategory("android.intent.category.DEFAULT") + activityIntent.putExtra("CONFIG", config) + + startActivity(activityIntent) + finish() + } + + private fun startReadConfig(intent: Intent?) { + val newIntent = intent + val newIntentAction: String = newIntent?.action ?: "" + + if (newIntent != null && newIntentAction == Intent.ACTION_VIEW) { + readConfig(newIntent, newIntentAction) + } + } + + private fun readConfig(newIntent: Intent, newIntentAction: String) { + if (isReadStorageAllowed()) { + val configString = processIntent(newIntent, newIntentAction) + startMainActivity(configString) + } else { + requestStoragePermission() + } + } + + private fun requestStoragePermission() { + ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), STORAGE_PERMISSION_CODE) + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + if (requestCode == STORAGE_PERMISSION_CODE) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + val configString = processIntent(intent, intent.action!!) + + if (configString != null) { + startMainActivity(configString) + } + } else { + Toast.makeText(this, "Oops you just denied the permission", Toast.LENGTH_LONG).show() + } + } + } + + private fun processIntent(intent: Intent, action: String): String? { + val scheme = intent.scheme + + if (scheme == null) { + return null + } + + if (action.compareTo(Intent.ACTION_VIEW) == 0) { + val resolver = contentResolver + + if (scheme.compareTo(ContentResolver.SCHEME_CONTENT) == 0) { + val uri = intent.data + val name: String? = getContentName(resolver, uri) + + println("Content intent detected: " + action + " : " + intent.dataString + " : " + intent.type + " : " + name) + + val input = resolver.openInputStream(uri!!) + + return input?.bufferedReader()?.use(BufferedReader::readText) + } else if (scheme.compareTo(ContentResolver.SCHEME_FILE) == 0) { + val uri = intent.data + val name = uri!!.lastPathSegment + + println("File intent detected: " + action + " : " + intent.dataString + " : " + intent.type + " : " + name) + + val input = resolver.openInputStream(uri) + + return input?.bufferedReader()?.use(BufferedReader::readText) + } + } + + return null + } + + private fun isReadStorageAllowed(): Boolean { + val permissionStatus = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) + return permissionStatus == PackageManager.PERMISSION_GRANTED + } + + private fun getContentName(resolver: ContentResolver?, uri: Uri?): String? { + val cursor = resolver!!.query(uri!!, null, null, null, null) + + cursor.use { + cursor!!.moveToFirst() + val nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME) + return if (nameIndex >= 0) { + return cursor.getString(nameIndex) + } else { + null + } + } + } +} \ No newline at end of file diff --git a/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt b/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt index 17888a0d..d2b5b7ab 100644 --- a/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt +++ b/client/android/src/org/amnezia/vpn/qt/VPNActivity.kt @@ -34,15 +34,23 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { private var configString: String? = null private var vpnServiceBinder: IBinder? = null private var isBound = false + set(value) { + field = value + + if (value && configString != null) { + sendImportConfigCommand() + } + } private val TAG = "VPNActivity" - private val STORAGE_PERMISSION_CODE = 42 private val CAMERA_ACTION_CODE = 101 private val CREATE_FILE_ACTION_CODE = 102 private var tmpFileContentToSave: String = "" + private val delayedCommands: ArrayList> = ArrayList() + companion object { private lateinit var instance: VPNActivity @@ -72,16 +80,16 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { } override fun onCreate(savedInstanceState: Bundle?) { - val newIntent = intent - val newIntentAction = newIntent.action - - if (newIntent != null && newIntentAction != null) { - configString = processIntent(newIntent, newIntentAction) - } - super.onCreate(savedInstanceState) instance = this + + val newIntent = intent + val newIntentAction: String? = newIntent.action + + if (newIntent != null && newIntentAction != null && newIntentAction == "org.amnezia.vpn.qt.IMPORT_CONFIG") { + configString = newIntent.getStringExtra("CONFIG") + } } private fun startQrCodeActivity() { @@ -123,9 +131,22 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { private fun dispatchParcel(actionCode: Int, body: String) { if (!isBound) { Log.d(TAG, "dispatchParcel: not bound") + delayedCommands.add(Pair(actionCode, body)) return } + if (delayedCommands.size > 0) { + for (command in delayedCommands) { + processCommand(command.first, command.second) + } + + delayedCommands.clear() + } + + processCommand(actionCode, body) + } + + private fun processCommand(actionCode: Int, body: String) { val out: Parcel = Parcel.obtain() out.writeByteArray(body.toByteArray()) @@ -141,19 +162,15 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { } override fun onNewIntent(newIntent: Intent) { - intent = newIntent + super.onNewIntent(intent) + + setIntent(newIntent) val newIntentAction = newIntent.action - if (newIntent != null && newIntentAction != null && newIntentAction != Intent.ACTION_MAIN) { - if (isReadStorageAllowed()) { - configString = processIntent(newIntent, newIntentAction) - } else { - requestStoragePermission() - } - } - - super.onNewIntent(intent) + if (newIntent != null && newIntentAction != null && newIntentAction == INTENT_ACTION_IMPORT_CONFIG) { + configString = newIntent.getStringExtra("CONFIG") + } } override fun onResume() { @@ -164,84 +181,6 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { } } - private fun isReadStorageAllowed(): Boolean { - val permissionStatus = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) - return permissionStatus == PackageManager.PERMISSION_GRANTED - } - - private fun requestStoragePermission() { - ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), STORAGE_PERMISSION_CODE) - } - - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - if (requestCode == STORAGE_PERMISSION_CODE) { - if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - Log.d(TAG, "Storage read permission granted") - - if (configString == null) { - configString = processIntent(intent, intent.action!!) - } - - if (configString != null) { - Log.d(TAG, "not empty") - sendImportConfigCommand() - } else { - Log.d(TAG, "empty") - } - } else { - Toast.makeText(this, "Oops you just denied the permission", Toast.LENGTH_LONG).show() - } - } - } - - private fun processIntent(intent: Intent, action: String): String? { - val scheme = intent.scheme - - if (scheme == null) { - return null - } - - if (action.compareTo(Intent.ACTION_VIEW) == 0) { - val resolver = contentResolver - - if (scheme.compareTo(ContentResolver.SCHEME_CONTENT) == 0) { - val uri = intent.data - val name: String? = getContentName(resolver, uri) - - Log.d(TAG, "Content intent detected: " + action + " : " + intent.dataString + " : " + intent.type + " : " + name) - - val input = resolver.openInputStream(uri!!) - - return input?.bufferedReader()?.use(BufferedReader::readText) - } else if (scheme.compareTo(ContentResolver.SCHEME_FILE) == 0) { - val uri = intent.data - val name = uri!!.lastPathSegment - - Log.d(TAG, "File intent detected: " + action + " : " + intent.dataString + " : " + intent.type + " : " + name) - - val input = resolver.openInputStream(uri) - - return input?.bufferedReader()?.use(BufferedReader::readText) - } - } - - return null - } - - private fun getContentName(resolver: ContentResolver?, uri: Uri?): String? { - val cursor = resolver!!.query(uri!!, null, null, null, null) - - cursor.use { - cursor!!.moveToFirst() - val nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME) - return if (nameIndex >= 0) { - return cursor.getString(nameIndex) - } else { - null - } - } - } - private fun sendImportConfigCommand() { if (configString != null) { val msg: Parcel = Parcel.obtain() @@ -257,7 +196,7 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { } } - private var connection: ServiceConnection = object : ServiceConnection { + private fun createConnection() = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, binder: IBinder) { vpnServiceBinder = binder @@ -283,6 +222,8 @@ class VPNActivity : org.qtproject.qt.android.bindings.QtActivity() { } } + private var connection: ServiceConnection = createConnection() + private fun registerBinder(): Boolean { val binder = VPNClientBinder() val out: Parcel = Parcel.obtain() diff --git a/client/platforms/android/android_controller.cpp b/client/platforms/android/android_controller.cpp index 3a93ea19..2e5641c9 100644 --- a/client/platforms/android/android_controller.cpp +++ b/client/platforms/android/android_controller.cpp @@ -92,7 +92,6 @@ AndroidController::AndroidController() : QObject() connect(activity, &AndroidVPNActivity::eventStatisticUpdate, this, [this](const QString& parcelBody) { qDebug() << "Transact: update"; - auto doc = QJsonDocument::fromJson(parcelBody.toUtf8()); QString rx = doc.object()["rx_bytes"].toString(); @@ -250,7 +249,7 @@ void AndroidController::cleanupBackendLogs() { } void AndroidController::importConfig(const QString& data){ - m_startPageLogic->importConnectionFromCode(data); + m_startPageLogic->selectConfigFormat(data); } const QJsonObject &AndroidController::vpnConfig() const diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index 8c78667d..7eb67adf 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -175,14 +175,7 @@ void StartPageLogic::onPushButtonImportOpenFile() file.open(QIODevice::ReadOnly); QByteArray data = file.readAll(); - auto configFormat = checkConfigFormat(QString(data)); - if (configFormat == ConfigTypes::OpenVpn) { - importConnectionFromOpenVpnConfig(QString(data)); - } else if (configFormat == ConfigTypes::WireGuard) { - importConnectionFromWireguardConfig(QString(data)); - } else { - importConnectionFromCode(QString(data)); - } + selectConfigFormat(QString(data)); } #ifdef Q_OS_ANDROID @@ -192,6 +185,18 @@ void StartPageLogic::startQrDecoder() } #endif +void StartPageLogic::selectConfigFormat(QString configData) +{ + auto configFormat = checkConfigFormat(configData); + if (configFormat == ConfigTypes::OpenVpn) { + importConnectionFromOpenVpnConfig(configData); + } else if (configFormat == ConfigTypes::WireGuard) { + importConnectionFromWireguardConfig(configData); + } else { + importConnectionFromCode(configData); + } +} + bool StartPageLogic::importConnection(const QJsonObject &profile) { ServerCredentials credentials; diff --git a/client/ui/pages_logic/StartPageLogic.h b/client/ui/pages_logic/StartPageLogic.h index b3dea002..6f21c105 100644 --- a/client/ui/pages_logic/StartPageLogic.h +++ b/client/ui/pages_logic/StartPageLogic.h @@ -35,6 +35,8 @@ public: Q_INVOKABLE void startQrDecoder(); #endif + void selectConfigFormat(QString configData); + bool importConnection(const QJsonObject &profile); bool importConnectionFromCode(QString code); bool importConnectionFromQr(const QByteArray &data); From f3aef67be6ee5338db412a2c15f5a25b6ebf5ec0 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Sun, 2 Apr 2023 09:09:20 +0300 Subject: [PATCH 26/43] Added a form for entering a passphrase for a private ssh key and the corresponding logic for processing a private key --- client/core/defs.h | 1 + client/core/servercontroller.cpp | 9 ++- client/core/servercontroller.h | 3 + client/core/sshclient.cpp | 52 ++++++++++++++-- client/core/sshclient.h | 5 +- client/resources.qrc | 1 + .../ui/qml/Controls/PopupWithInputField.qml | 62 +++++++++++++++++++ client/ui/qml/main.qml | 20 ++++++ client/ui/uilogic.cpp | 11 ++++ client/ui/uilogic.h | 5 +- 10 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 client/ui/qml/Controls/PopupWithInputField.qml diff --git a/client/core/defs.h b/client/core/defs.h index 125c3101..9017fbd3 100644 --- a/client/core/defs.h +++ b/client/core/defs.h @@ -13,6 +13,7 @@ struct ServerCredentials QString hostName; QString userName; QString password; + QString decryptedPrivateKey; int port = 22; bool isValid() const { return !hostName.isEmpty() && !userName.isEmpty() && !password.isEmpty() && port > 0; } diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index 4cf0a2d0..eb9305a2 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -46,7 +46,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr const std::function &cbReadStdOut, const std::function &cbReadStdErr) { - auto error = m_sshClient.connectToHost(credentials); + auto error = m_sshClient.connectToHost(credentials, m_passphraseCallback); if (error != ErrorCode::NoError) { return error; } @@ -221,7 +221,7 @@ ErrorCode ServerController::checkOpenVpnServer(DockerContainer container, const ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath, libssh::SftpOverwriteMode overwriteMode) { - auto error = m_sshClient.connectToHost(credentials); + auto error = m_sshClient.connectToHost(credentials, m_passphraseCallback); if (error != ErrorCode::NoError) { return error; } @@ -754,3 +754,8 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential return ErrorCode::NoError; } + +void ServerController::setPassphraseCallback(const std::function &callback) +{ + m_passphraseCallback = callback; +} diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h index fc16d081..6b1a4793 100644 --- a/client/core/servercontroller.h +++ b/client/core/servercontroller.h @@ -72,6 +72,8 @@ public: void setCancelInstallation(const bool cancel); ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap &installedContainers); + + void setPassphraseCallback(const std::function &callback); private: ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container); ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); @@ -86,6 +88,7 @@ private: bool m_cancelInstallation = false; libssh::Client m_sshClient; + std::function m_passphraseCallback; signals: void serverIsBusy(const bool isBusy); }; diff --git a/client/core/sshclient.cpp b/client/core/sshclient.cpp index bdb396c3..1523257e 100644 --- a/client/core/sshclient.cpp +++ b/client/core/sshclient.cpp @@ -10,18 +10,30 @@ #endif namespace libssh { + std::function Client::m_passphraseCallback; + Client::Client(QObject *parent) : QObject(parent) { } Client::~Client() { } - ErrorCode Client::connectToHost(const ServerCredentials &credentials) + int Client::callback(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata) + { + auto passphrase = m_passphraseCallback(); + passphrase.toStdString().copy(buf, passphrase.size() + 1); + return 0; + } + + ErrorCode Client::connectToHost(const ServerCredentials &credentials, const std::function &passphraseCallback) { // if (is_ssh_initialized()) { // qDebug() << "Failed to initialize ssh"; // return ErrorCode::InternalError; // } + + m_passphraseCallback = passphraseCallback; + if (m_session == nullptr) { m_session = ssh_new(); @@ -52,10 +64,42 @@ namespace libssh { int authResult = SSH_ERROR; if (credentials.password.contains("BEGIN") && credentials.password.contains("PRIVATE KEY")) { ssh_key privateKey; - ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, nullptr, nullptr, &privateKey); + authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey); + if (authResult != SSH_OK) { + qDebug() << ssh_get_error(m_session); + return fromLibsshErrorCode(ssh_get_error_code(m_session)); + } + + ssh_key publicKey; + authResult = ssh_pki_export_privkey_to_pubkey(privateKey, &publicKey); + if (authResult != SSH_OK) { + qDebug() << ssh_get_error(m_session); + return fromLibsshErrorCode(ssh_get_error_code(m_session)); + } + authResult = ssh_userauth_try_publickey(m_session, authUsername.c_str(), publicKey); + if (authResult != SSH_OK) { + qDebug() << ssh_get_error(m_session); + return fromLibsshErrorCode(ssh_get_error_code(m_session)); + } + authResult = ssh_userauth_publickey(m_session, authUsername.c_str(), privateKey); - } - else { + if (authResult != SSH_OK) { + qDebug() << ssh_get_error(m_session); + return fromLibsshErrorCode(ssh_get_error_code(m_session)); + } + + char* key = new char[65535]; + authResult = ssh_pki_export_privkey_base64(privateKey, nullptr, nullptr, nullptr, &key); + if (authResult != SSH_OK) { + qDebug() << ssh_get_error(m_session); + return fromLibsshErrorCode(ssh_get_error_code(m_session)); + } + +// credentials.decryptedPrivateKey(key); + + ssh_key_free(publicKey); + ssh_key_free(privateKey); + } else { authResult = ssh_userauth_password(m_session, authUsername.c_str(), credentials.password.toStdString().c_str()); } diff --git a/client/core/sshclient.h b/client/core/sshclient.h index 912748f0..057c72fe 100644 --- a/client/core/sshclient.h +++ b/client/core/sshclient.h @@ -26,7 +26,7 @@ namespace libssh { Client(QObject *parent = nullptr); ~Client(); - ErrorCode connectToHost(const ServerCredentials &credentials); + ErrorCode connectToHost(const ServerCredentials &credentials, const std::function &passphraseCallback); void disconnectFromHost(); ErrorCode executeCommand(const QString &data, const std::function &cbReadStdOut, @@ -41,10 +41,13 @@ namespace libssh { ErrorCode closeSftpSession(); ErrorCode fromLibsshErrorCode(int errorCode); ErrorCode fromLibsshSftpErrorCode(int errorCode); + static int callback(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata); ssh_session m_session = nullptr; ssh_channel m_channel = nullptr; sftp_session m_sftpSession = nullptr; + + static std::function m_passphraseCallback; signals: void writeToChannelFinished(); void sftpFileCopyFinished(); diff --git a/client/resources.qrc b/client/resources.qrc index 67937bda..ccc6ad68 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -165,5 +165,6 @@ ui/qml/Controls/PopupWithQuestion.qml ui/qml/Pages/PageAdvancedServerSettings.qml ui/qml/Controls/PopupWarning.qml + ui/qml/Controls/PopupWithInputField.qml diff --git a/client/ui/qml/Controls/PopupWithInputField.qml b/client/ui/qml/Controls/PopupWithInputField.qml new file mode 100644 index 00000000..acdf1247 --- /dev/null +++ b/client/ui/qml/Controls/PopupWithInputField.qml @@ -0,0 +1,62 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +Popup { + id: root + + property alias text: textField.text + property alias placeholderText: textField.placeholderText + property string yesText: "yes" + property string noText: "no" + property var yesFunc + property var noFunc + + signal editingFinished() + + anchors.centerIn: Overlay.overlay + modal: true + closePolicy: Popup.NoAutoClose + + width: parent.width - 20 + + ColumnLayout { + width: parent.width + + TextField { + id: textField + horizontalAlignment: Text.AlignHCenter + Layout.fillWidth: true + font.pixelSize: 16 + echoMode: TextInput.Password + } + + RowLayout { + Layout.fillWidth: true + BlueButtonType { + id: yesButton + Layout.preferredWidth: parent.width / 2 + Layout.fillWidth: true + text: yesText + onClicked: { + root.enabled = false + if (yesFunc && typeof yesFunc === "function") { + yesFunc() + } + root.enabled = true + } + } + BlueButtonType { + id: noButton + Layout.preferredWidth: parent.width / 2 + Layout.fillWidth: true + text: noText + onClicked: { + if (noFunc && typeof noFunc === "function") { + noFunc() + } + } + } + } + } +} diff --git a/client/ui/qml/main.qml b/client/ui/qml/main.qml index b8758384..8a23d7a2 100644 --- a/client/ui/qml/main.qml +++ b/client/ui/qml/main.qml @@ -234,6 +234,9 @@ Window { popupWarning.popupWarningText = message popupWarning.open() } + function onShowPassphraseRequestMessage() { + popupWithInputField.open() + } } MessageDialog { @@ -355,4 +358,21 @@ Window { PopupWarning { id: popupWarning } + PopupWithInputField { + id: popupWithInputField + placeholderText: "Enter private key passphrase" + yesFunc: function() { + editingFinished() + close() + UiLogic.passphraseDialogClosed() + text = "" + } + noFunc: function() { + close() + UiLogic.passphraseDialogClosed() + } + onEditingFinished: { + UiLogic.privateKeyPassphrase = text + } + } } diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 895a526c..527dc1a6 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -149,6 +149,16 @@ void UiLogic::initalizeUiLogic() connect(m_notificationHandler, &NotificationHandler::connectRequested, pageLogic(), &VpnLogic::onConnect); connect(m_notificationHandler, &NotificationHandler::disconnectRequested, pageLogic(), &VpnLogic::onDisconnect); + auto passphraseCallback = [this]() { + emit showPassphraseRequestMessage(); + QEventLoop loop; + QObject::connect(this, &UiLogic::passphraseDialogClosed, &loop, &QEventLoop::quit); + loop.exec(); + + return m_privateKeyPassphrase; + }; + m_serverController->setPassphraseCallback(passphraseCallback); + if (m_settings->serversCount() > 0) { if (m_settings->defaultServerIndex() < 0) m_settings->setDefaultServer(0); emit goToPage(Page::Vpn, true, false); @@ -576,3 +586,4 @@ bool UiLogic::isContainerAlreadyAddedToGui(DockerContainer container) } return false; } + diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index 92035fe5..ae7074e6 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -62,7 +62,7 @@ class UiLogic : public QObject AUTO_PROPERTY(bool, pageEnabled) AUTO_PROPERTY(int, pagesStackDepth) AUTO_PROPERTY(int, currentPageValue) - AUTO_PROPERTY(QString, popupWarningText) + AUTO_PROPERTY(QString, privateKeyPassphrase); READONLY_PROPERTY(QObject *, containersModel) READONLY_PROPERTY(QObject *, protocolsModel) @@ -136,6 +136,9 @@ signals: void toggleLogPanel(); void showWarningMessage(QString message); + void showPassphraseRequestMessage(); + void passphraseDialogClosed(); + private slots: // containers - INOUT arg void installServer(QPair &container); From fe9e813c799880cd4d0583aef75030085227a892 Mon Sep 17 00:00:00 2001 From: bakhtiyork Date: Sun, 2 Apr 2023 17:19:21 +0500 Subject: [PATCH 27/43] Custom cmake module path --- client/cmake/3rdparty.cmake | 2 ++ client/cmake/Modules/FindMbedTLS.cmake | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 client/cmake/Modules/FindMbedTLS.cmake diff --git a/client/cmake/3rdparty.cmake b/client/cmake/3rdparty.cmake index a3b460a5..fce24019 100644 --- a/client/cmake/3rdparty.cmake +++ b/client/cmake/3rdparty.cmake @@ -1,5 +1,7 @@ set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Modules;${CMAKE_MODULE_PATH}") + if(NOT IOS AND NOT ANDROID) include(${CLIENT_ROOT_DIR}/3rd/SingleApplication/singleapplication.cmake) endif() diff --git a/client/cmake/Modules/FindMbedTLS.cmake b/client/cmake/Modules/FindMbedTLS.cmake new file mode 100644 index 00000000..35589f17 --- /dev/null +++ b/client/cmake/Modules/FindMbedTLS.cmake @@ -0,0 +1,15 @@ + +set(MBEDTLS_ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}/3rd/mbedtls" CACHE PATH "" FORCE) +set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rd/mbedtls/include" CACHE PATH "" FORCE) +set(MBEDTLS_LIBRARIES "mbedtls" "mbedx509" "mbedcrypto" CACHE STRING "" FORCE) +set(MBEDTLS_FOUND TRUE CACHE BOOL "" FORCE) +set(MBEDTLS_CRYPTO_LIBRARY "mbedcrypto" CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBEDTLS_ALLOW_PRIVATE_ACCESS -DMBEDTLS_THREADING_C -DMBEDTLS_THREADING_PTHREAD") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBEDTLS_ALLOW_PRIVATE_ACCESS -DMBEDTLS_THREADING_C -DMBEDTLS_THREADING_PTHREAD") +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) +set(WITH_STATIC_LIB ON CACHE BOOL "" FORCE) + +include_directories(${MBEDTLS_INCLUDE_DIR}) + +# show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view +mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES) From af5b9172ef0d328ea7bf80b11f293d5d874d0434 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Sun, 2 Apr 2023 15:19:59 +0300 Subject: [PATCH 28/43] removed unused disconnectFromHost() from ServerController --- client/core/servercontroller.cpp | 6 ------ client/core/servercontroller.h | 1 - client/ui/pages_logic/AdvancedServerSettingsLogic.cpp | 1 - client/ui/uilogic.cpp | 3 --- client/vpnconnection.cpp | 2 -- 5 files changed, 13 deletions(-) diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index 132cb18c..67a21bba 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -839,12 +839,6 @@ void ServerController::setCancelInstallation(const bool cancel) m_cancelInstallation = cancel; } -void ServerController::disconnectFromHost(const ServerCredentials &credentials) -{ -// SshConnection *client = acquireConnection(sshParams(credentials)); -// if (client) client->disconnectFromHost(); -} - ErrorCode ServerController::setupServerFirewall(const ServerCredentials &credentials) { return runScript(credentials, diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h index b13f3ebf..68d47417 100644 --- a/client/core/servercontroller.h +++ b/client/core/servercontroller.h @@ -31,7 +31,6 @@ public: ErrorCode fromSshProcessExitStatus(int exitStatus); QSsh::SshConnectionParameters sshParams(const ServerCredentials &credentials); - void disconnectFromHost(const ServerCredentials &credentials); ErrorCode removeAllContainers(const ServerCredentials &credentials); ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container); diff --git a/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp b/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp index 0b02241c..187af9ee 100644 --- a/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp +++ b/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp @@ -45,7 +45,6 @@ void AdvancedServerSettingsLogic::onPushButtonClearServerClicked() } ErrorCode e = m_serverController->removeAllContainers(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex)); - m_serverController->disconnectFromHost(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex)); if (e) { emit uiLogic()->showWarningMessage(tr("Error occurred while cleaning the server.") + "\n" + tr("Error message: ") + errorString(e) + "\n" + diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index cdfd1833..3dbd7b86 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -342,8 +342,6 @@ void UiLogic::installServer(QPair &container) errorCode = pageLogic()->doInstallAction(installAction, pageFunc, progressBarFunc, noButton, waitInfoFunc, busyInfoFunc, cancelButtonFunc); - m_serverController->disconnectFromHost(m_installCredentials); - if (errorCode == ErrorCode::NoError) { if (!isServerCreated) { QJsonObject server; @@ -534,7 +532,6 @@ ErrorCode UiLogic::addAlreadyInstalledContainersGui(bool createNewServer, bool & QMap installedContainers; ErrorCode errorCode = m_serverController->getAlreadyInstalledContainers(credentials, installedContainers); - m_serverController->disconnectFromHost(credentials); if (errorCode != ErrorCode::NoError) { return errorCode; } diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 6d8aa493..21643ae5 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -372,8 +372,6 @@ void VpnConnection::connectToVpn(int serverIndex, createProtocolConnections(); - m_serverController->disconnectFromHost(credentials); - e = m_vpnProtocol.data()->start(); if (e) emit VpnProtocol::Error; } From 5e099f522e9fa91d40f1f7a5f36b939d12c5b5ad Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Mon, 3 Apr 2023 17:27:55 +0300 Subject: [PATCH 29/43] added private key export without password to client config --- client/core/defs.h | 2 +- client/core/errorstrings.cpp | 1 + client/core/servercontroller.cpp | 12 ++- client/core/servercontroller.h | 2 +- client/core/sshclient.cpp | 73 ++++++++++--------- client/core/sshclient.h | 4 +- client/resources.qrc | 2 +- client/ui/pages_logic/StartPageLogic.cpp | 30 +++++--- ...hInputField.qml => PopupWithTextField.qml} | 0 client/ui/qml/main.qml | 6 +- 10 files changed, 76 insertions(+), 56 deletions(-) rename client/ui/qml/Controls/{PopupWithInputField.qml => PopupWithTextField.qml} (100%) diff --git a/client/core/defs.h b/client/core/defs.h index 9017fbd3..257de62f 100644 --- a/client/core/defs.h +++ b/client/core/defs.h @@ -13,7 +13,6 @@ struct ServerCredentials QString hostName; QString userName; QString password; - QString decryptedPrivateKey; int port = 22; bool isValid() const { return !hostName.isEmpty() && !userName.isEmpty() && !password.isEmpty() && port > 0; } @@ -36,6 +35,7 @@ enum ErrorCode // Ssh connection errors SshRequsetDeniedError, SshInterruptedError, SshInternalError, + SshPrivateKeyError, // Ssh sftp errors SshSftpEofError, SshSftpNoSuchFileError, SshSftpPermissionDeniedError, diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp index 871eb61b..8108ff53 100644 --- a/client/core/errorstrings.cpp +++ b/client/core/errorstrings.cpp @@ -21,6 +21,7 @@ QString errorString(ErrorCode code){ case(SshRequsetDeniedError): return QObject::tr("Ssh request was denied"); case(SshInterruptedError): return QObject::tr("Ssh request was interrupted"); case(SshInternalError): return QObject::tr("Ssh internal error"); + case(SshPrivateKeyError): return QObject::tr("Invalid private key or invalid passphrase entered"); // Libssh sftp errors case(SshSftpEofError): return QObject::tr("Sftp error: End-of-file encountered"); diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index eb9305a2..5087e92a 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -46,7 +46,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr const std::function &cbReadStdOut, const std::function &cbReadStdErr) { - auto error = m_sshClient.connectToHost(credentials, m_passphraseCallback); + auto error = m_sshClient.connectToHost(credentials); if (error != ErrorCode::NoError) { return error; } @@ -221,7 +221,7 @@ ErrorCode ServerController::checkOpenVpnServer(DockerContainer container, const ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath, libssh::SftpOverwriteMode overwriteMode) { - auto error = m_sshClient.connectToHost(credentials, m_passphraseCallback); + auto error = m_sshClient.connectToHost(credentials); if (error != ErrorCode::NoError) { return error; } @@ -757,5 +757,11 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential void ServerController::setPassphraseCallback(const std::function &callback) { - m_passphraseCallback = callback; + m_sshClient.setPassphraseCallback(callback); +} + +ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey) +{ + auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey); + return error; } diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h index 6b1a4793..0547cbf0 100644 --- a/client/core/servercontroller.h +++ b/client/core/servercontroller.h @@ -74,6 +74,7 @@ public: ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap &installedContainers); void setPassphraseCallback(const std::function &callback); + ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey); private: ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container); ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); @@ -88,7 +89,6 @@ private: bool m_cancelInstallation = false; libssh::Client m_sshClient; - std::function m_passphraseCallback; signals: void serverIsBusy(const bool isBusy); }; diff --git a/client/core/sshclient.cpp b/client/core/sshclient.cpp index 1523257e..db3ca9f5 100644 --- a/client/core/sshclient.cpp +++ b/client/core/sshclient.cpp @@ -25,15 +25,8 @@ namespace libssh { return 0; } - ErrorCode Client::connectToHost(const ServerCredentials &credentials, const std::function &passphraseCallback) + ErrorCode Client::connectToHost(const ServerCredentials &credentials) { -// if (is_ssh_initialized()) { -// qDebug() << "Failed to initialize ssh"; -// return ErrorCode::InternalError; -// } - - m_passphraseCallback = passphraseCallback; - if (m_session == nullptr) { m_session = ssh_new(); @@ -64,39 +57,20 @@ namespace libssh { int authResult = SSH_ERROR; if (credentials.password.contains("BEGIN") && credentials.password.contains("PRIVATE KEY")) { ssh_key privateKey; - authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey); - if (authResult != SSH_OK) { - qDebug() << ssh_get_error(m_session); - return fromLibsshErrorCode(ssh_get_error_code(m_session)); - } - ssh_key publicKey; - authResult = ssh_pki_export_privkey_to_pubkey(privateKey, &publicKey); - if (authResult != SSH_OK) { - qDebug() << ssh_get_error(m_session); - return fromLibsshErrorCode(ssh_get_error_code(m_session)); - } - authResult = ssh_userauth_try_publickey(m_session, authUsername.c_str(), publicKey); - if (authResult != SSH_OK) { - qDebug() << ssh_get_error(m_session); - return fromLibsshErrorCode(ssh_get_error_code(m_session)); + authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey); + if (authResult == SSH_OK) { + authResult = ssh_pki_export_privkey_to_pubkey(privateKey, &publicKey); } - authResult = ssh_userauth_publickey(m_session, authUsername.c_str(), privateKey); - if (authResult != SSH_OK) { - qDebug() << ssh_get_error(m_session); - return fromLibsshErrorCode(ssh_get_error_code(m_session)); + if (authResult == SSH_OK) { + authResult = ssh_userauth_try_publickey(m_session, authUsername.c_str(), publicKey); } - char* key = new char[65535]; - authResult = ssh_pki_export_privkey_base64(privateKey, nullptr, nullptr, nullptr, &key); - if (authResult != SSH_OK) { - qDebug() << ssh_get_error(m_session); - return fromLibsshErrorCode(ssh_get_error_code(m_session)); + if (authResult == SSH_OK) { + authResult = ssh_userauth_publickey(m_session, authUsername.c_str(), privateKey); } -// credentials.decryptedPrivateKey(key); - ssh_key_free(publicKey); ssh_key_free(privateKey); } else { @@ -363,4 +337,35 @@ namespace libssh { default: return ErrorCode::SshSftpFailureError; } } + + ErrorCode Client::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey) + { + int authResult = SSH_ERROR; + ErrorCode errorCode = ErrorCode::NoError; + + ssh_key privateKey; + authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey); + if (authResult == SSH_OK) { + char* key = new char[65535]; + + authResult = ssh_pki_export_privkey_base64(privateKey, nullptr, nullptr, nullptr, &key); + decryptedPrivateKey = key; + delete[] key; + + if (authResult != SSH_OK) { + qDebug() << "failed to export private key"; + errorCode = ErrorCode::InternalError; + } + } else { + errorCode = ErrorCode::SshPrivateKeyError; + } + + ssh_key_free(privateKey); + return errorCode; + } + + void Client::setPassphraseCallback(const std::function &callback) + { + m_passphraseCallback = callback; + } } diff --git a/client/core/sshclient.h b/client/core/sshclient.h index 057c72fe..25f181b6 100644 --- a/client/core/sshclient.h +++ b/client/core/sshclient.h @@ -26,7 +26,7 @@ namespace libssh { Client(QObject *parent = nullptr); ~Client(); - ErrorCode connectToHost(const ServerCredentials &credentials, const std::function &passphraseCallback); + ErrorCode connectToHost(const ServerCredentials &credentials); void disconnectFromHost(); ErrorCode executeCommand(const QString &data, const std::function &cbReadStdOut, @@ -36,6 +36,8 @@ namespace libssh { const std::string& localPath, const std::string& remotePath, const std::string& fileDesc); + ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey); + void setPassphraseCallback(const std::function &callback); private: ErrorCode closeChannel(); ErrorCode closeSftpSession(); diff --git a/client/resources.qrc b/client/resources.qrc index ccc6ad68..3aa23c64 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -165,6 +165,6 @@ ui/qml/Controls/PopupWithQuestion.qml ui/qml/Pages/PageAdvancedServerSettings.qml ui/qml/Controls/PopupWarning.qml - ui/qml/Controls/PopupWithInputField.qml + ui/qml/Controls/PopupWithTextField.qml diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index 8c78667d..3fdfb29b 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -6,6 +6,7 @@ #include "configurators/vpn_configurator.h" #include "../uilogic.h" #include "utilities.h" +#include "core/servercontroller.h" #include #include @@ -94,8 +95,7 @@ void StartPageLogic::onPushButtonConnect() set_labelWaitInfoText(tr("Please fill in all fields")); return; } - } - else { + } else { if (lineEditIpText().isEmpty() || lineEditLoginText().isEmpty() || lineEditPasswordText().isEmpty() ) { @@ -111,7 +111,7 @@ void StartPageLogic::onPushButtonConnect() serverCredentials.hostName = serverCredentials.hostName.split(":").at(0); } serverCredentials.userName = lineEditLoginText(); - if (pushButtonConnectKeyChecked()){ + if (pushButtonConnectKeyChecked()) { QString key = textEditSshKeyText(); if (key.startsWith("ssh-rsa")) { emit uiLogic()->showPublicKeyWarning(); @@ -123,28 +123,34 @@ void StartPageLogic::onPushButtonConnect() } serverCredentials.password = key; - } - else { + } else { serverCredentials.password = lineEditPasswordText(); } set_pushButtonConnectEnabled(false); set_pushButtonConnectText(tr("Connecting...")); - ErrorCode e = ErrorCode::NoError; + ErrorCode errorCode = ErrorCode::NoError; #ifdef Q_DEBUG //QString output = m_serverController->checkSshConnection(serverCredentials, &e); #else QString output; #endif - bool ok = true; - if (e) { - set_labelWaitInfoVisible(true); - set_labelWaitInfoText(errorString(e)); - ok = false; + if (pushButtonConnectKeyChecked()) { + QString decryptedPrivateKey; + errorCode = uiLogic()->m_serverController->getDecryptedPrivateKey(serverCredentials, decryptedPrivateKey); + if (errorCode == ErrorCode::NoError) { + serverCredentials.password = decryptedPrivateKey; + } } - else { + + bool ok = true; + if (errorCode) { + set_labelWaitInfoVisible(true); + set_labelWaitInfoText(errorString(errorCode)); + ok = false; + } else { if (output.contains("Please login as the user")) { output.replace("\n", ""); set_labelWaitInfoVisible(true); diff --git a/client/ui/qml/Controls/PopupWithInputField.qml b/client/ui/qml/Controls/PopupWithTextField.qml similarity index 100% rename from client/ui/qml/Controls/PopupWithInputField.qml rename to client/ui/qml/Controls/PopupWithTextField.qml diff --git a/client/ui/qml/main.qml b/client/ui/qml/main.qml index 8a23d7a2..dfa33e5a 100644 --- a/client/ui/qml/main.qml +++ b/client/ui/qml/main.qml @@ -235,7 +235,7 @@ Window { popupWarning.open() } function onShowPassphraseRequestMessage() { - popupWithInputField.open() + popupWithTextField.open() } } @@ -358,8 +358,8 @@ Window { PopupWarning { id: popupWarning } - PopupWithInputField { - id: popupWithInputField + PopupWithTextField { + id: popupWithTextField placeholderText: "Enter private key passphrase" yesFunc: function() { editingFinished() From 1aa859b10ddc1007cd73e4b68a86d4441f8683c9 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Tue, 4 Apr 2023 07:09:30 +0300 Subject: [PATCH 30/43] moved passphraseCallback and passphraseDialog to startPage - made some methods of the servercontroller class private - returned a call to the checkSshConnection() function --- client/core/servercontroller.cpp | 16 -------- client/core/servercontroller.h | 37 +++++++------------ client/ui/pages_logic/StartPageLogic.cpp | 20 +++++++--- client/ui/pages_logic/StartPageLogic.h | 5 +++ .../protocols/ShadowSocksLogic.cpp | 14 +++---- client/ui/qml/Pages/PageStart.qml | 26 +++++++++++++ client/ui/qml/main.qml | 20 ---------- client/ui/uilogic.cpp | 10 ----- client/ui/uilogic.h | 4 -- 9 files changed, 66 insertions(+), 86 deletions(-) diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index 5087e92a..03ecf86d 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -92,7 +92,6 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr return ErrorCode::NoError; } - ErrorCode ServerController::runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script, const std::function &cbReadStdOut, @@ -203,21 +202,6 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container, return QByteArray::fromHex(stdOut.toUtf8()); } -ErrorCode ServerController::checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials) -{ - QString caCert = ServerController::getTextFileFromContainer(container, - credentials, protocols::openvpn::caCertPath); - QString taKey = ServerController::getTextFileFromContainer(container, - credentials, protocols::openvpn::taKeyPath); - - if (!caCert.isEmpty() && !taKey.isEmpty()) { - return ErrorCode::NoError; - } - else { - return ErrorCode::ServerCheckFailed; - } -} - ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath, libssh::SftpOverwriteMode overwriteMode) { diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h index 0547cbf0..99ae3cd6 100644 --- a/client/core/servercontroller.h +++ b/client/core/servercontroller.h @@ -22,12 +22,6 @@ public: typedef QList> Vars; -// ErrorCode fromSshConnectionErrorCode(QSsh::SshError error); - - // QSsh exitCode and exitStatus are different things -// ErrorCode fromSshProcessExitStatus(int exitStatus); - -// QSsh::SshConnectionParameters sshParams(const ServerCredentials &credentials); void disconnectFromHost(const ServerCredentials &credentials); ErrorCode removeAllContainers(const ServerCredentials &credentials); @@ -36,27 +30,20 @@ public: QJsonObject &config, bool isUpdate = false); ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &oldConfig, QJsonObject &newConfig); + ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap &installedContainers); // create initial config - generate passwords, etc QJsonObject createContainerInitialConfig(DockerContainer container, int port, TransportProto tp); - bool isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig); + ErrorCode uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials, + const QString &file, const QString &path, + libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting); - ErrorCode checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials); - - ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, - const QString &remotePath, libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting); - - ErrorCode uploadTextFileToContainer(DockerContainer container, - const ServerCredentials &credentials, const QString &file, const QString &path, - libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting); - - QByteArray getTextFileFromContainer(DockerContainer container, - const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode = nullptr); - - ErrorCode setupServerFirewall(const ServerCredentials &credentials); + QByteArray getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials, + const QString &path, ErrorCode *errorCode = nullptr); QString replaceVars(const QString &script, const Vars &vars); + Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject()); ErrorCode runScript(const ServerCredentials &credentials, QString script, const std::function &cbReadStdOut = nullptr, @@ -66,12 +53,9 @@ public: const std::function &cbReadStdOut = nullptr, const std::function &cbReadStdErr = nullptr); - Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject()); - QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr); void setCancelInstallation(const bool cancel); - ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap &installedContainers); void setPassphraseCallback(const std::function &callback); ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey); @@ -82,7 +66,14 @@ private: ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config); ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config); ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); + ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config); + bool isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig); + + ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, + const QString &remotePath, libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting); + + ErrorCode setupServerFirewall(const ServerCredentials &credentials); std::shared_ptr m_settings; std::shared_ptr m_configurator; diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index 8873f11d..cddd6d40 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -10,6 +10,7 @@ #include #include +#include #ifdef Q_OS_ANDROID #include @@ -131,11 +132,20 @@ void StartPageLogic::onPushButtonConnect() set_pushButtonConnectText(tr("Connecting...")); ErrorCode errorCode = ErrorCode::NoError; -#ifdef Q_DEBUG - //QString output = m_serverController->checkSshConnection(serverCredentials, &e); -#else - QString output; -#endif + + if (pushButtonConnectKeyChecked()) { + auto passphraseCallback = [this]() { + emit showPassphraseRequestMessage(); + QEventLoop loop; + QObject::connect(this, &StartPageLogic::passphraseDialogClosed, &loop, &QEventLoop::quit); + loop.exec(); + + return m_privateKeyPassphrase; + }; + m_serverController->setPassphraseCallback(passphraseCallback); + } + + QString output = m_serverController->checkSshConnection(serverCredentials, &errorCode); if (pushButtonConnectKeyChecked()) { QString decryptedPrivateKey; diff --git a/client/ui/pages_logic/StartPageLogic.h b/client/ui/pages_logic/StartPageLogic.h index 6f21c105..a20fd6c7 100644 --- a/client/ui/pages_logic/StartPageLogic.h +++ b/client/ui/pages_logic/StartPageLogic.h @@ -23,6 +23,8 @@ class StartPageLogic : public PageLogicBase AUTO_PROPERTY(QString, labelWaitInfoText) AUTO_PROPERTY(bool, pushButtonBackFromStartVisible) + AUTO_PROPERTY(QString, privateKeyPassphrase); + READONLY_PROPERTY(QRegularExpression, ipAddressPortRegex) public: Q_INVOKABLE void onUpdatePage() override; @@ -47,5 +49,8 @@ public: explicit StartPageLogic(UiLogic *uiLogic, QObject *parent = nullptr); ~StartPageLogic() = default; +signals: + void showPassphraseRequestMessage(); + void passphraseDialogClosed(); }; #endif // START_PAGE_LOGIC_H diff --git a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp index 5259a6e0..708073a6 100644 --- a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp +++ b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp @@ -104,15 +104,13 @@ void ShadowSocksLogic::onPushButtonSaveClicked() progressBarFunc.setTextVisibleFunc(true); progressBarFunc.setTextFunc(QString("Configuring...")); - ErrorCode e = uiLogic()->pageLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ + auto installAction = [this, containerConfig, &newContainerConfig]() { return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), - uiLogic()->m_selectedDockerContainer, - containerConfig, - newContainerConfig); - }, - pageFunc, progressBarFunc, - saveButtonFunc, waitInfoFunc, - busyInfoFuncy, cancelButtonFunc); + uiLogic()->m_selectedDockerContainer, containerConfig, newContainerConfig); + }; + ErrorCode e = uiLogic()->pageLogic()->doInstallAction(installAction, pageFunc, progressBarFunc, + saveButtonFunc, waitInfoFunc, + busyInfoFuncy, cancelButtonFunc); if (!e) { m_settings->setContainerConfig(uiLogic()->m_selectedServerIndex, uiLogic()->m_selectedDockerContainer, newContainerConfig); diff --git a/client/ui/qml/Pages/PageStart.qml b/client/ui/qml/Pages/PageStart.qml index eacb607d..85c63b4d 100644 --- a/client/ui/qml/Pages/PageStart.qml +++ b/client/ui/qml/Pages/PageStart.qml @@ -10,6 +10,14 @@ PageBase { page: PageEnum.Start logic: StartPageLogic + Connections { + target: StartPageLogic + + function onShowPassphraseRequestMessage() { + popupWithTextField.open() + } + } + BackButton { id: back_from_start visible: pageLoader.depth > 1 @@ -325,4 +333,22 @@ PageBase { } } } + + PopupWithTextField { + id: popupWithTextField + placeholderText: "Enter private key passphrase" + yesFunc: function() { + editingFinished() + close() + StartPageLogic.passphraseDialogClosed() + text = "" + } + noFunc: function() { + close() + StartPageLogic.passphraseDialogClosed() + } + onEditingFinished: { + StartPageLogic.privateKeyPassphrase = text + } + } } diff --git a/client/ui/qml/main.qml b/client/ui/qml/main.qml index 5439ad8e..d91c013f 100644 --- a/client/ui/qml/main.qml +++ b/client/ui/qml/main.qml @@ -238,9 +238,6 @@ Window { popupWarning.popupWarningText = message popupWarning.open() } - function onShowPassphraseRequestMessage() { - popupWithTextField.open() - } } MessageDialog { @@ -362,21 +359,4 @@ Window { PopupWarning { id: popupWarning } - PopupWithTextField { - id: popupWithTextField - placeholderText: "Enter private key passphrase" - yesFunc: function() { - editingFinished() - close() - UiLogic.passphraseDialogClosed() - text = "" - } - noFunc: function() { - close() - UiLogic.passphraseDialogClosed() - } - onEditingFinished: { - UiLogic.privateKeyPassphrase = text - } - } } diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 5a541b42..2b66d6c9 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -150,16 +150,6 @@ void UiLogic::initalizeUiLogic() connect(m_notificationHandler, &NotificationHandler::connectRequested, pageLogic(), &VpnLogic::onConnect); connect(m_notificationHandler, &NotificationHandler::disconnectRequested, pageLogic(), &VpnLogic::onDisconnect); - auto passphraseCallback = [this]() { - emit showPassphraseRequestMessage(); - QEventLoop loop; - QObject::connect(this, &UiLogic::passphraseDialogClosed, &loop, &QEventLoop::quit); - loop.exec(); - - return m_privateKeyPassphrase; - }; - m_serverController->setPassphraseCallback(passphraseCallback); - if (m_settings->serversCount() > 0) { if (m_settings->defaultServerIndex() < 0) m_settings->setDefaultServer(0); emit goToPage(Page::Vpn, true, false); diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index ae7074e6..3a5559f2 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -62,7 +62,6 @@ class UiLogic : public QObject AUTO_PROPERTY(bool, pageEnabled) AUTO_PROPERTY(int, pagesStackDepth) AUTO_PROPERTY(int, currentPageValue) - AUTO_PROPERTY(QString, privateKeyPassphrase); READONLY_PROPERTY(QObject *, containersModel) READONLY_PROPERTY(QObject *, protocolsModel) @@ -136,9 +135,6 @@ signals: void toggleLogPanel(); void showWarningMessage(QString message); - void showPassphraseRequestMessage(); - void passphraseDialogClosed(); - private slots: // containers - INOUT arg void installServer(QPair &container); From a005ed2a84d9ca6c5dff83877e82620598a0fece Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Tue, 4 Apr 2023 10:22:25 +0300 Subject: [PATCH 31/43] now an instance of the serverController class is created at the place of use --- client/amnezia_application.cpp | 5 ++-- client/amnezia_application.h | 1 - client/configurators/cloak_configurator.cpp | 13 +++++----- client/configurators/cloak_configurator.h | 3 +-- client/configurators/configurator_base.cpp | 6 ++--- client/configurators/configurator_base.h | 6 +---- client/configurators/ikev2_configurator.cpp | 13 +++++----- client/configurators/ikev2_configurator.h | 3 +-- client/configurators/openvpn_configurator.cpp | 23 ++++++++++-------- client/configurators/openvpn_configurator.h | 3 +-- .../shadowsocks_configurator.cpp | 13 +++++----- .../configurators/shadowsocks_configurator.h | 3 +-- client/configurators/ssh_configurator.cpp | 4 ++-- client/configurators/ssh_configurator.h | 3 +-- client/configurators/vpn_configurator.cpp | 17 +++++++------ client/configurators/vpn_configurator.h | 5 +--- .../configurators/wireguard_configurator.cpp | 24 ++++++++++--------- client/configurators/wireguard_configurator.h | 3 +-- client/core/servercontroller.cpp | 6 +---- client/core/servercontroller.h | 2 -- .../AdvancedServerSettingsLogic.cpp | 7 +++--- client/ui/pages_logic/PageLogicBase.cpp | 1 - client/ui/pages_logic/PageLogicBase.h | 1 - .../ServerConfiguringProgressLogic.cpp | 15 ++++++------ .../ui/pages_logic/ServerContainersLogic.cpp | 9 ++++--- client/ui/pages_logic/StartPageLogic.cpp | 9 +++---- .../ui/pages_logic/protocols/CloakLogic.cpp | 19 ++++++++------- .../ui/pages_logic/protocols/OpenVpnLogic.cpp | 19 ++++++++------- .../protocols/ShadowSocksLogic.cpp | 4 +++- client/ui/uilogic.cpp | 12 +++++----- client/ui/uilogic.h | 4 +--- client/vpnconnection.cpp | 4 +--- client/vpnconnection.h | 4 +--- 33 files changed, 125 insertions(+), 139 deletions(-) diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 588854d3..891c305a 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -68,8 +68,7 @@ #endif m_settings = std::shared_ptr(new Settings); - m_serverController = std::shared_ptr(new ServerController(m_settings, this)); - m_configurator = std::shared_ptr(new VpnConfigurator(m_settings, m_serverController, this)); + m_configurator = std::shared_ptr(new VpnConfigurator(m_settings, this)); } AmneziaApplication::~AmneziaApplication() @@ -90,7 +89,7 @@ AmneziaApplication::~AmneziaApplication() void AmneziaApplication::init() { m_engine = new QQmlApplicationEngine; - m_uiLogic = new UiLogic(m_settings, m_configurator, m_serverController); + m_uiLogic = new UiLogic(m_settings, m_configurator); const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml")); QObject::connect(m_engine, &QQmlApplicationEngine::objectCreated, diff --git a/client/amnezia_application.h b/client/amnezia_application.h index f0f8f529..1ac6e772 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -49,7 +49,6 @@ private: UiLogic *m_uiLogic {}; std::shared_ptr m_settings; std::shared_ptr m_configurator; - std::shared_ptr m_serverController; ContainerProps* m_containerProps {}; ProtocolProps* m_protocolProps {}; diff --git a/client/configurators/cloak_configurator.cpp b/client/configurators/cloak_configurator.cpp index 0cfd74fc..6206d141 100644 --- a/client/configurators/cloak_configurator.cpp +++ b/client/configurators/cloak_configurator.cpp @@ -7,8 +7,8 @@ #include "core/servercontroller.h" #include "containers/containers_defs.h" -CloakConfigurator::CloakConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): - ConfiguratorBase(settings, serverController, parent) +CloakConfigurator::CloakConfigurator(std::shared_ptr settings, QObject *parent): + ConfiguratorBase(settings, parent) { } @@ -17,12 +17,13 @@ QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) { ErrorCode e = ErrorCode::NoError; + ServerController serverController(m_settings); - QString cloakPublicKey = m_serverController->getTextFileFromContainer(container, credentials, + QString cloakPublicKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::cloak::ckPublicKeyPath, &e); cloakPublicKey.replace("\n", ""); - QString cloakBypassUid = m_serverController->getTextFileFromContainer(container, credentials, + QString cloakBypassUid = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::cloak::ckBypassUidKeyPath, &e); cloakBypassUid.replace("\n", ""); @@ -47,8 +48,8 @@ QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials, config.insert(config_key::remote, credentials.hostName); config.insert(config_key::port, "$CLOAK_SERVER_PORT"); - QString textCfg = m_serverController->replaceVars(QJsonDocument(config).toJson(), - m_serverController->genVarsForScript(credentials, container, containerConfig)); + QString textCfg = serverController.replaceVars(QJsonDocument(config).toJson(), + serverController.genVarsForScript(credentials, container, containerConfig)); // qDebug().noquote() << textCfg; return textCfg; diff --git a/client/configurators/cloak_configurator.h b/client/configurators/cloak_configurator.h index c6184805..cf6cd002 100644 --- a/client/configurators/cloak_configurator.h +++ b/client/configurators/cloak_configurator.h @@ -11,8 +11,7 @@ class CloakConfigurator : ConfiguratorBase { Q_OBJECT public: - CloakConfigurator(std::shared_ptr settings, - std::shared_ptr serverController, QObject *parent = nullptr); + CloakConfigurator(std::shared_ptr settings, QObject *parent = nullptr); QString genCloakConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); diff --git a/client/configurators/configurator_base.cpp b/client/configurators/configurator_base.cpp index 44377401..c24d7e1f 100644 --- a/client/configurators/configurator_base.cpp +++ b/client/configurators/configurator_base.cpp @@ -1,10 +1,8 @@ #include "configurator_base.h" -ConfiguratorBase::ConfiguratorBase(std::shared_ptr settings, - std::shared_ptr serverController, QObject *parent) +ConfiguratorBase::ConfiguratorBase(std::shared_ptr settings, QObject *parent) : QObject{parent}, - m_settings(settings), - m_serverController(serverController) + m_settings(settings) { } diff --git a/client/configurators/configurator_base.h b/client/configurators/configurator_base.h index 8c0614d9..da43a2bc 100644 --- a/client/configurators/configurator_base.h +++ b/client/configurators/configurator_base.h @@ -4,7 +4,6 @@ #include class Settings; -class ServerController; #include "containers/containers_defs.h" #include "core/defs.h" @@ -13,13 +12,10 @@ class ConfiguratorBase : public QObject { Q_OBJECT public: - explicit ConfiguratorBase(std::shared_ptr settings, - std::shared_ptr serverController, QObject *parent = nullptr); + explicit ConfiguratorBase(std::shared_ptr settings, QObject *parent = nullptr); protected: std::shared_ptr m_settings; - std::shared_ptr m_serverController; - }; #endif // CONFIGURATORBASE_H diff --git a/client/configurators/ikev2_configurator.cpp b/client/configurators/ikev2_configurator.cpp index 9b702824..7ed83da1 100644 --- a/client/configurators/ikev2_configurator.cpp +++ b/client/configurators/ikev2_configurator.cpp @@ -15,8 +15,8 @@ #include "core/servercontroller.h" -Ikev2Configurator::Ikev2Configurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): - ConfiguratorBase(settings, serverController, parent) +Ikev2Configurator::Ikev2Configurator(std::shared_ptr settings, QObject *parent): + ConfiguratorBase(settings, parent) { } @@ -41,16 +41,17 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se "--extKeyUsage serverAuth,clientAuth -8 \"%1\"") .arg(connData.clientId); - ErrorCode e = m_serverController->runContainerScript(credentials, container, scriptCreateCert); + ServerController serverController(m_settings); + ErrorCode e = serverController.runContainerScript(credentials, container, scriptCreateCert); QString scriptExportCert = QString("pk12util -W \"%1\" -d sql:/etc/ipsec.d -n \"%2\" -o \"%3\"") .arg(connData.password) .arg(connData.clientId) .arg(certFileName); - e = m_serverController->runContainerScript(credentials, container, scriptExportCert); + e = serverController.runContainerScript(credentials, container, scriptExportCert); - connData.clientCert = m_serverController->getTextFileFromContainer(container, credentials, certFileName, &e); - connData.caCert = m_serverController->getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e); + connData.clientCert = serverController.getTextFileFromContainer(container, credentials, certFileName, &e); + connData.caCert = serverController.getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e); qDebug() << "Ikev2Configurator::ConnectionData client cert size:" << connData.clientCert.size(); qDebug() << "Ikev2Configurator::ConnectionData ca cert size:" << connData.caCert.size(); diff --git a/client/configurators/ikev2_configurator.h b/client/configurators/ikev2_configurator.h index 35c03b19..a7d379f2 100644 --- a/client/configurators/ikev2_configurator.h +++ b/client/configurators/ikev2_configurator.h @@ -11,8 +11,7 @@ class Ikev2Configurator : ConfiguratorBase { Q_OBJECT public: - Ikev2Configurator(std::shared_ptr settings, - std::shared_ptr serverController, QObject *parent = nullptr); + Ikev2Configurator(std::shared_ptr settings, QObject *parent = nullptr); struct ConnectionData { QByteArray clientCert; // p12 client cert diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index 0ef6da0a..456aeb4d 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -19,8 +19,8 @@ #include #include -OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): - ConfiguratorBase(settings, serverController, parent) +OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr settings, QObject *parent): + ConfiguratorBase(settings, parent) { } @@ -40,7 +40,8 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co arg(amnezia::protocols::openvpn::clientsDirPath). arg(connData.clientId); - ErrorCode e = m_serverController->uploadTextFileToContainer(container, credentials, connData.request, reqFileName); + ServerController serverController(m_settings); + ErrorCode e = serverController.uploadTextFileToContainer(container, credentials, connData.request, reqFileName); if (e) { if (errorCode) *errorCode = e; return connData; @@ -52,8 +53,8 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co return connData; } - connData.caCert = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::caCertPath, &e); - connData.clientCert = m_serverController->getTextFileFromContainer(container, credentials, + connData.caCert = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::caCertPath, &e); + connData.clientCert = serverController.getTextFileFromContainer(container, credentials, QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath).arg(connData.clientId), &e); if (e) { @@ -61,7 +62,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co return connData; } - connData.taKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::taKeyPath, &e); + connData.taKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::taKeyPath, &e); if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) { if (errorCode) *errorCode = ErrorCode::SshSftpFailureError; @@ -73,8 +74,9 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) { - QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container), - m_serverController->genVarsForScript(credentials, container, containerConfig)); + ServerController serverController(m_settings); + QString config = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container), + serverController.genVarsForScript(credentials, container, containerConfig)); ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode); if (errorCode && *errorCode) { @@ -163,10 +165,11 @@ ErrorCode OpenVpnConfigurator::signCert(DockerContainer container, .arg(ContainerProps::containerToString(container)) .arg(clientId); + ServerController serverController(m_settings); QStringList scriptList {script_import, script_sign}; - QString script = m_serverController->replaceVars(scriptList.join("\n"), m_serverController->genVarsForScript(credentials, container)); + QString script = serverController.replaceVars(scriptList.join("\n"), serverController.genVarsForScript(credentials, container)); - return m_serverController->runScript(credentials, script); + return serverController.runScript(credentials, script); } OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest() diff --git a/client/configurators/openvpn_configurator.h b/client/configurators/openvpn_configurator.h index 25230499..3b84e0a0 100644 --- a/client/configurators/openvpn_configurator.h +++ b/client/configurators/openvpn_configurator.h @@ -11,8 +11,7 @@ class OpenVpnConfigurator : ConfiguratorBase { Q_OBJECT public: - OpenVpnConfigurator(std::shared_ptr settings, - std::shared_ptr serverController, QObject *parent = nullptr); + OpenVpnConfigurator(std::shared_ptr settings, QObject *parent = nullptr); struct ConnectionData { QString clientId; diff --git a/client/configurators/shadowsocks_configurator.cpp b/client/configurators/shadowsocks_configurator.cpp index 97503ac4..a71064c8 100644 --- a/client/configurators/shadowsocks_configurator.cpp +++ b/client/configurators/shadowsocks_configurator.cpp @@ -7,8 +7,8 @@ #include "containers/containers_defs.h" #include "core/servercontroller.h" -ShadowSocksConfigurator::ShadowSocksConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): - ConfiguratorBase(settings, serverController, parent) +ShadowSocksConfigurator::ShadowSocksConfigurator(std::shared_ptr settings, QObject *parent): + ConfiguratorBase(settings, parent) { } @@ -17,9 +17,10 @@ QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &c DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) { ErrorCode e = ErrorCode::NoError; + ServerController serverController(m_settings); - QString ssKey = m_serverController->getTextFileFromContainer(container, credentials, - amnezia::protocols::shadowsocks::ssKeyPath, &e); + QString ssKey = serverController.getTextFileFromContainer(container, credentials, + amnezia::protocols::shadowsocks::ssKeyPath, &e); ssKey.replace("\n", ""); if (e) { @@ -36,8 +37,8 @@ QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &c config.insert("method", "$SHADOWSOCKS_CIPHER"); - QString textCfg = m_serverController->replaceVars(QJsonDocument(config).toJson(), - m_serverController->genVarsForScript(credentials, container, containerConfig)); + QString textCfg = serverController.replaceVars(QJsonDocument(config).toJson(), + serverController.genVarsForScript(credentials, container, containerConfig)); //qDebug().noquote() << textCfg; return textCfg; diff --git a/client/configurators/shadowsocks_configurator.h b/client/configurators/shadowsocks_configurator.h index be80f169..b03149eb 100644 --- a/client/configurators/shadowsocks_configurator.h +++ b/client/configurators/shadowsocks_configurator.h @@ -10,8 +10,7 @@ class ShadowSocksConfigurator : ConfiguratorBase { Q_OBJECT public: - ShadowSocksConfigurator(std::shared_ptr settings, - std::shared_ptr serverController, QObject *parent = nullptr); + ShadowSocksConfigurator(std::shared_ptr settings, QObject *parent = nullptr); QString genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); diff --git a/client/configurators/ssh_configurator.cpp b/client/configurators/ssh_configurator.cpp index 725f6ead..e1435bc3 100644 --- a/client/configurators/ssh_configurator.cpp +++ b/client/configurators/ssh_configurator.cpp @@ -15,8 +15,8 @@ #include "utilities.h" -SshConfigurator::SshConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): - ConfiguratorBase(settings, serverController, parent) +SshConfigurator::SshConfigurator(std::shared_ptr settings, QObject *parent): + ConfiguratorBase(settings, parent) { } diff --git a/client/configurators/ssh_configurator.h b/client/configurators/ssh_configurator.h index d7a177c3..2f8cb550 100644 --- a/client/configurators/ssh_configurator.h +++ b/client/configurators/ssh_configurator.h @@ -11,8 +11,7 @@ class SshConfigurator : ConfiguratorBase { Q_OBJECT public: - SshConfigurator(std::shared_ptr settings, - std::shared_ptr serverController, QObject *parent = nullptr); + SshConfigurator(std::shared_ptr settings, QObject *parent = nullptr); QProcessEnvironment prepareEnv(); QString convertOpenSShKey(const QString &key); diff --git a/client/configurators/vpn_configurator.cpp b/client/configurators/vpn_configurator.cpp index 1433eeaa..ceb6a5a4 100644 --- a/client/configurators/vpn_configurator.cpp +++ b/client/configurators/vpn_configurator.cpp @@ -14,16 +14,15 @@ #include "utilities.h" #include "settings.h" -VpnConfigurator::VpnConfigurator(std::shared_ptr settings, - std::shared_ptr serverController, QObject *parent): - ConfiguratorBase(settings, serverController, parent) +VpnConfigurator::VpnConfigurator(std::shared_ptr settings, QObject *parent): + ConfiguratorBase(settings, parent) { - openVpnConfigurator = std::shared_ptr(new OpenVpnConfigurator(settings, serverController, this)); - shadowSocksConfigurator = std::shared_ptr(new ShadowSocksConfigurator(settings, serverController, this)); - cloakConfigurator = std::shared_ptr(new CloakConfigurator(settings, serverController, this)); - wireguardConfigurator = std::shared_ptr(new WireguardConfigurator(settings, serverController, this)); - ikev2Configurator = std::shared_ptr(new Ikev2Configurator(settings, serverController, this)); - sshConfigurator = std::shared_ptr(new SshConfigurator(settings, serverController, this)); + openVpnConfigurator = std::shared_ptr(new OpenVpnConfigurator(settings, this)); + shadowSocksConfigurator = std::shared_ptr(new ShadowSocksConfigurator(settings, this)); + cloakConfigurator = std::shared_ptr(new CloakConfigurator(settings, this)); + wireguardConfigurator = std::shared_ptr(new WireguardConfigurator(settings, this)); + ikev2Configurator = std::shared_ptr(new Ikev2Configurator(settings, this)); + sshConfigurator = std::shared_ptr(new SshConfigurator(settings, this)); } QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, diff --git a/client/configurators/vpn_configurator.h b/client/configurators/vpn_configurator.h index 47bdc1fd..5d0fcfee 100644 --- a/client/configurators/vpn_configurator.h +++ b/client/configurators/vpn_configurator.h @@ -19,8 +19,7 @@ class VpnConfigurator : ConfiguratorBase { Q_OBJECT public: - VpnConfigurator(std::shared_ptr settings, - std::shared_ptr serverController, QObject *parent = nullptr); + VpnConfigurator(std::shared_ptr settings, QObject *parent = nullptr); QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr); @@ -35,8 +34,6 @@ public: void updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig, const QString &stdOut); - std::shared_ptr m_serverController; - std::shared_ptr openVpnConfigurator; std::shared_ptr shadowSocksConfigurator; std::shared_ptr cloakConfigurator; diff --git a/client/configurators/wireguard_configurator.cpp b/client/configurators/wireguard_configurator.cpp index 4c22dc62..f7ab1657 100644 --- a/client/configurators/wireguard_configurator.cpp +++ b/client/configurators/wireguard_configurator.cpp @@ -21,8 +21,8 @@ #include "core/servercontroller.h" #include "settings.h" -WireguardConfigurator::WireguardConfigurator(std::shared_ptr settings, std::shared_ptr serverController, QObject *parent): - ConfiguratorBase(settings, serverController, parent) +WireguardConfigurator::WireguardConfigurator(std::shared_ptr settings, QObject *parent): + ConfiguratorBase(settings, parent) { } @@ -70,6 +70,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon } ErrorCode e = ErrorCode::NoError; + ServerController serverController(m_settings); // Get list of already created clients (only IP addreses) QString nextIpNumber; @@ -81,7 +82,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon return ErrorCode::NoError; }; - e = m_serverController->runContainerScript(credentials, container, script, cbReadStdOut); + e = serverController.runContainerScript(credentials, container, script, cbReadStdOut); if (errorCode && e) { *errorCode = e; return connData; @@ -119,14 +120,14 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon } // Get keys - connData.serverPubKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e); + connData.serverPubKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e); connData.serverPubKey.replace("\n", ""); if (e) { if (errorCode) *errorCode = e; return connData; } - connData.pskKey = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPskKeyPath, &e); + connData.pskKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPskKeyPath, &e); connData.pskKey.replace("\n", ""); if (e) { @@ -144,7 +145,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon arg(connData.pskKey). arg(connData.clientIP); - e = m_serverController->uploadTextFileToContainer(container, credentials, configPart, + e = serverController.uploadTextFileToContainer(container, credentials, configPart, protocols::wireguard::serverConfigPath, libssh::SftpOverwriteMode::SftpAppendToExisting); if (e) { @@ -152,9 +153,9 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon return connData; } - e = m_serverController->runScript(credentials, - m_serverController->replaceVars("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip /opt/amnezia/wireguard/wg0.conf)'", - m_serverController->genVarsForScript(credentials, container))); + e = serverController.runScript(credentials, + serverController.replaceVars("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip /opt/amnezia/wireguard/wg0.conf)'", + serverController.genVarsForScript(credentials, container))); return connData; } @@ -162,8 +163,9 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) { - QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container), - m_serverController->genVarsForScript(credentials, container, containerConfig)); + ServerController serverController(m_settings); + QString config = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container), + serverController.genVarsForScript(credentials, container, containerConfig)); ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode); if (errorCode && *errorCode) { diff --git a/client/configurators/wireguard_configurator.h b/client/configurators/wireguard_configurator.h index 76790d74..ab903d29 100644 --- a/client/configurators/wireguard_configurator.h +++ b/client/configurators/wireguard_configurator.h @@ -11,8 +11,7 @@ class WireguardConfigurator : ConfiguratorBase { Q_OBJECT public: - WireguardConfigurator(std::shared_ptr settings, - std::shared_ptr serverController, QObject *parent = nullptr); + WireguardConfigurator(std::shared_ptr settings, QObject *parent = nullptr); struct ConnectionData { QString clientPrivKey; // client private key diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index 03ecf86d..0963f0e1 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -39,6 +39,7 @@ ServerController::ServerController(std::shared_ptr settings, QObject * ServerController::~ServerController() { + m_sshClient.disconnectFromHost(); } @@ -629,11 +630,6 @@ void ServerController::setCancelInstallation(const bool cancel) m_cancelInstallation = cancel; } -void ServerController::disconnectFromHost(const ServerCredentials &credentials) -{ - m_sshClient.disconnectFromHost(); -} - ErrorCode ServerController::setupServerFirewall(const ServerCredentials &credentials) { return runScript(credentials, diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h index 99ae3cd6..431104e7 100644 --- a/client/core/servercontroller.h +++ b/client/core/servercontroller.h @@ -22,8 +22,6 @@ public: typedef QList> Vars; - void disconnectFromHost(const ServerCredentials &credentials); - ErrorCode removeAllContainers(const ServerCredentials &credentials); ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container); ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, diff --git a/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp b/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp index 187af9ee..71d9567e 100644 --- a/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp +++ b/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp @@ -44,10 +44,11 @@ void AdvancedServerSettingsLogic::onPushButtonClearServerClicked() uiLogic()->pageLogic()->onDisconnect(); } - ErrorCode e = m_serverController->removeAllContainers(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex)); - if (e) { + ServerController serverController(m_settings); + ErrorCode errorCode = serverController.removeAllContainers(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex)); + if (errorCode) { emit uiLogic()->showWarningMessage(tr("Error occurred while cleaning the server.") + "\n" + - tr("Error message: ") + errorString(e) + "\n" + + tr("Error message: ") + errorString(errorCode) + "\n" + tr("See logs for details.")); } else { set_labelWaitInfoVisible(true); diff --git a/client/ui/pages_logic/PageLogicBase.cpp b/client/ui/pages_logic/PageLogicBase.cpp index 9274ef49..05c4e3a1 100644 --- a/client/ui/pages_logic/PageLogicBase.cpp +++ b/client/ui/pages_logic/PageLogicBase.cpp @@ -11,7 +11,6 @@ PageLogicBase::PageLogicBase(UiLogic *logic, QObject *parent): { m_settings = logic->m_settings; m_configurator = logic->m_configurator; - m_serverController = logic->m_serverController; } diff --git a/client/ui/pages_logic/PageLogicBase.h b/client/ui/pages_logic/PageLogicBase.h index 887b0ec7..6616de9d 100644 --- a/client/ui/pages_logic/PageLogicBase.h +++ b/client/ui/pages_logic/PageLogicBase.h @@ -28,7 +28,6 @@ protected: std::shared_ptr m_settings; std::shared_ptr m_configurator; - std::shared_ptr m_serverController; signals: void updatePage(); diff --git a/client/ui/pages_logic/ServerConfiguringProgressLogic.cpp b/client/ui/pages_logic/ServerConfiguringProgressLogic.cpp index f6a8abdb..9874837f 100644 --- a/client/ui/pages_logic/ServerConfiguringProgressLogic.cpp +++ b/client/ui/pages_logic/ServerConfiguringProgressLogic.cpp @@ -96,19 +96,18 @@ ErrorCode ServerConfiguringProgressLogic::doInstallAction(const std::functionremoveContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), container); + ServerController serverController(m_settings); + ErrorCode e = serverController.removeContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), container); m_settings->removeContainerConfig(uiLogic()->m_selectedServerIndex, container); //buttonSetEnabledFunc(true); @@ -84,7 +85,8 @@ void ServerContainersLogic::onPushButtonRemoveClicked(DockerContainer container) void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int port, TransportProto tp) { - QJsonObject config = m_serverController->createContainerInitialConfig(c, port, tp); + ServerController serverController(m_settings); + QJsonObject config = serverController.createContainerInitialConfig(c, port, tp); emit uiLogic()->goToPage(Page::ServerConfiguringProgress); qApp->processEvents(); @@ -95,7 +97,8 @@ void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int p if (errorCode == ErrorCode::NoError) { if (!uiLogic()->isContainerAlreadyAddedToGui(c)) { auto installAction = [this, c, &config]() { - return m_serverController->setupContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), c, config); + ServerController serverController(m_settings); + return serverController.setupContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), c, config); }; errorCode = uiLogic()->pageLogic()->doInstallAction(installAction); diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index cddd6d40..6708a276 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -131,10 +131,11 @@ void StartPageLogic::onPushButtonConnect() set_pushButtonConnectEnabled(false); set_pushButtonConnectText(tr("Connecting...")); + ServerController serverController(m_settings); ErrorCode errorCode = ErrorCode::NoError; if (pushButtonConnectKeyChecked()) { - auto passphraseCallback = [this]() { + auto passphraseCallback = [this, &serverController]() { emit showPassphraseRequestMessage(); QEventLoop loop; QObject::connect(this, &StartPageLogic::passphraseDialogClosed, &loop, &QEventLoop::quit); @@ -142,14 +143,14 @@ void StartPageLogic::onPushButtonConnect() return m_privateKeyPassphrase; }; - m_serverController->setPassphraseCallback(passphraseCallback); + serverController.setPassphraseCallback(passphraseCallback); } - QString output = m_serverController->checkSshConnection(serverCredentials, &errorCode); + QString output = serverController.checkSshConnection(serverCredentials, &errorCode); if (pushButtonConnectKeyChecked()) { QString decryptedPrivateKey; - errorCode = uiLogic()->m_serverController->getDecryptedPrivateKey(serverCredentials, decryptedPrivateKey); + errorCode = serverController.getDecryptedPrivateKey(serverCredentials, decryptedPrivateKey); if (errorCode == ErrorCode::NoError) { serverCredentials.password = decryptedPrivateKey; } diff --git a/client/ui/pages_logic/protocols/CloakLogic.cpp b/client/ui/pages_logic/protocols/CloakLogic.cpp index d62f8624..3256de87 100644 --- a/client/ui/pages_logic/protocols/CloakLogic.cpp +++ b/client/ui/pages_logic/protocols/CloakLogic.cpp @@ -112,15 +112,16 @@ void CloakLogic::onPushButtonSaveClicked() progressBarFunc.setTextVisibleFunc(true); progressBarFunc.setTextFunc(QString("Configuring...")); - ErrorCode e = uiLogic()->pageLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ - return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), - uiLogic()->m_selectedDockerContainer, - containerConfig, - newContainerConfig); - }, - pageFunc, progressBarFunc, - saveButtonFunc, waitInfoFunc, - busyInfoFuncy, cancelButtonFunc); + + auto installAction = [this, containerConfig, &newContainerConfig]() { + ServerController serverController(m_settings); + return serverController.updateContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), + uiLogic()->m_selectedDockerContainer, containerConfig, newContainerConfig); + }; + + ErrorCode e = uiLogic()->pageLogic()->doInstallAction(installAction, pageFunc, progressBarFunc, + saveButtonFunc, waitInfoFunc, + busyInfoFuncy, cancelButtonFunc); if (!e) { m_settings->setContainerConfig(uiLogic()->m_selectedServerIndex, uiLogic()->m_selectedDockerContainer, newContainerConfig); diff --git a/client/ui/pages_logic/protocols/OpenVpnLogic.cpp b/client/ui/pages_logic/protocols/OpenVpnLogic.cpp index d5deecf3..fe3a2ed6 100644 --- a/client/ui/pages_logic/protocols/OpenVpnLogic.cpp +++ b/client/ui/pages_logic/protocols/OpenVpnLogic.cpp @@ -162,15 +162,16 @@ void OpenVpnLogic::onPushButtonSaveClicked() progressBarFunc.setTextVisibleFunc(true); progressBarFunc.setTextFunc(QString("Configuring...")); - ErrorCode e = uiLogic()->pageLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ - return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), - uiLogic()->m_selectedDockerContainer, - containerConfig, - newContainerConfig); - }, - pageFunc, progressBarFunc, - saveButtonFunc, waitInfoFunc, - busyInfoFuncy, cancelButtonFunc); + + auto installAction = [this, containerConfig, &newContainerConfig]() { + ServerController serverController(m_settings); + return serverController.updateContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), + uiLogic()->m_selectedDockerContainer, containerConfig, newContainerConfig); + }; + + ErrorCode e = uiLogic()->pageLogic()->doInstallAction(installAction, pageFunc, progressBarFunc, + saveButtonFunc, waitInfoFunc, + busyInfoFuncy, cancelButtonFunc); if (!e) { m_settings->setContainerConfig(uiLogic()->m_selectedServerIndex, uiLogic()->m_selectedDockerContainer, newContainerConfig); diff --git a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp index 708073a6..b1d75b8b 100644 --- a/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp +++ b/client/ui/pages_logic/protocols/ShadowSocksLogic.cpp @@ -104,8 +104,10 @@ void ShadowSocksLogic::onPushButtonSaveClicked() progressBarFunc.setTextVisibleFunc(true); progressBarFunc.setTextFunc(QString("Configuring...")); + auto installAction = [this, containerConfig, &newContainerConfig]() { - return m_serverController->updateContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), + ServerController serverController(m_settings); + return serverController.updateContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex), uiLogic()->m_selectedDockerContainer, containerConfig, newContainerConfig); }; ErrorCode e = uiLogic()->pageLogic()->doInstallAction(installAction, pageFunc, progressBarFunc, diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 2b66d6c9..52f3bbc0 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -78,16 +78,14 @@ using namespace amnezia; using namespace PageEnumNS; UiLogic::UiLogic(std::shared_ptr settings, std::shared_ptr configurator, - std::shared_ptr serverController, QObject *parent) : QObject(parent), m_settings(settings), - m_configurator(configurator), - m_serverController(serverController) + m_configurator(configurator) { m_containersModel = new ContainersModel(settings, this); m_protocolsModel = new ProtocolsModel(settings, this); - m_vpnConnection = new VpnConnection(settings, configurator, serverController); + m_vpnConnection = new VpnConnection(settings, configurator); m_vpnConnection->moveToThread(&m_vpnConnectionThread); m_vpnConnectionThread.start(); @@ -337,7 +335,8 @@ void UiLogic::installServer(QPair &container) if (!isContainerAlreadyAddedToGui(container.first)) { progressBarFunc.setTextFunc(QString("Installing %1").arg(ContainerProps::containerToString(container.first))); auto installAction = [&] () { - return m_serverController->setupContainer(m_installCredentials, container.first, container.second); + ServerController serverController(m_settings); + return serverController.setupContainer(m_installCredentials, container.first, container.second); }; errorCode = pageLogic()->doInstallAction(installAction, pageFunc, progressBarFunc, noButton, waitInfoFunc, @@ -531,7 +530,8 @@ ErrorCode UiLogic::addAlreadyInstalledContainersGui(bool createNewServer, bool & } QMap installedContainers; - ErrorCode errorCode = m_serverController->getAlreadyInstalledContainers(credentials, installedContainers); + ServerController serverController(m_settings); + ErrorCode errorCode = serverController.getAlreadyInstalledContainers(credentials, installedContainers); if (errorCode != ErrorCode::NoError) { return errorCode; } diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index 3a5559f2..e4eb9185 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -67,8 +67,7 @@ class UiLogic : public QObject READONLY_PROPERTY(QObject *, protocolsModel) public: - explicit UiLogic(std::shared_ptr settings, std::shared_ptr configurator, - std::shared_ptr serverController, QObject *parent = nullptr); + explicit UiLogic(std::shared_ptr settings, std::shared_ptr configurator, QObject *parent = nullptr); ~UiLogic(); void showOnStartup(); @@ -180,7 +179,6 @@ private: std::shared_ptr m_settings; std::shared_ptr m_configurator; - std::shared_ptr m_serverController; NotificationHandler* m_notificationHandler; diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 21643ae5..c9e97e03 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -30,11 +30,9 @@ #include "vpnconnection.h" VpnConnection::VpnConnection(std::shared_ptr settings, - std::shared_ptr configurator, - std::shared_ptr serverController, QObject* parent) : QObject(parent), + std::shared_ptr configurator, QObject* parent) : QObject(parent), m_settings(settings), m_configurator(configurator), - m_serverController(serverController), m_isIOSConnected(false) { } diff --git a/client/vpnconnection.h b/client/vpnconnection.h index ab8f2de0..8dea7478 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -33,8 +33,7 @@ class VpnConnection : public QObject public: explicit VpnConnection(std::shared_ptr settings, - std::shared_ptr configurator, - std::shared_ptr serverController, QObject* parent = nullptr); + std::shared_ptr configurator, QObject* parent = nullptr); ~VpnConnection() override; static QString bytesPerSecToText(quint64 bytes); @@ -96,7 +95,6 @@ protected: private: std::shared_ptr m_settings; std::shared_ptr m_configurator; - std::shared_ptr m_serverController; QJsonObject m_vpnConfiguration; QJsonObject m_routeMode; From f8ef69b88a4fa7bc5ebf07bd38869fbbf169c783 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Tue, 4 Apr 2023 13:32:37 +0300 Subject: [PATCH 32/43] removed setPassphraseCallback() function from ServerController and libssh::Client --- client/core/servercontroller.cpp | 9 ++------- client/core/servercontroller.h | 3 +-- client/core/sshclient.cpp | 8 ++------ client/core/sshclient.h | 3 +-- client/ui/pages_logic/StartPageLogic.cpp | 12 ++++++------ 5 files changed, 12 insertions(+), 23 deletions(-) diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index 0963f0e1..8324fa79 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -735,13 +735,8 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential return ErrorCode::NoError; } -void ServerController::setPassphraseCallback(const std::function &callback) +ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function &callback) { - m_sshClient.setPassphraseCallback(callback); -} - -ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey) -{ - auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey); + auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey, callback); return error; } diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h index 431104e7..2aaf4018 100644 --- a/client/core/servercontroller.h +++ b/client/core/servercontroller.h @@ -55,8 +55,7 @@ public: void setCancelInstallation(const bool cancel); - void setPassphraseCallback(const std::function &callback); - ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey); + ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function &callback); private: ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container); ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); diff --git a/client/core/sshclient.cpp b/client/core/sshclient.cpp index db3ca9f5..3a7896da 100644 --- a/client/core/sshclient.cpp +++ b/client/core/sshclient.cpp @@ -338,12 +338,13 @@ namespace libssh { } } - ErrorCode Client::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey) + ErrorCode Client::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function &passphraseCallback) { int authResult = SSH_ERROR; ErrorCode errorCode = ErrorCode::NoError; ssh_key privateKey; + m_passphraseCallback = passphraseCallback; authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey); if (authResult == SSH_OK) { char* key = new char[65535]; @@ -363,9 +364,4 @@ namespace libssh { ssh_key_free(privateKey); return errorCode; } - - void Client::setPassphraseCallback(const std::function &callback) - { - m_passphraseCallback = callback; - } } diff --git a/client/core/sshclient.h b/client/core/sshclient.h index 25f181b6..db22d0dd 100644 --- a/client/core/sshclient.h +++ b/client/core/sshclient.h @@ -36,8 +36,7 @@ namespace libssh { const std::string& localPath, const std::string& remotePath, const std::string& fileDesc); - ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey); - void setPassphraseCallback(const std::function &callback); + ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function &passphraseCallback); private: ErrorCode closeChannel(); ErrorCode closeSftpSession(); diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index 6708a276..09b6711c 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -143,19 +143,19 @@ void StartPageLogic::onPushButtonConnect() return m_privateKeyPassphrase; }; - serverController.setPassphraseCallback(passphraseCallback); - } - QString output = serverController.checkSshConnection(serverCredentials, &errorCode); - - if (pushButtonConnectKeyChecked()) { QString decryptedPrivateKey; - errorCode = serverController.getDecryptedPrivateKey(serverCredentials, decryptedPrivateKey); + errorCode = serverController.getDecryptedPrivateKey(serverCredentials, decryptedPrivateKey, passphraseCallback); if (errorCode == ErrorCode::NoError) { serverCredentials.password = decryptedPrivateKey; } } + QString output; + if (errorCode == ErrorCode::NoError) { + output = serverController.checkSshConnection(serverCredentials, &errorCode); + } + bool ok = true; if (errorCode) { set_labelWaitInfoVisible(true); From a9bb6f809940dc83fa49e91ae9d0ce2c92dc9a8a Mon Sep 17 00:00:00 2001 From: Dmitriy Karpushin Date: Tue, 4 Apr 2023 17:10:58 +0300 Subject: [PATCH 33/43] Fix to build at least x86_64 version of Amnezia desktop app on Apple Silicon --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e8dbd7c7..f1e5d37c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,10 @@ if(ANDROID) set(QT_ANDROID_BUILD_ALL_ABIS ON) endif() +if(APPLE AND NOT IOS) + set(CMAKE_OSX_ARCHITECTURES "x86_64") +endif() + add_subdirectory(client) if(NOT IOS AND NOT ANDROID) From 48d673c853b60c048cafac0c2ac4ca30df62d9dd Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Tue, 4 Apr 2023 18:20:19 +0300 Subject: [PATCH 34/43] fixed getting default port and default transport protocol in isServerPortBusy function --- client/core/servercontroller.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index 67a21bba..2be9d38f 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -871,13 +871,16 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential stdOut += data + "\n"; }; - const QString containerString = ProtocolProps::protoToString(ContainerProps::defaultProtocol(container)); + const Proto protocol = ContainerProps::defaultProtocol(container); + const QString containerString = ProtocolProps::protoToString(protocol); const QJsonObject containerConfig = config.value(containerString).toObject(); QStringList fixedPorts = ContainerProps::fixedPortsForContainer(container); - QString port = containerConfig.value(config_key::port).toString(protocols::openvpn::defaultPort); - QString transportProto = containerConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto); + QString defaultPort("%1"); + QString port = containerConfig.value(config_key::port).toString(defaultPort.arg(ProtocolProps::defaultPort(protocol))); + QString defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(protocol), protocol); + QString transportProto = containerConfig.value(config_key::transport_proto).toString(defaultTransportProto); QString script = QString("sudo lsof -i -P -n | grep -E ':%1 ").arg(port); for (auto &port : fixedPorts) { From 6e67946ae204d7dcd2926675551afe2828b21fba Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Tue, 4 Apr 2023 19:05:13 +0300 Subject: [PATCH 35/43] Removed the ability to add multiple servers with the same connection credentials via the "Add server" button --- .../AdvancedServerSettingsLogic.cpp | 2 +- .../ui/pages_logic/ServerContainersLogic.cpp | 6 ++-- client/ui/uilogic.cpp | 36 +++++++++++-------- client/ui/uilogic.h | 2 +- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp b/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp index 187af9ee..182e8bed 100644 --- a/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp +++ b/client/ui/pages_logic/AdvancedServerSettingsLogic.cpp @@ -68,7 +68,7 @@ void AdvancedServerSettingsLogic::onPushButtonScanServerClicked() bool isServerCreated; auto containersCount = m_settings->containers(uiLogic()->m_selectedServerIndex).size(); - ErrorCode errorCode = uiLogic()->addAlreadyInstalledContainersGui(false, isServerCreated); + ErrorCode errorCode = uiLogic()->addAlreadyInstalledContainersGui(isServerCreated); if (errorCode != ErrorCode::NoError) { emit uiLogic()->showWarningMessage(tr("Error occurred while scanning the server.") + "\n" + tr("Error message: ") + errorString(errorCode) + "\n" + diff --git a/client/ui/pages_logic/ServerContainersLogic.cpp b/client/ui/pages_logic/ServerContainersLogic.cpp index 870a10db..9df750e1 100644 --- a/client/ui/pages_logic/ServerContainersLogic.cpp +++ b/client/ui/pages_logic/ServerContainersLogic.cpp @@ -4,9 +4,7 @@ #include -#include "protocols/CloakLogic.h" -#include "protocols/OpenVpnLogic.h" -#include "protocols/ShadowSocksLogic.h" +#include "protocols/PageProtocolLogicBase.h" #include "core/servercontroller.h" #include @@ -90,7 +88,7 @@ void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int p qApp->processEvents(); bool isServerCreated = false; - ErrorCode errorCode = uiLogic()->addAlreadyInstalledContainersGui(false, isServerCreated); + ErrorCode errorCode = uiLogic()->addAlreadyInstalledContainersGui(isServerCreated); if (errorCode == ErrorCode::NoError) { if (!uiLogic()->isContainerAlreadyAddedToGui(c)) { diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 3dbd7b86..a257152c 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -332,7 +332,7 @@ void UiLogic::installServer(QPair &container) }; bool isServerCreated = false; - ErrorCode errorCode = addAlreadyInstalledContainersGui(true, isServerCreated); + ErrorCode errorCode = addAlreadyInstalledContainersGui(isServerCreated); if (errorCode == ErrorCode::NoError) { if (!isContainerAlreadyAddedToGui(container.first)) { progressBarFunc.setTextFunc(QString("Installing %1").arg(ContainerProps::containerToString(container.first))); @@ -520,18 +520,26 @@ void UiLogic::registerPagesLogic() registerPageLogic(); } -ErrorCode UiLogic::addAlreadyInstalledContainersGui(bool createNewServer, bool &isServerCreated) +ErrorCode UiLogic::addAlreadyInstalledContainersGui(bool &isServerCreated) { isServerCreated = false; - ServerCredentials credentials; - if (createNewServer) { - credentials = m_installCredentials; - } else { - credentials = m_settings->serverCredentials(m_selectedServerIndex); + ServerCredentials installCredentials = m_installCredentials; + bool createNewServer = true; + int serverIndex; + + for (int i = 0; i < m_settings->serversCount(); i++) { + const ServerCredentials credentials = m_settings->serverCredentials(i); + if (m_installCredentials.hostName == credentials.hostName && m_installCredentials.port == credentials.port) { + createNewServer = false; + isServerCreated = true; + installCredentials = credentials; + serverIndex = i; + break; + } } QMap installedContainers; - ErrorCode errorCode = m_serverController->getAlreadyInstalledContainers(credentials, installedContainers); + ErrorCode errorCode = m_serverController->getAlreadyInstalledContainers(installCredentials, installedContainers); if (errorCode != ErrorCode::NoError) { return errorCode; } @@ -540,10 +548,10 @@ ErrorCode UiLogic::addAlreadyInstalledContainersGui(bool createNewServer, bool & QJsonObject server; QJsonArray containerConfigs; if (createNewServer) { - server.insert(config_key::hostName, credentials.hostName); - server.insert(config_key::userName, credentials.userName); - server.insert(config_key::password, credentials.password); - server.insert(config_key::port, credentials.port); + server.insert(config_key::hostName, installCredentials.hostName); + server.insert(config_key::userName, installCredentials.userName); + server.insert(config_key::password, installCredentials.password); + server.insert(config_key::port, installCredentials.port); server.insert(config_key::description, m_settings->nextAvailableServerName()); } @@ -556,8 +564,8 @@ ErrorCode UiLogic::addAlreadyInstalledContainersGui(bool createNewServer, bool & containerConfigs.append(container.value()); server.insert(config_key::containers, containerConfigs); } else { - m_settings->setContainerConfig(m_selectedServerIndex, container.key(), container.value()); - m_settings->setDefaultContainer(m_selectedServerIndex, installedContainers.firstKey()); + m_settings->setContainerConfig(serverIndex, container.key(), container.value()); + m_settings->setDefaultContainer(serverIndex, installedContainers.firstKey()); } } diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index 92035fe5..b7e6f3ae 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -117,7 +117,7 @@ public: Q_INVOKABLE void saveBinaryFile(const QString& desc, QString ext, const QString& data); Q_INVOKABLE void copyToClipboard(const QString& text); - Q_INVOKABLE amnezia::ErrorCode addAlreadyInstalledContainersGui(bool createNewServer, bool &isServerCreated); + Q_INVOKABLE amnezia::ErrorCode addAlreadyInstalledContainersGui(bool &isServerCreated); void shareTempFile(const QString &suggestedName, QString ext, const QString& data); From 7e717754a307fd9170c576db09c3acfca5620620 Mon Sep 17 00:00:00 2001 From: pokamest Date: Wed, 5 Apr 2023 01:43:42 +0100 Subject: [PATCH 36/43] getOpenFileName fix for Android --- client/ui/pages_logic/AppSettingsLogic.cpp | 6 +++--- client/ui/pages_logic/StartPageLogic.cpp | 2 +- client/utilities.cpp | 17 +++++++++++++++++ client/utilities.h | 8 ++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/client/ui/pages_logic/AppSettingsLogic.cpp b/client/ui/pages_logic/AppSettingsLogic.cpp index e5358009..81e5c037 100644 --- a/client/ui/pages_logic/AppSettingsLogic.cpp +++ b/client/ui/pages_logic/AppSettingsLogic.cpp @@ -8,6 +8,7 @@ #include #include #include +#include using namespace amnezia; using namespace PageEnumNS; @@ -82,8 +83,8 @@ void AppSettingsLogic::onPushButtonBackupAppConfigClicked() void AppSettingsLogic::onPushButtonRestoreAppConfigClicked() { - QString fileName = QFileDialog::getOpenFileName(Q_NULLPTR, tr("Open backup"), - QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.backup"); + QString fileName = Utils::getOpenFileName(Q_NULLPTR, tr("Open backup"), + QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.backup"); if (fileName.isEmpty()) return; @@ -98,6 +99,5 @@ void AppSettingsLogic::onPushButtonRestoreAppConfigClicked() } else { emit uiLogic()->showWarningMessage(tr("Can't import config, file is corrupted.")); } - } diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index 7eb67adf..9fbb2efe 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -167,7 +167,7 @@ void StartPageLogic::onPushButtonImport() void StartPageLogic::onPushButtonImportOpenFile() { - QString fileName = QFileDialog::getOpenFileName(Q_NULLPTR, tr("Open config file"), + QString fileName = Utils::getOpenFileName(Q_NULLPTR, tr("Open config file"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.vpn *.ovpn *.conf"); if (fileName.isEmpty()) return; diff --git a/client/utilities.cpp b/client/utilities.cpp index e5d2fd52..c661636a 100644 --- a/client/utilities.cpp +++ b/client/utilities.cpp @@ -247,6 +247,23 @@ QString Utils::certUtilPath() #endif } +QString Utils::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) +{ + QString fileName = QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options); + +#ifdef Q_OS_ANDROID + // patch for files containing spaces etc + const QString sep {"raw%3A%2F"}; + if (fileName.startsWith("content://") && fileName.contains(sep)) { + QString contentUrl = fileName.split(sep).at(0); + QString rawUrl = fileName.split(sep).at(1); + rawUrl.replace(" ", "%20"); + fileName = contentUrl + sep + rawUrl; + } +#endif + return fileName; +} + #ifdef Q_OS_WIN // Inspired from http://stackoverflow.com/a/15281070/1529139 // and http://stackoverflow.com/q/40059902/1529139 diff --git a/client/utilities.h b/client/utilities.h index 932b9b27..6020e532 100644 --- a/client/utilities.h +++ b/client/utilities.h @@ -1,6 +1,7 @@ #ifndef UTILITIES_H #define UTILITIES_H +#include #include #include #include @@ -50,6 +51,13 @@ public: static QString wireguardExecPath(); static QString certUtilPath(); + static QString getOpenFileName(QWidget *parent = nullptr, + const QString &caption = QString(), + const QString &dir = QString(), + const QString &filter = QString(), + QString *selectedFilter = nullptr, + QFileDialog::Options options = QFileDialog::Options()); + #ifdef Q_OS_WIN static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent); From 2a7365730bfd43e1ce9d9fe21788f1fa8a84298f Mon Sep 17 00:00:00 2001 From: pokamest Date: Wed, 5 Apr 2023 03:39:05 +0100 Subject: [PATCH 37/43] getOpenFileName fix --- client/ui/pages_logic/AppSettingsLogic.cpp | 2 +- client/ui/pages_logic/StartPageLogic.cpp | 2 +- client/ui/uilogic.cpp | 19 ++++++++++++++++++- client/ui/uilogic.h | 14 ++++++++++---- client/utilities.cpp | 17 ----------------- client/utilities.h | 9 --------- 6 files changed, 30 insertions(+), 33 deletions(-) diff --git a/client/ui/pages_logic/AppSettingsLogic.cpp b/client/ui/pages_logic/AppSettingsLogic.cpp index 81e5c037..e86201e7 100644 --- a/client/ui/pages_logic/AppSettingsLogic.cpp +++ b/client/ui/pages_logic/AppSettingsLogic.cpp @@ -83,7 +83,7 @@ void AppSettingsLogic::onPushButtonBackupAppConfigClicked() void AppSettingsLogic::onPushButtonRestoreAppConfigClicked() { - QString fileName = Utils::getOpenFileName(Q_NULLPTR, tr("Open backup"), + QString fileName = UiLogic::getOpenFileName(Q_NULLPTR, tr("Open backup"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.backup"); if (fileName.isEmpty()) return; diff --git a/client/ui/pages_logic/StartPageLogic.cpp b/client/ui/pages_logic/StartPageLogic.cpp index 9fbb2efe..ca806897 100644 --- a/client/ui/pages_logic/StartPageLogic.cpp +++ b/client/ui/pages_logic/StartPageLogic.cpp @@ -167,7 +167,7 @@ void StartPageLogic::onPushButtonImport() void StartPageLogic::onPushButtonImportOpenFile() { - QString fileName = Utils::getOpenFileName(Q_NULLPTR, tr("Open config file"), + QString fileName = UiLogic::getOpenFileName(Q_NULLPTR, tr("Open config file"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.vpn *.ovpn *.conf"); if (fileName.isEmpty()) return; diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index a257152c..683213e5 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -498,6 +497,24 @@ void UiLogic::shareTempFile(const QString &suggestedName, QString ext, const QSt MobileUtils::shareText(filesToSend); } +QString UiLogic::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, + const QString &filter, QString *selectedFilter, QFileDialog::Options options) +{ + QString fileName = QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options); + +#ifdef Q_OS_ANDROID + // patch for files containing spaces etc + const QString sep {"raw%3A%2F"}; + if (fileName.startsWith("content://") && fileName.contains(sep)) { + QString contentUrl = fileName.split(sep).at(0); + QString rawUrl = fileName.split(sep).at(1); + rawUrl.replace(" ", "%20"); + fileName = contentUrl + sep + rawUrl; + } +#endif + return fileName; +} + void UiLogic::registerPagesLogic() { amnApp->qmlEngine()->rootContext()->setContextProperty("UiLogic", this); diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index b7e6f3ae..4daa42a7 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -1,12 +1,13 @@ #ifndef UILOGIC_H #define UILOGIC_H -#include -#include -#include +#include #include +#include #include +#include +#include #include #include #include @@ -120,7 +121,12 @@ public: Q_INVOKABLE amnezia::ErrorCode addAlreadyInstalledContainersGui(bool &isServerCreated); void shareTempFile(const QString &suggestedName, QString ext, const QString& data); - + static QString getOpenFileName(QWidget *parent = nullptr, + const QString &caption = QString(), + const QString &dir = QString(), + const QString &filter = QString(), + QString *selectedFilter = nullptr, + QFileDialog::Options options = QFileDialog::Options()); signals: void goToPage(PageEnumNS::Page page, bool reset = true, bool slide = true); void goToProtocolPage(Proto protocol, bool reset = true, bool slide = true); diff --git a/client/utilities.cpp b/client/utilities.cpp index c661636a..e5d2fd52 100644 --- a/client/utilities.cpp +++ b/client/utilities.cpp @@ -247,23 +247,6 @@ QString Utils::certUtilPath() #endif } -QString Utils::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) -{ - QString fileName = QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options); - -#ifdef Q_OS_ANDROID - // patch for files containing spaces etc - const QString sep {"raw%3A%2F"}; - if (fileName.startsWith("content://") && fileName.contains(sep)) { - QString contentUrl = fileName.split(sep).at(0); - QString rawUrl = fileName.split(sep).at(1); - rawUrl.replace(" ", "%20"); - fileName = contentUrl + sep + rawUrl; - } -#endif - return fileName; -} - #ifdef Q_OS_WIN // Inspired from http://stackoverflow.com/a/15281070/1529139 // and http://stackoverflow.com/q/40059902/1529139 diff --git a/client/utilities.h b/client/utilities.h index 6020e532..aeb06865 100644 --- a/client/utilities.h +++ b/client/utilities.h @@ -1,7 +1,6 @@ #ifndef UTILITIES_H #define UTILITIES_H -#include #include #include #include @@ -51,14 +50,6 @@ public: static QString wireguardExecPath(); static QString certUtilPath(); - static QString getOpenFileName(QWidget *parent = nullptr, - const QString &caption = QString(), - const QString &dir = QString(), - const QString &filter = QString(), - QString *selectedFilter = nullptr, - QFileDialog::Options options = QFileDialog::Options()); - - #ifdef Q_OS_WIN static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent); #endif From ba2ecf9789f93c1654f72f1f49a6ced5aefedfb0 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Wed, 5 Apr 2023 06:07:36 +0300 Subject: [PATCH 38/43] fixed cleanup of private/public keys after use --- client/core/sshclient.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/client/core/sshclient.cpp b/client/core/sshclient.cpp index 3a7896da..fe92af7e 100644 --- a/client/core/sshclient.cpp +++ b/client/core/sshclient.cpp @@ -56,8 +56,8 @@ namespace libssh { int authResult = SSH_ERROR; if (credentials.password.contains("BEGIN") && credentials.password.contains("PRIVATE KEY")) { - ssh_key privateKey; - ssh_key publicKey; + ssh_key privateKey = nullptr; + ssh_key publicKey = nullptr; authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey); if (authResult == SSH_OK) { authResult = ssh_pki_export_privkey_to_pubkey(privateKey, &publicKey); @@ -71,8 +71,12 @@ namespace libssh { authResult = ssh_userauth_publickey(m_session, authUsername.c_str(), privateKey); } - ssh_key_free(publicKey); - ssh_key_free(privateKey); + if (publicKey) { + ssh_key_free(publicKey); + } + if (privateKey) { + ssh_key_free(privateKey); + } } else { authResult = ssh_userauth_password(m_session, authUsername.c_str(), credentials.password.toStdString().c_str()); } @@ -343,7 +347,7 @@ namespace libssh { int authResult = SSH_ERROR; ErrorCode errorCode = ErrorCode::NoError; - ssh_key privateKey; + ssh_key privateKey = nullptr; m_passphraseCallback = passphraseCallback; authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey); if (authResult == SSH_OK) { @@ -361,7 +365,9 @@ namespace libssh { errorCode = ErrorCode::SshPrivateKeyError; } - ssh_key_free(privateKey); + if (privateKey) { + ssh_key_free(privateKey); + } return errorCode; } } From b3456ee96c4540a4cd102f6e851ba91e933e0a62 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Wed, 5 Apr 2023 06:20:10 +0300 Subject: [PATCH 39/43] fixed variable name in addAlreadyInstalledContainersGui() function --- client/ui/uilogic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 00b74568..cc66a47d 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -556,7 +556,7 @@ ErrorCode UiLogic::addAlreadyInstalledContainersGui(bool &isServerCreated) QMap installedContainers; ServerController serverController(m_settings); - ErrorCode errorCode = serverController.getAlreadyInstalledContainers(credentials, installedContainers); + ErrorCode errorCode = serverController.getAlreadyInstalledContainers(installCredentials, installedContainers); if (errorCode != ErrorCode::NoError) { return errorCode; } From ccfc9f2ad22d9fba432befe4a9d6f5f33a89204f Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Wed, 5 Apr 2023 09:45:03 +0300 Subject: [PATCH 40/43] added error handling for key authentication --- client/core/defs.h | 2 +- client/core/errorstrings.cpp | 1 + client/core/sshclient.cpp | 19 ++++++++++++------- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/client/core/defs.h b/client/core/defs.h index 257de62f..bafd088f 100644 --- a/client/core/defs.h +++ b/client/core/defs.h @@ -35,7 +35,7 @@ enum ErrorCode // Ssh connection errors SshRequsetDeniedError, SshInterruptedError, SshInternalError, - SshPrivateKeyError, + SshPrivateKeyError, SshPrivateKeyFormatError, // Ssh sftp errors SshSftpEofError, SshSftpNoSuchFileError, SshSftpPermissionDeniedError, diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp index 8108ff53..5d2a337b 100644 --- a/client/core/errorstrings.cpp +++ b/client/core/errorstrings.cpp @@ -22,6 +22,7 @@ QString errorString(ErrorCode code){ case(SshInterruptedError): return QObject::tr("Ssh request was interrupted"); case(SshInternalError): return QObject::tr("Ssh internal error"); case(SshPrivateKeyError): return QObject::tr("Invalid private key or invalid passphrase entered"); + case(SshPrivateKeyFormatError): return QObject::tr("The selected private key format is not supported, use openssh ED25519 key types or PEM key types"); // Libssh sftp errors case(SshSftpEofError): return QObject::tr("Sftp error: End-of-file encountered"); diff --git a/client/core/sshclient.cpp b/client/core/sshclient.cpp index fe92af7e..39d9f4f1 100644 --- a/client/core/sshclient.cpp +++ b/client/core/sshclient.cpp @@ -77,16 +77,21 @@ namespace libssh { if (privateKey) { ssh_key_free(privateKey); } + if (authResult != SSH_OK) { + qDebug() << ssh_get_error(m_session); + ErrorCode errorCode = fromLibsshErrorCode(ssh_get_error_code(m_session)); + if (errorCode == ErrorCode::NoError) { + errorCode = ErrorCode::SshPrivateKeyFormatError; + } + return errorCode; + } } else { authResult = ssh_userauth_password(m_session, authUsername.c_str(), credentials.password.toStdString().c_str()); + if (authResult != SSH_OK) { + qDebug() << ssh_get_error(m_session); + return fromLibsshErrorCode(ssh_get_error_code(m_session)); + } } - - if (authResult != SSH_OK) { - qDebug() << ssh_get_error(m_session); - return fromLibsshErrorCode(ssh_get_error_code(m_session)); - } - - return fromLibsshErrorCode(ssh_get_error_code(m_session)); } return ErrorCode::NoError; } From ef03a3d9d4b3c1c8649af75b30c027c2f91579b3 Mon Sep 17 00:00:00 2001 From: bakhtiyork Date: Thu, 6 Apr 2023 05:59:42 +0500 Subject: [PATCH 41/43] FindMbedTLS.cmake - adding mbedtls targets export --- client/cmake/Modules/FindMbedTLS.cmake | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/client/cmake/Modules/FindMbedTLS.cmake b/client/cmake/Modules/FindMbedTLS.cmake index 35589f17..e1c58f46 100644 --- a/client/cmake/Modules/FindMbedTLS.cmake +++ b/client/cmake/Modules/FindMbedTLS.cmake @@ -13,3 +13,13 @@ include_directories(${MBEDTLS_INCLUDE_DIR}) # show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES) + +install(TARGETS mbedtls mbedx509 mbedcrypto + EXPORT mbedtls-config + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT libraries) + +install(EXPORT mbedtls-config + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) From f931603203937122ecd2077e04b1f504b5e1cc61 Mon Sep 17 00:00:00 2001 From: bakhtiyork Date: Thu, 6 Apr 2023 20:33:12 +0500 Subject: [PATCH 42/43] Disabling symbol versioning for iOS --- client/cmake/3rdparty.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/client/cmake/3rdparty.cmake b/client/cmake/3rdparty.cmake index fce24019..da50978e 100644 --- a/client/cmake/3rdparty.cmake +++ b/client/cmake/3rdparty.cmake @@ -40,6 +40,7 @@ if(IOS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBEDTLS_ALLOW_PRIVATE_ACCESS") set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) set(WITH_STATIC_LIB ON CACHE BOOL "" FORCE) + set(WITH_SYMBOL_VERSIONING OFF CACHE BOOL "" FORCE) include_directories(${CLIENT_ROOT_DIR}/3rd/mbedtls/include) else(IOS) From 8374404b0f38ecd7c4587d4147055977bd2ab62b Mon Sep 17 00:00:00 2001 From: bakhtiyork Date: Fri, 7 Apr 2023 11:21:44 +0500 Subject: [PATCH 43/43] iOS - cmake: disabling testing and programs --- client/cmake/3rdparty.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/cmake/3rdparty.cmake b/client/cmake/3rdparty.cmake index da50978e..44120cf5 100644 --- a/client/cmake/3rdparty.cmake +++ b/client/cmake/3rdparty.cmake @@ -24,6 +24,8 @@ link_directories(${CMAKE_CURRENT_BINARY_DIR}/3rd/zlib) link_libraries(${ZLIB_LIBRARY}) if(IOS) + set(ENABLE_PROGRAMS OFF CACHE BOOL "" FORCE) + set(ENABLE_TESTING OFF CACHE BOOL "" FORCE) add_subdirectory(${CLIENT_ROOT_DIR}/3rd/mbedtls) set(WITH_MBEDTLS ON CACHE BOOL "" FORCE) set(WITH_GCRYPT OFF CACHE BOOL "" FORCE)