diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 453ba224..47071502 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -51,6 +51,7 @@ variables: - ./tools/vcpkg/install_ci/vcpkg_install.sh "${VCPKG_ROOT}" --configure-git - python3 -m pip install -r tools/requirements.txt - python3 -m pip install dmgbuild + - python3 -m pip install gcovr interruptible: true .template_aarch64_ubuntu_build: &template_aarch64_ubuntu_build @@ -102,6 +103,7 @@ variables: # Qt 6 dependencies - dnf install -y fontconfig-devel freetype-devel libX11-devel libxcb-devel xcb-util-devel xcb-util-image-devel xcb-util-cursor-devel xcb-util-keysyms-devel xcb-util-renderutil-devel libxkbcommon-x11-devel wayland-devel - python3 -m pip install --user -r tools/requirements.txt + - python3 -m pip install --user gcovr # install cmake 3.28.x (default for Fedora 29 is 3.14.5) - wget -q -N https://cmake.org/files/v3.28/cmake-3.28.3-linux-x86_64.sh -P ${RHEL_CMAKE_BUILD_PATH} - chmod u+x ${RHEL_CMAKE_BUILD_PATH}/cmake-3.28.3-linux-x86_64.sh @@ -184,7 +186,7 @@ build:win:x64:app: - temp/ expire_in: 1 day rules: - - if: $BUILD_WIN == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) + - if: $BUILD_WIN == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) && $NIGHTLY_TEST_BUILD != "y" build:win:x64:mr: <<: *template_win10_build @@ -199,7 +201,7 @@ build:win:x64:mr: - 'IF(Test-Path .\$BUILD_LIBS_FOLDER\) {Get-ChildItem .\$BUILD_LIBS_FOLDER\*.zip | Foreach {.\tools\bin\7z.exe x $_.FullName -o"$BUILD_LIBS_FOLDER\"}}' - tools/build_all --ci-mode rules: - - if: $BUILD_WIN == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null + - if: $BUILD_WIN == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null && $NIGHTLY_TEST_BUILD != "y" sign:win:app: <<: *template_win10_sign @@ -222,7 +224,7 @@ sign:win:app: optional: true artifacts: true rules: - - if: ($BUILD_WIN == "y" || $BUILD_WIN_ARM64 == "y") && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) + - if: ($BUILD_WIN == "y" || $BUILD_WIN_ARM64 == "y") && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) && $NIGHTLY_TEST_BUILD != "y" build:win:x64:installer: <<: *template_win10_build @@ -246,7 +248,7 @@ build:win:x64:installer: optional: true artifacts: true rules: - - if: $BUILD_WIN == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) + - if: $BUILD_WIN == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) && $NIGHTLY_TEST_BUILD != "y" sign:win:installer: <<: *template_win10_sign @@ -269,7 +271,7 @@ sign:win:installer: optional: true artifacts: true rules: - - if: ($BUILD_WIN == "y" || $BUILD_WIN_ARM64 == "y") && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) + - if: ($BUILD_WIN == "y" || $BUILD_WIN_ARM64 == "y") && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) && $NIGHTLY_TEST_BUILD != "y" build:win:x64:bootstrap: <<: *template_win10_build @@ -293,7 +295,7 @@ build:win:x64:bootstrap: optional: true artifacts: true rules: - - if: $BUILD_WIN == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) + - if: $BUILD_WIN == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) && $NIGHTLY_TEST_BUILD != "y" sign:win:bootstrap: <<: *template_win10_sign @@ -326,7 +328,7 @@ sign:win:bootstrap: optional: true artifacts: true rules: - - if: ($BUILD_WIN == "y" || $BUILD_WIN_ARM64 == "y") && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null + - if: ($BUILD_WIN == "y" || $BUILD_WIN_ARM64 == "y") && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null && $NIGHTLY_TEST_BUILD != "y" sign:win:bootstrap:tagged: <<: *template_win10_sign @@ -386,7 +388,7 @@ build:win:arm64:app: - temp/ expire_in: 1 day rules: - - if: $BUILD_WIN_ARM64 == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) + - if: $BUILD_WIN_ARM64 == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) && $NIGHTLY_TEST_BUILD != "y" build:win:arm64:mr: <<: *template_win10_build @@ -407,7 +409,7 @@ build:win:arm64:mr: - 'IF(Test-Path .\$BUILD_LIBS_FOLDER\) {Get-ChildItem .\$BUILD_LIBS_FOLDER\*.zip | Foreach {.\tools\bin\7z.exe x $_.FullName -o"$BUILD_LIBS_FOLDER\"}}' - tools/build_all --arm64 --ci-mode rules: - - if: $BUILD_WIN_ARM64 == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null + - if: $BUILD_WIN_ARM64 == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null && $NIGHTLY_TEST_BUILD != "y" build:win:arm64:installer: <<: *template_win10_build @@ -436,7 +438,7 @@ build:win:arm64:installer: optional: true artifacts: true rules: - - if: $BUILD_WIN_ARM64 == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) + - if: $BUILD_WIN_ARM64 == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) && $NIGHTLY_TEST_BUILD != "y" build:win:arm64:bootstrap: <<: *template_win10_build @@ -461,7 +463,8 @@ build:win:arm64:bootstrap: optional: true artifacts: true rules: - - if: $BUILD_WIN_ARM64 == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) + - if: $BUILD_WIN_ARM64 == "y" && ($CI_COMMIT_TAG != null || $CI_COMMIT_BRANCH != null) && $NIGHTLY_TEST_BUILD != "y" + .build_mac_installer_common: script: @@ -492,7 +495,7 @@ build:mac:installer: - curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem --upload-file build-exe/Windscribe_$VERSION.dmg "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/Windscribe_$VERSION.dmg" rules: - - if: $BUILD_MAC == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null + - if: $BUILD_MAC == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null && $NIGHTLY_TEST_BUILD != "y" # We don't upload artifacts for merge requests build:mac:installer:mr: @@ -504,7 +507,7 @@ build:mac:installer:mr: - !reference [.build_mac_installer_common, script] - tools/build_all --ci-mode --sign rules: - - if: $BUILD_MAC == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null + - if: $BUILD_MAC == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null && $NIGHTLY_TEST_BUILD != "y" build:mac:installer:tagged: <<: *template_mac_build @@ -546,7 +549,7 @@ build:aarch64_ubuntu:installer: --upload-file build-exe/windscribe_${VERSION}_arm64.deb "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/windscribe_${VERSION}_arm64.deb" timeout: 4 hours rules: - - if: $BUILD_LINUX_ARM64 == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null + - if: $BUILD_LINUX_ARM64 == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null && $NIGHTLY_TEST_BUILD != "y" when: manual allow_failure: true @@ -562,7 +565,7 @@ build:aarch64_ubuntu:installer:mr: - tools/build_all --ci-mode --sign timeout: 4 hours rules: - - if: $BUILD_LINUX_ARM64 == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null + - if: $BUILD_LINUX_ARM64 == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null && $NIGHTLY_TEST_BUILD != "y" when: manual allow_failure: true @@ -581,7 +584,7 @@ build:aarch64_ubuntu:installer:tagged: --upload-file build-exe/windscribe_${VERSION}_arm64.deb "${NEXUS_PATH_TAGGED_UPLOAD}/${TAG}/windscribe_${VERSION}_arm64.deb" timeout: 4 hours rules: - - if: $BUILD_LINUX_ARM64 == "y" && $CI_COMMIT_TAG != null + - if: $BUILD_LINUX_ARM64 == "y" && $CI_COMMIT_TAG != null && $NIGHTLY_TEST_BUILD != "y" when: manual allow_failure: true @@ -600,7 +603,7 @@ build:rhel:installer: --upload-file build-exe/windscribe_${VERSION}_amd64.deb "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/windscribe_${VERSION}_amd64.deb" rules: - - if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null + - if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null && $NIGHTLY_TEST_BUILD != "y" # We don't upload artifacts for merge requests build:rhel:installer:mr: @@ -613,7 +616,7 @@ build:rhel:installer:mr: - !reference [.build_linux_installer_common, script] - tools/build_all --ci-mode --sign --build-deb --build-rpm rules: - - if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null + - if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null && $NIGHTLY_TEST_BUILD != "y" build:rhel:installer:tagged: <<: *template_rhel_build @@ -632,7 +635,7 @@ build:rhel:installer:tagged: --upload-file build-exe/windscribe_${VERSION}_amd64.deb "${NEXUS_PATH_TAGGED_UPLOAD}/${TAG}/windscribe_${VERSION}_amd64.deb" rules: - - if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG != null + - if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG != null && $NIGHTLY_TEST_BUILD != "y" .template_archlinux_build: &template_archlinux_build image: archlinux:base-devel @@ -676,7 +679,7 @@ build:archlinux:installer: - job: "build:rhel:installer" optional: true rules: - - if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null + - if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null && $NIGHTLY_TEST_BUILD != "y" build:archlinux:installer:tagged: <<: *template_archlinux_build @@ -695,7 +698,7 @@ build:archlinux:installer:tagged: - job: "build:rhel:installer:tagged" optional: true rules: - - if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG != null + - if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG != null && $NIGHTLY_TEST_BUILD != "y" build:artifact:links: tags: [win10qty6] @@ -710,7 +713,7 @@ build:artifact:links: - echo ${NEXUS_PATH_BRANCH_UPLOAD}/linux/windscribe_${VERSION}_x86_64.pkg.tar.zst dependencies: [] rules: - - if: $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null + - if: $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null && $NIGHTLY_TEST_BUILD != "y" build:artifact:links:tagged: tags: [win10qty6] @@ -726,7 +729,7 @@ build:artifact:links:tagged: - echo ${NEXUS_PATH_TAGGED_UPLOAD}/${TAG}/windscribe_${VERSION}_x86_64.pkg.tar.zst dependencies: [] rules: - - if: $CI_COMMIT_TAG != null + - if: $CI_COMMIT_TAG != null && $NIGHTLY_TEST_BUILD != "y" lint:flake8: <<: *template_win10_build @@ -753,3 +756,66 @@ test:translations: dependencies: [] rules: - if: $BUILD_WIN == "y" + +test:wsnet:win: + <<: *template_win10_build + stage: Test + variables: + GIT_STRATEGY: clone + VCPKG_ROOT: '%VCPKG_ROOT_WINDOWS%' + VCPKG_DEFAULT_BINARY_CACHE: '%VCPKG_DEFAULT_BINARY_CACHE_WINDOWS%' + script: + - Set-Variable -name OS_IDENTIFIER -value "windows" + - !reference [.download_dependencies_win, script] + - 'IF(Test-Path .\$BUILD_LIBS_FOLDER\) {Get-ChildItem .\$BUILD_LIBS_FOLDER\*.zip | Foreach {.\tools\bin\7z.exe x $_.FullName -o"$BUILD_LIBS_FOLDER\"}}' + - tools/build_all --build-app --build-tests + - cd build/test + - ./wsnet_test.exe + rules: + - if: $BUILD_WIN == "y" && $NIGHTLY_TEST_BUILD == "y" + +test:wsnet:mac: + <<: *template_mac_build + stage: Test + variables: + GIT_STRATEGY: clone + script: + - !reference [.build_mac_installer_common, script] + - tools/build_all --build-app --build-tests + - build/client/wsnet_test + after_script: + - python3 -m gcovr --xml-pretty --exclude-unreachable-branches --print-summary -o coverage.xml --root ${CI_PROJECT_DIR} + coverage: /^\s*lines:\s*\d+.\d+\%/ + artifacts: + name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}-mac + expire_in: 1 day + reports: + coverage_report: + coverage_format: cobertura + path: coverage.xml + rules: + - if: $BUILD_MAC == "y" && $NIGHTLY_TEST_BUILD == "y" + +test:wsnet:rhel: + <<: *template_rhel_build + stage: Test + variables: + GIT_STRATEGY: clone + script: + - OS_IDENTIFIER="linux" + - !reference [.build_linux_installer_common, script] + - tools/build_all --build-app --build-tests + - build/client/wsnet_test + after_script: + - python3 -m gcovr --xml-pretty --exclude-unreachable-branches --print-summary -o coverage.xml --root ${CI_PROJECT_DIR} + coverage: /^\s*lines:\s*\d+.\d+\%/ + artifacts: + name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}-linux + expire_in: 1 day + reports: + coverage_report: + coverage_format: cobertura + path: coverage.xml + rules: + - if: $BUILD_LINUX == "y" && $NIGHTLY_TEST_BUILD == "y" + diff --git a/backend/windows/windscribe_service/wireguard/wireguardcontroller.cpp b/backend/windows/windscribe_service/wireguard/wireguardcontroller.cpp index 4ca3392f..3cfa841c 100644 --- a/backend/windows/windscribe_service/wireguard/wireguardcontroller.cpp +++ b/backend/windows/windscribe_service/wireguard/wireguardcontroller.cpp @@ -37,7 +37,7 @@ bool WireGuardController::installService(const std::wstring &exeName, const std: deviceName_ = path.stem().native(); } - serviceName_ = L"WireGuardTunnel$" + deviceName_; + std::wstring serviceName = L"WireGuardTunnel$" + deviceName_; std::wstring serviceCmdLine; { @@ -49,15 +49,15 @@ bool WireGuardController::installService(const std::wstring &exeName, const std: wsl::ServiceControlManager svcCtrl; svcCtrl.openSCM(SC_MANAGER_ALL_ACCESS); - if (svcCtrl.isServiceInstalled(serviceName_.c_str())) { + if (svcCtrl.isServiceInstalled(serviceName.c_str())) { Logger::instance().out("WireGuardController::installService - deleting existing WireGuard service"); std::error_code ec; - if (!svcCtrl.deleteService(serviceName_.c_str(), ec)) { + if (!svcCtrl.deleteService(serviceName.c_str(), ec)) { Logger::instance().out("WireGuardController::installService - failed to delete existing WireGuard service (%d)", ec.value()); } } - svcCtrl.installService(serviceName_.c_str(), serviceCmdLine.c_str(), + svcCtrl.installService(serviceName.c_str(), serviceCmdLine.c_str(), L"Windscribe Wireguard Tunnel", L"Manages the Windscribe WireGuard tunnel connection", SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, L"Nsi\0TcpIp\0", true); @@ -76,8 +76,14 @@ bool WireGuardController::deleteService() { is_initialized_ = false; - if (serviceName_.empty()) { - return true; + std::wstring serviceName(L"WireGuardTunnel$"); + if (deviceName_.empty()) { + // Use the default device name if we don't have one. This could occur when this method is called + // after the helper has been restarted or the machine rebooted after a fault. + serviceName += L"WindscribeWireguard"; + } + else { + serviceName += deviceName_; } bool bServiceDeleted = false; @@ -85,15 +91,14 @@ bool WireGuardController::deleteService() wsl::ServiceControlManager svcCtrl; svcCtrl.openSCM(SC_MANAGER_ALL_ACCESS); - if (svcCtrl.isServiceInstalled(serviceName_.c_str())) { + if (svcCtrl.isServiceInstalled(serviceName.c_str())) { Logger::instance().out("WireGuardController::deleteService - deleting WireGuard service"); std::error_code ec; - if (!svcCtrl.deleteService(serviceName_.c_str(), ec)) { + if (!svcCtrl.deleteService(serviceName.c_str(), ec)) { throw std::system_error(ec); } } - serviceName_.clear(); bServiceDeleted = true; } catch (std::system_error& ex) { @@ -101,7 +106,6 @@ bool WireGuardController::deleteService() } if (!bServiceDeleted && !exeName_.empty()) { - serviceName_.clear(); Logger::instance().out("WireGuardController::deleteService - task killing the WireGuard service"); std::wstring killCmd = Utils::getSystemDir() + L"\\taskkill.exe /f /t /im " + exeName_; ExecuteCmd::instance().executeBlockingCmd(killCmd); diff --git a/backend/windows/windscribe_service/wireguard/wireguardcontroller.h b/backend/windows/windscribe_service/wireguard/wireguardcontroller.h index 76192d88..14a76942 100644 --- a/backend/windows/windscribe_service/wireguard/wireguardcontroller.h +++ b/backend/windows/windscribe_service/wireguard/wireguardcontroller.h @@ -20,7 +20,6 @@ class WireGuardController final private: bool is_initialized_ = false; - std::wstring serviceName_; std::wstring deviceName_; std::wstring exeName_; diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 81908a65..79cf1ea1 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -156,8 +156,9 @@ add_subdirectory(common) qt_finalize_executable(Windscribe) if(DEFINED IS_BUILD_TESTS) - enable_testing () - add_test (NAME locationsmodel.test COMMAND locationsmodel.test) + # Disabled for now, revisit later + # enable_testing () + # add_test (NAME locationsmodel.test COMMAND locationsmodel.test) endif (DEFINED IS_BUILD_TESTS) # ----- Install section ----- diff --git a/client/common/changelog.txt b/client/common/changelog.txt index 9659190b..36984c2e 100644 --- a/client/common/changelog.txt +++ b/client/common/changelog.txt @@ -1,3 +1,23 @@ +2.10.6 (22/03/2024) +All: + * Added a limit of 50 split tunnel entries to ensure stability. #437 + * Improved retry efficiency for requests that are blocked [wsnet]. #939 + * Improved custom DNS to not use ctrld if custom DNS is set to an IPv4 address. #795 + * Improved conditions for network connectivity detection. #98 + * Improved installer robustness in error situations. #950 + * Fixed callback may not be called on error [wsnet]. #729 +Windows: + * Improved firewall behavior when logging out but not restarting. #378 + * Improved monitoring of WireGuard service startup status when PC boots after a system crash or hard reset. #682 + * Updated Windows-on-Arm split tunnel driver WHQL signing certifcate. #934 +MacOS: + * Fixed crash when using custom configs. #943 + * Fixed a scenario where IKEv2 would be attempted in Lockdown Mode. #469 +Linux: + * Added requirement for iputils or equivalent since wsnet may use the 'ping' utility directly. #945 + * Fixed app window resize again, forcing a size update at the end of animations. #930 + + 2.10.5 (13/03/2024) All: * Improved stability of DNS resolution for hostnames when using split tunneling. #805 diff --git a/client/common/types/connecteddnsinfo.cpp b/client/common/types/connecteddnsinfo.cpp index 44005f8c..9233375a 100644 --- a/client/common/types/connecteddnsinfo.cpp +++ b/client/common/types/connecteddnsinfo.cpp @@ -1,6 +1,7 @@ #include "connecteddnsinfo.h" #include #include "utils/ws_assert.h" +#include "utils/ipvalidation.h" namespace types { @@ -32,6 +33,11 @@ QString ConnectedDnsInfo::typeToString(const CONNECTED_DNS_TYPE &type) } } +bool ConnectedDnsInfo::isCustomIPv4Address() const +{ + return type == CONNECTED_DNS_TYPE_CUSTOM && IpValidation::isIp(upStream1) && isSplitDns == false; +} + bool ConnectedDnsInfo::operator==(const ConnectedDnsInfo &other) const { return other.type == type && diff --git a/client/common/types/connecteddnsinfo.h b/client/common/types/connecteddnsinfo.h index 7a758314..9fea7991 100644 --- a/client/common/types/connecteddnsinfo.h +++ b/client/common/types/connecteddnsinfo.h @@ -78,6 +78,8 @@ struct ConnectedDnsInfo return json; } + bool isCustomIPv4Address() const; + friend QDataStream& operator <<(QDataStream &stream, const ConnectedDnsInfo &o); friend QDataStream& operator >>(QDataStream &stream, ConnectedDnsInfo &o); diff --git a/client/common/utils/servicecontrolmanager.cpp b/client/common/utils/servicecontrolmanager.cpp index e553a800..23bf0268 100644 --- a/client/common/utils/servicecontrolmanager.cpp +++ b/client/common/utils/servicecontrolmanager.cpp @@ -357,6 +357,11 @@ void ServiceControlManager::startService() return; } + if (status != SERVICE_START_PENDING) { + errorMsg << "startService(" << serviceName_ << ") API request succeeded, but the service aborted its startup"; + throw std::system_error(ERROR_SERVICE_NOT_ACTIVE, std::system_category(), wstring_to_string(errorMsg.str())); + } + ::Sleep(100); } @@ -366,7 +371,7 @@ void ServiceControlManager::startService() elapsedTime = ::GetTickCount64() - startTime; errorMsg << "startService(" << serviceName_ << ") API request succeeded, but the service did not report as running after " << elapsedTime << "ms"; - throw std::system_error(ERROR_SERVICE_REQUEST_TIMEOUT, std::system_category(), wstring_to_string(errorMsg.str())); + throw std::system_error(ERROR_SERVICE_START_HANG, std::system_category(), wstring_to_string(errorMsg.str())); } elapsedTime = ::GetTickCount64() - startTime; @@ -651,10 +656,17 @@ bool ServiceControlManager::deleteService(LPCTSTR serviceName, std::error_code& // QueryServiceStatus to fail. SERVICE_STATUS status; if (::QueryServiceStatus(service_, &status)) { - if (status.dwCurrentState != SERVICE_STOPPED) { - if (!stopService(ec)) { - return false; - } + switch (status.dwCurrentState) { + case SERVICE_STOPPED: + case SERVICE_START_PENDING: + case SERVICE_STOP_PENDING: + // A service in one of these states will not accept stop commands. + break; + default: + // Ignoring stopService failure, as we still need to mark the service for deletion even if we couldn't stop it. + stopService(ec); + ec.clear(); + break; } } diff --git a/client/common/version/windscribe_version.h b/client/common/version/windscribe_version.h index 49f3c8be..d1dcfe62 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 5 +#define WINDSCRIBE_BUILD_VERSION 6 // only one of these should be enabled; neither -> stable //#define WINDSCRIBE_IS_BETA diff --git a/client/engine/engine/apiresources/CMakeLists.txt b/client/engine/engine/apiresources/CMakeLists.txt index dd090386..ab3c9254 100644 --- a/client/engine/engine/apiresources/CMakeLists.txt +++ b/client/engine/engine/apiresources/CMakeLists.txt @@ -7,6 +7,6 @@ target_sources(engine PRIVATE myipmanager.h ) -if(DEFINED IS_BUILD_TESTS) - add_subdirectory(tests) -endif(DEFINED IS_BUILD_TESTS) +#if(DEFINED IS_BUILD_TESTS) + #add_subdirectory(tests) +#endif(DEFINED IS_BUILD_TESTS) diff --git a/client/engine/engine/connectionmanager/connectionmanager.cpp b/client/engine/engine/connectionmanager/connectionmanager.cpp index 9fed2bd2..9e2e0d57 100644 --- a/client/engine/engine/connectionmanager/connectionmanager.cpp +++ b/client/engine/engine/connectionmanager/connectionmanager.cpp @@ -180,19 +180,6 @@ void ConnectionManager::clickConnect(const QString &ovpnConfig, const apiinfo::S updateConnectionSettingsPolicy(connectionSettings, portMap, proxySettings); connSettingsPolicy_->debugLocationInfoToLog(); - -#ifdef Q_OS_MAC - // For automatic policy, we would have removed IKEv2 from the list for lockdown mode. - // There is no custom config for IKEv2, so if we get here it is manual mode. - // We can get here either by: - // - User selecting IKEv2 in manual mode and then enabling Lockdown Mode, or - // - User selecting IKEv2 in manual mode in a previous version of Windscribe, then updating. - if (connSettingsPolicy_->getCurrentConnectionSettings().protocol == types::Protocol::IKEV2 && MacUtils::isLockdownMode()) { - emit errorDuringConnection(CONNECT_ERROR::LOCKDOWN_MODE_IKEV2); - return; - } -#endif - doConnect(); } @@ -368,15 +355,13 @@ void ConnectionManager::onConnectionConnected(const AdapterGatewayInfo &connecti qCDebug(LOG_CONNECTION) << "VPN adapter and gateway:" << vpnAdapterInfo_.makeLogString(); // override the DNS if we are using custom - if (connectedDnsInfo_.type == CONNECTED_DNS_TYPE_CUSTOM) - { - QString customDnsIp = ctrldManager_->listenIp(); + if (connectedDnsInfo_.type == CONNECTED_DNS_TYPE_CUSTOM) { + QString customDnsIp = dnsServersFromConnectedDnsInfo(); vpnAdapterInfo_.setDnsServers(QStringList() << customDnsIp); qCDebug(LOG_CONNECTION) << "Custom DNS detected, will override with: " << customDnsIp; } - if (state_ == STATE_DISCONNECTING_FROM_USER_CLICK) - { + if (state_ == STATE_DISCONNECTING_FROM_USER_CLICK) { qCDebug(LOG_CONNECTION) << "Already disconnecting -- do not enter connected state"; return; } @@ -881,15 +866,31 @@ void ConnectionManager::onWstunnelStarted() void ConnectionManager::doConnect() { - if (!networkDetectionManager_->isOnline()) - { +#ifdef Q_OS_MAC + // For automatic policy, we would have removed IKEv2 from the list for lockdown mode. + // There is no custom config for IKEv2, so if we get here it is manual mode. + // We can get here either by: + // - User selecting IKEv2 in manual mode and then enabling Lockdown Mode, or + // - User selecting IKEv2 in manual mode in a previous version of Windscribe, then updating. + if (!connSettingsPolicy_->isCustomConfig() && connSettingsPolicy_->getCurrentConnectionSettings().protocol == types::Protocol::IKEV2 && MacUtils::isLockdownMode()) { + emit errorDuringConnection(CONNECT_ERROR::LOCKDOWN_MODE_IKEV2); + return; + } +#endif + + bool isOnline = networkDetectionManager_->isOnline(); + defaultAdapterInfo_.clear(); + if (isOnline) { + defaultAdapterInfo_ = AdapterGatewayInfo::detectAndCreateDefaultAdapterInfo(); + } + + if (!isOnline || defaultAdapterInfo_.isEmpty()) { startReconnectionTimer(); waitForNetworkConnectivity(); return; } - defaultAdapterInfo_ = AdapterGatewayInfo::detectAndCreateDefaultAdapterInfo(); - qCDebug(LOG_CONNECTION) << "Default adapter and gateway:" << defaultAdapterInfo_.makeLogString(); + qCDebug(LOG_CONNECTION) << "Default adapter and gateway:" << defaultAdapterInfo_.makeLogString(); connectTimer_.stop(); connectingTimer_.setSingleShot(true); @@ -933,7 +934,7 @@ void ConnectionManager::doConnectPart2() #endif // start ctrld utility - if (connectedDnsInfo_.type == CONNECTED_DNS_TYPE_CUSTOM) { + if (connectedDnsInfo_.type == CONNECTED_DNS_TYPE_CUSTOM && !connectedDnsInfo_.isCustomIPv4Address()) { bool bStarted = false; if (connectedDnsInfo_.isSplitDns) bStarted = ctrldManager_->runProcess(connectedDnsInfo_.upStream1, connectedDnsInfo_.upStream2, connectedDnsInfo_.hostnames); @@ -955,6 +956,10 @@ void ConnectionManager::doConnectPart2() } dynamic_cast(helper_)->setCustomDnsIps(dnsIps); #endif + } else if (connectedDnsInfo_.isCustomIPv4Address()) { +#ifdef Q_OS_WIN + dynamic_cast(helper_)->setCustomDnsIps(QStringList() << connectedDnsInfo_.upStream1); +#endif } else { #ifdef Q_OS_WIN dynamic_cast(helper_)->setCustomDnsIps(QStringList()); @@ -1004,7 +1009,7 @@ void ConnectionManager::doConnectPart2() lastOvpnConfig_, currentConnectionDescr_.ip, currentConnectionDescr_.protocol, currentConnectionDescr_.port, localPort, mss, defaultAdapterInfo_.gateway(), currentConnectionDescr_.verifyX509name, - connectedDnsTypeAuto() ? "" : ctrldManager_->listenIp()); + dnsServersFromConnectedDnsInfo()); if (!bOvpnSuccess) { qCDebug(LOG_CONNECTION) << "Failed create ovpn config"; WS_ASSERT(false); @@ -1098,13 +1103,14 @@ void ConnectionManager::doConnectPart3() QStringList dnsIps; if (connectedDnsTypeAuto()) { dnsIps << pConfig->clientDnsAddress(); + } else if (connectedDnsInfo_.isCustomIPv4Address()) { + dnsIps << connectedDnsInfo_.upStream1; } else { if (IpValidation::isIp(connectedDnsInfo_.upStream1)) { dnsIps << connectedDnsInfo_.upStream1; } dnsIps << ctrldManager_->listenIp(); } - emit connectingToHostname(currentConnectionDescr_.hostname, currentConnectionDescr_.ip, dnsIps); } else @@ -1122,7 +1128,7 @@ void ConnectionManager::doConnectPart3() connector_->startConnect(makeOVPNFileFromCustom_->config(), "", "", usernameForCustomOvpn_, passwordForCustomOvpn_, lastProxySettings_, currentConnectionDescr_.wgCustomConfig.get(), false, false, true, - connectedDnsTypeAuto() ? QString() : ctrldManager_->listenIp()); + dnsServersFromConnectedDnsInfo()); } else { @@ -1143,7 +1149,7 @@ void ConnectionManager::doConnectPart3() recreateConnector(types::Protocol::OPENVPN_UDP); connector_->startConnect(makeOVPNFile_->config(), "", "", username, password, lastProxySettings_, nullptr, false, connSettingsPolicy_->isAutomaticMode(), false, - connectedDnsTypeAuto() ? QString() : ctrldManager_->listenIp()); + dnsServersFromConnectedDnsInfo()); } else if (currentConnectionDescr_.protocol.isIkev2Protocol()) { @@ -1162,7 +1168,7 @@ void ConnectionManager::doConnectPart3() recreateConnector(types::Protocol::IKEV2); connector_->startConnect(currentConnectionDescr_.hostname, currentConnectionDescr_.ip, currentConnectionDescr_.hostname, username, password, lastProxySettings_, nullptr, ExtraConfig::instance().isUseIkev2Compression(), connSettingsPolicy_->isAutomaticMode(), false, - connectedDnsTypeAuto() ? QString() : ctrldManager_->listenIp()); + dnsServersFromConnectedDnsInfo()); } else if (currentConnectionDescr_.protocol.isWireGuardProtocol()) { @@ -1179,7 +1185,7 @@ void ConnectionManager::doConnectPart3() connector_->startConnect(QString(), currentConnectionDescr_.ip, currentConnectionDescr_.dnsHostName, QString(), QString(), lastProxySettings_, &wireGuardConfig_, false, connSettingsPolicy_->isAutomaticMode(), false, - connectedDnsTypeAuto() ? QString() : ctrldManager_->listenIp()); + dnsServersFromConnectedDnsInfo()); } else { @@ -1351,7 +1357,7 @@ void ConnectionManager::onTunnelTestsFinished(bool bSuccess, const QString &ipAd void ConnectionManager::onTimerWaitNetworkConnectivity() { - if (networkDetectionManager_->isOnline()) + if (networkDetectionManager_->isOnline() && !AdapterGatewayInfo::detectAndCreateDefaultAdapterInfo().isEmpty()) { qCDebug(LOG_CONNECTION) << "We online, make the connection"; timerWaitNetworkConnectivity_.stop(); @@ -1572,6 +1578,16 @@ bool ConnectionManager::connectedDnsTypeAuto() const return connectedDnsInfo_.type == CONNECTED_DNS_TYPE_AUTO || connectedDnsInfo_.type == CONNECTED_DNS_TYPE_FORCED; } +QString ConnectionManager::dnsServersFromConnectedDnsInfo() const +{ + if (connectedDnsInfo_.type == CONNECTED_DNS_TYPE_AUTO || connectedDnsInfo_.type == CONNECTED_DNS_TYPE_FORCED) + return QString(); + else if (connectedDnsInfo_.isCustomIPv4Address()) + return connectedDnsInfo_.upStream1; + else + return ctrldManager_->listenIp(); +} + void ConnectionManager::disconnect() { Logger::instance().endConnectionMode(); diff --git a/client/engine/engine/connectionmanager/connectionmanager.h b/client/engine/engine/connectionmanager/connectionmanager.h index 7bb8dbc2..d43bb799 100644 --- a/client/engine/engine/connectionmanager/connectionmanager.h +++ b/client/engine/engine/connectionmanager/connectionmanager.h @@ -233,5 +233,7 @@ private slots: void connectOrStartConnectTimer(); void getWireGuardConfig(const QString &serverName, bool deleteOldestKey, const QString &deviceId); bool connectedDnsTypeAuto() const; + QString dnsServersFromConnectedDnsInfo() const; + void disconnect(); }; diff --git a/client/engine/engine/connectionmanager/connsettingspolicy/autoconnsettingspolicy.cpp b/client/engine/engine/connectionmanager/connsettingspolicy/autoconnsettingspolicy.cpp index 274541f8..d58b6620 100644 --- a/client/engine/engine/connectionmanager/connsettingspolicy/autoconnsettingspolicy.cpp +++ b/client/engine/engine/connectionmanager/connsettingspolicy/autoconnsettingspolicy.cpp @@ -149,6 +149,12 @@ bool AutoConnSettingsPolicy::isAutomaticMode() return true; } +bool AutoConnSettingsPolicy::isCustomConfig() +{ + return false; +} + + void AutoConnSettingsPolicy::resolveHostnames() { // nothing todo diff --git a/client/engine/engine/connectionmanager/connsettingspolicy/autoconnsettingspolicy.h b/client/engine/engine/connectionmanager/connsettingspolicy/autoconnsettingspolicy.h index d9e886e6..53398da2 100644 --- a/client/engine/engine/connectionmanager/connsettingspolicy/autoconnsettingspolicy.h +++ b/client/engine/engine/connectionmanager/connsettingspolicy/autoconnsettingspolicy.h @@ -18,6 +18,7 @@ class AutoConnSettingsPolicy : public BaseConnSettingsPolicy bool isFailed() const override; CurrentConnectionDescr getCurrentConnectionSettings() const override; bool isAutomaticMode() override; + bool isCustomConfig() override; void resolveHostnames() override; bool hasProtocolChanged() override; diff --git a/client/engine/engine/connectionmanager/connsettingspolicy/baseconnsettingspolicy.h b/client/engine/engine/connectionmanager/connsettingspolicy/baseconnsettingspolicy.h index a1528218..ffc3d5e5 100644 --- a/client/engine/engine/connectionmanager/connsettingspolicy/baseconnsettingspolicy.h +++ b/client/engine/engine/connectionmanager/connsettingspolicy/baseconnsettingspolicy.h @@ -65,6 +65,7 @@ class BaseConnSettingsPolicy : public QObject virtual bool isFailed() const = 0; virtual CurrentConnectionDescr getCurrentConnectionSettings() const = 0; virtual bool isAutomaticMode() = 0; + virtual bool isCustomConfig() = 0; virtual void resolveHostnames() = 0; virtual bool hasProtocolChanged() = 0; diff --git a/client/engine/engine/connectionmanager/connsettingspolicy/customconfigconnsettingspolicy.cpp b/client/engine/engine/connectionmanager/connsettingspolicy/customconfigconnsettingspolicy.cpp index 42ddf28d..eb33019b 100644 --- a/client/engine/engine/connectionmanager/connsettingspolicy/customconfigconnsettingspolicy.cpp +++ b/client/engine/engine/connectionmanager/connsettingspolicy/customconfigconnsettingspolicy.cpp @@ -61,6 +61,11 @@ bool CustomConfigConnSettingsPolicy::isAutomaticMode() return false; } +bool CustomConfigConnSettingsPolicy::isCustomConfig() +{ + return true; +} + void CustomConfigConnSettingsPolicy::resolveHostnames() { locationInfo_->resolveHostnames(); diff --git a/client/engine/engine/connectionmanager/connsettingspolicy/customconfigconnsettingspolicy.h b/client/engine/engine/connectionmanager/connsettingspolicy/customconfigconnsettingspolicy.h index 38be7100..3f8065b8 100644 --- a/client/engine/engine/connectionmanager/connsettingspolicy/customconfigconnsettingspolicy.h +++ b/client/engine/engine/connectionmanager/connsettingspolicy/customconfigconnsettingspolicy.h @@ -17,6 +17,7 @@ class CustomConfigConnSettingsPolicy : public BaseConnSettingsPolicy bool isFailed() const override; CurrentConnectionDescr getCurrentConnectionSettings() const override; bool isAutomaticMode() override; + bool isCustomConfig() override; void resolveHostnames() override; bool hasProtocolChanged() override; diff --git a/client/engine/engine/connectionmanager/connsettingspolicy/manualconnsettingspolicy.cpp b/client/engine/engine/connectionmanager/connsettingspolicy/manualconnsettingspolicy.cpp index 40b53d76..6ccb1f0f 100644 --- a/client/engine/engine/connectionmanager/connsettingspolicy/manualconnsettingspolicy.cpp +++ b/client/engine/engine/connectionmanager/connsettingspolicy/manualconnsettingspolicy.cpp @@ -93,6 +93,11 @@ bool ManualConnSettingsPolicy::isAutomaticMode() return false; } +bool ManualConnSettingsPolicy::isCustomConfig() +{ + return false; +} + void ManualConnSettingsPolicy::resolveHostnames() { //nothing todo diff --git a/client/engine/engine/connectionmanager/connsettingspolicy/manualconnsettingspolicy.h b/client/engine/engine/connectionmanager/connsettingspolicy/manualconnsettingspolicy.h index d86298e6..67e78373 100644 --- a/client/engine/engine/connectionmanager/connsettingspolicy/manualconnsettingspolicy.h +++ b/client/engine/engine/connectionmanager/connsettingspolicy/manualconnsettingspolicy.h @@ -20,6 +20,7 @@ class ManualConnSettingsPolicy : public BaseConnSettingsPolicy bool isFailed() const override; CurrentConnectionDescr getCurrentConnectionSettings() const override; bool isAutomaticMode() override; + bool isCustomConfig() override; void resolveHostnames() override; bool hasProtocolChanged() override; diff --git a/client/engine/engine/measurementcpuusage.cpp b/client/engine/engine/measurementcpuusage.cpp index acb8f7b0..3d7b09e3 100644 --- a/client/engine/engine/measurementcpuusage.cpp +++ b/client/engine/engine/measurementcpuusage.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "engine/helper/helper_win.h" #include "utils/logger.h" #include "utils/ws_assert.h" @@ -178,7 +180,7 @@ bool MeasurementCpuUsage::getPerformanceCounters() if (!match.hasMatch()) { auto it = counters_.find(processName); if (it == counters_.end()) { - PDH_HCOUNTER hCounter; + PDH_HCOUNTER hCounter = NULL; QString counterPath = QString("\\Process(%1)\\% Processor Time").arg(processName); PDH_STATUS status = PdhAddEnglishCounter(hQuery_, counterPath.toStdWString().c_str(), 0, &hCounter); if (status == ERROR_SUCCESS) { @@ -189,7 +191,14 @@ bool MeasurementCpuUsage::getPerformanceCounters() bAddedNewProcesses = true; } else { - qCDebug(LOG_BASIC) << "MeasurementCpuUsage::getPerformanceCounters failed to add counter for process =" << processName; + if (hCounter != NULL) { + PdhRemoveCounter(hCounter); + } + if (IsErrorSeverity(status)) { + if (status != PDH_CSTATUS_NO_OBJECT && status != PDH_CSTATUS_NO_COUNTER) { + qCDebug(LOG_BASIC) << "MeasurementCpuUsage::getPerformanceCounters failed to add counter for process" << processName << status; + } + } } } else { diff --git a/client/engine/engine/ping/CMakeLists.txt b/client/engine/engine/ping/CMakeLists.txt index 083c8680..e87f22fa 100644 --- a/client/engine/engine/ping/CMakeLists.txt +++ b/client/engine/engine/ping/CMakeLists.txt @@ -11,6 +11,6 @@ target_sources(engine PRIVATE pingstorage.h ) -if(DEFINED IS_BUILD_TESTS) - add_subdirectory(tests) -endif(DEFINED IS_BUILD_TESTS) +#if(DEFINED IS_BUILD_TESTS) + #add_subdirectory(tests) +#endif(DEFINED IS_BUILD_TESTS) diff --git a/client/gui/application/windowsnativeeventfilter.cpp b/client/gui/application/windowsnativeeventfilter.cpp index 53719e6c..a920fdcc 100644 --- a/client/gui/application/windowsnativeeventfilter.cpp +++ b/client/gui/application/windowsnativeeventfilter.cpp @@ -25,41 +25,31 @@ bool WindowsNativeEventFilter::nativeEventFilter(const QByteArray &b, void *mess MSG* msg = reinterpret_cast(message); - if ( msg->message == WM_QUERYENDSESSION || msg->message == WM_ENDSESSION ) - { + if (msg->message == WM_QUERYENDSESSION || msg->message == WM_ENDSESSION) { if (msg->message == WM_ENDSESSION && msg->wParam == FALSE) { qCDebug(LOG_BASIC) << "Windows shutdown interrupted by user"; WindscribeApplication::instance()->clearWasRestartOSFlag(); bShutdownAlreadyReceived_ = false; + // if lParam is 0, the system is shutting down or restarting, otherwise it's a logout + } else if (msg->lParam == 0 && !bShutdownAlreadyReceived_) { + qCDebug(LOG_BASIC) << "Windows shutdown received"; + WindscribeApplication::instance()->setWasRestartOSFlag(); + bShutdownAlreadyReceived_ = true; } - else - { - if (!bShutdownAlreadyReceived_) - { - qCDebug(LOG_BASIC) << "Windows shutdown received"; - WindscribeApplication::instance()->setWasRestartOSFlag(); - bShutdownAlreadyReceived_ = true; - } - } - } - else if (msg->message == WM_DPICHANGED) - { + } else if (msg->message == WM_DPICHANGED) { auto *widget = QWidget::find(WId(msg->hwnd)); if (widget) { auto *dpi_scale_aware_widget = dynamic_cast(widget); - if (dpi_scale_aware_widget) + if (dpi_scale_aware_widget) { dpi_scale_aware_widget->checkForAutoResize_win(); + } } - } - else if ( msg->message == dwActivateMessage_) - { + } else if ( msg->message == dwActivateMessage_) { qCDebug(LOG_BASIC) << "Windows activate app message received"; WindscribeApplication::instance()->onActivateFromAnotherInstance(); return true; - } - else if (msg->message == WM_WININICHANGE) - { + } else if (msg->message == WM_WININICHANGE) { // WM_WININICHANGE fires when OS light/dark mode is updated WindscribeApplication::instance()->onWinIniChanged(); return true; diff --git a/client/gui/mainwindow.cpp b/client/gui/mainwindow.cpp index 9b9bb5c4..93f7cfcc 100644 --- a/client/gui/mainwindow.cpp +++ b/client/gui/mainwindow.cpp @@ -512,6 +512,20 @@ bool MainWindow::doClose(QCloseEvent *event, bool isFromSigTerm_mac) // for startup fix (when app disabled in task manager) LaunchOnStartup::instance().setLaunchOnStartup(backend_->getPreferences()->isLaunchOnStartup()); +#if defined(Q_OS_WIN) + // In Windows, If user is logging off, but not restarting, turn off the firewall so it does not affect other users on the same system + // Note that this must occur before the backend cleanup call. + if (PersistentState::instance().isFirewallOn() && + backend_->getPreferences()->firewallSettings().mode == FIREWALL_MODE_AUTOMATIC && + // This is how to detect a user is logging off (See https://devblogs.microsoft.com/oldnewthing/20180705-00/?p=99175) + GetSystemMetrics(SM_SHUTTINGDOWN) && + !WindscribeApplication::instance()->isExitWithRestart()) + { + qCDebug(LOG_BASIC) << "Turning off firewall for non-restart logout"; + backend_->firewallOff(); + } +#endif + backend_->cleanup(WindscribeApplication::instance()->isExitWithRestart(), PersistentState::instance().isFirewallOn(), backend_->getPreferences()->firewallSettings().mode == FIREWALL_MODE_ALWAYS_ON || isExitingAfterUpdate_, backend_->getPreferences()->isLaunchOnStartup()); diff --git a/client/gui/mainwindowcontroller.cpp b/client/gui/mainwindowcontroller.cpp index bef062eb..000a984a 100644 --- a/client/gui/mainwindowcontroller.cpp +++ b/client/gui/mainwindowcontroller.cpp @@ -3173,6 +3173,10 @@ void MainWindowController::updateViewAndScene(int width, int height, int shadowS void MainWindowController::handleNextWindowChange() { +#ifdef Q_OS_LINUX + // Between window changes, force a main window geo update with updateShadow set to true, so that the workaround for #930 can take effect. + updateMainAndViewGeometry(true); +#endif if (!queueWindowChanges_.isEmpty()) { changeWindow(queueWindowChanges_.dequeue()); } else { diff --git a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingaddressesgroup.cpp b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingaddressesgroup.cpp index bdca5fb7..e624f66b 100644 --- a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingaddressesgroup.cpp +++ b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingaddressesgroup.cpp @@ -48,6 +48,11 @@ void SplitTunnelingAddressesGroup::addAddress(types::SplitTunnelingNetworkRoute void SplitTunnelingAddressesGroup::addAddressInternal(types::SplitTunnelingNetworkRoute &address) { + if (size() > kMaxAddresses) { + emit setError(tr("There are too many IPs or hostnames in the list. Please remove some before adding more.")); + return; + } + AddressItem *item = new AddressItem(address, this); connect(item, &AddressItem::deleteClicked, this, &SplitTunnelingAddressesGroup::onDeleteClicked); addresses_[item] = address; @@ -67,28 +72,26 @@ void SplitTunnelingAddressesGroup::onAddClicked(QString address) SPLIT_TUNNELING_NETWORK_ROUTE_TYPE type; types::SplitTunnelingNetworkRoute route; - switch(code) - { - case OK: - type = SPLIT_TUNNELING_NETWORK_ROUTE_TYPE_HOSTNAME; - if (IpValidation::isIpCidr(address)) - { - type = SPLIT_TUNNELING_NETWORK_ROUTE_TYPE_IP; - } - - route.name = address; - route.type = type; - addAddress(route); - break; - case ERROR_EXISTS: - emit setError(tr("IP or hostname already exists. Please enter a new IP or hostname.")); - break; - case ERROR_INVALID: - emit setError(tr("Incorrect IP address/mask combination. Please enter a valid hostname or IP address in plain or CIDR notation.")); - break; - case ERROR_RESERVED: - emit setError(tr("This IP address or range is reserved by Windscribe and can not be changed.")); - break; + switch(code) { + case OK: + type = SPLIT_TUNNELING_NETWORK_ROUTE_TYPE_HOSTNAME; + if (IpValidation::isIpCidr(address)) { + type = SPLIT_TUNNELING_NETWORK_ROUTE_TYPE_IP; + } + + route.name = address; + route.type = type; + addAddress(route); + break; + case ERROR_EXISTS: + emit setError(tr("IP or hostname already exists. Please enter a new IP or hostname.")); + break; + case ERROR_INVALID: + emit setError(tr("Incorrect IP address/mask combination. Please enter a valid hostname or IP address in plain or CIDR notation.")); + break; + case ERROR_RESERVED: + emit setError(tr("This IP address or range is reserved by Windscribe and can not be changed.")); + break; } } @@ -102,23 +105,19 @@ void SplitTunnelingAddressesGroup::onDeleteClicked() SplitTunnelingAddressesGroup::ValidationCode SplitTunnelingAddressesGroup::validate(QString &address) { - if (!IpValidation::isIpCidrOrDomain(address) || !IpValidation::isValidIpForCidr(address)) - { + if (!IpValidation::isIpCidrOrDomain(address) || !IpValidation::isValidIpForCidr(address)) { return ValidationCode::ERROR_INVALID; } - if (itemByName(address) != nullptr) - { + if (itemByName(address) != nullptr) { return ValidationCode::ERROR_EXISTS; } - if (!IpValidation::isValidIpForCidr(address)) - { + if (!IpValidation::isValidIpForCidr(address)) { return ValidationCode::ERROR_INVALID; } - if (IpValidation::isWindscribeReservedIp(address)) - { + if (IpValidation::isWindscribeReservedIp(address)) { return ValidationCode::ERROR_RESERVED; } @@ -127,10 +126,8 @@ SplitTunnelingAddressesGroup::ValidationCode SplitTunnelingAddressesGroup::valid AddressItem *SplitTunnelingAddressesGroup::itemByName(QString &address) { - for (AddressItem *item: addresses_.keys()) - { - if (item->getAddressText() == address) - { + for (AddressItem *item: addresses_.keys()) { + if (item->getAddressText() == address) { return item; } } @@ -140,8 +137,7 @@ AddressItem *SplitTunnelingAddressesGroup::itemByName(QString &address) void SplitTunnelingAddressesGroup::setLoggedIn(bool loggedIn) { newAddressItem_->setClickable(loggedIn); - for (AddressItem *item: addresses_.keys()) - { + for (AddressItem *item: addresses_.keys()) { item->setClickable(loggedIn); } } diff --git a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingaddressesgroup.h b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingaddressesgroup.h index 9f2c63f4..c58574b6 100644 --- a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingaddressesgroup.h +++ b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingaddressesgroup.h @@ -12,6 +12,8 @@ class SplitTunnelingAddressesGroup : public PreferenceGroup { Q_OBJECT public: + static const int kMaxAddresses = 50; + explicit SplitTunnelingAddressesGroup(ScalableGraphicsObject *parent, const QString &desc = "", const QString &descUrl = ""); diff --git a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappsgroup.cpp b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappsgroup.cpp index 515f19ff..ef68708f 100644 --- a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappsgroup.cpp +++ b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappsgroup.cpp @@ -63,12 +63,18 @@ void SplitTunnelingAppsGroup::setApps(QList apps) void SplitTunnelingAppsGroup::addApp(types::SplitTunnelingApp &app) { - addAppInternal(app); - emit appsUpdated(apps_.values()); + if(addAppInternal(app)) { + emit appsUpdated(apps_.values()); + } } -void SplitTunnelingAppsGroup::addAppInternal(types::SplitTunnelingApp &app) +bool SplitTunnelingAppsGroup::addAppInternal(types::SplitTunnelingApp &app) { + if (apps_.size() >= kMaxApps) { + emit setError(tr("There are too many apps in the list. Please remove some before adding more.")); + return false; + } + AppIncludedItem *item = new AppIncludedItem(app, this); connect(item, &AppIncludedItem::deleteClicked, this, &SplitTunnelingAppsGroup::onDeleteClicked); apps_[item] = app; @@ -78,6 +84,7 @@ void SplitTunnelingAppsGroup::addAppInternal(types::SplitTunnelingApp &app) if (mode_ == OP_MODE::DEFAULT) { showItems(indexOf(item)); } + return true; } void SplitTunnelingAppsGroup::addSearchApp(types::SplitTunnelingApp &app) @@ -89,8 +96,7 @@ void SplitTunnelingAppsGroup::addSearchApp(types::SplitTunnelingApp &app) addItem(item); hideItems(indexOf(item), -1, DISPLAY_FLAGS::FLAG_NO_ANIMATION); - if (mode_ == OP_MODE::SEARCH) - { + if (mode_ == OP_MODE::SEARCH) { showItems(indexOf(item)); } } @@ -122,12 +128,9 @@ void SplitTunnelingAppsGroup::onSearchTextChanged(QString text) showFilteredSearchItems(text); searchLineEditItem_->setSelected(true); - if (text == "") - { + if (text == "") { searchLineEditItem_->hideButtons(); - } - else - { + } else { searchLineEditItem_->showButtons(); } } @@ -143,8 +146,7 @@ void SplitTunnelingAppsGroup::onSearchModeExited() // show main bar and active items showItems(indexOf(splitTunnelingAppsItem_), -1, DISPLAY_FLAGS::FLAG_NO_ANIMATION); - for (BaseItem *item : apps_.keys()) - { + for (BaseItem *item : apps_.keys()) { showItems(indexOf(item), -1, DISPLAY_FLAGS::FLAG_NO_ANIMATION); } @@ -196,8 +198,7 @@ void SplitTunnelingAppsGroup::onSearchItemClicked() { AppSearchItem *item = static_cast(sender()); - if (item != nullptr) - { + if (item != nullptr) { onSearchModeExited(); toggleAppItemActive(item); } @@ -208,26 +209,23 @@ void SplitTunnelingAppsGroup::toggleAppItemActive(AppSearchItem *item) QString appName = item->getName(); AppIncludedItem *existingApp = appByName(appName); - if (!existingApp) - { + if (!existingApp) { types::SplitTunnelingApp app; app.name = appName; app.type = SPLIT_TUNNELING_APP_TYPE_SYSTEM; app.active = true; app.fullName = item->getFullName(); app.icon = item->getAppIcon(); - addAppInternal(app); + if (addAppInternal(app)) { + emit appsUpdated(apps_.values()); + } } - - emit appsUpdated(apps_.values()); } AppIncludedItem *SplitTunnelingAppsGroup::appByName(QString name) { - for (AppIncludedItem *item : apps_.keys()) - { - if (apps_[item].name == name) - { + for (AppIncludedItem *item : apps_.keys()) { + if (apps_[item].name == name) { return item; } } @@ -236,16 +234,11 @@ AppIncludedItem *SplitTunnelingAppsGroup::appByName(QString name) void SplitTunnelingAppsGroup::showFilteredSearchItems(QString filter) { - if (OP_MODE::SEARCH) - { - for (AppSearchItem *item : searchApps_.keys()) - { - if (filter == "" || (searchApps_[item].name.toLower().contains(filter.toLower()) && !appByName(searchApps_[item].name))) - { + if (OP_MODE::SEARCH) { + for (AppSearchItem *item : searchApps_.keys()) { + if (filter == "" || (searchApps_[item].name.toLower().contains(filter.toLower()) && !appByName(searchApps_[item].name))) { showItems(indexOf(item), -1, DISPLAY_FLAGS::FLAG_NO_ANIMATION); - } - else - { + } else { hideItems(indexOf(item), -1, DISPLAY_FLAGS::FLAG_NO_ANIMATION); } } @@ -254,22 +247,15 @@ void SplitTunnelingAppsGroup::showFilteredSearchItems(QString filter) void SplitTunnelingAppsGroup::keyPressEvent(QKeyEvent *event) { - if (event->key() == Qt::Key_Escape) - { - if (mode_ == OP_MODE::SEARCH) - { - if (searchLineEditItem_->text() == "") - { + if (event->key() == Qt::Key_Escape) { + if (mode_ == OP_MODE::SEARCH) { + if (searchLineEditItem_->text() == "") { onSearchModeExited(); - } - else - { + } else { searchLineEditItem_->setText(""); emit escape(); } - } - else - { + } else { emit escape(); } } @@ -279,15 +265,13 @@ void SplitTunnelingAppsGroup::setLoggedIn(bool loggedIn) { splitTunnelingAppsItem_->setClickable(loggedIn); searchLineEditItem_->setClickable(loggedIn); - if (mode_ == OP_MODE::SEARCH) - { + if (mode_ == OP_MODE::SEARCH) { onSearchModeExited(); } - for (AppIncludedItem *item : apps_.keys()) - { + for (AppIncludedItem *item : apps_.keys()) { item->setClickable(loggedIn); } } -} +} // namespace PreferencesWindow diff --git a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappsgroup.h b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappsgroup.h index 125e49c2..b13e904a 100644 --- a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappsgroup.h +++ b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappsgroup.h @@ -13,6 +13,8 @@ class SplitTunnelingAppsGroup : public PreferenceGroup { Q_OBJECT public: + static const int kMaxApps = 50; + explicit SplitTunnelingAppsGroup(ScalableGraphicsObject *parent, const QString &desc = "", const QString &descUrl = ""); @@ -28,6 +30,7 @@ class SplitTunnelingAppsGroup : public PreferenceGroup void addClicked(); void appsUpdated(QList apps); void escape(); + void setError(QString msg); protected slots: void keyPressEvent(QKeyEvent *event) override; @@ -41,7 +44,7 @@ private slots: void onSearchItemClicked(); private: - void addAppInternal(types::SplitTunnelingApp &app); + bool addAppInternal(types::SplitTunnelingApp &app); void addSearchApp(types::SplitTunnelingApp &app); void populateSearchApps(); void showFilteredSearchItems(QString filter); diff --git a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappswindowitem.cpp b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappswindowitem.cpp index 07e1b408..d93af05f 100644 --- a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappswindowitem.cpp +++ b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappswindowitem.cpp @@ -17,6 +17,7 @@ SplitTunnelingAppsWindowItem::SplitTunnelingAppsWindowItem(ScalableGraphicsObjec splitTunnelingAppsGroup_ = new SplitTunnelingAppsGroup(this); connect(splitTunnelingAppsGroup_, &SplitTunnelingAppsGroup::appsUpdated, this, &SplitTunnelingAppsWindowItem::onAppsUpdated); + connect(splitTunnelingAppsGroup_, &SplitTunnelingAppsGroup::setError, this, &SplitTunnelingAppsWindowItem::onError); connect(splitTunnelingAppsGroup_, &SplitTunnelingAppsGroup::addClicked, this, &SplitTunnelingAppsWindowItem::addButtonClicked); connect(splitTunnelingAppsGroup_, &SplitTunnelingAppsGroup::escape, this, &SplitTunnelingAppsWindowItem::escape); addItem(splitTunnelingAppsGroup_); @@ -48,6 +49,9 @@ void SplitTunnelingAppsWindowItem::addAppManually(types::SplitTunnelingApp app) void SplitTunnelingAppsWindowItem::onAppsUpdated(QList apps) { + // Clears error and sets the default description + setLoggedIn(loggedIn_); + preferences_->setSplitTunnelingApps(apps); emit appsUpdated(apps); } @@ -76,4 +80,9 @@ void SplitTunnelingAppsWindowItem::onPreferencesChanged() splitTunnelingAppsGroup_->setApps(preferences_->splitTunnelingApps()); } +void SplitTunnelingAppsWindowItem::onError(QString msg) +{ + desc_->setDescription(msg, true); +} + } // namespace PreferencesWindow diff --git a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappswindowitem.h b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappswindowitem.h index 907caf70..eb0099b7 100644 --- a/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappswindowitem.h +++ b/client/gui/preferenceswindow/splittunnelingwindow/splittunnelingappswindowitem.h @@ -27,6 +27,7 @@ class SplitTunnelingAppsWindowItem : public CommonGraphics::BasePage private slots: void onAppsUpdated(QList apps); + void onError(QString msg); void onLanguageChanged(); void onPreferencesChanged(); diff --git a/client/gui/translations/ws_desktop_ar.ts b/client/gui/translations/ws_desktop_ar.ts index ab80bf0c..c6e8f50f 100644 --- a/client/gui/translations/ws_desktop_ar.ts +++ b/client/gui/translations/ws_desktop_ar.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. عنوان IP هذا أو النطاق محجوز بواسطة Windscribe ولا يمكن تغييره. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + هناك عدد كبير جدا من عناوين IP أو أسماء المضيفين في القائمة. يرجى إزالة بعضها قبل إضافة المزيد. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first يرجى تسجيل الدخول لتعديل قواعد الانقسام النفقي. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + هناك الكثير من التطبيقات في القائمة. يرجى إزالة بعضها قبل إضافة المزيد. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_cs.ts b/client/gui/translations/ws_desktop_cs.ts index 8000c42c..77887a14 100644 --- a/client/gui/translations/ws_desktop_cs.ts +++ b/client/gui/translations/ws_desktop_cs.ts @@ -1849,6 +1849,10 @@ Nejprve se připojte k síti This IP address or range is reserved by Windscribe and can not be changed. Tato IP adresa nebo rozsah je rezervován společností Windscribe a nelze jej změnit. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + V seznamu je příliš mnoho IP adres nebo názvů hostitelů. Před přidáním dalších některé odstraňte. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Nejprve se připojte k síti Chcete-li změnit pravidla děleného tunelového propojení, přihlaste se. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + V seznamu je příliš mnoho aplikací. Před přidáním dalších některé odstraňte. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_de.ts b/client/gui/translations/ws_desktop_de.ts index 01de7f18..60372ab6 100644 --- a/client/gui/translations/ws_desktop_de.ts +++ b/client/gui/translations/ws_desktop_de.ts @@ -1849,6 +1849,10 @@ Zuerst eine Verbindung mit einem Netzwerk herstellen This IP address or range is reserved by Windscribe and can not be changed. Diese IP-Adresse oder dieser IP-Bereich ist von Windscribe reserviert und kann nicht geändert werden. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + Es gibt zu viele IPs oder Hostnamen in der Liste. Bitte entfernen Sie einige, bevor Sie weitere hinzufügen. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Zuerst eine Verbindung mit einem Netzwerk herstellen Bitte melden Sie sich an, um die Split-Tunneling-Regeln zu ändern. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + Es gibt zu viele Apps in der Liste. Bitte entfernen Sie einige, bevor Sie weitere hinzufügen. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_en.ts b/client/gui/translations/ws_desktop_en.ts index 3df55f28..4a2f5063 100644 --- a/client/gui/translations/ws_desktop_en.ts +++ b/client/gui/translations/ws_desktop_en.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. This IP address or range is reserved by Windscribe and can not be changed. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + There are too many IPs or hostnames in the list. Please remove some before adding more. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first Please log in to modify split tunneling rules. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + There are too many apps in the list. Please remove some before adding more. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_es.ts b/client/gui/translations/ws_desktop_es.ts index 839db358..994216c8 100644 --- a/client/gui/translations/ws_desktop_es.ts +++ b/client/gui/translations/ws_desktop_es.ts @@ -1849,6 +1849,10 @@ Conéctate primero a una red This IP address or range is reserved by Windscribe and can not be changed. Esta dirección IP o rango está reservado por Windscribe y no se puede cambiar. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + Hay demasiadas direcciones IP o nombres de host en la lista. Por favor, elimine algunos antes de añadir más. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Conéctate primero a una red Inicia sesión para modificar las reglas de túnel dividido. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + Hay demasiadas aplicaciones en la lista. Por favor, elimine algunos antes de añadir más. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_fa.ts b/client/gui/translations/ws_desktop_fa.ts index 11e63133..ea6e7907 100644 --- a/client/gui/translations/ws_desktop_fa.ts +++ b/client/gui/translations/ws_desktop_fa.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. این ادرس IP یا محدوده توسط Windscribe رزرو شده است و نمی توان ان را تغییر داد. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + تعداد زیادی اییپ یا نام میزبان در لیست وجود دارد. لطفا قبل از اضافه کردن بیشتر، برخی از انها را حذف کنید. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first لطفا برای تغییر قوانین شکافتن تونل وارد شوید. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + برنامه های زیادی در لیست وجود دارد. لطفا قبل از اضافه کردن بیشتر، برخی از انها را حذف کنید. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_fr.ts b/client/gui/translations/ws_desktop_fr.ts index 76c2af50..6ae60cdc 100644 --- a/client/gui/translations/ws_desktop_fr.ts +++ b/client/gui/translations/ws_desktop_fr.ts @@ -1849,6 +1849,10 @@ Se connecter d’abord à un réseau This IP address or range is reserved by Windscribe and can not be changed. Cette adresse IP ou plage est réservée par Windscribe et ne peut être modifiée. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + Il y a trop d’adresses IP ou de noms d’hôte dans la liste. Veuillez en retirer quelques-uns avant d’en ajouter d’autres. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Se connecter d’abord à un réseau Veuillez vous connecter pour modifier les règles de split tunneling. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + Il y a trop d’applications dans la liste. Veuillez en retirer quelques-uns avant d’en ajouter d’autres. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_hi.ts b/client/gui/translations/ws_desktop_hi.ts index fad80f39..c5ded4d0 100644 --- a/client/gui/translations/ws_desktop_hi.ts +++ b/client/gui/translations/ws_desktop_hi.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. यह IP पता या श्रेणी Windscribe द्वारा आरक्षित है और इसे बदला नहीं जा सकता. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + सूची में बहुत सारे आईपी या होस्टनाम हैं। कृपया अधिक जोड़ने से पहले कुछ हटा दें। + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first विभाजित टनलिंग नियमों को संशोधित करने के लिए कृपया लॉग इन करें. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + सूची में बहुत सारे ऐप्स हैं। कृपया अधिक जोड़ने से पहले कुछ हटा दें। + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_id.ts b/client/gui/translations/ws_desktop_id.ts index a00e4f5e..6be9f88f 100644 --- a/client/gui/translations/ws_desktop_id.ts +++ b/client/gui/translations/ws_desktop_id.ts @@ -1849,6 +1849,10 @@ Menyambungkan ke jaringan terlebih dahulu This IP address or range is reserved by Windscribe and can not be changed. Alamat atau rentang IP ini dicadangkan oleh Windscribe dan tidak dapat diubah. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + Ada terlalu banyak IP atau nama host dalam daftar. Harap hapus beberapa sebelum menambahkan lebih banyak. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Menyambungkan ke jaringan terlebih dahulu Silakan masuk untuk mengubah aturan tunneling terpisah. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + Ada terlalu banyak aplikasi dalam daftar. Harap hapus beberapa sebelum menambahkan lebih banyak. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_it.ts b/client/gui/translations/ws_desktop_it.ts index d6e4a4d7..dfbb654b 100644 --- a/client/gui/translations/ws_desktop_it.ts +++ b/client/gui/translations/ws_desktop_it.ts @@ -1849,6 +1849,10 @@ Connettersi prima a una rete This IP address or range is reserved by Windscribe and can not be changed. Questo indirizzo IP o intervallo è riservato da Windscribe e non può essere modificato. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + Ci sono troppi IP o nomi host nell'elenco. Si prega di rimuoverne alcuni prima di aggiungerne altri. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connettersi prima a una rete Effettua il login per modificare le regole di split tunneling. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + Ci sono troppe app nell'elenco. Si prega di rimuoverne alcuni prima di aggiungerne altri. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_ja.ts b/client/gui/translations/ws_desktop_ja.ts index 26ae114d..191f3de9 100644 --- a/client/gui/translations/ws_desktop_ja.ts +++ b/client/gui/translations/ws_desktop_ja.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. この IP アドレスまたは範囲は Windscribe によって予約されており、変更することはできません。 + + There are too many IPs or hostnames in the list. Please remove some before adding more. + リスト内の IP またはホスト名が多すぎます。さらに追加する前に、いくつかを削除してください。 + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first スプリットトンネリングルールを変更するにはログインしてください。 + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + リストにアプリが多すぎます。さらに追加する前に、いくつかを削除してください。 + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_ko.ts b/client/gui/translations/ws_desktop_ko.ts index 79ef5446..47a96db6 100644 --- a/client/gui/translations/ws_desktop_ko.ts +++ b/client/gui/translations/ws_desktop_ko.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. 이 IP 주소 또는 범위는 Windscribe에 의해 예약되며 변경할 수 없습니다. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + 목록에 IP 또는 호스트 이름이 너무 많습니다. 더 추가하기 전에 일부를 제거하십시오. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first 분할 터널링 규칙을 수정하려면 로그인하십시오. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + 목록에 앱이 너무 많습니다. 더 추가하기 전에 일부를 제거하십시오. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_pl.ts b/client/gui/translations/ws_desktop_pl.ts index c8b2622b..1902568c 100644 --- a/client/gui/translations/ws_desktop_pl.ts +++ b/client/gui/translations/ws_desktop_pl.ts @@ -1849,6 +1849,10 @@ Najpierw połącz się z siecią This IP address or range is reserved by Windscribe and can not be changed. Ten adres IP lub zakres jest zarezerwowany przez Windscribe i nie można go zmienić. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + Na liście znajduje się zbyt wiele adresów IP lub nazw hostów. Usuń niektóre z nich, zanim dodasz kolejne. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Najpierw połącz się z siecią Zaloguj się, aby zmodyfikować reguły dzielonego tunelowania. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + Na liście jest zbyt wiele aplikacji. Usuń niektóre z nich, zanim dodasz kolejne. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_pt.ts b/client/gui/translations/ws_desktop_pt.ts index 0f9c8049..5c14ce51 100644 --- a/client/gui/translations/ws_desktop_pt.ts +++ b/client/gui/translations/ws_desktop_pt.ts @@ -1849,6 +1849,10 @@ Conecte-se a uma rede primeiro This IP address or range is reserved by Windscribe and can not be changed. Este endereço IP ou intervalo é reservado pela Windscribe e não pode ser alterado. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + Há muitos IPs ou nomes de host na lista. Por favor, remova alguns antes de adicionar mais. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Conecte-se a uma rede primeiro Faça login para modificar as regras de tunelamento dividido. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + Há muitos aplicativos na lista. Por favor, remova alguns antes de adicionar mais. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_ru.ts b/client/gui/translations/ws_desktop_ru.ts index 3c513bf2..6734c239 100644 --- a/client/gui/translations/ws_desktop_ru.ts +++ b/client/gui/translations/ws_desktop_ru.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. Этот IP-адрес или диапазон зарезервирован Windscribe и не может быть изменен. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + В списке слишком много IP-адресов или имен хостов. Пожалуйста, удалите некоторые из них, прежде чем добавлять новые. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first Пожалуйста, войдите в систему, чтобы изменить правила раздельного туннелирования. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + В списке слишком много приложений. Пожалуйста, удалите некоторые из них, прежде чем добавлять новые. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_tr.ts b/client/gui/translations/ws_desktop_tr.ts index 62323348..228fbbad 100644 --- a/client/gui/translations/ws_desktop_tr.ts +++ b/client/gui/translations/ws_desktop_tr.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. Bu IP adresi veya aralığı Windscribe tarafından ayrılmıştır ve değiştirilemez. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + Listede çok fazla IP veya ana bilgisayar adı var. Lütfen daha fazlasını eklemeden önce bazılarını kaldırın. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first Bölünmüş tünelleme kurallarını değiştirmek için lütfen oturum açın. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + Listede çok fazla uygulama var. Lütfen daha fazlasını eklemeden önce bazılarını kaldırın. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_uk.ts b/client/gui/translations/ws_desktop_uk.ts index 16b2b24e..524ca66e 100644 --- a/client/gui/translations/ws_desktop_uk.ts +++ b/client/gui/translations/ws_desktop_uk.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. Ця IP-адреса або діапазон зарезервовані Windscribe і не можуть бути змінені. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + У списку забагато IP-адрес або імен хостів. Будь ласка, видаліть деякі з них, перш ніж додавати нові. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first Будь ласка, увійдіть в систему, щоб змінити правила роздільного тунелювання. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + У списку занадто багато додатків. Будь ласка, видаліть деякі з них, перш ніж додавати нові. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_vi.ts b/client/gui/translations/ws_desktop_vi.ts index fc8e7721..67bfb066 100644 --- a/client/gui/translations/ws_desktop_vi.ts +++ b/client/gui/translations/ws_desktop_vi.ts @@ -1849,6 +1849,10 @@ Kết nối với mạng trước This IP address or range is reserved by Windscribe and can not be changed. Địa chỉ IP hoặc dải tần này được Windscribe dành riêng và không thể thay đổi. + + There are too many IPs or hostnames in the list. Please remove some before adding more. + Có quá nhiều IP hoặc tên máy chủ trong danh sách. Vui lòng xóa một số trước khi thêm nhiều hơn. + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Kết nối với mạng trước Vui lòng đăng nhập để sửa đổi các quy tắc tạo đường hầm phân chia. + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + Có quá nhiều ứng dụng trong danh sách. Vui lòng xóa một số trước khi thêm nhiều hơn. + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_zh-CN.ts b/client/gui/translations/ws_desktop_zh-CN.ts index bbedb0a4..0a93eb04 100644 --- a/client/gui/translations/ws_desktop_zh-CN.ts +++ b/client/gui/translations/ws_desktop_zh-CN.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. 此IP地址或范围由Windscribe保留,无法更改。 + + There are too many IPs or hostnames in the list. Please remove some before adding more. + 列表中的 IP 或主机名过多。在添加更多之前,请删除一些。 + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first 请登录以修改拆分隧道规则。 + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + 列表中的应用太多。在添加更多之前,请删除一些。 + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/client/gui/translations/ws_desktop_zh-TW.ts b/client/gui/translations/ws_desktop_zh-TW.ts index aefb53b7..097d2460 100644 --- a/client/gui/translations/ws_desktop_zh-TW.ts +++ b/client/gui/translations/ws_desktop_zh-TW.ts @@ -1849,6 +1849,10 @@ Connect to a network first This IP address or range is reserved by Windscribe and can not be changed. 此IP位址或範圍由Windscribe保留,無法更改。 + + There are too many IPs or hostnames in the list. Please remove some before adding more. + 清單中的IP或主機名過多。在添加更多之前,請刪除一些。 + PreferencesWindow::SplitTunnelingAddressesWindowItem @@ -1865,6 +1869,13 @@ Connect to a network first 請登錄以修改分割隧道規則。 + + PreferencesWindow::SplitTunnelingAppsGroup + + There are too many apps in the list. Please remove some before adding more. + 清單中的應用太多。在添加更多之前,請刪除一些。 + + PreferencesWindow::SplitTunnelingAppsItem diff --git a/installer/common/installer_shim.h b/installer/common/installer_shim.h index 30af492f..bce6e750 100644 --- a/installer/common/installer_shim.h +++ b/installer/common/installer_shim.h @@ -7,7 +7,7 @@ class InstallerShim { public: enum INSTALLER_STATE { STATE_INIT, STATE_EXTRACTING, STATE_CANCELED, STATE_FINISHED, STATE_ERROR, STATE_LAUNCHED }; - enum INSTALLER_ERROR { ERROR_PERMISSION, ERROR_KILL, ERROR_CONNECT_HELPER, ERROR_DELETE, ERROR_OTHER }; + enum INSTALLER_ERROR { ERROR_PERMISSION, ERROR_KILL, ERROR_CONNECT_HELPER, ERROR_DELETE, ERROR_UNINSTALL, ERROR_OTHER }; static InstallerShim &instance() { diff --git a/installer/common/mainwindow.cpp b/installer/common/mainwindow.cpp index eef2c235..8c824397 100644 --- a/installer/common/mainwindow.cpp +++ b/installer/common/mainwindow.cpp @@ -190,6 +190,11 @@ void MainWindow::onInstallerCallback() 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)); + } 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)); } else { QMetaObject::invokeMethod(this, "showError", Qt::QueuedConnection, Q_ARG(QString, tr("Installation failed")), diff --git a/installer/common/translations/windscribe_installer_ar.ts b/installer/common/translations/windscribe_installer_ar.ts index c43ded48..b3f8588e 100644 --- a/installer/common/translations/windscribe_installer_ar.ts +++ b/installer/common/translations/windscribe_installer_ar.ts @@ -84,6 +84,10 @@ You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. ليس لديك أذونات كافية لتشغيل هذا التطبيق. الامتيازات الإدارية مطلوبة لتثبيت Windscribe. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + تعذر العثور على برنامج إلغاء التثبيت للتثبيت الحالي ل Windscribe. الرجاء إلغاء تثبيت التطبيق يدويا والمحاولة مرة أخرى. + QObject diff --git a/installer/common/translations/windscribe_installer_cs.ts b/installer/common/translations/windscribe_installer_cs.ts index 9ebc2b07..139e5aa6 100644 --- a/installer/common/translations/windscribe_installer_cs.ts +++ b/installer/common/translations/windscribe_installer_cs.ts @@ -84,6 +84,10 @@ 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. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Odinstalační program pro stávající instalaci aplikace Windscribe nebyl nalezen. Odinstalujte aplikaci ručně a zkuste to znovu. + QObject diff --git a/installer/common/translations/windscribe_installer_de.ts b/installer/common/translations/windscribe_installer_de.ts index a426541a..8dd76be6 100644 --- a/installer/common/translations/windscribe_installer_de.ts +++ b/installer/common/translations/windscribe_installer_de.ts @@ -84,6 +84,10 @@ 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. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Das Deinstallationsprogramm für die bestehende Installation von Windscribe konnte nicht gefunden werden. Bitte deinstallieren Sie die Anwendung manuell und versuchen Sie es erneut. + QObject diff --git a/installer/common/translations/windscribe_installer_en.ts b/installer/common/translations/windscribe_installer_en.ts index d40856ce..58492f8b 100644 --- a/installer/common/translations/windscribe_installer_en.ts +++ b/installer/common/translations/windscribe_installer_en.ts @@ -84,6 +84,10 @@ 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. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + QObject diff --git a/installer/common/translations/windscribe_installer_es.ts b/installer/common/translations/windscribe_installer_es.ts index 0107d9d2..197079bf 100644 --- a/installer/common/translations/windscribe_installer_es.ts +++ b/installer/common/translations/windscribe_installer_es.ts @@ -84,6 +84,10 @@ 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. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + No se pudo encontrar el desinstalador de la instalación existente de Windscribe. Desinstale la aplicación manualmente e inténtelo de nuevo. + QObject diff --git a/installer/common/translations/windscribe_installer_fa.ts b/installer/common/translations/windscribe_installer_fa.ts index 5f4aeee0..7148fd33 100644 --- a/installer/common/translations/windscribe_installer_fa.ts +++ b/installer/common/translations/windscribe_installer_fa.ts @@ -84,6 +84,10 @@ You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. شما مجوز کافی برای اجرای این برنامه را ندارید. امتیازات اداری برای نصب Windscribe مورد نیاز است. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + حذف نصب برای نصب موجود Windscribe یافت نشد. لطفا برنامه را به صورت دستی حذف کنید و دوباره امتحان کنید. + QObject diff --git a/installer/common/translations/windscribe_installer_fr.ts b/installer/common/translations/windscribe_installer_fr.ts index 6c1375f0..ae33ca8f 100644 --- a/installer/common/translations/windscribe_installer_fr.ts +++ b/installer/common/translations/windscribe_installer_fr.ts @@ -84,6 +84,10 @@ 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. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Le programme de désinstallation de l’installation existante de Windscribe est introuvable. Veuillez désinstaller l’application manuellement et réessayer. + QObject diff --git a/installer/common/translations/windscribe_installer_hi.ts b/installer/common/translations/windscribe_installer_hi.ts index 608444de..82467f35 100644 --- a/installer/common/translations/windscribe_installer_hi.ts +++ b/installer/common/translations/windscribe_installer_hi.ts @@ -84,6 +84,10 @@ You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. आपके पास इस अनुप्रयोग को चलाने के लिए पर्याप्त अनुमतियाँ नहीं हैं. विंडसाइड स्थापित करने के लिए व्यवस्थापकीय विशेषाधिकारों की आवश्यकता होती है. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Windscribe की मौजूदा स्थापना के लिए अनइंस्टालर नहीं मिल सका। कृपया अनुप्रयोग की स्थापना मैन्युअल रूप से रद्द करें और पुन: प्रयास करें. + QObject diff --git a/installer/common/translations/windscribe_installer_id.ts b/installer/common/translations/windscribe_installer_id.ts index 8d438e07..ac955f4d 100644 --- a/installer/common/translations/windscribe_installer_id.ts +++ b/installer/common/translations/windscribe_installer_id.ts @@ -84,6 +84,10 @@ 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. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Uninstaller untuk instalasi Windscribe yang ada tidak dapat ditemukan. Hapus instalan aplikasi secara manual dan coba lagi. + QObject diff --git a/installer/common/translations/windscribe_installer_it.ts b/installer/common/translations/windscribe_installer_it.ts index 13aaf183..2bf87cd6 100644 --- a/installer/common/translations/windscribe_installer_it.ts +++ b/installer/common/translations/windscribe_installer_it.ts @@ -84,6 +84,10 @@ 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. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Non è stato possibile trovare il programma di disinstallazione per l'installazione esistente di Windscribe. Disinstallare l'applicazione manualmente e riprovare. + QObject diff --git a/installer/common/translations/windscribe_installer_ja.ts b/installer/common/translations/windscribe_installer_ja.ts index 8e7f77f3..59e56745 100644 --- a/installer/common/translations/windscribe_installer_ja.ts +++ b/installer/common/translations/windscribe_installer_ja.ts @@ -84,6 +84,10 @@ You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. このアプリケーションを実行するための十分なアクセス許可がありません。Windscribeをインストールするには管理者権限が必要です。 + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Windscribeの既存のインストールのアンインストーラーが見つかりませんでした。アプリケーションを手動でアンインストールして、もう一度やり直してください。 + QObject diff --git a/installer/common/translations/windscribe_installer_ko.ts b/installer/common/translations/windscribe_installer_ko.ts index 20248350..bb3c24a1 100644 --- a/installer/common/translations/windscribe_installer_ko.ts +++ b/installer/common/translations/windscribe_installer_ko.ts @@ -84,6 +84,10 @@ You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. 이 응용 프로그램을 실행할 수 있는 충분한 권한이 없습니다. Windscribe를 설치하려면 관리자 권한이 필요합니다. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Windscribe의 기존 설치에 대한 제거 프로그램을 찾을 수 없습니다. 응용 프로그램을 수동으로 제거하고 다시 시도하십시오. + QObject diff --git a/installer/common/translations/windscribe_installer_pl.ts b/installer/common/translations/windscribe_installer_pl.ts index d76b1f46..6b816fce 100644 --- a/installer/common/translations/windscribe_installer_pl.ts +++ b/installer/common/translations/windscribe_installer_pl.ts @@ -84,6 +84,10 @@ You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. Nie masz wystarczających uprawnień, aby uruchomić tę aplikację. Wymagane są uprawnienia administratora, aby zainstalować Windscribe. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Nie można odnaleźć deinstalatora istniejącej instalacji Windscribe. Odinstaluj aplikację ręcznie i spróbuj ponownie. + QObject diff --git a/installer/common/translations/windscribe_installer_pt.ts b/installer/common/translations/windscribe_installer_pt.ts index 8fd74775..ba78d496 100644 --- a/installer/common/translations/windscribe_installer_pt.ts +++ b/installer/common/translations/windscribe_installer_pt.ts @@ -84,6 +84,10 @@ 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. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + O desinstalador para a instalação existente do Windscribe não pôde ser encontrado. Desinstale o aplicativo manualmente e tente novamente. + QObject diff --git a/installer/common/translations/windscribe_installer_ru.ts b/installer/common/translations/windscribe_installer_ru.ts index 12ff983a..ffceadd3 100644 --- a/installer/common/translations/windscribe_installer_ru.ts +++ b/installer/common/translations/windscribe_installer_ru.ts @@ -84,6 +84,10 @@ You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. У вас недостаточно разрешений для запуска этого приложения. Для установки Windscribe требуются права администратора. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Не удалось найти деинсталлятор для существующей установки Windscribe. Удалите приложение вручную и повторите попытку. + QObject diff --git a/installer/common/translations/windscribe_installer_tr.ts b/installer/common/translations/windscribe_installer_tr.ts index 28593dee..478f7088 100644 --- a/installer/common/translations/windscribe_installer_tr.ts +++ b/installer/common/translations/windscribe_installer_tr.ts @@ -84,6 +84,10 @@ 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. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Windscribe'ın mevcut kurulumu için kaldırıcı bulunamadı. Lütfen uygulamayı manuel olarak kaldırın ve tekrar deneyin. + QObject diff --git a/installer/common/translations/windscribe_installer_uk.ts b/installer/common/translations/windscribe_installer_uk.ts index a3f563f4..e5ea7fb7 100644 --- a/installer/common/translations/windscribe_installer_uk.ts +++ b/installer/common/translations/windscribe_installer_uk.ts @@ -84,6 +84,10 @@ You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. У вас недостатньо дозволів для запуску цієї програми. Для встановлення Windscribe потрібні адміністративні привілеї. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Не вдалося знайти деінсталятор для існуючої інсталяції Windscribe. Будь ласка, видаліть програму вручну та повторіть спробу. + QObject diff --git a/installer/common/translations/windscribe_installer_vi.ts b/installer/common/translations/windscribe_installer_vi.ts index 7505a988..7cc927a0 100644 --- a/installer/common/translations/windscribe_installer_vi.ts +++ b/installer/common/translations/windscribe_installer_vi.ts @@ -84,6 +84,10 @@ 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. + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + Không thể tìm thấy trình gỡ cài đặt cho cài đặt Windscribe hiện có. Vui lòng gỡ cài đặt ứng dụng theo cách thủ công và thử lại. + QObject diff --git a/installer/common/translations/windscribe_installer_zh-CN.ts b/installer/common/translations/windscribe_installer_zh-CN.ts index 4d99ef23..0769344e 100644 --- a/installer/common/translations/windscribe_installer_zh-CN.ts +++ b/installer/common/translations/windscribe_installer_zh-CN.ts @@ -84,6 +84,10 @@ You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. 您没有足够的权限来运行此应用程序。安装 Windscribe 需要管理权限。 + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + 无法找到现有安装的 Windscribe 的卸载程序。请手动卸载应用程序,然后重试。 + QObject diff --git a/installer/common/translations/windscribe_installer_zh-TW.ts b/installer/common/translations/windscribe_installer_zh-TW.ts index 8cbab8a9..daca2e4a 100644 --- a/installer/common/translations/windscribe_installer_zh-TW.ts +++ b/installer/common/translations/windscribe_installer_zh-TW.ts @@ -84,6 +84,10 @@ You don't have sufficient permissions to run this application. Administrative privileges are required to install Windscribe. 您沒有足夠的權限來執行此應用程式。安裝Windscribe需要管理許可權。 + + The uninstaller for the existing installation of Windscribe could not be found. Please uninstall the application manually and try again. + 無法找到現有安裝的Windscribe的卸載程式。請手動卸載應用程式,然後重試。 + QObject diff --git a/installer/linux/arch_package/PKGBUILD b/installer/linux/arch_package/PKGBUILD index 6eb2a33c..0eefa9f0 100644 --- a/installer/linux/arch_package/PKGBUILD +++ b/installer/linux/arch_package/PKGBUILD @@ -10,7 +10,8 @@ url="https://windscribe.com/download" license=('GPL2') depends=('nftables' 'c-ares' 'freetype2' 'hicolor-icon-theme' 'systemd' 'glibc>=2.28' 'glib2' 'zlib' 'gcc-libs' 'dbus' 'libglvnd' 'fontconfig' 'libx11' 'libxkbcommon' 'libxcb' 'xcb-util-wm' 'xcb-util-image' 'xcb-util-keysyms' - 'xcb-util-renderutil' 'sudo' 'shadow' 'xcb-util-cursor' 'networkmanager' 'procps-ng' 'polkit' 'iproute2') + 'xcb-util-renderutil' 'sudo' 'shadow' 'xcb-util-cursor' 'networkmanager' 'procps-ng' 'polkit' 'iproute2' + 'iputils') conflicts=('windscribe-cli') provides=('windscribe') options=('!strip' '!emptydirs') diff --git a/installer/linux/debian_package/DEBIAN/control b/installer/linux/debian_package/DEBIAN/control index c12e7bf8..ee911958 100644 --- a/installer/linux/debian_package/DEBIAN/control +++ b/installer/linux/debian_package/DEBIAN/control @@ -2,7 +2,7 @@ Package: windscribe Version: 2.8-0 Section: misc Architecture: amd64 -Depends: bash, iptables, libc6 (>= 2.28), libstdc++6, libglib2.0-0, libdbus-1-3, libsystemd0, zlib1g, policykit-1, libx11-6, libegl1, libgl1, libfreetype6, libglvnd0, libxkbcommon0, libfontconfig1, libxcb1, libx11-xcb1, libx11-6, libxkbcommon-x11-0, libxcb-icccm4, libxcb-image0, libxcb-keysyms1, libxcb-render-util0, sudo, passwd, net-tools, libopengl0, libxcb-cursor0, procps, policykit-1, pkexec | policykit-1 (<< 0.105-33), iproute2 +Depends: bash, iptables, libc6 (>= 2.28), libstdc++6, libglib2.0-0, libdbus-1-3, libsystemd0, zlib1g, policykit-1, libx11-6, libegl1, libgl1, libfreetype6, libglvnd0, libxkbcommon0, libfontconfig1, libxcb1, libx11-xcb1, libx11-6, libxkbcommon-x11-0, libxcb-icccm4, libxcb-image0, libxcb-keysyms1, libxcb-render-util0, sudo, passwd, net-tools, libopengl0, libxcb-cursor0, procps, policykit-1, pkexec | policykit-1 (<< 0.105-33), iproute2, iputils-ping Maintainer: Windscribe Limited Description: Windscribe Windscribe Client. diff --git a/installer/linux/rpm_package/SPECS/windscribe_rpm.spec b/installer/linux/rpm_package/SPECS/windscribe_rpm.spec index 4f891d17..e7e6ac97 100644 --- a/installer/linux/rpm_package/SPECS/windscribe_rpm.spec +++ b/installer/linux/rpm_package/SPECS/windscribe_rpm.spec @@ -43,6 +43,7 @@ Requires: shadow-utils Requires: procps-ng Requires: polkit Requires: iproute +Requires: iputils %description Windscribe client. diff --git a/installer/mac/installer/installer/base_installer.h b/installer/mac/installer/installer/base_installer.h index 60a53e64..78899e8e 100644 --- a/installer/mac/installer/installer/base_installer.h +++ b/installer/mac/installer/installer/base_installer.h @@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN enum INSTALLER_CURRENT_STATE { STATE_INIT, STATE_EXTRACTING, STATE_CANCELED, STATE_FINISHED, STATE_ERROR, STATE_LAUNCHED }; -enum INSTALLER_ERROR { ERROR_PERMISSION, ERROR_KILL, ERROR_CONNECT_HELPER, ERROR_DELETE, ERROR_OTHER }; +enum INSTALLER_ERROR { ERROR_PERMISSION, ERROR_KILL, ERROR_CONNECT_HELPER, ERROR_DELETE, ERROR_UNINSTALL, ERROR_OTHER }; @interface BaseInstaller : NSObject { diff --git a/installer/windows/additional_files/splittunnel/arm64/windscribesplittunnel.cat b/installer/windows/additional_files/splittunnel/arm64/windscribesplittunnel.cat index 583eef56..186ece82 100644 Binary files a/installer/windows/additional_files/splittunnel/arm64/windscribesplittunnel.cat and b/installer/windows/additional_files/splittunnel/arm64/windscribesplittunnel.cat differ diff --git a/installer/windows/additional_files/splittunnel/arm64/windscribesplittunnel.sys b/installer/windows/additional_files/splittunnel/arm64/windscribesplittunnel.sys index 2994b954..04615c35 100644 Binary files a/installer/windows/additional_files/splittunnel/arm64/windscribesplittunnel.sys and b/installer/windows/additional_files/splittunnel/arm64/windscribesplittunnel.sys differ diff --git a/installer/windows/installer/installer/blocks/files.cpp b/installer/windows/installer/installer/blocks/files.cpp index 9e6391c8..7c03b76b 100644 --- a/installer/windows/installer/installer/blocks/files.cpp +++ b/installer/windows/installer/installer/blocks/files.cpp @@ -143,6 +143,7 @@ int Files::moveFiles() bool Files::copyLibs() { std::error_code ec; + std::filesystem::copy_options opts = std::filesystem::copy_options::overwrite_existing; const filesystem::path installPath = installPath_; const wstring exeStr = getExePath(); @@ -155,7 +156,7 @@ bool Files::copyLibs() // Copy DLLs for (const auto &entry : filesystem::directory_iterator(exePath)) { if (entry.is_regular_file() && entry.path().extension() == ".dll") { - filesystem::copy_file(entry.path(), installPath / entry.path().filename(), ec); + filesystem::copy_file(entry.path(), installPath / entry.path().filename(), opts, ec); if (ec) { Log::instance().out(L"Could not copy DLL %ls: %hs", entry.path().wstring().c_str(), ec.message().c_str()); return false; @@ -166,7 +167,7 @@ bool Files::copyLibs() // Copy Qt plugins std::wstring paths[3] = { L"imageformats", L"platforms", L"styles" }; for (auto p : paths) { - filesystem::copy(exePath / p, installPath / p, ec); + filesystem::copy(exePath / p, installPath / p, opts, ec); if (ec) { Log::instance().out(L"Could not copy %ls: %hs", p.c_str(), ec.message().c_str()); return false; diff --git a/installer/windows/installer/installer/blocks/uninstallprev.cpp b/installer/windows/installer/installer/blocks/uninstallprev.cpp index 1f018434..7e9cfc0c 100644 --- a/installer/windows/installer/installer/blocks/uninstallprev.cpp +++ b/installer/windows/installer/installer/blocks/uninstallprev.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -85,8 +86,26 @@ int UninstallPrev::executeStep() reg.setValue("userId", ""); } - if (!uninstallOldVersion(uninstallString)) { - return -1; + DWORD lastError = 0; + if (!uninstallOldVersion(uninstallString, lastError)) { + Log::instance().out("UninstallPrev::executeStep: uninstallOldVersion failed: %lu", lastError); + if (lastError != 2) { // Any error other than "Not found" + return -1; + } + + // Uninstall failed because the uninstaller doesn't exist. + if (!isPrevInstall64Bit()) { + // A little hacky to pass a special code here, but this is the only way to indicate to caller. + // If the previous version is using the 32-bit hive, don't try to use the current (64-bit) uninstaller. + return -2; + } + + if (!extractUninstaller()) { + Log::instance().out("UninstallPrev::executeStep: could not extract uninstaller."); + return -1; + } + Log::instance().out("UninstallPrev::executeStep: successfully extracted uninstaller, trying again."); + return 65; } } return 100; @@ -113,12 +132,23 @@ wstring UninstallPrev::getUninstallString() return uninstallString; } -bool UninstallPrev::uninstallOldVersion(const wstring &uninstallString) +bool UninstallPrev::isPrevInstall64Bit() +{ + QSettings reg(QString::fromStdWString(ApplicationInfo::uninstallerRegistryKey()), QSettings::NativeFormat); + if (reg.contains(L"UninstallString")) { + return true; + } + return false; +} + +bool UninstallPrev::uninstallOldVersion(const wstring &uninstallString, DWORD &lastError) { const wstring sUnInstallString = removeQuotes(uninstallString); + DWORD error = 0; - const auto res = Utils::InstExec(sUnInstallString, L"/VERYSILENT", INFINITE, SW_HIDE); + const auto res = Utils::InstExec(sUnInstallString, L"/VERYSILENT", INFINITE, SW_HIDE, L"", &error); if (!res.has_value() || res.value() == MAXDWORD) { + lastError = error; return false; } @@ -193,3 +223,51 @@ void UninstallPrev::stopService() Log::instance().out("UninstallPrev::stopService %s (%lu)", ex.what(), ex.code().value()); } } + +bool UninstallPrev::extractUninstaller() +{ + Log::instance().out(L"Extracting uninstaller from the archive"); + + archive_.reset(new Archive(L"Windscribe")); + + std::list fileList; + SRes res = archive_->fileList(fileList); + if (res != SZ_OK) { + Log::instance().out(L"Failed to extract file list from archive."); + return false; + } + + int index = 0; + auto it = fileList.begin(); + while(index < fileList.size()) { + // Note the trailing 's' on the std::wstring literal, this is necessary since the file string has an embedded null byte. + if (*it == std::wstring(L"uninstall.exe\0"s)) { + break; + } + index++; + it = std::next(it); + } + if (index >= fileList.size()) { + Log::instance().out(L"Failed to find uninstall.exe in the archive."); + return false; + } + + std::list pathList; + std::wstring extractionPath = Path::extractDir(removeQuotes(getUninstallString())); + for (auto it = fileList.cbegin(); it != fileList.cend(); it++) { + // We're only extracting uninstall.exe, other paths are irrelevant + pathList.push_back(extractionPath); + } + + archive_->calcTotal(fileList, pathList); + + res = archive_->extractionFile(index); + if (res != SZ_OK) { + archive_->finish(); + Log::instance().out(L"Failed to extract from archive."); + return false; + } + archive_->finish(); + + return true; +} \ No newline at end of file diff --git a/installer/windows/installer/installer/blocks/uninstallprev.h b/installer/windows/installer/installer/blocks/uninstallprev.h index 0b3abade..8783f056 100644 --- a/installer/windows/installer/installer/blocks/uninstallprev.h +++ b/installer/windows/installer/installer/blocks/uninstallprev.h @@ -1,5 +1,9 @@ #pragma once +#include +#include + +#include "archive/archive.h" #include "../iinstall_block.h" class UninstallPrev : public IInstallBlock @@ -11,9 +15,12 @@ class UninstallPrev : public IInstallBlock private: int state_; bool isFactoryReset_; + std::unique_ptr archive_; std::wstring getUninstallString(); - bool uninstallOldVersion(const std::wstring &uninstallString); + bool uninstallOldVersion(const std::wstring &uninstallString, DWORD &lastError); + bool isPrevInstall64Bit(); + bool extractUninstaller(); std::wstring removeQuotes(const std::wstring &str); void doFactoryReset(); void stopService(); diff --git a/installer/windows/installer/installer/installer.cpp b/installer/windows/installer/installer/installer.cpp index a85ed47a..090ed541 100644 --- a/installer/windows/installer/installer/installer.cpp +++ b/installer/windows/installer/installer/installer.cpp @@ -97,7 +97,11 @@ void Installer::executionImpl() // error from block? else if (progressOfBlock < 0) { progress_ = overallProgress; - error_ = ERROR_OTHER; + if (progressOfBlock == -2) { + error_ = ERROR_UNINSTALL; + } else { + error_ = ERROR_OTHER; + } state_ = STATE_ERROR; callback_(); Log::instance().out(block->getLastError()); diff --git a/installer/windows/installer/installer/installer_base.h b/installer/windows/installer/installer/installer_base.h index 4415d049..8b70397f 100644 --- a/installer/windows/installer/installer/installer_base.h +++ b/installer/windows/installer/installer/installer_base.h @@ -12,7 +12,7 @@ enum INSTALLER_CURRENT_STATE { STATE_LAUNCHED, }; -enum INSTALLER_ERROR { ERROR_PERMISSION, ERROR_KILL, ERROR_CONNECT_HELPER, ERROR_DELETE, ERROR_OTHER }; +enum INSTALLER_ERROR { ERROR_PERMISSION, ERROR_KILL, ERROR_CONNECT_HELPER, ERROR_DELETE, ERROR_UNINSTALL, ERROR_OTHER }; class InstallerBase { diff --git a/installer/windows/utils/utils.cpp b/installer/windows/utils/utils.cpp index 8912a39d..78d1542a 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) + WORD showWindowFlags, const std::wstring ¤tFolder, DWORD *lastError) { wostringstream stream; if (!appName.empty()) { @@ -74,6 +74,9 @@ optional InstExec(const wstring& appName, const wstring& commandLine, DWO nullptr, lpCurrentDirectory, &si, &pi); if (result == FALSE) { Log::instance().out("Process::InstExec CreateProcess(%ls) failed (%lu)", exec.get(), ::GetLastError()); + if (lastError) { + *lastError = ::GetLastError(); + } return std::nullopt; } @@ -95,6 +98,9 @@ optional InstExec(const wstring& appName, const wstring& commandLine, DWO if (waitResult == WAIT_FAILED) { Log::instance().out("Process::InstExec WaitForSingleObject failed (%lu)", ::GetLastError()); + if (lastError) { + *lastError = ::GetLastError(); + } return std::nullopt; } @@ -107,6 +113,9 @@ optional InstExec(const wstring& appName, const wstring& commandLine, DWO result = ::GetExitCodeProcess(pi.hProcess, &processExitCode); if (result == FALSE) { Log::instance().out("Process::InstExec GetExitCodeProcess failed (%lu)", ::GetLastError()); + if (lastError) { + *lastError = ::GetLastError(); + } return std::nullopt; } diff --git a/installer/windows/utils/utils.h b/installer/windows/utils/utils.h index 5b34db3d..bd6781b0 100644 --- a/installer/windows/utils/utils.h +++ b/installer/windows/utils/utils.h @@ -21,7 +21,8 @@ std::wstring StartMenuProgramsFolder(); // or obtaining its exit code. Returns the process exit code or WAIT_TIMEOUT otherwise. std::optional InstExec(const std::wstring &appName, const std::wstring &commandLine, DWORD timeoutMS, WORD showWindowFlags, - const std::wstring ¤tFolder = std::wstring()); + const std::wstring ¤tFolder = std::wstring(), + DWORD *lastError = nullptr); DWORD getOSBuildNumber(); } diff --git a/libs/wsnet/CMakeLists.txt b/libs/wsnet/CMakeLists.txt index c3456d52..fefb081c 100644 --- a/libs/wsnet/CMakeLists.txt +++ b/libs/wsnet/CMakeLists.txt @@ -22,11 +22,6 @@ project(wsnet include(CMakePackageConfigHelpers) include(GNUInstallDirs) -#include code coverage cmake tool -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;") -include(code-coverage) -add_code_coverage_all_targets() - #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) @@ -86,11 +81,16 @@ set_property(TARGET cert-resources PROPERTY POSITION_INDEPENDENT_CODE ON) add_library(wsnet SHARED ${WS_CPP_PUBLIC_HEADERS}) add_library(wsnet::wsnet ALIAS wsnet) -target_code_coverage(wsnet AUTO ALL) - target_compile_features(wsnet PUBLIC cxx_std_17) -# Set platform specificd dependencies +if (DEFINED IS_BUILD_TESTS) + if (NOT WIN32) + target_compile_options(wsnet PRIVATE -g -O0 --coverage -fprofile-arcs -ftest-coverage) + target_link_options(wsnet PRIVATE --coverage) + endif() +endif() + +# Set platform specific dependencies if (IOS) set (OS_SPECIFIC_LIBRARIES "-framework Foundation") endif() @@ -107,6 +107,8 @@ if (WIN32) _WIN32_WINNT=0x0601 WIN32_LEAN_AND_MEAN PIO_APC_ROUTINE_DEFINED) + + set_target_properties(wsnet PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) endif (WIN32) target_include_directories(wsnet PUBLIC diff --git a/libs/wsnet/src/failover/failoverdata.h b/libs/wsnet/src/failover/failoverdata.h index 6e6c52bb..0a04b8e4 100644 --- a/libs/wsnet/src/failover/failoverdata.h +++ b/libs/wsnet/src/failover/failoverdata.h @@ -31,6 +31,15 @@ class FailoverData { return false; } + // needed for std::set + bool operator<(const FailoverData& rhs) const + { + // ignore ttl_ and startTime_ + std::string uniqId = domain_ + sniDomain_ + echConfig_; + std::string uniqId_rhs = rhs.domain_ + rhs.sniDomain_ + rhs.echConfig_; + return uniqId < uniqId_rhs; + } + private: std::string domain_; std::string sniDomain_; // empty if no SNI spoofing / domain fronting diff --git a/libs/wsnet/src/pingmanager/pingmethod_icmp_posix.cpp b/libs/wsnet/src/pingmanager/pingmethod_icmp_posix.cpp index 0bcc575e..9b74b395 100644 --- a/libs/wsnet/src/pingmanager/pingmethod_icmp_posix.cpp +++ b/libs/wsnet/src/pingmanager/pingmethod_icmp_posix.cpp @@ -25,7 +25,12 @@ void PingMethodIcmp_posix::ping(bool isFromDisconnectedVpnState) using namespace std::placeholders; isFromDisconnectedVpnState_ = isFromDisconnectedVpnState; - 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; + } } void PingMethodIcmp_posix::onProcessFinished(int exitCode, const std::string &output) diff --git a/libs/wsnet/src/pingmanager/pingmethod_icmp_win.cpp b/libs/wsnet/src/pingmanager/pingmethod_icmp_win.cpp index 8a7c1248..fffde558 100644 --- a/libs/wsnet/src/pingmanager/pingmethod_icmp_win.cpp +++ b/libs/wsnet/src/pingmanager/pingmethod_icmp_win.cpp @@ -20,6 +20,8 @@ PingMethodIcmp_win::PingMethodIcmp_win(EventCallbackManager_win &eventCallbackMa PingMethodIcmp_win::~PingMethodIcmp_win() { CloseHandle(hEvent_); + if (icmpFile_ != INVALID_HANDLE_VALUE) + IcmpCloseHandle(icmpFile_); } void PingMethodIcmp_win::ping(bool isFromDisconnectedVpnState) @@ -30,7 +32,7 @@ void PingMethodIcmp_win::ping(bool isFromDisconnectedVpnState) if (icmpFile_ == INVALID_HANDLE_VALUE) { spdlog::info("PingHost_ICMP_win IcmpCreateFile failed, error: {}", ::GetLastError()); assert(false); - //TODO: call callback function? + callFinished(); return; } @@ -41,8 +43,7 @@ void PingMethodIcmp_win::ping(bool isFromDisconnectedVpnState) IN_ADDR ipAddr; if (inet_pton(AF_INET, ip_.c_str(), &ipAddr) != 1) { spdlog::info("PingHost_ICMP_win inet_pton failed, error: {}", ::WSAGetLastError()); - assert(false); - //TODO: call callback function? + callFinished(); return; } @@ -58,13 +59,13 @@ void PingMethodIcmp_win::ping(bool isFromDisconnectedVpnState) if (result != 0) { spdlog::error("PingHost_ICMP_win IcmpSendEcho2 returned unexpected result, error: {}", ::GetLastError()); assert(false); - //TODO: call callback function? + callFinished(); return; } else if (::GetLastError() != ERROR_IO_PENDING) { spdlog::error("PingHost_ICMP_win IcmpSendEcho2 failed, error: {}", ::GetLastError()); assert(false); - //TODO: call callback function? + callFinished(); return; } } diff --git a/libs/wsnet/src/pingmanager/processmanager.cpp b/libs/wsnet/src/pingmanager/processmanager.cpp index 5e176e9c..738db0b2 100644 --- a/libs/wsnet/src/pingmanager/processmanager.cpp +++ b/libs/wsnet/src/pingmanager/processmanager.cpp @@ -22,7 +22,7 @@ ProcessManager::~ProcessManager() } } -void ProcessManager::execute(const std::vector &args, ProcessManagerCallback callback) +bool ProcessManager::execute(const std::vector &args, ProcessManagerCallback callback) { auto processData = std::make_unique(); using namespace std::placeholders; @@ -30,13 +30,14 @@ void ProcessManager::execute(const std::vector &args, ProcessManage std::error_code ec = processData->process->start(args); if (ec) { spdlog::error("Cannot start a process: {}, error: {}", fmt::join(args, " "), ec.value()); - return; + return true; } processData->callback = callback; std::lock_guard locker(mutex_); processes_.push_back(std::move(processData)); condition_.notify_all(); + return false; } void ProcessManager::checkTread() diff --git a/libs/wsnet/src/pingmanager/processmanager.h b/libs/wsnet/src/pingmanager/processmanager.h index f2f469a0..5bd8680c 100644 --- a/libs/wsnet/src/pingmanager/processmanager.h +++ b/libs/wsnet/src/pingmanager/processmanager.h @@ -23,7 +23,7 @@ class ProcessManager ProcessManager(); ~ProcessManager(); - void execute(const std::vector &args, ProcessManagerCallback callback); + bool execute(const std::vector &args, ProcessManagerCallback callback); private: std::mutex mutex_; diff --git a/libs/wsnet/src/serverapi/CMakeLists.txt b/libs/wsnet/src/serverapi/CMakeLists.txt index 38362b60..b3328bec 100644 --- a/libs/wsnet/src/serverapi/CMakeLists.txt +++ b/libs/wsnet/src/serverapi/CMakeLists.txt @@ -1,6 +1,7 @@ target_sources(wsnet PRIVATE baserequest.cpp baserequest.h + failedfailovers.h requestsfactory.cpp requestsfactory.h requestexecuterviafailover.cpp diff --git a/libs/wsnet/src/serverapi/failedfailovers.h b/libs/wsnet/src/serverapi/failedfailovers.h new file mode 100644 index 00000000..91419642 --- /dev/null +++ b/libs/wsnet/src/serverapi/failedfailovers.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include "failoverdata.h" + +namespace wsnet { + +// Helper class used by ServerAPI and RequestExecuterViaFailover to manage failed domains (FailoverData objects) +class FailedFailovers +{ +public: + void add(const FailoverData &failoverData) + { + failedFailovers_.insert(failoverData); + } + bool isContains(const FailoverData &failoverData) const + { + return failedFailovers_.find(failoverData) != failedFailovers_.end(); + } + void clear() + { + failedFailovers_.clear(); + } + +private: + std::set failedFailovers_; +}; + +} // namespace wsnet diff --git a/libs/wsnet/src/serverapi/requestexecuterviafailover.cpp b/libs/wsnet/src/serverapi/requestexecuterviafailover.cpp index 1b2e0965..5520dd5d 100644 --- a/libs/wsnet/src/serverapi/requestexecuterviafailover.cpp +++ b/libs/wsnet/src/serverapi/requestexecuterviafailover.cpp @@ -5,7 +5,8 @@ namespace wsnet { RequestExecuterViaFailover::RequestExecuterViaFailover(WSNetHttpNetworkManager *httpNetworkManager, std::unique_ptr request, std::unique_ptr failover, - bool bIgnoreSslErrors, bool isConnectedVpnState, WSNetAdvancedParameters *advancedParameters, RequestExecuterViaFailoverCallback callback) : + bool bIgnoreSslErrors, bool isConnectedVpnState, WSNetAdvancedParameters *advancedParameters, FailedFailovers &failedFailovers, + RequestExecuterViaFailoverCallback callback) : httpNetworkManager_(httpNetworkManager), advancedParameters_(advancedParameters), request_(std::move(request)), @@ -13,7 +14,8 @@ RequestExecuterViaFailover::RequestExecuterViaFailover(WSNetHttpNetworkManager * bIgnoreSslErrors_(bIgnoreSslErrors), isConnectedVpnState_(isConnectedVpnState), isConnectStateChanged_(false), - callback_(callback) + callback_(callback), + failedFailovers_(failedFailovers) { } @@ -59,7 +61,17 @@ void RequestExecuterViaFailover::onFailoverCallback(const std::vector= failoverData_.size()) + callback_(RequestExecuterRetCode::kFailoverFailed, std::move(request_), FailoverData("")); + else + executeBaseRequest(failoverData_[curIndFailoverData_]); } void RequestExecuterViaFailover::executeBaseRequest(const FailoverData &failoverData) @@ -93,6 +105,7 @@ void RequestExecuterViaFailover::onHttpNetworkRequestFinished(std::uint64_t http } if (errCode != NetworkError::kSuccess || request_->retCode() == ServerApiRetCode::kIncorrectJson) { + failedFailovers_.add(failoverData_[curIndFailoverData_]); // failover can contain several domains, let's try another one if there is one curIndFailoverData_++; if (curIndFailoverData_ >= failoverData_.size()) diff --git a/libs/wsnet/src/serverapi/requestexecuterviafailover.h b/libs/wsnet/src/serverapi/requestexecuterviafailover.h index 353f3653..0e1173a4 100644 --- a/libs/wsnet/src/serverapi/requestexecuterviafailover.h +++ b/libs/wsnet/src/serverapi/requestexecuterviafailover.h @@ -6,6 +6,7 @@ #include #include "baserequest.h" #include "failover/basefailover.h" +#include "failedfailovers.h" namespace wsnet { @@ -23,7 +24,8 @@ class RequestExecuterViaFailover public: // The request starts executing from the constructor immediately explicit RequestExecuterViaFailover(WSNetHttpNetworkManager *httpNetworkManager, std::unique_ptr request, std::unique_ptr failover, - bool bIgnoreSslErrors, bool isConnectedVpnState, WSNetAdvancedParameters *advancedParameters, RequestExecuterViaFailoverCallback callback); + bool bIgnoreSslErrors, bool isConnectedVpnState, WSNetAdvancedParameters *advancedParameters, FailedFailovers &failedFailovers, + RequestExecuterViaFailoverCallback callback); virtual ~RequestExecuterViaFailover(); void start(); @@ -33,6 +35,7 @@ class RequestExecuterViaFailover WSNetHttpNetworkManager *httpNetworkManager_; WSNetAdvancedParameters *advancedParameters_; RequestExecuterViaFailoverCallback callback_; + FailedFailovers &failedFailovers_; std::unique_ptr request_; std::unique_ptr failover_; diff --git a/libs/wsnet/src/serverapi/serverapi_impl.cpp b/libs/wsnet/src/serverapi/serverapi_impl.cpp index 8437a0d5..b297cade 100644 --- a/libs/wsnet/src/serverapi/serverapi_impl.cpp +++ b/libs/wsnet/src/serverapi/serverapi_impl.cpp @@ -55,6 +55,7 @@ void ServerAPI_impl::setIgnoreSslErrors(bool bIgnore) void ServerAPI_impl::resetFailover() { spdlog::info("ServerAPI_impl::resetFailover"); + failedFailovers_.clear(); auto failover = failoverContainer_->first(); curFailoverUid_ = failover->uniqueId(); curFailoverInd_ = 0; @@ -148,7 +149,7 @@ void ServerAPI_impl::executeRequest(std::unique_ptr request) // start RequestExecuterViaFailover and wait for the result in the callback function using namespace std::placeholders; requestExecutorViaFailover_.reset(new RequestExecuterViaFailover(httpNetworkManager_, std::move(request), std::move(curFailover), - bIgnoreSslErrors_, isConnectedToVpn_, advancedParameters_, + bIgnoreSslErrors_, isConnectedToVpn_, advancedParameters_, failedFailovers_, std::bind(&ServerAPI_impl::onRequestExecuterViaFailoverFinished, this, _1, _2, _3))); requestExecutorViaFailover_->start(); } else { diff --git a/libs/wsnet/src/serverapi/serverapi_impl.h b/libs/wsnet/src/serverapi/serverapi_impl.h index 301aa32c..3e1bea92 100644 --- a/libs/wsnet/src/serverapi/serverapi_impl.h +++ b/libs/wsnet/src/serverapi/serverapi_impl.h @@ -16,6 +16,7 @@ #include "utils/cancelablecallback.h" #include "serverapi_settings.h" #include "connectstate.h" +#include "failedfailovers.h" namespace wsnet { @@ -70,6 +71,7 @@ class ServerAPI_impl std::unique_ptr requestExecutorViaFailover_; std::optional failoverData_; // valid only in kReady/kFromSettingsReady states bool isFailoverFailedLogAlreadyDone_ = false; // log "failover failed: API not ready" only once to avoid spam + FailedFailovers failedFailovers_; void executeRequest(std::uint64_t requestId); void executeRequestImpl(std::unique_ptr request, const FailoverData &failoverData); diff --git a/libs/wsnet/src/serverapi/wsnet_utils_impl.cpp b/libs/wsnet/src/serverapi/wsnet_utils_impl.cpp index 6b1820b4..75fc1a3b 100644 --- a/libs/wsnet/src/serverapi/wsnet_utils_impl.cpp +++ b/libs/wsnet/src/serverapi/wsnet_utils_impl.cpp @@ -41,7 +41,7 @@ void WSNetUtils_impl::myIPViaFailover_impl(int failoverInd, std::unique_ptr(requestExecutorViaFailover); curUniqueId_++; diff --git a/libs/wsnet/src/serverapi/wsnet_utils_impl.h b/libs/wsnet/src/serverapi/wsnet_utils_impl.h index 7aed30cd..97a98f04 100644 --- a/libs/wsnet/src/serverapi/wsnet_utils_impl.h +++ b/libs/wsnet/src/serverapi/wsnet_utils_impl.h @@ -4,6 +4,7 @@ #include #include "WSNetHttpNetworkManager.h" #include "failover/ifailovercontainer.h" +#include "serverapi/failedfailovers.h" #include "requestexecuterviafailover.h" namespace wsnet { @@ -27,6 +28,7 @@ class WSNetUtils_impl : public WSNetUtils IFailoverContainer *failoverContainer_; std::uint64_t curUniqueId_ = 0; std::map > activeRequests_; + FailedFailovers failedFailovers_; void myIPViaFailover_impl(int failoverInd, std::unique_ptr request); void onRequestExecuterViaFailoverFinished(RequestExecuterRetCode retCode, std::unique_ptr request, FailoverData failoverData, std::uint64_t id); diff --git a/tools/base/arghelper.py b/tools/base/arghelper.py index 878c189d..e09bdb48 100644 --- a/tools/base/arghelper.py +++ b/tools/base/arghelper.py @@ -20,6 +20,7 @@ class ArgHelper: OPTION_SIGN_INSTALLER = "--sign-installer" OPTION_BUILD_BOOTSTRAP = "--build-bootstrap" OPTION_SIGN_BOOTSTRAP = "--sign-bootstrap" + OPTION_BUILD_TESTS = "--build-tests" OPTION_CLEAN = "--clean" # CI-specific options OPTION_CI_MODE = "--ci-mode" @@ -45,6 +46,7 @@ class ArgHelper: options.append((OPTION_SIGN_INSTALLER, "Sign the installer (Windows only)")) options.append((OPTION_BUILD_BOOTSTRAP, "Build the bootstrap (Windows only)")) options.append((OPTION_SIGN_BOOTSTRAP, "Sign the bootstrap (Windows only)")) + options.append((OPTION_BUILD_TESTS, "Build tests (only has an effect if --build-app is also used)")) options.append((OPTION_CLEAN, "Fully clean previous build files before building")) options.append(("\nCI-specific options", "")) options.append((OPTION_CI_MODE, "Used to indicate app is building on CI")) @@ -71,6 +73,7 @@ def __init__(self, program_arg_list): self.mode_sign_installer = ArgHelper.OPTION_SIGN_INSTALLER in program_arg_list self.mode_build_bootstrap = ArgHelper.OPTION_BUILD_BOOTSTRAP in program_arg_list self.mode_sign_bootstrap = ArgHelper.OPTION_SIGN_BOOTSTRAP in program_arg_list + self.mode_build_tests = ArgHelper.OPTION_BUILD_TESTS in program_arg_list # if nothing specified, build everything if (not self.mode_build_app and not self.mode_sign_app and not self.mode_build_installer and not self.mode_sign_installer and not self.mode_build_bootstrap and not self.mode_sign_bootstrap): @@ -118,6 +121,9 @@ def build_installer(self): def build_bootstrap(self): return self.mode_build_bootstrap + def build_tests(self): + return self.mode_build_tests + def sign_app(self): return self.mode_sign_app diff --git a/tools/build_all.py b/tools/build_all.py index cf8b4b52..f21855c7 100644 --- a/tools/build_all.py +++ b/tools/build_all.py @@ -241,6 +241,8 @@ def build_component(component, qt_root, buildenv=None): if arghelper.sign() or arghelper.sign_app() or arghelper.ci_mode(): generate_cmd.extend(["-DDEFINE_USE_SIGNATURE_CHECK_MACRO=ON"]) + if arghelper.build_tests(): + generate_cmd.extend(["-DIS_BUILD_TESTS=ON"]) if CURRENT_OS == "macos": # Build an universal binary only on CI if arghelper.ci_mode(): @@ -437,7 +439,7 @@ def sign_app_win32(configdata): def prep_installer_win32(configdata, crt_root): # Copy Windows files. - msg.Info("Copying libs...") + msg.Info("Copying libs ...") if crt_root: utl.CopyAllFiles(crt_root, BUILD_INSTALLER_FILES) @@ -721,8 +723,9 @@ def build_all(): temp_dir = iutl.PrepareTempDirectory("installer", not arghelper.ci_mode()) build_dir = os.path.join(pathhelper.ROOT_DIR, "build") utl.CreateDirectory(build_dir, arghelper.clean()) - global BUILD_INSTALLER_FILES, BUILD_SYMBOL_FILES, BUILD_INSTALLER_BOOTSTRAP_FILES + global BUILD_INSTALLER_FILES, BUILD_TEST_FILES, BUILD_SYMBOL_FILES, BUILD_INSTALLER_BOOTSTRAP_FILES BUILD_INSTALLER_FILES = os.path.join(temp_dir, "InstallerFiles") + BUILD_TEST_FILES = os.path.join(build_dir, "test") BUILD_INSTALLER_BOOTSTRAP_FILES = os.path.join(temp_dir, "InstallerBootstrapFiles") utl.CreateDirectory(BUILD_INSTALLER_FILES, not arghelper.ci_mode()) utl.CreateDirectory(BUILD_INSTALLER_BOOTSTRAP_FILES, not arghelper.ci_mode()) @@ -736,6 +739,14 @@ def build_all(): build_components(configdata, configdata["targets"], qt_root) if (CURRENT_OS == "win32"): prep_installer_win32(configdata, crt_root) + if arghelper.build_tests(): + utl.CopyAllFiles(crt_root, BUILD_TEST_FILES) + copy_files("MSVC", configdata["deploy_files"]["win32"]["installer"]["msvc"], msvc_root, BUILD_TEST_FILES) + for file in glob.glob(os.path.join(build_dir, "client", "*.dll")): + utl.CopyFile(file, os.path.join(BUILD_TEST_FILES, os.path.basename(file))) + for file in glob.glob(os.path.join(build_dir, "client", "wsnet", "*.dll")): + utl.CopyFile(file, os.path.join(BUILD_TEST_FILES, os.path.basename(file))) + copy_files("Test", ["wsnet_test.exe"], os.path.join(build_dir, "client"), BUILD_TEST_FILES) if arghelper.sign_app(): if (CURRENT_OS == "win32"): sign_app_win32(configdata) diff --git a/tools/signing__windows_drivers/readme.txt b/tools/signing__windows_drivers/readme.txt deleted file mode 100644 index c64fa63c..00000000 --- a/tools/signing__windows_drivers/readme.txt +++ /dev/null @@ -1,22 +0,0 @@ -The script sign.bat is designed to sign drivers for Windows. -Currently supports 2 architectures amd64 and arm64. - -The signing process consists of two steps: - -Step1 (signing and creating an cabinet file ready for upload to the Microsoft website): -1) Put in "amd64" or "arm64" subdirectory driver files(*.sys and *.inf) to be signed. -2) Copy this folder to the signing machine where the USB token with the certificate is installed. -3) Use sign.bat script, for example: - sign.bat amd64 windscribesplittunnel (for amd64 architecture) - sign.bat arm64 windscribesplittunnel (for arm64 architecture) -4) In the subdirectory "disk1" you will find the generated *.cab file. - -Step 2 (signing on the Microsoft site): -1) Goto https://partner.microsoft.com/en-us/dashboard/hardware/Search. You must be logged in with your account which has permissions to sign drivers. -2) Click "Submit new hardware". -3) Enter product name (for example, 'Windscribe 2.0 - Split Tunneling arm64'). -4) Select and upload your *.cab file generated on previous step. -5) The "Perform test-signing" checkbox should be enabled. -6) Select "Requested Signatures", selecting those related to the architecture of the uploaded driver. -7) Click "Submit" and wait for the driver to be signed by Microsoft. -8) Download signed drivers. \ No newline at end of file diff --git a/tools/signing__windows_drivers/sign.bat b/tools/signing__windows_drivers/sign.bat deleted file mode 100644 index 5c8a699b..00000000 --- a/tools/signing__windows_drivers/sign.bat +++ /dev/null @@ -1,90 +0,0 @@ -@echo off - -set curpath=%cd% -set ARCH_PAR=%1 -set FILE_TO_SIGN=%2 -set VSCOMNTOOLS="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" -set INF2CAT_TOOL_PATH="C:\Program Files (x86)\Windows Kits\10\bin\x86\inf2cat.exe" -set AMD_64_OS_LIST=7_X64,8_X64,6_3_X64,10_X64,10_AU_X64,10_RS2_X64,10_RS3_X64,10_RS4_X64,10_RS5_X64,10_19H1_X64,10_VB_X64,Server2008R2_X64,Server8_X64,Server6_3_X64,Server10_X64,Server2016_X64,ServerRS5_X64 -set ARM_64_OS_LIST=10_RS3_ARM64,10_RS4_ARM64,10_RS5_ARM64,10_19H1_ARM64,10_VB_ARM64,Server10_ARM64,ServerRS5_ARM64 - -if NOT exist %VSCOMNTOOLS% ( - echo The Microsoft Visual Studio 2019 vcvarsall.bat not found. - exit /b -) - -if NOT exist %INF2CAT_TOOL_PATH% ( - echo %INF2CAT_TOOL_PATH% not found. Please install Windows DDK. - exit /b -) - -IF NOT "%ARCH_PAR%"=="amd64" ( - IF NOT "%ARCH_PAR%"=="arm64" goto :bad_arch_parameter -) - -if NOT exist %curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.sys goto :bad_driver_name_parameter -if NOT exist %curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.inf goto :bad_driver_name_parameter - - -call %VSCOMNTOOLS% x86_amd64 - - -echo Signing architecture %ARCH_PAR%... -signtool sign /v /tr http://timestamp.digicert.com /td sha256 /fd sha256 /s my /n "Windscribe Limited" "%curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.sys" -signtool sign /v /as /tr http://timestamp.digicert.com /td sha1 /fd sha1 /s my /n "Windscribe Limited" "%curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.sys" - - -IF "%ARCH_PAR%"=="amd64" ( - %INF2CAT_TOOL_PATH% /driver:%curpath%/%ARCH_PAR% /os:%AMD_64_OS_LIST% -) -IF "%ARCH_PAR%"=="arm64" ( - %INF2CAT_TOOL_PATH% /driver:%curpath%/%ARCH_PAR% /os:%ARM_64_OS_LIST% -) - -signtool sign /v /tr http://timestamp.digicert.com /td sha256 /fd sha256 /s my /n "Windscribe Limited" "%curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.cat" -signtool sign /v /as /tr http://timestamp.digicert.com /td sha1 /fd sha1 /s my /n "Windscribe Limited" "%curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.cat" - -echo Making cab file... - -Set "out=%curpath%" -( - echo;.OPTION EXPLICIT - echo;.Set CabinetFileCountThreshold=0 - echo;.Set FolderFileCountThreshold=0 - echo;.Set FolderSizeThreshold=0 - echo;.Set MaxCabinetSize=0 - echo;.Set MaxDiskFileCount=0 - echo;.Set MaxDiskSize=0 - echo;.Set CompressionType=MSZIP - echo;.Set Cabinet=on - echo;.Set Compress=on - echo;.Set CabinetNameTemplate=%FILE_TO_SIGN%_%ARCH_PAR%.cab - echo;.Set DestinationDir=%ARCH_PAR% - echo;%ARCH_PAR%\%FILE_TO_SIGN%.inf - echo;%ARCH_PAR%\%FILE_TO_SIGN%.sys - echo;%ARCH_PAR%\%FILE_TO_SIGN%.cat -) > "%out%\cabinet_%ARCH_PAR%.ddf" - - -MakeCab /f cabinet_%ARCH_PAR%.ddf - -rem Deleting junk files -del cabinet_%ARCH_PAR%.ddf -del setup.inf -del setup.rpt - -echo Signing cab file... -signtool sign /v /tr http://timestamp.digicert.com /td sha256 /fd sha256 /s my /n "Windscribe Limited" "%curpath%\disk1\%FILE_TO_SIGN%_%ARCH_PAR%.cab" - -goto :end - -:bad_arch_parameter -echo Invalid architecture parameter. -echo Usage: sign.bat [amd64/arm64] driver_name. -goto :end - -:bad_driver_name_parameter -echo The driver_name is not specified or driver files not found. -echo Usage: sign.bat [amd64/arm64] driver_name. - -:end \ No newline at end of file diff --git a/tools/signing_windows_drivers/readme.txt b/tools/signing_windows_drivers/readme.txt new file mode 100644 index 00000000..794cb3d1 --- /dev/null +++ b/tools/signing_windows_drivers/readme.txt @@ -0,0 +1 @@ +See the 'Signing and deployment' section of the 'Split-tunnel Driver' Notion doc for instructions on how to use this batch file. diff --git a/tools/signing_windows_drivers/sign.bat b/tools/signing_windows_drivers/sign.bat new file mode 100644 index 00000000..923c0c73 --- /dev/null +++ b/tools/signing_windows_drivers/sign.bat @@ -0,0 +1,132 @@ +@echo off + +set curpath=%cd% +set ARCH_PAR=%1 +set FILE_TO_SIGN=%2 +set CONTAINER_NAME=%3 +set SIGNING_TOKEN_PASSWORD=%4 +set VSCOMNTOOLS="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" +set INF2CAT_TOOL_PATH="C:\Program Files (x86)\Windows Kits\10\bin\x86\inf2cat.exe" +set AMD_64_OS_LIST=7_X64,8_X64,6_3_X64,10_X64,10_AU_X64,10_RS2_X64,10_RS3_X64,10_RS4_X64,10_RS5_X64,10_19H1_X64,10_VB_X64,Server2008R2_X64,Server8_X64,Server6_3_X64,Server10_X64,Server2016_X64,ServerRS5_X64 +set ARM_64_OS_LIST=10_RS3_ARM64,10_RS4_ARM64,10_RS5_ARM64,10_19H1_ARM64,10_VB_ARM64,Server10_ARM64,ServerRS5_ARM64 + +if NOT exist %VSCOMNTOOLS% ( + echo The Microsoft Visual Studio 2019 vcvarsall.bat not found. + exit /b +) + +if NOT exist %INF2CAT_TOOL_PATH% ( + echo %INF2CAT_TOOL_PATH% not found. Please install Windows DDK. + exit /b +) + +IF NOT "%ARCH_PAR%"=="amd64" ( + IF NOT "%ARCH_PAR%"=="arm64" goto :bad_arch_parameter +) + +if NOT exist %curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.sys goto :bad_driver_name_parameter +if NOT exist %curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.inf goto :bad_driver_name_parameter + +if "%CONTAINER_NAME%"=="" goto :signing_container_name_missing + +if "%SIGNING_TOKEN_PASSWORD%"=="" goto :signing_token_missing + +call %VSCOMNTOOLS% x86_amd64 + + +echo Signing %ARCH_PAR% driver with SHA-256... +call signtool.exe sign /v /tr http://timestamp.digicert.com /td sha256 /fd sha256 /f code_signing.der /csp "eToken Base Cryptographic Provider" /kc "[{{%SIGNING_TOKEN_PASSWORD%}}]=%CONTAINER_NAME%" /n "Windscribe Limited" "%curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.sys" +if %errorlevel% equ 0 ( + echo Driver successfully signed. +) ELSE ( + goto :end +) +echo Signing %ARCH_PAR% driver with SHA-1... +call signtool.exe sign /v /as /tr http://timestamp.digicert.com /td sha1 /fd sha1 /f code_signing.der /csp "eToken Base Cryptographic Provider" /kc "[{{%SIGNING_TOKEN_PASSWORD%}}]=%CONTAINER_NAME%" /n "Windscribe Limited" "%curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.sys" +if %errorlevel% equ 0 ( + echo Driver successfully signed. +) ELSE ( + goto :end +) + + +IF "%ARCH_PAR%"=="amd64" ( + %INF2CAT_TOOL_PATH% /driver:%curpath%/%ARCH_PAR% /os:%AMD_64_OS_LIST% +) +IF "%ARCH_PAR%"=="arm64" ( + %INF2CAT_TOOL_PATH% /driver:%curpath%/%ARCH_PAR% /os:%ARM_64_OS_LIST% +) + +echo Signing %ARCH_PAR% catalog file with SHA-256... +call signtool.exe sign /v /tr http://timestamp.digicert.com /td sha256 /fd sha256 /f code_signing.der /csp "eToken Base Cryptographic Provider" /kc "[{{%SIGNING_TOKEN_PASSWORD%}}]=%CONTAINER_NAME%" /n "Windscribe Limited" "%curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.cat" +if %errorlevel% equ 0 ( + echo Driver successfully signed. +) ELSE ( + goto :end +) +echo Signing %ARCH_PAR% catalog file with SHA-1... +call signtool.exe sign /v /as /tr http://timestamp.digicert.com /td sha1 /fd sha1 /f code_signing.der /csp "eToken Base Cryptographic Provider" /kc "[{{%SIGNING_TOKEN_PASSWORD%}}]=%CONTAINER_NAME%" /n "Windscribe Limited" "%curpath%\%ARCH_PAR%\%FILE_TO_SIGN%.cat" +if %errorlevel% equ 0 ( + echo Driver successfully signed. +) ELSE ( + goto :end +) + +echo Making cab file... + +Set "out=%curpath%" +( + echo;.OPTION EXPLICIT + echo;.Set CabinetFileCountThreshold=0 + echo;.Set FolderFileCountThreshold=0 + echo;.Set FolderSizeThreshold=0 + echo;.Set MaxCabinetSize=0 + echo;.Set MaxDiskFileCount=0 + echo;.Set MaxDiskSize=0 + echo;.Set CompressionType=MSZIP + echo;.Set Cabinet=on + echo;.Set Compress=on + echo;.Set CabinetNameTemplate=%FILE_TO_SIGN%_%ARCH_PAR%.cab + echo;.Set DestinationDir=%ARCH_PAR% + echo;%ARCH_PAR%\%FILE_TO_SIGN%.inf + echo;%ARCH_PAR%\%FILE_TO_SIGN%.sys + echo;%ARCH_PAR%\%FILE_TO_SIGN%.cat +) > "%out%\cabinet_%ARCH_PAR%.ddf" + + +MakeCab /f cabinet_%ARCH_PAR%.ddf + +rem Deleting junk files +del cabinet_%ARCH_PAR%.ddf +del setup.inf +del setup.rpt + +echo Signing cabinet file... +call signtool.exe sign /v /tr http://timestamp.digicert.com /td sha256 /fd sha256 /f code_signing.der /csp "eToken Base Cryptographic Provider" /kc "[{{%SIGNING_TOKEN_PASSWORD%}}]=%CONTAINER_NAME%" /n "Windscribe Limited" "%curpath%\disk1\%FILE_TO_SIGN%_%ARCH_PAR%.cab" +if %errorlevel% equ 0 ( + echo Cabinet file successfully signed. +) ELSE ( + goto :end +) + +goto :end + +:bad_arch_parameter +echo Invalid architecture parameter. +echo Usage: sign.bat [amd64/arm64] driver_name. +goto :end + +:bad_driver_name_parameter +echo The driver_name is not specified or driver files not found. +echo Usage: sign.bat [amd64/arm64] driver_name. +goto :end + +:signing_container_name_missing +echo The code signing container name was not specified. +goto :end + +:signing_token_missing +echo The code signing token password was not specified. +goto :end + +:end