This commit is contained in:
Jonathan Martin
2026-03-02 08:43:15 -08:00
parent c0d606d6c2
commit b90fe8f742
443 changed files with 8563 additions and 41502 deletions
+1
View File
@@ -18,6 +18,7 @@ drawings/*/*.png
tools/.idea/
build/
.vscode/
.claude/
# secrets
tools/notarize.yml
+19 -257
View File
@@ -25,7 +25,12 @@ variables:
.template_win10_build: &template_win10_build
tags: [win10qty6]
before_script:
- ./tools/vcpkg/install_ci/vcpkg_install.bat %VCPKG_ROOT_WINDOWS% --configure-git
- $env:VCPKG_ROOT = $env:VCPKG_ROOT_WINDOWS
- $env:VCPKG_DEFAULT_BINARY_CACHE = $env:VCPKG_DEFAULT_BINARY_CACHE_WINDOWS
- $env:VCPKG_INSTALL_OPTIONS = "--clean-after-build"
- if (Test-Path ws-vcpkg-registry) { Remove-Item -Recurse -Force ws-vcpkg-registry }
- git clone https://github.com/Windscribe/ws-vcpkg-registry.git
- .\ws-vcpkg-registry\install-vcpkg\vcpkg_install.bat $env:VCPKG_ROOT_WINDOWS --configure-git
- python3 -m pip install -r tools/requirements.txt
# Remove the default Powershell curl alias so referencing 'curl' will call Windows built-in curl.exe
- Remove-Item alias:curl
@@ -50,7 +55,10 @@ variables:
before_script:
- brew install pkg-config
- export VCPKG_ROOT="${HOME}/vcpkg"
- ./tools/vcpkg/install_ci/vcpkg_install.sh "${VCPKG_ROOT}" --configure-git
- export VCPKG_INSTALL_OPTIONS="--clean-after-build"
- rm -rf ws-vcpkg-registry
- git clone https://github.com/Windscribe/ws-vcpkg-registry.git
- ./ws-vcpkg-registry/install-vcpkg/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
@@ -66,6 +74,8 @@ variables:
# vcpkg settings
- export VCPKG_ROOT="${HOME}/vcpkg"
- export VCPKG_FORCE_SYSTEM_BINARIES=1
- export VCPKG_CA_BUNDLE="$(pwd)/tools/cacert.pem"
- export VCPKG_BINARY_SOURCES="clear;http,https://${NEXUS_USERNAME}:${NEXUS_PASSWORD}@nexus.int.windscribe.com/repository/client-desktop/client-desktop/vcpkg_cache/current/binary_cache/{sha}.zip,readwrite"
- wget -q https://github.com/NixOS/patchelf/releases/download/0.18.0/patchelf-0.18.0-aarch64.tar.gz && mkdir -p tools/patchelf && tar -C tools/patchelf -xzf patchelf-0.18.0-aarch64.tar.gz
- export PATH=${RHEL_CMAKE_BUILD_PATH}/bin:`pwd`/tools/patchelf/bin:$PATH
- cmake --version
@@ -82,6 +92,8 @@ variables:
# vcpkg settings
- export VCPKG_ROOT="${HOME}/vcpkg"
- export PATH=${RHEL_CMAKE_BUILD_PATH}/bin:$PATH
- export VCPKG_CA_BUNDLE="$(pwd)/tools/cacert.pem"
- export VCPKG_BINARY_SOURCES="clear;http,https://${NEXUS_USERNAME}:${NEXUS_PASSWORD}@nexus.int.windscribe.com/repository/client-desktop/client-desktop/vcpkg_cache/current/binary_cache/{sha}.zip,readwrite"
- python3 -m pip install -r tools/requirements.txt
interruptible: true
@@ -105,11 +117,6 @@ variables:
- curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem
--create-dirs -o ${BUILD_LIBS_FOLDER}/wstunnel.zip "${NEXUS_PATH_DEPS}/${OS_IDENTIFIER}/wstunnel.zip"
.download_vcpkg_cache:
script:
- curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem
--create-dirs -o vcpkg_cache.zip "${NEXUS_PATH_VCPKG_CACHE}/${OS_IDENTIFIER}/vcpkg_cache.zip" || ./tools/vcpkg/install_ci/vcpkg_install.sh "${VCPKG_ROOT}" --configure-git
.download_dependencies_win:
script:
- Set-Variable -name SKIP_DOWNLOAD -value "0"
@@ -122,14 +129,11 @@ variables:
script:
- !reference [.download_dependency_wireguard, script]
- !reference [.download_dependency_wstunnel, script]
- !reference [.download_vcpkg_cache, script]
.package_vcpkg_cache:
script:
- rm -f vcpkg_cache.zip
- (cd ${HOME} && zip -qr vcpkg_cache.zip vcpkg)
- curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem
--upload-file ${HOME}/vcpkg_cache.zip "${NEXUS_PATH_VCPKG_CACHE}/${OS_IDENTIFIER}/vcpkg_cache.zip"
- export VCPKG_ROOT="${HOME}/vcpkg"
- export VCPKG_INSTALL_OPTIONS="--clean-after-build"
- rm -rf ws-vcpkg-registry
- git clone https://github.com/Windscribe/ws-vcpkg-registry.git
- ./ws-vcpkg-registry/install-vcpkg/vcpkg_install.sh "${VCPKG_ROOT}" --configure-git
.template_win_build_app: &template_win_build_app
<<: *template_win10_build
@@ -510,7 +514,6 @@ build:mac:installer:tagged:
script:
- !reference [.download_dependencies_posix, script]
- if [ -d ./${BUILD_LIBS_FOLDER}/ ]; then for z in ./${BUILD_LIBS_FOLDER}/*.zip; do unzip -qod ./${BUILD_LIBS_FOLDER} $z; done; fi
- if [ -f vcpkg_cache.zip ]; then rm -rf ${HOME}/vcpkg; unzip -qod ${HOME} vcpkg_cache.zip; fi
- VERSION=$(python3 tools/base/extract.py)
build:aarch64_ubuntu:installer:
@@ -526,7 +529,6 @@ build:aarch64_ubuntu:installer:
--upload-file build-exe/windscribe_${VERSION}_arm64.deb "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/windscribe_${VERSION}_arm64.deb"
- curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem
--upload-file build-exe/windscribe_${VERSION}_arm64_fedora.rpm "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/windscribe_${VERSION}_arm64_fedora.rpm"
- !reference [.package_vcpkg_cache, script]
rules:
- if: $BUILD_LINUX_ARM64 == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null && $NIGHTLY_TEST_BUILD != "y"
@@ -543,7 +545,6 @@ build:aarch64_ubuntu_cli:installer:
--upload-file build-exe/windscribe-cli_${VERSION}_arm64.deb "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/windscribe-cli_${VERSION}_arm64.deb"
- curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem
--upload-file build-exe/windscribe-cli_${VERSION}_arm64_fedora.rpm "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/windscribe-cli_${VERSION}_arm64_fedora.rpm"
- !reference [.package_vcpkg_cache, script]
rules:
- if: $BUILD_LINUX_ARM64 == "y" && $BUILD_LINUX_CLI == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null && $NIGHTLY_TEST_BUILD != "y"
@@ -623,7 +624,6 @@ build:rhel:installer:
--upload-file build-exe/windscribe_${VERSION}_amd64_opensuse.rpm "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/windscribe_${VERSION}_amd64_opensuse.rpm"
- curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem
--upload-file build-exe/windscribe_${VERSION}_amd64.deb "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/windscribe_${VERSION}_amd64.deb"
- !reference [.package_vcpkg_cache, script]
rules:
- if: $BUILD_LINUX == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null && $NIGHTLY_TEST_BUILD != "y"
@@ -642,7 +642,6 @@ build:rhel_cli:installer:
--upload-file build-exe/windscribe-cli_${VERSION}_amd64_opensuse.rpm "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/windscribe-cli_${VERSION}_amd64_opensuse.rpm"
- curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem
--upload-file build-exe/windscribe-cli_${VERSION}_amd64.deb "${NEXUS_PATH_BRANCH_UPLOAD}/${OS_IDENTIFIER}/windscribe-cli_${VERSION}_amd64.deb"
- !reference [.package_vcpkg_cache, script]
rules:
- if: $BUILD_LINUX == "y" && $BUILD_LINUX_CLI == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != null && $NIGHTLY_TEST_BUILD != "y"
@@ -883,178 +882,6 @@ test:translations:
rules:
- if: $BUILD_WIN == "y"
build:wsnet:win:
<<: *template_win10_build
stage: Build
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
rules:
- if: $BUILD_WIN == "y" && $NIGHTLY_TEST_BUILD == "y"
artifacts:
expire_in: 1 day
paths:
- build/test
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"
- Set-Variable ErrorActionPreference
- cd build/test
- pip3 install pproxy
- Start-Process -NoNewWindow -PassThru pproxy
- Try {
./wsnet_test.exe --gtest_output=xml:report_win.xml
} Catch {
throw
} Finally {
Get-Process "pproxy" | Stop-Process -Force
}
after_script:
# This command may fail because it was already killed above; that's fine.
- Get-Process "pproxy" -ErrorAction SilentlyContinue | Stop-Process -Force
retry: 2
needs:
- job: build:wsnet:win
optional: true
artifacts: true
rules:
- if: $BUILD_WIN == "y" && $NIGHTLY_TEST_BUILD == "y"
artifacts:
when: always
expire_in: 1 day
paths:
- build/test/report_win.xml
reports:
junit: build/test/report_win.xml
build:wsnet:mac:
<<: *template_mac_build
stage: Build
variables:
GIT_STRATEGY: clone
script:
- OS_IDENTIFIER="macos"
- !reference [.build_mac_installer_common, script]
- tools/build_all --static-analysis --build-app --build-tests
artifacts:
expire_in: 1 day
paths:
- build/test
- build/libs/wsnet
- build/_cmrc
rules:
- if: $BUILD_MAC == "y" && $NIGHTLY_TEST_BUILD == "y"
test:wsnet:mac:
<<: *template_mac_build
stage: Test
variables:
GIT_STRATEGY: clone
script:
- OS_IDENTIFIER="macos"
- !reference [.build_mac_installer_common, script]
# reinitialize vcpkg for for arm64-osx, since the tests would be built against them rather than the osx version.
- ${VCPKG_ROOT}/vcpkg install --x-install-root=${VCPKG_ROOT}/installed --x-manifest-root=tools/vcpkg --overlay-triplets=tools/vcpkg/triplets
- pip3 install pproxy
- set +o pipefail
- if [ "$(ps aux | grep -c [p]proxy)" -ne 0 ]; then ps aux | grep [p]proxy | awk '{print $2}' | xargs kill -9; fi
- /Users/ws-user/Library/Python/3.9/bin/pproxy &
# fix RPATH for wsnet_test, in case it was built on a different machine
- install_name_tool -add_rpath build/src/client/wsnet build/src/client/wsnet_test || true
- build/test/wsnet_test --gtest_output=xml:report_${OS_IDENTIFIER}.xml || FAILED=1
- kill %1
- if [ $FAILED ]; then exit 1; fi
coverage: /^\s*lines:\s*\d+.\d+\%/
after_script:
- python3 -m gcovr --xml-pretty --exclude-unreachable-branches --print-summary -o coverage.xml --root ${CI_PROJECT_DIR}
retry: 2
needs:
- job: build:wsnet:mac
optional: true
artifacts: true
artifacts:
when: always
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
junit: report_macos.xml
paths:
- report_macos.xml
rules:
- if: $BUILD_MAC == "y" && $NIGHTLY_TEST_BUILD == "y"
build:wsnet:rhel:
<<: *template_rhel_build
stage: Build
variables:
GIT_STRATEGY: clone
script:
- OS_IDENTIFIER="linux"
- !reference [.build_linux_installer_common, script]
- python3 -m pip install clang-tidy
- tools/build_all --static-analysis --build-app --build-tests
artifacts:
expire_in: 1 day
paths:
- build/test
- build/libs/wsnet
- build/_cmrc
rules:
- if: $BUILD_LINUX == "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]
- pip3 install pproxy
- set +o pipefail
- if [ "$(ps aux | grep -c [p]proxy)" -ne 0 ]; then ps aux | grep [p]proxy | awk '{print $2}' | xargs kill -9; fi
- pproxy &
- build/test/wsnet_test --gtest_output=xml:report_${OS_IDENTIFIER}.xml || FAILED=1
- kill %1
- if [ $FAILED ]; then exit 1; fi
coverage: /^\s*lines:\s*\d+.\d+\%/
after_script:
- python3 -m gcovr --xml-pretty --exclude-unreachable-branches --print-summary -o coverage.xml --root ${CI_PROJECT_DIR}
retry: 2
needs:
- job: build:wsnet:rhel
optional: true
artifacts: true
artifacts:
name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}-linux
when: always
expire_in: 1 day
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
junit: report_linux.xml
paths:
- report_linux.xml
rules:
- if: $BUILD_LINUX == "y" && $NIGHTLY_TEST_BUILD == "y"
test:version:mac:
<<: *template_mac_build
stage: Test
@@ -1076,68 +903,3 @@ test:version:mac:
dependencies: []
rules:
- if: $BUILD_MAC == "y" && $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH == null && $NIGHTLY_TEST_BUILD != "y"
build:wsnet:ios:
stage: Build
tags: [macos-arm64-qt6]
script:
# Patched vcpkg needed for iOS simulator support.
- git clone https://github.com/Windscribe/vcpkg.git ./libs/wsnet/tools/vcpkg
- cd ./libs/wsnet/tools/vcpkg
- ./bootstrap-vcpkg.sh &> /dev/null
- cd -
- export VCPKG_ROOT=$(pwd)/libs/wsnet/tools/vcpkg
- echo "Building iOS xcframework..."
- cd ./libs/wsnet/tools
- ./build_ios.sh &> /dev/null
- ls -lh ./build/WSNet.xcframework
- cd ./build
- zip -r WSNet.xcframework.zip WSNet.xcframework
artifacts:
name: "WSNet_iOS_${CI_COMMIT_SHORT_SHA}"
paths:
- ./libs/wsnet/tools/build/WSNet.xcframework.zip
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- libs/wsnet/**/*
build:wsnet:android:
<<: *template_rhel_build
stage: Build
script:
# Install dependencies.
- dnf install -y java-17-openjdk java-17-openjdk-devel zip unzip wget cmake ninja-build git gcc-c++ make
# Setup vcpkg.
- git clone https://github.com/microsoft/vcpkg.git /root/vcpkg
- cd /root/vcpkg
- git reset --hard f7423ee180c4b7f40d43402c2feb3859161ef625
- ./bootstrap-vcpkg.sh &> /dev/null
- export VCPKG_ROOT=/root/vcpkg
- export PATH="$VCPKG_ROOT:$PATH"
# Setup Java
- cd -
- echo "Setting up Java..."
- export JAVA_HOME=/usr/lib/jvm/java-17
- export PATH=$JAVA_HOME/bin:$PATH
# Setup NDK
- mkdir -p /opt/android-ndk
- wget https://dl.google.com/android/repository/android-ndk-r25b-linux.zip -O ndk.zip
- unzip -q ndk.zip -d /opt/android-ndk
- export ANDROID_NDK_HOME=/opt/android-ndk/android-ndk-r25b
- export PATH=$ANDROID_NDK_HOME:$PATH
- $ANDROID_NDK_HOME/ndk-build --version || true
# Build .aar
- cd ./libs/wsnet/tools
- ./build_android.sh &> /dev/null
- zip -r WSNet.aar.zip wsnet.aar
artifacts:
name: "WSNet_Android_${CI_COMMIT_SHORT_SHA}"
paths:
- ./libs/wsnet/tools/WSNet.aar.zip
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- libs/wsnet/**/*
+42 -1
View File
@@ -1,10 +1,51 @@
2.21.3 (24/02/2026)
All:
* Added in-app user registration functionality. #1628
* Improved build infrastructure by moving vcpkg dependencies to a separate repository. #1670
* Fixed incorrect window elements if showing credentials prompt immediately after CPU usage warning. #1653
* Fixed decoy traffic volume silently reverts to 'Low' after app restart. #1661
* Fixed decoy traffic not started when using pinned IP. #1664
* Fixed input sanitation when using custom config. #1671
* Fixed combobox items are not left-aligned. #1672
* Fixed incorrect window ordering when returning to login screen. #1673
MacOS:
* Fixed incorrect network connectivity drop when restarting split tunnel extension. #1646
Linux:
* Added AmneziaWG advanced anti-censorship support to the CLI. #1668
* Fixed split tunnel applications not populated on some distros. #1666
2.21.2 (19/02/2026)
All:
* Added build system scripts for AmneziaWG. #1655
* Improved AmneziaWG logic to use a default configuration when the unblock params API cannot be reached. #1658
* Improved network options description and added help link. #1657
* Fixed potentially incorrect firewall rules when using custom configs. #1642
MacOS:
* Fixed AmneziaWG params in a custom config are ignored. #1572
Linux:
* Added AmneziaWG advanced anti-censorship support. #1651
* Fixed AmneziaWG params in a custom config are ignored. #1572
* Fixed DNS not being set on the system for OpenVPN custom configs. #1643
2.21.1 (10/02/2026)
Windows:
* Added AmneziaWG advanced anti-censorship support. #1572
MacOS:
* Added AmneziaWG advanced anti-censorship support. #1572
2.20.7 (19/02/2026)
All:
* Fixed description width on protocol screen. #825
MacOS:
* Fixed app not displaying DNS conflict warning when a local DNS daemon is running and the custom DNS feature is enabled. #1660
* Fixed installer binary displaying incorrect version number and copyright date. #1662
Linux:
* Fixed inclusive split tunneling route may not be added correctly. #1656
2.20.6 (09/02/2026)
All:
* Added link to website for "Clear Wi-Fi History" feature. Shortened description. #1585
+3 -1
View File
@@ -212,10 +212,12 @@ if(BUILD_APP)
# Main GUI application
add_subdirectory(src/windscribe-cli)
add_subdirectory(libs/wsnet)
add_subdirectory(src/helper)
add_subdirectory(src/client)
# Load wsnet from the separate repository
include("${CMAKE_SOURCE_DIR}/cmake/fetch_wsnet.cmake")
if(WIN32)
add_custom_target(build-app ALL
DEPENDS Windscribe windscribe-cli WindscribeService WindscribeInstallHelper WireguardService uninstall
+8
View File
@@ -0,0 +1,8 @@
if(NOT TARGET wsnet::wsnet)
include(FetchContent)
FetchContent_Declare(wsnet
GIT_REPOSITORY git@github.com:Windscribe/wsnet.git
GIT_TAG 1.4.8
)
FetchContent_MakeAvailable(wsnet)
endif()
+1 -1
View File
@@ -37,7 +37,7 @@ macro(linux_copy_files DEST_DIR TARGET_NAME)
# Copy custom dependencies
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${WINDSCRIBE_BUILD_LIBS_PATH}/wireguard/windscribewireguard"
"${WINDSCRIBE_BUILD_LIBS_PATH}/wireguard/windscribeamneziawg"
"${DEST_DIR}/opt/windscribe/"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${WINDSCRIBE_BUILD_LIBS_PATH}/wstunnel/windscribewstunnel"
+7 -11
View File
@@ -22,23 +22,20 @@ if(NOT EXISTS "${CMAKE_TOOLCHAIN_FILE}")
message(FATAL_ERROR "vcpkg toolchain file not found: ${CMAKE_TOOLCHAIN_FILE}")
endif()
# Set vcpkg overlay paths for custom triplets
set(VCPKG_OVERLAY_TRIPLETS "${CMAKE_CURRENT_SOURCE_DIR}/tools/vcpkg/triplets" CACHE PATH "vcpkg overlay triplets")
# Determine vcpkg triplet based on platform and architecture
if(NOT DEFINED VCPKG_TARGET_TRIPLET)
if(WIN32)
if(BUILD_ARM64)
set(VCPKG_TARGET_TRIPLET "arm64-windows-static-release")
set(VCPKG_TARGET_TRIPLET "ws-arm64-windows-static-release")
elseif(CI_MODE)
set(VCPKG_TARGET_TRIPLET "x64-windows-static-release")
set(VCPKG_TARGET_TRIPLET "ws-x64-windows-static-release")
else()
set(VCPKG_TARGET_TRIPLET "x64-windows-static")
endif()
elseif(APPLE)
if(CI_MODE)
# Universal binary on CI
set(VCPKG_TARGET_TRIPLET "universal-osx")
set(VCPKG_TARGET_TRIPLET "ws-universal-osx")
else()
# Detect host architecture
execute_process(
@@ -47,7 +44,7 @@ if(NOT DEFINED VCPKG_TARGET_TRIPLET)
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(MACOS_ARCH STREQUAL "arm64")
set(VCPKG_TARGET_TRIPLET "arm64-osx")
set(VCPKG_TARGET_TRIPLET "ws-arm64-osx")
else()
set(VCPKG_TARGET_TRIPLET "x64-osx")
endif()
@@ -60,9 +57,9 @@ if(NOT DEFINED VCPKG_TARGET_TRIPLET)
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(LINUX_ARCH MATCHES "aarch64|arm64")
set(VCPKG_TARGET_TRIPLET "arm64-linux")
set(VCPKG_TARGET_TRIPLET "ws-arm64-linux")
else()
set(VCPKG_TARGET_TRIPLET "x64-linux")
set(VCPKG_TARGET_TRIPLET "ws-x64-linux")
endif()
endif()
@@ -83,7 +80,6 @@ macro(install_vcpkg_dependencies)
"${VCPKG_ROOT}/vcpkg" install
"--x-install-root=${VCPKG_ROOT}/installed"
"--x-manifest-root=${CMAKE_CURRENT_SOURCE_DIR}/tools/vcpkg"
"--overlay-triplets=${CMAKE_CURRENT_SOURCE_DIR}/tools/vcpkg/triplets"
"--triplet=${VCPKG_TARGET_TRIPLET}"
"--clean-buildtrees-after-build"
"--clean-packages-after-build"
@@ -92,7 +88,7 @@ macro(install_vcpkg_dependencies)
# Add host triplet for Windows and Linux
if(WIN32)
if(CI_MODE)
list(APPEND VCPKG_INSTALL_CMD "--host-triplet=x64-windows-static-release")
list(APPEND VCPKG_INSTALL_CMD "--host-triplet=ws-x64-windows-static-release")
else()
list(APPEND VCPKG_INSTALL_CMD "--host-triplet=x64-windows-static")
endif()
-1
View File
@@ -1 +0,0 @@
Here are libs that can also be used by mobile programs.
-2
View File
@@ -1,2 +0,0 @@
*.user
generated
-222
View File
@@ -1,222 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Overview
**wsnet** is a cross-platform C++17 networking library for Windscribe VPN clients (Windows/Mac/Linux/Android/iOS). It provides unified access to Windscribe's server APIs with built-in anti-censorship bypass methods, along with DNS resolution, HTTP networking, and ping functionality.
The library uses:
- **Boost.ASIO** for async I/O (single io_context thread model)
- **libcurl** (with ECH patches) for HTTP requests
- **c-ares** for asynchronous DNS resolution
- **OpenSSL** (with ECH patches) for TLS
- **Scapix** for automatic C++ → Java/Swift bindings on mobile platforms
- **vcpkg** for dependency management
## Building
### Desktop (Windows/Mac/Linux)
The library integrates via vcpkg. CMake must be installed along with platform-specific C++ compiler (Visual C++/XCode/clang).
**Build with tests (desktop only):**
```bash
cmake -B build -S . \
-DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake \
-DIS_BUILD_TESTS=ON
cmake --build build
```
**Run tests:**
```bash
./build/test/wsnet_test
```
Tests use Google Test and are located in `src/private/tests/`. Tests are only built when `IS_BUILD_TESTS` is defined and are excluded from mobile builds.
### Android
**Requirements:** Android Studio, `$VCPKG_ROOT` and `$JAVA_HOME` environment variables set.
```bash
cd tools
./build_android.sh
```
Output: `wsnet.aar` (Android Archive ready for integration)
### iOS
**Requirements:** XCode, `$VCPKG_ROOT` environment variable set.
```bash
cd tools
./build_ios.sh
```
Output: `build/WSNet.xcframework` (supports iOS, iOS Simulator, tvOS, tvOS Simulator)
## Architecture
### Core Components
The library is accessed through a singleton `WSNet::instance()` after initialization. Main components:
- **ServerAPI** - Main Windscribe API access (login, session, server locations, WireGuard configs, etc.) with full failover support
- **BridgeAPI** - Legacy Bridge protocol API (IP rotation, simple session-based, no failover)
- **DnsResolver** - Async DNS with custom server support and caching
- **HttpNetworkManager** - HTTP client with custom DNS integration and TLS modifications (SNI spoofing, ECH)
- **EmergencyConnect** - Fallback connectivity via hardcoded OpenVPN endpoints
- **PingManager** - ICMP and HTTP ping functionality
- **DecoyTraffic** - Traffic obfuscation features
- **ApiResourcesManager** - Manages API resources like server lists
All async operations return `shared_ptr<WSNetCancelableCallback>` for cancellation and use callback pattern.
### Public/Private Build System
The codebase has a **dual-build configuration**:
- **`src/private/`** - Production build with proprietary censorship bypass methods (16+ failover strategies including ECH, CDN fronting, dynamic domains). Contains `privatesettings.h` with hardcoded (obfuscated) endpoints and credentials.
- **`src/public/`** - Open-source fallback with minimal failover (only hardcoded domains).
CMake automatically selects private if it exists, otherwise uses public. Both implement the same `IFailoverContainer` interface.
### Failover Mechanism
ServerAPI uses a **hierarchical failover system** to bypass censorship:
1. Each request goes through `RequestExecutorViaFailover`
2. Tries failovers sequentially (tracked by UUID to prevent loops)
3. Each `BaseFailover` returns `FailoverData` containing:
- `domain` - Target domain
- `sniDomain` - SNI for domain fronting
- `echConfig` - Encrypted Client Hello configuration
- `ttl` - Time-to-live for dynamic failovers
4. If all failovers fail → returns `ApiRetCode::kFailoverFailed`
Failover types (private build): hardcoded domains → ECH with Cloudflare → dynamic Cloudflare → dynamic Google DoH → direct IP access → CDN fronting (Fastly/Yelp/PyPI).
### Mobile Bindings (Scapix)
For Android/iOS builds, Scapix automatically generates Java/Swift bindings from C++ headers:
- All public headers in `include/wsnet/WSNet*.h` are bridged
- Each header must contain exactly one class matching the filename (Java requirement)
- All public classes inherit from `scapix_object<T>` (empty on desktop, actual bridge on mobile)
- Generated code: `generated/bridge/java/com/wsnet/lib/` (Android) or `generated/bridge/objc/` (iOS)
Android-specific: Custom JNI with thread auto-attach and class loader caching.
iOS-specific: Builds as framework with Objective-C bridge headers.
### Threading Model
- Single worker thread runs Boost.ASIO `io_context`
- All callbacks dispatched to this thread
- Thread-safe from client perspective (can call from any thread)
- Protected by mutexes where needed (e.g., `PersistentSettings`)
### Key Patterns
1. **Pimpl** - Public interfaces delegate to `*_impl` classes for ABI stability
2. **Async callbacks** - All I/O returns cancelable callbacks with guaranteed invocation (unless canceled)
3. **Request queueing** - ServerAPI queues requests during failover attempts
4. **Persistent state** - Client must save/restore settings via `serverAPI()->currentSettings()` for optimal failover performance
5. **State management** - `ConnectState` tracks device online/offline and VPN connection status
## Common Development Tasks
### Adding a new ServerAPI endpoint
1. Add method signature to `include/wsnet/WSNetServerAPI.h`
2. Implement in `src/api/serverapi/serverapi_impl.h` and `.cpp`
3. Create a `Request` subclass (e.g., `MyIPRequest`) that inherits from `BaseRequest`
4. Override `getUrl()`, `getPlatformNamePostfix()`, and optionally `execute()`
5. Use `RequestExecutorViaFailover` helper for automatic failover handling
### Running a single test
Tests are Google Test based:
```bash
./build/test/wsnet_test --gtest_filter=TestSuiteName.TestName
```
Test files are in `src/private/tests/` and named `*.test.cpp`.
### Code Coverage
Coverage is enabled automatically when building with tests on non-Windows platforms:
```bash
# Build with coverage
cmake -B build -S . -DIS_BUILD_TESTS=ON \
-DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
cmake --build build
# Run tests
./build/test/wsnet_test
# Generate coverage report (requires lcov)
lcov --capture --directory build --output-file coverage.info
lcov --remove coverage.info '/usr/*' --output-file coverage.info # Remove system files
genhtml coverage.info --output-directory coverage_report
```
## Important Constraints
### ServerAPI State Management
Clients **must**:
1. Call `serverAPI()->setConnectivityState(bool)` when device connectivity changes
2. Call `serverAPI()->setIsConnectedToVpnState(bool)` when VPN state changes
3. Save `serverAPI()->currentSettings()` to persistent storage before shutdown
4. Restore settings via `WSNet::initialize(..., serverApiSettings)` on startup
This enables the library to remember the last working failover method for faster recovery.
### Request Behavior
- Requests can be called from any thread in any order
- Callbacks are **always** invoked unless explicitly canceled
- Callback timing is unpredictable (can be long during failover attempts)
- Return codes:
- `kSuccess = 0` - JSON data is valid and usable
- `kNetworkError = 1`, `kNoNetworkConnection = 2` - Retry recommended
- `kFailoverFailed = 3` - All bypass methods failed; recommend user enable "ignore SSL errors"
### Public Headers
When adding new public APIs:
- Filename must start with `WSNet` prefix
- Filename must match class name exactly (e.g., `WSNetFoo.h``class WSNetFoo`)
- Must be in `include/wsnet/` directory
- Must inherit from `scapix_object<ClassName>` for mobile compatibility
## File Locations
- **Public API**: `include/wsnet/WSNet*.h`
- **Implementation**: `src/api/`, `src/httpnetworkmanager/`, `src/dnsresolver/`, etc.
- **Failover logic**: `src/private/failover/` or `src/public/failover/`
- **Tests**: `src/private/tests/*.test.cpp`
- **Resources**: `resources/` (embedded via CMakeRC as `wsnet::rc`)
- **Build scripts**: `tools/build_android.sh`, `tools/build_ios.sh`
## Dependencies (vcpkg)
Main dependencies managed via vcpkg:
- `c-ares` - DNS resolution
- `curl` - HTTP (with ECH patches from private vcpkg registry)
- `openssl` - TLS (with ECH patches from private vcpkg registry)
- `spdlog` - Logging
- `rapidjson` - JSON parsing
- `skyr-url` - URL parsing
- `boost-filesystem` - File operations
- `gtest` - Testing
- `scapix` - Mobile bindings (Android/iOS only)
- `cmakerc` - Resource embedding
Custom patches for curl/openssl are in the private vcpkg registry: `ws/client/client-libs/ws-vcpkg-registry.git`
-160
View File
@@ -1,160 +0,0 @@
cmake_minimum_required(VERSION 3.21)
set(CMAKE_OSX_DEPLOYMENT_TARGET "12" CACHE STRING "Minimum OS X deployment version")
set(X_VCPKG_APPLOCAL_DEPS_INSTALL ON)
if (VCPKG_TARGET_ANDROID)
include("cmake/vcpkg_android.cmake")
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
##TODO:
#set(CMAKE_CXX_VISIBILITY_PRESET hidden)
#set(CMAKE_VISIBILITY_INLINES_HIDDEN True)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
project(wsnet
DESCRIPTION "The wsnet library for Windscribe client programs"
LANGUAGES CXX
)
find_package(c-ares CONFIG REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(CURL CONFIG REQUIRED)
find_package(spdlog CONFIG REQUIRED)
find_package(RapidJSON CONFIG REQUIRED)
find_package(skyr-url CONFIG REQUIRED)
find_package(GTest CONFIG REQUIRED)
find_package(CMakeRC)
find_path(CPP_BASE64_INCLUDE_DIRS "cpp-base64/base64.cpp")
find_package(Boost REQUIRED COMPONENTS filesystem)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
else()
message(STATUS "Boost NOT Found !")
endif(Boost_FOUND)
find_path(ADVOBFUSCATOR_INCLUDE_DIRS "Lib/Indexes.h")
# Get all public headers
# Each public header file must have one class and the file name must match the class name (Java language requirement).
# The file name must begin with the prefix "WSNet".
file(GLOB WS_CPP_PUBLIC_HEADERS RELATIVE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include/wsnet/WSNet*.h)
cmrc_add_resource_library(
cert-resources
ALIAS wsnet::rc
NAMESPACE wsnet
resources/certs_bundle.pem
resources/windscribe_cert.crt
resources/emergency.ovpn
)
set_property(TARGET cert-resources PROPERTY POSITION_INDEPENDENT_CODE ON)
if (WIN32)
add_library(wsnet STATIC ${WS_CPP_PUBLIC_HEADERS})
else()
add_library(wsnet SHARED ${WS_CPP_PUBLIC_HEADERS})
endif()
add_library(wsnet::wsnet ALIAS wsnet)
target_compile_features(wsnet PUBLIC cxx_std_17)
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 (APPLE)
set(OS_SPECIFIC_LIBRARIES "-framework Foundation" "-framework CFNetwork")
target_compile_options(wsnet PRIVATE "-fobjc-arc")
endif()
target_link_libraries(wsnet PRIVATE c-ares::cares CURL::libcurl spdlog::spdlog rapidjson skyr::skyr-url OpenSSL::SSL wsnet::rc Boost::filesystem ${OS_SPECIFIC_LIBRARIES})
target_include_directories(wsnet PRIVATE
${PROJECT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include/wsnet ${CMAKE_CURRENT_SOURCE_DIR}/src
${CPP_BASE64_INCLUDE_DIRS} ${ADVOBFUSCATOR_INCLUDE_DIRS}
)
if (WIN32)
target_compile_definitions(wsnet PRIVATE CMAKE_LIBRARY_LIBRARY
WINVER=0x0601
_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
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
# let the preprocessor know about Apple platform
if(APPLE)
target_compile_definitions(wsnet PUBLIC "IS_APPLE")
endif()
# For Android and iOS using the scapix library for automatic binding to Java/Objective C languages
if(ANDROID OR IOS)
target_compile_definitions(wsnet PUBLIC "IS_MOBILE_PLATFORM")
find_package(scapix CONFIG REQUIRED)
scapix_bridge_headers(wsnet "com.wsnet.lib" ${WS_CPP_PUBLIC_HEADERS})
endif()
if(ANDROID)
target_compile_definitions(wsnet PUBLIC SCAPIX_CUSTOM_JNI_ONLOAD SCAPIX_CACHE_CLASS_LOADER SCAPIX_JAVA_AUTO_ATTACH_THREAD)
target_link_options(wsnet PUBLIC "-Wl,-z,max-page-size=16384")
endif()
if (IOS)
foreach (CPP_HEADER ${WS_CPP_PUBLIC_HEADERS})
string(REGEX REPLACE "include/wsnet" "generated/bridge/objc/lib/bridge" OBJ ${CPP_HEADER})
set(WS_OBJC_PUBLIC_HEADERS ${WS_OBJC_PUBLIC_HEADERS} ${OBJ})
endforeach ()
set_target_properties(wsnet PROPERTIES
FRAMEWORK TRUE
MACOSX_FRAMEWORK_IDENTIFIER com.cmake.wsnet
PUBLIC_HEADER "${WS_OBJC_PUBLIC_HEADERS}"
)
# This file is also used by the above generated headers, so copy it to framework headers
install(FILES ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/src/scapix/source/scapix/bridge/objc/BridgeObject.h
DESTINATION wsnet.framework/Headers/scapix/bridge/objc
)
endif()
# Strip binary for release builds (in particular for Android for some reason this is not done automatically)
if(ANDROID)
add_custom_command(
TARGET "${CMAKE_PROJECT_NAME}" POST_BUILD
DEPENDS "${CMAKE_PROJECT_NAME}"
COMMAND $<$<CONFIG:release>:${CMAKE_STRIP}>
ARGS --strip-all $<TARGET_FILE:${CMAKE_PROJECT_NAME}>)
else()
##TODO:
#add_custom_command(
# TARGET "${CMAKE_PROJECT_NAME}" POST_BUILD
# DEPENDS "${CMAKE_PROJECT_NAME}"
# COMMAND $<$<CONFIG:release>:${CMAKE_STRIP}>
# ARGS -u $<TARGET_FILE:${CMAKE_PROJECT_NAME}>
#)
endif()
if(ANDROID OR IOS)
install(TARGETS wsnet
LIBRARY DESTINATION .
FRAMEWORK DESTINATION .
)
else()
#install(TARGETS wsnet EXPORT wsnet-targets)
endif()
add_subdirectory(src)
-339
View File
@@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
-193
View File
@@ -1,193 +0,0 @@
**wsnet** is a library that is designed for Windscribe clients for all platforms Windows/Mac/Linux/Android/iOS providing access to server APIs in a unified way. Also contains some other networking features such as an asynchronous DNS resolver with the ability to use custom DNS servers and a http network manager with some much needed Windscribe client specific features.
# Motivation
The server API can be accessed by several dozen anti-censorship bypass methods. Implementation and debugging all of these methods for each platform is rather laborious and difficult to test. So the library hides all these details and provides clients with a single and simple interface. Further modification of the server API access methods will only require changes to the library code. Also the library uses libraries like curl and openssl modified by ECH patches + our own to bypass censorship. Some such methods may be difficult or unrealizable to implement separately for Android/iOS platforms.
# Features
* Support for any architecture (x64, arm64 and so on) and platforms (Windows/Mac/Linux/Android/iOS).
* Ability to connect the library to a project via vcpkg tool (this is more relevant for desktop platforms).
* Asynchronous DNS resolver with support for custom DNS servers.
* Asynchronous HTTP manager providing the ability to whitelist IP-addresses in the firewall via callback functions.
* Asynchronous access to the Windscribe Server API with the ability to switch to staging servers.
* Implemented several dozen methods to bypass censorship used when accessing the server API.
* Functionality for ICMP and HTTP pinging.
* The library maintains logs that can be passed to the client.
* Asynchronous and thread-safe.
* Ready to use in Android and iOS immediately without writing additional code. Connection to Android and iOS projects through aar file and framework accordingly.
* Has automatic and semi-automatic tests. Tested with fairly good code coverage.
# How to build
The C++ compiler (XCode/Visual C++/clang), vcpkg tool and cmake must be installed before build.
## Desktop
To use the library in a desktop project, it is recommended to use vcpkg. Example of vcpkg settings to use the library.
vcpkg.json
```
{
"dependencies": ["wsnet"]
}
```
vcpkg-configuration.json
```
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg-configuration.schema.json",
"default-registry": {
"kind": "git",
"repository": "https://github.com/microsoft/vcpkg",
"baseline": "61f610845fb206298a69f708104a51d651872877"
},
"registries": [
{
"kind": "git",
"repository": "git@gitlab.int.windscribe.com:ws/client/client-libs/ws-vcpkg-registry.git",
"baseline": "0bff463c4aa39cdd251337a36e43f8eb9c05cb57",
"packages": [ "openssl", "curl", "wsnet"]
}
]
}
```
The vcpkg port and some of its dependencies(curl, openssl) are in the repository: `ws/client/client-libs/ws-vcpkg-registry.git`
## Android
* Android Studio must be installed.
* Run the build script: `build_android.sh`.
* Get a file `wsnet.aar` ready to use.
## iOS
* Run the build script: `build_ios.sh`.
* Get a framework `wsnet.framework` ready to use.
# How to use
The library must be initialized before it can be used, once during the lifetime of the application. Once initialized, all library functionality is available through a global instance of the WSNet class.
It is also recommended to install the logger callback function if necessary.
After finishing using the library, it is recommended to call the cleanup function, although not necessarily. The library will be cleaned in any case when the program finished. After calling cleanup, all pending callback functions will be canceled.
### Example (initialization):
```
#inlude <wsnet/WSNet.h>
using namespace wsnet;
void logger(const std::string &str)
{
printf("%s\n", str.c_str());
}
int main()
{
WSNet::setLogger(logger);
WSNet::initialize("macos", "2.7.10", false, "");
auto wsnet = WSNet::instance();
// Working with the library
....
WSNet::cleanup();
return 0;
}
```
``
### Example (Dns resolver):
```
wsnet->dnsResolver()->setDnsServers({ "1.1.1.1", "1.0.0.1"});
// Blocking DNS resolution, waiting until complete
auto res = wsnet->dnsResolver()->lookupBlocked("google.com");
// work with res
...
// Asynchronous DNS resolution
auto callback = [](std::uint64_t requestId, const std::string &hostname, std::shared_ptr<WSNetDnsRequestResult> result)
{
};
auto request = wsnet->dnsResolver()->lookup("google.com", 0, callback);
// To cancel a request early, you can call: request->cancel()
```
### Example (Server API):
```
wsnet->serverApi()->myIP([](ServerApiRetCode serverApiRetCode, const std::string &jsonData) {
printf("%s\n", jsonData.c_str());
});
```
All asynchronous functions (implying the return of the result after some time) take a callback function as a parameter and return an object(CancelableCallback), through which the client can cancel the request early, if required. After canceling the request, the callback function is guaranteed not to be called. It is important that the function exists in memory at the time the callback is called. If the callback function is being removed from memory, you should call cancel for the request before doing so. If you don't need to cancel the request, you can ignore the return value(CancelableCallback).
All library functions/classes are fairly obvious and documented in the public library header files (todo: link here). So look there for full documentation.
Example code for Android(Kotlin):
```
val logFunc = WSNet.Function0 { strLog : String ->
runOnUiThread {
// out log
}
}
WSNet.setLogger(logFunc)
WSNet.initialize("android", "1.1", false, "")
WSNet.instance().serverAPI().myIP({ serverApiRetCode: Int, jsonData: String ->
Log.v("Windscribe", jsonData)
})
```
Note: It is necessary to connect `wsnet.aar` file to the project before use the library.
Example for iOS(Swift):
```
let loggerFunc = { [](logStr: String) -> Void in
print(logStr)
}
WSNet.setLogger(loggerFunc)
WSNet.initialize("ios", appVersion: "1.1", isUseStagingDomains: false, serverApiSettings: "")
let wsnet = WSNet.instance()
wsnet.serverAPI().setIgnoreSslErrors(false)
wsnet.serverAPI().myIP(
{ [](requestId: Int32, data: String) -> Void in
print(data)
})
```
Note: It is necessary to add `wsnet.framework` folder to the project before use the library. It is also necessary to create a bridging header and import the necessary library header files there.
# ServerAPI Notes
For the most part, ServerAPI functionality is what will mostly be used from this library. Here are some notes on how to work with it properly.
For serverAPI to work efficiently, it needs to save some settings to persistent storage. In particular this is the latest working method of circumventing censorship.
Thus the client before finalization should call `string settings = serverAPI()->currentSettings()` and save the `settings` string to persistent storage.
When initializing the client, you should restore the settings from the storage and transfer them with the last parameter when initializing the library.
```
string serverApiSettings = readStringFromPersistentStorage();
WSNet::initialize("macos", "2.7.10", false, serverApiSettings);
```
Also the client must call functions `serverAPI()->setConnectivityState(bool isOnline)` when the connectivity state changes and `severAPI()->setIsConnectedToVpnState(bool isConnected)` when the VPN connectivity state changes.
The client can also control options such as whether to ignore SSL errors and set api resolution settings. The setTryingBackupEndpointCallback function can be useful when you want to show progress when searching for working failovers. In particular, this is implemented in the desktop client at the login stage.
Keep in mind that the ServerAPI server functions can be called in any order any number of times from any thread. The callback function will be guaranteed to be called (unless of course it has been canceled) but the time after which it will be called can be any. It can also be quite long while the failovers are being gone through.
The following results may be returned in the callback function:
* *kSuccess = 0*. Successful execution and the json data can be used. The json is guaranteed to be correct(it will definitely be json and will contain fields such as data and error(if this field is present).
* *kNetworkError = 1*, *kNoNetworkConnection = 2*. Various network errors, it is recommended to repeat the request from the client side
* *kFailoverFailed = 3*. This means that all failovers have been tried and none of them work. In this case, it is recommended to prompt the user to ignore SSL-errors and try the queries again. Otherwise, there's nothing more we can do. There will be no connection to the server API.
# Further improvements
* For Server API functions to make results return as wrapper classes instead of raw json data?
-703
View File
@@ -1,703 +0,0 @@
#
# Copyright (C) 2018-2020 by George Cave - gcave@stablecoder.ca
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
# USAGE: To enable any code coverage instrumentation/targets, the single CMake
# option of `CODE_COVERAGE` needs to be set to 'ON', either by GUI, ccmake, or
# on the command line.
#
# From this point, there are two primary methods for adding instrumentation to
# targets: 1 - A blanket instrumentation by calling `add_code_coverage()`, where
# all targets in that directory and all subdirectories are automatically
# instrumented. 2 - Per-target instrumentation by calling
# `target_code_coverage(<TARGET_NAME>)`, where the target is given and thus only
# that target is instrumented. This applies to both libraries and executables.
#
# To add coverage targets, such as calling `make ccov` to generate the actual
# coverage information for perusal or consumption, call
# `target_code_coverage(<TARGET_NAME>)` on an *executable* target.
#
# Example 1: All targets instrumented
#
# In this case, the coverage information reported will will be that of the
# `theLib` library target and `theExe` executable.
#
# 1a: Via global command
#
# ~~~
# add_code_coverage() # Adds instrumentation to all targets
#
# add_library(theLib lib.cpp)
#
# add_executable(theExe main.cpp)
# target_link_libraries(theExe PRIVATE theLib)
# target_code_coverage(theExe) # As an executable target, adds the 'ccov-theExe' target (instrumentation already added via global anyways) for generating code coverage reports.
# ~~~
#
# 1b: Via target commands
#
# ~~~
# add_library(theLib lib.cpp)
# target_code_coverage(theLib) # As a library target, adds coverage instrumentation but no targets.
#
# add_executable(theExe main.cpp)
# target_link_libraries(theExe PRIVATE theLib)
# target_code_coverage(theExe) # As an executable target, adds the 'ccov-theExe' target and instrumentation for generating code coverage reports.
# ~~~
#
# Example 2: Target instrumented, but with regex pattern of files to be excluded
# from report
#
# ~~~
# add_executable(theExe main.cpp non_covered.cpp)
# target_code_coverage(theExe EXCLUDE non_covered.cpp test/*) # As an executable target, the reports will exclude the non-covered.cpp file, and any files in a test/ folder.
# ~~~
#
# Example 3: Target added to the 'ccov' and 'ccov-all' targets
#
# ~~~
# add_code_coverage_all_targets(EXCLUDE test/*) # Adds the 'ccov-all' target set and sets it to exclude all files in test/ folders.
#
# add_executable(theExe main.cpp non_covered.cpp)
# target_code_coverage(theExe AUTO ALL EXCLUDE non_covered.cpp test/*) # As an executable target, adds to the 'ccov' and ccov-all' targets, and the reports will exclude the non-covered.cpp file, and any files in a test/ folder.
# ~~~
# Options
option(
CODE_COVERAGE
"Builds targets with code coverage instrumentation. (Requires GCC or Clang)"
OFF)
# Programs
find_program(LLVM_COV_PATH llvm-cov)
find_program(LLVM_PROFDATA_PATH llvm-profdata)
find_program(LCOV_PATH lcov)
find_program(GENHTML_PATH genhtml)
# Hide behind the 'advanced' mode flag for GUI/ccmake
mark_as_advanced(FORCE LLVM_COV_PATH LLVM_PROFDATA_PATH LCOV_PATH GENHTML_PATH)
# Variables
set(CMAKE_COVERAGE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/ccov)
set_property(GLOBAL PROPERTY JOB_POOLS ccov_serial_pool=1)
# Common initialization/checks
if(CODE_COVERAGE AND NOT CODE_COVERAGE_ADDED)
set(CODE_COVERAGE_ADDED ON)
# Common Targets
file(MAKE_DIRECTORY ${CMAKE_COVERAGE_OUTPUT_DIRECTORY})
if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang"
OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
if(CMAKE_C_COMPILER_ID MATCHES "AppleClang" OR CMAKE_CXX_COMPILER_ID
MATCHES "AppleClang")
# When on macOS and using the Apple-provided toolchain, use the
# XCode-provided llvm toolchain via `xcrun`
message(
STATUS
"Building with XCode-provided llvm code coverage tools (via `xcrun`)")
set(LLVM_COV_PATH xcrun llvm-cov)
set(LLVM_PROFDATA_PATH xcrun llvm-profdata)
else()
# Use the regular llvm toolchain
message(STATUS "Building with llvm code coverage tools")
endif()
if(NOT LLVM_COV_PATH)
message(FATAL_ERROR "llvm-cov not found! Aborting.")
else()
# Version number checking for 'EXCLUDE' compatibility
execute_process(COMMAND ${LLVM_COV_PATH} --version
OUTPUT_VARIABLE LLVM_COV_VERSION_CALL_OUTPUT)
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" LLVM_COV_VERSION ${LLVM_COV_VERSION_CALL_OUTPUT})
if(LLVM_COV_VERSION VERSION_LESS "7.0.0")
message(
WARNING
"target_code_coverage()/add_code_coverage_all_targets() 'EXCLUDE' option only available on llvm-cov >= 7.0.0"
)
endif()
endif()
# Targets
if(${CMAKE_VERSION} VERSION_LESS "3.17.0")
add_custom_target(
ccov-clean
COMMAND ${CMAKE_COMMAND} -E remove -f
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list
COMMAND ${CMAKE_COMMAND} -E remove -f
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list)
else()
add_custom_target(
ccov-clean
COMMAND ${CMAKE_COMMAND} -E rm -f
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list
COMMAND ${CMAKE_COMMAND} -E rm -f
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list)
endif()
# Used to get the shared object file list before doing the main all-
# processing
add_custom_target(
ccov-libs
COMMAND ;
COMMENT "libs ready for coverage report.")
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES
"GNU")
# Messages
message(STATUS "Building with lcov Code Coverage Tools")
if(CMAKE_BUILD_TYPE)
string(TOUPPER ${CMAKE_BUILD_TYPE} upper_build_type)
if(NOT ${upper_build_type} STREQUAL "DEBUG")
message(
WARNING
"Code coverage results with an optimized (non-Debug) build may be misleading"
)
endif()
else()
message(
WARNING
"Code coverage results with an optimized (non-Debug) build may be misleading"
)
endif()
if(NOT LCOV_PATH)
message(FATAL_ERROR "lcov not found! Aborting...")
endif()
if(NOT GENHTML_PATH)
message(FATAL_ERROR "genhtml not found! Aborting...")
endif()
# Targets
add_custom_target(ccov-clean COMMAND ${LCOV_PATH} --directory
${CMAKE_BINARY_DIR} --zerocounters)
else()
message(FATAL_ERROR "Code coverage requires Clang or GCC. Aborting.")
endif()
endif()
# Adds code coverage instrumentation to a library, or instrumentation/targets
# for an executable target.
# ~~~
# EXECUTABLE ADDED TARGETS:
# GCOV/LCOV:
# ccov : Generates HTML code coverage report for every target added with 'AUTO' parameter.
# ccov-${TARGET_NAME} : Generates HTML code coverage report for the associated named target.
# ccov-all : Generates HTML code coverage report, merging every target added with 'ALL' parameter into a single detailed report.
#
# LLVM-COV:
# ccov : Generates HTML code coverage report for every target added with 'AUTO' parameter.
# ccov-report : Generates HTML code coverage report for every target added with 'AUTO' parameter.
# ccov-${TARGET_NAME} : Generates HTML code coverage report.
# ccov-report-${TARGET_NAME} : Prints to command line summary per-file coverage information.
# ccov-export-${TARGET_NAME} : Exports the coverage report to a JSON file.
# ccov-show-${TARGET_NAME} : Prints to command line detailed per-line coverage information.
# ccov-all : Generates HTML code coverage report, merging every target added with 'ALL' parameter into a single detailed report.
# ccov-all-report : Prints summary per-file coverage information for every target added with ALL' parameter to the command line.
# ccov-all-export : Exports the coverage report to a JSON file.
#
# Required:
# TARGET_NAME - Name of the target to generate code coverage for.
# Optional:
# PUBLIC - Sets the visibility for added compile options to targets to PUBLIC instead of the default of PRIVATE.
# INTERFACE - Sets the visibility for added compile options to targets to INTERFACE instead of the default of PRIVATE.
# PLAIN - Do not set any target visibility (backward compatibility with old cmake projects)
# AUTO - Adds the target to the 'ccov' target so that it can be run in a batch with others easily. Effective on executable targets.
# ALL - Adds the target to the 'ccov-all' and 'ccov-all-report' targets, which merge several executable targets coverage data to a single report. Effective on executable targets.
# EXTERNAL - For GCC's lcov, allows the profiling of 'external' files from the processing directory
# COVERAGE_TARGET_NAME - For executables ONLY, changes the outgoing target name so instead of `ccov-${TARGET_NAME}` it becomes `ccov-${COVERAGE_TARGET_NAME}`.
# EXCLUDE <PATTERNS> - Excludes files of the patterns provided from coverage. Note that GCC/lcov excludes by glob pattern, and clang/LLVM excludes via regex! **These do not copy to the 'all' targets.**
# OBJECTS <TARGETS> - For executables ONLY, if the provided targets are shared libraries, adds coverage information to the output
# PRE_ARGS <ARGUMENTS> - For executables ONLY, prefixes given arguments to the associated ccov-* executable call ($<PRE_ARGS> ccov-*)
# ARGS <ARGUMENTS> - For executables ONLY, appends the given arguments to the associated ccov-* executable call (ccov-* $<ARGS>)
# ~~~
function(target_code_coverage TARGET_NAME)
# Argument parsing
set(options AUTO ALL EXTERNAL PUBLIC INTERFACE PLAIN)
set(single_value_keywords COVERAGE_TARGET_NAME)
set(multi_value_keywords EXCLUDE OBJECTS PRE_ARGS ARGS)
cmake_parse_arguments(
target_code_coverage "${options}" "${single_value_keywords}"
"${multi_value_keywords}" ${ARGN})
# Set the visibility of target functions to PUBLIC, INTERFACE or default to
# PRIVATE.
if(target_code_coverage_PUBLIC)
set(TARGET_VISIBILITY PUBLIC)
set(TARGET_LINK_VISIBILITY PUBLIC)
elseif(target_code_coverage_INTERFACE)
set(TARGET_VISIBILITY INTERFACE)
set(TARGET_LINK_VISIBILITY INTERFACE)
elseif(target_code_coverage_PLAIN)
set(TARGET_VISIBILITY PUBLIC)
set(TARGET_LINK_VISIBILITY)
else()
set(TARGET_VISIBILITY PRIVATE)
set(TARGET_LINK_VISIBILITY PRIVATE)
endif()
if(NOT target_code_coverage_COVERAGE_TARGET_NAME)
# If a specific name was given, use that instead.
set(target_code_coverage_COVERAGE_TARGET_NAME ${TARGET_NAME})
endif()
if(CODE_COVERAGE)
# Add code coverage instrumentation to the target's linker command
if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang"
OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
target_compile_options(${TARGET_NAME} ${TARGET_VISIBILITY}
-fprofile-instr-generate -fcoverage-mapping)
target_link_options(${TARGET_NAME} ${TARGET_VISIBILITY}
-fprofile-instr-generate -fcoverage-mapping)
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES
"GNU")
target_compile_options(
${TARGET_NAME} ${TARGET_VISIBILITY} -fprofile-arcs -ftest-coverage
$<$<COMPILE_LANGUAGE:CXX>:-fno-elide-constructors> -fno-default-inline)
target_link_libraries(${TARGET_NAME} ${TARGET_LINK_VISIBILITY} gcov)
endif()
# Targets
get_target_property(target_type ${TARGET_NAME} TYPE)
# Add shared library to processing for 'all' targets
if(target_type STREQUAL "SHARED_LIBRARY" AND target_code_coverage_ALL)
if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang"
OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
add_custom_target(
ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND
${CMAKE_COMMAND} -E echo "-object=$<TARGET_FILE:${TARGET_NAME}>" >>
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list
DEPENDS ${TARGET_NAME})
if(NOT TARGET ccov-libs)
message(
FATAL_ERROR
"Calling target_code_coverage with 'ALL' must be after a call to 'add_code_coverage_all_targets'."
)
endif()
add_dependencies(ccov-libs
ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME})
endif()
endif()
# For executables add targets to run and produce output
if(target_type STREQUAL "EXECUTABLE")
if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang"
OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
# If there are shared objects to also work with, generate the string to
# add them here
foreach(SO_TARGET ${target_code_coverage_OBJECTS})
# Check to see if the target is a shared object
if(TARGET ${SO_TARGET})
get_target_property(SO_TARGET_TYPE ${SO_TARGET} TYPE)
if(${SO_TARGET_TYPE} STREQUAL "SHARED_LIBRARY")
set(SO_OBJECTS ${SO_OBJECTS} -object=$<TARGET_FILE:${SO_TARGET}>)
endif()
endif()
endforeach()
# Run the executable, generating raw profile data Make the run data
# available for further processing. Separated to allow Windows to run
# this target serially.
add_custom_target(
ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND
${CMAKE_COMMAND} -E env ${CMAKE_CROSSCOMPILING_EMULATOR}
${target_code_coverage_PRE_ARGS}
LLVM_PROFILE_FILE=${target_code_coverage_COVERAGE_TARGET_NAME}.profraw
$<TARGET_FILE:${TARGET_NAME}> ${target_code_coverage_ARGS}
COMMAND
${CMAKE_COMMAND} -E echo "-object=$<TARGET_FILE:${TARGET_NAME}>"
${SO_OBJECTS} >> ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list
COMMAND
${CMAKE_COMMAND} -E echo
"${CMAKE_CURRENT_BINARY_DIR}/${target_code_coverage_COVERAGE_TARGET_NAME}.profraw"
>> ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list
JOB_POOL ccov_serial_pool
DEPENDS ccov-libs ${TARGET_NAME})
# Merge the generated profile data so llvm-cov can process it
add_custom_target(
ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND
${LLVM_PROFDATA_PATH} merge -sparse
${target_code_coverage_COVERAGE_TARGET_NAME}.profraw -o
${target_code_coverage_COVERAGE_TARGET_NAME}.profdata
DEPENDS ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME})
# Ignore regex only works on LLVM >= 7
if(LLVM_COV_VERSION VERSION_GREATER_EQUAL "7.0.0")
foreach(EXCLUDE_ITEM ${target_code_coverage_EXCLUDE})
set(EXCLUDE_REGEX ${EXCLUDE_REGEX}
-ignore-filename-regex='${EXCLUDE_ITEM}')
endforeach()
endif()
# Print out details of the coverage information to the command line
add_custom_target(
ccov-show-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND
${LLVM_COV_PATH} show $<TARGET_FILE:${TARGET_NAME}> ${SO_OBJECTS}
-instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata
-show-line-counts-or-regions ${EXCLUDE_REGEX}
DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME})
# Print out a summary of the coverage information to the command line
add_custom_target(
ccov-report-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND
${LLVM_COV_PATH} report $<TARGET_FILE:${TARGET_NAME}> ${SO_OBJECTS}
-instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata
${EXCLUDE_REGEX}
DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME})
# Export coverage information so continuous integration tools (e.g.
# Jenkins) can consume it
add_custom_target(
ccov-export-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND
${LLVM_COV_PATH} export $<TARGET_FILE:${TARGET_NAME}> ${SO_OBJECTS}
-instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata
-format="text" ${EXCLUDE_REGEX} >
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}.json
DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME})
# Generates HTML output of the coverage information for perusal
add_custom_target(
ccov-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND
${LLVM_COV_PATH} show $<TARGET_FILE:${TARGET_NAME}> ${SO_OBJECTS}
-instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata
-show-line-counts-or-regions
-output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}
-format="html" ${EXCLUDE_REGEX}
DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME})
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES
"GNU")
set(COVERAGE_INFO
"${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}.info"
)
# Run the executable, generating coverage information
add_custom_target(
ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND
${CMAKE_CROSSCOMPILING_EMULATOR} ${target_code_coverage_PRE_ARGS}
$<TARGET_FILE:${TARGET_NAME}> ${target_code_coverage_ARGS}
DEPENDS ${TARGET_NAME})
# Generate exclusion string for use
foreach(EXCLUDE_ITEM ${target_code_coverage_EXCLUDE})
set(EXCLUDE_REGEX ${EXCLUDE_REGEX} --remove ${COVERAGE_INFO}
'${EXCLUDE_ITEM}')
endforeach()
if(EXCLUDE_REGEX)
set(EXCLUDE_COMMAND ${LCOV_PATH} ${EXCLUDE_REGEX} --output-file
${COVERAGE_INFO})
else()
set(EXCLUDE_COMMAND ;)
endif()
if(NOT ${target_code_coverage_EXTERNAL})
set(EXTERNAL_OPTION --no-external)
endif()
# Capture coverage data
if(${CMAKE_VERSION} VERSION_LESS "3.17.0")
add_custom_target(
ccov-capture-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND ${CMAKE_COMMAND} -E remove -f ${COVERAGE_INFO}
COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters
COMMAND
${CMAKE_CROSSCOMPILING_EMULATOR} ${target_code_coverage_PRE_ARGS}
$<TARGET_FILE:${TARGET_NAME}> ${target_code_coverage_ARGS}
COMMAND
${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --base-directory
${CMAKE_SOURCE_DIR} --capture ${EXTERNAL_OPTION} --output-file
${COVERAGE_INFO}
COMMAND ${EXCLUDE_COMMAND}
DEPENDS ${TARGET_NAME})
else()
add_custom_target(
ccov-capture-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND ${CMAKE_COMMAND} -E rm -f ${COVERAGE_INFO}
COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters
COMMAND
${CMAKE_CROSSCOMPILING_EMULATOR} ${target_code_coverage_PRE_ARGS}
$<TARGET_FILE:${TARGET_NAME}> ${target_code_coverage_ARGS}
COMMAND
${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --base-directory
${CMAKE_SOURCE_DIR} --capture ${EXTERNAL_OPTION} --output-file
${COVERAGE_INFO}
COMMAND ${EXCLUDE_COMMAND}
DEPENDS ${TARGET_NAME})
endif()
# Generates HTML output of the coverage information for perusal
add_custom_target(
ccov-${target_code_coverage_COVERAGE_TARGET_NAME}
COMMAND
${GENHTML_PATH} -o
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}
${COVERAGE_INFO}
DEPENDS ccov-capture-${target_code_coverage_COVERAGE_TARGET_NAME})
endif()
add_custom_command(
TARGET ccov-${target_code_coverage_COVERAGE_TARGET_NAME}
POST_BUILD
COMMAND ;
COMMENT
"Open ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}/index.html in your browser to view the coverage report."
)
# AUTO
if(target_code_coverage_AUTO)
if(NOT TARGET ccov)
add_custom_target(ccov)
endif()
add_dependencies(ccov ccov-${target_code_coverage_COVERAGE_TARGET_NAME})
if(NOT CMAKE_C_COMPILER_ID MATCHES "GNU" AND NOT CMAKE_CXX_COMPILER_ID
MATCHES "GNU")
if(NOT TARGET ccov-report)
add_custom_target(ccov-report)
endif()
add_dependencies(
ccov-report
ccov-report-${target_code_coverage_COVERAGE_TARGET_NAME})
endif()
endif()
# ALL
if(target_code_coverage_ALL)
if(NOT TARGET ccov-all-processing)
message(
FATAL_ERROR
"Calling target_code_coverage with 'ALL' must be after a call to 'add_code_coverage_all_targets'."
)
endif()
add_dependencies(ccov-all-processing
ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME})
endif()
endif()
endif()
endfunction()
# Adds code coverage instrumentation to all targets in the current directory and
# any subdirectories. To add coverage instrumentation to only specific targets,
# use `target_code_coverage`.
function(add_code_coverage)
if(CODE_COVERAGE)
if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang"
OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
add_link_options(-fprofile-instr-generate -fcoverage-mapping)
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES
"GNU")
add_compile_options(
-fprofile-arcs -ftest-coverage
$<$<COMPILE_LANGUAGE:CXX>:-fno-elide-constructors> -fno-default-inline)
link_libraries(gcov)
endif()
endif()
endfunction()
# Adds the 'ccov-all' type targets that calls all targets added via
# `target_code_coverage` with the `ALL` parameter, but merges all the coverage
# data from them into a single large report instead of the numerous smaller
# reports. Also adds the ccov-all-capture Generates an all-merged.info file, for
# use with coverage dashboards (e.g. codecov.io, coveralls).
# ~~~
# Optional:
# EXCLUDE <PATTERNS> - Excludes files of the patterns provided from coverage. Note that GCC/lcov excludes by glob pattern, and clang/LLVM excludes via regex!
# ~~~
function(add_code_coverage_all_targets)
# Argument parsing
set(multi_value_keywords EXCLUDE)
cmake_parse_arguments(add_code_coverage_all_targets "" ""
"${multi_value_keywords}" ${ARGN})
if(CODE_COVERAGE)
if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang"
OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
# Merge the profile data for all of the run executables
if(WIN32)
add_custom_target(
ccov-all-processing
COMMAND
powershell -Command $$FILELIST = Get-Content
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list\; llvm-profdata.exe
merge -o ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata
-sparse $$FILELIST)
else()
add_custom_target(
ccov-all-processing
COMMAND
${LLVM_PROFDATA_PATH} merge -o
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata -sparse `cat
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list`)
endif()
# Regex exclude only available for LLVM >= 7
if(LLVM_COV_VERSION VERSION_GREATER_EQUAL "7.0.0")
foreach(EXCLUDE_ITEM ${add_code_coverage_all_targets_EXCLUDE})
set(EXCLUDE_REGEX ${EXCLUDE_REGEX}
-ignore-filename-regex='${EXCLUDE_ITEM}')
endforeach()
endif()
# Print summary of the code coverage information to the command line
if(WIN32)
add_custom_target(
ccov-all-report
COMMAND
powershell -Command $$FILELIST = Get-Content
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list\; llvm-cov.exe
report $$FILELIST
-instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata
${EXCLUDE_REGEX}
DEPENDS ccov-all-processing)
else()
add_custom_target(
ccov-all-report
COMMAND
${LLVM_COV_PATH} report `cat
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list`
-instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata
${EXCLUDE_REGEX}
DEPENDS ccov-all-processing)
endif()
# Export coverage information so continuous integration tools (e.g.
# Jenkins) can consume it
if(WIN32)
add_custom_target(
ccov-all-export
COMMAND
powershell -Command $$FILELIST = Get-Content
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list\; llvm-cov.exe
export $$FILELIST
-instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata
-format="text" ${EXCLUDE_REGEX} >
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/coverage.json
DEPENDS ccov-all-processing)
else()
add_custom_target(
ccov-all-export
COMMAND
${LLVM_COV_PATH} export `cat
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list`
-instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata
-format="text" ${EXCLUDE_REGEX} >
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/coverage.json
DEPENDS ccov-all-processing)
endif()
# Generate HTML output of all added targets for perusal
if(WIN32)
add_custom_target(
ccov-all
COMMAND
powershell -Command $$FILELIST = Get-Content
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list\; llvm-cov.exe show
$$FILELIST
-instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata
-show-line-counts-or-regions
-output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged
-format="html" ${EXCLUDE_REGEX}
DEPENDS ccov-all-processing)
else()
add_custom_target(
ccov-all
COMMAND
${LLVM_COV_PATH} show `cat
${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list`
-instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata
-show-line-counts-or-regions
-output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged
-format="html" ${EXCLUDE_REGEX}
DEPENDS ccov-all-processing)
endif()
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES
"GNU")
set(COVERAGE_INFO "${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.info")
# Nothing required for gcov
add_custom_target(ccov-all-processing COMMAND ;)
# Exclusion regex string creation
set(EXCLUDE_REGEX)
foreach(EXCLUDE_ITEM ${add_code_coverage_all_targets_EXCLUDE})
set(EXCLUDE_REGEX ${EXCLUDE_REGEX} --remove ${COVERAGE_INFO}
'${EXCLUDE_ITEM}')
endforeach()
if(EXCLUDE_REGEX)
set(EXCLUDE_COMMAND ${LCOV_PATH} ${EXCLUDE_REGEX} --output-file
${COVERAGE_INFO})
else()
set(EXCLUDE_COMMAND ;)
endif()
# Capture coverage data
if(${CMAKE_VERSION} VERSION_LESS "3.17.0")
add_custom_target(
ccov-all-capture
COMMAND ${CMAKE_COMMAND} -E remove -f ${COVERAGE_INFO}
COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --capture
--output-file ${COVERAGE_INFO}
COMMAND ${EXCLUDE_COMMAND}
DEPENDS ccov-all-processing)
else()
add_custom_target(
ccov-all-capture
COMMAND ${CMAKE_COMMAND} -E rm -f ${COVERAGE_INFO}
COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --capture
--output-file ${COVERAGE_INFO}
COMMAND ${EXCLUDE_COMMAND}
DEPENDS ccov-all-processing)
endif()
# Generates HTML output of all targets for perusal
add_custom_target(
ccov-all
COMMAND ${GENHTML_PATH} -o ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged
${COVERAGE_INFO} -p ${CMAKE_SOURCE_DIR}
DEPENDS ccov-all-capture)
endif()
add_custom_command(
TARGET ccov-all
POST_BUILD
COMMAND ;
COMMENT
"Open ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged/index.html in your browser to view the coverage report."
)
endif()
endfunction()
-4
View File
@@ -1,4 +0,0 @@
@PACKAGE_INIT@
include(${CMAKE_CURRENT_LIST_DIR}/wsnet-targets.cmake)
check_required_components(wsnet)
File diff suppressed because it is too large Load Diff
-78
View File
@@ -1,78 +0,0 @@
Subject: [PATCH] Added tv simulator support.
---
Index: triplets/community/arm64-ios-simulator.cmake
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/triplets/community/arm64-ios-simulator.cmake b/triplets/community/arm64-ios-simulator.cmake
--- a/triplets/community/arm64-ios-simulator.cmake (revision a2367ceec5f092d8777606ca110426cadd7ed7db)
+++ b/triplets/community/arm64-ios-simulator.cmake (date 1722967895545)
@@ -3,3 +3,4 @@
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME iOS)
set(VCPKG_OSX_SYSROOT iphonesimulator)
+set(CMAKE_OSX_SYSROOT iphonesimulator)
Index: triplets/community/arm64-tvos-simulator.cmake
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/triplets/community/arm64-tvos-simulator.cmake b/triplets/community/arm64-tvos-simulator.cmake
new file mode 100644
--- /dev/null (date 1723045409401)
+++ b/triplets/community/arm64-tvos-simulator.cmake (date 1723045409401)
@@ -0,0 +1,6 @@
+set(VCPKG_TARGET_ARCHITECTURE arm64)
+set(VCPKG_CRT_LINKAGE dynamic)
+set(VCPKG_LIBRARY_LINKAGE static)
+set(VCPKG_CMAKE_SYSTEM_NAME iOS)
+set(VCPKG_OSX_SYSROOT appletvsimulator)
+set(CMAKE_OSX_SYSROOT appletvsimulator)
\ No newline at end of file
Index: scripts/cmake/vcpkg_configure_cmake.cmake
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scripts/cmake/vcpkg_configure_cmake.cmake b/scripts/cmake/vcpkg_configure_cmake.cmake
--- a/scripts/cmake/vcpkg_configure_cmake.cmake (revision a2367ceec5f092d8777606ca110426cadd7ed7db)
+++ b/scripts/cmake/vcpkg_configure_cmake.cmake (date 1723046387153)
@@ -177,7 +177,13 @@
"${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg")
if(DEFINED VCPKG_CMAKE_SYSTEM_NAME)
- vcpkg_list(APPEND arg_OPTIONS "-DCMAKE_SYSTEM_NAME=${VCPKG_CMAKE_SYSTEM_NAME}")
+ if(VCPKG_OSX_SYSROOT STREQUAL "appletvos")
+ vcpkg_list(APPEND arg_OPTIONS "-DCMAKE_SYSTEM_NAME=tvOS")
+ elseif(VCPKG_OSX_SYSROOT STREQUAL "appletvsimulator")
+ vcpkg_list(APPEND arg_OPTIONS "-DCMAKE_SYSTEM_NAME=tvOS")
+ else()
+ vcpkg_list(APPEND arg_OPTIONS "-DCMAKE_SYSTEM_NAME=${VCPKG_CMAKE_SYSTEM_NAME}")
+ endif()
if(VCPKG_TARGET_IS_UWP AND NOT DEFINED VCPKG_CMAKE_SYSTEM_VERSION)
set(VCPKG_CMAKE_SYSTEM_VERSION 10.0)
elseif(VCPKG_TARGET_IS_ANDROID AND NOT DEFINED VCPKG_CMAKE_SYSTEM_VERSION)
Index: scripts/toolchains/ios.cmake
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/scripts/toolchains/ios.cmake b/scripts/toolchains/ios.cmake
--- a/scripts/toolchains/ios.cmake (revision a2367ceec5f092d8777606ca110426cadd7ed7db)
+++ b/scripts/toolchains/ios.cmake (date 1723047724902)
@@ -22,7 +22,13 @@
)
# Set the CMAKE_SYSTEM_NAME for try_compile calls.
- set(CMAKE_SYSTEM_NAME iOS CACHE STRING "")
+ if(CMAKE_OSX_SYSROOT STREQUAL "appletvos")
+ set(CMAKE_SYSTEM_NAME tvOS CACHE STRING "" FORCE)
+ elseif(CMAKE_OSX_SYSROOT STREQUAL "appletvsimulator")
+ set(CMAKE_SYSTEM_NAME tvOS CACHE STRING "" FORCE)
+ else()
+ set(CMAKE_SYSTEM_NAME iOS CACHE STRING "")
+ endif()
macro(_vcpkg_setup_ios_arch arch)
unset(_vcpkg_ios_system_processor)
-99
View File
@@ -1,99 +0,0 @@
#
# vcpkg_android.cmake
#
# Helper script when using vcpkg with cmake. It should be triggered via the variable VCPKG_TARGET_ANDROID
#
# For example:
# if (VCPKG_TARGET_ANDROID)
# include("cmake/vcpkg_android.cmake")
# endif()
#
# This script will:
# 1 & 2. check the presence of needed env variables: ANDROID_NDK_HOME and VCPKG_ROOT
# 3. set VCPKG_TARGET_TRIPLET according to ANDROID_ABI
# 4. Combine vcpkg and Android toolchains by setting CMAKE_TOOLCHAIN_FILE
# and VCPKG_CHAINLOAD_TOOLCHAIN_FILE
# Note: VCPKG_TARGET_ANDROID is not an official vcpkg variable.
# it is introduced for the need of this script
if (VCPKG_TARGET_ANDROID)
#
# 1. Check the presence of environment variable ANDROID_NDK_HOME
#
if (NOT DEFINED ENV{ANDROID_NDK_HOME})
message(FATAL_ERROR "
Please set an environment variable ANDROID_NDK_HOME
For example:
export ANDROID_NDK_HOME=/home/your-account/Android/Sdk/ndk-bundle
Or:
export ANDROID_NDK_HOME=/home/your-account/Android/android-ndk-r21b
")
endif()
#
# 2. Check the presence of environment variable VCPKG_ROOT
#
if (NOT DEFINED ENV{VCPKG_ROOT})
message(FATAL_ERROR "
Please set an environment variable VCPKG_ROOT
For example:
export VCPKG_ROOT=/path/to/vcpkg
")
endif()
#
# 3. Set VCPKG_TARGET_TRIPLET according to ANDROID_ABI
#
# There are four different Android ABI, each of which maps to
# a vcpkg triplet. The following table outlines the mapping from vcpkg architectures to android architectures
#
# |VCPKG_TARGET_TRIPLET | ANDROID_ABI |
# |---------------------------|----------------------|
# |arm64-android | arm64-v8a |
# |arm-android | armeabi-v7a |
# |x64-android | x86_64 |
# |x86-android | x86 |
#
# The variable must be stored in the cache in order to successfully the two toolchains.
#
if (ANDROID_ABI MATCHES "arm64-v8a")
set(VCPKG_TARGET_TRIPLET "arm64-android" CACHE STRING "" FORCE)
elseif(ANDROID_ABI MATCHES "armeabi-v7a")
set(VCPKG_TARGET_TRIPLET "arm-neon-android" CACHE STRING "" FORCE)
elseif(ANDROID_ABI MATCHES "x86_64")
set(VCPKG_TARGET_TRIPLET "x64-android" CACHE STRING "" FORCE)
elseif(ANDROID_ABI MATCHES "x86")
set(VCPKG_TARGET_TRIPLET "x86-android" CACHE STRING "" FORCE)
else()
message(FATAL_ERROR "
Please specify ANDROID_ABI
For example
cmake ... -DANDROID_ABI=armeabi-v7a
Possible ABIs are: arm64-v8a, armeabi-v7a, x64-android, x86-android
")
endif()
message("vcpkg_android.cmake: VCPKG_TARGET_TRIPLET was set to ${VCPKG_TARGET_TRIPLET}")
#
# 4. Combine vcpkg and Android toolchains
#
# vcpkg and android both provide dedicated toolchains:
#
# vcpkg_toolchain_file=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
# android_toolchain_file=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake
#
# When using vcpkg, the vcpkg toolchain shall be specified first.
# However, vcpkg provides a way to preload and additional toolchain,
# with the VCPKG_CHAINLOAD_TOOLCHAIN_FILE option.
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE $ENV{ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake)
set(CMAKE_TOOLCHAIN_FILE $ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
message("vcpkg_android.cmake: CMAKE_TOOLCHAIN_FILE was set to ${CMAKE_TOOLCHAIN_FILE}")
message("vcpkg_android.cmake: VCPKG_CHAINLOAD_TOOLCHAIN_FILE was set to ${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}")
endif(VCPKG_TARGET_ANDROID)
-59
View File
@@ -1,59 +0,0 @@
#pragma once
#include "scapix_object.h"
#include "exported.h"
#include "WSNetDnsResolver.h"
#include "WSNetHttpNetworkManager.h"
#include "WSNetBridgeAPI.h"
#include "WSNetServerAPI.h"
#include "WSNetEmergencyConnect.h"
#include "WSNetPingManager.h"
#include "WSNetAdvancedParameters.h"
#include "WSNetApiResourcesManager.h"
#include "WSNetDecoyTraffic.h"
#include "WSNetUtils.h"
namespace wsnet {
typedef std::function<void(const std::string &)> WSNetLoggerFunction;
class EXPORTED WSNet : public scapix_object<WSNet>
{
public:
virtual ~WSNet() {}
// basePlatform value can be "windows", "mac", "linux", "android", "ios"
// platformName and appVersion values are added to each request.
// difference between basePlatform and platformName is that platformName is more specific (for example windows_arm64/windows).
// deviceId - unique device identifier, in particular used for the API StaticIps
// must supply sessionTypeId, where 3 = DESKTOP, 4 = MOBILE (ios and android) to get an appropriate session type token
// set debugLog to true for more verbose log output
static bool initialize(const std::string &basePlatform, const std::string &platformName, const std::string &appVersion,
const std::string &deviceId, const std::string &openVpnVersion, const std::string &sessionTypeId,
bool isUseStagingDomains, const std::string &language, const std::string &persistentSettings,
WSNetLoggerFunction loggerFunction, bool debugLog, const std::string &amneziawgVersion);
static std::shared_ptr<WSNet> instance();
static void cleanup();
static bool isValid();
virtual void setConnectivityState(bool isOnline) = 0;
virtual void setIsConnectedToVpnState(bool isConnected) = 0;
virtual std::string currentPersistentSettings() = 0;
virtual std::shared_ptr<WSNetDnsResolver> dnsResolver() = 0;
virtual std::shared_ptr<WSNetHttpNetworkManager> httpNetworkManager() = 0;
virtual std::shared_ptr<WSNetBridgeAPI> bridgeAPI() = 0;
virtual std::shared_ptr<WSNetServerAPI> serverAPI() = 0;
virtual std::shared_ptr<WSNetApiResourcesManager> apiResourcersManager() = 0;
virtual std::shared_ptr<WSNetEmergencyConnect> emergencyConnect() = 0;
virtual std::shared_ptr<WSNetPingManager> pingManager() = 0;
virtual std::shared_ptr<WSNetDecoyTraffic> decoyTraffic() = 0;
virtual std::shared_ptr<WSNetAdvancedParameters> advancedParameters() = 0;
virtual std::shared_ptr<WSNetUtils> utils() = 0;
};
} // namespace wsnet
@@ -1,28 +0,0 @@
#pragma once
#include <string>
#include "scapix_object.h"
namespace wsnet {
// Advanced parameters that affect the functioning of some parts of the library
class WSNetAdvancedParameters : public scapix_object<WSNetAdvancedParameters>
{
public:
virtual ~WSNetAdvancedParameters() {}
virtual void setAPIExtraTLSPadding(bool isEnabled) = 0;
virtual bool isAPIExtraTLSPadding() const = 0;
virtual void setIgnoreCountryOverride(bool isIgnore) = 0;
virtual bool isIgnoreCountryOverride() const = 0;
// pass an empty string if don't need to override the country
virtual void setCountryOverrideValue(const std::string &country) = 0;
virtual std::string countryOverrideValue() const = 0;
virtual void setLogApiResponce(bool isEnabled) = 0;
virtual bool isLogApiResponce() const = 0;
};
} // namespace wsnet
@@ -1,128 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include <functional>
#include <memory>
#include "scapix_object.h"
#include "WSNetCancelableCallback.h"
#include "WSNetServerAPI.h"
namespace wsnet {
enum class ApiResourcesManagerNotification {
kLoginOk = 0, // login was successful and API resources (SessionStatus, Locations, ServerCredentials(both openvpn and ikev2), ServerConfigs, PortMap, StatisIPS) are ready for use
kLoginFailed, // login failed, returns error code in LoginResult variable and error message in string
kSessionUpdated, // SessionStatus
kSessionDeleted,
kServerCredentialsUpdated, // ServerCredentials(both openvpn and ikev2), ServerConfigs
kLocationsUpdated,
kStaticIpsUpdated,
kNotificationsUpdated,
kCheckUpdate,
kLogoutFinished,
kAuthTokenLoginFinished,
kAmneziawgUnblockParamsFinished
};
enum class LoginResult {
kSuccess = 0,
kNoApiConnectivity,
kNoConnectivity,
kIncorrectJson,
kBadUsername,
kSslError,
kBadCode2fa,
kMissingCode2fa,
kAccountDisabled,
kSessionInvalid,
kRateLimited,
kInvalidSecurityToken
};
typedef std::function<void(ApiResourcesManagerNotification notification, LoginResult loginResult, const std::string &errorMessage)> WSNetApiResourcesManagerCallback;
// The class provides management of API resources such as SessionStatus, Locations, ServerCredentials,
// ServerConfigs, PortMap, StatisIPS, Notifications, CheckUpdate.
// Also stores the last received resources in a persistent storage.
// Also ensures that resources are updated according to the schedule and notifies the client of this via callback functions.
// When using this class in the client, you should not call the following functions from WSNetServerAPI:
// login, session, deleteSession, serverLocations, serverCredentials, serverConfigs, portMap, checkUpdate, staticIps, notifications.
class WSNetApiResourcesManager : public scapix_object<WSNetApiResourcesManager>
{
public:
virtual ~WSNetApiResourcesManager() {}
// callback function for notifications
virtual std::shared_ptr<WSNetCancelableCallback> setCallback(WSNetApiResourcesManagerCallback callback) = 0;
// Set an existing authHash. Made so that when updating from older versions of the program, where the hash is stored in other settings, the user does not need to log in again.
virtual void setAuthHash(const std::string &authHash) = 0;
// Is there all the API data in a persistent repository?
// They can be from the last time the program was run or they can be fresh.
// If they are present, the client is ready to work and switch to the connect screen.
virtual bool isExist() const = 0;
// login with saved session authHash, return false if no saved authHash, true otherwise.
// Returns the result in the notifications kLoginOk/kLoginFailed
virtual bool loginWithAuthHash() = 0;
// authTokenLogin call, must be called before login API call. Required for two stage login + CAPTCHA
virtual void authTokenLogin(const std::string &username, bool useAsciiCaptcha) = 0;
// login with username/password
// optionally send captcha data
// Returns the result in the notifications kLoginOk/kLoginFailed
virtual void login(const std::string &username, const std::string &password, const std::string &code2fa,
const std::string &secureToken,
const std::string &captchaSolution = std::string(),
const std::vector<float> &captchaTrailX = std::vector<float>(),
const std::vector<float> &captchaTrailY = std::vector<float>()) = 0;
// does session deletion and deletes all saved data from persistent storage
virtual void logout() = 0;
// force update session right now without regard to scheduling
virtual void fetchSession() = 0;
// force update the server credentials(openvpn and ikev2) and openvpn config right now without regard to scheduling
// Notify with kServerCredentialsUpdated code.
virtual void fetchServerCredentials() = 0;
// return current authHash or empty string, if no authHash
virtual std::string authHash() = 0;
// remove all saved API data from persistent settings
virtual void removeFromPersistentSettings() = 0;
// makes an immediate call to check update and runs a regular update every 24 hours
virtual void checkUpdate(UpdateChannel channel, const std::string &appVersion, const std::string &appBuild,
const std::string &osVersion, const std::string &osBuild) = 0;
// pcpid used for Notifications API call
virtual void setNotificationPcpid(const std::string &pcpid) = 0;
// appleId or gpDeviceId (ios or android) device ID, set them empty if they are not required
virtual void setMobileDeviceId(const std::string &appleId, const std::string &gpDeviceId) = 0;
// the following functions return the current API data in json format
virtual std::string sessionStatus() const = 0;
virtual std::string portMap() const = 0;
virtual std::string locations() const = 0;
virtual std::string staticIps() const = 0;
virtual std::string serverCredentialsOvpn() const = 0;
virtual std::string serverCredentialsIkev2() const = 0;
virtual std::string serverConfigs() const = 0;
virtual std::string notifications() const = 0;
virtual std::string checkUpdate() const = 0;
virtual std::string authTokenLoginResult() const = 0;
virtual std::string amneziawgUnblockParams() const = 0;
// this function is for debugging purposes, allows to set arbitrary resource update intervals
virtual void setUpdateIntervals(int sessionInDisconnectedStateMs, int sessionInConnectedStateMs,
int locationsMs, int staticIpsMs, int serverConfigsAndCredentialsMs,
int portMapMs, int notificationsMs, int checkUpdateMs, int amneziawgUnblockParamsMs) = 0;
};
} // namespace wsnet
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include <functional>
#include <memory>
#include <string>
#include "scapix_object.h"
#include "WSNetCancelableCallback.h"
#include "WSNetServerAPI.h"
namespace wsnet {
using WSNetApiAvailableCallback = std::function<void(bool isAvailable)>;
class WSNetBridgeAPI : public scapix_object<WSNetBridgeAPI>
{
public:
virtual ~WSNetBridgeAPI() {}
virtual void setConnectedState(bool isConnected) = 0;
virtual void setIgnoreSslErrors(bool bIgnore) = 0;
virtual bool hasSessionToken() const = 0;
virtual void setApiAvailableCallback(WSNetApiAvailableCallback callback) = 0;
virtual void setCurrentHost(const std::string &host) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> rotateIp(WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> pinIp(const std::string &ip, WSNetRequestFinishedCallback callback) = 0;
};
} // namespace wsnet
@@ -1,17 +0,0 @@
#pragma once
#include "scapix_object.h"
namespace wsnet {
// You should call cancel(...) if you don't want the callback to be called. If callback has already been called, then cancel(...) has no effect.
class WSNetCancelableCallback : public scapix_object<WSNetCancelableCallback>
{
public:
virtual ~WSNetCancelableCallback() {}
virtual void cancel() = 0;
};
} // namespace wsnet
@@ -1,23 +0,0 @@
#pragma once
#include "scapix_object.h"
#include <cstdint>
namespace wsnet {
// Providing decoy traffic functionality
class WSNetDecoyTraffic : public scapix_object<WSNetDecoyTraffic>
{
public:
virtual ~WSNetDecoyTraffic() {}
// 0 - low, 1 - medium, 2 - high
virtual void setFakeTrafficVolume(std::uint32_t volume) = 0;
virtual void start() = 0;
virtual void stop() = 0;
};
} // namespace wsnet
@@ -1,23 +0,0 @@
#pragma once
#include <cstdint>
#include <vector>
#include <string>
#include <memory>
#include "scapix_object.h"
#include "WSNetRequestError.h"
namespace wsnet {
class WSNetDnsRequestResult : public scapix_object<WSNetDnsRequestResult>
{
public:
virtual ~WSNetDnsRequestResult() {}
virtual std::vector<std::string> ips() const = 0;
virtual std::uint32_t elapsedMs() const = 0;
virtual std::shared_ptr<WSNetRequestError> error() const = 0;
};
} // namespace wsnet
@@ -1,29 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include <functional>
#include <memory>
#include "scapix_object.h"
#include "WSNetDnsRequestResult.h"
#include "WSNetCancelableCallback.h"
namespace wsnet {
typedef std::function<void(std::uint64_t requestId, const std::string &hostname, std::shared_ptr<WSNetDnsRequestResult> result)> WSNetDnsResolverCallback;
// Async thread safe DNS resolver, you can call class functions from any thread.
class WSNetDnsResolver : public scapix_object<WSNetDnsResolver>
{
public:
virtual ~WSNetDnsResolver() {}
virtual void setDnsServers(const std::vector<std::string> &dnsServers) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> lookup(const std::string &hostname, std::uint64_t requestId, WSNetDnsResolverCallback callback) = 0;
virtual std::shared_ptr<WSNetDnsRequestResult> lookupBlocked(const std::string &hostname) = 0;
};
} // namespace wsnet
@@ -1,28 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include <functional>
#include "scapix_object.h"
#include "WSNetEmergencyConnectEndpoint.h"
#include "WSNetCancelableCallback.h"
namespace wsnet {
typedef std::function<void(const std::vector<std::shared_ptr<WSNetEmergencyConnectEndpoint>> &endpoints)> WSNetEmergencyConnectCallback;
// Emergency connect functionality
class WSNetEmergencyConnect : public scapix_object<WSNetEmergencyConnect>
{
public:
virtual ~WSNetEmergencyConnect() {}
virtual std::string ovpnConfig() const = 0;
virtual std::string username() const = 0;
virtual std::string password() const = 0;
// Returns a ready-to-use list of endpoints(ip, port, protocol), already randomized
virtual std::shared_ptr<WSNetCancelableCallback> getIpEndpoints(WSNetEmergencyConnectCallback callback) = 0;
};
} // namespace wsnet
@@ -1,23 +0,0 @@
#pragma once
#include <string>
#include "scapix_object.h"
namespace wsnet {
enum class Protocol {
kUdp = 0,
kTcp
};
class WSNetEmergencyConnectEndpoint : public scapix_object<WSNetEmergencyConnectEndpoint>
{
public:
virtual ~WSNetEmergencyConnectEndpoint() {}
virtual std::string ip() const = 0;
virtual std::uint16_t port() const = 0;
virtual Protocol protocol() const = 0;
};
} // namespace wsnet
@@ -1,73 +0,0 @@
#pragma once
#include <set>
#include <functional>
#include <memory>
#include "scapix_object.h"
#include "WSNetHttpRequest.h"
#include "WSNetCancelableCallback.h"
#include "WSNetRequestError.h"
namespace wsnet {
typedef std::function<void(std::uint64_t requestId, std::uint32_t elapsedMs,
std::shared_ptr<WSNetRequestError> error, const std::string &data)> WSNetHttpNetworkManagerFinishedCallback;
typedef std::function<void(std::uint64_t requestId, std::uint64_t bytesReceived,
std::uint64_t bytesTotal)> WSNetHttpNetworkManagerProgressCallback;
typedef std::function<void(std::uint64_t requestId, const std::string &data)> WSNetHttpNetworkManagerReadyDataCallback;
typedef std::function<void(const std::set<std::string> &ips)> WSNetHttpNetworkManagerWhitelistIpsCallback;
typedef std::function<void(const std::set<int> &sockets)> WSNetHttpNetworkManagerWhitelistSocketsCallback;
// Some simplified implementation of HTTP network manager for our needs based on curl and custom DNS-resolver based on c-ares.
// In particular, it has the functionality to whitelist IP addresses to firewall exceptions.
// It has an internal DNS cache.
// It's thread safe, you can call class functions from any thread.
class WSNetHttpNetworkManager : public scapix_object<WSNetHttpNetworkManager>
{
public:
virtual ~WSNetHttpNetworkManager() {}
// The actual request may take longer than the timeout specified
// This timeout includes time to dns resolution + time to connect to the curl server
// It also depends on the number of IP addresses of the domain.
virtual std::shared_ptr<WSNetHttpRequest> createGetRequest(const std::string &url, std::uint32_t timeoutMs,
bool isIgnoreSslErrors = false) = 0;
virtual std::shared_ptr<WSNetHttpRequest> createPostRequest(const std::string &url, std::uint32_t timeoutMs,
const std::string &data, bool isIgnoreSslErrors = false) = 0;
virtual std::shared_ptr<WSNetHttpRequest> createPutRequest(const std::string &url, std::uint32_t timeoutMs,
const std::string &data, bool isIgnoreSslErrors = false) = 0;
virtual std::shared_ptr<WSNetHttpRequest> createDeleteRequest(const std::string &url, std::uint32_t timeoutMs,
bool isIgnoreSslErrors = false) = 0;
std::shared_ptr<WSNetCancelableCallback> executeRequest(const std::shared_ptr<WSNetHttpRequest> &request, std::uint64_t requestId,
WSNetHttpNetworkManagerFinishedCallback finishedCallback)
{
return executeRequestEx(request, requestId, finishedCallback, nullptr, nullptr);
}
virtual std::shared_ptr<WSNetCancelableCallback> executeRequestEx(const std::shared_ptr<WSNetHttpRequest> &request, std::uint64_t requestId,
WSNetHttpNetworkManagerFinishedCallback finishedCallback,
WSNetHttpNetworkManagerProgressCallback progressCallback = nullptr,
WSNetHttpNetworkManagerReadyDataCallback readyDataCallback = nullptr) = 0;
// to not use a proxy all values must be empty
// address example: https://1.2.3.4:8083, details: https://curl.se/libcurl/c/CURLOPT_PROXY.html
virtual void setProxySettings(const std::string &address = std::string(),
const std::string &username = std::string(),
const std::string &password = std::string()) = 0;
// callback function allowing the caller to add IP-addresses to the firewall exceptions
// this callback function must return control after the firewall is configured
// you can pass null to disable the callback function
virtual std::shared_ptr<WSNetCancelableCallback> setWhitelistIpsCallback(WSNetHttpNetworkManagerWhitelistIpsCallback whitelistIpsCallback) = 0;
};
} // namespace wsnet
@@ -1,82 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "scapix_object.h"
namespace wsnet {
enum class HttpMethod {
kGet = 0,
kPost,
kPut,
kDelete
};
class WSNetHttpRequest : public scapix_object<WSNetHttpRequest>
{
public:
virtual ~WSNetHttpRequest() {}
virtual std::string url() const = 0;
virtual std::uint32_t timeoutMs() const = 0;
virtual std::string postData() const = 0;
virtual HttpMethod method() const = 0;
virtual std::string hostname() const = 0;
virtual std::uint16_t port() const = 0;
// true by default
virtual void setUseDnsCache(bool isUseDnsCache) = 0;
virtual bool isUseDnsCache() const = 0;
// empty by default
virtual void addHttpHeader(const std::string &header) = 0;
virtual std::vector<std::string> httpHeaders() const = 0;
// false by default
virtual void setIgnoreSslErrors(bool isIgnore) = 0;
virtual bool isIgnoreSslErrors() const = 0;
// false by default
virtual void setRemoveFromWhitelistIpsAfterFinish(bool isRemove) = 0;
virtual bool isRemoveFromWhitelistIpsAfterFinish() const = 0;
// empty by default
virtual void setEchConfig(const std::string &echConfig) = 0;
virtual std::string echConfig() const = 0;
// empty by default
virtual void setSniDomain(const std::string &sniDomain) = 0;
virtual std::string sniDomain() const = 0;
virtual std::string sniUrl() const = 0;
// false by default
virtual void setExtraTLSPadding(bool isExtraTLSPadding) = 0;
virtual bool isExtraTLSPadding() const = 0;
// Explicitly specify ip to avoid DNS resolution
// empty by default
virtual void setOverrideIp(const std::string &ip) = 0;
virtual std::string overrideIp() const = 0;
// true by default
virtual void setIsWhiteListIps(bool isWhiteListIps) = 0;
virtual bool isWhiteListIps() const = 0;
// false by default
// makes additional logs through which IP the request was made and its curl error
virtual void setIsDebugLogCurlError(bool isEnabled) = 0;
virtual bool isDebugLogCurlError() const = 0;
// Make a fresh connect (enable curl options CURLOPT_FRESH_CONNECT and CURLOPT_FORBID_REUSE)
// true by default
virtual void setIsEnableFreshConnect(bool bEnabled) = 0;
virtual bool isEnableFreshConnect() const = 0;
// empty by default
virtual void setSessionToken(const std::string &token) = 0;
virtual std::string sessionToken() const = 0;
};
} // namespace wsnet
@@ -1,30 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <functional>
#include <memory>
#include "scapix_object.h"
#include "WSNetCancelableCallback.h"
namespace wsnet {
enum class PingType { kHttp = 0, kIcmp };
typedef std::function<void(const std::string &ip, bool isSuccess, std::int32_t timeMs, bool isFromDisconnectedVpnState)> WSNetPingCallback;
// Useful for testing and debugging purposes
class WSNetPingManager : public scapix_object<WSNetPingManager>
{
public:
virtual ~WSNetPingManager() {}
// ip - required
// hostname - optional for http ping
// pingType: 0 - HTTP, 1 - ICMP
virtual std::shared_ptr<WSNetCancelableCallback> ping(const std::string &ip, const std::string &hostname,
PingType pingType, WSNetPingCallback callback) = 0;
};
} // namespace wsnet
@@ -1,27 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
#include "scapix_object.h"
namespace wsnet {
// A container for a request error, which may contain either a curl error or cares
class WSNetRequestError : public scapix_object<WSNetRequestError>
{
public:
virtual ~WSNetRequestError() {}
virtual bool isSuccess() const = 0;
virtual bool isDnsError() const = 0;
virtual bool isCurlError() const = 0;
virtual std::string toString() const = 0;
// Based on some curl and cares error codes we can assume that the error is caused by the lack of network connectivty
// We need to separate these errors so that we don't have to switch failovers for these types of errors
virtual bool isNoNetworkError() const = 0;
virtual int httpResponseCode() const = 0;
};
} // namespace wsnet
-160
View File
@@ -1,160 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <functional>
#include <memory>
#include "scapix_object.h"
#include "WSNetCancelableCallback.h"
namespace wsnet {
enum class UpdateChannel { kRelease = 0, kBeta, kGuineaPig, kInternal };
enum class ApiRetCode { kSuccess = 0, kNetworkError, kNoNetworkConnection, kIncorrectJson, kFailoverFailed, kNoToken, kBridgeApiError };
typedef ApiRetCode ServerApiRetCode; // for backward compatibility
typedef std::function<void(ApiRetCode apiRetCode, const std::string &jsonData)> WSNetRequestFinishedCallback;
typedef std::function<void(std::uint32_t num, std::uint32_t count)> WSNetTryingBackupEndpointCallback;
class WSNetServerAPI : public scapix_object<WSNetServerAPI>
{
public:
virtual ~WSNetServerAPI() {}
// Set parameters allowing overriding domains (for example, api-php8.windscribe.com, assets-php8.windscribe.com)
// If the corresponding parameter is empty, the override is not used for the corresponding query type
// The default behavior - all values are empty
virtual void setApiResolutionsSettings(const std::string &apiRoot, const std::string &assetsRoot) = 0;
virtual void setIgnoreSslErrors(bool bIgnore) = 0;
// resets the failover state to the initial state
// useful when you need to force reset from a client
virtual void resetFailover() = 0;
// callback function allowing the caller to know which failover is used
virtual std::shared_ptr<WSNetCancelableCallback> setTryingBackupEndpointCallback(WSNetTryingBackupEndpointCallback tryingBackupEndpointCallback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> login(const std::string &username, const std::string &password, const std::string &code2fa,
const std::string &secureToken, const std::string &captchaSolution, const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY,
WSNetRequestFinishedCallback callback) = 0;
// appleId or gpDeviceId (ios or android) device ID, set them empty if they are not required
virtual std::shared_ptr<WSNetCancelableCallback> session(const std::string &authHash, const std::string &appleId,
const std::string &gpDeviceId, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> claimVoucherCode(const std::string &authHash, const std::string &voucherCode, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> deleteSession(const std::string &authHash, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> serverLocations(const std::string &language, const std::string &revision,
bool isPro, const std::vector<std::string> &alcList,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> serverCredentials(const std::string &authHash, bool isOpenVpnProtocol, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> serverConfigs(const std::string &authHash, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> portMap(const std::string &authHash, std::uint32_t version, const std::vector<std::string> &forceProtocols, WSNetRequestFinishedCallback callback) = 0;
// set isDesktop = true for Desktop clients, or set isDesktop = false for Mobile clients
virtual std::shared_ptr<WSNetCancelableCallback> recordInstall(bool isDesktop, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> addEmail(const std::string &authHash, const std::string &email, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> confirmEmail(const std::string &authHash, WSNetRequestFinishedCallback callback) = 0;
// Required: username, password
// Optionals: referringUsername, email
virtual std::shared_ptr<WSNetCancelableCallback> signup(const std::string &username, const std::string &password,
const std::string &referringUsername, const std::string &email,
const std::string &voucherCode, const std::string &secureToken,
const std::string &captchaSolution, const std::vector<float> &captchaTrailX,
const std::vector<float> &captchaTrailY, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> webSession(const std::string &authHash, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> checkUpdate(UpdateChannel updateChannel,
const std::string &appVersion, const std::string &appBuild,
const std::string &osVersion, const std::string &osBuild,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> debugLog(const std::string &username, const std::string &strLog, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> speedRating(const std::string &authHash, const std::string &hostname, const std::string &ip,
std::int32_t rating, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> staticIps(const std::string &authHash, std::uint32_t version, WSNetRequestFinishedCallback callback) = 0;
// use this API call for connectivity tests when a VPN is connected
// this request is always made through the primary domain windscribe.com and also has a backup domain in case the first one returns something unexpecte.
// this request is intended for connectivity tests only and it does not use a failover mechanism.
virtual std::shared_ptr<WSNetCancelableCallback> pingTest(std::uint32_t timeoutMs, WSNetRequestFinishedCallback callback) = 0;
// pcpid parameter is optional and can be empty string
virtual std::shared_ptr<WSNetCancelableCallback> notifications(const std::string &authHash, const std::string &pcpid, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> getRobertFilters(const std::string &authHash, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> setRobertFilter(const std::string &authHash, const std::string &id, std::int32_t status, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> syncRobert(const std::string &authHash, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> wgConfigsInit(const std::string &authHash, const std::string &clientPublicKey,
bool deleteOldestKey, WSNetRequestFinishedCallback callback) = 0;
// wgTtl - optional string parameter, for example "3600"
// this is a wait time before server will discard returned interface address if no handshake is made
// this helps with device sleep/Idle events where network connectivity be restricted to conserve battery periodically
virtual std::shared_ptr<WSNetCancelableCallback> wgConfigsConnect(const std::string &authHash, const std::string &clientPublicKey,
const std::string &hostname, const std::string &deviceId, const std::string &wgTtl,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> wgConfigsPskRekey(const std::string &authHash, const std::string &clientPublicKey,
WSNetRequestFinishedCallback callback) = 0;
// returns your IP address, uses a failover mechanism, so it can work in restricted networks when a VPN is disconnected unlike PingTest
virtual std::shared_ptr<WSNetCancelableCallback> myIP(WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> mobileBillingPlans(const std::string &authHash, const std::string &mobilePlanType, const std::string &promo, int version, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> sendPayment(const std::string &authHash, const std::string &appleID, const std::string &appleData, const std::string &appleSIG,
WSNetRequestFinishedCallback callback) = 0;
// Required: purchaseToken
// Optionals: gpPackageName, gpProductId, type, amazonUserId
virtual std::shared_ptr<WSNetCancelableCallback> verifyPayment(const std::string &authHash,
const std::string &purchaseToken, const std::string &gpPackageName,
const std::string &gpProductId, const std::string &type,
const std::string &amazonUserId,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> postBillingCpid(const std::string &authHash, const std::string &payCpid, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> getXpressLoginCode(WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> verifyXpressLoginCode(const std::string &xpressCode, const std::string &sig, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> sendSupportTicket(const std::string &supportEmail, const std::string &supportName,
const std::string &supportSubject, const std::string &supportMessage,
const std::string &supportCategory,
const std::string &type,
const std::string &channel,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> regToken(WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> signupUsingToken(const std::string &token, WSNetRequestFinishedCallback callback) = 0;
// claimAccount - optional integer but passed as a string. If the string is empty, the parameter is ignored
virtual std::shared_ptr<WSNetCancelableCallback> claimAccount(const std::string &authHash, const std::string &username, const std::string &password,
const std::string &email, const std::string &voucherCode, const std::string &claimAccount,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> shakeData(const std::string &authHash,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> recordShakeForDataScore(const std::string &authHash,
const std::string &score, const std::string &signature,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> verifyTvLoginCode(const std::string &authHash, const std::string &xpressCode,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> cancelAccount(const std::string &authHash, const std::string &password,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> sso(const std::string &provider, const std::string &token,
WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> authTokenLogin(const std::string &username, bool useAsciiCaptcha, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> authTokenSignup(const std::string &username, bool useAsciiCaptcha, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> passwordRecovery(const std::string &email, WSNetRequestFinishedCallback callback) = 0;
virtual std::shared_ptr<WSNetCancelableCallback> amneziawgUnblockParams(const std::string &authHash, WSNetRequestFinishedCallback callback) = 0;
};
} // namespace wsnet
-24
View File
@@ -1,24 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include <functional>
#include "scapix_object.h"
#include "WSNetCancelableCallback.h"
#include "WSNetServerAPI.h"
namespace wsnet {
// Useful for testing and debugging purposes
class WSNetUtils : public scapix_object<WSNetUtils>
{
public:
virtual ~WSNetUtils() {}
virtual std::int32_t failoverCount() const = 0;
virtual std::string failoverName(int failoverInd) const = 0;
virtual std::shared_ptr<WSNetCancelableCallback> myIPViaFailover(int failoverInd, WSNetRequestFinishedCallback callback) = 0;
};
} // namespace wsnet
-31
View File
@@ -1,31 +0,0 @@
#ifndef EXPORTED_H
#define EXPORTED_H
// Define EXPORTED for any platform
#if defined _WIN32 || defined __CYGWIN__
#ifdef WIN_EXPORT
// Exporting...
#ifdef __GNUC__
#define EXPORTED __attribute__ ((dllexport))
#else
#define EXPORTED
#endif
#else
#ifdef __GNUC__
#define EXPORTED __attribute__ ((dllimport))
#else
#define EXPORTED
#endif
#endif
#define NOT_EXPORTED
#else
#if __GNUC__ >= 4
#define EXPORTED __attribute__ ((visibility ("default")))
#define NOT_EXPORTED __attribute__ ((visibility ("hidden")))
#else
#define EXPORTED
#define NOT_EXPORTED
#endif
#endif
#endif // EXPORTED_H
-17
View File
@@ -1,17 +0,0 @@
#pragma once
// Scapix optional integration ( more info -> https://www.scapix.com/language_bridge/optional_integration )
#ifdef SCAPIX_BRIDGE
#include <scapix/bridge/object.h>
template <typename T>
using scapix_object = scapix::bridge::object<T>;
#else
template <typename T>
class scapix_object {};
#endif
File diff suppressed because it is too large Load Diff
-73
View File
@@ -1,73 +0,0 @@
client
dev tun
nobind
auth-user-pass
reneg-sec 432000
resolv-retry infinite
auth SHA512
data-ciphers AES-256-GCM
verb 2
mute-replay-warnings
remote-cert-tls server
persist-key
persist-tun
key-direction 1
<ca>
-----BEGIN CERTIFICATE-----
MIIF3DCCA8SgAwIBAgIJAMsOivWTmu9fMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNV
BAYTAkNBMQswCQYDVQQIDAJPTjEQMA4GA1UEBwwHVG9yb250bzEbMBkGA1UECgwS
V2luZHNjcmliZSBMaW1pdGVkMRMwEQYDVQQLDApPcGVyYXRpb25zMRswGQYDVQQD
DBJXaW5kc2NyaWJlIE5vZGUgQ0EwHhcNMTYwMzA5MDMyNjIwWhcNNDAxMDI5MDMy
NjIwWjB7MQswCQYDVQQGEwJDQTELMAkGA1UECAwCT04xEDAOBgNVBAcMB1Rvcm9u
dG8xGzAZBgNVBAoMEldpbmRzY3JpYmUgTGltaXRlZDETMBEGA1UECwwKT3BlcmF0
aW9uczEbMBkGA1UEAwwSV2luZHNjcmliZSBOb2RlIENBMIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEAruBtLR1Vufd71LeQEqChgHS4AQJ0fSRner0gmZPE
r2TL5uWboOEWXFFoEUTthF+P/N8yy3xRZ8HhG/zKlmJ1xw+7KZRbTADD6shJPj3/
uvTIO80sU+9LmsyKSWuPhQ1NkgNA7rrMTfz9eHJ2MVDs4XCpYWyX9iuAQrHSY6aP
q+4TpCbUgprkM3Gwjh9RSt9IoDoc4CF2bWSaVepUcL9yz/SXLPzFx2OT9rFrDhL3
ryHRzJQ/tA+VD8A7lo8bhOcDqiXgEFmVOZNMLw+r167Qq1Ck7X86yr2mnW/6HK2g
JOvY0/SPKukfGJAiYZKdG+fe4ekyYcAVhDfPJg7rF9wUqPwUzejJyAs1K18JwX94
Y8fnD6vQobjpC3qfHtwQP7Uj2AcI6QC8ytWDegV6UIkHXAMXBQSX5suSQoE11deG
32cy7nyp5vhgy31rTyNoopqlcCAhPm6k0jVVQbvXhLcpTSL8iCCoMdrP28i/xsfv
ktBAkl5giHMdK6hxqWgPI+Bx9uPIhRp3fJ2z8AgFm8g1ARB2ZzQ+OZZ2RUIkJuUK
hi2kUhgKSAQ+eF89aoqDjp/J1miZqGRzt4DovSZfQOeL01RkKHEibAPYCfgHG2ZS
woLoeaxE2vNZiX4dpXiOQYTOIXOwEPZzPvfTQf9T4Kxvx3jzQnt3PzjlMCqKk3Ai
pm8CAwEAAaNjMGEwHQYDVR0OBBYEFEH2v9F2z938Ebngsj9RkVSSgs45MB8GA1Ud
IwQYMBaAFEH2v9F2z938Ebngsj9RkVSSgs45MA8GA1UdEwEB/wQFMAMBAf8wDgYD
VR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQAgI6NgYkVo5rB6yKStgHjj
ZsINsgEvoMuHwkM0YaV22XtKNiHdsiOmY/PGCRemFobTEHk5XHcvcOTWv/D1qVf8
fI21WAoNQVH7h8KEsr4uMGKCB6Lu8l6xALXRMjo1xb6JKBWXwIAzUu691rUD2exT
1E+A5t+xw+gzqV8rWTMIoUaH7O1EKjN6ryGW71Khiik8/ETrP3YT32ZbS2P902iM
Kw9rpmuS0wWhnO5k/iO/6YNA1ZMV5JG5oZvZQYEDk7enLD9HvqazofMuy/Sz/n62
ZCDdQsnabzxl04wwv5Y3JZbV/6bOM520GgdJEoDxviY05ax2Mz05otyBzrAVjFw9
RZt/Ls8ATifu9BusZ2ootvscdIuE3x+ZCl5lvANcFEnvgGw0qpCeASLpsfxwq1dR
gIn7BOiTauFv4eoeFAQvCD+l+EKGWKu3M2y19DgYX94N2+Xs2bwChroaO5e4iFem
MLMuWKZvYgnqS9OAtRSYWbNX/wliiPz7u13yj+qSWgMfu8WPYNQlMZJXuGWUvKLE
XCUExlu7/o8D4HpsVs30E0pUdaqN0vExB1KegxPWWrmLcYnPG3knXpkC3ZBZ5P/e
l/2eyhZRy9ydiITF8gM3L08E8aeqvzZMw2FDSmousydIzlXgeS5VuEf+lUFA2h8o
ZYGQgrLt+ot8MbLhJlkp4Q==
-----END CERTIFICATE-----
</ca>
<tls-auth>
-----BEGIN OpenVPN Static key V1-----
5801926a57ac2ce27e3dfd1dd6ef8204
2d82bd4f3f0021296f57734f6f1ea714
a6623845541c4b0c3dea0a050fe6746c
b66dfab14cda27e5ae09d7c155aa554f
399fa4a863f0e8c1af787e5c602a801d
3a2ec41e395a978d56729457fe6102d7
d9e9119aa83643210b33c678f9d4109e
3154ac9c759e490cb309b319cf708cae
83ddadc3060a7a26564d1a24411cd552
fe6620ea16b755697a4fc5e6e9d0cfc0
c5c4a1874685429046a424c026db672e
4c2c492898052ba59128d46200b40f88
0027a8b6610a4d559bdc9346d33a0a6b
08e75c7fd43192b162bfd0aef0c716b3
1584827693f676f9a5047123466f0654
eade34972586b31c6ce7e395f4b478cb
-----END OpenVPN Static key V1-----
</tls-auth>
-105
View File
@@ -1,105 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIGKjCCBBKgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgaYxCzAJBgNVBAYTAkNB
MQswCQYDVQQIDAJPTjEQMA4GA1UEBwwHVG9yb250bzEbMBkGA1UECgwSV2luZHNj
cmliZSBMaW1pdGVkMRMwEQYDVQQLDApPcGVyYXRpb25zMR8wHQYDVQQDDBZXaW5k
c2NyaWJlIEludGVybmFsIENBMSUwIwYJKoZIhvcNAQkBFhZzeXN0ZW1zQHdpbmRz
Y3JpYmUuY29tMB4XDTE2MDIxMDIwNTI0N1oXDTI2MDIwNzIwNTI0N1owgaAxCzAJ
BgNVBAYTAkNBMQswCQYDVQQIDAJPTjEbMBkGA1UECgwSV2luZHNjcmliZSBMaW1p
dGVkMRMwEQYDVQQLDApPcGVyYXRpb25zMSswKQYDVQQDDCJXaW5kc2NyaWJlIExp
bWl0ZWQgSW50ZXJtZWRpYXRlIENBMSUwIwYJKoZIhvcNAQkBFhZzeXN0ZW1zQHdp
bmRzY3JpYmUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwaBj
CHqTAUJs6+StzQlIlj60Ds+oP/3LLt3abMbvW9VXY4+pUlt78Yhmf2UD1RvpSYKT
N1lYJVHKme/EjOWrUiWpV04R234acQaUNe9o5n230FWzwcUWkinSkCLzKBQh0kop
4dA1yeMRaTJBUCGdSkdkU7+JrOctYRoHyNBMYUQqOiUuL53zYPcPahGhKRbM1ZXK
sOPuXIgMMHF/NyBycJdBAM2N/thoIw/IIyWC84jxs1z0t01W8oNsdpahsCiNu/yi
jOdgASRVGNuBoxlO6pI+ox2giO26nAGOfHhCYs/z1eBdLKakKLymVowL3gdrj3ux
eyVTFD0AZvKuXY8YovtTyF6+1UBrjOrx2vlq36lVkQrq4cWIdLKA5peolbGPs4hT
+k4LB0EEbDL48ALCoN/rQduSGuDgOlO6y3LBII6NiEXk1CjWjvfe5HdalaNrKPJb
pLXQCo6EOy/jHCYf6paMny0XZtvB1J2ab2mKMzI2J1L/tGp2ULe7fQti4nug1yKa
NaPrqlKvDBQsBU5bTUxl+ni7TswlO6z3gsSmn7CoLAjYtpX4lQ4seZIkJEsJ9Wzs
ZYbpgNTAZKO0nvPMofi9ibanqksjtfCJEJAHQWXuyH4AMWa7+p6cM+4wtIDQq19F
YJzG9G19OmYfv+vkpQJmhA3YQ4Zb1ZZZTdhvoYsCAwEAAaNmMGQwHQYDVR0OBBYE
FMUjmqhhNYw3MHlh031dzqGD1uKHMB8GA1UdIwQYMBaAFNE6GGA3GHBUazE15HSv
xs0IWoeCMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMA0GCSqG
SIb3DQEBCwUAA4ICAQA6i7/ZFk/GvoASLLwhDDxSB1DpH3EnkYZdvLNafHa/XVzp
kX4zqG8CRMxyb4jnKF3DLm2YO9AKYwDX2AblTjxXLsZiFnIxxqNGk8aDsnyVhU0U
Wu033+8rv1bKBCRXqeO56rjpRaUdyCYp7Wm81nv8CF9CcIJd6XIWC8va0scVjd7d
SxI1/ik4RUVR6VjGqRuDtGSO9Z8fFMsZ9VxlEyuJeRl1KCX59HizTTYe8UGSNLsx
4PXA2/fX5nyXb+95lQJZR8WVxjdQNr040g17iJ0w6sfRw2rlrkJDt9sPHzNTd0Ui
3rEqTiKQxiVW+7faq8LntKvfcAX70i0YgirpSgDT3JqBQOvP2kLSeXHgu3MAXNkS
vi9avahZsqPIekmkBc1ZwZwZC8UrTKz5GNFV8QVC7FsETvyonXV15gcCDHdem1GI
v81fEyNAU7yuf0vnIiWwZhZpBl8Ut3gLFehuo5lsWhcK0AmzGRz/ODIqGjrBEdwf
9qT/ypITZyBfzmsFu+EQc8TyAA1w8yrppldnWg5kAkiCGhsX8xZ1dEhM0Sd/W6nf
XcDb0CokHT74nxZNAcg65Bnby8JUjBuaRdk5IJ2XGAnp645e6R6MXdmNfEpS9XB+
zm11zCA+98jsqtImc6CGLupV4i56nffCvuohjpceMN8lhLDvJ+DLJKy1dLOVUw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIGNDCCBBygAwIBAgIJAKhWRhkcfvyLMA0GCSqGSIb3DQEBCwUAMIGmMQswCQYD
VQQGEwJDQTELMAkGA1UECAwCT04xEDAOBgNVBAcMB1Rvcm9udG8xGzAZBgNVBAoM
EldpbmRzY3JpYmUgTGltaXRlZDETMBEGA1UECwwKT3BlcmF0aW9uczEfMB0GA1UE
AwwWV2luZHNjcmliZSBJbnRlcm5hbCBDQTElMCMGCSqGSIb3DQEJARYWc3lzdGVt
c0B3aW5kc2NyaWJlLmNvbTAeFw0xNjAyMTAyMDM1NTJaFw0zNjAyMDUyMDM1NTJa
MIGmMQswCQYDVQQGEwJDQTELMAkGA1UECAwCT04xEDAOBgNVBAcMB1Rvcm9udG8x
GzAZBgNVBAoMEldpbmRzY3JpYmUgTGltaXRlZDETMBEGA1UECwwKT3BlcmF0aW9u
czEfMB0GA1UEAwwWV2luZHNjcmliZSBJbnRlcm5hbCBDQTElMCMGCSqGSIb3DQEJ
ARYWc3lzdGVtc0B3aW5kc2NyaWJlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBALZNDFhjUYSNuSwLHn6jgzLOHSCTqcVf7gR/7CYeNm4I4iDeHjtB
MHtkPWNTjbuFRVrLR7IC4jZmp197ctLM7TuY0jpC5Bxk+t7Lrsdmrym0LN5b6+Kv
PvPmPKBvoxz2zdpiKYkpP5uYuMWVkPmwoxCS1cZg3NQeDDp8Y9Jn4BISP1uZtFLt
2NYe1jrj58P7AGYpkgIoIDifbnIwyWfhypM0+ZWUFHbfxWvvvtZqecxuAkqAL8xw
H5zSVAhzSSDU76owSK79Nhn8dDnRscFqUqc4rmJrUpgES9nd1txj7oAC+qANlyZn
RjKS/XrT+obIhKtLy1wt702ISwr6QMcdsWnvmPFYPESmQeb+XwYkAAtTHxZMO96m
9W7sRknLiDQLuPiA3C/PcRWggm+5fiAs7kvVCI+Lc+bEBgNk6TQyWDKwmPqvnKKB
FsTB+kktH2VLrNVefdg/amoH2hYRWzifZIAswjjsC0dbiT/6yAbEhzx6+YJ1zP5I
HA46l4aAabItl9QEf+lSMvz9zD6M+cMROEd+Kf8TgWgih9OHB6sSag9Nh7YY7TqI
vx/oBGOCIrKHZSTioQz7G03EoDBve3GbowlZUv40ekxuJl3B2piFZSn+aW4dxs7O
ZjMwur8vtNnr9RGc0KKq4olt8fYHwyCqgMw3vztCUYO3AOHGS3gppN59AgMBAAGj
YzBhMB0GA1UdDgQWBBTROhhgNxhwVGsxNeR0r8bNCFqHgjAfBgNVHSMEGDAWgBTR
OhhgNxhwVGsxNeR0r8bNCFqHgjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAY/Ud6BA4Xuqlk1JL0Iu/Ri2cb9QtE8XA
Rp3Wv8ijlQvMdZ766iTa76MnjrtYjsE2v/4X/XSLwXMQre+w8TVRobtiGulsTXlE
7YJqhykYFPmlMWCVozjH0v2czhgAuSlTYzq1Qi5bU5ldCOkzUPEGIczw7n5gwf3+
y8BGTUxA9zVcDhpyFLh3KYrl3EbiE8yXmNkgcOgvAdWfz27YjK+oUIYeoUolrpEN
nZbqhN66JuCIe2PtCbRGkFQRcBMMr7P5CxbejnTPPYzXmqMZ20LWbVpBRx9+2HP+
GECpYqVqXvCSzsYhTYnPiSe0Mf3Wlv3bgMnuswW2MsHFwlcc6Rf26D0uhFwixMlU
OTAWFKmeBQwfmMsI9jQCofgIFkA5OnOLDkjUDsyjrTpc9a0B6TtxY5C/NpRd7C7C
eAPyVDK3Kok8huw+q7w86rb+kFb/Ps/Q7pkyowQViogjtfXz6PJgaI9ity7iKjZ3
sMcRJ/cBcooIfFBnvnctV65Qjf6OmJb2Po+nkQM4hS1dP6P1L0tWl31xvHb8fmsw
1rb7Fshx5/qxm/0dU5RzI1Yg6ukxiic9PLtuBIflWIdUIJoUazcXVEnn+tI2Tqpl
MLUv75Bg/WLPME1fZj1mv9tArgAzOpU7UO3ZqiWycJ4zkd8gYhpP9ygExIPn8EJO
RRHV1Tmvuj4=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIF5zCCA8+gAwIBAgIUXKzAwOtQBNDoTXcnwR7GxbVkRqAwDQYJKoZIhvcNAQEL
BQAwezELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAk9OMRAwDgYDVQQHDAdUb3JvbnRv
MRswGQYDVQQKDBJXaW5kc2NyaWJlIExpbWl0ZWQxEDAOBgNVBAsMB1N5c3RlbXMx
HjAcBgNVBAMMFVdpbmRzY3JpYmUgTm9kZSBDQSBYMTAeFw0yMTA3MDYyMTM5NDNa
Fw0zNzA3MDIyMTM5NDNaMHsxCzAJBgNVBAYTAkNBMQswCQYDVQQIDAJPTjEQMA4G
A1UEBwwHVG9yb250bzEbMBkGA1UECgwSV2luZHNjcmliZSBMaW1pdGVkMRAwDgYD
VQQLDAdTeXN0ZW1zMR4wHAYDVQQDDBVXaW5kc2NyaWJlIE5vZGUgQ0EgWDEwggIi
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDg/79XeOvthNbhtocxaJ6raIsr
lSrnUJ9xAyYHJV+auT4ZlACNE54NVhrGPBEVdNttUdezHaPUlQA+XTWUPlHMayIg
9dsQEFdHH3StnFrjYBzeCO76trPZ8McU6PzW+LqNEvFAwtdKjYMgHISkt0YPUPdB
7vED6yqbyiIAlmN5u/uLG441ImnEq5kjIQxVB+IHhkV4O7EuiKOEXvsKdFzdRACi
4rFOq9Z6zK2Yscdg89JvFOwIm1nY5PMYpZgUKkvdYMcvZQ8aFDaArniu+kUZiVyU
tcKRaCUCyyMM7iiN+5YV0vQ0Etv59ldOYPqL9aJ6QeRG9Plq5rP8ltbmXJRBO/kd
jQTBrP4gYddt5W0uv5rcMclZ9te0/JGl3Os3Gps5w7bYHeVdYb3j0PfsJAQ5WrM+
hS5/GaX3ltiJKXOA9kwtDG3YpPqvpMVAqpM6PFdRwTH62lOemVAOHRrThOVbclqp
Ebe3zH59jwSML5WXgVIfwrpcpndj2uEyKS50y30GzVBIn5M1pcQJJplYuBp8nVGC
qA9AVV+JHffVP/JrkvEJzhui8M5SVnkzmAK3i+rwL0NMRJKwKaSm1uJVvJyoXMMN
TEcu1lqnSl+i2UlIYAgeqeT//D9zcNgcOdP8ix6NhFChjE1dvNFv8mXxkezmu+et
PpQZTpgc1eBZvAAojwIDAQABo2MwYTAdBgNVHQ4EFgQUVLNKLT/c9fTG4BJ+6rTZ
kPjS4RgwHwYDVR0jBBgwFoAUVLNKLT/c9fTG4BJ+6rTZkPjS4RgwDwYDVR0TAQH/
BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAF4Bpc0X
dBsgF3WSeRLJ6t2J7vOjjMXBePwSL0g6GDjLpKW9sz9F3wfXaK5cKjY5tj5NEwmk
Vbqa+BXg4FWic0uLinI7tx7sLtvqHrKUFke35L8gjgIEpErg8nmBPokEVsmCcfYY
utwOi2IGikurpY29O4HniDY9baXp8kvwn1T92ZwF9G5SGzxc9Y0rGs+BwmDZu58I
hID3aqAJ16aHw5FHQWGUxje5uNbEUFdVaj7ODvznM6ef/5sAFVL15mftsRokLhCn
DdEjI/9QOYQoPrKJAudZzbWeOux3k93SehS7UWDZW4AFz/7XTaWL79tLqqtTI6Li
uHn73enHgH6BlsH3ESB+Has6Rn7aH0wBByLQ9+NYIfAwXUCd4nevUXeJ3r/aORi3
67ATj1yb3J8llFCsoc/PT7a+PxDT8co2m6TtcRK3mFT/71svWB0zy7qAtSWT1C82
W5JFkhkP44UMLwGUuJsrYy2qAZVru6Jp6vU/zOghLp5kwa1cO1GEbYinvoyTw4Xk
OuaIfEMUZA10QCCW8uocxqIZXTzvF7LaqqsTCcAMcviKGXS5lvxLtqTEDO5rYbf8
n71J2qUyUQ5yYTE0UFQYiYTuvCbtRg2TJdQy05nisw1O8Hm2erAmUveSTr3CWZ/a
v7Dtup352gRS6qxW4w0jRN3NLfLyazK/JjTX
-----END CERTIFICATE-----
-22
View File
@@ -1,22 +0,0 @@
target_sources(wsnet PRIVATE
wsnet.cpp
advancedparameters.h
connectstate.h
settings.h
)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/private")
add_subdirectory(private)
else()
add_subdirectory(public)
endif()
add_subdirectory(api)
add_subdirectory(apiresourcesmanager)
add_subdirectory(dnsresolver)
add_subdirectory(utils)
add_subdirectory(httpnetworkmanager)
add_subdirectory(failover)
add_subdirectory(emergencyconnect)
add_subdirectory(pingmanager)
add_subdirectory(decoytraffic)
-65
View File
@@ -1,65 +0,0 @@
#pragma once
#include <mutex>
#include "WSNetAdvancedParameters.h"
namespace wsnet {
// Thread safe implementation of the WSNetAdvancedParameters interface
class AdvancedParameters : public WSNetAdvancedParameters
{
public:
void setAPIExtraTLSPadding(bool isEnabled) override
{
std::lock_guard locker(mutex_);
isAPIExtraTLSPadding_ = isEnabled;
}
bool isAPIExtraTLSPadding() const override
{
std::lock_guard locker(mutex_);
return isAPIExtraTLSPadding_;
}
void setIgnoreCountryOverride(bool isIgnore) override
{
std::lock_guard locker(mutex_);
isIgnoreCountryOverride_ = isIgnore;
}
bool isIgnoreCountryOverride() const override
{
std::lock_guard locker(mutex_);
return isIgnoreCountryOverride_;
}
void setCountryOverrideValue(const std::string &country) override
{
std::lock_guard locker(mutex_);
countryOverrideValue_ = country;
}
std::string countryOverrideValue() const override
{
std::lock_guard locker(mutex_);
return countryOverrideValue_;
}
void setLogApiResponce(bool isEnabled) override
{
std::lock_guard locker(mutex_);
isLogApiResponce_ = isEnabled;
}
bool isLogApiResponce() const override
{
std::lock_guard locker(mutex_);
return isLogApiResponce_;
}
private:
mutable std::mutex mutex_;
bool isAPIExtraTLSPadding_ = false;
bool isIgnoreCountryOverride_ = false;
std::string countryOverrideValue_;
bool isLogApiResponce_ = false;
};
} // namespace wsnet
-7
View File
@@ -1,7 +0,0 @@
target_sources(wsnet PRIVATE
baserequest.cpp
baserequest.h
)
add_subdirectory(bridgeapi)
add_subdirectory(serverapi)
-135
View File
@@ -1,135 +0,0 @@
#include "baserequest.h"
#include <assert.h>
#include <skyr/url.hpp>
#include <rapidjson/document.h>
#include "utils/wsnet_logger.h"
#include "settings.h"
#include "utils/utils.h"
#include "utils/urlquery_utils.h"
namespace wsnet {
BaseRequest::BaseRequest(HttpMethod requestType, SubdomainType subDomainType, RequestPriority priority, const std::string &name,
std::map<std::string, std::string> extraParams, RequestFinishedCallback callback) :
requestType_(requestType),
subDomainType_(subDomainType),
priority_(priority),
name_(name),
extraParams_(extraParams),
callback_(callback)
{
}
void BaseRequest::setApiOverrideSettings(const ApiOverrideSettings &apiOverrideSettings)
{
if (subDomainType_ == SubdomainType::kApi && !apiOverrideSettings.apiRoot.empty())
domainOverride_ = apiOverrideSettings.apiRoot;
else if (subDomainType_ == SubdomainType::kAssets && !apiOverrideSettings.assetsRoot.empty())
domainOverride_ = apiOverrideSettings.assetsRoot;
}
bool BaseRequest::isApiDomainOverriden() const
{
return !domainOverride_.empty();
}
std::string BaseRequest::url(const std::string &domain) const
{
auto url = skyr::url("https://" + hostname(domain, subDomainType_) + "/" + name());
if (requestType_ == HttpMethod::kGet || requestType_ == HttpMethod::kDelete) {
auto &sp = url.search_parameters();
for (auto &it : extraParams_)
if (!it.second.empty())
sp.set(it.first, it.second);
urlquery_utils::addPlatformQueryItems(sp);
}
return url.c_str();
}
std::string BaseRequest::postData() const
{
if (requestType_ == HttpMethod::kPost || requestType_ == HttpMethod::kPut) {
skyr::url_search_parameters sp;
for (auto &it : extraParams_)
if (!it.second.empty())
sp.set(it.first, it.second);
urlquery_utils::addPlatformQueryItems(sp);
return sp.to_string();
}
return std::string();
}
void BaseRequest::handle(const std::string &arr)
{
json_ = arr;
if (arr.empty()) {
setRetCode(ApiRetCode::kIncorrectJson);
g_logger->info("Received an empty json response, return ApiRetCode::kIncorrectJson");
return;
}
if (!isIgnoreJsonParse_) {
using namespace rapidjson;
Document doc;
doc.Parse(arr.c_str());
if (doc.HasParseError() || !doc.IsObject()) {
g_logger->info("Received an incorrect json response: {}", arr);
setRetCode(ApiRetCode::kIncorrectJson);
return;
}
auto jsonObject = doc.GetObject();
// all responses must contain errorCode or/and data fields
if (!jsonObject.HasMember("errorCode") && !jsonObject.HasMember("data")) {
g_logger->info("Received an incorrect json response: {}", arr);
setRetCode(ApiRetCode::kIncorrectJson);
return;
}
}
}
bool BaseRequest::isCanceled()
{
if (callback_) {
return callback_->isCanceled();
} else {
return false;
}
}
void BaseRequest::callCallback()
{
if (callback_) {
callback_->call(retCode_, json_);
}
}
std::string BaseRequest::hostname(const std::string &domain, SubdomainType subdomain) const
{
// staging mode always takes priority over all other API settings
if (Settings::instance().isStaging() || domainOverride_.empty()) {
// If the domain is an IP address then we do different transformations
if (utils::isIpAddress(domain)) {
if (subdomain == SubdomainType::kAssets) {
return domain + "/" + Settings::instance().serverAssetsSubdomain();
} else {
return domain;
}
} else {
if (subdomain == SubdomainType::kApi)
return Settings::instance().serverApiSubdomain() + "." + domain;
else if (subdomain == SubdomainType::kAssets)
return Settings::instance().serverAssetsSubdomain() + "." + domain;
}
}
// if it is an overridden domain, return without transformations
if (!domainOverride_.empty()) {
return domainOverride_;
}
assert(false);
return "";
}
} // namespace wsnet
-93
View File
@@ -1,93 +0,0 @@
#pragma once
#include <map>
#include "WSNetHttpRequest.h"
#include "WSNetServerAPI.h"
#include "utils/cancelablecallback.h"
#include "settings.h"
namespace wsnet {
enum class SubdomainType { kApi, kAssets, kBridgeAPI };
enum class RequestPriority { kNormal, kHigh };
using RequestFinishedCallback = std::shared_ptr<CancelableCallback<WSNetRequestFinishedCallback>>;
struct ApiOverrideSettings
{
std::string apiRoot;
std::string assetsRoot;
bool isOverriden() const
{
return !apiRoot.empty() || !assetsRoot.empty();
}
};
class BaseRequest
{
public:
explicit BaseRequest(HttpMethod requestType, SubdomainType subDomainType, RequestPriority priority, const std::string &name,
std::map<std::string, std::string> extraParams,
RequestFinishedCallback callback);
virtual ~BaseRequest() {};
void setApiOverrideSettings(const ApiOverrideSettings &apiOverrideSettings);
bool isApiDomainOverriden() const;
virtual std::string url(const std::string &domain) const;
std::string contentTypeHeader() const { return contentTypeHeader_; }
void setContentTypeHeader(const std::string &data) { contentTypeHeader_ = data; }
void setBearerToken(const std::string &bearerToken) { bearerToken_ = bearerToken; }
std::string bearerToken() const { return bearerToken_; }
void setIgnoreJsonParse() { isIgnoreJsonParse_ = true; }
virtual std::string postData() const;
std::string name() const { return name_; }
virtual void handle(const std::string &arr);
bool isCanceled();
void callCallback();
HttpMethod requestType() const { return requestType_; }
void setTimeout(int ms) { timeout_ = ms; }
int timeout() const { return timeout_; }
RequestPriority priority() const { return priority_; }
bool isUseDnsCache() const { return isUseDnsCache_; }
void setUseDnsCache(bool isUse) { isUseDnsCache_ = isUse; }
bool isWriteToLog() const { return isWriteToLog_; }
void setNotWriteToLog() { isWriteToLog_ = false; }
void setRetCode(ApiRetCode retCode) { retCode_ = retCode; }
ApiRetCode retCode() const { return retCode_; }
protected:
int timeout_ = kApiTimeout;
HttpMethod requestType_;
SubdomainType subDomainType_;
std::string domainOverride_;
RequestPriority priority_;
bool isUseDnsCache_ = true;
std::string name_;
std::map<std::string, std::string> extraParams_;
RequestFinishedCallback callback_;
bool isWriteToLog_ = true;
ApiRetCode retCode_ = ApiRetCode::kSuccess;
std::string contentTypeHeader_;
std::string bearerToken_ = "0";
bool isIgnoreJsonParse_ = false;
std::string json_;
virtual std::string hostname(const std::string &domain, SubdomainType subdomain) const;
};
} // namespace wsnet
@@ -1,14 +0,0 @@
target_sources(wsnet PRIVATE
bridgeapi.cpp
bridgeapi.h
bridgeapi_impl.cpp
bridgeapi_impl.h
bridgeapi_request.cpp
bridgeapi_request.h
bridgeapi_requestsfactory.cpp
bridgeapi_requestsfactory.h
bridgeapi_utils.cpp
bridgeapi_utils.h
bridgetokenrequest.cpp
bridgetokenrequest.h
)
@@ -1,98 +0,0 @@
#include "bridgeapi.h"
#include <spdlog/spdlog.h>
#include "bridgeapi_impl.h"
#include "bridgeapi_request.h"
#include "bridgeapi_requestsfactory.h"
#include "settings.h"
namespace wsnet {
BridgeAPI::BridgeAPI(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager, PersistentSettings &persistentSettings, WSNetAdvancedParameters *advancedParameters, ConnectState &connectState) :
io_context_(io_context),
persistentSettings_(persistentSettings),
advancedParameters_(advancedParameters),
connectState_(connectState)
{
impl_ = std::make_unique<BridgeAPI_impl>(httpNetworkManager, persistentSettings_, advancedParameters, connectState);
subscriberId_ = connectState_.subscribeConnectedToVpnState(std::bind(&BridgeAPI::onVPNConnectStateChanged, this, std::placeholders::_1));
}
BridgeAPI::~BridgeAPI()
{
connectState_.unsubscribeConnectedToVpnState(subscriberId_);
impl_.reset();
}
void BridgeAPI::setConnectedState(bool isConnected)
{
boost::asio::post(io_context_, [this, isConnected] {
impl_->setConnectedState(isConnected);
});
}
void BridgeAPI::setIgnoreSslErrors(bool bIgnore)
{
boost::asio::post(io_context_, [this, bIgnore] {
impl_->setIgnoreSslErrors(bIgnore);
});
}
bool BridgeAPI::hasSessionToken() const
{
return impl_->hasSessionToken();
}
void BridgeAPI::setApiAvailableCallback(WSNetApiAvailableCallback callback)
{
boost::asio::post(io_context_, [this, callback] {
impl_->setApiAvailableCallback(callback);
});
}
void BridgeAPI::setCurrentHost(const std::string &host)
{
boost::asio::post(io_context_, [this, host] {
impl_->setCurrentHost(host);
});
}
std::shared_ptr<WSNetCancelableCallback> BridgeAPI::pinIp(const std::string &ip, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
// Use the bridge token from impl
BaseRequest *request = bridgeapi_requests_factory::pinIp("", ip, cancelableCallback);
// This request does not return any data
request->setIgnoreJsonParse();
auto token = impl_->sessionToken();
if (token) {
static_cast<BridgeAPIRequest *>(request)->setSessionToken(token->first);
}
boost::asio::post(io_context_, [this, request] { impl_->pinIp(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> BridgeAPI::rotateIp(WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
// Use the bridge token from impl
BaseRequest *request = bridgeapi_requests_factory::rotateIp("", cancelableCallback);
// This request does not return any data
request->setIgnoreJsonParse();
auto token = impl_->sessionToken();
if (token) {
static_cast<BridgeAPIRequest *>(request)->setSessionToken(token->first);
}
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
void BridgeAPI::onVPNConnectStateChanged(bool isConnected)
{
boost::asio::post(io_context_, [this, isConnected] {
impl_->setConnectedState(isConnected);
});
}
} // namespace wsnet
-40
View File
@@ -1,40 +0,0 @@
#pragma once
#include "WSNetBridgeAPI.h"
#include <boost/asio.hpp>
#include "WSNetHttpNetworkManager.h"
#include "WSNetAdvancedParameters.h"
#include "utils/persistentsettings.h"
#include "connectstate.h"
namespace wsnet {
class BridgeAPI_impl;
class BridgeAPI : public WSNetBridgeAPI
{
public:
explicit BridgeAPI(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager, PersistentSettings &persistentSettings, WSNetAdvancedParameters *advancedParameters, ConnectState &connectState);
virtual ~BridgeAPI();
void setConnectedState(bool isConnected) override;
void setIgnoreSslErrors(bool bIgnore) override;
bool hasSessionToken() const override;
void setApiAvailableCallback(WSNetApiAvailableCallback callback) override;
void setCurrentHost(const std::string &host) override;
std::shared_ptr<WSNetCancelableCallback> pinIp(const std::string &ip, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> rotateIp(WSNetRequestFinishedCallback callback) override;
private:
std::unique_ptr<BridgeAPI_impl> impl_;
boost::asio::io_context &io_context_;
PersistentSettings &persistentSettings_;
WSNetAdvancedParameters *advancedParameters_;
ConnectState &connectState_;
std::uint32_t subscriberId_;
void onVPNConnectStateChanged(bool isConnected);
};
} // namespace wsnet
@@ -1,305 +0,0 @@
#include "bridgeapi_impl.h"
#include "bridgeapi_utils.h"
#include "bridgeapi_requestsfactory.h"
#include "bridgetokenrequest.h"
#include "settings.h"
#include "utils/cancelablecallback.h"
#include "utils/wsnet_logger.h"
#include "utils/requesterror.h"
namespace wsnet {
BridgeAPI_impl::BridgeAPI_impl(WSNetHttpNetworkManager *httpNetworkManager, PersistentSettings &persistentSettings, WSNetAdvancedParameters *advancedParameters, ConnectState &connectState) :
httpNetworkManager_(httpNetworkManager),
advancedParameters_(advancedParameters),
connectState_(connectState),
persistentSettings_(persistentSettings)
{
sessionTokens_ = persistentSettings_.sessionTokens();
}
BridgeAPI_impl::~BridgeAPI_impl()
{
for (auto &it : activeHttpRequests_) {
it.second.asyncCallback_->cancel();
}
// Clean up any queued pinIp request
if (queuedPinIpRequest_) {
queuedPinIpRequest_->setRetCode(ApiRetCode::kNoToken);
queuedPinIpRequest_->callCallback();
queuedPinIpRequest_.reset();
}
}
void BridgeAPI_impl::setConnectedState(bool isConnected)
{
if (isConnected && !isConnected_) {
std::string currentToken;
auto token = sessionToken();
if (token) {
if (token->second > 0) {
// We have a valid token with an expiry time, check if it's expired
auto now = std::chrono::system_clock::now();
auto nowTimestamp = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
if (nowTimestamp >= token->second) {
g_logger->info("Removing expired session token for host '{}'", currentHost_);
sessionTokens_.erase(currentHost_);
persistentSettings_.setSessionTokens(sessionTokens_);
} else {
// Token is not expired, set expiry time to 0 since it's valid until disconnection
currentToken = token->first;
sessionTokens_[currentHost_].second = 0;
persistentSettings_.setSessionTokens(sessionTokens_);
}
} else {
currentToken = token->first;
}
}
g_logger->info("BridgeAPI_impl::setConnectedState, fetching token for host '{}'{}", currentHost_, currentToken.empty() ? "" : " with cached token");
isFetchingToken_ = true;
auto request = std::unique_ptr<BaseRequest>(bridgeapi_requests_factory::fetchToken(currentToken, nullptr));
executeRequestImpl(std::move(request));
} else if (!isConnected) {
setSessionTokenExpiry();
isFetchingToken_ = false;
// Clear any queued pinIp request since we're disconnected
if (queuedPinIpRequest_) {
g_logger->info("Clearing queued pinIp request due to disconnection");
queuedPinIpRequest_->setRetCode(ApiRetCode::kNoNetworkConnection);
queuedPinIpRequest_->callCallback();
queuedPinIpRequest_.reset();
}
// Notify that the API is no longer available
if (apiAvailableCallback_) {
apiAvailableCallback_(false);
}
}
isConnected_ = isConnected;
}
void BridgeAPI_impl::setIgnoreSslErrors(bool bIgnore)
{
bIgnoreSslErrors_ = bIgnore;
g_logger->info("BridgeAPI_impl::setIgnoreSslErrors, {}", bIgnore);
}
// execute request if the failover detected or queue
void BridgeAPI_impl::executeRequest(std::unique_ptr<BaseRequest> request)
{
// if request already canceled do nothing
if (request->isCanceled()) {
return;
}
// check if we are online
if (!connectState_.isOnline() || !isConnected_) {
request->setRetCode(ApiRetCode::kNoNetworkConnection);
request->callCallback();
return;
}
// Check if we need a token and don't have one
if (!sessionToken()) {
request->setRetCode(ApiRetCode::kNoToken);
request->callCallback();
return;
}
// in the connected mode always use the primary domain
executeRequestImpl(std::move(request));
}
void BridgeAPI_impl::executeRequestImpl(std::unique_ptr<BaseRequest> request)
{
using namespace std::placeholders;
g_logger->info("BridgeAPI_impl::executeRequestImpl, bIgnoreSslErrors_: {}", bIgnoreSslErrors_);
auto httpRequest = serverapi_utils::createHttpRequest(httpNetworkManager_, Settings::instance().bridgeApiAddress(), request.get(), bIgnoreSslErrors_, advancedParameters_->isAPIExtraTLSPadding());
httpRequest->setIsDebugLogCurlError(true);
std::uint64_t requestId = curUniqueId_++;
auto asyncCallback_ = httpNetworkManager_->executeRequestEx(httpRequest, requestId, std::bind(&BridgeAPI_impl::onHttpNetworkRequestFinished, this, _1, _2, _3, _4),
std::bind(&BridgeAPI_impl::onHttpNetworkRequestProgressCallback, this, _1, _2, _3));
HttpRequestInfo hti { std::move(request), asyncCallback_};
activeHttpRequests_[requestId] = std::move(hti);
}
void BridgeAPI_impl::setErrorCodeAndEmitRequestFinished(BaseRequest *request, ApiRetCode retCode)
{
request->setRetCode(retCode);
request->callCallback();
}
void BridgeAPI_impl::onHttpNetworkRequestFinished(std::uint64_t requestId, std::uint32_t elapsedMs, std::shared_ptr<WSNetRequestError> error, const std::string &data)
{
auto it = activeHttpRequests_.find(requestId);
assert(it != activeHttpRequests_.end());
if (it->second.request->isCanceled()) {
activeHttpRequests_.erase(it);
return;
}
// Extract HTTP response code from the error object
int httpResponseCode = 0;
auto requestError = std::dynamic_pointer_cast<RequestError>(error);
if (requestError) {
httpResponseCode = requestError->httpResponseCode();
}
// Check if this is a token fetch request
auto tokenRequest = dynamic_cast<BridgeTokenRequest*>(it->second.request.get());
bool isTokenRequest = (tokenRequest != nullptr);
// If this is a token request and we're no longer connected, ignore the result
if (isTokenRequest && !isConnected_) {
g_logger->info("Token request finished but no longer connected, ignoring result");
activeHttpRequests_.erase(it);
return;
}
if (error->isSuccess() && httpResponseCode == 200) {
if (advancedParameters_->isLogApiResponce()) {
g_logger->info("API request {} finished", it->second.request->name());
g_logger->info("{}", data);
}
it->second.request->handle(data);
if (it->second.request->retCode() == ApiRetCode::kSuccess) {
if (isTokenRequest) {
isFetchingToken_ = false;
std::string newToken = tokenRequest->getSessionToken();
sessionTokens_[currentHost_] = {newToken, 0};
g_logger->info("Successfully received session token for host '{}'", currentHost_);
persistentSettings_.setSessionTokens(sessionTokens_);
// Notify that the API is now available
if (apiAvailableCallback_) {
apiAvailableCallback_(true);
}
// Execute any queued pinIp request now that we have a token
if (queuedPinIpRequest_) {
g_logger->info("Executing queued pinIp request with fresh token");
// Update the token on the request before executing
auto bridgeRequest = dynamic_cast<BridgeAPIRequest*>(queuedPinIpRequest_.get());
if (bridgeRequest) {
auto token = sessionToken();
if (token) {
bridgeRequest->setSessionToken(token->first);
}
}
executeRequest(std::move(queuedPinIpRequest_));
queuedPinIpRequest_.reset();
}
} else {
it->second.request->callCallback();
}
activeHttpRequests_.erase(it);
return;
}
}
// Failure
if (isTokenRequest) {
auto token = sessionToken();
if (token && error->isSuccess()) {
// We have an existing token and server told us it's no good (i.e. httpResponseCode != 200), try getting a new one
clearSessionToken();
g_logger->info("Token request failed {} (HTTP response code: {}), clearing cached token for host '{}' and trying again", error->toString(), httpResponseCode, currentHost_);
auto request = std::unique_ptr<BaseRequest>(bridgeapi_requests_factory::fetchToken("", nullptr));
executeRequestImpl(std::move(request));
} else {
isFetchingToken_ = false;
g_logger->info("Token request failed: {} (HTTP response code: {})", error->toString(), httpResponseCode);
}
// Clear any queued pinIp request since token fetch failed
if (queuedPinIpRequest_) {
g_logger->info("Clearing queued pinIp request due to token fetch failure");
queuedPinIpRequest_->setRetCode(ApiRetCode::kNoToken);
queuedPinIpRequest_->callCallback();
queuedPinIpRequest_.reset();
}
} else {
g_logger->info("API request {} failed with error = {} (HTTP response code: {})", it->second.request->name(), error->toString(), httpResponseCode);
setErrorCodeAndEmitRequestFinished(it->second.request.get(), it->second.request->retCode() == ApiRetCode::kSuccess ? ApiRetCode::kBridgeApiError : it->second.request->retCode());
}
activeHttpRequests_.erase(it);
}
void BridgeAPI_impl::onHttpNetworkRequestProgressCallback(std::uint64_t requestId, std::uint64_t bytesReceived, std::uint64_t bytesTotal)
{
auto it = activeHttpRequests_.find(requestId);
assert(it != activeHttpRequests_.end());
if (it->second.request->isCanceled()) {
it->second.asyncCallback_->cancel();
activeHttpRequests_.erase(it);
}
}
const std::pair<std::string, std::int64_t> *BridgeAPI_impl::sessionToken() const
{
auto it = sessionTokens_.find(currentHost_);
if (it != sessionTokens_.end()) {
return &it->second;
}
return nullptr;
}
bool BridgeAPI_impl::hasSessionToken() const
{
return sessionToken() != nullptr;
}
void BridgeAPI_impl::setApiAvailableCallback(WSNetApiAvailableCallback callback)
{
apiAvailableCallback_ = callback;
}
void BridgeAPI_impl::pinIp(std::unique_ptr<BaseRequest> request)
{
// Store the request to be executed when session token is available
queuedPinIpRequest_ = std::move(request);
// If we are connected, and not currently fetching a new token, execute immediately
if (isConnected_ && !isFetchingToken_) {
executeRequest(std::move(queuedPinIpRequest_));
queuedPinIpRequest_.reset();
}
// Otherwise, the request will be executed when the token fetch completes, or cancelled if the token request fails
}
void BridgeAPI_impl::clearSessionToken()
{
sessionTokens_.erase(currentHost_);
persistentSettings_.setSessionTokens(sessionTokens_);
}
void BridgeAPI_impl::setCurrentHost(const std::string &host)
{
g_logger->info("BridgeAPI_impl::setCurrentHost: '{}'", host);
currentHost_ = host;
}
void BridgeAPI_impl::setSessionTokenExpiry()
{
auto it = sessionTokens_.find(currentHost_);
if (it != sessionTokens_.end()) {
auto expiryTime = std::chrono::system_clock::now() + std::chrono::hours(24);
auto expiryTimestamp = std::chrono::duration_cast<std::chrono::seconds>(expiryTime.time_since_epoch()).count();
if (it->second.second == 0) {
it->second.second = expiryTimestamp;
persistentSettings_.setSessionTokens(sessionTokens_);
g_logger->info("Set session token expiry to 24 hours from disconnect for host '{}'", currentHost_);
}
}
}
} // namespace wsnet
@@ -1,71 +0,0 @@
#pragma once
#include "WSNetBridgeAPI.h"
#include <mutex>
#include <queue>
#include <map>
#include <optional>
#include <atomic>
#include <chrono>
#include "WSNetHttpNetworkManager.h"
#include "WSNetAdvancedParameters.h"
#include "../baserequest.h"
#include "bridgeapi_request.h"
#include "connectstate.h"
#include "utils/cancelablecallback.h"
#include "utils/persistentsettings.h"
namespace wsnet {
class BridgeAPI_impl
{
public:
explicit BridgeAPI_impl(WSNetHttpNetworkManager *httpNetworkManager, PersistentSettings &persistentSettings, WSNetAdvancedParameters *advancedParameters, ConnectState &connectState);
virtual ~BridgeAPI_impl();
void setConnectedState(bool isConnected);
void setIgnoreSslErrors(bool bIgnore);
const std::pair<std::string, std::int64_t> *sessionToken() const;
bool hasSessionToken() const;
void setApiAvailableCallback(WSNetApiAvailableCallback callback);
void setCurrentHost(const std::string &host);
void executeRequest(std::unique_ptr<BaseRequest> request);
void pinIp(std::unique_ptr<BaseRequest> request);
private:
WSNetHttpNetworkManager *httpNetworkManager_;
WSNetAdvancedParameters *advancedParameters_;
ConnectState &connectState_;
std::uint64_t curUniqueId_ = 0; // for generate unique identifiers for HTTP-requests
PersistentSettings &persistentSettings_; // The BridgeAPISettings class is protected by mutex, so it's thread-safe
bool bIgnoreSslErrors_ = false;
bool isConnected_ = false;
bool isFetchingToken_ = false;
std::map<std::string, std::pair<std::string, std::int64_t>> sessionTokens_;
std::string currentHost_;
std::unique_ptr<BaseRequest> queuedPinIpRequest_;
WSNetApiAvailableCallback apiAvailableCallback_;
struct HttpRequestInfo {
std::unique_ptr<BaseRequest> request;
std::shared_ptr<WSNetCancelableCallback> asyncCallback_;
};
std::map<std::uint64_t, HttpRequestInfo> activeHttpRequests_;
void executeRequestImpl(std::unique_ptr<BaseRequest> request);
void setErrorCodeAndEmitRequestFinished(BaseRequest *request, ApiRetCode retCode);
void onHttpNetworkRequestFinished(std::uint64_t requestId, std::uint32_t elapsedMs, std::shared_ptr<WSNetRequestError> error, const std::string &data);
// This callback function is necessary to cancel the request as quickly as possible if it was canceled on the calling side
void onHttpNetworkRequestProgressCallback(std::uint64_t requestId, std::uint64_t bytesReceived, std::uint64_t bytesTotal);
void clearSessionToken();
void setSessionTokenExpiry();
};
} // namespace wsnet
@@ -1,94 +0,0 @@
#include "bridgeapi_request.h"
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include <skyr/url.hpp>
#include "utils/urlquery_utils.h"
#include "utils/wsnet_logger.h"
namespace wsnet {
BridgeAPIRequest::BridgeAPIRequest(HttpMethod requestType, SubdomainType subDomainType, const std::string &name,
std::map<std::string, std::string> extraParams, const std::string &sessionToken, RequestFinishedCallback callback) :
BaseRequest(requestType, subDomainType, RequestPriority::kNormal, name, extraParams, callback),
sessionToken_(sessionToken)
{
setTimeout(kRequestTimeoutMs);
}
void BridgeAPIRequest::setSessionToken(const std::string &token)
{
sessionToken_ = token;
}
std::string BridgeAPIRequest::sessionToken() const
{
return sessionToken_;
}
std::string BridgeAPIRequest::url(const std::string &domain) const
{
auto url = skyr::url("https://" + hostname(domain, subDomainType_) + "/" + name());
if (requestType_ == HttpMethod::kGet || requestType_ == HttpMethod::kDelete) {
auto &sp = url.search_parameters();
for (auto &it : extraParams_) {
if (!it.second.empty()) {
sp.set(it.first, it.second);
}
}
}
return url.c_str();
}
std::string BridgeAPIRequest::postData() const
{
if (requestType_ == HttpMethod::kPost || requestType_ == HttpMethod::kPut) {
rapidjson::Document doc;
doc.SetObject();
auto& allocator = doc.GetAllocator();
for (const auto& param : extraParams_) {
if (!param.second.empty()) {
rapidjson::Value key(param.first.c_str(), allocator);
rapidjson::Value value(param.second.c_str(), allocator);
doc.AddMember(key, value, allocator);
}
}
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
doc.Accept(writer);
return buffer.GetString();
}
return std::string();
}
std::string BridgeAPIRequest::hostname(const std::string &domain, SubdomainType subdomain) const
{
return domain;
}
void BridgeAPIRequest::handle(const std::string &arr)
{
json_ = arr;
if (arr.empty()) {
setRetCode(ApiRetCode::kIncorrectJson);
g_logger->info("Received an empty json response, return ApiRetCode::kIncorrectJson");
return;
}
if (!isIgnoreJsonParse_) {
using namespace rapidjson;
Document doc;
doc.Parse(arr.c_str());
if (doc.HasParseError() || !doc.IsObject()) {
g_logger->info("Received an incorrect json response: {}", arr);
setRetCode(ApiRetCode::kIncorrectJson);
return;
}
}
}
} // namespace wsnet
@@ -1,31 +0,0 @@
#pragma once
#include <map>
#include "../baserequest.h"
namespace wsnet {
class BridgeAPIRequest : public BaseRequest
{
public:
explicit BridgeAPIRequest(HttpMethod requestType, SubdomainType subDomainType, const std::string &name,
std::map<std::string, std::string> extraParams, const std::string &sessionToken,
RequestFinishedCallback callback);
virtual ~BridgeAPIRequest() {};
virtual std::string url(const std::string &domain) const override;
virtual std::string postData() const override;
virtual void handle(const std::string &arr) override;
void setSessionToken(const std::string &token);
std::string sessionToken() const;
protected:
virtual std::string hostname(const std::string &domain, SubdomainType subdomain) const override;
const int kRequestTimeoutMs = 5000;
std::string sessionToken_;
};
} // namespace wsnet
@@ -1,30 +0,0 @@
#include "bridgeapi_requestsfactory.h"
#include "bridgeapi_request.h"
#include "bridgetokenrequest.h"
#include "utils/utils.h"
namespace wsnet {
BaseRequest *bridgeapi_requests_factory::pinIp(const std::string &sessionToken, const std::string &ip, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["ip"] = ip;
auto request = new BridgeAPIRequest(HttpMethod::kPost, SubdomainType::kBridgeAPI, "v1/ip/pin", extraParams, sessionToken, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *bridgeapi_requests_factory::rotateIp(const std::string &sessionToken, RequestFinishedCallback callback)
{
auto request = new BridgeAPIRequest(HttpMethod::kPost, SubdomainType::kBridgeAPI, "v1/ip/rotate", std::map<std::string, std::string>(), sessionToken, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *bridgeapi_requests_factory::fetchToken(const std::string &sessionToken, RequestFinishedCallback callback)
{
return new BridgeTokenRequest(sessionToken, callback);
}
} // namespace wsnet
@@ -1,14 +0,0 @@
#pragma once
#include "../baserequest.h"
#include "bridgeapi_request.h"
namespace wsnet {
namespace bridgeapi_requests_factory
{
BaseRequest *pinIp(const std::string &sessionToken, const std::string &ip, RequestFinishedCallback callback);
BaseRequest *rotateIp(const std::string &sessionToken, RequestFinishedCallback callback);
BaseRequest *fetchToken(const std::string &sessionToken, RequestFinishedCallback callback);
}
} // namespace wsnet
@@ -1,48 +0,0 @@
#include "bridgeapi_utils.h"
#include <assert.h>
#include "bridgeapi_request.h"
namespace wsnet {
std::shared_ptr<WSNetHttpRequest> serverapi_utils::createHttpRequest(WSNetHttpNetworkManager *httpNetworkManager, const std::string &domain, BaseRequest *request, bool bIgnoreSslErrors, bool isAPIExtraTLSPadding)
{
// Make sure the network return code is reset
request->setRetCode(ApiRetCode::kSuccess);
std::shared_ptr<WSNetHttpRequest> httpRequest;
switch (request->requestType()) {
case HttpMethod::kGet:
httpRequest = httpNetworkManager->createGetRequest(request->url(domain), request->timeout(), bIgnoreSslErrors);
break;
case HttpMethod::kPost:
httpRequest = httpNetworkManager->createPostRequest(request->url(domain), request->timeout(), request->postData(), bIgnoreSslErrors);
break;
case HttpMethod::kDelete:
httpRequest = httpNetworkManager->createDeleteRequest(request->url(domain), request->timeout(), bIgnoreSslErrors);
break;
case HttpMethod::kPut:
httpRequest = httpNetworkManager->createPutRequest(request->url(domain), request->timeout(), request->postData(), bIgnoreSslErrors);
break;
default:
assert(false);
}
if (!request->isUseDnsCache()) {
httpRequest->setUseDnsCache(false);
}
if (isAPIExtraTLSPadding) {
httpRequest->setExtraTLSPadding(true);
}
const std::string token = static_cast<BridgeAPIRequest *>(request)->sessionToken();
if (!token.empty()) {
httpRequest->setSessionToken(token);
}
return httpRequest;
}
} // namespace wsnet
@@ -1,12 +0,0 @@
#pragma once
#include "../baserequest.h"
#include "WSNetHttpNetworkManager.h"
namespace wsnet {
namespace serverapi_utils {
std::shared_ptr<WSNetHttpRequest> createHttpRequest(WSNetHttpNetworkManager *httpNetworkManager, const std::string &domain, BaseRequest *request, bool bIgnoreSslErrors, bool isAPIExtraTLSPadding);
}
} // namespace wsnet
@@ -1,47 +0,0 @@
#include "bridgetokenrequest.h"
#include <nlohmann/json.hpp>
#include "utils/wsnet_logger.h"
namespace wsnet {
BridgeTokenRequest::BridgeTokenRequest(const std::string &sessionToken, RequestFinishedCallback callback) :
BridgeAPIRequest(HttpMethod::kPost, SubdomainType::kBridgeAPI, "v1/token", std::map<std::string, std::string>(), sessionToken, callback)
{
setTimeout(5000);
}
void BridgeTokenRequest::handle(const std::string &arr)
{
// Call parent handle first
BridgeAPIRequest::handle(arr);
// If parent handle failed, don't proceed
if (retCode() != ApiRetCode::kSuccess) {
return;
}
// Parse the token from the response
try {
nlohmann::json j = nlohmann::json::parse(arr);
if (j.contains("session_token")) {
sessionTokenResponse_ = j["session_token"];
g_logger->info("BridgeTokenRequest: token parsed successfully");
} else if (j.contains("token")) {
sessionTokenResponse_ = j["token"];
g_logger->info("BridgeTokenRequest: token parsed successfully");
} else {
g_logger->error("BridgeTokenRequest: invalid token response format");
setRetCode(ApiRetCode::kIncorrectJson);
}
} catch (const std::exception &e) {
g_logger->error("BridgeTokenRequest: token JSON parse error: {}", e.what());
setRetCode(ApiRetCode::kIncorrectJson);
}
}
const std::string& BridgeTokenRequest::getSessionToken() const
{
return sessionTokenResponse_;
}
} // namespace wsnet
@@ -1,21 +0,0 @@
#pragma once
#include "bridgeapi_request.h"
namespace wsnet {
class BridgeTokenRequest : public BridgeAPIRequest
{
public:
explicit BridgeTokenRequest(const std::string &sessionToken, RequestFinishedCallback callback);
virtual ~BridgeTokenRequest() {};
virtual void handle(const std::string &arr) override;
const std::string& getSessionToken() const;
private:
std::string sessionTokenResponse_;
};
} // namespace wsnet
@@ -1,21 +0,0 @@
target_sources(wsnet PRIVATE
failedfailovers.h
pingtest.cpp
pingtest.h
requestexecuterviafailover.cpp
requestexecuterviafailover.h
serverapi.cpp
serverapi.h
serverapi_impl.cpp
serverapi_impl.h
serverapi_requestsfactory.cpp
serverapi_requestsfactory.h
serverapi_utils.cpp
serverapi_utils.h
setrobertfilter_request.cpp
setrobertfilter_request.h
serverlocations_request.cpp
serverlocations_request.h
wsnet_utils_impl.h
wsnet_utils_impl.cpp
)
@@ -1,28 +0,0 @@
#pragma once
#include <set>
#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<FailoverData> failedFailovers_;
};
} // namespace wsnet
-81
View File
@@ -1,81 +0,0 @@
#include "pingtest.h"
#include <skyr/url.hpp>
#include "utils/wsnet_logger.h"
#include "utils/urlquery_utils.h"
#include "utils/utils.h"
namespace wsnet {
struct PingTest::EndpointsImpl {
std::vector<skyr::url> endpoints;
};
PingTest::~PingTest() = default;
PingTest::PingTest(WSNetHttpNetworkManager *httpNetworkManager) : httpNetworkManager_(httpNetworkManager),
endpointsImpl_(std::make_unique<EndpointsImpl>())
{
auto tunnelTestEndpoints = Settings::instance().tunnelTestEndpoints();
for (const std::string &it : tunnelTestEndpoints) {
skyr::url url("https://" + it);
auto &sp = url.search_parameters();
urlquery_utils::addPlatformQueryItems(sp);
endpointsImpl_->endpoints.push_back(url);
}
}
void PingTest::doPingTest(std::uint32_t timeoutMs, RequestFinishedCallback callback)
{
assert(!endpointsImpl_->endpoints.empty());
assert(callback != nullptr);
// Do the first ping test through the primary domain
auto httpRequest = httpNetworkManager_->createGetRequest(endpointsImpl_->endpoints[0].c_str(), timeoutMs, false);
// We do not use DNS cache, as we need to verify the functionality of the connected VPN's DNS.
httpRequest->setUseDnsCache(false);
httpRequest->setIsWhiteListIps(false);
using namespace std::placeholders;
std::uint64_t requestId = curUniqueId_++;
RequestInfo ri { callback, 0, timeoutMs};
activeRequests_[requestId] = ri;
httpNetworkManager_->executeRequestEx(httpRequest, requestId, std::bind(&PingTest::onHttpNetworkRequestFinished, this, _1, _2, _3, _4));
}
void PingTest::onHttpNetworkRequestFinished(std::uint64_t requestId, std::uint32_t elapsedMs, std::shared_ptr<WSNetRequestError> error, const std::string &data)
{
auto it = activeRequests_.find(requestId);
assert(it != activeRequests_.end());
if (it->second.callback->isCanceled()) {
activeRequests_.erase(it);
return;
}
bool bSuccess = false;
if (error->isSuccess()) {
auto trimmedData = utils::trim(data);
// Extract HTTP response code from the error object. It must be 200 and returned data must be a valid IP address.
if (error->httpResponseCode() == 200 && utils::isIpAddress(trimmedData)) {
it->second.callback->call(ApiRetCode::kSuccess, trimmedData);
bSuccess = true;
} else if (it->second.curEndpointInd < (endpointsImpl_->endpoints.size() - 1)) {
// try next backup endpoint
it->second.curEndpointInd++;
g_logger->info("Trying backup endpoint for PingTest: {}", endpointsImpl_->endpoints[it->second.curEndpointInd].domain()->c_str());
auto httpRequest = httpNetworkManager_->createGetRequest(endpointsImpl_->endpoints[it->second.curEndpointInd].c_str(), it->second.timeoutMs, false);
httpRequest->setUseDnsCache(false);
httpRequest->setIsWhiteListIps(false);
using namespace std::placeholders;
httpNetworkManager_->executeRequestEx(httpRequest, requestId, std::bind(&PingTest::onHttpNetworkRequestFinished, this, _1, _2, _3, _4));
return;
}
}
if (!bSuccess) {
it->second.callback->call(ApiRetCode::kNetworkError, "");
}
activeRequests_.erase(it);
}
} // namespace wsnet
-38
View File
@@ -1,38 +0,0 @@
#pragma once
#include "WSNetHttpNetworkManager.h"
#include "../baserequest.h"
namespace wsnet {
// This request is different from all the others, so it's placed in a separate class.
// This request is always made through the primary domain windscribe.com and also has a backup domain in case the first one returns something unexpected.
// This request is intended for connectivity tests only and it does not use a failover mechanism.
class PingTest
{
public:
explicit PingTest(WSNetHttpNetworkManager *httpNetworkManager);
virtual ~PingTest();
void doPingTest(std::uint32_t timeoutMs, RequestFinishedCallback callback);
private:
WSNetHttpNetworkManager *httpNetworkManager_;
std::uint64_t curUniqueId_ = 0;
// Forward declare instead of including skyr/url.hpp which brings conflicts to Windows
struct EndpointsImpl;
std::unique_ptr<EndpointsImpl> endpointsImpl_;
struct RequestInfo {
RequestFinishedCallback callback;
int curEndpointInd;
std::uint32_t timeoutMs;
};
std::map<std::uint64_t, RequestInfo> activeRequests_;
void onHttpNetworkRequestFinished(std::uint64_t requestId, std::uint32_t elapsedMs, std::shared_ptr<WSNetRequestError> error, const std::string &data);
};
} // namespace wsnet
@@ -1,134 +0,0 @@
#include "requestexecuterviafailover.h"
#include "utils/wsnet_logger.h"
#include "serverapi_utils.h"
namespace wsnet {
RequestExecuterViaFailover::RequestExecuterViaFailover(WSNetHttpNetworkManager *httpNetworkManager, std::unique_ptr<BaseRequest> request, std::unique_ptr<BaseFailover> failover,
bool bIgnoreSslErrors, bool isConnectedVpnState, WSNetAdvancedParameters *advancedParameters, FailedFailovers &failedFailovers,
RequestExecuterViaFailoverCallback callback) :
httpNetworkManager_(httpNetworkManager),
advancedParameters_(advancedParameters),
request_(std::move(request)),
failover_(std::move(failover)),
bIgnoreSslErrors_(bIgnoreSslErrors),
isConnectedVpnState_(isConnectedVpnState),
isConnectStateChanged_(false),
callback_(callback),
failedFailovers_(failedFailovers)
{
}
RequestExecuterViaFailover::~RequestExecuterViaFailover()
{
if (asyncCallback_) {
asyncCallback_->cancel();
}
}
void RequestExecuterViaFailover::start()
{
// if true then a result is ready immediately
// otherwise we are waiting for the onFailoverCallback
if (failover_->getData(bIgnoreSslErrors_, failoverData_, std::bind(&RequestExecuterViaFailover::onFailoverCallback, this, std::placeholders::_1, std::placeholders::_2))) {
onFailoverCallback(FailoverResult::kSuccess, failoverData_);
}
}
void RequestExecuterViaFailover::setIsConnectedToVpnState(bool isConnected)
{
if (isConnectedVpnState_ != isConnected) {
isConnectStateChanged_ = true;
}
}
void RequestExecuterViaFailover::onFailoverCallback(FailoverResult result, const std::vector<FailoverData> &data)
{
// if connect state changed then we can't be sure what failover worked right. Must repeat the request in ServerAPI
if (isConnectStateChanged_) {
callback_(RequestExecuterRetCode::kConnectStateChanged, std::move(request_), FailoverData(""));
return;
}
if (request_->isCanceled()) {
callback_(RequestExecuterRetCode::kRequestCanceled, std::move(request_), FailoverData(""));
return;
}
if (result == FailoverResult::kFailed) {
callback_(RequestExecuterRetCode::kFailoverFailed, std::move(request_), FailoverData(""));
return;
} else if (result == FailoverResult::kNoNetwork) {
callback_(RequestExecuterRetCode::kNoNetwork, std::move(request_), FailoverData(""));
return;
}
failoverData_ = data;
curIndFailoverData_ = 0;
// if we have already tried this domain and it is failed skip it
// keep in mind the failover can contain several domains
while (curIndFailoverData_ < failoverData_.size() && failedFailovers_.isContains(failoverData_[curIndFailoverData_])) {
g_logger->debug("Got an already failed domain, skip it");
curIndFailoverData_++;
}
if (curIndFailoverData_ >= failoverData_.size())
callback_(RequestExecuterRetCode::kFailoverFailed, std::move(request_), FailoverData(""));
else
executeBaseRequest(failoverData_[curIndFailoverData_]);
}
void RequestExecuterViaFailover::executeBaseRequest(const FailoverData &failoverData)
{
using namespace std::placeholders;
auto httpRequest = serverapi_utils::createHttpRequestWithFailoverParameters(httpNetworkManager_, failoverData, request_.get(), bIgnoreSslErrors_, advancedParameters_->isAPIExtraTLSPadding());
httpRequest->setIsDebugLogCurlError(true);
asyncCallback_ = httpNetworkManager_->executeRequestEx(httpRequest, 0, std::bind(&RequestExecuterViaFailover::onHttpNetworkRequestFinished, this, _1, _2, _3, _4),
std::bind(&RequestExecuterViaFailover::onHttpNetworkRequestProgressCallback, this, _1, _2, _3));
}
void RequestExecuterViaFailover::onHttpNetworkRequestFinished(std::uint64_t httpRequestId, std::uint32_t elapsedMs, std::shared_ptr<WSNetRequestError> error, const std::string &data)
{
asyncCallback_.reset();
if (request_->isCanceled()) {
callback_(RequestExecuterRetCode::kRequestCanceled, std::move(request_), FailoverData(""));
return;
}
// if connect state changed then we can't be sure what failover worked right. Must repeat the request in ServerAPI
if (isConnectStateChanged_) {
callback_(RequestExecuterRetCode::kConnectStateChanged, std::move(request_), FailoverData(""));
return;
}
if (error->isSuccess()) {
request_->handle(data);
if (advancedParameters_->isLogApiResponce()) {
g_logger->info("API request {} finished", request_->name());
g_logger->info("{}", data);
}
}
if (!error->isSuccess() || 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())
callback_(RequestExecuterRetCode::kFailoverFailed, std::move(request_), FailoverData(""));
else
executeBaseRequest(failoverData_[curIndFailoverData_]);
return;
}
callback_(RequestExecuterRetCode::kSuccess, std::move(request_), failoverData_[curIndFailoverData_]);
}
void RequestExecuterViaFailover::onHttpNetworkRequestProgressCallback(std::uint64_t requestId, std::uint64_t bytesReceived, std::uint64_t bytesTotal)
{
if (request_->isCanceled()) {
assert(asyncCallback_);
asyncCallback_->cancel();
asyncCallback_.reset();
callback_(RequestExecuterRetCode::kRequestCanceled, std::move(request_), FailoverData(""));
}
}
} // namespace wsnet
@@ -1,58 +0,0 @@
#pragma once
#include "WSNetHttpNetworkManager.h"
#include "WSNetAdvancedParameters.h"
#include <mutex>
#include <thread>
#include "../baserequest.h"
#include "failover/basefailover.h"
#include "failedfailovers.h"
namespace wsnet {
// Helper class used by ServerAPI.
// Tries to execute a request through the specified failover and returns the result of this execution.
// In short it executes the failover request first and then, if successful, the request itself
enum class RequestExecuterRetCode { kSuccess, kNoNetwork, kRequestCanceled, kFailoverFailed, kConnectStateChanged};
typedef std::function<void(RequestExecuterRetCode retCode, std::unique_ptr<BaseRequest> request, FailoverData failoverData)> RequestExecuterViaFailoverCallback;
// Not thread safe
class RequestExecuterViaFailover
{
public:
// The request starts executing from the constructor immediately
explicit RequestExecuterViaFailover(WSNetHttpNetworkManager *httpNetworkManager, std::unique_ptr<BaseRequest> request, std::unique_ptr<BaseFailover> failover,
bool bIgnoreSslErrors, bool isConnectedVpnState, WSNetAdvancedParameters *advancedParameters, FailedFailovers &failedFailovers,
RequestExecuterViaFailoverCallback callback);
virtual ~RequestExecuterViaFailover();
void start();
void setIsConnectedToVpnState(bool isConnected);
private:
WSNetHttpNetworkManager *httpNetworkManager_;
WSNetAdvancedParameters *advancedParameters_;
RequestExecuterViaFailoverCallback callback_;
FailedFailovers &failedFailovers_;
std::unique_ptr<BaseRequest> request_;
std::unique_ptr<BaseFailover> failover_;
bool bIgnoreSslErrors_;
bool isConnectedVpnState_;
bool isConnectStateChanged_;
std::shared_ptr<WSNetCancelableCallback> asyncCallback_;
std::vector<FailoverData> failoverData_;
int curIndFailoverData_;
void onFailoverCallback(FailoverResult result, const std::vector<FailoverData> &data);
void executeBaseRequest(const FailoverData &failoverData);
void onHttpNetworkRequestFinished(std::uint64_t httpRequestId, std::uint32_t elapsedMs, std::shared_ptr<WSNetRequestError> error, const std::string &data);
// This callback function is necessary to cancel the request as quickly as possible if it was canceled on the calling side
void onHttpNetworkRequestProgressCallback(std::uint64_t requestId, std::uint64_t bytesReceived, std::uint64_t bytesTotal);
};
} // namespace wsnet
-429
View File
@@ -1,429 +0,0 @@
#include "serverapi.h"
#include <spdlog/spdlog.h>
#include "serverapi_impl.h"
#include "serverapi_requestsfactory.h"
#include "settings.h"
namespace wsnet {
ServerAPI::ServerAPI(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager, IFailoverContainer *failoverContainer,
PersistentSettings &persistentSettings, WSNetAdvancedParameters *advancedParameters, ConnectState &connectState) :
io_context_(io_context),
persistentSettings_(persistentSettings),
advancedParameters_(advancedParameters),
connectState_(connectState),
pingTest_(httpNetworkManager)
{
impl_ = std::make_unique<ServerAPI_impl>(httpNetworkManager, failoverContainer, persistentSettings_, advancedParameters, connectState);
subscriberId_ = connectState_.subscribeConnectedToVpnState(std::bind(&ServerAPI::onVPNConnectStateChanged, this, std::placeholders::_1));
}
ServerAPI::~ServerAPI()
{
connectState_.unsubscribeConnectedToVpnState(subscriberId_);
}
void ServerAPI::setApiResolutionsSettings(const std::string &apiRoot, const std::string &assetsRoot)
{
boost::asio::post(io_context_, [this, apiRoot, assetsRoot] {
impl_->setApiResolutionsSettings(apiRoot, assetsRoot);
});
}
void ServerAPI::setIgnoreSslErrors(bool bIgnore)
{
boost::asio::post(io_context_, [this, bIgnore] {
impl_->setIgnoreSslErrors(bIgnore);
});
}
void ServerAPI::resetFailover()
{
boost::asio::post(io_context_, [this] {
impl_->resetFailover();
});
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::setTryingBackupEndpointCallback(WSNetTryingBackupEndpointCallback tryingBackupEndpointCallback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetTryingBackupEndpointCallback>>(tryingBackupEndpointCallback);
boost::asio::post(io_context_, [this, cancelableCallback] {
impl_->setTryingBackupEndpointCallback(cancelableCallback);
});
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::login(const std::string &username, const std::string &password, const std::string &code2fa,
const std::string &secureToken, const std::string &captchaSolution,
const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::login(username, password, code2fa, Settings::instance().sessionTypeId(), secureToken, captchaSolution, captchaTrailX, captchaTrailY, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::session(const std::string &authHash, const std::string &appleId, const std::string &gpDeviceId, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::session(authHash, appleId, gpDeviceId, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::claimVoucherCode(const std::string &authHash, const std::string &voucherCode, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::claimVoucherCode(authHash, voucherCode, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::deleteSession(const std::string &authHash, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::deleteSession(authHash, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::serverLocations(const std::string &language, const std::string &revision, bool isPro, const std::vector<std::string> &alcList, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::serverLocations(persistentSettings_, language, revision, isPro, alcList,
connectState_, advancedParameters_, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::serverCredentials(const std::string &authHash, bool isOpenVpnProtocol, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::serverCredentials(authHash, isOpenVpnProtocol, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::serverConfigs(const std::string &authHash, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::serverConfigs(authHash, Settings::instance().openVpnVersion(), cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::portMap(const std::string &authHash, std::uint32_t version, const std::vector<std::string> &forceProtocols, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::portMap(authHash, version, forceProtocols, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::recordInstall(bool isDesktop, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::recordInstall(isDesktop, Settings::instance().basePlatform(), cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::addEmail(const std::string &authHash, const std::string &email, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::addEmail(authHash, email, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::confirmEmail(const std::string &authHash, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::confirmEmail(authHash, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::signup(const std::string &username, const std::string &password, const std::string &referringUsername,
const std::string &email, const std::string &voucherCode,
const std::string &secureToken, const std::string &captchaSolution,
const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::signup(username, password, referringUsername, email, Settings::instance().sessionTypeId(), voucherCode, secureToken, captchaSolution,captchaTrailX, captchaTrailY, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::webSession(const std::string &authHash, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::webSession(authHash, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::checkUpdate(UpdateChannel updateChannel, const std::string &appVersion, const std::string &appBuild,
const std::string &osVersion, const std::string &osBuild, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::checkUpdate(updateChannel, appVersion, appBuild, osVersion, osBuild, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::debugLog(const std::string &username, const std::string &strLog, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::debugLog(username, strLog, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::speedRating(const std::string &authHash, const std::string &hostname, const std::string &ip, std::int32_t rating, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::speedRating(authHash, hostname, ip, rating, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::staticIps(const std::string &authHash, std::uint32_t version, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::staticIps(authHash, version, Settings::instance().basePlatform(), Settings::instance().deviceId(), cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::pingTest(std::uint32_t timeoutMs, WSNetRequestFinishedCallback callback)
{
// PingTest does not use a failover mechanism and has backup endpoint attempts, so it is implemented in a separate class
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
boost::asio::post(io_context_, [this, timeoutMs, cancelableCallback] { pingTest_.doPingTest(timeoutMs, cancelableCallback); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::notifications(const std::string &authHash, const std::string &pcpid, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::notifications(authHash, pcpid, Settings::instance().language(), cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::getRobertFilters(const std::string &authHash, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::getRobertFilters(authHash, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::setRobertFilter(const std::string &authHash, const std::string &id, std::int32_t status, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::setRobertFilter(authHash, id, status, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::syncRobert(const std::string &authHash, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::syncRobert(authHash, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::wgConfigsInit(const std::string &authHash, const std::string &clientPublicKey, bool deleteOldestKey, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::wgConfigsInit(authHash, clientPublicKey, deleteOldestKey, Settings::instance().deviceId(), cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::wgConfigsConnect(const std::string &authHash, const std::string &clientPublicKey, const std::string &hostname, const std::string &deviceId, const std::string &wgTtl, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::wgConfigsConnect(authHash, clientPublicKey, hostname, deviceId, wgTtl, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::wgConfigsPskRekey(const std::string &authHash, const std::string &clientPublicKey, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::wgConfigsPskRekey(authHash, clientPublicKey, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::myIP(WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::myIP(cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::mobileBillingPlans(const std::string &authHash, const std::string &mobilePlanType, const std::string &promo, int version, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::mobileBillingPlans(authHash, mobilePlanType, promo, version, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::sendPayment(const std::string &authHash, const std::string &appleID, const std::string &appleData, const std::string &appleSIG, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::sendPayment(authHash, appleID, appleData, appleSIG, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::verifyPayment(const std::string &authHash, const std::string &purchaseToken, const std::string &gpPackageName, const std::string &gpProductId, const std::string &type, const std::string &amazonUserId, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::verifyPayment(authHash, purchaseToken, gpPackageName, gpProductId, type, amazonUserId, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::postBillingCpid(const std::string &authHash, const std::string &payCpid, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::postBillingCpid(authHash, payCpid, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::getXpressLoginCode(WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::getXpressLoginCode(cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::verifyXpressLoginCode(const std::string &xpressCode, const std::string &sig, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::verifyXpressLoginCode(xpressCode, sig, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::sendSupportTicket(const std::string &supportEmail, const std::string &supportName,
const std::string &supportSubject, const std::string &supportMessage,
const std::string &supportCategory, const std::string &type, const std::string &channel, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::sendSupportTicket(supportEmail, supportName, supportSubject, supportMessage, supportCategory, type, channel, Settings::instance().basePlatform(), cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::regToken(WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::regToken(cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::signupUsingToken(const std::string &token, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::signupUsingToken(token, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::claimAccount(const std::string &authHash, const std::string &username, const std::string &password, const std::string &email, const std::string &voucherCode, const std::string &claimAccount, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::claimAccount(authHash, username, password, email, voucherCode, claimAccount, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::shakeData(const std::string &authHash, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::shakeData(authHash, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::recordShakeForDataScore(const std::string &authHash, const std::string &score, const std::string &signature, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::recordShakeForDataScore(authHash, Settings::instance().basePlatform(), score, signature, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::verifyTvLoginCode(const std::string &authHash, const std::string &xpressCode, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::verifyTvLoginCode(authHash, xpressCode, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::cancelAccount(const std::string &authHash, const std::string &password, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::cancelAccount(authHash, password, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::sso(const std::string &provider, const std::string &token, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::sso(provider, token, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::authTokenLogin(const std::string &username, bool useAsciiCaptcha, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::authTokenLogin(username, useAsciiCaptcha, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::authTokenSignup(const std::string &username, bool useAsciiCaptcha, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::authTokenSignup(username, useAsciiCaptcha, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::passwordRecovery(const std::string &email, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::passwordRecovery(email, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
std::shared_ptr<WSNetCancelableCallback> ServerAPI::amneziawgUnblockParams(const std::string &authHash, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::amneziawgUnblockParams(authHash, Settings::instance().amneziaWGVersion(), advancedParameters_, cancelableCallback);
boost::asio::post(io_context_, [this, request] { impl_->executeRequest(std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
void ServerAPI::onVPNConnectStateChanged(bool isConnected)
{
boost::asio::post(io_context_, [this, isConnected] {
impl_->setIsConnectedToVpnState(isConnected);
});
}
} // namespace wsnet
-132
View File
@@ -1,132 +0,0 @@
#pragma once
#include "WSNetServerAPI.h"
#include <boost/asio.hpp>
#include "WSNetHttpNetworkManager.h"
#include "WSNetAdvancedParameters.h"
#include "failover/ifailovercontainer.h"
#include "utils/persistentsettings.h"
#include "connectstate.h"
#include "pingtest.h"
namespace wsnet {
class ServerAPI_impl;
class ServerAPI : public WSNetServerAPI
{
public:
explicit ServerAPI(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager, IFailoverContainer *failoverContainer,
PersistentSettings &persistentSettings, WSNetAdvancedParameters *advancedParameters, ConnectState &connectState);
virtual ~ServerAPI();
void setApiResolutionsSettings(const std::string &apiRoot, const std::string &assetsRoot) override;
void setIgnoreSslErrors(bool bIgnore) override;
void resetFailover() override;
std::shared_ptr<WSNetCancelableCallback> setTryingBackupEndpointCallback(WSNetTryingBackupEndpointCallback tryingBackupEndpointCallback) override;
std::shared_ptr<WSNetCancelableCallback> login(const std::string &username, const std::string &password,
const std::string &code2fa, const std::string &secureToken, const std::string &captchaSolution,
const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> session(const std::string &authHash, const std::string &appleId,
const std::string &gpDeviceId, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> claimVoucherCode(const std::string &authHash, const std::string &voucherCode, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> deleteSession(const std::string &authHash, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> serverLocations(const std::string &language, const std::string &revision,
bool isPro, const std::vector<std::string> &alcList,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> serverCredentials(const std::string &authHash, bool isOpenVpnProtocol, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> serverConfigs(const std::string &authHash, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> portMap(const std::string &authHash, std::uint32_t version, const std::vector<std::string> &forceProtocols, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> recordInstall(bool isDesktop, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> addEmail(const std::string &authHash, const std::string &email, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> confirmEmail(const std::string &authHash, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> signup(const std::string &username, const std::string &password, const std::string &referringUsername,
const std::string &email, const std::string &voucherCode, const std::string &secureToken, const std::string &captchaSolution,
const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> webSession(const std::string &authHash, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> checkUpdate(UpdateChannel updateChannel,
const std::string &appVersion, const std::string &appBuild,
const std::string &osVersion, const std::string &osBuild,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> debugLog(const std::string &username, const std::string &strLog, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> speedRating(const std::string &authHash, const std::string &hostname, const std::string &ip,
std::int32_t rating, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> staticIps(const std::string &authHash, std::uint32_t version, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> pingTest(std::uint32_t timeoutMs, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> notifications(const std::string &authHash, const std::string &pcpid, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> getRobertFilters(const std::string &authHash, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> setRobertFilter(const std::string &authHash, const std::string &id, std::int32_t status, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> syncRobert(const std::string &authHash, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> wgConfigsInit(const std::string &authHash, const std::string &clientPublicKey,
bool deleteOldestKey, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> wgConfigsConnect(const std::string &authHash, const std::string &clientPublicKey,
const std::string &hostname, const std::string &deviceId, const std::string &wgTtl,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> wgConfigsPskRekey(const std::string &authHash, const std::string &clientPublicKey,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> myIP(WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> mobileBillingPlans(const std::string &authHash, const std::string &mobilePlanType, const std::string &promo, int version, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> sendPayment(const std::string &authHash, const std::string &appleID, const std::string &appleData, const std::string &appleSIG,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> verifyPayment(const std::string &authHash, const std::string &purchaseToken, const std::string &gpPackageName,
const std::string &gpProductId, const std::string &type, const std::string &amazonUserId,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> postBillingCpid(const std::string &authHash, const std::string &payCpid, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> getXpressLoginCode(WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> verifyXpressLoginCode(const std::string &xpressCode, const std::string &sig, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> sendSupportTicket(const std::string &supportEmail, const std::string &supportName,
const std::string &supportSubject, const std::string &supportMessage,
const std::string &supportCategory,
const std::string &type,
const std::string &channel,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> regToken(WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> signupUsingToken(const std::string &token, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> claimAccount(const std::string &authHash, const std::string &username, const std::string &password,
const std::string &email, const std::string &voucherCode, const std::string &claimAccount,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> shakeData(const std::string &authHash, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> recordShakeForDataScore(const std::string &authHash,
const std::string &score, const std::string &signature,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> verifyTvLoginCode(const std::string &authHash, const std::string &xpressCode,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> cancelAccount(const std::string &authHash, const std::string &password,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> sso(const std::string &provider, const std::string &token,
WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> authTokenLogin(const std::string &username, bool useAsciiCaptcha, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> authTokenSignup(const std::string &username, bool useAsciiCaptcha, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> passwordRecovery(const std::string &email, WSNetRequestFinishedCallback callback) override;
std::shared_ptr<WSNetCancelableCallback> amneziawgUnblockParams(const std::string &authHash, WSNetRequestFinishedCallback callback) override;
private:
std::unique_ptr<ServerAPI_impl> impl_;
boost::asio::io_context &io_context_;
PersistentSettings &persistentSettings_;
WSNetAdvancedParameters *advancedParameters_;
ConnectState &connectState_;
std::uint32_t subscriberId_;
PingTest pingTest_;
void onVPNConnectStateChanged(bool isConnected);
};
} // namespace wsnet
@@ -1,356 +0,0 @@
#include "serverapi_impl.h"
#include "utils/wsnet_logger.h"
#include "settings.h"
#include "serverapi_utils.h"
namespace wsnet {
ServerAPI_impl::ServerAPI_impl(WSNetHttpNetworkManager *httpNetworkManager, IFailoverContainer *failoverContainer, PersistentSettings &persistentSettings,
WSNetAdvancedParameters *advancedParameters, ConnectState &connectState) :
httpNetworkManager_(httpNetworkManager),
advancedParameters_(advancedParameters),
connectState_(connectState),
failoverContainer_(failoverContainer),
persistentSettings_(persistentSettings),
curInternalFailoverInd_(0),
failoverState_(FailoverState::kUnknown)
{
// try reading a failover from the settings
auto failover = failoverContainer_->failoverById(persistentSettings_.failoverId());
// if it fails, use the first one
if (!failover) {
g_logger->info("ServerAPI_impl::ServerAPI_impl, use the first failover");
resetFailover();
} else {
curFailoverUid_ = failover->uniqueId();
startFailoverUid_ = curFailoverUid_;
g_logger->info("ServerAPI_impl::ServerAPI_impl, use a failover from settings");
}
}
ServerAPI_impl::~ServerAPI_impl()
{
for (auto &it : activeHttpRequests_) {
it.second.asyncCallback_->cancel();
}
}
void ServerAPI_impl::setApiResolutionsSettings(const std::string &apiRoot, const std::string &assetsRoot)
{
apiOverrideSettings_.apiRoot = apiRoot;
apiOverrideSettings_.assetsRoot = assetsRoot;
if (!apiOverrideSettings_.isOverriden()) {
g_logger->info("ServerAPI_impl::setApiResolutionsSettings, default behavior, no overridden domains");
} else {
g_logger->info("ServerAPI_impl::setApiResolutionsSettings, overridden domains are set, apiRoot = {}, assetsRoot = {}", apiRoot, assetsRoot);
}
}
void ServerAPI_impl::setIgnoreSslErrors(bool bIgnore)
{
if (!bIgnoreSslErrors_ && bIgnore && failoverState_ != FailoverState::kReady) {
// User turned on ignore SSL errors. If the API is currently not ready, reset failover
resetFailover();
}
bIgnoreSslErrors_ = bIgnore;
g_logger->info("ServerAPI_impl::setIgnoreSslErrors, {}", bIgnore);
}
void ServerAPI_impl::resetFailover()
{
g_logger->info("ServerAPI_impl::resetFailover");
resetFailoverImpl(true);
}
void ServerAPI_impl::setIsConnectedToVpnState(bool isConnected)
{
isConnectedToVpn_ = isConnected;
if (requestExecutorViaFailover_)
requestExecutorViaFailover_->setIsConnectedToVpnState(isConnected);
}
void ServerAPI_impl::setTryingBackupEndpointCallback(std::shared_ptr<CancelableCallback<WSNetTryingBackupEndpointCallback> > tryingBackupEndpointCallback)
{
tryingBackupEndpointCallback_ = tryingBackupEndpointCallback;
}
// execute request if the failover detected or queue
void ServerAPI_impl::executeRequest(std::unique_ptr<BaseRequest> request)
{
//if request already canceled do nothing
if (request->isCanceled()) {
return;
}
request->setApiOverrideSettings(apiOverrideSettings_);
// check if we are online
if (!connectState_.isOnline()) {
request->setRetCode(ServerApiRetCode::kNoNetworkConnection);
request->callCallback();
executeWaitingInQueueRequests();
return;
}
// if API resolution settings overrides the domain of the current request then we use that domain immediately
if (request->isApiDomainOverriden()) {
// In this case FailoverData will be empty, because the domain itself is already contained in the request
executeRequestImpl(std::move(request), FailoverData());
executeWaitingInQueueRequests();
return;
}
// if failover already in progress then move the request to queue
if (requestExecutorViaFailover_) {
// take into account priority
// in particular, wgConfigsInit, wgConfigsConnect and pingTest should have a higher priority in the queue to avoid potential connection delays
if (request->priority() == RequestPriority::kHigh)
queueRequests_.push_front(std::move(request));
else
queueRequests_.push_back(std::move(request));
return;
}
if (isConnectedToVpn_) {
// in the connected mode always use the primary domain
executeRequestImpl(std::move(request), FailoverData(hostnameForConnectedState()));
executeWaitingInQueueRequests();
} else {
assert(requestExecutorViaFailover_ == nullptr);
bool bUseFailover = false;
if (failoverState_ == FailoverState::kUnknown) {
bUseFailover = true;
} else if (failoverState_ == FailoverState::kReady) {
if (failoverData_->isExpired()) {
g_logger->info("The current failover domain is expired. Reset the failover state.");
failoverState_ = FailoverState::kUnknown;
bUseFailover = true;
}
}
if (bUseFailover) {
auto curFailover = failoverContainer_->failoverById(curFailoverUid_);
g_logger->info("Trying: {}", curFailover->name());
// Do not emit this signal for the first failover
if (failoverState_ == FailoverState::kUnknown && curInternalFailoverInd_ > 0 && tryingBackupEndpointCallback_)
tryingBackupEndpointCallback_->call(curInternalFailoverInd_, failoverContainer_->count() - 1);
// 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_, failedFailovers_,
std::bind(&ServerAPI_impl::onRequestExecuterViaFailoverFinished, this, _1, _2, _3)));
requestExecutorViaFailover_->start();
} else {
if (failoverState_ == FailoverState::kReady) {
assert(failoverData_.has_value());
executeRequestImpl(std::move(request), *failoverData_);
} else if (failoverState_ == FailoverState::kFailed) {
logAllFailoversFailed(request.get());
request->setRetCode(ServerApiRetCode::kFailoverFailed);
request->callCallback();
}
}
}
}
void ServerAPI_impl::executeRequestImpl(std::unique_ptr<BaseRequest> request, const FailoverData &failoverData)
{
using namespace std::placeholders;
auto httpRequest = serverapi_utils::createHttpRequestWithFailoverParameters(httpNetworkManager_, failoverData, request.get(), bIgnoreSslErrors_, advancedParameters_->isAPIExtraTLSPadding());
httpRequest->setIsDebugLogCurlError(true);
std::uint64_t requestId = curUniqueId_++;
auto asyncCallback_ = httpNetworkManager_->executeRequestEx(httpRequest, requestId, std::bind(&ServerAPI_impl::onHttpNetworkRequestFinished, this, _1, _2, _3, _4),
std::bind(&ServerAPI_impl::onHttpNetworkRequestProgressCallback, this, _1, _2, _3));
HttpRequestInfo hti { std::move(request), asyncCallback_, !isConnectedToVpn_, false};
activeHttpRequests_[requestId] = std::move(hti);
}
void ServerAPI_impl::executeWaitingInQueueRequests()
{
// We need a copy here because executeRequest can add requests to queueRequests_ to avoid an infinite loop
std::deque<std::unique_ptr<BaseRequest>> copyQueueRequests = std::move(queueRequests_);
queueRequests_.clear();
while (!copyQueueRequests.empty()) {
std::unique_ptr<BaseRequest> req = std::move(copyQueueRequests.front());
copyQueueRequests.pop_front();
executeRequest(std::move(req));
}
}
std::string ServerAPI_impl::hostnameForConnectedState() const
{
return Settings::instance().primaryServerDomain();
}
void ServerAPI_impl::setErrorCodeAndEmitRequestFinished(BaseRequest *request, ServerApiRetCode retCode)
{
request->setRetCode(retCode);
request->callCallback();
}
void ServerAPI_impl::onRequestExecuterViaFailoverFinished(RequestExecuterRetCode retCode, std::unique_ptr<BaseRequest> request, FailoverData failoverData)
{
assert(failoverState_ == FailoverState::kUnknown);
std::unique_ptr<RequestExecuterViaFailover> requestExecutorViaFailoverCopy = std::move(requestExecutorViaFailover_);
requestExecutorViaFailover_.reset();
if (retCode == RequestExecuterRetCode::kSuccess) {
failoverState_ = FailoverState::kReady;
persistentSettings_.setFailoverId(curFailoverUid_);
failoverData_ = failoverData;
request->callCallback();
executeWaitingInQueueRequests();
} else if (retCode == RequestExecuterRetCode::kRequestCanceled) {
executeWaitingInQueueRequests();
} else if (retCode == RequestExecuterRetCode::kFailoverFailed) {
auto nextFailover = getNextFailover();
if (nextFailover) {
curFailoverUid_ = nextFailover->uniqueId();
curInternalFailoverInd_++;
executeRequest(std::move(request));
} else {
// If there was at least one successful request, we never go to state FailoverState::kFailed
// In this case we go through all the failovers again
if (bWasSuccesfullRequest_) {
g_logger->info("API request {} failed: all failovers failed, reset failover", request->name());
resetFailoverImpl(false);
setErrorCodeAndEmitRequestFinished(request.get(), ServerApiRetCode::kNetworkError);
executeWaitingInQueueRequests();
} else {
failoverState_ = FailoverState::kFailed;
if (!isFailoverFailedLogAlreadyDone_) {
g_logger->info("API request {} failed: API not ready", request->name());
isFailoverFailedLogAlreadyDone_ = true;
}
logAllFailoversFailed(request.get());
setErrorCodeAndEmitRequestFinished(request.get(), ServerApiRetCode::kFailoverFailed);
executeWaitingInQueueRequests();
}
}
} else if (retCode == RequestExecuterRetCode::kConnectStateChanged) {
// Repeat the execution of the request via failover
executeRequest(std::move(request));
} else if (retCode == RequestExecuterRetCode::kNoNetwork) {
setErrorCodeAndEmitRequestFinished(request.get(), ServerApiRetCode::kNoNetworkConnection);
executeWaitingInQueueRequests();
} else {
assert(false);
}
}
void ServerAPI_impl::onHttpNetworkRequestFinished(std::uint64_t requestId, std::uint32_t elapsedMs, std::shared_ptr<WSNetRequestError> error, const std::string &data)
{
auto it = activeHttpRequests_.find(requestId);
assert(it != activeHttpRequests_.end());
if (it->second.request->isCanceled()) {
activeHttpRequests_.erase(it);
return;
}
if (error->isSuccess()) {
if (advancedParameters_->isLogApiResponce()) {
g_logger->info("API request {} finished", it->second.request->name());
g_logger->info("{}", data);
}
it->second.request->handle(data);
// handle() may cause the retcode to change. Only call callback here if it's still successful.
if (it->second.request->retCode() == ServerApiRetCode::kSuccess) {
bWasSuccesfullRequest_ = true;
it->second.request->callCallback();
activeHttpRequests_.erase(it);
return;
}
} else if (error->isNoNetworkError()) {
g_logger->info("API request {} failed with error = {}", it->second.request->name(), error->toString());
setErrorCodeAndEmitRequestFinished(it->second.request.get(), ServerApiRetCode::kNoNetworkConnection);
activeHttpRequests_.erase(it);
return;
}
// Either error->isSuccess() is false or the retcode was changed to kIncorrectJson by handle().
g_logger->info("API request {} failed with error = {}", it->second.request->name(), error->toString());
// we need to start going through the backup domains again
// except for the DNS resolve error
if (it->second.bFromDisconnectedVPNState_ && (!error->isDnsError() || it->second.request->retCode() == ServerApiRetCode::kIncorrectJson)) {
if (!it->second.bDiscard) {
resetFailoverImpl(false);
g_logger->info("ServerAPI_impl::onHttpNetworkRequestFinished, reset failover");
// mark all pending requests for discard
for (auto &req : activeHttpRequests_) {
req.second.bDiscard = true;
}
}
// Repeat the execution of the request via failover
executeRequest(std::move(it->second.request));
} else {
setErrorCodeAndEmitRequestFinished(it->second.request.get(), ServerApiRetCode::kNetworkError);
}
activeHttpRequests_.erase(it);
}
void ServerAPI_impl::onHttpNetworkRequestProgressCallback(std::uint64_t requestId, std::uint64_t bytesReceived, std::uint64_t bytesTotal)
{
auto it = activeHttpRequests_.find(requestId);
assert(it != activeHttpRequests_.end());
if (it->second.request->isCanceled()) {
it->second.asyncCallback_->cancel();
activeHttpRequests_.erase(it);
}
}
std::unique_ptr<BaseFailover> ServerAPI_impl::getNextFailover()
{
// switching to the next failover
// we consider the last one to be the one we started with, i.e. startFailoverUid_
auto nextFailover = failoverContainer_->next(curFailoverUid_);
if (!nextFailover) {
// looping
nextFailover = failoverContainer_->first();
}
if (nextFailover->uniqueId() == startFailoverUid_)
return nullptr;
else
return nextFailover;
}
void ServerAPI_impl::resetFailoverImpl(bool toFirst)
{
std::unique_ptr<BaseFailover> failover;
if (toFirst) {
failover = failoverContainer_->first();
} else {
startFailoverUid_.clear();
failover = getNextFailover();
assert(failover);
}
curFailoverUid_ = failover->uniqueId();
startFailoverUid_ = curFailoverUid_;
curInternalFailoverInd_ = 0;
failoverState_ = FailoverState::kUnknown;
failedFailovers_.clear();
persistentSettings_.setFailoverId(""); // clear setting
}
void ServerAPI_impl::logAllFailoversFailed(BaseRequest *request)
{
if (!isFailoverFailedLogAlreadyDone_) {
g_logger->info("API request {} failed: API not ready", request->name());
isFailoverFailedLogAlreadyDone_ = true;
}
}
} // namespace wsnet
@@ -1,93 +0,0 @@
#pragma once
#include "WSNetServerAPI.h"
#include <mutex>
#include <queue>
#include <map>
#include <optional>
#include <atomic>
#include "WSNetHttpNetworkManager.h"
#include "WSNetAdvancedParameters.h"
#include "../baserequest.h"
#include "connectstate.h"
#include "failover/ifailovercontainer.h"
#include "failover/failoverdata.h"
#include "requestexecuterviafailover.h"
#include "utils/cancelablecallback.h"
#include "utils/persistentsettings.h"
#include "connectstate.h"
#include "failedfailovers.h"
namespace wsnet {
class ServerAPI_impl
{
public:
explicit ServerAPI_impl(WSNetHttpNetworkManager *httpNetworkManager, IFailoverContainer *failoverContainer,
PersistentSettings &persistentSettings, WSNetAdvancedParameters *advancedParameters, ConnectState &connectState);
virtual ~ServerAPI_impl();
void setApiResolutionsSettings(const std::string &apiRoot, const std::string &assetsRoot);
void setIgnoreSslErrors(bool bIgnore);
void resetFailover();
void setIsConnectedToVpnState(bool isConnected);
void setTryingBackupEndpointCallback(std::shared_ptr<CancelableCallback<WSNetTryingBackupEndpointCallback>> tryingBackupEndpointCallback);
void executeRequest(std::unique_ptr<BaseRequest> request);
private:
WSNetHttpNetworkManager *httpNetworkManager_;
WSNetAdvancedParameters *advancedParameters_;
ConnectState &connectState_;
IFailoverContainer *failoverContainer_;
std::shared_ptr<CancelableCallback<WSNetTryingBackupEndpointCallback>> tryingBackupEndpointCallback_ = nullptr;
std::deque<std::unique_ptr<BaseRequest>> queueRequests_; // a queue of requests that are waiting for the failover to complete
std::uint64_t curUniqueId_ = 0; // for generate unique identifiers for HTTP-requests
PersistentSettings &persistentSettings_; // The ServerAPISettings class is protected by mutex, so it's thread-safe
ApiOverrideSettings apiOverrideSettings_;
bool bIgnoreSslErrors_ = false;
bool isConnectedToVpn_ = false;
struct HttpRequestInfo {
std::unique_ptr<BaseRequest> request;
std::shared_ptr<WSNetCancelableCallback> asyncCallback_;
bool bFromDisconnectedVPNState_;
bool bDiscard;
};
std::map<std::uint64_t, HttpRequestInfo> activeHttpRequests_;
// current failover state
std::string curFailoverUid_;
std::string startFailoverUid_;
int curInternalFailoverInd_;
enum class FailoverState { kUnknown, kReady, kFailed } failoverState_;
std::unique_ptr<RequestExecuterViaFailover> requestExecutorViaFailover_;
std::optional<FailoverData> failoverData_; // valid only in kReady state
bool isFailoverFailedLogAlreadyDone_ = false; // log "failover failed: API not ready" only once to avoid spam
FailedFailovers failedFailovers_;
bool bWasSuccesfullRequest_ = false; // was at least one successful request?
void executeRequest(std::uint64_t requestId);
void executeRequestImpl(std::unique_ptr<BaseRequest> request, const FailoverData &failoverData);
void executeWaitingInQueueRequests();
std::string hostnameForConnectedState() const;
void setErrorCodeAndEmitRequestFinished(BaseRequest *request, ServerApiRetCode retCode);
void onRequestExecuterViaFailoverFinished(RequestExecuterRetCode retCode, std::unique_ptr<BaseRequest> request, FailoverData failoverData);
void onHttpNetworkRequestFinished(std::uint64_t requestId, std::uint32_t elapsedMs, std::shared_ptr<WSNetRequestError> error, const std::string &data);
// This callback function is necessary to cancel the request as quickly as possible if it was canceled on the calling side
void onHttpNetworkRequestProgressCallback(std::uint64_t requestId, std::uint64_t bytesReceived, std::uint64_t bytesTotal);
std::unique_ptr<BaseFailover> getNextFailover();
void resetFailoverImpl(bool toFirst);
void logAllFailoversFailed(BaseRequest *request);
};
} // namespace wsnet
@@ -1,508 +0,0 @@
#include "serverapi_requestsfactory.h"
#include "setrobertfilter_request.h"
#include "serverlocations_request.h"
#include "utils/utils.h"
#include "utils/urlquery_utils.h"
#include <cpp-base64/base64.h>
#include <cpp-base64/base64.cpp>
namespace wsnet {
BaseRequest *serverapi_requests_factory::login(const std::string &username, const std::string &password, const std::string &code2fa,
const std::string &sessionTypeId, const std::string &secureToken, const std::string &captchaSolution,
const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["username"] = username;
extraParams["password"] = password;
extraParams["2fa_code"] = code2fa;
extraParams["session_type_id"] = sessionTypeId;
auto captchaParams = urlquery_utils::buildCaptchaParams(secureToken, captchaSolution, captchaTrailX, captchaTrailY);
extraParams.insert(captchaParams.begin(), captchaParams.end());
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "Session", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *serverapi_requests_factory::session(const std::string &authHash, const std::string &appleId,
const std::string &gpDeviceId, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["apple_id"] = appleId;
extraParams["gp_device_id"] = gpDeviceId;
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "Session", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::claimVoucherCode(const std::string &authHash, const std::string &voucherCode, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["voucher_code"] = voucherCode;
auto request = new BaseRequest(HttpMethod::kPut, SubdomainType::kApi, RequestPriority::kNormal, "Users", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::deleteSession(const std::string &authHash, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
auto request = new BaseRequest(HttpMethod::kDelete, SubdomainType::kApi, RequestPriority::kNormal, "Session", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::serverLocations(PersistentSettings &persistentSettings, const std::string &language, const std::string &revision, bool isPro, const std::vector<std::string> &alcList,
ConnectState &connectState, WSNetAdvancedParameters *advancedParameters, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
// generate alc parameter
std::string alcField = utils::join(alcList, ",");
if (!alcField.empty())
extraParams["alc"] = alcField;
std::string strIsPro = isPro ? "1" : "0";
return new ServerLocationsRequest(RequestPriority::kNormal, "/serverlist/mob-v2/" + strIsPro + "/" + revision, extraParams, persistentSettings,
connectState, advancedParameters, callback);
}
BaseRequest *serverapi_requests_factory::myIP(RequestFinishedCallback callback)
{
return new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "MyIp", std::map<std::string, std::string>(), callback);
}
BaseRequest *serverapi_requests_factory::serverCredentials(const std::string &authHash, bool isOpenVpnProtocol, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["type"] = isOpenVpnProtocol ? "openvpn" : "ikev2";
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "ServerCredentials", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::serverConfigs(const std::string &authHash, const std::string &ovpnVersion, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["ovpn_version"] = ovpnVersion;
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "ServerConfigs", extraParams, callback);
request->setIgnoreJsonParse();
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::portMap(const std::string &authHash, std::uint32_t version, const std::vector<std::string> &forceProtocols, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["version"] = std::to_string(version);
for (int i = 0; i < forceProtocols.size(); ++i) {
std::string fp = "force_protocols[" + std::to_string(i) + "]";
extraParams[fp] = forceProtocols[i];
}
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "PortMap", extraParams, callback);
request->setContentTypeHeader("Content-type: application/x-www-form-urlencoded");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::recordInstall(bool isDesktop, const std::string &platform, RequestFinishedCallback callback)
{
std::string name;
if (isDesktop)
name = "RecordInstall/app/" + platform;
else
name = "RecordInstall/mobile/" + platform;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, name, std::map<std::string, std::string>(), callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *serverapi_requests_factory::confirmEmail(const std::string &authHash, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["resend_confirmation"] = "1";
auto request = new BaseRequest(HttpMethod::kPut, SubdomainType::kApi, RequestPriority::kNormal, "Users", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::addEmail(const std::string &authHash, const std::string &email, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["email"] = email;
extraParams["email_forced"] = "1";
auto request = new BaseRequest(HttpMethod::kPut, SubdomainType::kApi, RequestPriority::kNormal, "Users", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::signup(const std::string &username, const std::string &password, const std::string &referringUsername, const std::string &email,
const std::string &sessionTypeId, const std::string &voucherCode, const std::string &secureToken, const std::string &captchaSolution,
const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["session_type_id"] = sessionTypeId;
extraParams["username"] = username;
extraParams["password"] = password;
extraParams["referring_username"] = referringUsername;
extraParams["email"] = email;
extraParams["voucher_code"] = voucherCode;
auto captchaParams = urlquery_utils::buildCaptchaParams(secureToken, captchaSolution, captchaTrailX, captchaTrailY);
extraParams.insert(captchaParams.begin(), captchaParams.end());
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "Users", extraParams, callback);
return request;
}
BaseRequest *serverapi_requests_factory::webSession(const std::string &authHash, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["temp_session"] = "1";
extraParams["session_type_id"] = "1";
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "WebSession", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::checkUpdate(UpdateChannel updateChannel, const std::string &appVersion, const std::string &appBuild,
const std::string &osVersion, const std::string &osBuild, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["version"] = appVersion;
extraParams["build"] = appBuild;
if (updateChannel == UpdateChannel::kBeta)
extraParams["beta"] = "1";
else if (updateChannel == UpdateChannel::kGuineaPig)
extraParams["beta"] = "2";
else if (updateChannel == UpdateChannel::kInternal)
extraParams["beta"] = "3";
extraParams["os_version"] = osVersion;
extraParams["os_build"] = osBuild;
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "CheckUpdate", extraParams, callback);
return request;
}
BaseRequest *serverapi_requests_factory::debugLog(const std::string &username, const std::string &strLog, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["logfile"] = base64_encode(strLog);
extraParams["username"] = username;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "Report/applog", extraParams, callback);
request->setContentTypeHeader("Content-type: application/x-www-form-urlencoded");
return request;
}
BaseRequest *serverapi_requests_factory::speedRating(const std::string &authHash, const std::string &hostname, const std::string &ip, std::int32_t rating, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["hostname"] = hostname;
extraParams["ip"] = ip;
extraParams["rating"] = std::to_string(rating);
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "SpeedRating", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::staticIps(const std::string &authHash, std::uint32_t version, const std::string &platform, const std::string &deviceId, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["version"] = std::to_string(version);
extraParams["os"] = platform;
extraParams["device_id"] = deviceId;
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "StaticIps", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::notifications(const std::string &authHash, const std::string &pcpid, const std::string &language, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["pcpid"] = pcpid;
extraParams["lang"] = language;
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "Notifications", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::getRobertFilters(const std::string &authHash, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "Robert/filters", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::setRobertFilter(const std::string &authHash, const std::string &id, std::int32_t status, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
std::string json = "{\"filter\":\"" + id + "\", \"status\":" + std::to_string(status) + "}";
auto request = new SetRobertFilterRequest(HttpMethod::kPut, SubdomainType::kApi, RequestPriority::kNormal, "Robert/filter", extraParams, json, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::syncRobert(const std::string &authHash, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "Robert/syncrobert", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::wgConfigsInit(const std::string &authHash, const std::string &clientPublicKey, bool deleteOldestKey, const std::string &deviceId, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["wg_pubkey"] = clientPublicKey;
extraParams["device_id"] = deviceId;
if (deleteOldestKey)
extraParams["force_init"] = "1";
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kHigh, "WgConfigs/init", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::wgConfigsConnect(const std::string &authHash, const std::string &clientPublicKey, const std::string &hostname, const std::string &deviceId, const std::string &wgTtl, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["wg_pubkey"] = clientPublicKey;
extraParams["hostname"] = hostname;
extraParams["device_id"] = deviceId;
extraParams["wg_ttl"] = wgTtl;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kHigh, "WgConfigs/connect", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::wgConfigsPskRekey(const std::string &authHash, const std::string &clientPublicKey, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["wg_pubkey"] = clientPublicKey;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kHigh, "WgConfigs/psk-rekey", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::mobileBillingPlans(const std::string &authHash, const std::string &mobilePlanType, const std::string &promo, int version, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["mobile_plan_type"] = mobilePlanType;
extraParams["promo_code"] = promo;
extraParams["version"] = std::to_string(version);
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "MobileBillingPlans", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::verifyPayment(const std::string &authHash, const std::string &purchaseToken, const std::string &gpPackageName, const std::string &gpProductId, const std::string &type, const std::string &amazonUserId, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["purchase_token"] = purchaseToken;
extraParams["gp_package_name"] = gpPackageName;
extraParams["gp_product_id"] = gpProductId;
extraParams["type"] = type;
extraParams["amazon_user_id"] = amazonUserId;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "AndroidIPN", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::postBillingCpid(const std::string &authHash, const std::string &payCpid, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["pay_cpid"] = payCpid;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "BillingCpid", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::getXpressLoginCode(RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "XpressLogin", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *serverapi_requests_factory::verifyXpressLoginCode(const std::string &xpressCode, const std::string &sig, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["session_type_id"] = "3";
extraParams["xpress_code"] = xpressCode;
extraParams["sig"] = sig;
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "XpressLogin", extraParams, callback);
return request;
}
BaseRequest *serverapi_requests_factory::sendSupportTicket(const std::string &supportEmail, const std::string &supportName, const std::string &supportSubject, const std::string &supportMessage,
const std::string &supportCategory, const std::string &type, const std::string &channel, const std::string &platform, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["support_email"] = supportEmail;
extraParams["support_name"] = supportName;
extraParams["support_subject"] = supportSubject;
extraParams["support_message"] = supportMessage;
extraParams["support_category"] = supportCategory;
extraParams["issue_metadata[type]"] = type;
extraParams["issue_metadata[channel]"] = channel;
extraParams["issue_metadata[platform]"] = platform;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "SupportTicket", extraParams, callback);
request->setContentTypeHeader("Content-type: application/x-www-form-urlencoded");
return request;
}
BaseRequest *serverapi_requests_factory::regToken(RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "RegToken", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *serverapi_requests_factory::signupUsingToken(const std::string &token, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["token"] = token;
extraParams["session_type_id"] = "4";
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "Users", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *serverapi_requests_factory::claimAccount(const std::string &authHash, const std::string &username, const std::string &password, const std::string &email, const std::string &voucherCode, const std::string &claimAccount, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["username"] = username;
extraParams["password"] = password;
extraParams["email"] = email;
extraParams["voucher_code"] = voucherCode;
extraParams["claim_account"] = claimAccount;
auto request = new BaseRequest(HttpMethod::kPut, SubdomainType::kApi, RequestPriority::kNormal, "Users", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::sendPayment(const std::string &authHash, const std::string &appleID, const std::string &appleData, const std::string &appleSIG, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["apple_id"] = appleID;
extraParams["apple_data"] = appleData;
extraParams["apple_sig"] = appleSIG;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "AppleIPN", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::recordShakeForDataScore(const std::string &authHash, const std::string &platform, const std::string &score, const std::string &signature, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["platform"] = platform;
extraParams["score"] = score;
extraParams["sig"] = signature;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "ShakeData", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::shakeData(const std::string &authHash, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "ShakeData", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::verifyTvLoginCode(const std::string &authHash, const std::string &xpressCode, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["xpress_code"] = xpressCode;
auto request = new BaseRequest(HttpMethod::kPut, SubdomainType::kApi, RequestPriority::kNormal, "XpressLogin", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::cancelAccount(const std::string &authHash, const std::string &password, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["password"] = password;
extraParams["type"] = "account";
extraParams["message"] = "iOS inapp deletetion";
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "Cancel", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
request->setBearerToken(authHash);
return request;
}
BaseRequest *serverapi_requests_factory::sso(const std::string& provider, const std::string& token, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["token"] = token;
std::string path = "Sso/" + provider;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, path, extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *serverapi_requests_factory::authTokenLogin(const std::string &username, bool useAsciiCaptcha, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["username"] = username;
if (useAsciiCaptcha) {
extraParams["captcha_type"] = "ascii";
}
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "AuthToken/login", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *serverapi_requests_factory::authTokenSignup(const std::string &username, bool useAsciiCaptcha, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["username"] = username;
if (useAsciiCaptcha) {
extraParams["captcha_type"] = "ascii";
}
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "AuthToken/signup", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *serverapi_requests_factory::passwordRecovery(const std::string &email, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["email"] = email;
auto request = new BaseRequest(HttpMethod::kPost, SubdomainType::kApi, RequestPriority::kNormal, "PasswordRecovery", extraParams, callback);
request->setContentTypeHeader("Content-type: text/html; charset=utf-8");
return request;
}
BaseRequest *serverapi_requests_factory::amneziawgUnblockParams(const std::string &authHash, const std::string &amneziawgVersion, WSNetAdvancedParameters *advancedParameters, RequestFinishedCallback callback)
{
std::map<std::string, std::string> extraParams;
extraParams["amneziawg_version"] = amneziawgVersion;
if (!advancedParameters->countryOverrideValue().empty()) {
// We always send this if it is available. The AdvancedParameters::isIgnoreCountryOverride doesn't apply here, as we need to send the
// country override to the server to receive Amnezia unblock params specfic to that country.
extraParams["country_override"] = advancedParameters->countryOverrideValue();
}
auto request = new BaseRequest(HttpMethod::kGet, SubdomainType::kApi, RequestPriority::kNormal, "UnblockParams/amneziawg", extraParams, callback);
request->setBearerToken(authHash);
return request;
}
} // namespace wsnet
@@ -1,97 +0,0 @@
#pragma once
#include "../baserequest.h"
#include "utils/persistentsettings.h"
#include "connectstate.h"
#include "WSNetAdvancedParameters.h"
namespace wsnet {
namespace serverapi_requests_factory
{
BaseRequest *login(const std::string &username, const std::string &password, const std::string &code2fa,
const std::string &sessionTypeId, const std::string &secureToken, const std::string &captchaSolution,
const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY, RequestFinishedCallback callback);
BaseRequest *session(const std::string &authHash, const std::string &appleId, const std::string &gpDeviceId, RequestFinishedCallback callback);
BaseRequest *claimVoucherCode(const std::string &authHash, const std::string &voucherCode, RequestFinishedCallback callback);
BaseRequest *deleteSession(const std::string &authHash, RequestFinishedCallback callback);
BaseRequest *serverLocations(PersistentSettings &persistentSettings, const std::string &language, const std::string &revision,
bool isPro, const std::vector<std::string> &alcList, ConnectState &connectState, WSNetAdvancedParameters *advancedParameters,
RequestFinishedCallback callback);
BaseRequest *serverCredentials(const std::string &authHash, bool isOpenVpnProtocol, RequestFinishedCallback callback);
BaseRequest *serverConfigs(const std::string &authHash, const std::string &ovpnVersion, RequestFinishedCallback callback);
BaseRequest *portMap(const std::string &authHash, std::uint32_t version, const std::vector<std::string> &forceProtocols, RequestFinishedCallback callback);
BaseRequest *recordInstall(bool isDesktop, const std::string &platform, RequestFinishedCallback callback);
BaseRequest *addEmail(const std::string &authHash, const std::string &email, RequestFinishedCallback callback);
BaseRequest *confirmEmail(const std::string &authHash, RequestFinishedCallback callback);
BaseRequest *signup(const std::string &username, const std::string &password,
const std::string &referringUsername, const std::string &email,
const std::string &sessionTypeId, const std::string &voucherCode,
const std::string &secureToken, const std::string &captchaSolution,
const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY,RequestFinishedCallback callback);
BaseRequest *webSession(const std::string &authHash, RequestFinishedCallback callback);
BaseRequest *checkUpdate(UpdateChannel updateChannel, const std::string &appVersion, const std::string &appBuild,
const std::string &osVersion, const std::string &osBuild,
RequestFinishedCallback callback);
BaseRequest *debugLog(const std::string &username, const std::string &strLog, RequestFinishedCallback callback);
BaseRequest *speedRating(const std::string &authHash, const std::string &hostname, const std::string &ip,
std::int32_t rating, RequestFinishedCallback callback);
BaseRequest *staticIps(const std::string &authHash, std::uint32_t version, const std::string &platform, const std::string &deviceId, RequestFinishedCallback callback);
BaseRequest *notifications(const std::string &authHash, const std::string &pcpid, const std::string &language, RequestFinishedCallback callback);
BaseRequest *getRobertFilters(const std::string &authHash, RequestFinishedCallback callback);
BaseRequest *setRobertFilter(const std::string &authHash, const std::string &id, std::int32_t status, RequestFinishedCallback callback);
BaseRequest *syncRobert(const std::string &authHash, RequestFinishedCallback callback);
BaseRequest *wgConfigsInit(const std::string &authHash, const std::string &clientPublicKey, bool deleteOldestKey, const std::string &deviceId, RequestFinishedCallback callback);
BaseRequest *wgConfigsConnect(const std::string &authHash, const std::string &clientPublicKey,
const std::string &hostname, const std::string &deviceId, const std::string &wgTtl,
RequestFinishedCallback callback);
BaseRequest *wgConfigsPskRekey(const std::string &authHash, const std::string &clientPublicKey,
RequestFinishedCallback callback);
BaseRequest *myIP(RequestFinishedCallback callback);
BaseRequest *mobileBillingPlans(const std::string &authHash, const std::string &mobilePlanType, const std::string &promo, int version, RequestFinishedCallback callback);
BaseRequest *sendPayment(const std::string &authHash, const std::string &appleID, const std::string &appleData, const std::string &appleSIG, RequestFinishedCallback callback);
BaseRequest *verifyPayment(const std::string &authHash, const std::string &purchaseToken, const std::string &gpPackageName,
const std::string &gpProductId, const std::string &type,
const std::string &amazonUserId,
RequestFinishedCallback callback);
BaseRequest *postBillingCpid(const std::string &authHash, const std::string &payCpid, RequestFinishedCallback callback);
BaseRequest *getXpressLoginCode(RequestFinishedCallback callback);
BaseRequest *verifyXpressLoginCode(const std::string &xpressCode, const std::string &sig, RequestFinishedCallback callback);
BaseRequest *sendSupportTicket(const std::string &supportEmail, const std::string &supportName,
const std::string &supportSubject, const std::string &supportMessage,
const std::string &supportCategory,
const std::string &type,
const std::string &channel,
const std::string &platform,
RequestFinishedCallback callback);
BaseRequest *regToken(RequestFinishedCallback callback);
BaseRequest *signupUsingToken(const std::string &token, RequestFinishedCallback callback);
BaseRequest *claimAccount(const std::string &authHash, const std::string &username, const std::string &password,
const std::string &email, const std::string &voucherCode, const std::string &claimAccount, RequestFinishedCallback callback);
BaseRequest *shakeData(const std::string &authHash, RequestFinishedCallback callback);
BaseRequest *recordShakeForDataScore(const std::string &authHash, const std::string &platform,
const std::string &score, const std::string &signature,
RequestFinishedCallback callback);
BaseRequest *verifyTvLoginCode(const std::string &authHash, const std::string &xpressCode, RequestFinishedCallback callback);
BaseRequest *cancelAccount(const std::string &authHash, const std::string &password, RequestFinishedCallback callback);
BaseRequest *sso(const std::string &provider, const std::string &token, RequestFinishedCallback callback);
BaseRequest *authTokenLogin(const std::string &username, bool useAsciiCaptcha, RequestFinishedCallback callback);
BaseRequest *authTokenSignup(const std::string &username, bool useAsciiCaptcha, RequestFinishedCallback callback);
BaseRequest *passwordRecovery(const std::string &email, RequestFinishedCallback callback);
BaseRequest *amneziawgUnblockParams(const std::string &authHash, const std::string &amneziawgVersion, WSNetAdvancedParameters *advancedParameters, RequestFinishedCallback callback);
}
} // namespace wsnet
@@ -1,52 +0,0 @@
#include "serverapi_utils.h"
namespace wsnet {
std::shared_ptr<WSNetHttpRequest> serverapi_utils::createHttpRequestWithFailoverParameters(WSNetHttpNetworkManager *httpNetworkManager, const FailoverData &failoverData, BaseRequest *request,
bool bIgnoreSslErrors, bool isAPIExtraTLSPadding)
{
// Make sure the network return code is reset
request->setRetCode(ServerApiRetCode::kSuccess);
std::shared_ptr<WSNetHttpRequest> httpRequest;
switch (request->requestType()) {
case HttpMethod::kGet:
httpRequest = httpNetworkManager->createGetRequest(request->url(failoverData.domain()), request->timeout(), bIgnoreSslErrors);
break;
case HttpMethod::kPost:
httpRequest = httpNetworkManager->createPostRequest(request->url(failoverData.domain()), request->timeout(), request->postData(), bIgnoreSslErrors);
break;
case HttpMethod::kDelete:
httpRequest = httpNetworkManager->createDeleteRequest(request->url(failoverData.domain()), request->timeout(), bIgnoreSslErrors);
break;
case HttpMethod::kPut:
httpRequest = httpNetworkManager->createPutRequest(request->url(failoverData.domain()), request->timeout(), request->postData(), bIgnoreSslErrors);
break;
default:
assert(false);
}
if (!request->isUseDnsCache())
httpRequest->setUseDnsCache(false);
if (!failoverData.echConfig().empty())
httpRequest->setEchConfig(failoverData.echConfig());
if (isAPIExtraTLSPadding)
httpRequest->setExtraTLSPadding(true);
if (!failoverData.sniDomain().empty()) {
httpRequest->setSniDomain(failoverData.sniDomain());
// Force-disable Extra Padding for CDN domains
httpRequest->setExtraTLSPadding(false);
}
// Add Authorization header if bearer token is present
if (!request->bearerToken().empty()) {
httpRequest->addHttpHeader("Authorization: Bearer " + request->bearerToken());
}
return httpRequest;
}
} // namespace wsnet
@@ -1,14 +0,0 @@
#pragma once
#include "WSNetHttpNetworkManager.h"
#include "failover/failoverdata.h"
#include "../baserequest.h"
namespace wsnet {
namespace serverapi_utils {
std::shared_ptr<WSNetHttpRequest> createHttpRequestWithFailoverParameters(WSNetHttpNetworkManager *httpNetworkManager, const FailoverData &failoverData, BaseRequest *request,
bool bIgnoreSslErrors, bool isAPIExtraTLSPadding);
}
} // namespace wsnet
@@ -1,102 +0,0 @@
#include "serverlocations_request.h"
#include <skyr/url.hpp>
#include "utils/wsnet_logger.h"
#include <rapidjson/document.h>
namespace wsnet {
ServerLocationsRequest::ServerLocationsRequest(RequestPriority priority, const std::string &name,
std::map<std::string, std::string> extraParams, PersistentSettings &persistentSettings,
ConnectState &connectState, WSNetAdvancedParameters *advancedParameters, RequestFinishedCallback callback) :
BaseRequest(HttpMethod::kGet, SubdomainType::kAssets, priority, name, extraParams, callback),
persistentSettings_(persistentSettings),
connectState_(connectState),
advancedParameters_(advancedParameters)
{
}
std::string ServerLocationsRequest::url(const std::string &domain) const
{
isFromDisconnectedVPNState_ = !connectState_.isVPNConnected();
auto url = skyr::url("https://" + hostname(domain, subDomainType_) + "/" + name());
auto &sp = url.search_parameters();
for (auto &it : extraParams_)
if (!it.second.empty())
sp.set(it.first, it.second);
// country override logic
std::string countryOverride;
if (advancedParameters_->isIgnoreCountryOverride()) {
// Instruct the serverlist endpoint to ignore geolocation based on our IP.
countryOverride = "ZZ";
}
else {
if (!advancedParameters_->countryOverrideValue().empty()) {
countryOverride = advancedParameters_->countryOverrideValue();
} else if (connectState_.isVPNConnected()) {
if (!persistentSettings_.countryOverride().empty()) {
countryOverride = persistentSettings_.countryOverride();
}
}
}
if (!countryOverride.empty()) {
sp.set("country_override", countryOverride);
g_logger->info("API request ServerLocations added countryOverride = {}", countryOverride);
}
return url.c_str();
}
void ServerLocationsRequest::handle(const std::string &arr)
{
if (arr.empty()) {
setRetCode(ServerApiRetCode::kIncorrectJson);
return;
}
if (!isIgnoreJsonParse_) {
using namespace rapidjson;
Document doc;
doc.Parse(arr.c_str());
if (doc.HasParseError() || !doc.IsObject()) {
setRetCode(ServerApiRetCode::kIncorrectJson);
return;
}
auto jsonObject = doc.GetObject();
// all responses must contain errorCode or/and data fields
if (!jsonObject.HasMember("errorCode") && !jsonObject.HasMember("data")) {
setRetCode(ServerApiRetCode::kIncorrectJson);
return;
}
// manage the country override flag according to the documentation
// https://gitlab.int.windscribe.com/ws/client/desktop/client-desktop-public/-/issues/354
if (!jsonObject.HasMember("info")) {
setRetCode(ServerApiRetCode::kIncorrectJson);
return;
}
auto jsonInfo = jsonObject["info"].GetObject();
if (jsonInfo.HasMember("country_override")) {
if (isFromDisconnectedVPNState_ && (!connectState_.isVPNConnected())) {
auto countryOverride = jsonInfo["country_override"].GetString();
persistentSettings_.setCountryOverride(countryOverride);
g_logger->info("API request ServerLocations saved countryOverride = {}", countryOverride);
}
} else {
if (isFromDisconnectedVPNState_ && (!connectState_.isVPNConnected())) {
persistentSettings_.setCountryOverride(std::string());
g_logger->info("API request ServerLocations removed countryOverride flag");
}
}
}
json_ = arr;
}
} // namespace wsnet
@@ -1,34 +0,0 @@
#pragma once
#include <map>
#include "WSNetAdvancedParameters.h"
#include "../baserequest.h"
#include "utils/persistentsettings.h"
#include "connectstate.h"
namespace wsnet {
// This request is different from all the others, so we make a class with overriding behavior
// In particular, the country override logic needs to be executed here
// Also, do not pass client_auth_hash, platform, version parameters for this request
class ServerLocationsRequest : public BaseRequest
{
public:
explicit ServerLocationsRequest(RequestPriority priority, const std::string &name,
std::map<std::string, std::string> extraParams, PersistentSettings &persistentSettings,
ConnectState &connectState, WSNetAdvancedParameters *advancedParameters, RequestFinishedCallback callback);
virtual ~ServerLocationsRequest() {};
std::string url(const std::string &domain) const override;
void handle(const std::string &arr) override;
private:
PersistentSettings &persistentSettings_;
mutable bool isFromDisconnectedVPNState_;
ConnectState &connectState_;
WSNetAdvancedParameters *advancedParameters_;
};
} // namespace wsnet
@@ -1,33 +0,0 @@
#include "setrobertfilter_request.h"
#include <skyr/url.hpp>
#include "utils/urlquery_utils.h"
namespace wsnet {
SetRobertFilterRequest::SetRobertFilterRequest(HttpMethod requestType, SubdomainType subDomainType, RequestPriority priority, const std::string &name,
std::map<std::string, std::string> extraParams, const std::string &jsonPostData, RequestFinishedCallback callback) :
BaseRequest(requestType, subDomainType, priority, name, extraParams, callback),
jsonPostData_(jsonPostData)
{
}
std::string SetRobertFilterRequest::url(const std::string &domain) const
{
auto url = skyr::url("https://" + hostname(domain, subDomainType_) + "/" + name());
auto &sp = url.search_parameters();
for (auto &it : extraParams_)
if (!it.second.empty())
sp.set(it.first, it.second);
urlquery_utils::addPlatformQueryItems(sp);
return url.c_str();
}
std::string SetRobertFilterRequest::postData() const
{
return jsonPostData_;
}
} // namespace wsnet
@@ -1,25 +0,0 @@
#pragma once
#include <map>
#include "../baserequest.h"
namespace wsnet {
// This request is different from all the others, so we make a class with overriding behavior
class SetRobertFilterRequest : public BaseRequest
{
public:
explicit SetRobertFilterRequest(HttpMethod requestType, SubdomainType subDomainType, RequestPriority priority, const std::string &name,
std::map<std::string, std::string> extraParams, const std::string &jsonPostData,
RequestFinishedCallback callback);
virtual ~SetRobertFilterRequest() {};
std::string url(const std::string &domain) const override;
std::string postData() const override;
private:
std::string jsonPostData_;
};
} // namespace wsnet
@@ -1,87 +0,0 @@
#include "wsnet_utils_impl.h"
#include "serverapi_requestsfactory.h"
namespace wsnet {
WSNetUtils_impl::WSNetUtils_impl(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager,
IFailoverContainer *failoverContainer, WSNetAdvancedParameters *advancedParameters) :
io_context_(io_context),
httpNetworkManager_(httpNetworkManager),
advancedParameters_(advancedParameters),
failoverContainer_(failoverContainer)
{
}
WSNetUtils_impl::~WSNetUtils_impl()
{
activeRequests_.clear();
}
std::int32_t WSNetUtils_impl::failoverCount() const
{
return failoverContainer_->count();
}
std::string WSNetUtils_impl::failoverName(int failoverInd) const
{
return failoverByInd(failoverInd)->name();
}
std::shared_ptr<WSNetCancelableCallback> WSNetUtils_impl::myIPViaFailover(int failoverInd, WSNetRequestFinishedCallback callback)
{
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetRequestFinishedCallback>>(callback);
BaseRequest *request = serverapi_requests_factory::myIP(cancelableCallback);
boost::asio::post(io_context_, [this, failoverInd, request] { myIPViaFailover_impl(failoverInd, std::unique_ptr<BaseRequest>(request)); });
return cancelableCallback;
}
void WSNetUtils_impl::myIPViaFailover_impl(int failoverInd, std::unique_ptr<BaseRequest> request)
{
using namespace std::placeholders;
auto failover = failoverByInd(failoverInd);
RequestExecuterViaFailover *requestExecutorViaFailover = new RequestExecuterViaFailover(httpNetworkManager_, std::move(request), std::move(failover),
false, false, advancedParameters_, failedFailovers_,
std::bind(&WSNetUtils_impl::onRequestExecuterViaFailoverFinished, this, _1, _2, _3, curUniqueId_));
activeRequests_[curUniqueId_] = std::unique_ptr<RequestExecuterViaFailover>(requestExecutorViaFailover);
curUniqueId_++;
requestExecutorViaFailover->start();
}
void WSNetUtils_impl::onRequestExecuterViaFailoverFinished(RequestExecuterRetCode retCode, std::unique_ptr<BaseRequest> request, FailoverData failoverData, std::uint64_t id)
{
activeRequests_.erase(id);
if (retCode == RequestExecuterRetCode::kSuccess) {
request->callCallback();
} else if (retCode == RequestExecuterRetCode::kRequestCanceled) {
// nothing todo
} else if (retCode == RequestExecuterRetCode::kFailoverFailed) {
request->setRetCode(ServerApiRetCode::kFailoverFailed);
request->callCallback();
} else if (retCode == RequestExecuterRetCode::kConnectStateChanged) {
request->setRetCode(ServerApiRetCode::kNetworkError);
request->callCallback();
} else {
assert(false);
}
}
std::unique_ptr<BaseFailover> WSNetUtils_impl::failoverByInd(int ind) const
{
assert (ind >= 0 && ind < failoverContainer_->count());
int i = 0;
std::unique_ptr<BaseFailover> failover = failoverContainer_->first();
assert(failover);
while (failover) {
if (ind == i)
return failover;
failover = failoverContainer_->next(failover->uniqueId());
i++;
}
return nullptr;
}
} // namespace wsnet
@@ -1,38 +0,0 @@
#pragma once
#include "WSNetUtils.h"
#include <boost/asio.hpp>
#include "WSNetHttpNetworkManager.h"
#include "failover/ifailovercontainer.h"
#include "failedfailovers.h"
#include "requestexecuterviafailover.h"
namespace wsnet {
class WSNetUtils_impl : public WSNetUtils
{
public:
explicit WSNetUtils_impl(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager,
IFailoverContainer *failoverContainer, WSNetAdvancedParameters *advancedParameters);
virtual ~WSNetUtils_impl();
std::int32_t failoverCount() const override;
std::string failoverName(int failoverInd) const override;
std::shared_ptr<WSNetCancelableCallback> myIPViaFailover(int failoverInd, WSNetRequestFinishedCallback callback) override;
private:
boost::asio::io_context &io_context_;
WSNetHttpNetworkManager *httpNetworkManager_;
WSNetAdvancedParameters *advancedParameters_;
IFailoverContainer *failoverContainer_;
std::uint64_t curUniqueId_ = 0;
std::map<std::uint64_t, std::unique_ptr<RequestExecuterViaFailover> > activeRequests_;
FailedFailovers failedFailovers_;
void myIPViaFailover_impl(int failoverInd, std::unique_ptr<BaseRequest> request);
void onRequestExecuterViaFailoverFinished(RequestExecuterRetCode retCode, std::unique_ptr<BaseRequest> request, FailoverData failoverData, std::uint64_t id);
std::unique_ptr<BaseFailover> failoverByInd(int ind) const;
};
} // namespace wsnet
@@ -1,6 +0,0 @@
target_sources(wsnet PRIVATE
apiresourcesmanager.cpp
apiresourcesmanager.h
sessionstatus.cpp
sessionstatus.h
)
@@ -1,822 +0,0 @@
#include "apiresourcesmanager.h"
#include "utils/wsnet_logger.h"
#include "utils/cancelablecallback.h"
#include "utils/utils.h"
#include "settings.h"
namespace wsnet {
using namespace std::chrono;
ApiResourcesManager::ApiResourcesManager(boost::asio::io_context &io_context, WSNetServerAPI *serverAPI, PersistentSettings &persistentSettings, ConnectState &connectState) :
io_context_(io_context),
fetchTimer_(io_context, boost::asio::chrono::seconds(1)),
serverAPI_(serverAPI),
persistentSettings_(persistentSettings),
connectState_(connectState)
{
sessionStatus_.reset(SessionStatus::createFromJson(persistentSettings_.sessionStatus()));
}
ApiResourcesManager::~ApiResourcesManager()
{
fetchTimer_.cancel();
for (const auto &it : requestsInProgress_) {
it.second->cancel();
}
}
std::shared_ptr<WSNetCancelableCallback> ApiResourcesManager::setCallback(WSNetApiResourcesManagerCallback callback)
{
std::lock_guard locker(mutex_);
if (callback == nullptr) {
callback_.reset();
return nullptr;
} else {
callback_ = std::make_shared<CancelableCallback<WSNetApiResourcesManagerCallback>>(callback);
return callback_;
}
}
void ApiResourcesManager::setAuthHash(const std::string &authHash)
{
std::lock_guard locker(mutex_);
persistentSettings_.setAuthHash(authHash);
}
bool ApiResourcesManager::isExist() const
{
std::lock_guard locker(mutex_);
return !persistentSettings_.authHash().empty() &&
!persistentSettings_.sessionStatus().empty() &&
!persistentSettings_.locations().empty() &&
!persistentSettings_.serverCredentialsOvpn().empty() &&
!persistentSettings_.serverCredentialsIkev2().empty() &&
!persistentSettings_.serverConfigs().empty() &&
!persistentSettings_.portMap().empty() &&
!persistentSettings_.staticIps().empty() &&
!persistentSettings_.notifications().empty();
}
bool ApiResourcesManager::loginWithAuthHash()
{
std::lock_guard locker(mutex_);
if (requestsInProgress_.find(RequestType::kSessionStatus) != requestsInProgress_.end()) {
g_logger->error("Incorrect use of API, the function ApiResourcesManager::loginWithAuthHash is called twice");
assert(false);
}
if (persistentSettings_.authHash().empty())
return false;
using namespace std::placeholders;
requestsInProgress_[RequestType::kSessionStatus] = serverAPI_->session(persistentSettings_.authHash(), appleId_, gpDeviceId_, std::bind(&ApiResourcesManager::onInitialSessionAnswer, this, _1, _2));
return true;
}
void ApiResourcesManager::authTokenLogin(const std::string &username, bool useAsciiCaptcha)
{
std::lock_guard locker(mutex_);
if (requestsInProgress_.find(RequestType::kAuthTokenLogin) != requestsInProgress_.end()) {
g_logger->error("Incorrect use of API, the function ApiResourcesManager::authTokenLogin is called twice");
assert(false);
}
using namespace std::placeholders;
requestsInProgress_[RequestType::kAuthTokenLogin] = serverAPI_->authTokenLogin(username, useAsciiCaptcha, std::bind(&ApiResourcesManager::onAuthTokenLoginAnswer, this, username, useAsciiCaptcha, _1, _2));
}
void ApiResourcesManager::login(const std::string &username, const std::string &password, const std::string &code2fa, const std::string &secureToken,
const std::string &captchaSolution, const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY)
{
std::lock_guard locker(mutex_);
if (requestsInProgress_.find(RequestType::kSessionStatus) != requestsInProgress_.end()) {
g_logger->error("Incorrect use of API, the function ApiResourcesManager::login is called twice");
assert(false);
}
using namespace std::placeholders;
requestsInProgress_[RequestType::kSessionStatus] = serverAPI_->login(username, password, code2fa, secureToken, captchaSolution, captchaTrailX, captchaTrailY,
std::bind(&ApiResourcesManager::onLoginAnswer, this, _1, _2, username, password, code2fa, secureToken, captchaSolution, captchaTrailX, captchaTrailY));
}
void ApiResourcesManager::logout()
{
std::lock_guard locker(mutex_);
fetchTimer_.cancel();
using namespace std::placeholders;
serverAPI_->deleteSession(persistentSettings_.authHash(), std::bind(&ApiResourcesManager::onDeleteSessionAnswer, this, _1, _2));
clearValues();
}
void ApiResourcesManager::fetchSession()
{
std::lock_guard locker(mutex_);
lastUpdateTimeMs_.erase(RequestType::kSessionStatus);
}
void ApiResourcesManager::fetchServerCredentials()
{
std::lock_guard locker(mutex_);
assert(!isFetchingServerCredentials_);
isFetchingServerCredentials_ = true;
isOpenVpnCredentialsReceived_ = false;
isIkev2CredentialsReceived_ = false;
isServerConfigsReceived_ = false;
lastUpdateTimeMs_.erase(RequestType::kServerCredentialsOpenVPN);
lastUpdateTimeMs_.erase(RequestType::kServerCredentialsIkev2);
lastUpdateTimeMs_.erase(RequestType::kServerConfigs);
auto authHash = persistentSettings_.authHash();
fetchServerCredentialsOpenVpn(authHash);
fetchServerCredentialsIkev2(authHash);
fetchServerConfigs(authHash);
}
std::string ApiResourcesManager::authHash()
{
return persistentSettings_.authHash();
}
void ApiResourcesManager::removeFromPersistentSettings()
{
std::lock_guard locker(mutex_);
clearValues();
}
void ApiResourcesManager::checkUpdate(UpdateChannel channel, const std::string &appVersion, const std::string &appBuild, const std::string &osVersion, const std::string &osBuild)
{
std::lock_guard locker(mutex_);
checkUpdateData_.channel = channel;
checkUpdateData_.appVersion = appVersion;
checkUpdateData_.appBuild = appBuild;
checkUpdateData_.osVersion = osVersion;
checkUpdateData_.osBuild = osBuild;
lastUpdateTimeMs_.erase(RequestType::kCheckUpdate);
isCheckUpdateDataSet_ = true;
}
void ApiResourcesManager::setNotificationPcpid(const std::string &pcpid)
{
std::lock_guard locker(mutex_);
pcpidNotifications_ = pcpid;
}
void ApiResourcesManager::setMobileDeviceId(const std::string &appleId, const std::string &gpDeviceId)
{
std::lock_guard locker(mutex_);
appleId_ = appleId;
gpDeviceId_ = gpDeviceId;
}
std::string ApiResourcesManager::sessionStatus() const
{
return persistentSettings_.sessionStatus();
}
std::string ApiResourcesManager::portMap() const
{
return persistentSettings_.portMap();
}
std::string ApiResourcesManager::locations() const
{
return persistentSettings_.locations();
}
std::string ApiResourcesManager::staticIps() const
{
return persistentSettings_.staticIps();
}
std::string ApiResourcesManager::serverCredentialsOvpn() const
{
return persistentSettings_.serverCredentialsOvpn();
}
std::string ApiResourcesManager::serverCredentialsIkev2() const
{
return persistentSettings_.serverCredentialsIkev2();
}
std::string ApiResourcesManager::serverConfigs() const
{
return persistentSettings_.serverConfigs();
}
std::string ApiResourcesManager::notifications() const
{
return persistentSettings_.notifications();
}
std::string ApiResourcesManager::checkUpdate() const
{
std::lock_guard locker(mutex_);
return checkUpdate_;
}
std::string ApiResourcesManager::amneziawgUnblockParams() const
{
return persistentSettings_.amneziawgUnblockParams();
}
std::string ApiResourcesManager::authTokenLoginResult() const
{
std::lock_guard locker(mutex_);
return authTokenLoginResult_;
}
void ApiResourcesManager::setUpdateIntervals(int sessionInDisconnectedStateMs, int sessionInConnectedStateMs,
int locationsMs, int staticIpsMs, int serverConfigsAndCredentialsMs,
int portMapMs, int notificationsMs, int checkUpdateMs, int amneziawgUnblockParamsMs)
{
std::lock_guard locker(mutex_);
sessionInDisconnectedStateMs_ = sessionInDisconnectedStateMs;
sessionInConnectedStateMs_ = sessionInConnectedStateMs;
locationsMs_ = locationsMs;
staticIpsMs_ = staticIpsMs;
serverConfigsAndCredentialsMs_ = serverConfigsAndCredentialsMs;
portMapMs_ = portMapMs;
notificationsMs_ = notificationsMs;
checkUpdateMs_ = checkUpdateMs;
amneziawgUnblockParamsMs_ = amneziawgUnblockParamsMs;
}
void ApiResourcesManager::handleLoginOrSessionAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
std::unique_ptr<SessionStatus> ss(SessionStatus::createFromJson(jsonData));
if (ss) {
if (ss->errorCode() == SessionErrorCode::kSuccess) {
sessionStatus_ = std::move(ss);
persistentSettings_.setSessionStatus(jsonData);
if (!sessionStatus_->authHash().empty()) {
persistentSettings_.setAuthHash(sessionStatus_->authHash());
}
lastUpdateTimeMs_[RequestType::kSessionStatus] = { steady_clock::now(), true };
updateSessionStatus();
checkForReadyLogin();
fetchAll();
// start the update timer
fetchTimer_.async_wait(std::bind(&ApiResourcesManager::onFetchTimer, this, std::placeholders::_1));
} else if (ss->errorCode() == SessionErrorCode::kBadUsername) {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kBadUsername, ss->errorMessage());
} else if (ss->errorCode() == SessionErrorCode::kMissingCode2FA) {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kMissingCode2fa, ss->errorMessage());
} else if (ss->errorCode() == SessionErrorCode::kBadCode2FA) {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kBadCode2fa, ss->errorMessage());
} else if (ss->errorCode() == SessionErrorCode::kAccountDisabled) {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kAccountDisabled, ss->errorMessage());
} else if (ss->errorCode() == SessionErrorCode::kSessionInvalid) {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kSessionInvalid, ss->errorMessage());
} else if (ss->errorCode() == SessionErrorCode::kRateLimited) {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kRateLimited, ss->errorMessage());
} else if (ss->errorCode() == SessionErrorCode::kInvalidSecurityToken) {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kInvalidSecurityToken, ss->errorMessage());
} else {
assert(false);
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kNoApiConnectivity, ss->errorMessage());
}
} else {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kIncorrectJson, std::string());
}
} else if (serverApiRetCode == ServerApiRetCode::kNoNetworkConnection) {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kNoConnectivity, std::string());
} else if (serverApiRetCode == ServerApiRetCode::kIncorrectJson) {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kIncorrectJson, std::string());
} else if (serverApiRetCode == ServerApiRetCode::kFailoverFailed) {
callback_->call(ApiResourcesManagerNotification::kLoginFailed, LoginResult::kNoApiConnectivity, std::string());
} else {
assert(false);
}
}
void ApiResourcesManager::checkForReadyLogin()
{
if (!persistentSettings_.authHash().empty() &&
!persistentSettings_.sessionStatus().empty() &&
!persistentSettings_.locations().empty() &&
!persistentSettings_.serverCredentialsOvpn().empty() &&
!persistentSettings_.serverCredentialsIkev2().empty() &&
!persistentSettings_.serverConfigs().empty() &&
!persistentSettings_.portMap().empty() &&
!persistentSettings_.staticIps().empty() &&
!persistentSettings_.notifications().empty()) {
if (!isLoginOkEmitted_) {
isLoginOkEmitted_ = true;
callback_->call(ApiResourcesManagerNotification::kLoginOk, LoginResult::kSuccess, std::string());
}
}
}
void ApiResourcesManager::checkForServerCredentialsFetchFinished()
{
if (isFetchingServerCredentials_ && isOpenVpnCredentialsReceived_ && isIkev2CredentialsReceived_ && isServerConfigsReceived_) {
isFetchingServerCredentials_ = false;
callback_->call(ApiResourcesManagerNotification::kServerCredentialsUpdated, LoginResult::kSuccess, std::string());
}
}
void ApiResourcesManager::fetchAll()
{
// fetch session
if (connectState_.isVPNConnected()) {
// every 1 min in the connected state
if (isTimeoutForRequest(RequestType::kSessionStatus, sessionInConnectedStateMs_))
fetchSession(persistentSettings_.authHash());
} else {
// every 1 hour in the disconnected state
if (isTimeoutForRequest(RequestType::kSessionStatus, sessionInDisconnectedStateMs_))
fetchSession(persistentSettings_.authHash());
}
// fetch locations every 24 hours
if (isTimeoutForRequest(RequestType::kLocations, locationsMs_))
fetchLocations();
// fetch static ips every 24 hours
if (isTimeoutForRequest(RequestType::kStaticIps, staticIpsMs_))
fetchStaticIps(persistentSettings_.authHash());
// fetch server configs every 24 hours
if (isTimeoutForRequest(RequestType::kServerConfigs, serverConfigsAndCredentialsMs_))
fetchServerConfigs(persistentSettings_.authHash());
// fetch server credentials every 24 hours
if (isTimeoutForRequest(RequestType::kServerCredentialsOpenVPN, serverConfigsAndCredentialsMs_))
fetchServerCredentialsOpenVpn(persistentSettings_.authHash());
if (isTimeoutForRequest(RequestType::kServerCredentialsIkev2, serverConfigsAndCredentialsMs_))
fetchServerCredentialsIkev2(persistentSettings_.authHash());
// fetch portmap every 24 hours
if (isTimeoutForRequest(RequestType::kPortMap, portMapMs_))
fetchPortMap(persistentSettings_.authHash());
// fetch notifications every 1 hour
if (isTimeoutForRequest(RequestType::kNotifications, notificationsMs_))
fetchNotifications(persistentSettings_.authHash());
// fetch updates every 24 hour
if (isCheckUpdateDataSet_ && isTimeoutForRequest(RequestType::kCheckUpdate, checkUpdateMs_))
fetchCheckUpdate();
// fetch amneziawg unblock params every 24 hours
if (isTimeoutForRequest(RequestType::kAmneziawgUnblockParams, amneziawgUnblockParamsMs_))
fetchAmneziawgUnblockParams(persistentSettings_.authHash());
}
void ApiResourcesManager::fetchSession(const std::string &authHash)
{
if (requestsInProgress_.find(RequestType::kSessionStatus) != requestsInProgress_.end())
return;
using namespace std::placeholders;
requestsInProgress_[RequestType::kSessionStatus] = serverAPI_->session(authHash, appleId_, gpDeviceId_, std::bind(&ApiResourcesManager::onSessionAnswer, this, _1, _2));
}
void ApiResourcesManager::fetchLocations()
{
if (requestsInProgress_.find(RequestType::kLocations) != requestsInProgress_.end())
return;
using namespace std::placeholders;
requestsInProgress_[RequestType::kLocations] = serverAPI_->serverLocations("en", sessionStatus_->revisionHash(), sessionStatus_->isPremium(), sessionStatus_->alcList(),
std::bind(&ApiResourcesManager::onServerLocationsAnswer, this, _1, _2));
}
void ApiResourcesManager::fetchStaticIps(const std::string &authHash)
{
if (requestsInProgress_.find(RequestType::kStaticIps) != requestsInProgress_.end())
return;
if (sessionStatus_->staticIpsCount() > 0) {
using namespace std::placeholders;
requestsInProgress_[RequestType::kStaticIps] = serverAPI_->staticIps(authHash, 2, std::bind(&ApiResourcesManager::onStaticIpsAnswer, this, _1, _2));
} else {
// We can't use an empty string because the initialization logic relies on comparison with the empty string
// So use empty json object
persistentSettings_.setStaticIps("{}");
lastUpdateTimeMs_[RequestType::kStaticIps] = { steady_clock::now(), true };
checkForReadyLogin();
if (isLoginOkEmitted_)
callback_->call(ApiResourcesManagerNotification::kStaticIpsUpdated, LoginResult::kSuccess, std::string());
else
checkForReadyLogin();
}
}
void ApiResourcesManager::fetchServerConfigs(const std::string &authHash)
{
if (requestsInProgress_.find(RequestType::kServerConfigs) != requestsInProgress_.end())
return;
using namespace std::placeholders;
requestsInProgress_[RequestType::kServerConfigs] = serverAPI_->serverConfigs(authHash,
std::bind(&ApiResourcesManager::onServerConfigsAnswer, this, _1, _2));
}
void ApiResourcesManager::fetchServerCredentialsOpenVpn(const std::string &authHash)
{
if (requestsInProgress_.find(RequestType::kServerCredentialsOpenVPN) != requestsInProgress_.end())
return;
using namespace std::placeholders;
requestsInProgress_[RequestType::kServerCredentialsOpenVPN] = serverAPI_->serverCredentials(authHash, true,
std::bind(&ApiResourcesManager::onServerCredentialsOpenVpnAnswer, this, _1, _2));
}
void ApiResourcesManager::fetchServerCredentialsIkev2(const std::string &authHash)
{
if (requestsInProgress_.find(RequestType::kServerCredentialsIkev2) != requestsInProgress_.end())
return;
using namespace std::placeholders;
requestsInProgress_[RequestType::kServerCredentialsIkev2] = serverAPI_->serverCredentials(authHash, false,
std::bind(&ApiResourcesManager::onServerCredentialsIkev2Answer, this, _1, _2));
}
void ApiResourcesManager::fetchPortMap(const std::string &authHash)
{
if (requestsInProgress_.find(RequestType::kPortMap) != requestsInProgress_.end())
return;
using namespace std::placeholders;
requestsInProgress_[RequestType::kPortMap] = serverAPI_->portMap(authHash, 6, std::vector<std::string>(),
std::bind(&ApiResourcesManager::onPortMapAnswer, this, _1, _2));
}
void ApiResourcesManager::fetchNotifications(const std::string &authHash)
{
if (requestsInProgress_.find(RequestType::kNotifications) != requestsInProgress_.end())
return;
using namespace std::placeholders;
requestsInProgress_[RequestType::kNotifications] = serverAPI_->notifications(authHash, pcpidNotifications_,
std::bind(&ApiResourcesManager::onNotificationsAnswer, this, _1, _2));
}
void ApiResourcesManager::fetchCheckUpdate()
{
if (requestsInProgress_.find(RequestType::kCheckUpdate) != requestsInProgress_.end())
return;
using namespace std::placeholders;
requestsInProgress_[RequestType::kCheckUpdate] = serverAPI_->checkUpdate(checkUpdateData_.channel, checkUpdateData_.appVersion, checkUpdateData_.appBuild,
checkUpdateData_.osVersion, checkUpdateData_.osBuild,
std::bind(&ApiResourcesManager::onCheckUpdateAnswer, this, _1, _2));
}
void ApiResourcesManager::fetchAmneziawgUnblockParams(const std::string &authHash)
{
if (requestsInProgress_.find(RequestType::kAmneziawgUnblockParams) != requestsInProgress_.end())
return;
using namespace std::placeholders;
requestsInProgress_[RequestType::kAmneziawgUnblockParams] =
serverAPI_->amneziawgUnblockParams(authHash, std::bind(&ApiResourcesManager::onAmneziawgUnblockParamsAnswer, this, _1, _2));
}
void ApiResourcesManager::updateSessionStatus()
{
assert(sessionStatus_);
if (prevSessionStatus_) {
if (prevSessionStatus_->isPremium() != sessionStatus_->isPremium() ||
prevSessionStatus_->status() != sessionStatus_->status() ||
prevSessionStatus_->rebill() != sessionStatus_->rebill() ||
prevSessionStatus_->billingPlanId() != sessionStatus_->billingPlanId() ||
prevSessionStatus_->premiumExpiredDate() != sessionStatus_->premiumExpiredDate() ||
prevSessionStatus_->trafficMax() != sessionStatus_->trafficMax() ||
prevSessionStatus_->username() != sessionStatus_->username() ||
prevSessionStatus_->userId() != sessionStatus_->userId() ||
prevSessionStatus_->email() != sessionStatus_->email() ||
prevSessionStatus_->emailStatus() != sessionStatus_->emailStatus() ||
prevSessionStatus_->staticIpsCount() != sessionStatus_->staticIpsCount() ||
prevSessionStatus_->alcList() != sessionStatus_->alcList() ||
prevSessionStatus_->lastResetDate() != sessionStatus_->lastResetDate())
{
g_logger->info("update session status (changed since last call)");
sessionStatus_->debugLog();
}
if (prevSessionStatus_->revisionHash() != sessionStatus_->revisionHash() || prevSessionStatus_->isPremium() != sessionStatus_->isPremium() ||
prevSessionStatus_->billingPlanId() != sessionStatus_->billingPlanId() ||
prevSessionStatus_->alcList() != sessionStatus_->alcList() || (prevSessionStatus_->status() != 1 && sessionStatus_->status() == 1)) {
fetchLocations();
}
if (prevSessionStatus_->revisionHash() != sessionStatus_->revisionHash() || prevSessionStatus_->staticIpsCount() != sessionStatus_->staticIpsCount() ||
sessionStatus_->isContainsStaticDeviceId(Settings::instance().deviceId()) ||
prevSessionStatus_->isPremium() != sessionStatus_->isPremium() ||
prevSessionStatus_->billingPlanId() != sessionStatus_->billingPlanId()) {
fetchStaticIps(persistentSettings_.authHash());
}
if (prevSessionStatus_->isPremium() != sessionStatus_->isPremium() || prevSessionStatus_->billingPlanId() != sessionStatus_->billingPlanId()) {
fetchServerCredentialsOpenVpn(persistentSettings_.authHash());
fetchServerCredentialsIkev2(persistentSettings_.authHash());
fetchNotifications(persistentSettings_.authHash());
}
if (prevSessionStatus_->status() == 2 && sessionStatus_->status() == 1) {
fetchServerCredentialsOpenVpn(persistentSettings_.authHash());
fetchServerCredentialsIkev2(persistentSettings_.authHash());
}
} else {
g_logger->info("update session status (changed since last call)");
sessionStatus_->debugLog();
}
prevSessionStatus_ = std::make_unique<SessionStatus>(sessionStatus_.get());
if (isLoginOkEmitted_)
callback_->call(ApiResourcesManagerNotification::kSessionUpdated, LoginResult::kSuccess, std::string());
}
void ApiResourcesManager::onFetchTimer(const boost::system::error_code &err)
{
if (err)
return;
std::lock_guard locker(mutex_);
if (!persistentSettings_.authHash().empty()) {
fetchAll();
} else {
g_logger->error("ApiResourcesManager::onFetchTimer, authHash is empty although it shouldn't");
assert(false);
}
// repeat the update timer
fetchTimer_.expires_after(boost::asio::chrono::seconds(1));
fetchTimer_.async_wait(std::bind(&ApiResourcesManager::onFetchTimer, this, std::placeholders::_1));
}
void ApiResourcesManager::onAuthTokenLoginAnswer(const std::string &username, bool useAsciiCaptcha, ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
requestsInProgress_.erase(RequestType::kAuthTokenLogin);
if (serverApiRetCode == ServerApiRetCode::kNetworkError) {
// repeat the request
boost::asio::post(io_context_, [this, username, useAsciiCaptcha] {
authTokenLogin(username, useAsciiCaptcha);
});
} else if (serverApiRetCode == ServerApiRetCode::kNoNetworkConnection) {
callback_->call(ApiResourcesManagerNotification::kAuthTokenLoginFinished, LoginResult::kNoConnectivity, std::string());
} else if (serverApiRetCode == ServerApiRetCode::kIncorrectJson) {
callback_->call(ApiResourcesManagerNotification::kAuthTokenLoginFinished, LoginResult::kIncorrectJson, std::string());
} else if (serverApiRetCode == ServerApiRetCode::kFailoverFailed) {
callback_->call(ApiResourcesManagerNotification::kAuthTokenLoginFinished, LoginResult::kNoApiConnectivity, std::string());
} else {
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
authTokenLoginResult_ = jsonData;
} else {
authTokenLoginResult_.clear();
}
callback_->call(ApiResourcesManagerNotification::kAuthTokenLoginFinished, LoginResult::kSuccess, std::string());
}
}
void ApiResourcesManager::onInitialSessionAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
requestsInProgress_.erase(RequestType::kSessionStatus);
if (serverApiRetCode == ServerApiRetCode::kNetworkError) {
// repeat the request in 1 sec
auto timer = std::make_shared<boost::asio::steady_timer>(io_context_);
timer->expires_after(std::chrono::seconds(1));
timer->async_wait(
[this, timer](const boost::system::error_code& ec) {
if (!ec) {
loginWithAuthHash();
}
}
);
} else {
handleLoginOrSessionAnswer(serverApiRetCode, jsonData);
}
}
void ApiResourcesManager::onLoginAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData, const std::string &username, const std::string &password, const std::string &code2fa, const std::string &secureToken,
const std::string &captchaSolution, const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY)
{
std::lock_guard locker(mutex_);
requestsInProgress_.erase(RequestType::kSessionStatus);
if (serverApiRetCode == ServerApiRetCode::kNetworkError) {
// repeat the request in 1 sec
auto timer = std::make_shared<boost::asio::steady_timer>(io_context_);
timer->expires_after(std::chrono::seconds(1));
timer->async_wait(
[this, timer, username, password, code2fa, secureToken, captchaSolution, captchaTrailX, captchaTrailY](const boost::system::error_code& ec) {
if (!ec) {
login(username, password, code2fa, secureToken, captchaSolution, captchaTrailX, captchaTrailY);
}
}
);
} else {
handleLoginOrSessionAnswer(serverApiRetCode, jsonData);
}
}
void ApiResourcesManager::onSessionAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
std::unique_ptr<SessionStatus> ss(SessionStatus::createFromJson(jsonData));
if (ss) {
if (ss->errorCode() == SessionErrorCode::kSuccess) {
sessionStatus_ = std::move(ss);
persistentSettings_.setSessionStatus(jsonData);
updateSessionStatus();
} else if (ss->errorCode() == SessionErrorCode::kSessionInvalid) {
callback_->call(ApiResourcesManagerNotification::kSessionDeleted, LoginResult::kSuccess, std::string());
}
}
}
lastUpdateTimeMs_[RequestType::kSessionStatus] = { steady_clock::now(), serverApiRetCode == ServerApiRetCode::kSuccess };
requestsInProgress_.erase(RequestType::kSessionStatus);
}
void ApiResourcesManager::onServerLocationsAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
persistentSettings_.setLocations(jsonData);
if (isLoginOkEmitted_)
callback_->call(ApiResourcesManagerNotification::kLocationsUpdated, LoginResult::kSuccess, std::string());
else
checkForReadyLogin();
}
lastUpdateTimeMs_[RequestType::kLocations] = { steady_clock::now(), serverApiRetCode == ServerApiRetCode::kSuccess };
requestsInProgress_.erase(RequestType::kLocations);
}
void ApiResourcesManager::onStaticIpsAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
persistentSettings_.setStaticIps(jsonData);
checkForReadyLogin();
if (isLoginOkEmitted_)
callback_->call(ApiResourcesManagerNotification::kStaticIpsUpdated, LoginResult::kSuccess, std::string());
else
checkForReadyLogin();
}
lastUpdateTimeMs_[RequestType::kStaticIps] = { steady_clock::now(), serverApiRetCode == ServerApiRetCode::kSuccess };
requestsInProgress_.erase(RequestType::kStaticIps);
}
void ApiResourcesManager::onServerConfigsAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
persistentSettings_.setServerConfigs(jsonData);
isServerConfigsReceived_ = true;
checkForServerCredentialsFetchFinished();
checkForReadyLogin();
}
lastUpdateTimeMs_[RequestType::kServerConfigs] = { steady_clock::now(), serverApiRetCode == ServerApiRetCode::kSuccess };
requestsInProgress_.erase(RequestType::kServerConfigs);
}
void ApiResourcesManager::onServerCredentialsOpenVpnAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
persistentSettings_.setServerCredentialsOvpn(jsonData);
isOpenVpnCredentialsReceived_ = true;
checkForServerCredentialsFetchFinished();
checkForReadyLogin();
}
lastUpdateTimeMs_[RequestType::kServerCredentialsOpenVPN] = { steady_clock::now(), serverApiRetCode == ServerApiRetCode::kSuccess };
requestsInProgress_.erase(RequestType::kServerCredentialsOpenVPN);
}
void ApiResourcesManager::onServerCredentialsIkev2Answer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
persistentSettings_.setServerCredentialsIkev2(jsonData);
isIkev2CredentialsReceived_ = true;
checkForServerCredentialsFetchFinished();
checkForReadyLogin();
}
lastUpdateTimeMs_[RequestType::kServerCredentialsIkev2] = { steady_clock::now(), serverApiRetCode == ServerApiRetCode::kSuccess };
requestsInProgress_.erase(RequestType::kServerCredentialsIkev2);
}
void ApiResourcesManager::onPortMapAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
persistentSettings_.setPortMap(jsonData);
checkForReadyLogin();
}
lastUpdateTimeMs_[RequestType::kPortMap] = { steady_clock::now(), serverApiRetCode == ServerApiRetCode::kSuccess };
requestsInProgress_.erase(RequestType::kPortMap);
}
void ApiResourcesManager::onNotificationsAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
persistentSettings_.setNotifications(jsonData);
if (isLoginOkEmitted_)
callback_->call(ApiResourcesManagerNotification::kNotificationsUpdated, LoginResult::kSuccess, std::string());
else
checkForReadyLogin();
}
lastUpdateTimeMs_[RequestType::kNotifications] = { steady_clock::now(), serverApiRetCode == ServerApiRetCode::kSuccess };
requestsInProgress_.erase(RequestType::kNotifications);
}
void ApiResourcesManager::onCheckUpdateAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
checkUpdate_ = jsonData;
callback_->call(ApiResourcesManagerNotification::kCheckUpdate, LoginResult::kSuccess, std::string());
}
lastUpdateTimeMs_[RequestType::kCheckUpdate] = { steady_clock::now(), serverApiRetCode == ServerApiRetCode::kSuccess };
requestsInProgress_.erase(RequestType::kCheckUpdate);
}
void ApiResourcesManager::onAmneziawgUnblockParamsAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
if (serverApiRetCode == ServerApiRetCode::kSuccess) {
persistentSettings_.setAmneziawgUnblockParams(jsonData);
callback_->call(ApiResourcesManagerNotification::kAmneziawgUnblockParamsFinished, LoginResult::kSuccess, std::string());
}
lastUpdateTimeMs_[RequestType::kAmneziawgUnblockParams] = { steady_clock::now(), serverApiRetCode == ServerApiRetCode::kSuccess };
requestsInProgress_.erase(RequestType::kAmneziawgUnblockParams);
}
void ApiResourcesManager::onDeleteSessionAnswer(ServerApiRetCode serverApiRetCode, const std::string &jsonData)
{
std::lock_guard locker(mutex_);
g_logger->info("ApiResourcesManager::onDeleteSessionAnswer retCode: {}", (int)serverApiRetCode);
callback_->call(ApiResourcesManagerNotification::kLogoutFinished, LoginResult::kSuccess, std::string());
}
bool ApiResourcesManager::isTimeoutForRequest(RequestType requestType, int timeout)
{
auto it = lastUpdateTimeMs_.find(requestType);
if (it == lastUpdateTimeMs_.end())
return true;
if (it->second.isRequestSuccess) {
if (utils::since(it->second.updateTime).count() > timeout)
return true;
} else {
if (utils::since(it->second.updateTime).count() > kDelayBetweenFailedRequests)
return true;
}
return false;
}
void ApiResourcesManager::clearValues()
{
g_logger->info("ApiResourcesManager::clearValues");
isFetchingServerCredentials_ = false;
isLoginOkEmitted_ = false;
sessionStatus_.reset();
prevSessionStatus_.reset();
checkUpdate_.clear();
lastUpdateTimeMs_.clear();
persistentSettings_.setAuthHash(std::string());
persistentSettings_.setSessionStatus(std::string());
persistentSettings_.setLocations(std::string());
persistentSettings_.setServerCredentialsOvpn(std::string());
persistentSettings_.setServerCredentialsIkev2(std::string());
persistentSettings_.setServerConfigs(std::string());
persistentSettings_.setPortMap(std::string());
persistentSettings_.setStaticIps(std::string());
persistentSettings_.setNotifications(std::string());
}
} // namespace wsnet
@@ -1,175 +0,0 @@
#pragma once
#include "WSNetApiResourcesManager.h"
#include <boost/asio.hpp>
#include <optional>
#include "WSNetServerAPI.h"
#include "connectstate.h"
#include "sessionstatus.h"
#include "utils/persistentsettings.h"
#include "utils/cancelablecallback.h"
namespace wsnet {
enum class RequestType { kSessionStatus, kAuthTokenLogin, kLocations, kServerCredentialsOpenVPN, kServerCredentialsIkev2, kServerConfigs, kPortMap, kStaticIps, kNotifications, kCheckUpdate, kAmneziawgUnblockParams };
class ApiResourcesManager : public WSNetApiResourcesManager
{
public:
explicit ApiResourcesManager(boost::asio::io_context &io_context, WSNetServerAPI *serverAPI, PersistentSettings &persistentSettings, ConnectState &connectState);
virtual ~ApiResourcesManager();
std::shared_ptr<WSNetCancelableCallback> setCallback(WSNetApiResourcesManagerCallback callback) override;
void setAuthHash(const std::string &authHash) override;
bool isExist() const override;
bool loginWithAuthHash() override;
void authTokenLogin(const std::string &username, bool useAsciiCaptcha) override;
void login(const std::string &username, const std::string &password, const std::string &code2fa, const std::string &secureToken,
const std::string &captchaSolution = std::string(),
const std::vector<float> &captchaTrailX = std::vector<float>(),
const std::vector<float> &captchaTrailY = std::vector<float>()) override;
void logout() override;
void fetchSession() override;
void fetchServerCredentials() override;
std::string authHash() override;
// Is this need?
void removeFromPersistentSettings() override;
void checkUpdate(UpdateChannel channel, const std::string &appVersion, const std::string &appBuild,
const std::string &osVersion, const std::string &osBuild) override;
void setNotificationPcpid(const std::string &pcpid) override;
void setMobileDeviceId(const std::string &appleId, const std::string &gpDeviceId) override;
std::string sessionStatus() const override;
std::string portMap() const override;
std::string locations() const override;
std::string staticIps() const override;
std::string serverCredentialsOvpn() const override;
std::string serverCredentialsIkev2() const override;
std::string serverConfigs() const override;
std::string notifications() const override;
std::string checkUpdate() const override;
std::string authTokenLoginResult() const override;
std::string amneziawgUnblockParams() const override;
void setUpdateIntervals(int sessionInDisconnectedStateMs, int sessionInConnectedStateMs,
int locationsMs, int staticIpsMs, int serverConfigsAndCredentialsMs,
int portMapMs, int notificationsMs, int checkUpdateMs, int amneziawgUnblockParamsMs) override;
private:
mutable std::mutex mutex_;
std::shared_ptr<CancelableCallback<WSNetApiResourcesManagerCallback>> callback_ = nullptr;
boost::asio::io_context &io_context_;
boost::asio::steady_timer fetchTimer_;
WSNetServerAPI *serverAPI_;
PersistentSettings &persistentSettings_;
ConnectState &connectState_;
std::unique_ptr<SessionStatus> sessionStatus_;
std::unique_ptr<SessionStatus> prevSessionStatus_;
std::string checkUpdate_;
std::string pcpidNotifications_;
std::string appleId_;
std::string gpDeviceId_;
std::string authTokenLoginResult_; // result from authTokenLogin call
static constexpr int kMinute = 60 * 1000;
static constexpr int kHour = 60 * 60 * 1000;
static constexpr int k24Hours = 24 * 60 * 60 * 1000;
static constexpr int kDelayBetweenFailedRequests = 1000;
// update intervals
int sessionInDisconnectedStateMs_ = kHour;
int sessionInConnectedStateMs_ = kMinute;
int locationsMs_ = k24Hours;
int staticIpsMs_ = k24Hours;
int serverConfigsAndCredentialsMs_ = k24Hours;
int portMapMs_ = k24Hours;
int notificationsMs_ = kHour;
int checkUpdateMs_ = k24Hours;
int amneziawgUnblockParamsMs_ = k24Hours;
struct UpdateInfo {
std::chrono::time_point<std::chrono::steady_clock> updateTime;
bool isRequestSuccess;
};
std::map<RequestType, UpdateInfo > lastUpdateTimeMs_;
std::map<RequestType, std::shared_ptr<wsnet::WSNetCancelableCallback> > requestsInProgress_;
bool isLoginOkEmitted_ = false;
// internal variables for fetchServerCredentials() functionality
bool isFetchingServerCredentials_ = false;
bool isOpenVpnCredentialsReceived_;
bool isIkev2CredentialsReceived_;
bool isServerConfigsReceived_;
struct
{
UpdateChannel channel;
std::string appVersion;
std::string appBuild;
std::string osVersion;
std::string osBuild;
} checkUpdateData_;
bool isCheckUpdateDataSet_ = false;
void handleLoginOrSessionAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void checkForReadyLogin();
void checkForServerCredentialsFetchFinished();
void fetchAll();
void fetchSession(const std::string &authHash);
void fetchLocations();
void fetchStaticIps(const std::string &authHash);
void fetchServerConfigs(const std::string &authHash);
void fetchServerCredentialsOpenVpn(const std::string &authHash);
void fetchServerCredentialsIkev2(const std::string &authHash);
void fetchPortMap(const std::string &authHash);
void fetchNotifications(const std::string &authHash);
void fetchCheckUpdate();
void fetchAmneziawgUnblockParams(const std::string &authHash);
void updateSessionStatus();
void onFetchTimer(boost::system::error_code const& err);
void onAuthTokenLoginAnswer(const std::string &username, bool useAsciiCaptcha, wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onInitialSessionAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onLoginAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData,
const std::string &username, const std::string &password, const std::string &code2fa,
const std::string &secureToken,
const std::string &captchaSolution, const std::vector<float> &captchaTrailX, const std::vector<float> &captchaTrailY);
void onSessionAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onServerLocationsAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onStaticIpsAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onServerConfigsAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onServerCredentialsOpenVpnAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onServerCredentialsIkev2Answer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onPortMapAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onNotificationsAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onCheckUpdateAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onAmneziawgUnblockParamsAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
void onDeleteSessionAnswer(wsnet::ServerApiRetCode serverApiRetCode, const std::string &jsonData);
bool isTimeoutForRequest(RequestType requestType, int timeout);
void clearValues();
};
} // namespace wsnet
@@ -1,265 +0,0 @@
#include "sessionstatus.h"
#include <rapidjson/document.h>
#include "utils/wsnet_logger.h"
namespace {
std::string safeGetString(const rapidjson::Document::Object &obj, const std::string &name)
{
if (!obj.HasMember(name.c_str()))
return std::string();
if (obj[name.c_str()].IsNull())
return std::string();
assert(obj[name.c_str()].IsString());
return obj[name.c_str()].GetString();
}
}
namespace wsnet {
SessionStatus *SessionStatus::createFromJson(const std::string &json)
{
if (json.empty()) {
return nullptr;
}
using namespace rapidjson;
Document doc;
doc.Parse(json.c_str());
if (doc.HasParseError() || !doc.IsObject()) {
return nullptr;
}
SessionStatus *ss = new SessionStatus;
auto jsonObj = doc.GetObject();
if (jsonObj.HasMember("errorCode")) {
int errorCode = jsonObj["errorCode"].GetInt();
switch (errorCode)
{
// 701 - will be returned if the supplied session_auth_hash is invalid. Any authenticated endpoint can
// throw this error. This can happen if the account gets disabled, or they rotate their session
// secret (pressed Delete Sessions button in the My Account section). We should terminate the
// tunnel and go to the login screen.
case 701:
ss->errorCode_ = SessionErrorCode::kSessionInvalid;
break;
// 702 - will be returned ONLY in the login flow, and means the supplied credentials were not valid.
// Currently we disregard the API errorMessage and display the hardcoded ones (this is for
// multi-language support).
case 702:
ss->errorCode_ = SessionErrorCode::kBadUsername;
break;
// 703 - deprecated / never returned anymore, however we should still keep this for future purposes.
// If 703 is thrown on login (and only on login), display the exact errorMessage to the user,
// instead of what we do for 702 errors.
// 706 - this is thrown only on login flow, and means the target account is disabled or banned.
// Do exactly the same thing as for 703 - show the errorMessage.
case 703:
case 706:
ss->errorMessage_ = safeGetString(jsonObj, "errorMessage");
ss->errorCode_ = SessionErrorCode::kAccountDisabled;
break;
// 707 - We have been rate limited by the server. Ask user to try later.
case 707:
ss->errorCode_ = SessionErrorCode::kRateLimited;
break;
// 708 - Invalid or expired security token
case 708:
ss->errorMessage_ = safeGetString(jsonObj, "errorMessage");
ss->errorCode_ = SessionErrorCode::kInvalidSecurityToken;
break;
case 1340:
ss->errorCode_ = SessionErrorCode::kMissingCode2FA;
break;
case 1341:
ss->errorCode_ = SessionErrorCode::kBadCode2FA;
break;
default:
ss->errorCode_ = SessionErrorCode::kUnknownError;
}
return ss;
}
auto data = jsonObj["data"].GetObject();
// check for required fields in json
std::vector<std::string> required_fileds = {"status", "is_premium", "billing_plan_id", "traffic_used", "traffic_max", "user_id",
"username", "email", "email_status", "loc_hash"};
for (const auto &it : required_fileds)
if (!data.HasMember(it.c_str())) {
delete ss;
return nullptr;
}
if (data.HasMember("session_auth_hash"))
ss->authHash_ = safeGetString(data, "session_auth_hash");
ss->jsonData_ = json;
ss->status_ = data["status"].GetInt();
ss->is_premium_ = (data["is_premium"].GetInt() == 1); // 0 - free, 1 - premium
ss->billingPlanId_ = data["billing_plan_id"].GetInt();
ss->trafficUsed_ = data["traffic_used"].GetInt64();
ss->trafficMax_ = data["traffic_max"].GetInt64();
ss->userId_ = safeGetString(data, "user_id");
ss->username_ = safeGetString(data, "username");
ss->email_ = safeGetString(data, "email");
ss->emailStatus_ = data["email_status"].GetInt();
ss->revisionHash_ = safeGetString(data, "loc_hash");
if (data.HasMember("rebill"))
ss->rebill_ = data["rebill"].GetInt();
else
ss->rebill_ = 0;
if (data.HasMember("premium_expiry_date"))
ss->premiumExpireDate_ = safeGetString(data, "premium_expiry_date");
if (data.HasMember("last_reset")) {
ss->lastResetDate_ = safeGetString(data, "last_reset");
}
ss->alc_.clear();
if (data.HasMember("alc") && data["alc"].IsArray()) {
auto alcArray = data["alc"].GetArray();
for (auto it = alcArray.begin(); it != alcArray.end(); ++it) {
ss->alc_.push_back(it->GetString());
}
}
ss->staticIps_ = 0;
ss->staticIpsUpdateDevices_.clear();
if (data.HasMember("sip") && data["sip"].IsObject()) {
auto objSip = data["sip"].GetObject();
if (objSip.HasMember("count")) {
ss->staticIps_ = objSip["count"].GetInt();
}
if (objSip.HasMember("update") && objSip["update"].IsArray()) {
auto jsonUpdateIps = objSip["update"].GetArray();
for (auto it = jsonUpdateIps.begin(); it != jsonUpdateIps.end(); ++it) {
ss->staticIpsUpdateDevices_.insert(it->GetString());
}
}
}
return ss;
}
std::uint32_t SessionStatus::staticIpsCount() const
{
return staticIps_;
}
bool SessionStatus::isContainsStaticDeviceId(const std::string &deviceId) const
{
return staticIpsUpdateDevices_.find(deviceId) != staticIpsUpdateDevices_.end();
}
std::string SessionStatus::revisionHash() const
{
return revisionHash_;
}
bool SessionStatus::isPremium() const
{
return is_premium_;
}
std::vector<std::string> SessionStatus::alcList() const
{
return alc_;
}
std::string SessionStatus::username() const
{
return username_;
}
std::string SessionStatus::userId() const
{
return userId_;
}
std::string SessionStatus::email() const
{
return email_;
}
std::int32_t SessionStatus::emailStatus() const
{
return emailStatus_;
}
std::int32_t SessionStatus::rebill() const
{
return rebill_;
}
std::int32_t SessionStatus::billingPlanId() const
{
return billingPlanId_;
}
std::string SessionStatus::premiumExpiredDate() const
{
return premiumExpireDate_;
}
std::string SessionStatus::lastResetDate() const
{
return lastResetDate_;
}
std::int32_t SessionStatus::status() const
{
return status_;
}
std::int64_t SessionStatus::trafficUsed() const
{
return trafficUsed_;
}
std::int64_t SessionStatus::trafficMax() const
{
return trafficMax_;
}
std::string SessionStatus::authHash() const
{
return authHash_;
}
SessionErrorCode SessionStatus::errorCode() const
{
return errorCode_;
}
std::string SessionStatus::errorMessage() const
{
return errorMessage_;
}
std::string SessionStatus::jsonData() const
{
return jsonData_;
}
void SessionStatus::debugLog() const
{
g_logger->info("[SessionStatus] (is_premium: {}; status: {}; rebill: {}; billing_plan_id: {}; premium_expire_date: {}; traffic_used: {}; "
"traffic_max: {}; email_status: {}; static_ips_count: {}; alc_count: {}; last_reset_date: {})",
is_premium_, status_, rebill_, billingPlanId_, premiumExpireDate_, trafficUsed_, trafficMax_, emailStatus_,
staticIps_, alc_.size(), lastResetDate_);
}
} // namespace wsnet
@@ -1,77 +0,0 @@
#pragma once
#include <cstdint>
#include <set>
#include <string>
#include <vector>
#include <rapidjson/document.h>
namespace wsnet {
enum class SessionErrorCode { kSuccess, kSessionInvalid, kBadUsername, kAccountDisabled, kMissingCode2FA, kBadCode2FA, kRateLimited, kInvalidSecurityToken, kUnknownError };
// wrapper for SessionStatus json text
class SessionStatus
{
public:
// return nullptr if failed
static SessionStatus *createFromJson(const std::string &json);
// copy constructor
SessionStatus(const SessionStatus *ss) {
*this = *ss;
}
std::uint32_t staticIpsCount() const;
bool isContainsStaticDeviceId(const std::string &deviceId) const;
std::string revisionHash() const;
bool isPremium() const;
std::vector<std::string> alcList() const;
std::string username() const;
std::string userId() const;
std::string email() const;
std::int32_t emailStatus() const;
std::int32_t rebill() const;
std::int32_t billingPlanId() const;
std::string premiumExpiredDate() const;
std::string lastResetDate() const;
std::int32_t status() const;
std::int64_t trafficUsed() const;
std::int64_t trafficMax() const;
std::string authHash() const;
SessionErrorCode errorCode() const;
std::string errorMessage() const;
std::string jsonData() const;
void debugLog() const;
private:
SessionStatus() {}; // can only be created by the static function createFromJson(...)
std::string jsonData_;
bool is_premium_;
std::int32_t status_; // 2 - disabled
std::int32_t rebill_;
std::int32_t billingPlanId_;
std::string premiumExpireDate_;
std::string lastResetDate_;
std::int64_t trafficUsed_;
std::int64_t trafficMax_;
std::string username_;
std::string userId_;
std::string email_;
std::int32_t emailStatus_;
std::uint32_t staticIps_;
std::vector<std::string> alc_; // enabled locations for free users
SessionErrorCode errorCode_ = SessionErrorCode::kSuccess;
std::string errorMessage_;
std::string authHash_; // can be empty for Session request
std::string revisionHash_;
std::set<std::string> staticIpsUpdateDevices_;
};
} // namespace wsnet
-68
View File
@@ -1,68 +0,0 @@
#pragma once
#include <mutex>
#include <map>
namespace wsnet {
typedef std::function<void(bool isConnected)> ConnectedToVpnStateChangedCallback;
// Provides Network and VPN connection state
// Thread safe
class ConnectState
{
public:
void setConnectivityState(bool isOnline)
{
std::lock_guard locker(mutex_);
isOnline_ = isOnline;
}
void setIsConnectedToVpnState(bool isConnected)
{
std::lock_guard locker(mutex_);
if (isVPNConnected_ != isConnected) {
isVPNConnected_ = isConnected;
// notify subscribers
for (const auto &it : subscribers_) {
it.second(isVPNConnected_);
}
}
}
bool isOnline() const
{
std::lock_guard locker(mutex_);
return isOnline_;
}
bool isVPNConnected() const
{
std::lock_guard locker(mutex_);
return isVPNConnected_;
}
// returns id which must be used in the unsubscribeConnectedToVpnState(id) function
std::uint32_t subscribeConnectedToVpnState(ConnectedToVpnStateChangedCallback callback)
{
std::lock_guard locker(mutex_);
std::uint32_t id = curId_;
curId_++;
subscribers_[id] = callback;
return id;
}
void unsubscribeConnectedToVpnState(std::uint32_t id)
{
std::lock_guard locker(mutex_);
subscribers_.erase(id);
}
private:
mutable std::mutex mutex_;
bool isOnline_ = true;
bool isVPNConnected_ = false;
std::uint32_t curId_ = 0;
std::map<std::uint32_t, ConnectedToVpnStateChangedCallback> subscribers_;
};
} // namespace wsnet
@@ -1,6 +0,0 @@
target_sources(wsnet PRIVATE
decoytraffic.cpp
decoytraffic.h
decoytraffic_impl.cpp
decoytraffic_impl.h
)
@@ -1,74 +0,0 @@
#include "decoytraffic.h"
#include "utils/wsnet_logger.h"
namespace wsnet {
DecoyTraffic::DecoyTraffic(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager) :
uploadTraffic_(io_context, httpNetworkManager, true, toVolumePerMinute(0) * kUploadTrafficShare),
downloadTraffic_(io_context, httpNetworkManager, false, toVolumePerMinute(0) * kDownloadTrafficShare)
{
}
DecoyTraffic::~DecoyTraffic()
{
stopImpl();
}
void DecoyTraffic::setFakeTrafficVolume(std::uint32_t volume)
{
std::lock_guard locker(mutex_);
assert(volume >= 0 && volume <= 2);
uploadTraffic_.setTrafficVolumePerMinute(toVolumePerMinute(volume) * kUploadTrafficShare);
downloadTraffic_.setTrafficVolumePerMinute(toVolumePerMinute(volume) * kDownloadTrafficShare);
g_logger->info("DecoyTraffic setFakeTrafficVolume to {}", volume);
}
void DecoyTraffic::start()
{
std::lock_guard locker(mutex_);
if (!bStarted_) {
bStarted_ = true;
g_logger->info("Decoy traffic started");
startTime_ = std::chrono::steady_clock::now();
// Making slightly different start times for upload and download traffic
uploadTraffic_.start(1);
downloadTraffic_.start(3);
} else {
return;
}
}
void DecoyTraffic::stop()
{
stopImpl();
}
void DecoyTraffic::stopImpl()
{
std::lock_guard locker(mutex_);
if (!bStarted_) return;
bStarted_ = false;
auto totalUpload = uploadTraffic_.stop();
auto totalDownload = downloadTraffic_.stop();
g_logger->info("Decoy traffic stopped. Total time: {} sec. Total upload: {} Mb. Total download: {} Mb.",
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - startTime_).count(),
totalUpload, totalDownload);
}
std::uint32_t DecoyTraffic::toVolumePerMinute(std::uint32_t volume)
{
double bytesPerHour;
if (volume == 0) { // low, 1.5 Gb/hour
bytesPerHour = 1.5 * 1024 * 1024 * 1024;
} else if (volume == 1) { // medium, 7 Gb/hour
bytesPerHour = 7.0 * 1024 * 1024 * 1024;
} else { // high, 18 Gb/hour
bytesPerHour = 18.0 * 1024 * 1024 * 1024;
}
double bytesPerMinute = bytesPerHour / 60.0;
return bytesPerMinute;
}
} // namespace wsnet
@@ -1,38 +0,0 @@
#pragma once
#include <boost/asio.hpp>
#include <deque>
#include "WSNetDecoyTraffic.h"
#include "WSNetHttpNetworkManager.h"
#include "decoytraffic_impl.h"
namespace wsnet {
// Thread safe
class DecoyTraffic : public WSNetDecoyTraffic
{
public:
explicit DecoyTraffic(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager);
virtual ~DecoyTraffic();
void setFakeTrafficVolume(std::uint32_t volume) override;
void start() override;
void stop() override;
private:
const double kUploadTrafficShare = 0.6; // share of upload traffic 60%
const double kDownloadTrafficShare = 0.4; // share of download traffic 40%
DecoyTraffic_impl uploadTraffic_;
DecoyTraffic_impl downloadTraffic_;
std::mutex mutex_;
bool bStarted_ = false;
std::chrono::time_point<std::chrono::steady_clock> startTime_;
void stopImpl();
std::uint32_t toVolumePerMinute(std::uint32_t volume);
};
} // namespace wsnet
@@ -1,194 +0,0 @@
#include "decoytraffic_impl.h"
#include <boost/chrono.hpp>
#include <algorithm>
#include "utils/utils.h"
#include "utils/wsnet_logger.h"
namespace wsnet {
DecoyTraffic_impl::DecoyTraffic_impl(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager, bool isUpload, std::uint32_t volumePerMinute) :
io_context_(io_context), httpNetworkManager_(httpNetworkManager),
isUpload_(isUpload),
timer_(io_context),
targetSpeed_(volumePerMinute / 60.0),
intervalDist_(1.0 / AVERAGE_INTERVAL)
{
gen_.seed(std::random_device()());
}
DecoyTraffic_impl::~DecoyTraffic_impl()
{
stop();
}
void DecoyTraffic_impl::setTrafficVolumePerMinute(std::uint32_t volumePerMinute)
{
std::lock_guard locker(mutex_);
targetSpeed_ = volumePerMinute / 60.0;
}
void DecoyTraffic_impl::start(std::uint32_t startIntervalSeconds)
{
std::lock_guard locker(mutex_);
assert(!bStarted_);
bStarted_ = true;
requestFinishedTime_ = {}; // set to zero
total_ = 0;
avgNetworkSpeed_ = targetSpeed_; // initial assumption
// For the first request we make the size small enough to determine the bandwidth
// Because if the size is large and the actual bandwidth is small, the request may take a very long time to complete
averageSize_ = 10000; // 1 Kb
sizeDist_ = std::exponential_distribution<>(1.0 / averageSize_);
speedHistory_.clear();
timer_.expires_after(std::chrono::seconds(startIntervalSeconds));
timer_.async_wait(std::bind(&DecoyTraffic_impl::sendJob, this, boost::asio::placeholders::error));
}
double DecoyTraffic_impl::stop()
{
std::lock_guard locker(mutex_);
if (!bStarted_) return 0;
bStarted_ = false;
if (request_) {
request_->cancel();
request_.reset();
}
timer_.cancel();
return total_ / 1000000.0;
}
void DecoyTraffic_impl::sendJob(boost::system::error_code const& err)
{
std::lock_guard locker(mutex_);
if (err) return;
// generate packet size
initialSize_ = std::max((std::uint32_t)1, (std::uint32_t)(sizeDist_(gen_) + 0.5));
remainingSize_ = initialSize_;
requestStartTime_ = std::chrono::high_resolution_clock::now();
if (isUpload_) {
sendRequest(remainingSize_, 1);
//g_logger->info("sendRequest Upload {}", remainingSize_);
} else {
sendRequest(1 , remainingSize_);
//g_logger->info("sendRequest Download {}", remainingSize_);
}
}
void DecoyTraffic_impl::sendRequest(std::uint32_t dataToSendSize, std::uint32_t dataToReceiveSize)
{
using namespace std::placeholders;
if (isUpload_) {
// 1Mb limit for upload data
dataToSendSize = std::min(dataToSendSize, (std::uint32_t)1024*1024);
} else {
// 6291456 bytes limit for download data (I don't know why, but that's how it's set up on the server side)
dataToReceiveSize = std::min(dataToReceiveSize, (std::uint32_t)6291456);
}
auto postData = "data=" + std::string(dataToSendSize, 'a');
auto req = httpNetworkManager_->createPostRequest("http://10.255.255.1:8085", 5000, postData);
req->addHttpHeader("Content-type: text/plain; charset=utf-8");
req->addHttpHeader("X-DECOY-RESPONSE: " + std::to_string(dataToReceiveSize));
req->setIsEnableFreshConnect(false);
//g_logger->info("sendRequest {} {}", dataToSendSize, dataToReceiveSize);
unsigned int size = isUpload_ ? dataToSendSize : dataToReceiveSize;
request_ = httpNetworkManager_->executeRequest(req, 1, std::bind(&DecoyTraffic_impl::onFinishedRequest, this, _1, _2, _3, _4, size));
}
void DecoyTraffic_impl::onFinishedRequest(std::uint64_t requestId, std::uint32_t elapsedMs, std::shared_ptr<WSNetRequestError> error, const std::string &data,
unsigned int size)
{
std::lock_guard locker(mutex_);
if (!error->isSuccess()) {
//g_logger->warn("Request failed: {}, {}", (int) errCode, curlError);
// Repeat in a second
timer_.expires_after(std::chrono::seconds(1));
timer_.async_wait(std::bind(&DecoyTraffic_impl::sendJob, this, boost::asio::placeholders::error));
return;
} else {
// always +1 byte for upload/download data
total_ += size + 1;
// we send until we send all the data
if (isUpload_ && size < remainingSize_) {
remainingSize_ = remainingSize_ - size;
sendRequest(remainingSize_, 1);
return;
} else if (!isUpload_ && data.size() < remainingSize_) {
remainingSize_ = remainingSize_ - data.size();
sendRequest(1, remainingSize_);
return;
}
// calculate request execution time
requestFinishedTime_ = std::chrono::high_resolution_clock::now();
double sendDuration = std::chrono::duration<double>(requestFinishedTime_ - requestStartTime_).count();
double currentSpeed = sendDuration > 0 ? initialSize_ / sendDuration : 0;
updateNetworkSpeed(currentSpeed);
//g_logger->info("Request finished in {} size {} Mb", sendDuration, initialSize_ / 1024.0f / 1024.0f);
// adapting sending parameters
double allowedSpeed = std::min(targetSpeed_, avgNetworkSpeed_);
// adjusting the packet size to reflect the new interval
averageSize_ = std::clamp(
allowedSpeed * AVERAGE_INTERVAL,
10.0,
targetSpeed_ * 5.0 // Maximum size 5x of average
);
//g_logger->info("averageSize_ {}", averageSize_);
// distribution update
sizeDist_ = std::exponential_distribution<>(1.0 / averageSize_);
// generating the waiting interval
double delaySeconds = intervalDist_(gen_);
delaySeconds = std::max(delaySeconds - sendDuration, 0.0);
//g_logger->info("Delay {}", delaySeconds);
timer_.expires_after(std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::duration<double>(delaySeconds)
));
timer_.async_wait(std::bind(&DecoyTraffic_impl::sendJob, this, boost::asio::placeholders::error));
}
}
void DecoyTraffic_impl::updateNetworkSpeed(double newSpeed)
{
speedHistory_.push_back(newSpeed);
if (speedHistory_.size() > kWindowSize) {
speedHistory_.pop_front();
}
// Calculation of moving average
avgNetworkSpeed_ = std::accumulate(speedHistory_.begin(), speedHistory_.end(), 0.0) / speedHistory_.size();
}
std::uint32_t DecoyTraffic_impl::toInterval(FakeTrafficType fakeTraffic) const
{
// for low we create on average large time pauses between requests
switch (fakeTraffic) {
case FakeTrafficType::kLow:
return utils::random(15, 30);
case FakeTrafficType::kMedium:
return utils::random(10, 20);
case FakeTrafficType::kHigh:
return utils::random(2, 10);
default:
assert(false);
return utils::random(5, 30);
}
}
} // namespace wsnet
@@ -1,65 +0,0 @@
#pragma once
#include <boost/asio.hpp>
#include <random>
#include <deque>
#include "WSNetHttpNetworkManager.h"
namespace wsnet {
enum class FakeTrafficType { kLow = 0, kMedium, kHigh };
// Thread safe
class DecoyTraffic_impl
{
public:
explicit DecoyTraffic_impl(boost::asio::io_context &io_context, WSNetHttpNetworkManager *httpNetworkManager, bool isUpload, std::uint32_t volumePerMinute);
virtual ~DecoyTraffic_impl();
void setTrafficVolumePerMinute(std::uint32_t volumePerMinute);
void start(std::uint32_t startIntervalSeconds);
// return total upload/download Mbytes for the current session
double stop();
private:
std::mutex mutex_;
boost::asio::io_context &io_context_;
WSNetHttpNetworkManager *httpNetworkManager_;
bool isUpload_;
boost::asio::steady_timer timer_;
bool bStarted_ = false;
std::shared_ptr<wsnet::WSNetCancelableCallback> request_;
std::chrono::time_point<std::chrono::high_resolution_clock> requestFinishedTime_;
std::chrono::time_point<std::chrono::high_resolution_clock> requestStartTime_;
std::uint64_t total_;
std::uint32_t initialSize_;
std::uint32_t remainingSize_;
double targetSpeed_; // target speed (bytes/sec)
double avgNetworkSpeed_; // current network speed estimate (bytes/sec)
double averageSize_; // current average packet size
// Average delay between requests is 5 seconds
static constexpr double AVERAGE_INTERVAL = 5.0;
std::mt19937 gen_;
std::exponential_distribution<> intervalDist_;
std::exponential_distribution<> sizeDist_;
std::deque<double> speedHistory_; // Velocity history for moving average
const int kWindowSize = 5; // Window size for averaging
void sendJob(const boost::system::error_code &err);
void sendRequest(uint32_t dataToSendSize, uint32_t dataToReceiveSize);
void onFinishedRequest(std::uint64_t requestId, std::uint32_t elapsedMs, std::shared_ptr<WSNetRequestError> error, const std::string &data,
unsigned int size);
void updateNetworkSpeed(double newSpeed);
std::uint32_t toInterval(FakeTrafficType fakeTraffic) const;
};
} // namespace wsnet
-15
View File
@@ -1,15 +0,0 @@
target_sources(wsnet PRIVATE
areslibraryinit.cpp
areslibraryinit.h
dnsresolver_cares.cpp
dnsresolver_cares.h
dnsservers.cpp
dnsservers.h
)
if (APPLE AND NOT IOS)
target_sources(wsnet PRIVATE
getdnsconfig_mac.cpp
getdnsconfig_mac.h
)
endif()
@@ -1,77 +0,0 @@
#include "areslibraryinit.h"
#include "utils/wsnet_logger.h"
#include <ares.h>
#if defined(ANDROID) || defined(__ANDROID__)
extern JavaVM *g_javaVM;
#endif
namespace wsnet {
AresLibraryInit::AresLibraryInit() : bInitialized_(false), bFailedInitialize_(false)
{
g_logger->info("c-ares version: {}", ARES_VERSION_STR);
}
AresLibraryInit::~AresLibraryInit()
{
if (bInitialized_)
ares_library_cleanup();
}
bool AresLibraryInit::init()
{
if (!bInitialized_) {
if (!bFailedInitialize_) {
#if defined(__ANDROID__)
ares_library_init_jvm(g_javaVM);
#endif
int status = ares_library_init(ARES_LIB_INIT_ALL);
if (status != ARES_SUCCESS) {
g_logger->error("ares_library_init failed: {}", ares_strerror(status));
bFailedInitialize_ = true;
return false;
} else {
if (!initAndroid()) {
bFailedInitialize_ = true;
return false;
}
bInitialized_ = true;
return true;
}
}
}
return true;
}
// See: https://c-ares.org/ares_library_init_android.html
bool AresLibraryInit::initAndroid()
{
#if defined(__ANDROID__)
JNIEnv *env = NULL;
jint res = g_javaVM->GetEnv((void **)&env, JNI_VERSION_1_6);
assert(res == JNI_OK);
jclass activityThreadCls = env->FindClass("android/app/ActivityThread");
jmethodID currentActivityThread = env->GetStaticMethodID(activityThreadCls, "currentActivityThread", "()Landroid/app/ActivityThread;");
jobject activityThreadObj = env->CallStaticObjectMethod(activityThreadCls, currentActivityThread);
jmethodID getApplication = env->GetMethodID(activityThreadCls, "getApplication", "()Landroid/app/Application;");
jobject context = env->CallObjectMethod(activityThreadObj, getApplication);
jclass obj_cls = env->FindClass("android/content/Context");
jmethodID obj_mid = env->GetMethodID(obj_cls, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
jfieldID fid = env->GetStaticFieldID(obj_cls, "CONNECTIVITY_SERVICE", "Ljava/lang/String;");
jstring str = (jstring)env->GetStaticObjectField(obj_cls, fid);
jobject connectivity_manager = env->CallObjectMethod(context, obj_mid, str);
assert(connectivity_manager);
int status = ares_library_init_android(connectivity_manager);
if (status != ARES_SUCCESS) {
g_logger->error("ares_library_init_android failed: {}", ares_strerror(status));
return false;
}
#endif
return true;
}
} // namespace wsnet
@@ -1,20 +0,0 @@
#pragma once
namespace wsnet {
class AresLibraryInit
{
public:
AresLibraryInit();
~AresLibraryInit();
bool init();
private:
bool bInitialized_;
bool bFailedInitialize_;
bool initAndroid();
};
} // namespace wsnet
@@ -1,324 +0,0 @@
#define CARES_NO_DEPRECATED // Someday remove this and replace the functions with the new c-ares interface
#include <ares.h>
#include "dnsresolver_cares.h"
#include <assert.h>
#include <fmt/ranges.h>
#include "utils/wsnet_logger.h"
#include "utils/requesterror.h"
#include "utils/utils.h"
#if defined(__APPLE__) || defined(__linux__)
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <poll.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <winsock2.h>
#define poll WSAPoll
#endif
#if defined(__APPLE__) && !defined(IS_MOBILE_PLATFORM)
#include "getdnsconfig_mac.h"
#endif
namespace wsnet {
DnsResolver_cares::DnsResolver_cares() : curRequestId_(0)
{
}
DnsResolver_cares::~DnsResolver_cares()
{
g_logger->info("DnsResolver_cares destructor started");
finish_ = true;
condition_.notify_all();
thread_.join();
g_logger->info("DnsResolver_cares destructor finished");
}
bool DnsResolver_cares::init()
{
if (aresLibraryInit_.init()) {
thread_ = std::thread(std::bind(&DnsResolver_cares::run, this));
return true;
}
return false;
}
void DnsResolver_cares::setDnsServers(const std::vector<std::string> &dnsServers)
{
std::lock_guard locker(mutex_);
g_logger->info("Set dns servers by client: {}", fmt::join(dnsServers, ","));
dnsServers_ = DnsServers(dnsServers);
}
std::shared_ptr<WSNetCancelableCallback> DnsResolver_cares::lookup(const std::string &hostname, std::uint64_t userDataId, WSNetDnsResolverCallback callback)
{
std::lock_guard locker(mutex_);
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetDnsResolverCallback>>(callback);
QueueItem qi;
qi.hostname = hostname;
qi.callback = cancelableCallback;
qi.userDataId = userDataId;
qi.requestId = curRequestId_++;
activeRequests_.insert(qi.requestId);
queue_.push(qi);
condition_.notify_all();
return cancelableCallback;
}
std::shared_ptr<WSNetDnsRequestResult> DnsResolver_cares::lookupBlocked(const std::string &hostname)
{
// helper class for wait an async request
class BlockedRequest {
public:
BlockedRequest(WSNetDnsResolver *dnsResolver, const std::string &hostname)
{
dnsResolver->lookup(hostname, 0, std::bind(&BlockedRequest::callback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}
std::shared_ptr<WSNetDnsRequestResult> waitForFinished()
{
std::unique_lock locker(mutex_);
cv_.wait(locker, [this] { return isFinished_; });
return result_;
}
private:
void callback(std::uint64_t id, const std::string &hostname, std::shared_ptr<WSNetDnsRequestResult> result)
{
std::lock_guard locker(mutex_);
result_ = result;
isFinished_ = true;
cv_.notify_all();
}
std::mutex mutex_;
std::condition_variable cv_;
bool isFinished_ = false;
std::shared_ptr<WSNetDnsRequestResult> result_;
};
BlockedRequest blockedRequest(this, hostname);
return blockedRequest.waitForFinished();
}
void DnsResolver_cares::run()
{
ares_channel channel;
struct ares_options options;
int optmask;
memset(&options, 0, sizeof(options));
optmask = ARES_OPT_TRIES | ARES_OPT_TIMEOUTMS | ARES_OPT_MAXTIMEOUTMS;
options.tries = kTries;
options.timeout = kTimeoutMs;
options.maxtimeout = kTimeoutMs;
[[maybe_unused]] int status = ares_init_options(&channel, &options, optmask);
assert(status == ARES_SUCCESS);
DnsServers dnsServersInstalled;
DnsServers dnsServersInChannel = getDefaultSystemConfiguration();
status = ares_set_servers_csv(channel, dnsServersInChannel.getAsCsv().c_str());
assert(status == ARES_SUCCESS);
g_logger->info("DNS servers in channel: {}", dnsServersInChannel.getAsCsv());
std::queue<QueueItem> localQueue;
while (!finish_) {
// Check if c-ares still has active sockets
// If so, do not block so that the next batch can be processed immediately
ares_socket_t temp_sockets[ARES_GETSOCK_MAXNUM];
int temp_bitmask = ares_getsock(channel, temp_sockets, ARES_GETSOCK_MAXNUM);
bool has_active_sockets = (temp_bitmask != 0);
// Wait only if there are no active requests and no active sockets
if (!has_active_sockets) {
// mutex lock section
std::unique_lock<std::mutex> locker(mutex_);
condition_.wait(locker, [this]{ return !activeRequests_.empty() || finish_; });
localQueue = queue_;
queue_ = std::queue<QueueItem>();
if (dnsServersInstalled != dnsServers_) {
dnsServersInstalled = dnsServers_;
}
}
// Check if the list of DNS-servers has changed
// We must to cancel current requests before installing new DNS-servers
if (dnsServersInstalled.isEmpty()) { // Use default system DNS-servers
DnsServers dnsServersDefaultConfiguration = getDefaultSystemConfiguration();
if (dnsServersInChannel != dnsServersDefaultConfiguration) {
ares_cancel(channel);
status = ares_set_servers_csv(channel, dnsServersDefaultConfiguration.getAsCsv().c_str());
assert(status == ARES_SUCCESS);
dnsServersInChannel = dnsServersDefaultConfiguration;
g_logger->info("DNS servers in channel are changed: {}", dnsServersInChannel.getAsCsv());
}
} else {
if (dnsServersInChannel != dnsServersInstalled) {
ares_cancel(channel);
status = ares_set_servers_csv(channel, dnsServersInstalled.getAsCsv().c_str());
if (status != ARES_SUCCESS) {
g_logger->error("Failed to set DNS servers to channel: {}", dnsServersInstalled.getAsCsv());
} else {
dnsServersInChannel = dnsServersInstalled;
g_logger->info("DNS servers in channel are changed: {}", dnsServersInChannel.getAsCsv());
}
}
}
// start new requests from the queue
while (!localQueue.empty()) {
QueueItem qi = localQueue.front();
ArgToCaresCallback *arg = new ArgToCaresCallback(); // will be deleted in caresCallback
arg->this_ = this;
arg->qi = qi;
arg->qi.startTime = std::chrono::steady_clock::now();
ares_gethostbyname(channel, arg->qi.hostname.c_str(), AF_INET, caresCallback, arg);
localQueue.pop();
}
// process
ares_socket_t sockets[ARES_GETSOCK_MAXNUM];
int bitmask = ares_getsock(channel, sockets, ARES_GETSOCK_MAXNUM);
struct pollfd pfds[ARES_GETSOCK_MAXNUM];
int nfds = 0;
for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
if (ARES_GETSOCK_READABLE(bitmask, i) || ARES_GETSOCK_WRITABLE(bitmask, i)) {
pfds[nfds].fd = sockets[i];
pfds[nfds].events = 0;
pfds[nfds].revents = 0;
if (ARES_GETSOCK_READABLE(bitmask, i)) {
pfds[nfds].events |= POLLIN;
}
if (ARES_GETSOCK_WRITABLE(bitmask, i)) {
pfds[nfds].events |= POLLOUT;
}
nfds++;
}
}
if (nfds > 0) {
// do not block for longer than kTimeoutMs interval
int timeout_ms = kTimeoutMs;
poll(pfds, nfds, timeout_ms);
// Convert poll events to ares_fd_events_t for ares_process_fds
ares_fd_events_t events[ARES_GETSOCK_MAXNUM];
int nevents = 0;
for (int i = 0; i < nfds; i++) {
events[nevents].fd = pfds[i].fd;
events[nevents].events = 0;
if (pfds[i].revents & POLLIN) {
events[nevents].events |= ARES_FD_EVENT_READ;
}
if (pfds[i].revents & POLLOUT) {
events[nevents].events |= ARES_FD_EVENT_WRITE;
}
// Include the fd even if no events (for timeout processing)
nevents++;
}
ares_process_fds(channel, events, nevents, ARES_PROCESS_FLAG_NONE);
} else {
// No file descriptors to process, but still need to handle timeouts
ares_process_fds(channel, NULL, 0, ARES_PROCESS_FLAG_NONE);
}
}
ares_destroy(channel);
}
void DnsResolver_cares::caresCallback(void *arg, int status, int timeouts, hostent *host)
{
ArgToCaresCallback *pars = (ArgToCaresCallback *)arg;
{
std::lock_guard locker(pars->this_->mutex_);
auto it = pars->this_->activeRequests_.find(pars->qi.requestId);
if (it != pars->this_->activeRequests_.end()) {
pars->this_->activeRequests_.erase(it);
} else {
assert(false);
}
}
std::shared_ptr<DnsRequestResult> result = std::make_shared<DnsRequestResult>();
if (status == ARES_SUCCESS) {
for (char **p = host->h_addr_list; *p; p++) {
char addr_buf[46] = "??";
ares_inet_ntop(host->h_addrtype, *p, addr_buf, sizeof(addr_buf));
result->ips_.push_back(addr_buf);
}
}
result->elapsedMs_ = (unsigned int)utils::since(pars->qi.startTime).count();
result->error_ = std::make_shared<RequestError>(status, RequestErrorType::kCares);
// if the channel was destroyed, then do not call a callback function
if (status != ARES_EDESTRUCTION) {
// do callback
pars->qi.callback->call(pars->qi.userDataId, pars->qi.hostname, result);
}
delete pars;
}
void DnsResolver_cares::logDnsServersFromSystemConfigurationFrameworkIfChanged(const std::string &servers)
{
// log only if changed to avoid spam
static std::string lastServers;
if (lastServers != servers) {
lastServers = servers;
g_logger->info("DNS servers from System Configuration Framework: {}", servers);
}
}
DnsServers DnsResolver_cares::getDefaultSystemConfiguration()
{
DnsServers dnsServersDefaultConfiguration;
// get the current system DNS-server through a temporary channel
ares_channel tempChannel;
struct ares_options options;
memset(&options, 0, sizeof(options));
// ARES_FLAG_NO_DFLT_SVR flag => do not attempt to add a default local named server if there are no other servers available
int status = ares_init_options(&tempChannel, &options, ARES_FLAG_NO_DFLT_SVR);
if (status != ARES_SUCCESS) {
// Sometimes we see a bug on MacOS where c-ares cannot get the DNS configuration and uses the 127.0.0.1 address instead
// To make c-ares return an error instead of using the 127.0.0.1 address, we use the flag ARES_FLAG_NO_DFLT_SVR in ares_init_options call above
// It seems the method that c-ares uses to detect DNS configuration is not 100% reliable.
// The implementation of the method is here: https://github.com/c-ares/c-ares/blob/main/src/lib/ares_sysconfig_mac.c
// So if the c-ares method fails, let's try another method using the System Configuration Framework.
#if defined(__APPLE__) && !defined(IS_MOBILE_PLATFORM)
auto strDnsServers = getDnsConfig_mac();
logDnsServersFromSystemConfigurationFrameworkIfChanged(strDnsServers);
dnsServersDefaultConfiguration = DnsServers(strDnsServers.c_str());
#endif
} else {
char *servers = ares_get_servers_csv(tempChannel);
dnsServersDefaultConfiguration = DnsServers(servers);
if (servers) {
ares_free_string(servers);
}
ares_destroy(tempChannel);
}
return dnsServersDefaultConfiguration;
}
} // namespace wsnet
@@ -1,81 +0,0 @@
#pragma once
#include <thread>
#include <atomic>
#include <mutex>
#include <queue>
#include <set>
#include <condition_variable>
#include "WSNetDnsResolver.h"
#include "areslibraryinit.h"
#include "dnsservers.h"
#include "utils/cancelablecallback.h"
namespace wsnet {
// DnsResolver implementation based on the cares library
// Thread safe
class DnsResolver_cares : public WSNetDnsResolver
{
public:
explicit DnsResolver_cares();
virtual ~DnsResolver_cares();
bool init();
void setDnsServers(const std::vector<std::string> &dnsServers) override;
std::shared_ptr<WSNetCancelableCallback> lookup(const std::string &hostname, std::uint64_t userDataId, WSNetDnsResolverCallback callback) override;
std::shared_ptr<WSNetDnsRequestResult> lookupBlocked(const std::string &hostname) override;
private:
void run();
static void caresCallback(void *arg, int status, int timeouts, hostent *host);
static constexpr int kTimeoutMs = 2000; // default value in c-ares, let's leave it as it is
static constexpr int kTries = 2; // the number of tries the resolver will try contacting each name server before giving up.
struct QueueItem
{
std::uint64_t requestId;
std::string hostname;
std::chrono::time_point<std::chrono::steady_clock> startTime;
std::uint64_t userDataId;
std::shared_ptr<CancelableCallback<WSNetDnsResolverCallback>> callback;
};
struct ArgToCaresCallback
{
DnsResolver_cares *this_;
QueueItem qi;
};
class DnsRequestResult : public WSNetDnsRequestResult
{
public:
std::vector<std::string> ips() const override { return ips_; }
std::uint32_t elapsedMs() const override { return elapsedMs_; }
std::shared_ptr<WSNetRequestError> error() const override { return error_; }
std::vector<std::string> ips_;
unsigned int elapsedMs_;
std::shared_ptr<WSNetRequestError> error_;
};
AresLibraryInit aresLibraryInit_;
std::thread thread_;
std::atomic_bool finish_ = false;
std::mutex mutex_;
std::condition_variable condition_;
std::queue<QueueItem> queue_;
std::set<std::uint64_t> activeRequests_;
DnsServers dnsServers_;
std::uint64_t curRequestId_;
void logDnsServersFromSystemConfigurationFrameworkIfChanged(const std::string &servers);
DnsServers getDefaultSystemConfiguration();
};
} // namespace wsnet
-35
View File
@@ -1,35 +0,0 @@
#include "dnsservers.h"
#include <assert.h>
#include "utils/utils.h"
namespace wsnet {
DnsServers::DnsServers(const std::vector<std::string> &ips)
{
servers_ = ips;
for (auto &it : servers_) {
it += ":53";
}
}
DnsServers::DnsServers(const char *csv)
{
servers_ = utils::split(csv, ',');
}
bool DnsServers::operator==(const DnsServers &other) const
{
return servers_ == other.servers_;
}
bool DnsServers::operator!=(const DnsServers &other) const
{
return !operator==(other);
}
std::string DnsServers::getAsCsv() const
{
return utils::join(servers_, ",");
}
} // namespace wsnet
-28
View File
@@ -1,28 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include <ares.h>
namespace wsnet {
// wrapper for struct ares_addr_node for convenient work
class DnsServers
{
public:
DnsServers() {}
DnsServers(const std::vector<std::string> &ips);
DnsServers(const char *csv);
bool operator==( const DnsServers &other ) const;
bool operator!=( const DnsServers &other ) const;
bool isEmpty() const { return servers_.empty(); }
std::string getAsCsv() const;
private:
std::vector<std::string> servers_;
};
} // namespace wsnet
@@ -1,64 +0,0 @@
#include "getdnsconfig_mac.h"
#include <SystemConfiguration/SystemConfiguration.h>
#include <CoreFoundation/CoreFoundation.h>
#include <vector>
#include <unordered_set>
#include "utils/wsnet_logger.h"
#include "utils/utils.h"
namespace wsnet {
void removeDuplicates(std::vector<std::string> &vec)
{
std::unordered_set<std::string> seen;
auto it = vec.begin();
while (it != vec.end()) {
if (seen.find(*it) != seen.end()) {
it = vec.erase(it);
} else {
seen.insert(*it);
++it;
}
}
}
std::string getDnsConfig_mac()
{
std::vector<std::string> servers;
SCDynamicStoreRef store = SCDynamicStoreCreate(nullptr, CFSTR("GetDNSInfo"), nullptr, nullptr);
if (!store) {
g_logger->error("getOsDnsServersFromPath(), SCDynamicStoreCreate failed");
return std::string();
}
CFDictionaryRef dnsInfo = (CFDictionaryRef)SCDynamicStoreCopyValue(store, CFSTR("State:/Network/Global/DNS"));
if (!dnsInfo) {
g_logger->error("getOsDnsServersFromPath(), SCDynamicStoreCopyValue failed");
CFRelease(store);
return std::string();
}
CFArrayRef serverAddresses = (CFArrayRef)CFDictionaryGetValue(dnsInfo, CFSTR("ServerAddresses"));
if (serverAddresses && CFGetTypeID(serverAddresses) == CFArrayGetTypeID()) {
CFIndex count = CFArrayGetCount(serverAddresses);
for (CFIndex i = 0; i < count; i++) {
CFStringRef server = (CFStringRef)CFArrayGetValueAtIndex(serverAddresses, i);
char buffer[256];
if (CFStringGetCString(server, buffer, sizeof(buffer), kCFStringEncodingUTF8)) {
servers.push_back(buffer);
}
}
}
CFRelease(dnsInfo);
CFRelease(store);
removeDuplicates(servers);
return utils::join(servers, ",");
}
} // namespace wsnet
@@ -1,9 +0,0 @@
#pragma once
#include <string>
namespace wsnet {
// returns a list of DNS servers installed in MacOS in CSV format using the System Configuration Framework
std::string getDnsConfig_mac();
} // namespace wsnet
@@ -1,5 +0,0 @@
target_sources(wsnet PRIVATE
emergencyconnect.h
emergencyconnect.cpp
emergencyconnectendpoint.h
)
@@ -1,116 +0,0 @@
#include "emergencyconnect.h"
#include <cmrc/cmrc.hpp>
#include "utils/wsnet_logger.h"
#include "failover/failovercontainer.h"
#include "emergencyconnectendpoint.h"
#include "utils/utils.h"
#ifndef FAILOVER_CONTAINER_PUBLIC
#include "privatesettings.h"
#endif
CMRC_DECLARE(wsnet);
namespace wsnet {
EmergencyConnect::EmergencyConnect(boost::asio::io_context &io_context, IFailoverContainer *failoverContainer, WSNetDnsResolver *dnsResolver) :
io_context_(io_context),
failoverContainer_(failoverContainer),
dnsResolver_(dnsResolver)
{
}
EmergencyConnect::~EmergencyConnect()
{
for (auto &it : dnsRequests_)
it.second.first->cancel();
}
std::string EmergencyConnect::ovpnConfig() const
{
auto fs = cmrc::wsnet::get_filesystem();
assert(fs.is_file("resources/emergency.ovpn"));
auto ovpn = fs.open("resources/emergency.ovpn");
return std::string(ovpn.begin(), ovpn.end());
}
std::string EmergencyConnect::username() const
{
#ifndef FAILOVER_CONTAINER_PUBLIC
return PrivateSettings::instance().emergencyUsername();
#else
return std::string();
#endif
}
std::string EmergencyConnect::password() const
{
#ifndef FAILOVER_CONTAINER_PUBLIC
return PrivateSettings::instance().emergencyPassword();
#else
return std::string();
#endif
}
std::shared_ptr<WSNetCancelableCallback> EmergencyConnect::getIpEndpoints(WSNetEmergencyConnectCallback callback)
{
#ifndef FAILOVER_CONTAINER_PUBLIC
auto cancelableCallback = std::make_shared<CancelableCallback<WSNetEmergencyConnectCallback>>(callback);
boost::asio::post(io_context_, [this, cancelableCallback] {
auto failover = failoverContainer_->failoverById(FAILOVER_OLD_RANDOM_DOMAIN_GENERATION);
assert(failover);
std::vector<FailoverData> data;
bool isSuccess = failover->getData(false, data, nullptr);
assert(isSuccess);
assert(data.size() == 1);
std::string hashedDomain = "econnect." + data[0].domain();
using namespace std::placeholders;
auto dnsRequest = dnsResolver_->lookup(hashedDomain, curRequestId_, std::bind(&EmergencyConnect::onDnsResolved, this, _1, _2, _3));
dnsRequests_[curRequestId_] = std::make_pair(dnsRequest, cancelableCallback);
curRequestId_++;
});
return cancelableCallback;
#else
return nullptr;
#endif
}
void EmergencyConnect::onDnsResolved(std::uint64_t requestId, const std::string &hostname, std::shared_ptr<WSNetDnsRequestResult> result)
{
#ifndef FAILOVER_CONTAINER_PUBLIC
boost::asio::post(io_context_, [this, requestId, hostname, result] {
auto it = dnsRequests_.find(requestId);
if (it == dnsRequests_.end())
return;
std::vector<std::shared_ptr<WSNetEmergencyConnectEndpoint>> endpoints;
if (result->error()->isSuccess()) {
std::vector<std::shared_ptr<WSNetEmergencyConnectEndpoint>> list;
auto ips = result->ips();
ips = utils::randomizeList(ips);
for (const auto &ip : ips) {
endpoints.push_back(std::make_shared<EmergencyConnectEndpoint>(ip, 443, Protocol::kUdp));
endpoints.push_back(std::make_shared<EmergencyConnectEndpoint>(ip, 443, Protocol::kTcp));
}
} else {
g_logger->warn("EmergencyConnect::onDnsResolved failed. {}", result->error()->toString());
}
std::vector<std::shared_ptr<WSNetEmergencyConnectEndpoint>> endpointsHardcoded;
endpointsHardcoded.push_back(std::make_shared<EmergencyConnectEndpoint>(PrivateSettings::instance().emergencyIP1(), 1194, Protocol::kUdp));
endpointsHardcoded.push_back(std::make_shared<EmergencyConnectEndpoint>(PrivateSettings::instance().emergencyIP2(), 1194, Protocol::kUdp));
endpointsHardcoded = utils::randomizeList(endpointsHardcoded);
endpoints.insert(endpoints.end(), endpointsHardcoded.begin(), endpointsHardcoded.end());
it->second.second->call(endpoints);
dnsRequests_.erase(it);
});
#endif
}
} // namespace wsnet
@@ -1,37 +0,0 @@
#pragma once
#include <map>
#include <boost/asio.hpp>
#include "WSNetEmergencyConnect.h"
#include "WSNetDnsResolver.h"
#include "failover/ifailovercontainer.h"
#include "utils/cancelablecallback.h"
namespace wsnet {
class EmergencyConnect : public WSNetEmergencyConnect
{
public:
explicit EmergencyConnect(boost::asio::io_context &io_context, IFailoverContainer *failoverContainer, WSNetDnsResolver *dnsResolver);
virtual ~EmergencyConnect();
std::string ovpnConfig() const override;
std::string username() const override;
std::string password() const override;
std::shared_ptr<WSNetCancelableCallback> getIpEndpoints(WSNetEmergencyConnectCallback callback) override;
private:
boost::asio::io_context &io_context_;
IFailoverContainer *failoverContainer_;
WSNetDnsResolver *dnsResolver_;
std::mutex mutex_;
std::uint64_t curRequestId_ = 0;
std::map<std::uint64_t, std::pair< std::shared_ptr<WSNetCancelableCallback>, std::shared_ptr<CancelableCallback<WSNetEmergencyConnectCallback>>> > dnsRequests_;
void onDnsResolved(std::uint64_t requestId, const std::string &hostname, std::shared_ptr<WSNetDnsRequestResult> result);
};
} // namespace wsnet

Some files were not shown because too many files have changed in this diff Show More