mirror of
https://github.com/Windscribe/Desktop-App.git
synced 2026-05-07 20:12:44 +00:00
v2.21.3
This commit is contained in:
@@ -18,6 +18,7 @@ drawings/*/*.png
|
||||
tools/.idea/
|
||||
build/
|
||||
.vscode/
|
||||
.claude/
|
||||
|
||||
# secrets
|
||||
tools/notarize.yml
|
||||
|
||||
+19
-257
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -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
@@ -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 +0,0 @@
|
||||
Here are libs that can also be used by mobile programs.
|
||||
@@ -1,2 +0,0 @@
|
||||
*.user
|
||||
generated
|
||||
@@ -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`
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
@@ -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?
|
||||
@@ -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()
|
||||
@@ -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
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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>
|
||||
@@ -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-----
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -1,7 +0,0 @@
|
||||
target_sources(wsnet PRIVATE
|
||||
baserequest.cpp
|
||||
baserequest.h
|
||||
)
|
||||
|
||||
add_subdirectory(bridgeapi)
|
||||
add_subdirectory(serverapi)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user