From 2974d6d5d720a01499b29ca9ee21cc7dab3a306f Mon Sep 17 00:00:00 2001 From: Jonathan Martin Date: Wed, 15 May 2024 09:23:33 -0700 Subject: [PATCH] v2.10.10 --- .../kernelmodule/kernelmodulecommunicator.cpp | 4 + backend/mac/helper/helper-info.plist | 2 +- backend/mac/helper/server.cpp | 4 + .../command_parser.cpp | 30 +- .../install_service_command.cpp | 34 +- .../install_service_command.h | 5 +- .../windscribe_install_helper/logger.cpp | 31 +- .../windscribe_install_helper/logger.h | 4 +- .../windscribe_install_helper.cpp | 12 + .../windows/windscribe_service/CMakeLists.txt | 2 + .../ipc/serialize_structs.h | 9 +- .../ipc/servicecommunication.h | 13 +- backend/windows/windscribe_service/ovpn.cpp | 1 + .../windscribe_service/process_command.cpp | 57 ++- .../windscribe_service/process_command.h | 2 - .../windows/windscribe_service/registry.cpp | 82 ++-- backend/windows/windscribe_service/registry.h | 17 +- backend/windows/windscribe_service/utils.cpp | 44 ++- backend/windows/windscribe_service/utils.h | 1 + client/common/changelog.txt | 15 + .../legacy_protobuf_support/types.pb-c.c | 84 +--- .../legacy_protobuf_support/types.pb-c.h | 58 +-- client/common/types/enums.h | 76 ++-- client/common/types/sharesecurehotspot.h | 2 +- client/common/utils/crashdump.cpp | 2 +- client/common/utils/crashhandler.cpp | 2 +- client/common/version/windscribe_version.h | 2 +- .../connectionmanager/connectionmanager.cpp | 9 +- .../finishactiveconnections.cpp | 3 +- .../connectionmanager/openvpnconnection.cpp | 15 +- .../wireguardconnection_posix.cpp | 6 - .../wireguardconnection_win.cpp | 3 +- .../emergencycontroller.cpp | 5 +- client/engine/engine/engine.cpp | 5 - client/engine/engine/helper/helper_win.cpp | 22 +- client/engine/engine/helper/helper_win.h | 3 +- client/engine/engine/helper/ihelper.h | 2 +- .../engine/helper/installhelper_win.cpp | 75 ++-- .../engine/engine/helper/installhelper_win.h | 12 +- client/engine/engine/ping/pingmanager.cpp | 18 +- client/engine/engine/ping/pingmanager.h | 2 + client/gui/mainwindow.cpp | 6 - installer/common/alertwindow.cpp | 5 + installer/common/alertwindow.h | 3 +- installer/common/alertwindowcontents.cpp | 15 +- installer/common/alertwindowcontents.h | 2 + installer/common/installer_shim.h | 2 +- installer/common/installer_win.qrc | 2 +- installer/common/mainwindow.cpp | 360 +++++++++++------- installer/common/mainwindow.h | 25 +- installer/common/resources/ERROR.svg | 11 +- installer/common/resources/WARNING.svg | 10 + .../translations/windscribe_installer_ar.ts | 20 +- .../translations/windscribe_installer_cs.ts | 20 +- .../translations/windscribe_installer_de.ts | 20 +- .../translations/windscribe_installer_en.ts | 20 +- .../translations/windscribe_installer_es.ts | 20 +- .../translations/windscribe_installer_fa.ts | 20 +- .../translations/windscribe_installer_fr.ts | 20 +- .../translations/windscribe_installer_hi.ts | 20 +- .../translations/windscribe_installer_id.ts | 20 +- .../translations/windscribe_installer_it.ts | 20 +- .../translations/windscribe_installer_ja.ts | 20 +- .../translations/windscribe_installer_ko.ts | 20 +- .../translations/windscribe_installer_pl.ts | 20 +- .../translations/windscribe_installer_pt.ts | 20 +- .../translations/windscribe_installer_ru.ts | 20 +- .../translations/windscribe_installer_tr.ts | 20 +- .../translations/windscribe_installer_uk.ts | 20 +- .../translations/windscribe_installer_vi.ts | 20 +- .../windscribe_installer_zh-CN.ts | 20 +- .../windscribe_installer_zh-TW.ts | 20 +- installer/mac/installer/helper/helper_mac.mm | 2 - .../mac/installer/installer/installer_shim.mm | 4 +- installer/windows/installer/CMakeLists.txt | 1 + .../installer/blocks/install_openvpn_dco.cpp | 4 +- .../installer/blocks/uninstallprev.cpp | 2 +- .../installer/installer/installer_shim.cpp | 9 +- .../installer/installer/installer_utils.cpp | 140 +++++++ .../installer/installer/installer_utils.h | 13 + .../windows/installer/installer/settings.cpp | 21 +- .../windows/installer/installer/settings.h | 8 +- installer/windows/installer/main.cpp | 20 +- installer/windows/utils/applicationinfo.cpp | 20 +- installer/windows/utils/logger.cpp | 10 - installer/windows/utils/logger.h | 2 - installer/windows/utils/path.cpp | 12 + installer/windows/utils/path.h | 1 + installer/windows/utils/utils.cpp | 38 +- installer/windows/utils/utils.h | 2 +- .../windows/utils/windscribepathcheck.cpp | 7 +- libs/wsnet/CMakeLists.txt | 58 +-- .../include/wsnet/WSNetHttpNetworkManager.h | 11 +- libs/wsnet/include/wsnet/WSNetServerAPI.h | 15 +- .../wsnet/src/dnsresolver/dnsresolver_cares.h | 1 - .../src/emergencyconnect/emergencyconnect.cpp | 8 +- .../src/emergencyconnect/emergencyconnect.h | 6 +- libs/wsnet/src/failover/failoverdata.h | 4 +- .../httpnetworkmanager/curlnetworkmanager.cpp | 53 ++- .../httpnetworkmanager/curlnetworkmanager.h | 10 + .../httpnetworkmanager/httpnetworkmanager.cpp | 29 +- .../httpnetworkmanager/httpnetworkmanager.h | 7 +- .../httpnetworkmanager_impl.cpp | 17 +- .../httpnetworkmanager_impl.h | 7 +- .../pingmanager/eventcallbackmanager_win.cpp | 1 - libs/wsnet/src/pingmanager/pingmanager.cpp | 8 +- libs/wsnet/src/pingmanager/pingmanager.h | 6 +- .../src/pingmanager/pingmethod_icmp_posix.cpp | 2 +- libs/wsnet/src/pingmanager/processmanager.cpp | 95 ++--- libs/wsnet/src/pingmanager/processmanager.h | 29 +- libs/wsnet/src/serverapi/baserequest.h | 1 - libs/wsnet/src/serverapi/requestsfactory.cpp | 36 +- libs/wsnet/src/serverapi/requestsfactory.h | 7 +- libs/wsnet/src/serverapi/serverapi.cpp | 108 ++++-- libs/wsnet/src/serverapi/serverapi.h | 15 +- libs/wsnet/src/serverapi/wsnet_utils_impl.cpp | 6 +- libs/wsnet/src/serverapi/wsnet_utils_impl.h | 6 +- libs/wsnet/src/wsnet.cpp | 25 +- libs/wsnet/vcpkg.json | 10 +- tools/build_all.py | 17 +- tools/build_all.yml | 2 +- tools/vcpkg/vcpkg.json | 7 +- 122 files changed, 1542 insertions(+), 997 deletions(-) create mode 100644 installer/common/resources/WARNING.svg create mode 100644 installer/windows/installer/installer/installer_utils.cpp create mode 100644 installer/windows/installer/installer/installer_utils.h diff --git a/backend/linux/helper/wireguard/kernelmodule/kernelmodulecommunicator.cpp b/backend/linux/helper/wireguard/kernelmodule/kernelmodulecommunicator.cpp index 185a04287..be1ceccfc 100644 --- a/backend/linux/helper/wireguard/kernelmodule/kernelmodulecommunicator.cpp +++ b/backend/linux/helper/wireguard/kernelmodule/kernelmodulecommunicator.cpp @@ -20,6 +20,10 @@ bool KernelModuleCommunicator::start(const std::string &deviceName) bool KernelModuleCommunicator::stop() { + // Bring down utun420 via nmcli first, or NetworkManager/GNOME may throw up a scary looking "error". + // This is a workaround for #996; this is not really our bug but it's a bad user experience otherwise. + Utils::executeCommand("nmcli", {"con", "down", deviceName_.c_str()}); + wg_del_device(deviceName_.c_str()); return true; } diff --git a/backend/mac/helper/helper-info.plist b/backend/mac/helper/helper-info.plist index d273b6edc..343d9a5e1 100644 --- a/backend/mac/helper/helper-info.plist +++ b/backend/mac/helper/helper-info.plist @@ -9,7 +9,7 @@ CFBundleName WindscribeHelper CFBundleVersion - 62 + 63 NSHumanReadableCopyright Copyright © 2024 Windscribe Limited. All rights reserved. LSMinimumSystemVersion diff --git a/backend/mac/helper/server.cpp b/backend/mac/helper/server.cpp index 7c4b78abe..7e6dfc222 100644 --- a/backend/mac/helper/server.cpp +++ b/backend/mac/helper/server.cpp @@ -98,6 +98,10 @@ void Server::run() return; } + system("mkdir -p /var/run"); + system("mkdir -p /etc/windscribe"); + Utils::createWindscribeUserAndGroup(); + xpc_connection_t listener = xpc_connection_create_mach_service("com.windscribe.helper.macos", NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); if (!listener) { LOG("xpc_connection_create_mach_service failed"); diff --git a/backend/windows/windscribe_install_helper/command_parser.cpp b/backend/windows/windscribe_install_helper/command_parser.cpp index 15131691f..bdd4f2d1f 100644 --- a/backend/windows/windscribe_install_helper/command_parser.cpp +++ b/backend/windows/windscribe_install_helper/command_parser.cpp @@ -1,7 +1,22 @@ #include "command_parser.h" +#include + #include "install_service_command.h" +static std::wstring getInstallDir() +{ + wchar_t buffer[MAX_PATH]; + DWORD pathLen = ::GetModuleFileName(NULL, buffer, MAX_PATH); + if (pathLen == 0) { + Logger::WSDebugMessage(L"Windscribe install helper GetModuleFileName failed (%lu)", ::GetLastError()); + return std::wstring(); + } + + std::filesystem::path path(buffer); + return path.parent_path().native(); +} + CommandParser::CommandParser() { } @@ -13,13 +28,14 @@ CommandParser::~CommandParser() BasicCommand *CommandParser::parse(int argc, wchar_t* argv[]) { // Command for install helper - // /InstallService log_path service_path - if (argc == 4 && wcscmp(argv[1], L"/InstallService") == 0) - { - Logger *logger = new Logger(argv[2]); - logger->outCmdLine(argc, argv); - InstallServiceCommand *cmd = new InstallServiceCommand(logger, argv[3]); - return cmd; + // /InstallService + if (argc == 2 && wcscmp(argv[1], L"/InstallService") == 0) { + const auto installDir = getInstallDir(); + if (!installDir.empty()) { + Logger *logger = new Logger(installDir.c_str()); + InstallServiceCommand *cmd = new InstallServiceCommand(logger, installDir); + return cmd; + } } return nullptr; diff --git a/backend/windows/windscribe_install_helper/install_service_command.cpp b/backend/windows/windscribe_install_helper/install_service_command.cpp index a454478b0..937a76073 100644 --- a/backend/windows/windscribe_install_helper/install_service_command.cpp +++ b/backend/windows/windscribe_install_helper/install_service_command.cpp @@ -1,13 +1,15 @@ #include "install_service_command.h" +#include #include #include "servicecontrolmanager.h" using namespace std; -InstallServiceCommand::InstallServiceCommand(Logger *logger, const wchar_t *servicePath) : - BasicCommand(logger), servicePath_(servicePath) +InstallServiceCommand::InstallServiceCommand(Logger *logger, const wstring &installDir) + : BasicCommand(logger), + installDir_(installDir) { } @@ -23,25 +25,31 @@ void InstallServiceCommand::execute() const wstring serviceName(L"WindscribeService"); if (scm.isServiceInstalled(serviceName.c_str())) { - logger_->outStr(L"Remove previous instance of Windscribe Service\n"); - scm.deleteService(serviceName.c_str()); + logger_->outStr(L"Removing previous instance of Windscribe service"); + std::error_code ec; + if (!scm.deleteService(serviceName.c_str(), ec)) { + // We'll still try to reinstall the service even if the delete failed/timed out. + logger_->outStr(L"Failed to delete existing Windscribe service (%d)", ec.value()); + } } - if (!servicePath_.starts_with(L'\"')) { - servicePath_.insert(0, L"\""); + wstring serviceCmdLine; + { + wostringstream stream; + stream << L"\"" << installDir_ << L"\\WindscribeService.exe\""; + serviceCmdLine = stream.str(); } - if (!servicePath_.ends_with(L'\"')) { - servicePath_.append(L"\""); - } - - scm.installService(serviceName.c_str(), servicePath_.c_str(), + scm.installService(serviceName.c_str(), serviceCmdLine.c_str(), L"Windscribe Service", L"Manages the firewall and controls the VPN tunnel", SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, L"Nsi\0TcpIp\0", true); - scm.setServiceSIDType(SERVICE_SID_TYPE_UNRESTRICTED); + scm.openService(serviceName.c_str(), SERVICE_QUERY_STATUS | SERVICE_START); + scm.startService(); + + logger_->outStr(L"Reinstalled Windscribe service"); } catch (system_error& ex) { - logger_->outStr(L"WARNING: failed to reinstall the Windscribe service - %s\n", ex.what()); + logger_->outStr(L"WARNING: failed to reinstall the Windscribe service - %s", ex.what()); } } diff --git a/backend/windows/windscribe_install_helper/install_service_command.h b/backend/windows/windscribe_install_helper/install_service_command.h index 1259de903..ed74965a2 100644 --- a/backend/windows/windscribe_install_helper/install_service_command.h +++ b/backend/windows/windscribe_install_helper/install_service_command.h @@ -1,14 +1,15 @@ #pragma once + #include "basic_command.h" class InstallServiceCommand : public BasicCommand { public: - InstallServiceCommand(Logger *logger, const wchar_t *servicePath); + InstallServiceCommand(Logger *logger, const std::wstring &installDir); ~InstallServiceCommand() override; void execute() override; private: - std::wstring servicePath_; + const std::wstring installDir_; }; diff --git a/backend/windows/windscribe_install_helper/logger.cpp b/backend/windows/windscribe_install_helper/logger.cpp index 5dfebbc05..1fde8baa2 100644 --- a/backend/windows/windscribe_install_helper/logger.cpp +++ b/backend/windows/windscribe_install_helper/logger.cpp @@ -3,25 +3,18 @@ #include #include +#include using namespace std; -static void WSDebugMessage(const wchar_t* format, ...) +Logger::Logger(const wchar_t *installDir) { - va_list arg_list; - va_start(arg_list, format); - wchar_t szMsg[1024]; - _vsnwprintf_s(szMsg, 1024, _TRUNCATE, format, arg_list); - va_end(arg_list); + std::filesystem::path logFile(installDir); + logFile.append(L"logwindscribeinstallhelper.txt"); - ::OutputDebugString(szMsg); -} - -Logger::Logger(const wchar_t *path) -{ - errno_t result = _wfopen_s(&file_, path, L"wt,ccs=UTF-8"); + errno_t result = _wfopen_s(&file_, logFile.native().c_str(), L"wt,ccs=UTF-8"); if ((result != 0) || (file_ == nullptr)) { - WSDebugMessage(L"Windscribe install helper failed to open its log file '%s' (%d)", path, result); + WSDebugMessage(L"Windscribe install helper failed to open its log file '%s' (%d)", logFile.native().c_str(), result); } } @@ -54,8 +47,20 @@ void Logger::outStr(const wchar_t* format, ...) if (file_) { fputws(szMsg, file_); + fputws(L"\n", file_); } else { ::OutputDebugString(szMsg); } } + +void Logger::WSDebugMessage(const wchar_t* format, ...) +{ + va_list arg_list; + va_start(arg_list, format); + wchar_t szMsg[1024]; + _vsnwprintf_s(szMsg, 1024, _TRUNCATE, format, arg_list); + va_end(arg_list); + + ::OutputDebugString(szMsg); +} diff --git a/backend/windows/windscribe_install_helper/logger.h b/backend/windows/windscribe_install_helper/logger.h index 97cc226af..c97cd03ca 100644 --- a/backend/windows/windscribe_install_helper/logger.h +++ b/backend/windows/windscribe_install_helper/logger.h @@ -5,7 +5,7 @@ class Logger { public: - explicit Logger(const wchar_t *path); + explicit Logger(const wchar_t *installDir); virtual ~Logger(); Logger(const Logger &) = delete; Logger &operator=(const Logger &) = delete; @@ -13,6 +13,8 @@ class Logger void outStr(const wchar_t* format, ...); void outCmdLine(int argc, wchar_t* argv[]); + static void WSDebugMessage(const wchar_t* format, ...); + private: FILE *file_ = nullptr; }; diff --git a/backend/windows/windscribe_install_helper/windscribe_install_helper.cpp b/backend/windows/windscribe_install_helper/windscribe_install_helper.cpp index 28d738ec9..0307d5bad 100644 --- a/backend/windows/windscribe_install_helper/windscribe_install_helper.cpp +++ b/backend/windows/windscribe_install_helper/windscribe_install_helper.cpp @@ -6,6 +6,18 @@ #include "command_parser.h" +// Set the DLL load directory to the system directory before entering WinMain(). +struct LoadSystemDLLsFromSystem32 +{ + LoadSystemDLLsFromSystem32() + { + // Remove the current directory from the search path for dynamically loaded + // DLLs as a precaution. This call has no effect for delay load DLLs. + SetDllDirectory(L""); + SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32); + } +} loadSystemDLLs; + int _tmain(int argc, _TCHAR* argv[]) { CommandParser parser; diff --git a/backend/windows/windscribe_service/CMakeLists.txt b/backend/windows/windscribe_service/CMakeLists.txt index 5b4a92e10..7a34263d7 100644 --- a/backend/windows/windscribe_service/CMakeLists.txt +++ b/backend/windows/windscribe_service/CMakeLists.txt @@ -23,6 +23,7 @@ add_definitions(-DUNICODE -D_UNICODE -DWINDSCRIBE_SERVICE) project(Service) find_package(Boost REQUIRED COMPONENTS serialization) +find_path(WINREG_INCLUDE_DIRS "winreg/WinReg.hpp") add_subdirectory(../../../libs/wsnet wsnet) @@ -95,6 +96,7 @@ target_link_libraries(WindscribeService target_include_directories(WindscribeService PRIVATE ${WINDSCRIBE_BUILD_LIBS_PATH}/wintun/include ../../../client/common/ + ${WINREG_INCLUDE_DIRS} ) install(TARGETS WindscribeService wsnet diff --git a/backend/windows/windscribe_service/ipc/serialize_structs.h b/backend/windows/windscribe_service/ipc/serialize_structs.h index 66d1783ac..941f6fa4f 100644 --- a/backend/windows/windscribe_service/ipc/serialize_structs.h +++ b/backend/windows/windscribe_service/ipc/serialize_structs.h @@ -20,7 +20,7 @@ template void serialize(Archive & ar, CMD_TASK_KILL & g, const unsigned int version) { UNREFERENCED_PARAMETER(version); - ar & g.szExecutableName; + ar & g.target; } template @@ -32,13 +32,6 @@ void serialize(Archive & ar, CMD_SET_METRIC & g, const unsigned int version) ar & g.szMetricNumber; } -template -void serialize(Archive & ar, CMD_WMIC_ENABLE & g, const unsigned int version) -{ - UNREFERENCED_PARAMETER(version); - ar & g.szAdapterName; -} - template void serialize(Archive & ar, CMD_WMIC_GET_CONFIG_ERROR_CODE & g, const unsigned int version) { diff --git a/backend/windows/windscribe_service/ipc/servicecommunication.h b/backend/windows/windscribe_service/ipc/servicecommunication.h index 03a3c5a79..d051b45b3 100644 --- a/backend/windows/windscribe_service/ipc/servicecommunication.h +++ b/backend/windows/windscribe_service/ipc/servicecommunication.h @@ -29,7 +29,7 @@ #define AA_COMMAND_ENUM_PROCESSES 26 #define AA_COMMAND_TASK_KILL 27 #define AA_COMMAND_SET_METRIC 28 -#define AA_COMMAND_WMIC_ENABLE 29 +#define AA_COMMAND_WMIC_ENABLE 29 // deprecated #define AA_COMMAND_WMIC_GET_CONFIG_ERROR_CODE 30 #define AA_COMMAND_ENABLE_BFE 31 #define AA_COMMAND_RUN_OPENVPN 32 @@ -60,6 +60,10 @@ #include #include +enum CmdKillTarget { + kTargetOpenVpn +}; + struct CMD_FIREWALL_ON { bool allowLanTraffic = false; @@ -95,7 +99,7 @@ struct CMD_SUSPEND_UNBLOCKING_CMD struct CMD_TASK_KILL { - std::wstring szExecutableName; + CmdKillTarget target; }; struct CMD_SET_METRIC @@ -105,11 +109,6 @@ struct CMD_SET_METRIC std::wstring szMetricNumber; }; -struct CMD_WMIC_ENABLE -{ - std::wstring szAdapterName; -}; - struct CMD_WMIC_GET_CONFIG_ERROR_CODE { std::wstring szAdapterName; diff --git a/backend/windows/windscribe_service/ovpn.cpp b/backend/windows/windscribe_service/ovpn.cpp index a6207cedd..59e1b6115 100644 --- a/backend/windows/windscribe_service/ovpn.cpp +++ b/backend/windows/windscribe_service/ovpn.cpp @@ -60,6 +60,7 @@ bool writeOVPNFile(std::wstring &filename, int port, const std::wstring &config, file << L"management 127.0.0.1 " + std::to_wstring(port) + L"\r\n"; file << L"management-query-passwords\r\n"; file << L"management-hold\r\n"; + file << L"verb 3\r\n"; if (httpProxy.length() > 0) { file << L"http-proxy " + httpProxy + L" " + std::to_wstring(httpPort) + L" auto\r\n"; diff --git a/backend/windows/windscribe_service/process_command.cpp b/backend/windows/windscribe_service/process_command.cpp index 617c738ec..23301ec0b 100644 --- a/backend/windows/windscribe_service/process_command.cpp +++ b/backend/windows/windscribe_service/process_command.cpp @@ -379,12 +379,22 @@ MessagePacketResult enumProcesses(boost::archive::text_iarchive &ia) MessagePacketResult taskKill(boost::archive::text_iarchive &ia) { + MessagePacketResult mpr; + CMD_TASK_KILL cmdTaskKill; ia >> cmdTaskKill; - std::wstring killCmd = Utils::getSystemDir() + L"\\taskkill.exe /f /t /im " + cmdTaskKill.szExecutableName; - Logger::instance().out(L"AA_COMMAND_TASK_KILL, cmd=%s", killCmd.c_str()); - return ExecuteCmd::instance().executeBlockingCmd(killCmd); + if (cmdTaskKill.target == kTargetOpenVpn) { + std::wstringstream killCmd; + killCmd << Utils::getSystemDir() << L"\\taskkill.exe /f /t /im \"" << Utils::getExePath() << L"\\windscribeopenvpn.exe\""; + Logger::instance().out(L"AA_COMMAND_TASK_KILL, cmd=%s", killCmd.str().c_str()); + mpr = ExecuteCmd::instance().executeBlockingCmd(killCmd.str()); + } + else { + Logger::instance().out(L"AA_COMMAND_TASK_KILL, invalid ID received %d", cmdTaskKill.target); + } + + return mpr; } MessagePacketResult setMetric(boost::archive::text_iarchive &ia) @@ -398,16 +408,6 @@ MessagePacketResult setMetric(boost::archive::text_iarchive &ia) return ExecuteCmd::instance().executeBlockingCmd(setMetricCmd); } -MessagePacketResult wmicEnable(boost::archive::text_iarchive &ia) -{ - CMD_WMIC_ENABLE cmdWmicEnable; - ia >> cmdWmicEnable; - - std::wstring wmicCmd = Utils::getSystemDir() + L"\\wbem\\wmic.exe path win32_networkadapter where description=\"" + cmdWmicEnable.szAdapterName + L"\" call enable"; - Logger::instance().out(L"AA_COMMAND_WMIC_ENABLE, cmd=%s", wmicCmd.c_str()); - return ExecuteCmd::instance().executeBlockingCmd(wmicCmd); -} - MessagePacketResult wmicGetConfigErrorCode(boost::archive::text_iarchive &ia) { CMD_WMIC_GET_CONFIG_ERROR_CODE cmdWmicGetConfigErrorCode; @@ -497,12 +497,23 @@ MessagePacketResult setMacAddressRegistryValueSz(boost::archive::text_iarchive & { MessagePacketResult mpr; - CMD_SET_MAC_ADDRESS_REGISTRY_VALUE_SZ cmdSetMacAddressRegistryValueSz; - ia >> cmdSetMacAddressRegistryValueSz; + CMD_SET_MAC_ADDRESS_REGISTRY_VALUE_SZ cmd; + ia >> cmd; + + // Verify we've received a valid subkey for this Registry key. + if (!Registry::subkeyExists(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", cmd.szInterfaceName)) { + Logger::instance().out(L"setMacAddressRegistryValueSz did not find key %s", cmd.szInterfaceName.c_str()); + return mpr; + } - std::wstring keyPath = L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\" + cmdSetMacAddressRegistryValueSz.szInterfaceName; + if (!Utils::isMacAddress(cmd.szValue)) { + Logger::instance().out(L"setMacAddressRegistryValueSz received an invalid MAC address %s", cmd.szValue.c_str()); + return mpr; + } + + std::wstring keyPath = L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\" + cmd.szInterfaceName; std::wstring propertyName = L"NetworkAddress"; - std::wstring propertyValue = cmdSetMacAddressRegistryValueSz.szValue; + std::wstring propertyValue = cmd.szValue; mpr.success = Registry::regWriteSzProperty(HKEY_LOCAL_MACHINE, keyPath.c_str(), propertyName, propertyValue); @@ -518,11 +529,17 @@ MessagePacketResult removeMacAddressRegistryProperty(boost::archive::text_iarchi { MessagePacketResult mpr; - CMD_REMOVE_MAC_ADDRESS_REGISTRY_PROPERTY cmdRemoveMacAddressRegistryProperty; - ia >> cmdRemoveMacAddressRegistryProperty; + CMD_REMOVE_MAC_ADDRESS_REGISTRY_PROPERTY cmd; + ia >> cmd; + + // Verify we've received a valid subkey for this Registry key. + if (!Registry::subkeyExists(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", cmd.szInterfaceName)) { + Logger::instance().out(L"removeMacAddressRegistryProperty did not find key %s", cmd.szInterfaceName.c_str()); + return mpr; + } std::wstring propertyName = L"NetworkAddress"; - std::wstring keyPath = L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\" + cmdRemoveMacAddressRegistryProperty.szInterfaceName; + std::wstring keyPath = L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\" + cmd.szInterfaceName; wchar_t keyPathSz[128]; wcsncpy_s(keyPathSz, 128, keyPath.c_str(), _TRUNCATE); diff --git a/backend/windows/windscribe_service/process_command.h b/backend/windows/windscribe_service/process_command.h index c01de7338..82c150784 100644 --- a/backend/windows/windscribe_service/process_command.h +++ b/backend/windows/windscribe_service/process_command.h @@ -55,7 +55,6 @@ MessagePacketResult closeTcpConnections(boost::archive::text_iarchive &ia); MessagePacketResult enumProcesses(boost::archive::text_iarchive &ia); MessagePacketResult taskKill(boost::archive::text_iarchive &ia); MessagePacketResult setMetric(boost::archive::text_iarchive &ia); -MessagePacketResult wmicEnable(boost::archive::text_iarchive &ia); MessagePacketResult wmicGetConfigErrorCode(boost::archive::text_iarchive &ia); MessagePacketResult enableBfe(boost::archive::text_iarchive &ia); MessagePacketResult runOpenvpn(boost::archive::text_iarchive &ia); @@ -111,7 +110,6 @@ static const std::map + +#include "logger.h" +#include "utils.h" +#include "utils/wsscopeguard.h" using namespace std; -bool Registry::regWriteDwordProperty(HKEY h, const wstring &subkeyName, const wstring &valueName, DWORD value) +namespace Registry +{ + +// TODO **JDRM** (tech debt) refactor these methods to use the winreg class. + +bool regWriteDwordProperty(HKEY h, const wstring &subkeyName, const wstring &valueName, DWORD value) { HKEY hKey{ NULL }; - auto exitGuard = wsl::wsScopeGuard([&] - { - if (hKey != NULL) - RegCloseKey(hKey); - }); + auto exitGuard = wsl::wsScopeGuard([&] { + if (hKey != NULL) + RegCloseKey(hKey); + }); LONG nError = RegOpenKeyEx(h, subkeyName.c_str(), NULL, KEY_ALL_ACCESS, &hKey); @@ -36,14 +43,13 @@ bool Registry::regWriteDwordProperty(HKEY h, const wstring &subkeyName, const ws } } -bool Registry::regWriteSzProperty(HKEY h, const wchar_t * subkeyName, const wstring &valueName, const wstring &value) +bool regWriteSzProperty(HKEY h, const wchar_t * subkeyName, const wstring &valueName, const wstring &value) { HKEY hKey{ NULL }; - auto exitGuard = wsl::wsScopeGuard([&] - { - if (hKey != NULL) - RegCloseKey(hKey); - }); + auto exitGuard = wsl::wsScopeGuard([&] { + if (hKey != NULL) + RegCloseKey(hKey); + }); LONG nError = RegOpenKeyEx(h, subkeyName, NULL, KEY_ALL_ACCESS, &hKey); @@ -69,14 +75,13 @@ bool Registry::regWriteSzProperty(HKEY h, const wchar_t * subkeyName, const wstr } // todo Function returns true if prop was not removed and false otherwise. Probably it should be changed. -bool Registry::regDeleteProperty(HKEY h, const wstring &subkeyName, const wstring &valueName) +bool regDeleteProperty(HKEY h, const wstring &subkeyName, const wstring &valueName) { HKEY hKey{ NULL }; - auto exitGuard = wsl::wsScopeGuard([&] - { - if (hKey != NULL) - RegCloseKey(hKey); - }); + auto exitGuard = wsl::wsScopeGuard([&] { + if (hKey != NULL) + RegCloseKey(hKey); + }); LONG nError = RegOpenKeyEx(h, subkeyName.c_str(), 0, KEY_SET_VALUE, &hKey); @@ -97,14 +102,13 @@ bool Registry::regDeleteProperty(HKEY h, const wstring &subkeyName, const wstrin } } -bool Registry::regGetProperty(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName, LPBYTE value, DWORD* size) +bool regGetProperty(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName, LPBYTE value, DWORD* size) { HKEY hKey{ NULL }; - auto exitGuard = wsl::wsScopeGuard([&] - { - if (hKey != NULL) - RegCloseKey(hKey); - }); + auto exitGuard = wsl::wsScopeGuard([&] { + if (hKey != NULL) + RegCloseKey(hKey); + }); LONG nError = RegOpenKeyEx(h, subkeyName.c_str(), 0, KEY_READ, &hKey); @@ -124,7 +128,31 @@ bool Registry::regGetProperty(HKEY h, const std::wstring& subkeyName, const std: return true; } -bool Registry::regAddDwordValueIfNotExists(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName) +bool regAddDwordValueIfNotExists(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName) { return regWriteDwordProperty(h, subkeyName, valueName, 0); } + +bool subkeyExists(HKEY rootKey, const std::wstring& parentKey, const std::wstring& subkey) +{ + bool exists = false; + try { + winreg::RegKey registry; + registry.Open(rootKey, parentKey); + const auto subkeys = registry.EnumSubKeys(); + for (const auto &key : subkeys) { + // Perform a case-insensitive search since registry key paths are case-insensitive. + if (Utils::iequals(key, subkey)) { + exists = true; + break; + } + } + } + catch (winreg::RegException &ex) { + Logger::instance().out(L"subkeyExists error checking key %s: %hs", parentKey.c_str(), ex.what()); + } + + return exists; +} + +}; diff --git a/backend/windows/windscribe_service/registry.h b/backend/windows/windscribe_service/registry.h index 4c7c0e801..a363896f9 100644 --- a/backend/windows/windscribe_service/registry.h +++ b/backend/windows/windscribe_service/registry.h @@ -3,13 +3,16 @@ #include #include -class Registry +namespace Registry { - public: - static bool regWriteDwordProperty(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName, DWORD value); - static bool regWriteSzProperty(HKEY h, const wchar_t *subkeyName, const std::wstring& valueName, const std::wstring& value); - static bool regDeleteProperty(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName); - static bool regGetProperty(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName, LPBYTE value, DWORD* size); - static bool regAddDwordValueIfNotExists(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName); +bool regWriteDwordProperty(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName, DWORD value); +bool regWriteSzProperty(HKEY h, const wchar_t *subkeyName, const std::wstring& valueName, const std::wstring& value); +bool regDeleteProperty(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName); +bool regGetProperty(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName, LPBYTE value, DWORD* size); +bool regAddDwordValueIfNotExists(HKEY h, const std::wstring& subkeyName, const std::wstring& valueName); + +// Returns true if the given parent key contains the subkey. +bool subkeyExists(HKEY rootKey, const std::wstring &parentKey, const std::wstring& subkey); + }; diff --git a/backend/windows/windscribe_service/utils.cpp b/backend/windows/windscribe_service/utils.cpp index 3fcc98d99..ca3baa8d3 100644 --- a/backend/windows/windscribe_service/utils.cpp +++ b/backend/windows/windscribe_service/utils.cpp @@ -1,13 +1,19 @@ #include "all_headers.h" #include "utils.h" -#include "logger.h" -#include + #include +#include +#include +#include #include -#include #include -#include "../../../client/common/utils/executable_signature/executable_signature.h" -#include "../../../client/common/utils/win32handle.h" +#include + +#include + +#include "logger.h" +#include "utils/executable_signature/executable_signature.h" +#include "utils/win32handle.h" #pragma comment(lib, "wbemuuid.lib") @@ -533,4 +539,32 @@ std::wstring getSystemDir() return std::wstring(path); } +bool isMacAddress(const std::wstring &value) +{ + bool valid = false; + + if (value.find_first_of(L":-") == std::wstring::npos) { + if (value.size() == 12) { + const auto result = std::count_if(value.begin(), value.end(), [](wint_t c){ return std::iswxdigit(c); }); + valid = (result == 12); + } + } + else { + // We expect the MAC address in AA-BB-CC-DD-EE-FF format, with the separator being a '-' or ':'. + if (value.size() == 17) { + // Convert to the non-DIX standard "-" notation required by the IP Helper API. + std::wstring mac(value); + std::replace(mac.begin(), mac.end(), L':', L'-'); + + // Let the Windows API do the validation for us. + PCWSTR terminator = NULL; + DL_EUI48 addr; + auto status = ::RtlEthernetStringToAddressW(mac.c_str(), &terminator, &addr); + valid = (status == ERROR_SUCCESS); + } + } + + return valid; +} + } diff --git a/backend/windows/windscribe_service/utils.h b/backend/windows/windscribe_service/utils.h index ca8f6f788..e2c7d2656 100644 --- a/backend/windows/windscribe_service/utils.h +++ b/backend/windows/windscribe_service/utils.h @@ -30,6 +30,7 @@ namespace Utils bool hasWhitespaceInString(std::wstring &str); bool verifyWindscribeProcessPath(HANDLE hPipe); bool iequals(const std::wstring &a, const std::wstring &b); + bool isMacAddress(const std::wstring &value); void callNetworkAdapterMethod(const std::wstring &methodName, const std::wstring &adapterRegistryName); GUID guidFromString(const std::wstring &str); diff --git a/client/common/changelog.txt b/client/common/changelog.txt index 42afc21de..e72f9fdc6 100644 --- a/client/common/changelog.txt +++ b/client/common/changelog.txt @@ -1,3 +1,18 @@ +2.10.10 (15/05/2024) +All: + * Fixed wsnet bugs, in particular the icmp ping bug. Also other library refactoring related improvements taken from 2.11. #999 + * Improved internal error handling. #987 +Windows: + * Added security warning in the installer when installing to a custom folder. #988 + * Added debugging information for wsnet. #1001 + * Fixed openvpn adapter IP assertion. #997 + * Fixed privilege escalation vulnerability allowing an attacker to inject a DLL into the client app and task kill any process (Reported by Zeze Lin). #984 +MacOS: + * Fixed not adding the windscribe group in the helper. #1004 +Linux: + * Fixed GNOME/NetworkManager may show a scary message when disconnecting WireGuard. #996 + + 2.10.9 (29/04/2024) All: * Improved limit of 50 split tunnel entries to only apply to hostnames. #437 diff --git a/client/common/legacy_protobuf_support/types.pb-c.c b/client/common/legacy_protobuf_support/types.pb-c.c index 55915ceb8..7e675fadc 100644 --- a/client/common/legacy_protobuf_support/types.pb-c.c +++ b/client/common/legacy_protobuf_support/types.pb-c.c @@ -5018,95 +5018,13 @@ const ProtobufCEnumDescriptor proto_types__client_id__descriptor = static const ProtobufCEnumValue proto_types__connect_error__enum_values_by_number[42] = { { "NO_CONNECT_ERROR", "PROTO_TYPES__CONNECT_ERROR__NO_CONNECT_ERROR", 0 }, - { "AUTH_ERROR", "PROTO_TYPES__CONNECT_ERROR__AUTH_ERROR", 1 }, - { "COULD_NOT_FETCH_CREDENTAILS", "PROTO_TYPES__CONNECT_ERROR__COULD_NOT_FETCH_CREDENTAILS", 2 }, - { "LOCATION_NOT_EXIST", "PROTO_TYPES__CONNECT_ERROR__LOCATION_NOT_EXIST", 3 }, - { "LOCATION_NO_ACTIVE_NODES", "PROTO_TYPES__CONNECT_ERROR__LOCATION_NO_ACTIVE_NODES", 4 }, - { "CANT_RESOLVE_HOSTNAME", "PROTO_TYPES__CONNECT_ERROR__CANT_RESOLVE_HOSTNAME", 5 }, - { "CONNECTION_BLOCKED", "PROTO_TYPES__CONNECT_ERROR__CONNECTION_BLOCKED", 6 }, - { "NO_OPENVPN_SOCKET", "PROTO_TYPES__CONNECT_ERROR__NO_OPENVPN_SOCKET", 7 }, - { "CANT_RUN_OPENVPN", "PROTO_TYPES__CONNECT_ERROR__CANT_RUN_OPENVPN", 8 }, - { "CANNOT_ALLOCATE_TUN_TAP", "PROTO_TYPES__CONNECT_ERROR__CANNOT_ALLOCATE_TUN_TAP", 9 }, - { "NO_INSTALLED_TUN_TAP", "PROTO_TYPES__CONNECT_ERROR__NO_INSTALLED_TUN_TAP", 10 }, - { "ALL_TAP_IN_USE", "PROTO_TYPES__CONNECT_ERROR__ALL_TAP_IN_USE", 11 }, - { "CANNOT_CONNECT_TO_SERVICE_PIPE", "PROTO_TYPES__CONNECT_ERROR__CANNOT_CONNECT_TO_SERVICE_PIPE", 12 }, - { "CANNOT_WRITE_TO_SERVICE_PIPE", "PROTO_TYPES__CONNECT_ERROR__CANNOT_WRITE_TO_SERVICE_PIPE", 13 }, - { "NO_AVAILABLE_PORT", "PROTO_TYPES__CONNECT_ERROR__NO_AVAILABLE_PORT", 14 }, - { "PROXY_AUTH_ERROR", "PROTO_TYPES__CONNECT_ERROR__PROXY_AUTH_ERROR", 15 }, - { "UDP_CANT_ASSIGN", "PROTO_TYPES__CONNECT_ERROR__UDP_CANT_ASSIGN", 16 }, - { "CONNECTED_ERROR", "PROTO_TYPES__CONNECT_ERROR__CONNECTED_ERROR", 17 }, - { "INITIALIZATION_SEQUENCE_COMPLETED_WITH_ERRORS", "PROTO_TYPES__CONNECT_ERROR__INITIALIZATION_SEQUENCE_COMPLETED_WITH_ERRORS", 18 }, - { "UDP_NO_BUFFER_SPACE", "PROTO_TYPES__CONNECT_ERROR__UDP_NO_BUFFER_SPACE", 19 }, - { "UDP_NETWORK_DOWN", "PROTO_TYPES__CONNECT_ERROR__UDP_NETWORK_DOWN", 20 }, - { "TCP_ERROR", "PROTO_TYPES__CONNECT_ERROR__TCP_ERROR", 21 }, - { "CANNOT_OPEN_CUSTOM_CONFIG", "PROTO_TYPES__CONNECT_ERROR__CANNOT_OPEN_CUSTOM_CONFIG", 22 }, - { "IKEV_FAILED_TO_CONNECT", "PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_TO_CONNECT", 23 }, - { "IKEV_NOT_FOUND_WIN", "PROTO_TYPES__CONNECT_ERROR__IKEV_NOT_FOUND_WIN", 24 }, - { "IKEV_FAILED_SET_ENTRY_WIN", "PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_SET_ENTRY_WIN", 25 }, - { "IKEV_FAILED_MODIFY_HOSTS_WIN", "PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_MODIFY_HOSTS_WIN", 26 }, - { "IKEV_NETWORK_EXTENSION_NOT_FOUND_MAC", "PROTO_TYPES__CONNECT_ERROR__IKEV_NETWORK_EXTENSION_NOT_FOUND_MAC", 27 }, - { "IKEV_FAILED_SET_KEYCHAIN_MAC", "PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_SET_KEYCHAIN_MAC", 28 }, - { "IKEV_FAILED_START_MAC", "PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_START_MAC", 29 }, - { "IKEV_FAILED_LOAD_PREFERENCES_MAC", "PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_LOAD_PREFERENCES_MAC", 30 }, - { "IKEV_FAILED_SAVE_PREFERENCES_MAC", "PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_SAVE_PREFERENCES_MAC", 31 }, - { "WIREGUARD_CONNECTION_ERROR", "PROTO_TYPES__CONNECT_ERROR__WIREGUARD_CONNECTION_ERROR", 32 }, - { "EMERGENCY_FAILED_CONNECT", "PROTO_TYPES__CONNECT_ERROR__EMERGENCY_FAILED_CONNECT", 33 }, - { "WINTUN_OVER_CAPACITY", "PROTO_TYPES__CONNECT_ERROR__WINTUN_OVER_CAPACITY", 34 }, - { "WINTUN_DRIVER_REINSTALLATION_ERROR", "PROTO_TYPES__CONNECT_ERROR__WINTUN_DRIVER_REINSTALLATION_ERROR", 35 }, - { "TAP_DRIVER_REINSTALLATION_ERROR", "PROTO_TYPES__CONNECT_ERROR__TAP_DRIVER_REINSTALLATION_ERROR", 36 }, - { "WINTUN_FATAL_ERROR", "PROTO_TYPES__CONNECT_ERROR__WINTUN_FATAL_ERROR", 37 }, - { "EXE_VERIFY_WSTUNNEL_ERROR", "PROTO_TYPES__CONNECT_ERROR__EXE_VERIFY_WSTUNNEL_ERROR", 38 }, - { "EXE_VERIFY_STUNNEL_ERROR", "PROTO_TYPES__CONNECT_ERROR__EXE_VERIFY_STUNNEL_ERROR", 39 }, - { "EXE_VERIFY_OPENVPN_ERROR", "PROTO_TYPES__CONNECT_ERROR__EXE_VERIFY_OPENVPN_ERROR", 40 }, - { "EXE_VERIFY_WIREGUARD_ERROR", "PROTO_TYPES__CONNECT_ERROR__EXE_VERIFY_WIREGUARD_ERROR", 41 }, }; static const ProtobufCIntRange proto_types__connect_error__value_ranges[] = { -{0, 0},{0, 42} +{0, 0},{0, 0} }; static const ProtobufCEnumValueIndex proto_types__connect_error__enum_values_by_name[42] = { - { "ALL_TAP_IN_USE", 11 }, - { "AUTH_ERROR", 1 }, - { "CANNOT_ALLOCATE_TUN_TAP", 9 }, - { "CANNOT_CONNECT_TO_SERVICE_PIPE", 12 }, - { "CANNOT_OPEN_CUSTOM_CONFIG", 22 }, - { "CANNOT_WRITE_TO_SERVICE_PIPE", 13 }, - { "CANT_RESOLVE_HOSTNAME", 5 }, - { "CANT_RUN_OPENVPN", 8 }, - { "CONNECTED_ERROR", 17 }, - { "CONNECTION_BLOCKED", 6 }, - { "COULD_NOT_FETCH_CREDENTAILS", 2 }, - { "EMERGENCY_FAILED_CONNECT", 33 }, - { "EXE_VERIFY_OPENVPN_ERROR", 40 }, - { "EXE_VERIFY_STUNNEL_ERROR", 39 }, - { "EXE_VERIFY_WIREGUARD_ERROR", 41 }, - { "EXE_VERIFY_WSTUNNEL_ERROR", 38 }, - { "IKEV_FAILED_LOAD_PREFERENCES_MAC", 30 }, - { "IKEV_FAILED_MODIFY_HOSTS_WIN", 26 }, - { "IKEV_FAILED_SAVE_PREFERENCES_MAC", 31 }, - { "IKEV_FAILED_SET_ENTRY_WIN", 25 }, - { "IKEV_FAILED_SET_KEYCHAIN_MAC", 28 }, - { "IKEV_FAILED_START_MAC", 29 }, - { "IKEV_FAILED_TO_CONNECT", 23 }, - { "IKEV_NETWORK_EXTENSION_NOT_FOUND_MAC", 27 }, - { "IKEV_NOT_FOUND_WIN", 24 }, - { "INITIALIZATION_SEQUENCE_COMPLETED_WITH_ERRORS", 18 }, - { "LOCATION_NOT_EXIST", 3 }, - { "LOCATION_NO_ACTIVE_NODES", 4 }, - { "NO_AVAILABLE_PORT", 14 }, { "NO_CONNECT_ERROR", 0 }, - { "NO_INSTALLED_TUN_TAP", 10 }, - { "NO_OPENVPN_SOCKET", 7 }, - { "PROXY_AUTH_ERROR", 15 }, - { "TAP_DRIVER_REINSTALLATION_ERROR", 36 }, - { "TCP_ERROR", 21 }, - { "UDP_CANT_ASSIGN", 16 }, - { "UDP_NETWORK_DOWN", 20 }, - { "UDP_NO_BUFFER_SPACE", 19 }, - { "WINTUN_DRIVER_REINSTALLATION_ERROR", 35 }, - { "WINTUN_FATAL_ERROR", 37 }, - { "WINTUN_OVER_CAPACITY", 34 }, - { "WIREGUARD_CONNECTION_ERROR", 32 }, }; const ProtobufCEnumDescriptor proto_types__connect_error__descriptor = { diff --git a/client/common/legacy_protobuf_support/types.pb-c.h b/client/common/legacy_protobuf_support/types.pb-c.h index fdc025ece..bbc270d52 100644 --- a/client/common/legacy_protobuf_support/types.pb-c.h +++ b/client/common/legacy_protobuf_support/types.pb-c.h @@ -69,63 +69,7 @@ typedef enum _ProtoTypes__ClientId { PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(PROTO_TYPES__CLIENT_ID) } ProtoTypes__ClientId; typedef enum _ProtoTypes__ConnectError { - /* - * common - */ - PROTO_TYPES__CONNECT_ERROR__NO_CONNECT_ERROR = 0, - PROTO_TYPES__CONNECT_ERROR__AUTH_ERROR = 1, - PROTO_TYPES__CONNECT_ERROR__COULD_NOT_FETCH_CREDENTAILS = 2, - PROTO_TYPES__CONNECT_ERROR__LOCATION_NOT_EXIST = 3, - PROTO_TYPES__CONNECT_ERROR__LOCATION_NO_ACTIVE_NODES = 4, - PROTO_TYPES__CONNECT_ERROR__CANT_RESOLVE_HOSTNAME = 5, - PROTO_TYPES__CONNECT_ERROR__CONNECTION_BLOCKED = 6, - /* - * openvpn - */ - PROTO_TYPES__CONNECT_ERROR__NO_OPENVPN_SOCKET = 7, - PROTO_TYPES__CONNECT_ERROR__CANT_RUN_OPENVPN = 8, - PROTO_TYPES__CONNECT_ERROR__CANNOT_ALLOCATE_TUN_TAP = 9, - PROTO_TYPES__CONNECT_ERROR__NO_INSTALLED_TUN_TAP = 10, - PROTO_TYPES__CONNECT_ERROR__ALL_TAP_IN_USE = 11, - PROTO_TYPES__CONNECT_ERROR__CANNOT_CONNECT_TO_SERVICE_PIPE = 12, - PROTO_TYPES__CONNECT_ERROR__CANNOT_WRITE_TO_SERVICE_PIPE = 13, - PROTO_TYPES__CONNECT_ERROR__NO_AVAILABLE_PORT = 14, - PROTO_TYPES__CONNECT_ERROR__PROXY_AUTH_ERROR = 15, - PROTO_TYPES__CONNECT_ERROR__UDP_CANT_ASSIGN = 16, - PROTO_TYPES__CONNECT_ERROR__CONNECTED_ERROR = 17, - PROTO_TYPES__CONNECT_ERROR__INITIALIZATION_SEQUENCE_COMPLETED_WITH_ERRORS = 18, - PROTO_TYPES__CONNECT_ERROR__UDP_NO_BUFFER_SPACE = 19, - PROTO_TYPES__CONNECT_ERROR__UDP_NETWORK_DOWN = 20, - PROTO_TYPES__CONNECT_ERROR__TCP_ERROR = 21, - PROTO_TYPES__CONNECT_ERROR__CANNOT_OPEN_CUSTOM_CONFIG = 22, - /* - * ikev2 - */ - PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_TO_CONNECT = 23, - PROTO_TYPES__CONNECT_ERROR__IKEV_NOT_FOUND_WIN = 24, - PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_SET_ENTRY_WIN = 25, - PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_MODIFY_HOSTS_WIN = 26, - PROTO_TYPES__CONNECT_ERROR__IKEV_NETWORK_EXTENSION_NOT_FOUND_MAC = 27, - PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_SET_KEYCHAIN_MAC = 28, - PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_START_MAC = 29, - PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_LOAD_PREFERENCES_MAC = 30, - PROTO_TYPES__CONNECT_ERROR__IKEV_FAILED_SAVE_PREFERENCES_MAC = 31, - /* - * wireguard - */ - PROTO_TYPES__CONNECT_ERROR__WIREGUARD_CONNECTION_ERROR = 32, - /* - * emergency - */ - PROTO_TYPES__CONNECT_ERROR__EMERGENCY_FAILED_CONNECT = 33, - PROTO_TYPES__CONNECT_ERROR__WINTUN_OVER_CAPACITY = 34, - PROTO_TYPES__CONNECT_ERROR__WINTUN_DRIVER_REINSTALLATION_ERROR = 35, - PROTO_TYPES__CONNECT_ERROR__TAP_DRIVER_REINSTALLATION_ERROR = 36, - PROTO_TYPES__CONNECT_ERROR__WINTUN_FATAL_ERROR = 37, - PROTO_TYPES__CONNECT_ERROR__EXE_VERIFY_WSTUNNEL_ERROR = 38, - PROTO_TYPES__CONNECT_ERROR__EXE_VERIFY_STUNNEL_ERROR = 39, - PROTO_TYPES__CONNECT_ERROR__EXE_VERIFY_OPENVPN_ERROR = 40, - PROTO_TYPES__CONNECT_ERROR__EXE_VERIFY_WIREGUARD_ERROR = 41 + PROTO_TYPES__CONNECT_ERROR__NO_CONNECT_ERROR = 0 PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(PROTO_TYPES__CONNECT_ERROR) } ProtoTypes__ConnectError; typedef enum _ProtoTypes__DisconnectReason { diff --git a/client/common/types/enums.h b/client/common/types/enums.h index e76a6ac32..f8848d49f 100644 --- a/client/common/types/enums.h +++ b/client/common/types/enums.h @@ -61,50 +61,38 @@ enum DISCONNECT_REASON { enum CONNECT_ERROR { NO_CONNECT_ERROR = 0, AUTH_ERROR = 1, - COULD_NOT_FETCH_CREDENTAILS = 2, - LOCATION_NOT_EXIST = 3, - LOCATION_NO_ACTIVE_NODES = 4, - CANT_RESOLVE_HOSTNAME = 5, - CONNECTION_BLOCKED = 6, - NO_OPENVPN_SOCKET = 7, - CANT_RUN_OPENVPN = 8, - CANNOT_ALLOCATE_TUN_TAP = 9, - NO_INSTALLED_TUN_TAP = 10, - ALL_TAP_IN_USE = 11, - CANNOT_CONNECT_TO_SERVICE_PIPE = 12, - CANNOT_WRITE_TO_SERVICE_PIPE = 13, - NO_AVAILABLE_PORT = 14, - PROXY_AUTH_ERROR = 15, - UDP_CANT_ASSIGN = 16, - CONNECTED_ERROR = 17, - INITIALIZATION_SEQUENCE_COMPLETED_WITH_ERRORS = 18, - UDP_NO_BUFFER_SPACE = 19, - UDP_NETWORK_DOWN = 20, - TCP_ERROR = 21, - CANNOT_OPEN_CUSTOM_CONFIG = 22, - IKEV_FAILED_TO_CONNECT = 23, - IKEV_NOT_FOUND_WIN = 24, - IKEV_FAILED_SET_ENTRY_WIN = 25, - IKEV_FAILED_MODIFY_HOSTS_WIN = 26, - IKEV_NETWORK_EXTENSION_NOT_FOUND_MAC = 27, - IKEV_FAILED_SET_KEYCHAIN_MAC = 28, - IKEV_FAILED_START_MAC = 29, - IKEV_FAILED_LOAD_PREFERENCES_MAC = 30, - IKEV_FAILED_SAVE_PREFERENCES_MAC = 31, - WIREGUARD_CONNECTION_ERROR = 32, - EMERGENCY_FAILED_CONNECT = 33, - WINTUN_OVER_CAPACITY = 34, - WINTUN_FATAL_ERROR = 35, - EXE_VERIFY_WSTUNNEL_ERROR = 36, - EXE_VERIFY_STUNNEL_ERROR = 37, - EXE_VERIFY_OPENVPN_ERROR = 38, - EXE_VERIFY_WIREGUARD_ERROR = 39, - STATE_TIMEOUT_FOR_AUTOMATIC = 40, - WIREGUARD_ADAPTER_SETUP_FAILED = 41, - WIREGUARD_COULD_NOT_RETRIEVE_CONFIG = 42, - CTRLD_START_FAILED = 43, - PRIV_KEY_PASSWORD_ERROR = 44, - LOCKDOWN_MODE_IKEV2 = 45, + LOCATION_NOT_EXIST = 2, + LOCATION_NO_ACTIVE_NODES = 3, + CONNECTION_BLOCKED = 4, + NO_OPENVPN_SOCKET = 5, + EXE_SUBPROCESS_FAILED = 6, + NO_INSTALLED_TUN_TAP = 7, + UDP_CANT_ASSIGN = 8, + CONNECTED_ERROR = 9, + INITIALIZATION_SEQUENCE_COMPLETED_WITH_ERRORS = 10, + UDP_NO_BUFFER_SPACE = 11, + UDP_NETWORK_DOWN = 12, + TCP_ERROR = 13, + CANNOT_OPEN_CUSTOM_CONFIG = 14, + IKEV_FAILED_TO_CONNECT = 15, + IKEV_NOT_FOUND_WIN = 16, + IKEV_FAILED_SET_ENTRY_WIN = 17, + IKEV_FAILED_MODIFY_HOSTS_WIN = 18, + IKEV_NETWORK_EXTENSION_NOT_FOUND_MAC = 19, + IKEV_FAILED_SET_KEYCHAIN_MAC = 20, + IKEV_FAILED_START_MAC = 21, + IKEV_FAILED_LOAD_PREFERENCES_MAC = 22, + IKEV_FAILED_SAVE_PREFERENCES_MAC = 23, + WIREGUARD_CONNECTION_ERROR = 24, + EMERGENCY_FAILED_CONNECT = 25, + WINTUN_OVER_CAPACITY = 26, + WINTUN_FATAL_ERROR = 27, + STATE_TIMEOUT_FOR_AUTOMATIC = 28, + WIREGUARD_ADAPTER_SETUP_FAILED = 29, + WIREGUARD_COULD_NOT_RETRIEVE_CONFIG = 30, + CTRLD_START_FAILED = 31, + PRIV_KEY_PASSWORD_ERROR = 32, + LOCKDOWN_MODE_IKEV2 = 33, }; enum PROXY_SHARING_TYPE { diff --git a/client/common/types/sharesecurehotspot.h b/client/common/types/sharesecurehotspot.h index e2f492135..efe044682 100644 --- a/client/common/types/sharesecurehotspot.h +++ b/client/common/types/sharesecurehotspot.h @@ -25,7 +25,7 @@ struct ShareSecureHotspot ShareSecureHotspot(const QJsonObject &json) { - if (json.contains(jsonInfo.kIsEnabledProp) && json[jsonInfo.kIsEnabledProp].isDouble()) + if (json.contains(jsonInfo.kIsEnabledProp) && json[jsonInfo.kIsEnabledProp].isBool()) isEnabled = json[jsonInfo.kIsEnabledProp].toBool(); if (json.contains(jsonInfo.kSSIDProp) && json[jsonInfo.kSSIDProp].isString()) diff --git a/client/common/utils/crashdump.cpp b/client/common/utils/crashdump.cpp index 1efff68fc..5de697f7c 100644 --- a/client/common/utils/crashdump.cpp +++ b/client/common/utils/crashdump.cpp @@ -42,7 +42,7 @@ class CrashDumpInternal CrashDumpInternal::CrashDumpInternal() { - dbgHelpHandle_ = ::LoadLibrary(TEXT("dbghelp.dll")); + dbgHelpHandle_ = ::LoadLibraryEx(L"dbghelp.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (dbgHelpHandle_) { fnImagehlpApiVersionEx_ = reinterpret_cast( GetProcAddress(dbgHelpHandle_, "ImagehlpApiVersionEx")); diff --git a/client/common/utils/crashhandler.cpp b/client/common/utils/crashhandler.cpp index 790432d21..9eb2677bc 100644 --- a/client/common/utils/crashhandler.cpp +++ b/client/common/utils/crashhandler.cpp @@ -177,7 +177,7 @@ CrashHandler::CrashHandler() typedef BOOL(WINAPI * GETPROCESSUSERMODEEXCEPTIONPOLICY)(LPDWORD lpFlags); const DWORD kProcessCallbackFilterEnabled = 1u; - auto hKernel32 = LoadLibrary(TEXT("kernel32.dll")); + auto hKernel32 = LoadLibraryEx(L"kernel32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (hKernel32) { SETPROCESSUSERMODEEXCEPTIONPOLICY pfnSetProcessUserModeExceptionPolicy = (SETPROCESSUSERMODEEXCEPTIONPOLICY)GetProcAddress( diff --git a/client/common/version/windscribe_version.h b/client/common/version/windscribe_version.h index b325d6819..a3b716b2c 100644 --- a/client/common/version/windscribe_version.h +++ b/client/common/version/windscribe_version.h @@ -2,7 +2,7 @@ #define WINDSCRIBE_MAJOR_VERSION 2 #define WINDSCRIBE_MINOR_VERSION 10 -#define WINDSCRIBE_BUILD_VERSION 9 +#define WINDSCRIBE_BUILD_VERSION 10 // only one of these should be enabled; neither -> stable //#define WINDSCRIBE_IS_BETA diff --git a/client/engine/engine/connectionmanager/connectionmanager.cpp b/client/engine/engine/connectionmanager/connectionmanager.cpp index 2062a6074..5b89947b4 100644 --- a/client/engine/engine/connectionmanager/connectionmanager.cpp +++ b/client/engine/engine/connectionmanager/connectionmanager.cpp @@ -555,10 +555,8 @@ void ConnectionManager::onConnectionError(CONNECT_ERROR err) testVPNTunnel_->stopTests(); if ((err == CONNECT_ERROR::AUTH_ERROR && bEmitAuthError_) - || err == CONNECT_ERROR::CANT_RUN_OPENVPN || err == CONNECT_ERROR::NO_OPENVPN_SOCKET || err == CONNECT_ERROR::NO_INSTALLED_TUN_TAP - || err == CONNECT_ERROR::ALL_TAP_IN_USE || (!connSettingsPolicy_->isAutomaticMode() && err == CONNECT_ERROR::WIREGUARD_CONNECTION_ERROR) || (!connSettingsPolicy_->isAutomaticMode() && err == CONNECT_ERROR::WIREGUARD_ADAPTER_SETUP_FAILED) || err == CONNECT_ERROR::WINTUN_FATAL_ERROR @@ -577,8 +575,7 @@ void ConnectionManager::onConnectionError(CONNECT_ERROR err) || err == CONNECT_ERROR::IKEV_FAILED_START_MAC || err == CONNECT_ERROR::IKEV_FAILED_LOAD_PREFERENCES_MAC || err == CONNECT_ERROR::IKEV_FAILED_SAVE_PREFERENCES_MAC)) - || (!connSettingsPolicy_->isAutomaticMode() && err == CONNECT_ERROR::EXE_VERIFY_OPENVPN_ERROR) - || err == CONNECT_ERROR::EXE_VERIFY_WIREGUARD_ERROR) + || err == CONNECT_ERROR::EXE_SUBPROCESS_FAILED) { // immediately stop trying to connect disconnect(); @@ -1012,7 +1009,7 @@ void ConnectionManager::doConnectPart2() if (!stunnelManager_->runProcess(currentConnectionDescr_.ip, currentConnectionDescr_.port, ExtraConfig::instance().getStealthExtraTLSPadding() || isAntiCensorship_)) { disconnect(); - emit errorDuringConnection(CONNECT_ERROR::EXE_VERIFY_STUNNEL_ERROR); + emit errorDuringConnection(CONNECT_ERROR::EXE_SUBPROCESS_FAILED); return; } // call doConnectPart2 in onWstunnelStarted slot @@ -1020,7 +1017,7 @@ void ConnectionManager::doConnectPart2() } else if (currentConnectionDescr_.protocol == types::Protocol::WSTUNNEL) { if (!wstunnelManager_->runProcess(currentConnectionDescr_.ip, currentConnectionDescr_.port)) { disconnect(); - emit errorDuringConnection(CONNECT_ERROR::EXE_VERIFY_WSTUNNEL_ERROR); + emit errorDuringConnection(CONNECT_ERROR::EXE_SUBPROCESS_FAILED); return; } // call doConnectPart2 in onWstunnelStarted slot diff --git a/client/engine/engine/connectionmanager/finishactiveconnections.cpp b/client/engine/engine/connectionmanager/finishactiveconnections.cpp index e4d30af13..4a5d9ca9e 100644 --- a/client/engine/engine/connectionmanager/finishactiveconnections.cpp +++ b/client/engine/engine/connectionmanager/finishactiveconnections.cpp @@ -40,8 +40,7 @@ void FinishActiveConnections::finishAllActiveConnections_win(IHelper *helper) void FinishActiveConnections::finishOpenVpnActiveConnections_win(IHelper *helper) { Helper_win *helper_win = dynamic_cast(helper); - const QString fileName = OpenVpnVersionController::instance().getOpenVpnFileName(); - helper_win->executeTaskKill(fileName); + helper_win->executeTaskKill(kTargetOpenVpn); } void FinishActiveConnections::finishIkev2ActiveConnections_win(IHelper *helper) diff --git a/client/engine/engine/connectionmanager/openvpnconnection.cpp b/client/engine/engine/connectionmanager/openvpnconnection.cpp index 989566c07..6dfc754f6 100644 --- a/client/engine/engine/connectionmanager/openvpnconnection.cpp +++ b/client/engine/engine/connectionmanager/openvpnconnection.cpp @@ -188,7 +188,7 @@ void OpenVPNConnection::onKillControllerTimer() killControllerTimer_.stop(); #ifdef Q_OS_WIN Helper_win *helper_win= dynamic_cast(helper_); - helper_win->executeTaskKill(OpenVpnVersionController::instance().getOpenVpnFileName()); + helper_win->executeTaskKill(kTargetOpenVpn); #else Helper_posix *helper_posix = dynamic_cast(helper_); helper_posix->executeTaskKill(kTargetOpenVpn); @@ -211,17 +211,10 @@ void OpenVPNConnection::funcRunOpenVPN() { qCDebug(LOG_CONNECTION) << "Can't run OpenVPN"; - // don't bother re-attempting if signature is invalid - if (err == IHelper::EXECUTE_VERIFY_ERROR) - { - setCurrentStateAndEmitError(STATUS_DISCONNECTED, CONNECT_ERROR::EXE_VERIFY_OPENVPN_ERROR); - return; - } - if (retries >= 2) { qCDebug(LOG_CONNECTION) << "Can't run openvpn process"; - setCurrentStateAndEmitError(STATUS_DISCONNECTED, CONNECT_ERROR::CANT_RUN_OPENVPN); + setCurrentStateAndEmitError(STATUS_DISCONNECTED, CONNECT_ERROR::EXE_SUBPROCESS_FAILED); return; } if (bStopThread_) @@ -585,10 +578,6 @@ void OpenVPNConnection::handleRead(const boost::system::error_code &err, size_t setCurrentStateAndEmitDisconnected(STATUS_DISCONNECTED); } } - else if (serverReply.contains(">FATAL:All tap-windows6 adapters on this system are currently in use", Qt::CaseInsensitive)) - { - emit error(CONNECT_ERROR::ALL_TAP_IN_USE); - } else if (serverReply.contains(">FATAL:All wintun adapters on this system are currently in use", Qt::CaseInsensitive)) { emit error(CONNECT_ERROR::WINTUN_FATAL_ERROR); diff --git a/client/engine/engine/connectionmanager/wireguardconnection_posix.cpp b/client/engine/engine/connectionmanager/wireguardconnection_posix.cpp index 3d6e5e711..3439088c6 100644 --- a/client/engine/engine/connectionmanager/wireguardconnection_posix.cpp +++ b/client/engine/engine/connectionmanager/wireguardconnection_posix.cpp @@ -58,12 +58,6 @@ void WireGuardConnectionImpl::connect() while ((err = host_->helper_->startWireGuard()) != IHelper::EXECUTE_SUCCESS) { - // don't bother another attempt if signature is invalid - if (err == IHelper::EXECUTE_VERIFY_ERROR) - { - host_->setError(EXE_VERIFY_WIREGUARD_ERROR); - return; - } if (retry >= 2) { qCDebug(LOG_WIREGUARD) << "Can't start WireGuard after" << retry << "retries"; diff --git a/client/engine/engine/connectionmanager/wireguardconnection_win.cpp b/client/engine/engine/connectionmanager/wireguardconnection_win.cpp index 520555528..5d369b076 100644 --- a/client/engine/engine/connectionmanager/wireguardconnection_win.cpp +++ b/client/engine/engine/connectionmanager/wireguardconnection_win.cpp @@ -130,8 +130,7 @@ void WireGuardConnection::run() if (err != IHelper::EXECUTE_SUCCESS) { qCDebug(LOG_CONNECTION) << "Windscribe service could not install the WireGuard service"; - emit error((err == IHelper::EXECUTE_VERIFY_ERROR ? CONNECT_ERROR::EXE_VERIFY_WIREGUARD_ERROR - : CONNECT_ERROR::WIREGUARD_CONNECTION_ERROR)); + emit error(CONNECT_ERROR::WIREGUARD_CONNECTION_ERROR); emit disconnected(); return; } diff --git a/client/engine/engine/emergencycontroller/emergencycontroller.cpp b/client/engine/engine/emergencycontroller/emergencycontroller.cpp index 473a2afa1..422aa5163 100644 --- a/client/engine/engine/emergencycontroller/emergencycontroller.cpp +++ b/client/engine/engine/emergencycontroller/emergencycontroller.cpp @@ -203,10 +203,9 @@ void EmergencyController::onConnectionError(CONNECT_ERROR err) connector_->startDisconnect(); if (err == CONNECT_ERROR::AUTH_ERROR - || err == CONNECT_ERROR::CANT_RUN_OPENVPN + || err == CONNECT_ERROR::EXE_SUBPROCESS_FAILED || err == CONNECT_ERROR::NO_OPENVPN_SOCKET - || err == CONNECT_ERROR::NO_INSTALLED_TUN_TAP - || err == CONNECT_ERROR::ALL_TAP_IN_USE) + || err == CONNECT_ERROR::NO_INSTALLED_TUN_TAP) { // emit error in disconnected event state_ = STATE_ERROR_DURING_CONNECTION; diff --git a/client/engine/engine/engine.cpp b/client/engine/engine/engine.cpp index d4911fa43..62ba9aa9e 100644 --- a/client/engine/engine/engine.cpp +++ b/client/engine/engine/engine.cpp @@ -1568,11 +1568,6 @@ void Engine::onConnectionManagerError(CONNECT_ERROR err) connectStateController_->setDisconnectedState(DISCONNECTED_WITH_ERROR, CONNECT_ERROR::WINTUN_FATAL_ERROR); return; } - else if (err == CONNECT_ERROR::ALL_TAP_IN_USE) - { - qCDebug(LOG_BASIC) << "Engine: unexpected CONNECT_ERROR::ALL_TAP_IN_USE error encountered."; - return; - } else if (err == CONNECT_ERROR::WINTUN_FATAL_ERROR) { qCDebug(LOG_BASIC) << "OpenVPN reported the Windscribe wintun adapter as already in use"; diff --git a/client/engine/engine/helper/helper_win.cpp b/client/engine/engine/helper/helper_win.cpp index 9c1dbe2a9..07b5bdf19 100644 --- a/client/engine/engine/helper/helper_win.cpp +++ b/client/engine/engine/helper/helper_win.cpp @@ -65,8 +65,7 @@ Helper_win::STATE Helper_win::currentState() const bool Helper_win::reinstallHelper() { - QString servicePath = QCoreApplication::applicationDirPath() + "/WindscribeService.exe"; - return InstallHelper_win::executeInstallHelperCmd(servicePath); + return InstallHelper_win::executeInstallHelperCmd(); } void Helper_win::setNeedFinish() @@ -335,12 +334,12 @@ IHelper::ExecuteError Helper_win::executeOpenVPN(const QString &config, unsigned return mpr.success ? IHelper::EXECUTE_SUCCESS : IHelper::EXECUTE_ERROR; } -bool Helper_win::executeTaskKill(const QString &executableName) +bool Helper_win::executeTaskKill(CmdKillTarget target) { QMutexLocker locker(&mutex_); CMD_TASK_KILL cmdTaskKill; - cmdTaskKill.szExecutableName = executableName.toStdWString(); + cmdTaskKill.target = target; std::stringstream stream; boost::archive::text_oarchive oa(stream, boost::archive::no_header); @@ -368,21 +367,6 @@ QString Helper_win::executeSetMetric(const QString &interfaceType, const QString return QString::fromLocal8Bit(mpr.additionalString.c_str(), mpr.additionalString.size()); } -QString Helper_win::executeWmicEnable(const QString &adapterName) -{ - QMutexLocker locker(&mutex_); - - CMD_WMIC_ENABLE cmdWmicEnable; - cmdWmicEnable.szAdapterName = adapterName.toStdWString(); - - std::stringstream stream; - boost::archive::text_oarchive oa(stream, boost::archive::no_header); - oa << cmdWmicEnable; - - MessagePacketResult mpr = sendCmdToHelper(AA_COMMAND_WMIC_ENABLE, stream.str()); - return QString::fromLocal8Bit(mpr.additionalString.c_str(), mpr.additionalString.size()); -} - QString Helper_win::executeWmicGetConfigManagerErrorCode(const QString &adapterName) { QMutexLocker locker(&mutex_); diff --git a/client/engine/engine/helper/helper_win.h b/client/engine/engine/helper/helper_win.h index 71551a6ab..7650ba173 100644 --- a/client/engine/engine/helper/helper_win.h +++ b/client/engine/engine/helper/helper_win.h @@ -36,7 +36,7 @@ class Helper_win : public IHelper const QString &connectedIp, const types::Protocol &protocol) override; bool setCustomDnsWhileConnected(unsigned long ifIndex, const QString &overrideDnsIpAddress); bool changeMtu(const QString &adapter, int mtu) override; - bool executeTaskKill(const QString &name); + bool executeTaskKill(CmdKillTarget target); ExecuteError executeOpenVPN(const QString &config, unsigned int port, const QString &httpProxy, unsigned int httpPort, const QString &socksProxy, unsigned int socksPort, unsigned long &outCmdId, bool isCustomConfig) override; @@ -53,7 +53,6 @@ class Helper_win : public IHelper // Windows specific functions bool isHelperConnected() const; QString executeSetMetric(const QString &interfaceType, const QString &interfaceName, const QString &metricNumber); - QString executeWmicEnable(const QString &adapterName); QString executeWmicGetConfigManagerErrorCode(const QString &adapterName); bool isIcsSupported(); diff --git a/client/engine/engine/helper/ihelper.h b/client/engine/engine/helper/ihelper.h index 03606621c..cbf29b9f2 100644 --- a/client/engine/engine/helper/ihelper.h +++ b/client/engine/engine/helper/ihelper.h @@ -23,7 +23,7 @@ class IHelper : public QThread explicit IHelper(QObject *parent = 0) : QThread(parent) {} virtual ~IHelper() {} - enum ExecuteError { EXECUTE_SUCCESS, EXECUTE_ERROR, EXECUTE_VERIFY_ERROR }; + enum ExecuteError { EXECUTE_SUCCESS, EXECUTE_ERROR }; virtual void startInstallHelper() = 0; virtual STATE currentState() const = 0; diff --git a/client/engine/engine/helper/installhelper_win.cpp b/client/engine/engine/helper/installhelper_win.cpp index 782f75173..dea2e83c6 100644 --- a/client/engine/engine/helper/installhelper_win.cpp +++ b/client/engine/engine/helper/installhelper_win.cpp @@ -1,9 +1,7 @@ #include "installhelper_win.h" #include -#include #include -#include #include #include @@ -11,86 +9,65 @@ #include "utils/executable_signature/executable_signature.h" #include "utils/logger.h" -bool InstallHelper_win::checkInstallHelper(QString &outPath) +namespace InstallHelper_win { - QString strPath = QCoreApplication::applicationDirPath(); - strPath += "/WindscribeInstallHelper.exe"; - ExecutableSignature sigCheck; - if (!sigCheck.verify(strPath.toStdWString())) - { - qCDebug(LOG_BASIC) << "WindscribeInstallHelper.exe incorrect signature: " << QString::fromStdString(sigCheck.lastError()); - return false; - } - - outPath = strPath; - return QFile::exists(strPath); -} - -QString InstallHelper_win::getPathForLogFile() +static void outputLogFileToLoggerAndRemove(const QString &logPath) { - // The install helper runs as root, and therefore should not log to a user writable folder. - QString strPath = QCoreApplication::applicationDirPath(); - strPath += "/logwindscribeinstallhelper.txt"; - return strPath; -} + QString logFile = logPath + "/logwindscribeinstallhelper.txt"; + QFile file(logFile); -void InstallHelper_win::outputLogFileToLoggerAndRemove(QString &logPath) -{ - QFile file(logPath); - if (file.open(QIODevice::ReadOnly)) - { + if (file.exists() && file.open(QIODevice::ReadOnly)) { QTextStream in(&file); - while (!in.atEnd()) - { - QString line = in.readLine(); - qCDebug(LOG_BASIC) << line; + while (!in.atEnd()) { + qCDebug(LOG_BASIC) << in.readLine(); } file.close(); file.remove(); } } -bool InstallHelper_win::executeInstallHelperCmd(const QString &servicePath) +bool executeInstallHelperCmd() { - QString utilPath; - if (!checkInstallHelper(utilPath)) - { + QString installDir = QCoreApplication::applicationDirPath(); + + QString installHelperExe = installDir + "/WindscribeInstallHelper.exe"; + if (!QFile::exists(installHelperExe)) { qCDebug(LOG_BASIC) << "WindscribeInstallHelper.exe not found in the app directory"; return false; } - if (!QFile::exists(servicePath)) - { - qCDebug(LOG_BASIC) << "Windscribe service not found in path:" << servicePath; + ExecutableSignature sigCheck; + if (!sigCheck.verify(installHelperExe.toStdWString())) { + qCDebug(LOG_BASIC) << "WindscribeInstallHelper.exe incorrect signature:" << QString::fromStdString(sigCheck.lastError()); return false; } - QString logPath = getPathForLogFile(); - - std::wstring ws = utilPath.toStdWString(); - std::wstring pars = L"/InstallService"; - pars += L" \"" + logPath.toStdWString() + L"\""; - pars += L" \"" + servicePath.toStdWString() + L"\""; + QString helperExe = installDir + "/WindscribeService.exe"; + if (!QFile::exists(helperExe)) { + qCDebug(LOG_BASIC) << "Windscribe service not found in path:" << helperExe; + return false; + } SHELLEXECUTEINFO sinfo; memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO)); sinfo.cbSize = sizeof(SHELLEXECUTEINFO); sinfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS; sinfo.hwnd = NULL; - sinfo.lpFile = ws.c_str(); - sinfo.lpParameters = pars.c_str(); + sinfo.lpFile = installHelperExe.toStdWString().c_str(); + sinfo.lpParameters = L"/InstallService"; sinfo.lpVerb = L"runas"; sinfo.nShow = SW_HIDE; - if (ShellExecuteEx(&sinfo)) - { + if (ShellExecuteEx(&sinfo)) { WaitForSingleObject(sinfo.hProcess, INFINITE); CloseHandle(sinfo.hProcess); - outputLogFileToLoggerAndRemove(logPath); + outputLogFileToLoggerAndRemove(installDir); return true; } qCDebug(LOG_BASIC) << "InstallHelper::executeInstallHelperCmd ShellExecuteEx failed:" << GetLastError(); return false; } + +}; diff --git a/client/engine/engine/helper/installhelper_win.h b/client/engine/engine/helper/installhelper_win.h index e774244e5..31b59a71f 100644 --- a/client/engine/engine/helper/installhelper_win.h +++ b/client/engine/engine/helper/installhelper_win.h @@ -1,14 +1,8 @@ #pragma once -#include - -class InstallHelper_win +namespace InstallHelper_win { -public: - static bool executeInstallHelperCmd(const QString &servicePath); -private: - static bool checkInstallHelper(QString &outPath); - static QString getPathForLogFile(); - static void outputLogFileToLoggerAndRemove(QString &logPath); +bool executeInstallHelperCmd(); + }; diff --git a/client/engine/engine/ping/pingmanager.cpp b/client/engine/engine/ping/pingmanager.cpp index 78f75389e..dfee2f75d 100644 --- a/client/engine/engine/ping/pingmanager.cpp +++ b/client/engine/engine/ping/pingmanager.cpp @@ -102,6 +102,9 @@ void PingManager::onPingTimer() for (auto it = ips_.begin(); it != ips_.end(); ++it) { PingIpState &pni = it.value(); + if (pni.nowPinging) + continue; + // Checking the option ws-use-icmp-pings and force ICMP pings if enabled. wsnet::PingType pingType = pni.ipInfo.pingType; if (ExtraConfig::instance().getUseICMPPings()) { @@ -110,13 +113,23 @@ void PingManager::onPingTimer() if (pni.iterationTime != pingStorage_.currentIterationTime()) { pingLog_.addLog("PingNodesController::onPingTimer", QString::fromLatin1("ping new node: %1 (%2 - %3)").arg(pni.ipInfo.ip, pni.ipInfo.city, pni.ipInfo.nick)); + pni.nowPinging = true; WSNet::instance()->pingManager()->ping(pni.ipInfo.ip.toStdString(), pni.ipInfo.hostname.toStdString(), pingType, - std::bind(&PingManager::onPingFinished, this, _1, _2, _3, _4)); + [this](const std::string &ip, bool isSuccess, std::int32_t timeMs, bool isFromDisconnectedVpnState) { + QMetaObject::invokeMethod(this, [this, ip, isSuccess, timeMs, isFromDisconnectedVpnState] { + onPingFinished(ip, isSuccess, timeMs, isFromDisconnectedVpnState); + }); + }); } else if (pni.latestPingFailed) { if (pni.nextTimeForFailedPing == 0 || QDateTime::currentMSecsSinceEpoch() >= pni.nextTimeForFailedPing) { + pni.nowPinging = true; pingLog_.addLog("PingNodesController::onPingTimer", "start ping because latest ping failed: " + it.key()); WSNet::instance()->pingManager()->ping(pni.ipInfo.ip.toStdString(), pni.ipInfo.hostname.toStdString(), pingType, - std::bind(&PingManager::onPingFinished, this, _1, _2, _3, _4)); + [this](const std::string &ip, bool isSuccess, std::int32_t timeMs, bool isFromDisconnectedVpnState) { + QMetaObject::invokeMethod(this, [this, ip, isSuccess, timeMs, isFromDisconnectedVpnState] { + onPingFinished(ip, isSuccess, timeMs, isFromDisconnectedVpnState); + }); + }); } } } @@ -130,6 +143,7 @@ void PingManager::onPingFinished(const std::string &ip, bool isSuccess, int32_t if (itNode == ips_.end()) { return; } + itNode->nowPinging = false; // Note: we only issue ping requests in the disconnected state. However, it is possible we transitioned to the // connecting/connected state between the time the ping request was issued to PingHost and when it was executed. diff --git a/client/engine/engine/ping/pingmanager.h b/client/engine/engine/ping/pingmanager.h index 63d5f36a4..31a21dc86 100644 --- a/client/engine/engine/ping/pingmanager.h +++ b/client/engine/engine/ping/pingmanager.h @@ -61,6 +61,7 @@ private slots: PingIpInfo ipInfo; qint64 iterationTime; bool latestPingFailed; + bool nowPinging; int failedPingsInRow; qint64 nextTimeForFailedPing; int curDelayForFailedPing = MIN_DELAY_FOR_FAILED_IN_ROW_PINGS; @@ -83,6 +84,7 @@ private slots: { iterationTime = 0; latestPingFailed = false; + nowPinging = false; failedPingsInRow = 0; nextTimeForFailedPing = 0; curDelayForFailedPing = MIN_DELAY_FOR_FAILED_IN_ROW_PINGS; diff --git a/client/gui/mainwindow.cpp b/client/gui/mainwindow.cpp index 93f7cfcc9..13a9e3f0d 100644 --- a/client/gui/mainwindow.cpp +++ b/client/gui/mainwindow.cpp @@ -3539,12 +3539,6 @@ void MainWindow::handleDisconnectWithError(const types::ConnectState &connectSta selectedLocation_->locationdId().isCustomConfigsLocation()); } msg = tr("The custom configuration could not be loaded. Please check that it’s correct or contact support."); - } else if (connectState.connectError == EXE_VERIFY_WSTUNNEL_ERROR || - connectState.connectError == EXE_VERIFY_STUNNEL_ERROR || - connectState.connectError == EXE_VERIFY_WIREGUARD_ERROR || - connectState.connectError == EXE_VERIFY_OPENVPN_ERROR) - { - msg = tr("The application is corrupted. Please reinstall Windscribe."); } else if (connectState.connectError == CTRLD_START_FAILED) { msg = tr("Unable to start custom DNS service. Please ensure you don't have any other local DNS services running, or contact support."); } else if (connectState.connectError == WIREGUARD_ADAPTER_SETUP_FAILED) { diff --git a/installer/common/alertwindow.cpp b/installer/common/alertwindow.cpp index 7aee9b935..ea85456c9 100644 --- a/installer/common/alertwindow.cpp +++ b/installer/common/alertwindow.cpp @@ -61,6 +61,11 @@ void AlertWindow::setDescription(const QString &desc) contents_->setDescription(desc); } +void AlertWindow::setDescriptionSize(int px) +{ + contents_->setDescriptionSize(px); +} + void AlertWindow::setPrimaryButton(const QString &text) { contents_->setPrimaryButton(text); diff --git a/installer/common/alertwindow.h b/installer/common/alertwindow.h index 6ce6505bd..f6e05d25c 100644 --- a/installer/common/alertwindow.h +++ b/installer/common/alertwindow.h @@ -20,6 +20,7 @@ class AlertWindow : public QWidget void setTitle(const QString &title); void setTitleSize(int px); void setDescription(const QString &desc); + void setDescriptionSize(int px); void setPrimaryButton(const QString &text); void setPrimaryButtonColor(const QColor &color); void setPrimaryButtonFontColor(const QColor &color); @@ -38,4 +39,4 @@ private slots: private: AlertWindowContents *contents_; -}; \ No newline at end of file +}; diff --git a/installer/common/alertwindowcontents.cpp b/installer/common/alertwindowcontents.cpp index 1edda7109..22b3288da 100644 --- a/installer/common/alertwindowcontents.cpp +++ b/installer/common/alertwindowcontents.cpp @@ -12,7 +12,7 @@ #include "themecontroller.h" AlertWindowContents::AlertWindowContents(QWidget *parent) - : QWidget(parent), primaryButtonColor_(ThemeController::instance().primaryButtonColor()), titleSize_(18) + : QWidget(parent), primaryButtonColor_(ThemeController::instance().primaryButtonColor()), titleSize_(18), descSize_(13) { icon_ = new QLabel(this); @@ -47,7 +47,7 @@ void AlertWindowContents::onThemeChanged() QString fontName = ThemeController::instance().defaultFontName(); title_->setStyleSheet(QString("color: %1; font-family: %2; font-size: %3px; font-weight: 600;").arg(fontColor).arg(fontName).arg(titleSize_)); - desc_->setStyleSheet(QString("color: %1; font-family: %2; font-size: 13px;").arg(fontColor).arg(fontName)); + desc_->setStyleSheet(QString("color: %1; font-family: %2; font-size: %3px;").arg(fontColor).arg(fontName).arg(descSize_)); QString primaryButtonStyle; primaryButtonStyle += "QPushButton { background-color: %1; color: %2; border: none; border-radius: 17px; font-family: %3; font-size: 14px; }"; @@ -76,7 +76,7 @@ void AlertWindowContents::updateDimensions() { qreal pmWidth = icon_->pixmap().width()/icon_->pixmap().devicePixelRatio(); qreal pmHeight = icon_->pixmap().height()/icon_->pixmap().devicePixelRatio(); - icon_->setGeometry((300 - pmWidth)/2, 56, pmWidth, pmHeight); + icon_->setGeometry((300 - pmWidth)/2, 48, pmWidth, pmHeight); QFont titleFont(ThemeController::instance().defaultFontName()); titleFont.setWeight(QFont::DemiBold); @@ -86,7 +86,7 @@ void AlertWindowContents::updateDimensions() title_->setGeometry(0, 76 + icon_->height(), 300, titleFm.boundingRect(0, 0, 300, height(), Qt::TextWordWrap, title_->text()).height()); QFont descFont(ThemeController::instance().defaultFontName()); - descFont.setPixelSize(13); + descFont.setPixelSize(descSize_); QFontMetrics fmDesc(descFont); desc_->setGeometry(0, 92 + icon_->height() + title_->height(), 300, fmDesc.boundingRect(0, 0, 300, height(), Qt::TextWordWrap, desc_->text()).height()); @@ -100,7 +100,7 @@ void AlertWindowContents::updateDimensions() } int height = - 56 + // height above icon + 48 + // height above icon icon_->height() + 20 + // space between icon and title title_->height() + @@ -180,3 +180,8 @@ void AlertWindowContents::setSecondaryButton(const QString &text) updateDimensions(); } +void AlertWindowContents::setDescriptionSize(int px) +{ + descSize_ = px; + updateDimensions(); +} diff --git a/installer/common/alertwindowcontents.h b/installer/common/alertwindowcontents.h index c42ac3ee5..0d97e0581 100644 --- a/installer/common/alertwindowcontents.h +++ b/installer/common/alertwindowcontents.h @@ -18,6 +18,7 @@ class AlertWindowContents : public QWidget void setTitle(const QString &title); void setTitleSize(int px); void setDescription(const QString &desc); + void setDescriptionSize(int px); void setPrimaryButton(const QString &text); void setPrimaryButtonColor(const QColor &color); void setPrimaryButtonFontColor(const QColor &color); @@ -42,6 +43,7 @@ private slots: QColor primaryButtonFontColor_; int titleSize_; + int descSize_; void updateDimensions(); }; diff --git a/installer/common/installer_shim.h b/installer/common/installer_shim.h index a98a9340c..84ea58795 100644 --- a/installer/common/installer_shim.h +++ b/installer/common/installer_shim.h @@ -21,7 +21,7 @@ class InstallerShim void setCallback(std::function func); // NB: can't ifdef platform-specific functions out for Mac here because we can't pull in any Qt headers std::wstring installDir(); - bool setInstallDir(std::wstring &path); + void setInstallDir(const std::wstring &path); bool isFactoryResetEnabled(); void setFactoryReset(bool on); bool isCreateShortcutEnabled(); diff --git a/installer/common/installer_win.qrc b/installer/common/installer_win.qrc index a6bad7395..57b6a566d 100644 --- a/installer/common/installer_win.qrc +++ b/installer/common/installer_win.qrc @@ -17,6 +17,6 @@ resources/WINDOWS_MINIMIZE_HOVER.svg resources/WINDSCRIBE_ICON.svg resources/Windscribe.ico + resources/WARNING.svg - diff --git a/installer/common/mainwindow.cpp b/installer/common/mainwindow.cpp index ed563f80d..202756425 100644 --- a/installer/common/mainwindow.cpp +++ b/installer/common/mainwindow.cpp @@ -6,18 +6,18 @@ #include #include #include + +#include "languagecontroller.h" +#include "themecontroller.h" + #ifdef Q_OS_WIN -#include -#include +#include "../windows/installer/installer/installer_utils.h" #include "../windows/utils/applicationinfo.h" #include "../windows/utils/path.h" #include "../windows/utils/windscribepathcheck.h" #endif -#include "languagecontroller.h" -#include "themecontroller.h" -MainWindow::MainWindow(bool isAdmin, InstallerOptions &options) : QWidget(nullptr), - options_(options), mousePressed_(false), fatalError_(false), exiting_(false), installing_(false) +MainWindow::MainWindow(bool isAdmin, InstallerOptions &options) : QWidget(nullptr), options_(options) { installerShim_ = &InstallerShim::instance(); @@ -33,58 +33,68 @@ MainWindow::MainWindow(bool isAdmin, InstallerOptions &options) : QWidget(nullpt LanguageController::instance(); installerShim_->setFactoryReset(options_.factoryReset); - std::wstring installPath = options_.installPath.toStdWString(); - installerShim_->setInstallDir(installPath); installerShim_->setAutoStart(options_.autostart); installerShim_->setInstallDrivers(options_.installDrivers); std::wstring username = options_.username.toStdWString(); std::wstring password = options_.password.toStdWString(); installerShim_->setCredentials(username, password); - if (!options_.silent) { - QScreen *primaryScreen = qApp->primaryScreen(); - if (primaryScreen) { - int screenWidth = primaryScreen->geometry().width(); - int screenHeight = primaryScreen->geometry().height(); - - if (options_.centerX >= 0 && options_.centerY >= 0) { - setGeometry(options_.centerX - kWindowWidth/2, options_.centerY - kWindowHeight/2, kWindowWidth, kWindowHeight); - } else { - setGeometry((screenWidth - kWindowWidth) / 2, (screenHeight - kWindowHeight) / 2, kWindowWidth, kWindowHeight); - } - } else { - setGeometry(0, 0, kWindowWidth, kWindowHeight); +#ifdef Q_OS_WIN + // Custom install path not currently supported on macOS. + if (!options_.installPath.isEmpty()) { + auto wpath = options_.installPath.toStdWString(); + if (PathCheck::isNeedAppendSubdirectory(wpath, installerShim_->installDir())) { + wpath = Path::append(wpath, ApplicationInfo::name()); } + installerShim_->setInstallDir(wpath); + } +#endif - initialWindow_ = new InitialWindow(this); - initialWindow_->setGeometry(0, 0, width(), height()); - connect(initialWindow_, &InitialWindow::installClicked, this, &MainWindow::onInstallClicked); - connect(initialWindow_, &InitialWindow::settingsClicked, this, &MainWindow::onSettingsClicked); - connect(initialWindow_, &InitialWindow::minimizeClicked, this, &MainWindow::onMinimizeClicked); - connect(initialWindow_, &InitialWindow::closeClicked, this, &MainWindow::onCloseClicked); - - settingsWindow_ = new SettingsWindow(this); - settingsWindow_->setGeometry(0, 0, width(), height()); - connect(settingsWindow_, &SettingsWindow::escapeClicked, this, &MainWindow::onSettingsWindowEscapeClicked); - connect(settingsWindow_, &SettingsWindow::browseDirClicked, this, &MainWindow::onChangeDirClicked); - connect(settingsWindow_, &SettingsWindow::factoryResetToggled, this, &MainWindow::onSettingsWindowFactoryResetToggled); - connect(settingsWindow_, &SettingsWindow::createShortcutToggled, this, &MainWindow::onSettingsWindowCreateShortcutToggled); - connect(settingsWindow_, &SettingsWindow::installPathChanged, this, &MainWindow::onSettingsWindowInstallPathChanged); - connect(settingsWindow_, &SettingsWindow::animationFinished, this, &MainWindow::onSettingsWindowAnimFinished); - connect(settingsWindow_, &SettingsWindow::minimizeClicked, this, &MainWindow::onMinimizeClicked); - connect(settingsWindow_, &SettingsWindow::closeClicked, this, &MainWindow::onCloseClicked); - settingsWindow_->setCreateShortcut(installerShim_->isCreateShortcutEnabled()); - settingsWindow_->setFactoryReset(installerShim_->isFactoryResetEnabled()); - settingsWindow_->setInstallPath(QString::fromStdWString(installerShim_->installDir())); - settingsWindow_->hide(); + if (options_.silent) { + startInstall(); + return; + } + + QScreen *primaryScreen = qApp->primaryScreen(); + if (primaryScreen) { + int screenWidth = primaryScreen->geometry().width(); + int screenHeight = primaryScreen->geometry().height(); - alertWindow_ = new AlertWindow(this); - alertWindow_->setGeometry(0, 0, width(), height()); - connect(alertWindow_, &AlertWindow::primaryButtonClicked, this, &MainWindow::onAlertWindowPrimaryButtonClicked); - connect(alertWindow_, &AlertWindow::escapeClicked, this, &MainWindow::onAlertWindowEscapeClicked); - alertWindow_->hide(); + if (options_.centerX >= 0 && options_.centerY >= 0) { + setGeometry(options_.centerX - kWindowWidth/2, options_.centerY - kWindowHeight/2, kWindowWidth, kWindowHeight); + } else { + setGeometry((screenWidth - kWindowWidth) / 2, (screenHeight - kWindowHeight) / 2, kWindowWidth, kWindowHeight); + } + } else { + setGeometry(0, 0, kWindowWidth, kWindowHeight); } + initialWindow_ = new InitialWindow(this); + initialWindow_->setGeometry(0, 0, width(), height()); + connect(initialWindow_, &InitialWindow::installClicked, this, &MainWindow::onInstallClicked); + connect(initialWindow_, &InitialWindow::settingsClicked, this, &MainWindow::onSettingsClicked); + connect(initialWindow_, &InitialWindow::minimizeClicked, this, &MainWindow::onMinimizeClicked); + connect(initialWindow_, &InitialWindow::closeClicked, this, &MainWindow::onCloseClicked); + + settingsWindow_ = new SettingsWindow(this); + settingsWindow_->setGeometry(0, 0, width(), height()); + connect(settingsWindow_, &SettingsWindow::escapeClicked, this, &MainWindow::onSettingsWindowEscapeClicked); + connect(settingsWindow_, &SettingsWindow::browseDirClicked, this, &MainWindow::onChangeDirClicked); + connect(settingsWindow_, &SettingsWindow::factoryResetToggled, this, &MainWindow::onSettingsWindowFactoryResetToggled); + connect(settingsWindow_, &SettingsWindow::createShortcutToggled, this, &MainWindow::onSettingsWindowCreateShortcutToggled); + connect(settingsWindow_, &SettingsWindow::installPathChanged, this, &MainWindow::onSettingsWindowInstallPathChanged); + connect(settingsWindow_, &SettingsWindow::animationFinished, this, &MainWindow::onSettingsWindowAnimFinished); + connect(settingsWindow_, &SettingsWindow::minimizeClicked, this, &MainWindow::onMinimizeClicked); + connect(settingsWindow_, &SettingsWindow::closeClicked, this, &MainWindow::onCloseClicked); + settingsWindow_->setCreateShortcut(installerShim_->isCreateShortcutEnabled()); + settingsWindow_->setFactoryReset(installerShim_->isFactoryResetEnabled()); + settingsWindow_->setInstallPath(QString::fromStdWString(installerShim_->installDir())); + settingsWindow_->hide(); + + alertWindow_ = new AlertWindow(this); + alertWindow_->setGeometry(0, 0, width(), height()); + alertWindow_->hide(); + if (!isAdmin) { showError(tr("Installation failed"), tr("You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe."), @@ -92,7 +102,7 @@ MainWindow::MainWindow(bool isAdmin, InstallerOptions &options) : QWidget(nullpt return; } - if (options_.updating || options_.silent) { + if (options_.updating) { onInstallClicked(); } else { initialWindow_->show(); @@ -105,10 +115,19 @@ MainWindow::~MainWindow() void MainWindow::onInstallClicked() { - if (!installing_) { - installing_ = true; - installerShim_->start(options_.updating); +#ifdef Q_OS_WIN + // Display the warning every time if a user is manually upgrading and they're using a custom folder. + // We'll only pester users doing an in-app upgrade if they are upgrading from a version not containing + // this security check. + if (isWarnUserCustomPath()) { + if (!options_.updating || InstallerUtils::installedAppVersionLessThan(L"2.10.10")) { + showCustomPathWarning(true); + return; + } } +#endif + + startInstall(); } void MainWindow::onSettingsClicked() @@ -148,18 +167,16 @@ void MainWindow::onSettingsWindowAnimFinished(bool dimmed) } } -void MainWindow::setProgress(int progress) -{ - QMetaObject::invokeMethod(initialWindow_, "setProgress", Qt::QueuedConnection, Q_ARG(int, progress)); -} - void MainWindow::onInstallerCallback() { switch (installerShim_->state()) { case InstallerShim::STATE_INIT: break; case InstallerShim::STATE_EXTRACTING: - QMetaObject::invokeMethod(initialWindow_, "setProgress", Qt::QueuedConnection, Q_ARG(int, installerShim_->progress())); + // No UI created when running in silent mode. + if (initialWindow_) { + QMetaObject::invokeMethod(initialWindow_, "setProgress", Qt::QueuedConnection, Q_ARG(int, installerShim_->progress())); + } break; case InstallerShim::STATE_CANCELED: case InstallerShim::STATE_LAUNCHED: @@ -169,42 +186,32 @@ void MainWindow::onInstallerCallback() installerShim_->finish(); break; case InstallerShim::STATE_ERROR: + QString errorMsg; InstallerShim::INSTALLER_ERROR error = installerShim_->lastError(); if (error == InstallerShim::ERROR_PERMISSION) { - QMetaObject::invokeMethod(this, "showError", Qt::QueuedConnection, - Q_ARG(QString, tr("Installation failed")), - Q_ARG(QString, tr("The installation was cancelled. Administrator privileges are required to install the application.")), - Q_ARG(bool, true)); + errorMsg = tr("The installation was cancelled. Administrator privileges are required to install the application."); } else if (error == InstallerShim::ERROR_KILL) { - QMetaObject::invokeMethod(this, "showError", Qt::QueuedConnection, - Q_ARG(QString, tr("Installation failed")), - Q_ARG(QString, tr("Windscribe is running and could not be closed. Please close the application manually and try again.")), - Q_ARG(bool, true)); + errorMsg = tr("Windscribe is running and could not be closed. Please close the application manually and try again."); } else if (error == InstallerShim::ERROR_CONNECT_HELPER) { - QMetaObject::invokeMethod(this, "showError", Qt::QueuedConnection, - Q_ARG(QString, tr("Installation failed")), - Q_ARG(QString, tr("The installer could not connect to the privileged helper tool. Please try again.")), - Q_ARG(bool, true)); + errorMsg = tr("The installer could not connect to the privileged helper tool. Please try again."); } else if (error == InstallerShim::ERROR_DELETE) { - QMetaObject::invokeMethod(this, "showError", Qt::QueuedConnection, - Q_ARG(QString, tr("Installation failed")), - Q_ARG(QString, tr("An existing installation of Windscribe could not be removed. Please uninstall the application manually and try again.")), - Q_ARG(bool, true)); + errorMsg = tr("An existing installation of Windscribe could not be removed. Please uninstall the application manually and try again."); } else if (error == InstallerShim::ERROR_UNINSTALL) { - QMetaObject::invokeMethod(this, "showError", Qt::QueuedConnection, - Q_ARG(QString, tr("Installation failed")), - Q_ARG(QString, tr("The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again.")), - Q_ARG(bool, true)); + errorMsg = tr("The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again."); } else if (error == InstallerShim::ERROR_MOVE_CUSTOM_DIR) { - QMetaObject::invokeMethod(this, "showError", Qt::QueuedConnection, - Q_ARG(QString, tr("Installation failed")), - Q_ARG(QString, tr("The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again.")), - Q_ARG(bool, true)); + errorMsg = tr("The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again."); } else { - QMetaObject::invokeMethod(this, "showError", Qt::QueuedConnection, - Q_ARG(QString, tr("Installation failed")), - Q_ARG(QString, tr("The installation could not be completed successfully. Please contact our Technical Support.")), - Q_ARG(bool, true)); + errorMsg = tr("The installation could not be completed successfully. Please contact our Technical Support."); + } + // No UI created when running in silent mode. + if (options_.silent) { + // On Windows this will go to the system debugger (e.g. Debug View app). + qDebug() << errorMsg; + qApp->exit(); + } + else { + QMetaObject::invokeMethod(this, "showError", Qt::QueuedConnection, Q_ARG(QString, tr("Installation failed")), + Q_ARG(QString, errorMsg), Q_ARG(bool, true)); } break; } @@ -247,55 +254,27 @@ void MainWindow::mouseReleaseEvent(QMouseEvent *event) } } -#ifdef Q_OS_WIN -static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) -{ - if (uMsg == BFFM_INITIALIZED) { - std::wstring tmp = (const wchar_t*)lpData; - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); - } - return 0; -} -#endif - void MainWindow::onChangeDirClicked() { #ifdef Q_OS_WIN - std::wstring path_param = installerShim_->installDir(); std::wstring title = tr("Select a folder in the list below and click OK.").toStdWString(); - - BROWSEINFO bi = { 0 }; - bi.hwndOwner = (HWND)winId(); - bi.lpszTitle = title.c_str(); - bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_DONTGOBELOWDOMAIN | BIF_NEWDIALOGSTYLE; - bi.lpfn = BrowseCallbackProc; - bi.lParam = (LPARAM)path_param.c_str(); - - LPITEMIDLIST pidl = SHBrowseForFolder(&bi); - - if (pidl != 0) { - //get the name of the folder and put it in path - TCHAR path[MAX_PATH]; - SHGetPathFromIDList(pidl, path); - CoTaskMemFree(pidl); - - std::wstring final_path = path; - - if (PathCheck::isNeedAppendSubdirectory(path, path_param)) { - final_path = Path::append(path, ApplicationInfo::name()); - } - - setInstallPath(QString::fromStdWString(final_path)); + std::wstring installFolder = InstallerUtils::selectInstallFolder((HWND)winId(), title, installerShim_->installDir()); + if (!installFolder.empty()) { + setInstallPath(QString::fromStdWString(installFolder)); } #endif } void MainWindow::showError(const QString &title, const QString &desc, bool fatal) { - if (options_.silent) { + if (!alertWindow_) { return; } + fatalError_ = fatal; + + disconnect(alertWindow_, nullptr, nullptr, nullptr); + alertWindow_->setIcon(":/resources/ERROR.svg"); alertWindow_->setTitle(title); alertWindow_->setTitleSize(16); @@ -304,17 +283,24 @@ void MainWindow::showError(const QString &title, const QString &desc, bool fatal alertWindow_->setPrimaryButtonColor(ThemeController::instance().primaryButtonColor()); alertWindow_->setPrimaryButtonFontColor(ThemeController::instance().primaryButtonFontColor()); alertWindow_->setSecondaryButton(""); - fatalError_ = fatal; + + connect(alertWindow_, &AlertWindow::primaryButtonClicked, this, &MainWindow::onAlertWindowPrimaryButtonClicked); + connect(alertWindow_, &AlertWindow::escapeClicked, this, &MainWindow::onAlertWindowEscapeClicked); + alertWindow_->show(); alertWindow_->setFocus(); } void MainWindow::showExitPrompt() { - if (options_.silent) { + if (!alertWindow_) { return; } + exiting_ = true; + + disconnect(alertWindow_, nullptr, nullptr, nullptr); + alertWindow_->setIcon(":/resources/SHUTDOWN_ICON.svg"); alertWindow_->setTitle(tr("Quit Windscribe Installer?")); alertWindow_->setTitleSize(14); @@ -324,19 +310,72 @@ void MainWindow::showExitPrompt() alertWindow_->setPrimaryButtonFontColor(QColor(0xFF, 0xFF, 0xFF)); alertWindow_->setSecondaryButton(tr("Cancel")); - exiting_ = true; + connect(alertWindow_, &AlertWindow::primaryButtonClicked, this, &MainWindow::onAlertWindowPrimaryButtonClicked); + connect(alertWindow_, &AlertWindow::escapeClicked, this, &MainWindow::onAlertWindowEscapeClicked); + alertWindow_->show(); alertWindow_->setFocus(); } -void MainWindow::onAlertWindowPrimaryButtonClicked() +void MainWindow::showCustomPathWarning(bool installing) { - alertWindow_->hide(); - if (settingsWindow_->isVisible()) { - settingsWindow_->setFocus(); - } else { - initialWindow_->setFocus(); + // Custom install path not currently supported on macOS. +#ifdef Q_OS_WIN + if (!alertWindow_) { + return; } + + disconnect(alertWindow_, nullptr, nullptr, nullptr); + + // Using slightly smaller font sizes to ensure the 'Cancel' button is not pushed off the bottom + // of the screen. + alertWindow_->setIcon(":/resources/WARNING.svg"); + alertWindow_->setTitle(tr("Security Warning")); + alertWindow_->setTitleSize(14); + alertWindow_->setDescription( + tr("Installation to a custom folder may allow an attacker to tamper with the Windscribe application." + " To ensure the security of the application, and your system, we strongly recommend you install" + " to the default location in the 'Program Files' folder. Click OK to continue with the custom" + " folder or Cancel to use the default location.")); + alertWindow_->setDescriptionSize(12); + alertWindow_->setPrimaryButton(tr("OK")); + alertWindow_->setPrimaryButtonColor(ThemeController::instance().primaryButtonColor()); + alertWindow_->setPrimaryButtonFontColor(ThemeController::instance().primaryButtonFontColor()); + alertWindow_->setSecondaryButton(tr("Cancel")); + + if (installing) { + connect(alertWindow_, &AlertWindow::primaryButtonClicked, this, [this] { + showActiveWindowAfterAlert(); + startInstall(); + }); + connect(alertWindow_, &AlertWindow::escapeClicked, this, [this] { + installerShim_->setInstallDir(ApplicationInfo::defaultInstallPath()); + showActiveWindowAfterAlert(); + startInstall(); + }); + } + else { + connect(alertWindow_, &AlertWindow::primaryButtonClicked, this, [this] { showActiveWindowAfterAlert(); }); + connect(alertWindow_, &AlertWindow::escapeClicked, this, [this] { + // User opted not to use the custom install path they selected. Revert to the default install path. + const auto defaultPath = ApplicationInfo::defaultInstallPath(); + installerShim_->setInstallDir(defaultPath); + settingsWindow_->setInstallPath(QString::fromStdWString(defaultPath)); + lastCustomPathWarning_.clear(); + showActiveWindowAfterAlert(); + }); + } + + alertWindow_->show(); + alertWindow_->setFocus(); +#else + Q_UNUSED(installing) +#endif +} + +void MainWindow::onAlertWindowPrimaryButtonClicked() +{ + showActiveWindowAfterAlert(); if (fatalError_ || exiting_) { qApp->exit(); } @@ -344,12 +383,7 @@ void MainWindow::onAlertWindowPrimaryButtonClicked() void MainWindow::onAlertWindowEscapeClicked() { - alertWindow_->hide(); - if (settingsWindow_->isVisible()) { - settingsWindow_->setFocus(); - } else { - initialWindow_->setFocus(); - } + showActiveWindowAfterAlert(); exiting_ = false; if (fatalError_) { qApp->exit(); @@ -370,14 +404,58 @@ void MainWindow::closeEvent(QCloseEvent *event) void MainWindow::setInstallPath(const QString &path) { - std::wstring wpath = path.toStdWString(); - bool err = installerShim_->setInstallDir(wpath); - if (err) { - // This function only called for Windows, so we know which error it is + // Custom install path not currently supported on macOS. +#ifdef Q_OS_WIN + auto wpath = path.toStdWString(); + + if (!Path::isOnSystemDrive(wpath)) { + const auto defaultPath = ApplicationInfo::defaultInstallPath(); + installerShim_->setInstallDir(defaultPath); + settingsWindow_->setInstallPath(QString::fromStdWString(defaultPath)); showError(tr("Invalid path"), tr("The specified installation path is not on the system drive. To ensure the security of the application, and your system, it must be installed on the same drive as Windows. The installation folder has been reset to the default."), false); + return; + } + + if (PathCheck::isNeedAppendSubdirectory(wpath, installerShim_->installDir())) { + wpath = Path::append(wpath, ApplicationInfo::name()); + } + + installerShim_->setInstallDir(wpath); + settingsWindow_->setInstallPath(QString::fromStdWString(wpath)); + + if (isWarnUserCustomPath()) { + lastCustomPathWarning_ = wpath; + showCustomPathWarning(false); + } +#endif +} + +void MainWindow::showActiveWindowAfterAlert() +{ + alertWindow_->hide(); + if (settingsWindow_->isVisible()) { + settingsWindow_->setFocus(); } else { - settingsWindow_->setInstallPath(path); + initialWindow_->setFocus(); } } + +void MainWindow::startInstall() +{ + if (!installing_) { + installing_ = true; + installerShim_->start(options_.updating); + } +} + +bool MainWindow::isWarnUserCustomPath() const +{ +#ifdef Q_OS_WIN + const auto installPath = installerShim_->installDir(); + return !Path::equivalent(lastCustomPathWarning_, installPath) && !Path::isSystemProtected(installPath); +#else + return false; +#endif +} diff --git a/installer/common/mainwindow.h b/installer/common/mainwindow.h index fc83cf7fa..10546862d 100644 --- a/installer/common/mainwindow.h +++ b/installer/common/mainwindow.h @@ -17,8 +17,6 @@ class MainWindow : public QWidget MainWindow(bool isAdmin, InstallerOptions &options); ~MainWindow(); - void setProgress(int progress); - protected: void mouseMoveEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override; @@ -42,17 +40,22 @@ private slots: void onInstallerCallback(); private: - InstallerOptions options_; - InitialWindow *initialWindow_; - SettingsWindow *settingsWindow_; - AlertWindow *alertWindow_; - InstallerShim *installerShim_; - bool mousePressed_; - bool fatalError_; - bool exiting_; - bool installing_; + const InstallerOptions options_; + InitialWindow *initialWindow_ = nullptr; + SettingsWindow *settingsWindow_ = nullptr; + AlertWindow *alertWindow_ = nullptr; + InstallerShim *installerShim_ = nullptr; + bool mousePressed_ = false; + bool fatalError_ = false; + bool exiting_ = false; + bool installing_ = false; QPoint dragPosition_; + std::wstring lastCustomPathWarning_; + bool isWarnUserCustomPath() const; + void showActiveWindowAfterAlert(); void showExitPrompt(); void setInstallPath(const QString &path); + void showCustomPathWarning(bool installing); + void startInstall(); }; diff --git a/installer/common/resources/ERROR.svg b/installer/common/resources/ERROR.svg index 2085b6279..6ea046ec0 100644 --- a/installer/common/resources/ERROR.svg +++ b/installer/common/resources/ERROR.svg @@ -1,3 +1,10 @@ - - + + + + + + + + + diff --git a/installer/common/resources/WARNING.svg b/installer/common/resources/WARNING.svg new file mode 100644 index 000000000..942a8f721 --- /dev/null +++ b/installer/common/resources/WARNING.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/installer/common/translations/windscribe_installer_ar.ts b/installer/common/translations/windscribe_installer_ar.ts index 0d647334a..850b0caad 100644 --- a/installer/common/translations/windscribe_installer_ar.ts +++ b/installer/common/translations/windscribe_installer_ar.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. يحتوي مجلد التثبيت على بيانات تعذر إلغاء تثبيتها. الرجاء إلغاء تثبيت التطبيق يدويا والمحاولة مرة أخرى. + + Security Warning + تحذير أمني + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + قد يسمح التثبيت في مجلد مخصص للمهاجم بالعبث بتطبيق Windscribe. لضمان أمان التطبيق ونظامك ، نوصي بشدة بالتثبيت في الموقع الافتراضي في مجلد "ملفات البرامج". انقر فوق موافق لمتابعة المجلد المخصص أو إلغاء الأمر لاستخدام الموقع الافتراضي. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. يرشد المثبت لتخطي تثبيت برامج التشغيل. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - يرشد المثبت لإخفاء واجهة المستخدم الخاصة به. يعني -no-drivers و -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. احذف التفضيلات والسجلات والبيانات الأخرى الموجودة، إن وجدت. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. لم يتمكن المثبت من تحديد ما إذا كان يعمل بحقوق المسؤول أم لا. يرجى الإبلاغ عن هذا الفشل إلى دعم Windscribe. + + Instructs the installer to hide its user interface. + يرشد المثبت لإخفاء واجهة المستخدم الخاصة به. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + ليس لديك أذونات كافية لتشغيل هذا التطبيق. الامتيازات الإدارية مطلوبة لتثبيت Windscribe. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_cs.ts b/installer/common/translations/windscribe_installer_cs.ts index c4815c2e7..1217cd53d 100644 --- a/installer/common/translations/windscribe_installer_cs.ts +++ b/installer/common/translations/windscribe_installer_cs.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. Instalační složka obsahuje data, která nelze odinstalovat. Odinstalujte aplikaci ručně a zkuste to znovu. + + Security Warning + Upozornění zabezpečení + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + Instalace do vlastní složky může útočníkovi umožnit manipulovat s aplikací Windscribe. Chcete-li zajistit bezpečnost aplikace a vašeho systému, důrazně doporučujeme instalaci do výchozího umístění ve složce "Program Files". Klepněte na tlačítko OK, chcete-li pokračovat ve vlastní složce, nebo na tlačítko Storno, chcete-li použít výchozí umístění. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Pokyn instalačnímu programu, aby přeskočil instalaci ovladačů. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Pokyne instalačnímu programu, aby skryl své uživatelské rozhraní. Implikuje -no-drivers a -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Odstraňte existující předvolby, protokoly a další data, pokud existují. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. Instalační program nebyl schopen určit, zda je spuštěn s právy správce. Nahlaste prosím tuto chybu podpoře Windscribe. + + Instructs the installer to hide its user interface. + Pokyne instalačnímu programu, aby skryl své uživatelské rozhraní. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + Nemáte dostatečná oprávnění ke spuštění této aplikace. K instalaci aplikace Windscribe jsou vyžadována oprávnění správce. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_de.ts b/installer/common/translations/windscribe_installer_de.ts index 0f7d9efbe..4c383455d 100644 --- a/installer/common/translations/windscribe_installer_de.ts +++ b/installer/common/translations/windscribe_installer_de.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. Der Installationsordner enthält Daten, die nicht deinstalliert werden konnten. Bitte deinstallieren Sie die Anwendung manuell und versuchen Sie es erneut. + + Security Warning + Sicherheitswarnung + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + Die Installation in einem benutzerdefinierten Ordner kann es einem Angreifer ermöglichen, die Windscribe-Anwendung zu manipulieren. Um die Sicherheit der Anwendung und Ihres Systems zu gewährleisten, empfehlen wir Ihnen dringend, die Installation am Standardspeicherort im Ordner "Programme" durchzuführen. Klicken Sie auf OK, um mit dem benutzerdefinierten Ordner fortzufahren, oder auf Abbrechen, um den Standardspeicherort zu verwenden. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Weist das Installationsprogramm an, die Installation von Treibern zu überspringen. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Weist das Installationsprogramm an, die Benutzeroberfläche auszublenden. Impliziert -no-drivers und -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Löschen Sie vorhandene Einstellungen, Protokolle und andere Daten, falls vorhanden. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. Das Installationsprogramm konnte nicht feststellen, ob es mit Administratorrechten ausgeführt wird. Bitte melden Sie diesen Fehler dem Windscribe-Support. + + Instructs the installer to hide its user interface. + Weist das Installationsprogramm an, die Benutzeroberfläche auszublenden. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + Sie verfügen nicht über ausreichende Berechtigungen zum Ausführen dieser Anwendung. Für die Installation von Windscribe sind Administratorrechte erforderlich. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_en.ts b/installer/common/translations/windscribe_installer_en.ts index 2dc9433d0..8b8655c97 100644 --- a/installer/common/translations/windscribe_installer_en.ts +++ b/installer/common/translations/windscribe_installer_en.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. + + Security Warning + Security Warning + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Instructs the installer to skip installing drivers. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Delete existing preferences, logs, and other data, if they exist. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. + + Instructs the installer to hide its user interface. + Instructs the installer to hide its user interface. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_es.ts b/installer/common/translations/windscribe_installer_es.ts index 254ed01d2..66c5afc80 100644 --- a/installer/common/translations/windscribe_installer_es.ts +++ b/installer/common/translations/windscribe_installer_es.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. La carpeta de instalación contiene datos que no se han podido desinstalar. Desinstale la aplicación manualmente e inténtelo de nuevo. + + Security Warning + Advertencia de seguridad + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + La instalación en una carpeta personalizada puede permitir que un atacante manipule la aplicación Windscribe. Para garantizar la seguridad de la aplicación y de su sistema, le recomendamos encarecidamente que la instale en la ubicación predeterminada de la carpeta "Archivos de programa". Haga clic en Aceptar para continuar con la carpeta personalizada o en Cancelar para usar la ubicación predeterminada. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Indica al instalador que omita la instalación de controladores. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Indica al instalador que oculte su interfaz de usuario. Implica -no-drivers y -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Elimine las preferencias, los registros y otros datos existentes, si existen. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. El instalador no pudo determinar si se está ejecutando con derechos de administrador. Informa de este fallo al servicio de asistencia de Windscribe. + + Instructs the installer to hide its user interface. + Indica al instalador que oculte su interfaz de usuario. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + No tiene permisos suficientes para ejecutar esta aplicación. Se requieren privilegios administrativos para instalar Windscribe. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_fa.ts b/installer/common/translations/windscribe_installer_fa.ts index b6ed001ef..c9524aae1 100644 --- a/installer/common/translations/windscribe_installer_fa.ts +++ b/installer/common/translations/windscribe_installer_fa.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. پوشه نصب حاوی داده هایی است که نمی توان انها را حذف نصب کرد. لطفا برنامه را به صورت دستی حذف کنید و دوباره امتحان کنید. + + Security Warning + هشدار امنیتی + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + نصب یک پوشه سفارشی ممکن است به مهاجم اجازه دهد تا برنامه Windscribe را دستکاری کند. برای اطمینان از امنیت برنامه و سیستم شما، ما به شدت توصیه می کنیم که به مکان پیش فرض در پوشه "فایل های برنامه" نصب کنید. روی OK کلیک کنید تا پوشه سفارشی ادامه یابد یا برای استفاده از مکان پیش فرض لغو شود. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. اموزش نصب کننده به جست و خیز نصب درایور. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - به نصب کننده دستور می دهد رابط کاربری خود را پنهان کند. به معنی -no-drivers و -no-auto-start است. - Delete existing preferences, logs, and other data, if they exist. حذف ترجیحات موجود، سیاهههای مربوط و سایر داده ها، در صورت وجود. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. نصب کننده قادر به تعیین اینکه ایا با حقوق سرپرست اجرا می شود، نبود. لطفا این شکست را به پشتیبانی Windscribe گزارش دهید. + + Instructs the installer to hide its user interface. + به نصب کننده دستور می دهد رابط کاربری خود را پنهان کند. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + شما مجوز کافی برای اجرای این برنامه را ندارید. امتیازات اداری برای نصب Windscribe مورد نیاز است. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_fr.ts b/installer/common/translations/windscribe_installer_fr.ts index 5049849b1..d167a33ec 100644 --- a/installer/common/translations/windscribe_installer_fr.ts +++ b/installer/common/translations/windscribe_installer_fr.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. Le dossier d’installation contient des données qui n’ont pas pu être désinstallées. Veuillez désinstaller l’application manuellement et réessayer. + + Security Warning + Avertissement de sécurité + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + L’installation dans un dossier personnalisé peut permettre à un attaquant de falsifier l’application Windscribe. Pour garantir la sécurité de l’application et de votre système, nous vous recommandons vivement d’installer l’application à l’emplacement par défaut dans le dossier « Program Files ». Cliquez sur OK pour continuer avec le dossier personnalisé ou sur Annuler pour utiliser l’emplacement par défaut. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Indique au programme d’installation d’ignorer l’installation des pilotes. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Indique au programme d’installation de masquer son interface utilisateur. Implique -no-drivers et -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Supprimez les préférences, journaux et autres données existants, le cas échéant. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. Le programme d’installation n’a pas pu déterminer s’il s’exécute avec des droits d’administrateur. Veuillez signaler cette défaillance à l’assistance Windscribe. + + Instructs the installer to hide its user interface. + Indique au programme d’installation de masquer son interface utilisateur. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + Vous ne disposez pas des autorisations suffisantes pour exécuter cette application. Des privilèges d’administrateur sont requis pour installer Windscribe. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_hi.ts b/installer/common/translations/windscribe_installer_hi.ts index c98ffe20b..6fb509a69 100644 --- a/installer/common/translations/windscribe_installer_hi.ts +++ b/installer/common/translations/windscribe_installer_hi.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. स्थापना फ़ोल्डर में वह डेटा है जिसकी स्थापना रद्द नहीं की जा सकी. कृपया अनुप्रयोग की स्थापना मैन्युअल रूप से रद्द करें और पुन: प्रयास करें. + + Security Warning + सुरक्षा चेतावनी + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + कस्टम फ़ोल्डर में स्थापना एक हमलावर को Windscribe अनुप्रयोग के साथ छेड़छाड़ करने की अनुमति दे सकती है। एप्लिकेशन और आपके सिस्टम की सुरक्षा सुनिश्चित करने के लिए, हम दृढ़ता से अनुशंसा करते हैं कि आप 'प्रोग्राम फ़ाइलें' फ़ोल्डर में डिफ़ॉल्ट स्थान पर स्थापित करें। कस्टम फ़ोल्डर के साथ जारी रखने के लिए ठीक क्लिक करें या डिफ़ॉल्ट स्थान का उपयोग करने के लिए रद्द करें। + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. इंस्टॉलर को ड्राइवरों को स्थापित करना छोड़ने का निर्देश देता है। - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - इंस्टॉलर को अपने उपयोगकर्ता इंटरफ़ेस को छिपाने का निर्देश देता है। इसका अर्थ है -नो-ड्राइवर और -नो-ऑटो-स्टार्ट। - Delete existing preferences, logs, and other data, if they exist. मौजूदा प्राथमिकताएं, लॉग, और अन्य डेटा हटाएँ, यदि वे मौजूद हैं. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. इंस्टॉलर यह निर्धारित करने में असमर्थ था कि क्या यह व्यवस्थापक यी अधिकारों के साथ चल रहा है. कृपया इस विफलता की रिपोर्ट विंडसाइड समर्थन को करें. + + Instructs the installer to hide its user interface. + इंस्टॉलर को अपने यूजर इंटरफेस को छिपाने का निर्देश देता है। + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + आपके पास यह अनुप्रयोग चलाने के लिए पर्याप्त अनुमतियाँ नहीं हैं. विंडसाइड को स्थापित करने के लिए प्रशासनिक विशेषाधिकारों की आवश्यकता होती है। + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_id.ts b/installer/common/translations/windscribe_installer_id.ts index 90aec3134..01a722125 100644 --- a/installer/common/translations/windscribe_installer_id.ts +++ b/installer/common/translations/windscribe_installer_id.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. Folder instalasi berisi data yang tidak dapat dihapus. Hapus instalan aplikasi secara manual dan coba lagi. + + Security Warning + Peringatan Keamanan + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + Penginstalan ke folder kustom memungkinkan penyerang mengutak-atik aplikasi Windscribe. Untuk memastikan keamanan aplikasi, dan sistem Anda, kami sangat menyarankan Anda menginstal ke lokasi default di folder 'Program Files'. Klik OK untuk melanjutkan dengan folder kustom atau Batal untuk menggunakan lokasi default. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Menginstruksikan penginstal untuk melewati penginstalan driver. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Menginstruksikan penginstal untuk menyembunyikan antarmuka penggunanya. Menyiratkan -no-drivers dan -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Hapus preferensi, log, dan data lain yang ada, jika ada. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. Penginstal tidak dapat menentukan apakah itu berjalan dengan hak administrator. Harap laporkan kegagalan ini ke dukungan Windscribe. + + Instructs the installer to hide its user interface. + Menginstruksikan penginstal untuk menyembunyikan antarmuka penggunanya. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + Anda tidak memiliki izin yang memadai untuk menjalankan aplikasi ini. Hak administratif diperlukan untuk menginstal Windscribe. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_it.ts b/installer/common/translations/windscribe_installer_it.ts index 76c821c23..30c4279a0 100644 --- a/installer/common/translations/windscribe_installer_it.ts +++ b/installer/common/translations/windscribe_installer_it.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. La cartella di installazione contiene dati che non è stato possibile disinstallare. Disinstallare l'applicazione manualmente e riprovare. + + Security Warning + Avviso di sicurezza + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + L'installazione in una cartella personalizzata può consentire a un utente malintenzionato di manomettere l'applicazione Windscribe. Per garantire la sicurezza dell'applicazione e del sistema, si consiglia vivamente di eseguire l'installazione nella posizione predefinita nella cartella "Programmi". Fare clic su OK per continuare con la cartella personalizzata o su Annulla per utilizzare il percorso predefinito. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Indica al programma di installazione di ignorare l'installazione dei driver. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Indica al programma di installazione di nascondere l'interfaccia utente. Implica -no-drivers e -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Eliminare le preferenze, i registri e altri dati esistenti, se esistenti. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. Il programma di installazione non è stato in grado di determinare se è in esecuzione con diritti di amministratore. Si prega di segnalare l'errore all'assistenza Windscribe. + + Instructs the installer to hide its user interface. + Indica al programma di installazione di nascondere l'interfaccia utente. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + Non si dispone di autorizzazioni sufficienti per eseguire l'applicazione. Per installare Windscribe sono necessari privilegi amministrativi. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_ja.ts b/installer/common/translations/windscribe_installer_ja.ts index 6e952e996..6d415c3c2 100644 --- a/installer/common/translations/windscribe_installer_ja.ts +++ b/installer/common/translations/windscribe_installer_ja.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. インストールフォルダには、アンインストールできなかったデータが含まれています。アプリケーションを手動でアンインストールして、もう一度やり直してください。 + + Security Warning + セキュリティ警告 + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + カスタムフォルダにインストールすると、攻撃者が Windscribe アプリケーションを改ざんする可能性があります。アプリケーションとシステムのセキュリティを確保するために、「Program Files」フォルダーのデフォルトの場所にインストールすることを強くお勧めします。「OK」をクリックしてカスタム・フォルダを続行するか、「キャンセル」をクリックしてデフォルトの場所を使用します。 + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. ドライバーのインストールをスキップするようにインストーラーに指示します。 - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - ユーザー インターフェイスを非表示にするようにインストーラーに指示します。 -ドライバーなしと-自動開始なしを意味します。 - Delete existing preferences, logs, and other data, if they exist. 既存の設定、ログ、およびその他のデータが存在する場合は削除します。 @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. インストーラーは、管理者権限で実行されているかどうかを判断できませんでした。 このエラーを Windscribe サポートに報告してください。 + + Instructs the installer to hide its user interface. + ユーザー インターフェイスを非表示にするようにインストーラーに指示します。 + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + このアプリケーションを実行するための十分なアクセス許可がありません。Windscribeをインストールするには管理者権限が必要です。 + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_ko.ts b/installer/common/translations/windscribe_installer_ko.ts index 1277d6a8b..4957c339b 100644 --- a/installer/common/translations/windscribe_installer_ko.ts +++ b/installer/common/translations/windscribe_installer_ko.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. 설치 폴더에는 제거할 수 없는 데이터가 포함되어 있습니다. 응용 프로그램을 수동으로 제거하고 다시 시도하십시오. + + Security Warning + 보안 경고 + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + 사용자 지정 폴더에 설치하면 공격자가 Windscribe 응용 프로그램을 변조할 수 있습니다. 응용 프로그램 및 시스템의 보안을 보장하려면 'Program Files' 폴더의 기본 위치에 설치하는 것이 좋습니다. 확인을 클릭하여 사용자 지정 폴더를 계속하거나 취소를 클릭하여 기본 위치를 사용합니다. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. 설치 관리자가 드라이버 설치를 건너뛰도록 지시합니다. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - 설치 관리자가 사용자 인터페이스를 숨기도록 지시합니다. -no-drivers 및 -no-auto-start를 의미합니다. - Delete existing preferences, logs, and other data, if they exist. 기존 기본 설정, 로그 및 기타 데이터(있는 경우)를 삭제합니다. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. 설치 관리자가 관리자 권한으로 실행 중인지 확인할 수 없습니다. 이 실패를 Windscribe 지원팀에 보고하십시오. + + Instructs the installer to hide its user interface. + 설치 관리자에게 사용자 인터페이스를 숨기도록 지시합니다. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + 이 응용 프로그램을 실행할 수 있는 충분한 권한이 없습니다. Windscribe를 설치하려면 관리자 권한이 필요합니다. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_pl.ts b/installer/common/translations/windscribe_installer_pl.ts index ce7c93af9..d33d1949d 100644 --- a/installer/common/translations/windscribe_installer_pl.ts +++ b/installer/common/translations/windscribe_installer_pl.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. Folder instalacyjny zawiera dane, których nie można odinstalować. Odinstaluj aplikację ręcznie i spróbuj ponownie. + + Security Warning + Ostrzeżenie dotyczące bezpieczeństwa + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + Instalacja w folderze niestandardowym może pozwolić atakującemu na manipulowanie aplikacją Windscribe. Aby zapewnić bezpieczeństwo aplikacji i systemu, zdecydowanie zalecamy instalację w domyślnej lokalizacji w folderze "Program Files". Kliknij przycisk OK, aby kontynuować pracę z folderem niestandardowym, lub przycisk Anuluj, aby użyć lokalizacji domyślnej. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Nakazuje instalatorowi pominięcie instalowania sterowników. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Nakazuje instalatorowi ukrycie interfejsu użytkownika. Implikuje -no-drivers i -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Usuń istniejące preferencje, dzienniki i inne dane, jeśli istnieją. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. Instalator nie był w stanie określić, czy jest uruchomiony z uprawnieniami administratora. Prosimy o zgłoszenie tego błędu do pomocy technicznej Windscribe. + + Instructs the installer to hide its user interface. + Nakazuje instalatorowi ukrycie interfejsu użytkownika. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + Nie masz wystarczających uprawnień do uruchamiania tej aplikacji. Do zainstalowania Windscribe wymagane są uprawnienia administratora. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_pt.ts b/installer/common/translations/windscribe_installer_pt.ts index 1cdc00b26..ec3c24070 100644 --- a/installer/common/translations/windscribe_installer_pt.ts +++ b/installer/common/translations/windscribe_installer_pt.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. A pasta de instalação contém dados que não puderam ser desinstalados. Desinstale o aplicativo manualmente e tente novamente. + + Security Warning + Aviso de Segurança + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + A instalação em uma pasta personalizada pode permitir que um invasor adultere o aplicativo Windscribe. Para garantir a segurança da aplicação e do seu sistema, recomendamos vivamente que instale na localização predefinida na pasta 'Program Files'. Clique em OK para continuar com a pasta personalizada ou em Cancelar para usar o local padrão. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Instrui o instalador a ignorar a instalação de drivers. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Instrui o instalador a ocultar sua interface de usuário. Implica -no-drivers e -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Exclua preferências, logs e outros dados existentes, se existirem. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. O instalador não conseguiu determinar se está a ser executado com direitos de administrador. Por favor, reporte esta falha ao suporte do Windscribe. + + Instructs the installer to hide its user interface. + Instrui o instalador a ocultar sua interface de usuário. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + Você não tem permissões suficientes para executar este aplicativo. São necessários privilégios administrativos para instalar o Windscribe. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_ru.ts b/installer/common/translations/windscribe_installer_ru.ts index bd05075ad..669d8da3e 100644 --- a/installer/common/translations/windscribe_installer_ru.ts +++ b/installer/common/translations/windscribe_installer_ru.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. Папка установки содержит данные, которые не удалось удалить. Удалите приложение вручную и повторите попытку. + + Security Warning + Предупреждение системы безопасности + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + Установка в пользовательскую папку может позволить злоумышленнику взломать приложение Windscribe. Чтобы обеспечить безопасность приложения и вашей системы, мы настоятельно рекомендуем вам установить его в папку «Program Files» по умолчанию. Нажмите кнопку ОК, чтобы продолжить работу с пользовательской папкой, или кнопку Отмена, чтобы использовать расположение по умолчанию. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Указывает установщику пропустить установку драйверов. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Указывает установщику скрыть свой пользовательский интерфейс. Подразумевает -no-drivers и -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Удалите существующие настройки, журналы и другие данные, если они существуют. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. Установщику не удалось определить, работает ли он с правами администратора. Пожалуйста, сообщите об этом сбое в службу поддержки Windscribe. + + Instructs the installer to hide its user interface. + Указывает установщику скрыть свой пользовательский интерфейс. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + У вас недостаточно разрешений для запуска этого приложения. Для установки Windscribe требуются права администратора. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_tr.ts b/installer/common/translations/windscribe_installer_tr.ts index b34c01ea6..6bd81a7ac 100644 --- a/installer/common/translations/windscribe_installer_tr.ts +++ b/installer/common/translations/windscribe_installer_tr.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. Yükleme klasörü kaldırılamayan veriler içeriyor. Lütfen uygulamayı manuel olarak kaldırın ve tekrar deneyin. + + Security Warning + Güvenlik Uyarısı + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + Özel bir klasöre yükleme, bir saldırganın Windscribe uygulamasını kurcalamasına izin verebilir. Uygulamanın ve sisteminizin güvenliğini sağlamak için, 'Program Files' klasöründeki varsayılan konuma yüklemenizi şiddetle tavsiye ederiz. Özel klasörle devam etmek için Tamam'ı veya varsayılan konumu kullanmak için İptal'i tıklatın. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Yükleyiciye sürücüleri yüklemeyi atlamasını söyler. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Yükleyiciye kullanıcı arabirimini gizlemesini söyler. -no-drivers ve -no-auto-start anlamına gelir. - Delete existing preferences, logs, and other data, if they exist. Varsa mevcut tercihleri, günlükleri ve diğer verileri silin. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. Yükleyici, yönetici haklarıyla çalışıp çalışmadığını belirleyemedi. Lütfen bu hatayı Windscribe desteğine bildirin. + + Instructs the installer to hide its user interface. + Yükleyiciye kullanıcı arabirimini gizlemesini söyler. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + Bu uygulamayı çalıştırmak için yeterli izinlere sahip değilsiniz. Windscribe'ı yüklemek için yönetici ayrıcalıkları gereklidir. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_uk.ts b/installer/common/translations/windscribe_installer_uk.ts index 0b38e12a9..100c15b4f 100644 --- a/installer/common/translations/windscribe_installer_uk.ts +++ b/installer/common/translations/windscribe_installer_uk.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. Папка інсталяції містить дані, які не вдалося видалити. Будь ласка, видаліть програму вручну та повторіть спробу. + + Security Warning + Попередження системи безпеки + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + Встановлення в спеціальну папку може дозволити зловмиснику втрутитися в роботу програми Windscribe. Щоб забезпечити безпеку програми та вашої системи, ми настійно рекомендуємо встановити її в папку «Program Files» за замовчуванням. Натисніть кнопку «OK», щоб продовжити роботу з власною папкою, або «Скасувати», щоб використовувати розташування за замовчуванням. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Наказує інсталятору пропустити встановлення драйверів. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Наказує інсталятору приховати інтерфейс користувача. Неявним чином встановлює -no-drivers і -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Видаліть наявні параметри, журнали та інші дані, якщо вони існують. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. Інсталятор не зміг визначити, чи працює він із правами адміністратора. Будь ласка, повідомте про цю помилку в службу підтримки Windscribe. + + Instructs the installer to hide its user interface. + Наказує інсталятору приховати інтерфейс користувача. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + У вас недостатньо дозволів для запуску цієї програми. Для встановлення Windscribe потрібні адміністративні привілеї. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_vi.ts b/installer/common/translations/windscribe_installer_vi.ts index 6059c222a..8f6707ed8 100644 --- a/installer/common/translations/windscribe_installer_vi.ts +++ b/installer/common/translations/windscribe_installer_vi.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. Thư mục cài đặt chứa dữ liệu không thể gỡ cài đặt. Vui lòng gỡ cài đặt ứng dụng theo cách thủ công và thử lại. + + Security Warning + Cảnh báo bảo mật + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + Cài đặt vào một thư mục tùy chỉnh có thể cho phép kẻ tấn công giả mạo ứng dụng Windscribe. Để đảm bảo tính bảo mật của ứng dụng và hệ thống của bạn, chúng tôi khuyên bạn nên cài đặt vào vị trí mặc định trong thư mục 'Tệp chương trình'. Bấm OK để tiếp tục với thư mục tùy chỉnh hoặc Hủy bỏ để sử dụng vị trí mặc định. + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. Hướng dẫn trình cài đặt bỏ qua cài đặt trình điều khiển. - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - Hướng dẫn trình cài đặt ẩn giao diện người dùng của nó. Ngụ ý -no-driver và -no-auto-start. - Delete existing preferences, logs, and other data, if they exist. Xóa các tùy chọn, nhật ký và dữ liệu khác hiện có, nếu chúng tồn tại. @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. Trình cài đặt không thể xác định xem nó có đang chạy với quyền quản trị viên hay không. Vui lòng báo cáo lỗi này cho bộ phận hỗ trợ của Windscribe. + + Instructs the installer to hide its user interface. + Hướng dẫn trình cài đặt ẩn giao diện người dùng của nó. + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + Bạn không có đủ quyền để chạy ứng dụng này. Cần có đặc quyền quản trị để cài đặt Windscribe. + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_zh-CN.ts b/installer/common/translations/windscribe_installer_zh-CN.ts index 6c9d90a8c..789b2019f 100644 --- a/installer/common/translations/windscribe_installer_zh-CN.ts +++ b/installer/common/translations/windscribe_installer_zh-CN.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. 安装文件夹包含无法卸载的数据。请手动卸载应用程序,然后重试。 + + Security Warning + 安全警告 + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + 安装到自定义文件夹可能允许攻击者篡改 Windscribe 应用程序。为确保应用程序和系统的安全,我们强烈建议您安装到“Program Files”文件夹中的默认位置。单击“确定”继续使用自定义文件夹,或单击“取消”使用默认位置。 + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. 指示安装程序跳过安装驱动程序。 - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - 指示安装程序隐藏其用户界面。 表示 -无驱动程序和 -无自动启动。 - Delete existing preferences, logs, and other data, if they exist. 删除现有首选项、日志和其他数据(如果存在)。 @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. 安装程序无法确定它是否以管理员权限运行。 请将此故障报告给 Windscribe 支持。 + + Instructs the installer to hide its user interface. + 指示安装程序隐藏其用户界面。 + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + 您没有足够的权限来运行此应用程序。安装 Windscribe 需要管理权限。 + SettingsWindow diff --git a/installer/common/translations/windscribe_installer_zh-TW.ts b/installer/common/translations/windscribe_installer_zh-TW.ts index b52978b7c..31655fb11 100644 --- a/installer/common/translations/windscribe_installer_zh-TW.ts +++ b/installer/common/translations/windscribe_installer_zh-TW.ts @@ -92,6 +92,14 @@ The installation folder contains data which could not be uninstalled. Please uninstall the application manually and try again. 安裝資料夾包含無法卸載的數據。請手動卸載應用程式,然後重試。 + + Security Warning + 安全警告 + + + Installation to a custom folder may allow an attacker to tamper with the Windscribe application. To ensure the security of the application, and your system, we strongly recommend you install to the default location in the 'Program Files' folder. Click OK to continue with the custom folder or Cancel to use the default location. + 安裝到自定義資料夾可能允許攻擊者篡改 Windscribe 應用程式。為確保應用程式和系統的安全,我們強烈建議您安裝到“Program Files”資料夾中的預設位置。按兩下確定繼續使用自訂資料夾,或按下取消「使用預設位置」。 + QObject @@ -123,10 +131,6 @@ Instructs the installer to skip installing drivers. 指示安裝程式跳過安裝驅動程式。 - - Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start. - 指示安裝程序隱藏其用戶介面。 表示 -無驅動程式和 -無自動啟動。 - Delete existing preferences, logs, and other data, if they exist. 刪除現有首選項、日誌和其他資料(如果存在)。 @@ -187,6 +191,14 @@ The installer was unable to determine if it is running with administrator rights. Please report this failure to Windscribe support. 安裝程式無法確定它是否以管理員許可權運行。 請將此故障報告給Windscribe支援。 + + Instructs the installer to hide its user interface. + 指示安裝程序隱藏其用戶介面。 + + + You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. + 您沒有足夠的權限來執行此應用程式。安裝Windscribe需要管理許可權。 + SettingsWindow diff --git a/installer/mac/installer/helper/helper_mac.mm b/installer/mac/installer/helper/helper_mac.mm index 9844c0b2e..4733e9a29 100644 --- a/installer/mac/installer/helper/helper_mac.mm +++ b/installer/mac/installer/helper/helper_mac.mm @@ -140,7 +140,6 @@ CMD_ANSWER Helper_mac::sendCmdToHelper(int cmdId, const std::string &data) { - [[Logger sharedLogger] logAndStdOut:[NSString stringWithFormat:@"sendCmdToHelper: %li", (long) cmdId]]; xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_int64(message, "cmdId", cmdId); xpc_dictionary_set_data(message, "data", data.c_str(), data.size()); @@ -151,7 +150,6 @@ [[Logger sharedLogger] logAndStdOut:[NSString stringWithFormat:@"xpc_connection_send_message_with_reply_sync return XPC_TYPE_ERROR"]]; return CMD_ANSWER(); } else if (type == XPC_TYPE_DICTIONARY) { - [[Logger sharedLogger] logAndStdOut:[NSString stringWithFormat:@"xpc_connection_send_message_with_reply_sync received dictionary"]]; size_t length; const void *buf = xpc_dictionary_get_data(answer, "data", &length); if (buf && length > 0) { diff --git a/installer/mac/installer/installer/installer_shim.mm b/installer/mac/installer/installer/installer_shim.mm index 9adf9a5d4..bb9b749c8 100644 --- a/installer/mac/installer/installer/installer_shim.mm +++ b/installer/mac/installer/installer/installer_shim.mm @@ -44,10 +44,10 @@ return ((__bridge Installer *)installer_).progress; } -bool InstallerShim::setInstallDir(std::wstring &path) +void InstallerShim::setInstallDir(const std::wstring &path) { // not supported on Mac - return true; + return; } std::wstring InstallerShim::installDir() diff --git a/installer/windows/installer/CMakeLists.txt b/installer/windows/installer/CMakeLists.txt index e9d8ff233..9cffbfa12 100644 --- a/installer/windows/installer/CMakeLists.txt +++ b/installer/windows/installer/CMakeLists.txt @@ -27,6 +27,7 @@ set(SOURCES ../../../client/common/archive/archive.cpp installer/installer.cpp installer/installer_shim.cpp + installer/installer_utils.cpp installer/blocks/files.cpp installer/blocks/icons.cpp installer/blocks/install_authhelper.cpp diff --git a/installer/windows/installer/installer/blocks/install_openvpn_dco.cpp b/installer/windows/installer/installer/blocks/install_openvpn_dco.cpp index db5ef5b1d..fd4e6602f 100644 --- a/installer/windows/installer/installer/blocks/install_openvpn_dco.cpp +++ b/installer/windows/installer/installer/blocks/install_openvpn_dco.cpp @@ -6,10 +6,10 @@ #include #include "../installer_base.h" +#include "../installer_utils.h" #include "../settings.h" #include "../../../utils/applicationinfo.h" #include "../../../utils/logger.h" -#include "../../../utils/utils.h" #include "types/global_consts.h" @@ -21,7 +21,7 @@ InstallOpenVPNDCO::InstallOpenVPNDCO(double weight) : IInstallBlock(weight, L"op int InstallOpenVPNDCO::executeStep() { - DWORD buildNum = Utils::getOSBuildNumber(); + DWORD buildNum = InstallerUtils::getOSBuildNumber(); if (buildNum < kMinWindowsBuildNumberForOpenVPNDCO) { Log::instance().out( "WARNING: OS version is not compatible with the OpenVPN DCO driver. Windows 10 build %lu or newer is required" diff --git a/installer/windows/installer/installer/blocks/uninstallprev.cpp b/installer/windows/installer/installer/blocks/uninstallprev.cpp index 2eb149ee5..8ed979319 100644 --- a/installer/windows/installer/installer/blocks/uninstallprev.cpp +++ b/installer/windows/installer/installer/blocks/uninstallprev.cpp @@ -269,4 +269,4 @@ bool UninstallPrev::extractUninstaller() archive_->finish(); return true; -} \ No newline at end of file +} diff --git a/installer/windows/installer/installer/installer_shim.cpp b/installer/windows/installer/installer/installer_shim.cpp index 2e3b1930e..851a556e9 100644 --- a/installer/windows/installer/installer/installer_shim.cpp +++ b/installer/windows/installer/installer/installer_shim.cpp @@ -2,8 +2,6 @@ #include "installer.h" #include "settings.h" -#include "../../utils/applicationinfo.h" -#include "../../utils/path.h" InstallerShim::InstallerShim() { @@ -50,14 +48,9 @@ void InstallerShim::finish() reinterpret_cast(installer_)->launchApp(); } -bool InstallerShim::setInstallDir(std::wstring &path) +void InstallerShim::setInstallDir(const std::wstring &path) { - if (!Path::isOnSystemDrive(path)) { - return true; - } - Settings::instance().setPath(path); - return false; } std::wstring InstallerShim::installDir() diff --git a/installer/windows/installer/installer/installer_utils.cpp b/installer/windows/installer/installer/installer_utils.cpp new file mode 100644 index 000000000..53fab08c2 --- /dev/null +++ b/installer/windows/installer/installer/installer_utils.cpp @@ -0,0 +1,140 @@ +#include "installer_utils.h" + +#include +#include + +#include + +#include "settings.h" +#include "../../utils/applicationinfo.h" +#include "../../utils/logger.h" + +using namespace std; + +namespace InstallerUtils +{ + +DWORD getOSBuildNumber() +{ + HMODULE hDLL = ::GetModuleHandleA("ntdll.dll"); + if (hDLL == NULL) { + Log::WSDebugMessage(L"Failed to load the ntdll module (%lu)", ::GetLastError()); + return 0; + } + + typedef NTSTATUS (WINAPI* RtlGetVersionFunc)(LPOSVERSIONINFOEXW lpVersionInformation); + + RtlGetVersionFunc rtlGetVersionFunc = (RtlGetVersionFunc)::GetProcAddress(hDLL, "RtlGetVersion"); + if (rtlGetVersionFunc == NULL) { + Log::WSDebugMessage(L"Failed to load RtlGetVersion function (%lu)", ::GetLastError()); + return 0; + } + + RTL_OSVERSIONINFOEXW rtlOsVer; + ::ZeroMemory(&rtlOsVer, sizeof(RTL_OSVERSIONINFOEXW)); + rtlOsVer.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); + rtlGetVersionFunc(&rtlOsVer); + + return rtlOsVer.dwBuildNumber; +} + +static wstring getVersionInfoItem(const wstring &exeName, const wstring &itemName) +{ + wstring itemValue; + + struct LANGANDCODEPAGE { + WORD wLanguage; + WORD wCodePage; + } *lpTranslate; + + DWORD dwNotUsed; + DWORD dwSize = ::GetFileVersionInfoSize(exeName.c_str(), &dwNotUsed); + + if (dwSize > 0) { + unique_ptr versionInfo(new UCHAR[dwSize]); + BOOL result = ::GetFileVersionInfo(exeName.c_str(), 0L, dwSize, versionInfo.get()); + if (result) { + // To get a string value must pass query in the form + // "\StringFileInfo\\keyname" + // where is the languageID concatenated with the code page, in hex. + UINT nTranslateLen; + result = ::VerQueryValue(versionInfo.get(), L"\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &nTranslateLen); + + if (result) { + for (UINT i = 0; i < (nTranslateLen/sizeof(struct LANGANDCODEPAGE)); ++i) { + wchar_t subBlock[MAX_PATH]; + swprintf_s(subBlock, MAX_PATH, L"\\StringFileInfo\\%04x%04x\\%s", lpTranslate[i].wLanguage, + lpTranslate[i].wCodePage, itemName.c_str()); + + LPVOID lpvi; + UINT nLen; + result = ::VerQueryValue(versionInfo.get(), subBlock, &lpvi, &nLen); + + if (result && nLen > 0) { + itemValue = wstring((LPCTSTR)lpvi); + break; + } + } + } + } + } + + return itemValue; +} + +bool installedAppVersionLessThan(const wstring &version) +{ + filesystem::path appExe(Settings::instance().getPath()); + appExe.append(ApplicationInfo::appExeName()); + + if (!filesystem::exists(appExe)) { + return false; + } + + const wstring installedAppVersion = getVersionInfoItem(appExe.native(), L"ProductVersion"); + if (installedAppVersion.empty()) { + Log::WSDebugMessage(L"installedAppVersionLessThan - failed to retrieve installed app version"); + return false; + } + + int result = ::StrCmpLogicalW(installedAppVersion.c_str(), version.c_str()); + return (result < 0); +} + +static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + if (uMsg == BFFM_INITIALIZED) { + wstring tmp = (const wchar_t*)lpData; + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); + } + return 0; +} + +wstring selectInstallFolder(HWND owner, const wstring &title, const wstring &initialFolder) +{ + wstring installFolder; + + BROWSEINFO bi = { 0 }; + bi.hwndOwner = owner; + bi.lpszTitle = title.c_str(); + bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_DONTGOBELOWDOMAIN | BIF_NEWDIALOGSTYLE; + bi.lpfn = BrowseCallbackProc; + bi.lParam = (LPARAM)initialFolder.c_str(); + + LPITEMIDLIST pidl = ::SHBrowseForFolder(&bi); + + if (pidl != 0) { + //get the name of the folder and put it in path + wchar_t path[MAX_PATH]; + auto result = ::SHGetPathFromIDList(pidl, path); + ::CoTaskMemFree(pidl); + + if (result) { + installFolder = path; + } + } + + return installFolder; +} + +} diff --git a/installer/windows/installer/installer/installer_utils.h b/installer/windows/installer/installer/installer_utils.h new file mode 100644 index 000000000..584b6cfd1 --- /dev/null +++ b/installer/windows/installer/installer/installer_utils.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +namespace InstallerUtils +{ + +DWORD getOSBuildNumber(); +bool installedAppVersionLessThan(const std::wstring &version); +std::wstring selectInstallFolder(HWND owner, const std::wstring &title, const std::wstring &initialFolder); + +} diff --git a/installer/windows/installer/installer/settings.cpp b/installer/windows/installer/installer/settings.cpp index 05b98f1e6..ce5ce8b65 100644 --- a/installer/windows/installer/installer/settings.cpp +++ b/installer/windows/installer/installer/settings.cpp @@ -6,13 +6,16 @@ #include "../../utils/path.h" #include "wincryptutils.h" -Settings::Settings() : isCreateShortcut_(true) +Settings::Settings() { + setPath(ApplicationInfo::defaultInstallPath()); } void Settings::setPath(const std::wstring &path) { - path_ = Path::removeSeparator(path); + if (!path.empty()) { + path_ = Path::removeSeparator(path); + } } std::wstring Settings::getPath() const @@ -69,15 +72,15 @@ void Settings::setCredentials(const std::wstring &username, const std::wstring & void Settings::readFromRegistry() { QSettings reg(QString::fromStdWString(ApplicationInfo::installerRegistryKey()), QSettings::NativeFormat); + if (reg.contains("applicationPath")) { - setPath(reg.value("applicationPath").toString().toStdWString()); - } + const auto path = reg.value("applicationPath").toString().toStdWString(); - if (path_.empty() || !Path::isOnSystemDrive(path_)) { - // Default the install path if one does not exist in the Registy. - // For security purposes, ensure the user did not try to 'tweak' the Registry entry - // to specify installation on a non-system drive. - setPath(ApplicationInfo::defaultInstallPath()); + if (!path.empty() && Path::isOnSystemDrive(path)) { + // For security purposes, ensure the user did not try to 'tweak' the Registry entry + // to specify installation on a non-system drive. + setPath(path); + } } if (reg.contains("isCreateShortcut")) { diff --git a/installer/windows/installer/installer/settings.h b/installer/windows/installer/installer/settings.h index d07753bc8..99039a8e7 100644 --- a/installer/windows/installer/installer/settings.h +++ b/installer/windows/installer/installer/settings.h @@ -32,10 +32,10 @@ class Settings std::wstring path_; std::wstring username_; std::wstring password_; - bool isCreateShortcut_; - bool isInstallDrivers_; - bool isAutoStart_; - bool isFactoryReset_; + bool isCreateShortcut_ = true; + bool isInstallDrivers_ = true; + bool isAutoStart_ = true; + bool isFactoryReset_ = false; explicit Settings(); ~Settings() = default; diff --git a/installer/windows/installer/main.cpp b/installer/windows/installer/main.cpp index 62e74a60c..236f021e9 100644 --- a/installer/windows/installer/main.cpp +++ b/installer/windows/installer/main.cpp @@ -51,14 +51,10 @@ static std::optional isElevated() return Elevation.TokenIsElevated; } -static int WSMessageBox(const QString title, const QString text) +static int WSMessageBox(const QString &title, const QString &text) { - QMessageBox *box = new QMessageBox(QMessageBox::Critical, title, text); - - int nResult = box->exec(); - delete box; - - return nResult; + QScopedPointer box(new QMessageBox(QMessageBox::Critical, title, text)); + return box->exec(); } static void loadSystemLanguage(QTranslator &translator, QApplication *app) @@ -212,7 +208,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmd .arg(QObject::tr("Show this information.")) .arg(QObject::tr("Do not launch the application after installation.")) .arg(QObject::tr("Instructs the installer to skip installing drivers.")) - .arg(QObject::tr("Instructs the installer to hide its user interface. Implies -no-drivers and -no-auto-start.")) + .arg(QObject::tr("Instructs the installer to hide its user interface.")) .arg(QObject::tr("Delete existing preferences, logs, and other data, if they exist.")) .arg(QObject::tr("Overrides the default installation directory. Installation directory must be on the system drive.")) .arg(QObject::tr("Sets the username the application will use to automatically log in when first launched.")) @@ -349,6 +345,14 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmd return 0; } + // MainWindow does not create a UI when running in silent mode. We'll have to use a standard messagebox + // for this edge case. + if (!isAdmin.value() && ops.silent) { + WSMessageBox(QObject::tr("Windscribe Install Error"), + QObject::tr("You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe.")); + return 0; + } + MainWindow w(isAdmin.value(), ops); w.show(); diff --git a/installer/windows/utils/applicationinfo.cpp b/installer/windows/utils/applicationinfo.cpp index aeeb3b75f..8905b2491 100644 --- a/installer/windows/utils/applicationinfo.cpp +++ b/installer/windows/utils/applicationinfo.cpp @@ -1,11 +1,10 @@ #include "applicationinfo.h" -#include #include #include -#include "logger.h" #include "path.h" +#include "utils.h" #include "version/windscribe_version.h" namespace ApplicationInfo { @@ -59,21 +58,8 @@ wstring appExeName() wstring defaultInstallPath() { - wstring defaultPath; - - TCHAR programFilesPath[MAX_PATH]; - BOOL result = ::SHGetSpecialFolderPath(0, programFilesPath, CSIDL_PROGRAM_FILES, FALSE); - if (!result) { - Log::WSDebugMessage(L"defaultInstallPath - SHGetSpecialFolderPath failed"); - defaultPath = wstring(L"C:\\Program Files"); - } - else { - defaultPath = wstring(programFilesPath); - } - - defaultPath = Path::append(defaultPath, name()); - - return defaultPath; + wstring programFiles = Utils::programFilesFolder(); + return Path::append(programFiles, name()); } wstring appRegistryKey() diff --git a/installer/windows/utils/logger.cpp b/installer/windows/utils/logger.cpp index 89bd5d28b..87d9023bf 100644 --- a/installer/windows/utils/logger.cpp +++ b/installer/windows/utils/logger.cpp @@ -105,14 +105,12 @@ void Log::writeFile(const wstring& installPath) const DWORD attrs = ::GetFileAttributes(installPath.c_str()); if (attrs == INVALID_FILE_ATTRIBUTES) { - writeToSystemDebugger(); WSDebugMessage(L"Log::writeFile - GetFileAttributes(%s) failed (%lu)", installPath.c_str(), ::GetLastError()); return; } // This will be true if a symbolic link has been created on the folder, or a file within the folder. if (attrs & FILE_ATTRIBUTE_REPARSE_POINT) { - writeToSystemDebugger(); WSDebugMessage(L"Log::writeFile - the target folder is, or contains, a suspicious symbolic link (%s)", installPath.c_str()); return; } @@ -123,7 +121,6 @@ void Log::writeFile(const wstring& installPath) const FILE* fileHandle = nullptr; errno_t result = _wfopen_s(&fileHandle, fileName.c_str(), L"wx"); if ((result != 0) || (fileHandle == nullptr)) { - writeToSystemDebugger(); WSDebugMessage(L"Log::writeFile - could not open %s (%d)", fileName.c_str(), result); return; } @@ -135,10 +132,3 @@ void Log::writeFile(const wstring& installPath) const fflush(fileHandle); fclose(fileHandle); } - -void Log::writeToSystemDebugger() const -{ - for (const auto &entry : logEntries_) { - ::OutputDebugStringW(entry.c_str()); - } -} diff --git a/installer/windows/utils/logger.h b/installer/windows/utils/logger.h index 947469364..0e668a9dc 100644 --- a/installer/windows/utils/logger.h +++ b/installer/windows/utils/logger.h @@ -36,6 +36,4 @@ class Log Log(); ~Log(); - - void writeToSystemDebugger() const; }; diff --git a/installer/windows/utils/path.cpp b/installer/windows/utils/path.cpp index 56ac67c50..0d8f03d4b 100644 --- a/installer/windows/utils/path.cpp +++ b/installer/windows/utils/path.cpp @@ -80,4 +80,16 @@ wstring append(const std::wstring &dir, const std::wstring &suffix) return parent.make_preferred(); } +bool isSystemProtected(const wstring &dir) +{ + // We're not doing any actual 'system protected' checks here. The user should be installing + // to 'Program Files'. Any other system-protected location is an anti-pattern. + + // make_preferred to normalize the path separator. + filesystem::path fsDir(dir); + const auto targetDir = removeSeparator(fsDir.make_preferred()); + const auto programFiles = Utils::programFilesFolder(); + return ::PathIsPrefix(programFiles.c_str(), dir.c_str()); +} + } diff --git a/installer/windows/utils/path.h b/installer/windows/utils/path.h index ec917cb45..10346520a 100644 --- a/installer/windows/utils/path.h +++ b/installer/windows/utils/path.h @@ -13,4 +13,5 @@ namespace Path bool equivalent(const std::wstring& fileName1, const std::wstring& fileName2); bool isOnSystemDrive(const std::wstring& fileName); bool isRoot(const std::wstring& fileName); + bool isSystemProtected(const std::wstring &dir); } diff --git a/installer/windows/utils/utils.cpp b/installer/windows/utils/utils.cpp index 78d1542a4..1bbb381a4 100644 --- a/installer/windows/utils/utils.cpp +++ b/installer/windows/utils/utils.cpp @@ -29,7 +29,7 @@ wstring GetSystemDir() } optional InstExec(const wstring& appName, const wstring& commandLine, DWORD timeoutMS, - WORD showWindowFlags, const std::wstring ¤tFolder, DWORD *lastError) + WORD showWindowFlags, const wstring ¤tFolder, DWORD *lastError) { wostringstream stream; if (!appName.empty()) { @@ -77,7 +77,7 @@ optional InstExec(const wstring& appName, const wstring& commandLine, DWO if (lastError) { *lastError = ::GetLastError(); } - return std::nullopt; + return nullopt; } ::CloseHandle(pi.hThread); @@ -101,7 +101,7 @@ optional InstExec(const wstring& appName, const wstring& commandLine, DWO if (lastError) { *lastError = ::GetLastError(); } - return std::nullopt; + return nullopt; } if (waitResult == WAIT_TIMEOUT) { @@ -116,7 +116,7 @@ optional InstExec(const wstring& appName, const wstring& commandLine, DWO if (lastError) { *lastError = ::GetLastError(); } - return std::nullopt; + return nullopt; } return processExitCode; @@ -183,7 +183,7 @@ FindAppWindowHandleProc(HWND hwnd, LPARAM lParam) return TRUE; } - std::wstring exeName = Path::extractName(std::wstring(imageName, pathLen)); + wstring exeName = Path::extractName(wstring(imageName, pathLen)); if (_wcsicmp(exeName.c_str(), ApplicationInfo::appExeName().c_str()) == 0) { @@ -203,34 +203,22 @@ FindAppWindowHandleProc(HWND hwnd, LPARAM lParam) HWND appMainWindowHandle() { - auto pWindowInfo = std::make_unique(); + auto pWindowInfo = make_unique(); ::EnumWindows((WNDENUMPROC)FindAppWindowHandleProc, (LPARAM)pWindowInfo.get()); return pWindowInfo->appMainWindow; } -DWORD getOSBuildNumber() +wstring programFilesFolder() { - HMODULE hDLL = ::GetModuleHandleA("ntdll.dll"); - if (hDLL == NULL) { - Log::WSDebugMessage(L"Failed to load the ntdll module (%lu)", ::GetLastError()); - return 0; + TCHAR programFilesPath[MAX_PATH]; + BOOL result = ::SHGetSpecialFolderPath(0, programFilesPath, CSIDL_PROGRAM_FILES, FALSE); + if (!result) { + Log::WSDebugMessage(L"programFilesFolder - SHGetSpecialFolderPath failed, using default"); + return wstring(L"C:\\Program Files"); } - typedef NTSTATUS (WINAPI* RtlGetVersionFunc)(LPOSVERSIONINFOEXW lpVersionInformation); - - RtlGetVersionFunc rtlGetVersionFunc = (RtlGetVersionFunc)::GetProcAddress(hDLL, "RtlGetVersion"); - if (rtlGetVersionFunc == NULL) { - Log::WSDebugMessage(L"Failed to load RtlGetVersion function (%lu)", ::GetLastError()); - return 0; - } - - RTL_OSVERSIONINFOEXW rtlOsVer; - ::ZeroMemory(&rtlOsVer, sizeof(RTL_OSVERSIONINFOEXW)); - rtlOsVer.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); - rtlGetVersionFunc(&rtlOsVer); - - return rtlOsVer.dwBuildNumber; + return wstring(programFilesPath); } } diff --git a/installer/windows/utils/utils.h b/installer/windows/utils/utils.h index bd6781b05..1288f7bc3 100644 --- a/installer/windows/utils/utils.h +++ b/installer/windows/utils/utils.h @@ -13,6 +13,7 @@ HWND appMainWindowHandle(); std::wstring DesktopFolder(); std::wstring GetSystemDir(); +std::wstring programFilesFolder(); std::wstring StartMenuProgramsFolder(); // Run appName with the given commandLine and showWindowFlags. Wait timeoutMS milliseconds for @@ -24,5 +25,4 @@ std::optional InstExec(const std::wstring &appName, const std::wstring &c const std::wstring ¤tFolder = std::wstring(), DWORD *lastError = nullptr); -DWORD getOSBuildNumber(); } diff --git a/installer/windows/utils/windscribepathcheck.cpp b/installer/windows/utils/windscribepathcheck.cpp index d4f426af8..b5e616c1c 100644 --- a/installer/windows/utils/windscribepathcheck.cpp +++ b/installer/windows/utils/windscribepathcheck.cpp @@ -2,6 +2,7 @@ #include +#include "applicationinfo.h" #include "path.h" namespace PathCheck @@ -9,6 +10,10 @@ namespace PathCheck bool isNeedAppendSubdirectory(const std::wstring &installPath, const std::wstring &prevInstallPath) { + if (Path::equivalent(ApplicationInfo::defaultInstallPath(), installPath)) { + return false; + } + // this is current app dir, then nothing to append if (!installPath.empty() && !prevInstallPath.empty() && Path::equivalent(installPath, prevInstallPath)) { return false; @@ -33,4 +38,4 @@ bool isNeedAppendSubdirectory(const std::wstring &installPath, const std::wstrin return (isDirExists && !isDirEmpty); } -} \ No newline at end of file +} diff --git a/libs/wsnet/CMakeLists.txt b/libs/wsnet/CMakeLists.txt index 8d46f39cc..1b9116d96 100644 --- a/libs/wsnet/CMakeLists.txt +++ b/libs/wsnet/CMakeLists.txt @@ -18,26 +18,6 @@ project(wsnet LANGUAGES CXX ) -# Helpers functions for creating config files that can be included by other projects to find and use a package -include(CMakePackageConfigHelpers) -include(GNUInstallDirs) - -#TODO: move fork to another repo or make vcpkg port? -# For Android and iOS using the scapix library for automatic binding to Java/Objective C languages -if(ANDROID OR IOS) - include(FetchContent) - FetchContent_Declare( - cmodule - URL "https://github.com/AzanovAA/cmodule/archive/refs/heads/master.zip" - URL_HASH SHA256=895b6676f81b487bff254eb9e0550e86b1325b84595973205056531e4831d3f8 - - #URL "https://github.com/scapix-com/cmodule/archive/refs/tags/v1.0.42.tar.gz" - #URL_HASH SHA256=0fc5bb6bde3054664713bc9cba48f44a2f8af8fa2b94eb0da1031d5298f9ccf6 - ) - FetchContent_MakeAvailable(cmodule) - find_package(Scapix REQUIRED) -endif() - find_package(c-ares CONFIG REQUIRED) find_package(OpenSSL REQUIRED) find_package(CURL CONFIG REQUIRED) @@ -46,27 +26,21 @@ find_package(RapidJSON CONFIG REQUIRED) find_package(skyr-url CONFIG REQUIRED) find_package(GTest CONFIG REQUIRED) find_package(CMakeRC) -find_path(BSHOSHANY_THREAD_POOL_INCLUDE_DIRS "BS_thread_pool.hpp") find_path(CPP_BASE64_INCLUDE_DIRS "cpp-base64/base64.cpp") -find_package(reproc++ CONFIG REQUIRED) + +find_package(Boost REQUIRED COMPONENTS filesystem) +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) +else() + message(STATUS "Boost NOT Found !") +endif(Boost_FOUND) find_path(ADVOBFUSCATOR_INCLUDE_DIRS "Lib/Indexes.h") +# Get all public headers # Each public header file must have one class and the file name must match the class name (Java language requirement). -set(WS_CPP_PUBLIC_HEADERS - include/wsnet/WSNet.h - include/wsnet/WSNetAdvancedParameters.h - include/wsnet/WSNetCancelableCallback.h - include/wsnet/WSNetDnsRequestResult.h - include/wsnet/WSNetDnsResolver.h - include/wsnet/WSNetEmergencyConnect.h - include/wsnet/WSNetEmergencyConnectEndpoint.h - include/wsnet/WSNetHttpRequest.h - include/wsnet/WSNetHttpNetworkManager.h - include/wsnet/WSNetServerAPI.h - include/wsnet/WSNetPingManager.h - include/wsnet/WSNetUtils.h -) +# The file name must begin with the prefix "WSNet". +file(GLOB WS_CPP_PUBLIC_HEADERS RELATIVE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include/wsnet/WSNet*.h) cmrc_add_resource_library( cert-resources @@ -95,9 +69,9 @@ if (IOS) set (OS_SPECIFIC_LIBRARIES "-framework Foundation") endif() -target_link_libraries(wsnet PRIVATE c-ares::cares CURL::libcurl spdlog::spdlog rapidjson skyr::skyr-url OpenSSL::SSL wsnet::rc reproc++ ${OS_SPECIFIC_LIBRARIES}) +target_link_libraries(wsnet PRIVATE c-ares::cares CURL::libcurl spdlog::spdlog rapidjson skyr::skyr-url OpenSSL::SSL wsnet::rc Boost::filesystem ${OS_SPECIFIC_LIBRARIES}) target_include_directories(wsnet PRIVATE - ${PROJECT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include/wsnet ${CMAKE_CURRENT_SOURCE_DIR}/src ${BSHOSHANY_THREAD_POOL_INCLUDE_DIRS} + ${PROJECT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include/wsnet ${CMAKE_CURRENT_SOURCE_DIR}/src ${CPP_BASE64_INCLUDE_DIRS} ${ADVOBFUSCATOR_INCLUDE_DIRS} ) @@ -115,9 +89,10 @@ target_include_directories(wsnet PUBLIC $ $) -target_compile_definitions(wsnet PUBLIC BS_THREAD_POOL_ENABLE_PAUSE) +# For Android and iOS using the scapix library for automatic binding to Java/Objective C languages if(ANDROID OR IOS) + find_package(scapix CONFIG REQUIRED) scapix_bridge_headers(wsnet "com.wsnet.lib" ${WS_CPP_PUBLIC_HEADERS}) endif() @@ -136,6 +111,11 @@ if (IOS) MACOSX_FRAMEWORK_IDENTIFIER com.cmake.wsnet PUBLIC_HEADER "${WS_OBJC_PUBLIC_HEADERS}" ) + + # This file is also used by the above generated headers, so copy it to framework headers + install(FILES ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/src/scapix/source/scapix/bridge/objc/BridgeObject.h + DESTINATION wsnet.framework/Headers/scapix/bridge/objc + ) endif() # Strip binary for release builds (in particular for Android for some reason this is not done automatically) diff --git a/libs/wsnet/include/wsnet/WSNetHttpNetworkManager.h b/libs/wsnet/include/wsnet/WSNetHttpNetworkManager.h index cce68a9ba..20ea34257 100644 --- a/libs/wsnet/include/wsnet/WSNetHttpNetworkManager.h +++ b/libs/wsnet/include/wsnet/WSNetHttpNetworkManager.h @@ -22,6 +22,8 @@ typedef std::function WS typedef std::function &ips)> WSNetHttpNetworkManagerWhitelistIpsCallback; +typedef std::function &sockets)> WSNetHttpNetworkManagerWhitelistSocketsCallback; + // Some simplified implementation of HTTP network manager for our needs based on curl and custom DNS-resolver based on c-ares. // In particular, it has the functionality to whitelist IP addresses to firewall exceptions. // It has an internal DNS cache. @@ -60,8 +62,15 @@ class WSNetHttpNetworkManager : public scapix_object const std::string &username = std::string(), const std::string &password = std::string()) = 0; - // callback function allowing the caller to add addresses to the firewall exceptions + // callback function allowing the caller to add IP-addresses to the firewall exceptions + // this callback function must return control after the firewall is configured + // you can pass null to disable the callback function virtual std::shared_ptr setWhitelistIpsCallback(WSNetHttpNetworkManagerWhitelistIpsCallback whitelistIpsCallback) = 0; + + // callback function allowing the caller to add sockets to the firewall exceptions (Android specific) + // this callback function must return control after the firewall is configured + // you can pass null to disable the callback function + virtual std::shared_ptr setWhitelistSocketsCallback(WSNetHttpNetworkManagerWhitelistSocketsCallback whitelistSocketsCallback) = 0; }; } // namespace wsnet diff --git a/libs/wsnet/include/wsnet/WSNetServerAPI.h b/libs/wsnet/include/wsnet/WSNetServerAPI.h index 5885a675b..0edf04f5b 100644 --- a/libs/wsnet/include/wsnet/WSNetServerAPI.h +++ b/libs/wsnet/include/wsnet/WSNetServerAPI.h @@ -83,7 +83,11 @@ class WSNetServerAPI : public scapix_object virtual std::shared_ptr myIP(WSNetRequestFinishedCallback callback) = 0; - virtual std::shared_ptr mobileBillingPlans(const std::string &mobilePlanType, int version, WSNetRequestFinishedCallback callback) = 0; + virtual std::shared_ptr mobileBillingPlans(const std::string &authHash, const std::string &mobilePlanType, const std::string &promo, int version, WSNetRequestFinishedCallback callback) = 0; + + + virtual std::shared_ptr sendPayment(const std::string &authHash, const std::string &appleID, const std::string &appleData, const std::string &appleSIG, + WSNetRequestFinishedCallback callback) = 0; // Required: purchaseToken // Optionals: gpPackageName, gpProductId, type, amazonUserId @@ -93,6 +97,7 @@ class WSNetServerAPI : public scapix_object const std::string &amazonUserId, WSNetRequestFinishedCallback callback) = 0; + virtual std::shared_ptr postBillingCpid(const std::string &authHash, const std::string &payCpid, WSNetRequestFinishedCallback callback) = 0; virtual std::shared_ptr getXpressLoginCode(WSNetRequestFinishedCallback callback) = 0; virtual std::shared_ptr verifyXpressLoginCode(const std::string &xpressCode, const std::string &sig, WSNetRequestFinishedCallback callback) = 0; @@ -112,6 +117,14 @@ class WSNetServerAPI : public scapix_object virtual std::shared_ptr claimAccount(const std::string &authHash, const std::string &username, const std::string &password, const std::string &email, const std::string &claimAccount, WSNetRequestFinishedCallback callback) = 0; + + + virtual std::shared_ptr shakeData(const std::string &authHash, + WSNetRequestFinishedCallback callback) = 0; + virtual std::shared_ptr recordShakeForDataScore(const std::string &authHash, const std::string &platform, + const std::string &score, const std::string &signature, + WSNetRequestFinishedCallback callback) = 0; + }; } // namespace wsnet diff --git a/libs/wsnet/src/dnsresolver/dnsresolver_cares.h b/libs/wsnet/src/dnsresolver/dnsresolver_cares.h index ed00f5a9f..72b61c907 100644 --- a/libs/wsnet/src/dnsresolver/dnsresolver_cares.h +++ b/libs/wsnet/src/dnsresolver/dnsresolver_cares.h @@ -6,7 +6,6 @@ #include #include #include -#include #include "WSNetDnsResolver.h" #include "areslibraryinit.h" diff --git a/libs/wsnet/src/emergencyconnect/emergencyconnect.cpp b/libs/wsnet/src/emergencyconnect/emergencyconnect.cpp index 2475e4593..e8b9eff43 100644 --- a/libs/wsnet/src/emergencyconnect/emergencyconnect.cpp +++ b/libs/wsnet/src/emergencyconnect/emergencyconnect.cpp @@ -10,8 +10,8 @@ CMRC_DECLARE(wsnet); namespace wsnet { -EmergencyConnect::EmergencyConnect(BS::thread_pool &taskQueue, IFailoverContainer *failoverContainer, WSNetDnsResolver *dnsResolver) : - taskQueue_(taskQueue), +EmergencyConnect::EmergencyConnect(boost::asio::io_context &io_context, IFailoverContainer *failoverContainer, WSNetDnsResolver *dnsResolver) : + io_context_(io_context), failoverContainer_(failoverContainer), dnsResolver_(dnsResolver) { @@ -53,7 +53,7 @@ std::shared_ptr EmergencyConnect::getIpEndpoints(WSNetE { #ifndef FAILOVER_CONTAINER_PUBLIC auto cancelableCallback = std::make_shared>(callback); - taskQueue_.detach_task([this, cancelableCallback] { + boost::asio::post(io_context_, [this, cancelableCallback] { auto failover = failoverContainer_->failoverById(FAILOVER_OLD_RANDOM_DOMAIN_GENERATION); assert(failover); std::vector data; @@ -78,7 +78,7 @@ void EmergencyConnect::onDnsResolved(std::uint64_t requestId, const std::string { #ifndef FAILOVER_CONTAINER_PUBLIC - taskQueue_.detach_task([this, requestId, hostname, result] { + boost::asio::post(io_context_, [this, requestId, hostname, result] { auto it = dnsRequests_.find(requestId); if (it == dnsRequests_.end()) return; diff --git a/libs/wsnet/src/emergencyconnect/emergencyconnect.h b/libs/wsnet/src/emergencyconnect/emergencyconnect.h index ed06492c7..8cb584f99 100644 --- a/libs/wsnet/src/emergencyconnect/emergencyconnect.h +++ b/libs/wsnet/src/emergencyconnect/emergencyconnect.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include "WSNetEmergencyConnect.h" #include "WSNetDnsResolver.h" #include "failover/ifailovercontainer.h" @@ -12,7 +12,7 @@ namespace wsnet { class EmergencyConnect : public WSNetEmergencyConnect { public: - explicit EmergencyConnect(BS::thread_pool &taskQueue, IFailoverContainer *failoverContainer, WSNetDnsResolver *dnsResolver); + explicit EmergencyConnect(boost::asio::io_context &io_context, IFailoverContainer *failoverContainer, WSNetDnsResolver *dnsResolver); virtual ~EmergencyConnect(); std::string ovpnConfig() const override; @@ -22,7 +22,7 @@ class EmergencyConnect : public WSNetEmergencyConnect std::shared_ptr getIpEndpoints(WSNetEmergencyConnectCallback callback) override; private: - BS::thread_pool &taskQueue_; + boost::asio::io_context &io_context_; IFailoverContainer *failoverContainer_; WSNetDnsResolver *dnsResolver_; diff --git a/libs/wsnet/src/failover/failoverdata.h b/libs/wsnet/src/failover/failoverdata.h index 0a04b8e41..dd992c059 100644 --- a/libs/wsnet/src/failover/failoverdata.h +++ b/libs/wsnet/src/failover/failoverdata.h @@ -13,7 +13,7 @@ class FailoverData { public: explicit FailoverData(const std::string &domain) : domain_(domain) {} explicit FailoverData(const std::string &domain, const std::string &sniDomain) : domain_(domain), sniDomain_(sniDomain) {} - explicit FailoverData(const std::string &domain, const std::string &echConfig, int ttl) : + explicit FailoverData(const std::string &domain, const std::string &echConfig, unsigned long ttl) : domain_(domain), echConfig_(echConfig), ttl_(ttl) { startTime_ = std::chrono::steady_clock::now(); @@ -44,7 +44,7 @@ class FailoverData { std::string domain_; std::string sniDomain_; // empty if no SNI spoofing / domain fronting std::string echConfig_; // empty if it does not support ECH - std::optional ttl_; // TTL in seconds + std::optional ttl_; // TTL in seconds std::chrono::steady_clock::time_point startTime_; }; diff --git a/libs/wsnet/src/httpnetworkmanager/curlnetworkmanager.cpp b/libs/wsnet/src/httpnetworkmanager/curlnetworkmanager.cpp index 2b841c188..17b62fb1e 100644 --- a/libs/wsnet/src/httpnetworkmanager/curlnetworkmanager.cpp +++ b/libs/wsnet/src/httpnetworkmanager/curlnetworkmanager.cpp @@ -6,6 +6,10 @@ #include #include +#ifdef _WIN32 +#else + #include +#endif namespace wsnet { CurlNetworkManager::CurlNetworkManager(CurlFinishedCallback finishedCallback, CurlProgressCallback progressCallback, CurlReadyDataCallback readyDataCallback) : @@ -82,6 +86,12 @@ void CurlNetworkManager::setProxySettings(const std::string &address, const std: proxySettings_.password = password; } +void CurlNetworkManager::setWhitelistSocketsCallback(std::shared_ptr > callback) +{ + std::lock_guard locker(mutex_); + whitelistSocketsCallback_ = callback; +} + void CurlNetworkManager::run() { while (!finish_) { @@ -191,6 +201,41 @@ int CurlNetworkManager::progressCallback(void *ri, curl_off_t dltotal, curl_off_ return 0; } +int CurlNetworkManager::curlSocketCallback(void *clientp, curl_socket_t curlfd, curlsocktype purpose) +{ + CurlNetworkManager *this_ = (CurlNetworkManager *)clientp; + + std::lock_guard locker(this_->mutex_); + // whitelist the new socket descriptor + if (this_->whitelistSockets_.find(curlfd) == this_->whitelistSockets_.end()) { + this_->whitelistSockets_.insert(curlfd); + if (this_->whitelistSocketsCallback_) { + this_->whitelistSocketsCallback_->call(this_->whitelistSockets_); + } + } + return CURL_SOCKOPT_OK; +} + +int CurlNetworkManager::curlCloseSocketCallback(void *clientp, curl_socket_t curlfd) +{ + CurlNetworkManager *this_ = (CurlNetworkManager *)clientp; +#ifdef _WIN32 + closesocket(curlfd); +#else + close(curlfd); +#endif + std::lock_guard locker(this_->mutex_); + // whitelist the deleted socket descriptor + if (this_->whitelistSockets_.find(curlfd) != this_->whitelistSockets_.end()) { + this_->whitelistSockets_.erase(curlfd); + if (this_->whitelistSocketsCallback_) { + this_->whitelistSocketsCallback_->call(this_->whitelistSockets_); + } + } + + return CURL_SOCKOPT_OK; +} + bool CurlNetworkManager::setupOptions(RequestInfo *requestInfo, const std::shared_ptr &request, const std::vector &ips) { if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_WRITEFUNCTION, writeDataCallback) != CURLE_OK) return false; @@ -198,9 +243,15 @@ bool CurlNetworkManager::setupOptions(RequestInfo *requestInfo, const std::share if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_ACCEPT_ENCODING, "") != CURLE_OK) return false; if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_URL, request->url().c_str()) != CURLE_OK) return false; + if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_SOCKOPTFUNCTION, curlSocketCallback) != CURLE_OK) return false; + if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_SOCKOPTDATA, this) != CURLE_OK) return false; + if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_CLOSESOCKETFUNCTION, curlCloseSocketCallback) != CURLE_OK) return false; + if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_CLOSESOCKETDATA, this) != CURLE_OK) return false; + spdlog::debug("New curl request : {}", request->url().c_str()); - if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_FRESH_CONNECT, 1) != CURLE_OK) return false; + // It is necessary? + //if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_FRESH_CONNECT, 1) != CURLE_OK) return false; if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_CONNECTTIMEOUT_MS , request->timeoutMs()) != CURLE_OK) return false; if (curl_easy_setopt(requestInfo->curlEasyHandle, CURLOPT_XFERINFOFUNCTION, progressCallback) != CURLE_OK) return false; diff --git a/libs/wsnet/src/httpnetworkmanager/curlnetworkmanager.h b/libs/wsnet/src/httpnetworkmanager/curlnetworkmanager.h index 6641ced38..93aa03470 100644 --- a/libs/wsnet/src/httpnetworkmanager/curlnetworkmanager.h +++ b/libs/wsnet/src/httpnetworkmanager/curlnetworkmanager.h @@ -9,6 +9,7 @@ #include "WSNetHttpRequest.h" #include "WSNetHttpNetworkManager.h" #include "certmanager.h" +#include "utils/cancelablecallback.h" namespace wsnet { @@ -30,6 +31,9 @@ class CurlNetworkManager void cancelRequest(std::uint64_t requestId); void setProxySettings(const std::string &address, const std::string &username, const std::string &password); + + void setWhitelistSocketsCallback(std::shared_ptr > callback); + private: void run(); @@ -78,9 +82,15 @@ class CurlNetworkManager CURLM *multiHandle_; std::map activeRequests_; + std::shared_ptr > whitelistSocketsCallback_; + std::set whitelistSockets_; + static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm); static size_t writeDataCallback(void *ptr, size_t size, size_t count, void *ri); static int progressCallback(void *ri, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); + static int curlSocketCallback(void *clientp, curl_socket_t curlfd, curlsocktype purpose); + static int curlCloseSocketCallback(void *clientp, curl_socket_t curlfd); + bool setupOptions(RequestInfo *requestInfo, const std::shared_ptr &request, const std::vector &ips); bool setupResolveHosts(RequestInfo *requestInfo, const std::shared_ptr &request, const std::vector &ips); diff --git a/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager.cpp b/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager.cpp index 94fc107f7..dae191e8f 100644 --- a/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager.cpp +++ b/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager.cpp @@ -4,8 +4,8 @@ namespace wsnet { -HttpNetworkManager::HttpNetworkManager(BS::thread_pool &taskQueue, WSNetDnsResolver *dnsResolver) : - taskQueue_(taskQueue), impl_(taskQueue, dnsResolver) +HttpNetworkManager::HttpNetworkManager(boost::asio::io_context &io_context, WSNetDnsResolver *dnsResolver) : + io_context_(io_context), impl_(io_context, dnsResolver) { } @@ -38,7 +38,7 @@ std::shared_ptr HttpNetworkManager::executeRequestEx(co WSNetHttpNetworkManagerProgressCallback progressCallback, WSNetHttpNetworkManagerReadyDataCallback readyReadCallback) { auto cc = std::make_shared(finishedCallback, progressCallback, readyReadCallback); - taskQueue_.detach_task([this, request, id, cc] { + boost::asio::post(io_context_, [this, request, id, cc] { impl_.executeRequest(request, id, cc); }); return cc; @@ -46,7 +46,7 @@ std::shared_ptr HttpNetworkManager::executeRequestEx(co void HttpNetworkManager::setProxySettings(const std::string &address, const std::string &username, const std::string &password) { - taskQueue_.detach_task([this, address, username, password] { + boost::asio::post(io_context_, [this, address, username, password] { impl_.setProxySettings(address, username, password); }); } @@ -55,18 +55,33 @@ std::shared_ptr HttpNetworkManager::setWhitelistIpsCall { if (whitelistIpsCallback) { auto cancelableCallback = std::make_shared>(whitelistIpsCallback); - taskQueue_.detach_task([this, cancelableCallback] { + boost::asio::post(io_context_, [this, cancelableCallback] { impl_.setWhitelistIpsCallback(cancelableCallback); }); - return cancelableCallback; } else { - taskQueue_.detach_task([this] { + boost::asio::post(io_context_, [this] { impl_.setWhitelistIpsCallback(nullptr); }); return nullptr; } } +std::shared_ptr HttpNetworkManager::setWhitelistSocketsCallback(WSNetHttpNetworkManagerWhitelistSocketsCallback whitelistSocketsCallback) +{ + if (whitelistSocketsCallback) { + auto cancelableCallback = std::make_shared>(whitelistSocketsCallback); + boost::asio::post(io_context_, [this, cancelableCallback] { + impl_.setWhitelistSocketsCallback(cancelableCallback); + }); + return cancelableCallback; + } else { + boost::asio::post(io_context_, [this] { + impl_.setWhitelistSocketsCallback(nullptr); + }); + return nullptr; + } +} + } // namespace wsnet diff --git a/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager.h b/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager.h index 22e54df57..d833e09d7 100644 --- a/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager.h +++ b/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager.h @@ -1,7 +1,7 @@ #pragma once #include "WSNetHttpNetworkManager.h" -#include +#include #include "httpnetworkmanager_impl.h" namespace wsnet { @@ -10,7 +10,7 @@ namespace wsnet { class HttpNetworkManager : public WSNetHttpNetworkManager { public: - HttpNetworkManager(BS::thread_pool &taskQueue, WSNetDnsResolver *dnsResolver); + HttpNetworkManager(boost::asio::io_context &io_context, WSNetDnsResolver *dnsResolver); bool init(); @@ -36,9 +36,10 @@ class HttpNetworkManager : public WSNetHttpNetworkManager const std::string &password = std::string()) override; std::shared_ptr setWhitelistIpsCallback(WSNetHttpNetworkManagerWhitelistIpsCallback whitelistIpsCallback) override; + std::shared_ptr setWhitelistSocketsCallback(WSNetHttpNetworkManagerWhitelistSocketsCallback whitelistSocketsCallback) override; private: - BS::thread_pool &taskQueue_; + boost::asio::io_context &io_context_; HttpNetworkManager_impl impl_; }; diff --git a/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager_impl.cpp b/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager_impl.cpp index 9b2961189..676953a7d 100644 --- a/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager_impl.cpp +++ b/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager_impl.cpp @@ -4,8 +4,8 @@ namespace wsnet { -HttpNetworkManager_impl::HttpNetworkManager_impl(BS::thread_pool &taskQueue, WSNetDnsResolver *dnsResolver) : - taskQueue_(taskQueue), +HttpNetworkManager_impl::HttpNetworkManager_impl(boost::asio::io_context &io_context, WSNetDnsResolver *dnsResolver) : + io_context_(io_context), dnsCache_(dnsResolver, std::bind(&HttpNetworkManager_impl::onDnsResolvedCallback, this, std::placeholders::_1)), curlNetworkManager_(std::bind(&HttpNetworkManager_impl::onCurlFinishedCallback, this, std::placeholders::_1, std::placeholders::_2), std::bind(&HttpNetworkManager_impl::onCurlProgressCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), @@ -61,9 +61,14 @@ void HttpNetworkManager_impl::setWhitelistIpsCallback(std::shared_ptr > callback) +{ + curlNetworkManager_.setWhitelistSocketsCallback(callback); +} + void HttpNetworkManager_impl::onDnsResolvedCallback(const DnsCacheResult &result) { - taskQueue_.detach_task([this, result] { + boost::asio::post(io_context_, [this, result] { onDnsResolvedImpl(result); }); } @@ -94,21 +99,21 @@ void HttpNetworkManager_impl::onDnsResolvedImpl(const DnsCacheResult &result) void HttpNetworkManager_impl::onCurlFinishedCallback(std::uint64_t requestId, bool bSuccess) { - taskQueue_.detach_task([this, requestId, bSuccess] { + boost::asio::post(io_context_, [this, requestId, bSuccess] { onCurlFinishedCallbackImpl(requestId, bSuccess); }); } void HttpNetworkManager_impl::onCurlProgressCallback(std::uint64_t requestId, std::uint64_t bytesReceived, std::uint64_t bytesTotal) { - taskQueue_.detach_task([this, requestId, bytesReceived, bytesTotal] { + boost::asio::post(io_context_, [this, requestId, bytesReceived, bytesTotal] { onCurlProgressCallbackImpl(requestId, bytesReceived, bytesTotal); }); } void HttpNetworkManager_impl::onCurlReadyDataCallback(std::uint64_t requestId, const std::string &data) { - taskQueue_.detach_task([this, requestId, data] { + boost::asio::post(io_context_, [this, requestId, data] { onCurlReadyDataCallbackImpl(requestId, data); }); } diff --git a/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager_impl.h b/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager_impl.h index 061167d4c..6c52e73d7 100644 --- a/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager_impl.h +++ b/libs/wsnet/src/httpnetworkmanager/httpnetworkmanager_impl.h @@ -2,7 +2,7 @@ #include "WSNetHttpNetworkManager.h" #include -#include +#include #include "WSNetDnsResolver.h" #include "curlnetworkmanager.h" #include "dnscache.h" @@ -15,7 +15,7 @@ using HttpNetworkManagerCallbacks = CancelableCallback3 > callback); + void setWhitelistSocketsCallback(std::shared_ptr > callback); private: - BS::thread_pool &taskQueue_; + boost::asio::io_context &io_context_; DnsCache dnsCache_; CurlNetworkManager curlNetworkManager_; std::shared_ptr > whitelistIpsCallback_; diff --git a/libs/wsnet/src/pingmanager/eventcallbackmanager_win.cpp b/libs/wsnet/src/pingmanager/eventcallbackmanager_win.cpp index c6d17b146..3b74895fe 100644 --- a/libs/wsnet/src/pingmanager/eventcallbackmanager_win.cpp +++ b/libs/wsnet/src/pingmanager/eventcallbackmanager_win.cpp @@ -42,7 +42,6 @@ void EventCallbackManager_win::remove(HANDLE hEvent) } } - void EventCallbackManager_win::run() { while (!finish_) { diff --git a/libs/wsnet/src/pingmanager/pingmanager.cpp b/libs/wsnet/src/pingmanager/pingmanager.cpp index 579579601..b22998278 100644 --- a/libs/wsnet/src/pingmanager/pingmanager.cpp +++ b/libs/wsnet/src/pingmanager/pingmanager.cpp @@ -10,13 +10,13 @@ namespace wsnet { -PingManager::PingManager(BS::thread_pool &taskQueue, WSNetHttpNetworkManager *httpNetworkManager) : - taskQueue_(taskQueue), +PingManager::PingManager(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager) : + io_context_(io_context), httpNetworkManager_(httpNetworkManager) { #ifndef _WIN32 - processManager_ = std::make_unique(); + processManager_ = std::make_unique(io_context); #endif } @@ -63,7 +63,7 @@ void PingManager::setIsConnectedToVpnState(bool isConnected) void PingManager::onPingMethodFinished(std::uint64_t id) { // Executing in thread pool to eliminate deadlocks - taskQueue_.detach_task([this, id] { + boost::asio::post(io_context_, [this, id] { std::lock_guard locker(mutex_); auto it = map_.find(id); assert(it != map_.end()); diff --git a/libs/wsnet/src/pingmanager/pingmanager.h b/libs/wsnet/src/pingmanager/pingmanager.h index 271cc44c5..6821efbf4 100644 --- a/libs/wsnet/src/pingmanager/pingmanager.h +++ b/libs/wsnet/src/pingmanager/pingmanager.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include "WSNetPingManager.h" #include "WSNetHttpNetworkManager.h" #include "ipingmethod.h" @@ -19,7 +19,7 @@ namespace wsnet { class PingManager : public WSNetPingManager { public: - explicit PingManager(BS::thread_pool &taskQueue, WSNetHttpNetworkManager *httpNetworkManager); + explicit PingManager(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager); virtual ~PingManager(); std::shared_ptr ping(const std::string &ip, const std::string &hostname, @@ -28,7 +28,7 @@ class PingManager : public WSNetPingManager void setIsConnectedToVpnState(bool isConnected); private: - BS::thread_pool &taskQueue_; + boost::asio::io_context &io_context_; WSNetHttpNetworkManager *httpNetworkManager_; #ifdef _WIN32 diff --git a/libs/wsnet/src/pingmanager/pingmethod_icmp_posix.cpp b/libs/wsnet/src/pingmanager/pingmethod_icmp_posix.cpp index 9b74b3951..3d5fbcf88 100644 --- a/libs/wsnet/src/pingmanager/pingmethod_icmp_posix.cpp +++ b/libs/wsnet/src/pingmanager/pingmethod_icmp_posix.cpp @@ -26,7 +26,7 @@ void PingMethodIcmp_posix::ping(bool isFromDisconnectedVpnState) using namespace std::placeholders; isFromDisconnectedVpnState_ = isFromDisconnectedVpnState; - if (processManager_->execute({"ping", "-c", "1", "-W", "2000", ip_}, std::bind(&PingMethodIcmp_posix::onProcessFinished, this, _1, _2))) { + if (!processManager_->execute("ping", {"-c", "1", "-W", "2000", ip_}, std::bind(&PingMethodIcmp_posix::onProcessFinished, this, _1, _2))) { spdlog::error("PingMethodIcmp_posix::ping cannot execute ping command"); callFinished(); return; diff --git a/libs/wsnet/src/pingmanager/processmanager.cpp b/libs/wsnet/src/pingmanager/processmanager.cpp index 738db0b2f..a52f4840e 100644 --- a/libs/wsnet/src/pingmanager/processmanager.cpp +++ b/libs/wsnet/src/pingmanager/processmanager.cpp @@ -1,85 +1,58 @@ #include "processmanager.h" #include -#include -#include namespace wsnet { -ProcessManager::ProcessManager() +ProcessManager::ProcessManager(boost::asio::io_context &io_context) : + io_context_(io_context) { - checkThread_ = std::thread(std::bind(&ProcessManager::checkTread, this)); } ProcessManager::~ProcessManager() { - finish_ = true; - condition_.notify_all(); - checkThread_.join(); - std::lock_guard locker(mutex_); for (auto &it : processes_) { - it->process->kill(); + it.second->process.terminate(); } } -bool ProcessManager::execute(const std::vector &args, ProcessManagerCallback callback) +bool ProcessManager::execute(const std::string &cmd, const std::vector &args, ProcessManagerCallback callback) { - auto processData = std::make_unique(); - using namespace std::placeholders; - processData->process = std::make_unique(); - std::error_code ec = processData->process->start(args); - if (ec) { - spdlog::error("Cannot start a process: {}, error: {}", fmt::join(args, " "), ec.value()); - return true; - } - processData->callback = callback; - std::lock_guard locker(mutex_); - processes_.push_back(std::move(processData)); - condition_.notify_all(); - return false; -} - -void ProcessManager::checkTread() -{ - while (!finish_) { - { - std::unique_lock locker(mutex_); - condition_.wait(locker, [this]{ return !processes_.empty() || finish_; }); - } - - if (finish_) - return; - - { - std::unique_lock locker(mutex_); - auto it = processes_.begin(); - while(it != processes_.end()) { - - std::error_code ec; - int status = 0; - std::tie(status, ec) = (*it)->process->wait(std::chrono::milliseconds(0)); - if (status != REPROC_ETIMEDOUT) { - - std::string output; - reproc::sink::string sink(output); - ec = reproc::drain(*(*it)->process, sink, reproc::sink::null); - if (!ec) - (*it)->callback(status, output); - else { - spdlog::error("Cannot drain a process, error: {}", ec.value()); - (*it)->callback(-1, output); - } - it = processes_.erase(it); - } else { - it++; + try { + auto childProcess = std::make_unique(); + childProcess->callback = callback; + childProcess->process = boost::process::child(boost::process::search_path(cmd), args, + boost::process::std_out > childProcess->data, + io_context_, + boost::process::on_exit = [this, id = curId_](int exit, std::error_code ec) { + // on exit function handler + std::string data; + ProcessManagerCallback callback; + // copy data and callback and remove an item from processes + { + std::lock_guard locker(mutex_); + auto it = processes_.find(id); + assert(it != processes_.end()); + std::ostringstream os; + os << it->second->data.rdbuf(); + data = os.str(); + callback = it->second->callback; + processes_.erase(it); } - } - } + // call callback + callback(exit, data); + }); + + processes_[curId_++] = std::move(childProcess); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } catch(...) { + spdlog::error("Cannot start a process: {}", cmd); + return false; } + + return true; } } // namespace wsnet diff --git a/libs/wsnet/src/pingmanager/processmanager.h b/libs/wsnet/src/pingmanager/processmanager.h index 5bd8680cf..cc97d67e8 100644 --- a/libs/wsnet/src/pingmanager/processmanager.h +++ b/libs/wsnet/src/pingmanager/processmanager.h @@ -1,45 +1,40 @@ #pragma once #include -#include +#include #include #include #include #include -#include -#include -#include +#include +#include namespace wsnet { typedef std::function ProcessManagerCallback; // Simple process manager. Allows you to start a process and set a callback function that is called after the process is finished. -// Based on reproc (Redirected Process) cross-platform C/C++ library -// In destructor kills all running processes // Thread safe class ProcessManager { public: - ProcessManager(); + ProcessManager(boost::asio::io_context &io_context); ~ProcessManager(); - bool execute(const std::vector &args, ProcessManagerCallback callback); + bool execute(const std::string &cmd, const std::vector &args, ProcessManagerCallback callback); private: - std::mutex mutex_; - std::thread checkThread_; - std::condition_variable condition_; - std::atomic_bool finish_ = false; + boost::asio::io_context &io_context_; - struct ProcessData + struct ChildProcess { - std::unique_ptr process; + boost::process::child process; + boost::process::ipstream data; ProcessManagerCallback callback; }; - std::vector> processes_; - - void checkTread(); + std::mutex mutex_; + uint64_t curId_ = 0; + std::unordered_map> processes_; }; } // namespace wsnet diff --git a/libs/wsnet/src/serverapi/baserequest.h b/libs/wsnet/src/serverapi/baserequest.h index fa30462d8..f15bf92f3 100644 --- a/libs/wsnet/src/serverapi/baserequest.h +++ b/libs/wsnet/src/serverapi/baserequest.h @@ -45,7 +45,6 @@ class BaseRequest bool isUseDnsCache() const { return isUseDnsCache_; } void setUseDnsCache(bool isUse) { isUseDnsCache_ = isUse; } - bool isWriteToLog() const { return isWriteToLog_; } void setNotWriteToLog() { isWriteToLog_ = false; } diff --git a/libs/wsnet/src/serverapi/requestsfactory.cpp b/libs/wsnet/src/serverapi/requestsfactory.cpp index bcebf3366..fcdcf1dfb 100644 --- a/libs/wsnet/src/serverapi/requestsfactory.cpp +++ b/libs/wsnet/src/serverapi/requestsfactory.cpp @@ -251,10 +251,12 @@ BaseRequest *requests_factory::wgConfigsConnect(const std::string &authHash, con return request; } -BaseRequest *requests_factory::mobileBillingPlans(const std::string &mobilePlanType, int version, RequestFinishedCallback callback) +BaseRequest *requests_factory::mobileBillingPlans(const std::string &authHash, const std::string &mobilePlanType, const std::string &promo, int version, RequestFinishedCallback callback) { std::map extraParams; + extraParams["session_auth_hash"] = authHash; extraParams["mobile_plan_type"] = mobilePlanType; + extraParams["promo"] = promo; extraParams["version"] = std::to_string(version); auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "MobileBillingPlans", extraParams, callback); return request; @@ -352,4 +354,36 @@ BaseRequest *requests_factory::claimAccount(const std::string &authHash, const s return request; } +BaseRequest *requests_factory::sendPayment(const std::string &authHash, const std::string &appleID, const std::string &appleData, const std::string &appleSIG, RequestFinishedCallback callback) +{ + std::map extraParams; + extraParams["session_auth_hash"] = authHash; + extraParams["apple_id"] = appleID; + extraParams["apple_data"] = appleData; + extraParams["apple_sig"] = appleSIG; + auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "AppleIPN", extraParams, callback); + request->setContentTypeHeader("Content-type: text/html; charset=utf-8"); + return request; +} + +BaseRequest *requests_factory::recordShakeForDataScore(const std::string &authHash, const std::string &platform, const std::string &score, const std::string &signature, RequestFinishedCallback callback) +{ + std::map extraParams; + extraParams["session_auth_hash"] = authHash; + extraParams["platform"] = platform; + extraParams["score"] = score; + extraParams["sig"] = signature; + auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "ShakeData", extraParams, callback); + request->setContentTypeHeader("Content-type: text/html; charset=utf-8"); + return request; +} + +BaseRequest *requests_factory::shakeData(const std::string &authHash, RequestFinishedCallback callback) +{ + std::map extraParams; + extraParams["session_auth_hash"] = authHash; + auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "ShakeData", extraParams, callback); + return request; +} + } // namespace wsnet diff --git a/libs/wsnet/src/serverapi/requestsfactory.h b/libs/wsnet/src/serverapi/requestsfactory.h index 270af863c..a436f3b2a 100644 --- a/libs/wsnet/src/serverapi/requestsfactory.h +++ b/libs/wsnet/src/serverapi/requestsfactory.h @@ -51,8 +51,9 @@ namespace requests_factory BaseRequest *myIP(RequestFinishedCallback callback); - BaseRequest *mobileBillingPlans(const std::string &mobilePlanType, int version, RequestFinishedCallback callback); + BaseRequest *mobileBillingPlans(const std::string &authHash, const std::string &mobilePlanType, const std::string &promo, int version, RequestFinishedCallback callback); + BaseRequest *sendPayment(const std::string &authHash, const std::string &appleID, const std::string &appleData, const std::string &appleSIG, RequestFinishedCallback callback); BaseRequest *verifyPayment(const std::string &authHash, const std::string &purchaseToken, const std::string &gpPackageName, const std::string &gpProductId, const std::string &type, const std::string &amazonUserId, @@ -75,6 +76,10 @@ namespace requests_factory BaseRequest *claimAccount(const std::string &authHash, const std::string &username, const std::string &password, const std::string &email, const std::string &claimAccount, RequestFinishedCallback callback); + BaseRequest *shakeData(const std::string &authHash, RequestFinishedCallback callback); + BaseRequest *recordShakeForDataScore(const std::string &authHash, const std::string &platform, + const std::string &score, const std::string &signature, + RequestFinishedCallback callback); } } // namespace wsnet diff --git a/libs/wsnet/src/serverapi/serverapi.cpp b/libs/wsnet/src/serverapi/serverapi.cpp index dfa91715c..a12c5657f 100644 --- a/libs/wsnet/src/serverapi/serverapi.cpp +++ b/libs/wsnet/src/serverapi/serverapi.cpp @@ -5,9 +5,9 @@ namespace wsnet { -ServerAPI::ServerAPI(BS::thread_pool &taskQueue, WSNetHttpNetworkManager *httpNetworkManager, IFailoverContainer *failoverContainer, +ServerAPI::ServerAPI(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager, IFailoverContainer *failoverContainer, const std::string &settings, WSNetAdvancedParameters *advancedParameters, ConnectState &connectState) : - taskQueue_(taskQueue), + io_context_(io_context), settings_(settings), advancedParameters_(advancedParameters), connectState_(connectState) @@ -28,14 +28,14 @@ std::string ServerAPI::currentSettings() void ServerAPI::setApiResolutionsSettings(bool isAutomatic, std::string manualAddress) { - taskQueue_.detach_task([this, isAutomatic, manualAddress] { + boost::asio::post(io_context_, [this, isAutomatic, manualAddress] { impl_->setApiResolutionsSettings(isAutomatic, manualAddress); }); } void ServerAPI::setIgnoreSslErrors(bool bIgnore) { - taskQueue_.detach_task([this, bIgnore] { + boost::asio::post(io_context_, [this, bIgnore] { impl_->setIgnoreSslErrors(bIgnore); }); } @@ -43,7 +43,7 @@ void ServerAPI::setIgnoreSslErrors(bool bIgnore) std::shared_ptr ServerAPI::setTryingBackupEndpointCallback(WSNetTryingBackupEndpointCallback tryingBackupEndpointCallback) { auto cancelableCallback = std::make_shared>(tryingBackupEndpointCallback); - taskQueue_.detach_task([this, cancelableCallback] { + boost::asio::post(io_context_, [this, cancelableCallback] { impl_->setTryingBackupEndpointCallback(cancelableCallback); }); return cancelableCallback; @@ -52,13 +52,13 @@ std::shared_ptr ServerAPI::setTryingBackupEndpointCallb std::shared_ptr ServerAPI::login(const std::string &username, const std::string &password, const std::string &code2fa, WSNetRequestFinishedCallback callback) { // For login only request, we reset a failover to the initial state - taskQueue_.detach_task([this] { + boost::asio::post(io_context_, [this] { impl_->resetFailover(); }); auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::login(username, password, code2fa, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -66,7 +66,7 @@ std::shared_ptr ServerAPI::session(const std::string &a { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::session(authHash, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -74,7 +74,7 @@ std::shared_ptr ServerAPI::deleteSession(const std::str { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::deleteSession(authHash, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -83,7 +83,7 @@ std::shared_ptr ServerAPI::serverLocations(const std::s auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::serverLocations(settings_, language, revision, isPro, alcList, connectState_, advancedParameters_, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -91,7 +91,7 @@ std::shared_ptr ServerAPI::serverCredentials(const std: { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::serverCredentials(authHash, isOpenVpnProtocol, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -99,7 +99,7 @@ std::shared_ptr ServerAPI::serverConfigs(const std::str { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::serverConfigs(authHash, ovpnVersion, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -107,7 +107,7 @@ std::shared_ptr ServerAPI::portMap(const std::string &a { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::portMap(authHash, version, forceProtocols, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -115,7 +115,7 @@ std::shared_ptr ServerAPI::recordInstall(const std::str { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::recordInstall(platform, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -123,7 +123,7 @@ std::shared_ptr ServerAPI::addEmail(const std::string & { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::addEmail(authHash, email, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -131,7 +131,7 @@ std::shared_ptr ServerAPI::confirmEmail(const std::stri { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::confirmEmail(authHash, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -139,7 +139,7 @@ std::shared_ptr ServerAPI::signup(const std::string &us { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::signup(username, password, referringUsername, email, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -147,7 +147,7 @@ std::shared_ptr ServerAPI::webSession(const std::string { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::webSession(authHash, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -156,7 +156,7 @@ std::shared_ptr ServerAPI::checkUpdate(UpdateChannel up { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::checkUpdate(updateChannel, appVersion, appBuild, osVersion, osBuild, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -164,7 +164,7 @@ std::shared_ptr ServerAPI::debugLog(const std::string & { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::debugLog(username, strLog, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -172,7 +172,7 @@ std::shared_ptr ServerAPI::speedRating(const std::strin { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::speedRating(authHash, hostname, ip, rating, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -180,7 +180,7 @@ std::shared_ptr ServerAPI::staticIps(const std::string { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::staticIps(authHash, platform, deviceId, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -188,7 +188,7 @@ std::shared_ptr ServerAPI::pingTest(std::uint32_t timeo { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::pingTest(timeoutMs, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -196,7 +196,7 @@ std::shared_ptr ServerAPI::notifications(const std::str { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::notifications(authHash, pcpid, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -204,7 +204,7 @@ std::shared_ptr ServerAPI::getRobertFilters(const std:: { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::getRobertFilters(authHash, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -212,7 +212,7 @@ std::shared_ptr ServerAPI::setRobertFilter(const std::s { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::setRobertFilter(authHash, id, status, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -220,7 +220,7 @@ std::shared_ptr ServerAPI::syncRobert(const std::string { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::syncRobert(authHash, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -228,7 +228,7 @@ std::shared_ptr ServerAPI::wgConfigsInit(const std::str { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::wgConfigsInit(authHash, clientPublicKey, deleteOldestKey, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -236,7 +236,7 @@ std::shared_ptr ServerAPI::wgConfigsConnect(const std:: { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::wgConfigsConnect(authHash, clientPublicKey, hostname, deviceId, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -244,15 +244,23 @@ std::shared_ptr ServerAPI::myIP(WSNetRequestFinishedCal { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::myIP(cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } -std::shared_ptr ServerAPI::mobileBillingPlans(const std::string &mobilePlanType, int version, WSNetRequestFinishedCallback callback) +std::shared_ptr ServerAPI::mobileBillingPlans(const std::string &authHash, const std::string &mobilePlanType, const std::string &promo, int version, WSNetRequestFinishedCallback callback) { auto cancelableCallback = std::make_shared>(callback); - BaseRequest *request = requests_factory::mobileBillingPlans(mobilePlanType, version, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + BaseRequest *request = requests_factory::mobileBillingPlans(authHash, mobilePlanType, promo, version, cancelableCallback); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + return cancelableCallback; +} + +std::shared_ptr ServerAPI::sendPayment(const std::string &authHash, const std::string &appleID, const std::string &appleData, const std::string &appleSIG, WSNetRequestFinishedCallback callback) +{ + auto cancelableCallback = std::make_shared>(callback); + BaseRequest *request = requests_factory::sendPayment(authHash, appleID, appleData, appleSIG, cancelableCallback); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -260,7 +268,7 @@ std::shared_ptr ServerAPI::verifyPayment(const std::str { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::verifyPayment(authHash, purchaseToken, gpPackageName, gpProductId, type, amazonUserId, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -268,7 +276,7 @@ std::shared_ptr ServerAPI::postBillingCpid(const std::s { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::postBillingCpid(authHash, payCpid, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -276,7 +284,7 @@ std::shared_ptr ServerAPI::getXpressLoginCode(WSNetRequ { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::getXpressLoginCode(cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -284,7 +292,7 @@ std::shared_ptr ServerAPI::verifyXpressLoginCode(const { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::verifyXpressLoginCode(xpressCode, sig, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -295,7 +303,7 @@ std::shared_ptr ServerAPI::sendSupportTicket(const std: { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::sendSupportTicket(supportEmail, supportName, supportSubject, supportMessage, supportCategory, type, channel, platform, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -303,7 +311,7 @@ std::shared_ptr ServerAPI::regToken(WSNetRequestFinishe { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::regToken(cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -311,7 +319,7 @@ std::shared_ptr ServerAPI::signupUsingToken(const std:: { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::signupUsingToken(token, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } @@ -319,13 +327,29 @@ std::shared_ptr ServerAPI::claimAccount(const std::stri { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::claimAccount(authHash, username, password, email, claimAccount, cancelableCallback); - taskQueue_.detach_task([this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + return cancelableCallback; +} + +std::shared_ptr ServerAPI::shakeData(const std::string &authHash, WSNetRequestFinishedCallback callback) +{ + auto cancelableCallback = std::make_shared>(callback); + BaseRequest *request = requests_factory::shakeData(authHash, cancelableCallback); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); + return cancelableCallback; +} + +std::shared_ptr ServerAPI::recordShakeForDataScore(const std::string &authHash, const std::string &platform, const std::string &score, const std::string &signature, WSNetRequestFinishedCallback callback) +{ + auto cancelableCallback = std::make_shared>(callback); + BaseRequest *request = requests_factory::recordShakeForDataScore(authHash, platform, score, signature, cancelableCallback); + boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr(request)); }); return cancelableCallback; } void ServerAPI::onVPNConnectStateChanged(bool isConnected) { - taskQueue_.detach_task([this, isConnected] { + boost::asio::post(io_context_, [this, isConnected] { impl_->setIsConnectedToVpnState(isConnected); }); } diff --git a/libs/wsnet/src/serverapi/serverapi.h b/libs/wsnet/src/serverapi/serverapi.h index 9a3e3724e..b3d936790 100644 --- a/libs/wsnet/src/serverapi/serverapi.h +++ b/libs/wsnet/src/serverapi/serverapi.h @@ -1,7 +1,7 @@ #pragma once #include "WSNetServerAPI.h" -#include +#include #include "WSNetHttpNetworkManager.h" #include "WSNetAdvancedParameters.h" #include "failover/ifailovercontainer.h" @@ -15,7 +15,7 @@ class ServerAPI_impl; class ServerAPI : public WSNetServerAPI { public: - explicit ServerAPI(BS::thread_pool &taskQueue, WSNetHttpNetworkManager *httpNetworkManager, IFailoverContainer *failoverContainer, + explicit ServerAPI(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager, IFailoverContainer *failoverContainer, const std::string &settings, WSNetAdvancedParameters *advancedParameters, ConnectState &connectState); virtual ~ServerAPI(); @@ -71,8 +71,10 @@ class ServerAPI : public WSNetServerAPI std::shared_ptr myIP(WSNetRequestFinishedCallback callback) override; - std::shared_ptr mobileBillingPlans(const std::string &mobilePlanType, int version, WSNetRequestFinishedCallback callback) override; + std::shared_ptr mobileBillingPlans(const std::string &authHash, const std::string &mobilePlanType, const std::string &promo, int version, WSNetRequestFinishedCallback callback) override; + std::shared_ptr sendPayment(const std::string &authHash, const std::string &appleID, const std::string &appleData, const std::string &appleSIG, + WSNetRequestFinishedCallback callback) override; std::shared_ptr verifyPayment(const std::string &authHash, const std::string &purchaseToken, const std::string &gpPackageName, const std::string &gpProductId, const std::string &type, const std::string &amazonUserId, WSNetRequestFinishedCallback callback) override; @@ -94,9 +96,14 @@ class ServerAPI : public WSNetServerAPI const std::string &email, const std::string &claimAccount, WSNetRequestFinishedCallback callback) override; + std::shared_ptr shakeData(const std::string &authHash, WSNetRequestFinishedCallback callback) override; + std::shared_ptr recordShakeForDataScore(const std::string &authHash, const std::string &platform, + const std::string &score, const std::string &signature, + WSNetRequestFinishedCallback callback) override; + private: std::unique_ptr impl_; - BS::thread_pool &taskQueue_; + boost::asio::io_context &io_context_; ServerAPISettings settings_; WSNetAdvancedParameters *advancedParameters_; ConnectState &connectState_; diff --git a/libs/wsnet/src/serverapi/wsnet_utils_impl.cpp b/libs/wsnet/src/serverapi/wsnet_utils_impl.cpp index 75fc1a3b2..ea83f8ab4 100644 --- a/libs/wsnet/src/serverapi/wsnet_utils_impl.cpp +++ b/libs/wsnet/src/serverapi/wsnet_utils_impl.cpp @@ -3,9 +3,9 @@ namespace wsnet { -WSNetUtils_impl::WSNetUtils_impl(BS::thread_pool &taskQueue, WSNetHttpNetworkManager *httpNetworkManager, +WSNetUtils_impl::WSNetUtils_impl(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager, IFailoverContainer *failoverContainer, WSNetAdvancedParameters *advancedParameters) : - taskQueue_(taskQueue), + io_context_(io_context), httpNetworkManager_(httpNetworkManager), advancedParameters_(advancedParameters), failoverContainer_(failoverContainer) @@ -31,7 +31,7 @@ std::shared_ptr WSNetUtils_impl::myIPViaFailover(int fa { auto cancelableCallback = std::make_shared>(callback); BaseRequest *request = requests_factory::myIP(cancelableCallback); - taskQueue_.detach_task([this, failoverInd, request] { myIPViaFailover_impl(failoverInd, std::unique_ptr(request)); }); + boost::asio::post(io_context_, [this, failoverInd, request] { myIPViaFailover_impl(failoverInd, std::unique_ptr(request)); }); return cancelableCallback; } diff --git a/libs/wsnet/src/serverapi/wsnet_utils_impl.h b/libs/wsnet/src/serverapi/wsnet_utils_impl.h index 97a98f042..5f9a77bba 100644 --- a/libs/wsnet/src/serverapi/wsnet_utils_impl.h +++ b/libs/wsnet/src/serverapi/wsnet_utils_impl.h @@ -1,7 +1,7 @@ #pragma once #include "WSNetUtils.h" -#include +#include #include "WSNetHttpNetworkManager.h" #include "failover/ifailovercontainer.h" #include "serverapi/failedfailovers.h" @@ -12,7 +12,7 @@ namespace wsnet { class WSNetUtils_impl : public WSNetUtils { public: - explicit WSNetUtils_impl(BS::thread_pool &taskQueue, WSNetHttpNetworkManager *httpNetworkManager, + explicit WSNetUtils_impl(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager, IFailoverContainer *failoverContainer, WSNetAdvancedParameters *advancedParameters); virtual ~WSNetUtils_impl(); @@ -22,7 +22,7 @@ class WSNetUtils_impl : public WSNetUtils std::shared_ptr myIPViaFailover(int failoverInd, WSNetRequestFinishedCallback callback) override; private: - BS::thread_pool &taskQueue_; + boost::asio::io_context &io_context_; WSNetHttpNetworkManager *httpNetworkManager_; WSNetAdvancedParameters *advancedParameters_; IFailoverContainer *failoverContainer_; diff --git a/libs/wsnet/src/wsnet.cpp b/libs/wsnet/src/wsnet.cpp index 2cd193873..dd06a9668 100644 --- a/libs/wsnet/src/wsnet.cpp +++ b/libs/wsnet/src/wsnet.cpp @@ -2,7 +2,7 @@ #include "WSNet.h" #include -#include +#include #include "utils/wsnet_callback_sink.h" #include "dnsresolver/dnsresolver_cares.h" #include "httpnetworkmanager/httpnetworkmanager.h" @@ -25,15 +25,15 @@ namespace wsnet { class WSNet_impl : public WSNet { public: - WSNet_impl() : taskQueue_(1) + WSNet_impl() : work_(boost::asio::make_work_guard(io_context_)) { + thread_ = std::thread([this](){ io_context_.run(); }); } virtual ~WSNet_impl() { - // suspend all tasks in the pool before exiting - // to prevent callback functions from being called when parent objects have already been deleted - taskQueue_.pause(); + work_.reset(); // Allow all handlers to be allowed to finish normally + thread_.join(); } bool initializeImpl(const std::string &platformName,const std::string &appVersion, bool isUseStagingDomains, const std::string &serverApiSettings) @@ -46,7 +46,7 @@ class WSNet_impl : public WSNet return false; } - httpNetworkManager_ = std::make_shared(taskQueue_, dnsResolver_.get()); + httpNetworkManager_ = std::make_shared(io_context_, dnsResolver_.get()); if (!httpNetworkManager_->init()) { spdlog::critical("Failed to initialize HttpNetworkManager"); return false; @@ -61,10 +61,10 @@ class WSNet_impl : public WSNet failoverContainer_ = std::make_unique(httpNetworkManager_.get()); advancedParameters_ = std::make_shared(); - serverAPI_ = std::make_shared(taskQueue_, httpNetworkManager_.get(), failoverContainer_.get(), serverApiSettings, advancedParameters_.get(), connectState_); - emergencyConnect_ = std::make_shared(taskQueue_, failoverContainer_.get(), dnsResolver_.get()); - pingManager_ = std::make_shared(taskQueue_, httpNetworkManager_.get()); - utils_ = std::make_shared(taskQueue_, httpNetworkManager_.get(), failoverContainer_.get(), advancedParameters_.get()); + serverAPI_ = std::make_shared(io_context_, httpNetworkManager_.get(), failoverContainer_.get(), serverApiSettings, advancedParameters_.get(), connectState_); + emergencyConnect_ = std::make_shared(io_context_, failoverContainer_.get(), dnsResolver_.get()); + pingManager_ = std::make_shared(io_context_, httpNetworkManager_.get()); + utils_ = std::make_shared(io_context_, httpNetworkManager_.get(), failoverContainer_.get(), advancedParameters_.get()); return true; } @@ -87,7 +87,10 @@ class WSNet_impl : public WSNet std::shared_ptr utils() override { return utils_; } private: - BS::thread_pool taskQueue_; + std::thread thread_; + boost::asio::io_context io_context_; + boost::asio::executor_work_guard work_; + ConnectState connectState_; std::shared_ptr dnsResolver_; std::shared_ptr httpNetworkManager_; diff --git a/libs/wsnet/vcpkg.json b/libs/wsnet/vcpkg.json index 47b6a0edf..a6612dd38 100644 --- a/libs/wsnet/vcpkg.json +++ b/libs/wsnet/vcpkg.json @@ -1,18 +1,20 @@ { "dependencies": [ "gtest", + "scapix", "spdlog", { "name": "curl", "features": [ "openssl" ] }, "rapidjson", + "boost-config", + "boost-metaparse", + "boost-process", "skyr-url", "cmakerc", - "bshoshany-thread-pool", "cpp-base64", - "reproc", - "c-ares", - "advobfuscator" + "c-ares", + "advobfuscator" ] } diff --git a/tools/build_all.py b/tools/build_all.py index f21855c73..49c4d19dc 100644 --- a/tools/build_all.py +++ b/tools/build_all.py @@ -345,13 +345,16 @@ def deploy_component(configdata, component_name, buildenv=None, target_name_over iutl.RunCommand(install_cmd, env=buildenv, shell=(CURRENT_OS == "win32")) if BUILD_SYMBOL_FILES and "symbols" in component: - srcfile = os.path.join(temp_wd, target_location, component["symbols"]) - if os.path.exists(srcfile): - dstfile = BUILD_SYMBOL_FILES - if "outdir" in component: - dstfile = os.path.join(dstfile, component["outdir"]) - dstfile = os.path.join(dstfile, component["symbols"]) - utl.CopyFile(srcfile, dstfile) + c_symbols = component.get("symbols", None) + symbols = [c_symbols] if (type(c_symbols) is not list) else c_symbols + for s in symbols: + srcfile = os.path.join(temp_wd, target_location, s) + if os.path.exists(srcfile): + dstfile = BUILD_SYMBOL_FILES + if "outdir" in component: + dstfile = os.path.join(dstfile, component["outdir"]) + dstfile = os.path.join(dstfile, os.path.basename(s)) + utl.CopyFile(srcfile, dstfile) def build_components(configdata, targetlist, qt_root): diff --git a/tools/build_all.yml b/tools/build_all.yml index 971179d5d..3bfe7c0ea 100644 --- a/tools/build_all.yml +++ b/tools/build_all.yml @@ -7,7 +7,7 @@ client: name: Client subdir: client target: Windscribe.exe - symbols: Windscribe.pdb + symbols: [Windscribe.pdb, wsnet/wsnet.pdb] macos: name: Client subdir: client diff --git a/tools/vcpkg/vcpkg.json b/tools/vcpkg/vcpkg.json index 673099851..07918e55d 100644 --- a/tools/vcpkg/vcpkg.json +++ b/tools/vcpkg/vcpkg.json @@ -5,6 +5,7 @@ "boost-logic", "boost-serialization", "boost-thread", + "boost-process", "bshoshany-thread-pool", "openssl", "openvpn", @@ -21,6 +22,10 @@ "reproc", "c-ares", "advobfuscator", - "7zip" + "7zip", + { + "name": "winreg", + "platform": "windows" + } ] }