diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 0c9dfb32..a51c19b2 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -10,7 +10,7 @@ env:
jobs:
Build-Linux-Ubuntu:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-20.04
env:
QT_VERSION: 6.6.2
@@ -20,8 +20,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
- FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
- PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Install Qt'
@@ -92,8 +90,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
- FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
- PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Get sources'
@@ -160,8 +156,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
- FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
- PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Setup xcode'
@@ -196,7 +190,7 @@ jobs:
- name: 'Install go'
uses: actions/setup-go@v5
with:
- go-version: '1.24'
+ go-version: '1.22.1'
cache: false
- name: 'Setup gomobile'
@@ -249,82 +243,18 @@ jobs:
# ------------------------------------------------------
- Build-MacOS-old:
+ Build-MacOS:
runs-on: macos-latest
env:
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
QT_VERSION: 6.4.3
+ QIF_VERSION: 4.6
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
- FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
- PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
-
- steps:
- - name: 'Setup xcode'
- uses: maxim-lobanov/setup-xcode@v1
- with:
- xcode-version: '15.4.0'
-
- - name: 'Install Qt'
- uses: jurplel/install-qt-action@v3
- with:
- version: ${{ env.QT_VERSION }}
- host: 'mac'
- target: 'desktop'
- arch: 'clang_64'
- modules: 'qtremoteobjects qt5compat qtshadertools'
- dir: ${{ runner.temp }}
- setup-python: 'true'
- set-env: 'true'
- extra: '--external 7z --base ${{ env.QT_MIRROR }}'
-
-
- - name: 'Get sources'
- uses: actions/checkout@v4
- with:
- submodules: 'true'
- fetch-depth: 10
-
- - name: 'Setup ccache'
- uses: hendrikmuhs/ccache-action@v1.2
-
- - name: 'Build project'
- run: |
- export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
- bash deploy/build_macos.sh
-
- - name: 'Upload installer artifact'
- uses: actions/upload-artifact@v4
- with:
- name: AmneziaVPN_MacOS_old_installer
- path: deploy/build/pkg/AmneziaVPN.pkg
- retention-days: 7
-
- - name: 'Upload unpacked artifact'
- uses: actions/upload-artifact@v4
- with:
- name: AmneziaVPN_MacOS_old_unpacked
- path: deploy/build/client/AmneziaVPN.app
- retention-days: 7
-
-# ------------------------------------------------------
-
- Build-MacOS:
- runs-on: macos-latest
-
- env:
- QT_VERSION: 6.8.0
- PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
- PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
- DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
- DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
- DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
- FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
- PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Setup xcode'
@@ -345,6 +275,11 @@ jobs:
set-env: 'true'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
+ - name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}'
+ run: |
+ mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework
+ wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip
+ unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/
- name: 'Get sources'
uses: actions/checkout@v4
@@ -358,13 +293,14 @@ jobs:
- name: 'Build project'
run: |
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
+ export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin"
bash deploy/build_macos.sh
- name: 'Upload installer artifact'
uses: actions/upload-artifact@v4
with:
name: AmneziaVPN_MacOS_installer
- path: deploy/build/pkg/AmneziaVPN.pkg
+ path: AmneziaVPN.dmg
retention-days: 7
- name: 'Upload unpacked artifact'
@@ -388,8 +324,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
- FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
- PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Install desktop Qt'
@@ -401,8 +335,7 @@ jobs:
arch: 'linux_gcc_64'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
- py7zrversion: '==0.22.*'
- extra: '--base ${{ env.QT_MIRROR }}'
+ extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install android_x86_64 Qt'
uses: jurplel/install-qt-action@v4
@@ -413,8 +346,7 @@ jobs:
arch: 'android_x86_64'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
- py7zrversion: '==0.22.*'
- extra: '--base ${{ env.QT_MIRROR }}'
+ extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install android_x86 Qt'
uses: jurplel/install-qt-action@v4
@@ -425,8 +357,7 @@ jobs:
arch: 'android_x86'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
- py7zrversion: '==0.22.*'
- extra: '--base ${{ env.QT_MIRROR }}'
+ extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install android_armv7 Qt'
uses: jurplel/install-qt-action@v4
@@ -437,8 +368,7 @@ jobs:
arch: 'android_armv7'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
- py7zrversion: '==0.22.*'
- extra: '--base ${{ env.QT_MIRROR }}'
+ extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install android_arm64_v8a Qt'
uses: jurplel/install-qt-action@v4
@@ -449,8 +379,7 @@ jobs:
arch: 'android_arm64_v8a'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
- py7zrversion: '==0.22.*'
- extra: '--base ${{ env.QT_MIRROR }}'
+ extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Grant execute permission for qt-cmake'
shell: bash
diff --git a/.github/workflows/tag-deploy.yml b/.github/workflows/tag-deploy.yml
index 31c334bf..2bcbd8c6 100644
--- a/.github/workflows/tag-deploy.yml
+++ b/.github/workflows/tag-deploy.yml
@@ -20,8 +20,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
- FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
- PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Install desktop Qt'
diff --git a/.github/workflows/tag-upload.yml b/.github/workflows/tag-upload.yml
index 9ac2da58..22629ed3 100644
--- a/.github/workflows/tag-upload.yml
+++ b/.github/workflows/tag-upload.yml
@@ -1,41 +1,64 @@
name: 'Upload a new version'
on:
- workflow_dispatch:
- inputs:
- RELEASE_VERSION:
- description: 'Release version (e.g. 1.2.3.4)'
- required: true
- type: string
+ push:
+ tags:
+ - '[0-9]+.[0-9]+.[0-9]+.[0-9]+'
jobs:
- Upload-S3:
+ upload:
runs-on: ubuntu-latest
+ name: upload
steps:
- - name: Checkout
+ - name: Checkout CMakeLists.txt
uses: actions/checkout@v4
with:
- ref: ${{ inputs.RELEASE_VERSION }}
+ ref: ${{ github.ref_name }}
sparse-checkout: |
CMakeLists.txt
- deploy/deploy_s3.sh
sparse-checkout-cone-mode: false
- name: Verify git tag
run: |
- TAG_NAME=${{ inputs.RELEASE_VERSION }}
+ GIT_TAG=${{ github.ref_name }}
CMAKE_TAG=$(grep 'project.*VERSION' CMakeLists.txt | sed -E 's/.* ([0-9]+.[0-9]+.[0-9]+.[0-9]+)$/\1/')
- if [[ "$TAG_NAME" == "$CMAKE_TAG" ]]; then
- echo "Git tag ($TAG_NAME) matches CMakeLists.txt version ($CMAKE_TAG)."
+
+ if [[ "$GIT_TAG" == "$CMAKE_TAG" ]]; then
+ echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are the same. Continuing..."
else
- echo "::error::Mismatch: Git tag ($TAG_NAME) != CMakeLists.txt version ($CMAKE_TAG). Exiting with error..."
+ echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are not the same! Cancelling..."
exit 1
fi
- - name: Setup Rclone
- uses: AnimMouse/setup-rclone@v1
+ - name: Download artifacts from the "${{ github.ref_name }}" tag
+ uses: robinraju/release-downloader@v1.8
with:
- rclone_config: ${{ secrets.RCLONE_CONFIG }}
+ tag: ${{ github.ref_name }}
+ fileName: "AmneziaVPN_(Linux_|)${{ github.ref_name }}*"
+ out-file-path: ${{ github.ref_name }}
- - name: Send dist to S3
- run: bash deploy/deploy_s3.sh ${{ inputs.RELEASE_VERSION }}
+ - name: Upload beta version
+ uses: jakejarvis/s3-sync-action@master
+ if: contains(github.event.base_ref, 'dev')
+ with:
+ args: --include "AmneziaVPN*" --delete
+ env:
+ AWS_S3_BUCKET: updates
+ AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
+ AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
+ SOURCE_DIR: ${{ github.ref_name }}
+ DEST_DIR: beta/${{ github.ref_name }}
+
+ - name: Upload stable version
+ uses: jakejarvis/s3-sync-action@master
+ if: contains(github.event.base_ref, 'master')
+ with:
+ args: --include "AmneziaVPN*" --delete
+ env:
+ AWS_S3_BUCKET: updates
+ AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
+ AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
+ SOURCE_DIR: ${{ github.ref_name }}
+ DEST_DIR: stable/${{ github.ref_name }}
diff --git a/.gitignore b/.gitignore
index 503adc2d..5b90fd55 100644
--- a/.gitignore
+++ b/.gitignore
@@ -133,8 +133,4 @@ client/3rd/ShadowSocks/ss_ios.xcconfig
out/
# CMake files
-CMakeFiles/
-
-ios-ne-build.sh
-macos-ne-build.sh
-macos-signed-build.sh
+CMakeFiles/
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
index 90edb582..3ceaa56e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
+[submodule "client/3rd/OpenVPNAdapter"]
+ path = client/3rd/OpenVPNAdapter
+ url = https://github.com/amnezia-vpn/OpenVPNAdapter.git
[submodule "client/3rd/qtkeychain"]
path = client/3rd/qtkeychain
url = https://github.com/frankosterfeld/qtkeychain.git
@@ -7,7 +10,6 @@
[submodule "client/3rd-prebuilt"]
path = client/3rd-prebuilt
url = https://github.com/amnezia-vpn/3rd-prebuilt
- branch = feature/special-handshake
[submodule "client/3rd/amneziawg-apple"]
path = client/3rd/amneziawg-apple
url = https://github.com/amnezia-vpn/amneziawg-apple
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fec613de..cb695631 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
-project(${PROJECT} VERSION 4.8.8.1
+project(${PROJECT} VERSION 4.8.2.4
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
-set(APP_ANDROID_VERSION_CODE 2087)
+set(APP_ANDROID_VERSION_CODE 2071)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
diff --git a/README.md b/README.md
index 992c3ad0..8f887808 100644
--- a/README.md
+++ b/README.md
@@ -13,13 +13,13 @@
[](https://amnezia.org)
-### [Website](https://amnezia.org) | [Alt website link](https://storage.googleapis.com/amnezia/amnezia.org) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
+### [Website](https://amnezia.org) | [Alt website link](https://storage.googleapis.com/kldscp/amnezia.org) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
> [!TIP]
-> If the [Amnezia website](https://amnezia.org) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/amnezia/amnezia.org ).
+> If the [Amnezia website](https://amnezia.org) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/kldscp/amnezia.org).
-
+
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
@@ -185,7 +185,7 @@ GPL v3.0
Patreon: [https://www.patreon.com/amneziavpn](https://www.patreon.com/amneziavpn)
-Bitcoin: bc1qmhtgcf9637rl3kqyy22r2a8wa8laka4t9rx2mf
+Bitcoin: bc1q26eevjcg9j0wuyywd2e3uc9cs2w58lpkpjxq6p
USDT BEP20: 0x6abD576765a826f87D1D95183438f9408C901bE4
USDT TRC20: TELAitazF1MZGmiNjTcnxDjEiH5oe7LC9d
XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3
diff --git a/README_RU.md b/README_RU.md
index 44681875..fe9dd286 100644
--- a/README_RU.md
+++ b/README_RU.md
@@ -6,16 +6,16 @@
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский
-[AmneziaVPN](https://amnezia.org) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
+[AmneziaVPN](https://amnezia.org) — это open sourse VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
[](https://amnezia.org)
-### [Сайт](https://amnezia.org) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
+### [Сайт](https://amnezia.org) | [Зеркало на сайт](https://storage.googleapis.com/kldscp/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
> [!TIP]
-> Если [сайт Amnezia](https://amnezia.org) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org).
+> Если [сайт Amnezia](https://amnezia.org) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/kldscp/amnezia.org).
-
+
[Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases)
@@ -30,7 +30,7 @@
- Классические VPN-протоколы: OpenVPN, WireGuard и IKEv2.
- Протоколы с маскировкой трафика (обфускацией): OpenVPN с плагином [Cloak](https://github.com/cbeuw/Cloak), Shadowsocks (OpenVPN over Shadowsocks), [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/) and XRay.
- Поддержка Split Tunneling — добавляйте любые сайты или приложения в список, чтобы включить VPN только для них.
-- Поддерживает платформы: Windows, macOS, Linux, Android, iOS.
+- Поддерживает платформы: Windows, MacOS, Linux, Android, iOS.
- Поддержка конфигурации протокола AmneziaWG на [бета-прошивке Keenetic](https://docs.keenetic.com/ua/air/kn-1611/en/6319-latest-development-release.html#UUID-186c4108-5afd-c10b-f38a-cdff6c17fab3_section-idm33192196168192-improved).
## Ссылки
@@ -38,10 +38,10 @@
- [https://amnezia.org](https://amnezia.org) - Веб-сайт проекта | [Альтернативная ссылка (зеркало)](https://storage.googleapis.com/kldscp/amnezia.org)
- [https://docs.amnezia.org](https://docs.amnezia.org) - Документация
- [https://www.reddit.com/r/AmneziaVPN](https://www.reddit.com/r/AmneziaVPN) - Reddit
-- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Канал поддержки в Telegram (Английский)
-- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Канал поддержки в Telegram (Фарси)
-- [https://t.me/amnezia_vpn_mm](https://t.me/amnezia_vpn_mm) - Канал поддержки в Telegram (Мьянма)
-- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Канал поддержки в Telegram (Русский)
+- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Канал поддржки в Telegram (Английский)
+- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Канал поддржки в Telegram (Фарси)
+- [https://t.me/amnezia_vpn_mm](https://t.me/amnezia_vpn_mm) - Канал поддржки в Telegram (Мьянма)
+- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Канал поддржки в Telegram (Русский)
- [https://vpnpay.io/en/amnezia-premium/](https://vpnpay.io/en/amnezia-premium/) - Amnezia Premium | [Зеркало](https://storage.googleapis.com/kldscp/vpnpay.io/ru/amnezia-premium\)
## Технологии
@@ -55,112 +55,6 @@ AmneziaVPN использует несколько проектов с откр
- [LibSsh](https://libssh.org)
- и другие...
-## Проверка исходного кода
-После клонирования репозитория обязательно загрузите все подмодули.
-
-```bash
-git submodule update --init --recursive
-```
-
-
-## Разработка
-Хотите внести свой вклад? Добро пожаловать!
-
-### Помощь с переводами
-
-Загрузите самые актуальные файлы перевода.
-
-Перейдите на [вкладку "Actions"](https://github.com/amnezia-vpn/amnezia-client/actions?query=is%3Asuccess+branch%3Adev), нажмите на первую строку. Затем прокрутите вниз до раздела "Artifacts" и скачайте "AmneziaVPN_translations".
-
-Распакуйте этот файл. Каждый файл с расширением *.ts содержит строки для соответствующего языка.
-
-Переведите или исправьте строки в одном или нескольких файлах *.ts и загрузите их обратно в этот репозиторий в папку ``client/translations``. Это можно сделать через веб-интерфейс или любым другим знакомым вам способом.
-
-### Сборка исходного кода и деплой
-Проверьте папку deploy для скриптов сборки.
-
-### Как собрать iOS-приложение из исходного кода на MacOS
-1. Убедитесь, что у вас установлен Xcode версии 14 или выше.
-2. Для генерации проекта Xcode используется QT. Требуется версия QT 6.6.2. Установите QT для MacOS здесь или через QT Online Installer. Необходимые модули:
-- MacOS
-- iOS
-- Модуль совместимости с Qt 5
-- Qt Shader Tools
-- Дополнительные библиотеки:
- - Qt Image Formats
- - Qt Multimedia
- - Qt Remote Objects
-
-
-3. Установите CMake, если это необходимо. Рекомендуемая версия — 3.25. Скачать CMake можно здесь.
-4. Установите Go версии >= v1.16. Если Go ещё не установлен, скачайте его с [официального сайта](https://golang.org/dl/) или используйте Homebrew. Установите gomobile:
-
-```bash
-export PATH=$PATH:~/go/bin
-go install golang.org/x/mobile/cmd/gomobile@latest
-gomobile init
-```
-
-5. Соберите проект:
-```bash
-export QT_BIN_DIR="/Qt//ios/bin"
-export QT_MACOS_ROOT_DIR="/Qt//macos"
-export QT_IOS_BIN=$QT_BIN_DIR
-export PATH=$PATH:~/go/bin
-mkdir build-ios
-$QT_IOS_BIN/qt-cmake . -B build-ios -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR
-```
-Замените и на ваши значения.
-
-Если появляется ошибка gomobile: command not found, убедитесь, что PATH настроен на папку bin, где установлен gomobile:
-```bash
-export PATH=$(PATH):/path/to/GOPATH/bin
-```
-
-6. Откройте проект в Xcode. Теперь вы можете тестировать, архивировать или публиковать приложение.
-
-Если сборка завершится с ошибкой:
-```
-make: ***
-[$(PROJECTDIR)/client/build/AmneziaVPN.build/Debug-iphoneos/wireguard-go-bridge/goroot/.prepared]
-Error 1
-```
-Добавьте пользовательскую переменную PATH в настройки сборки для целей AmneziaVPN и WireGuardNetworkExtension с ключом `PATH` и значением `${PATH}/path/to/bin/folder/with/go/executable`, e.g. `${PATH}:/usr/local/go/bin`.
-
-Если ошибка повторяется на Mac с M1, установите версию CMake для архитектуры ARM:
-```
-arch -arm64 brew install cmake
-```
-
- При первой попытке сборка может завершиться с ошибкой source files not found. Это происходит из-за параллельной компиляции зависимостей в XCode. Просто перезапустите сборку.
-
-
-## Как собрать Android-приложение
-Сборка тестировалась на MacOS. Требования:
-- JDK 11
-- Android SDK 33
-- CMake 3.25.0
-
-Установите QT, QT Creator и Android Studio.
-Настройте QT Creator:
-
-- В меню QT Creator перейдите в `QT Creator` -> `Preferences` -> `Devices` ->`Android`.
-- Укажите путь к JDK 11.
-- Укажите путь к Android SDK (`$ANDROID_HOME`)
-
-Если вы сталкиваетесь с ошибками, связанными с отсутствием SDK или сообщением «SDK manager not running», их нельзя исправить просто корректировкой путей. Если у вас есть несколько свободных гигабайт на диске, вы можете позволить Qt Creator установить все необходимые компоненты, выбрав пустую папку для расположения Android SDK и нажав кнопку **Set Up SDK**. Учтите: это установит второй Android SDK и NDK на вашем компьютере!
-
-Убедитесь, что настроена правильная версия CMake: перейдите в **Qt Creator -> Preferences** и в боковом меню выберите пункт **Kits**. В центральной части окна, на вкладке **Kits**, найдите запись для инструмента **CMake Tool**. Если выбранная по умолчанию версия CMake ниже 3.25.0, установите на свою систему CMake версии 3.25.0 или выше, а затем выберите опцию **System CMake at <путь>** из выпадающего списка. Если этот пункт отсутствует, это может означать, что вы еще не установили CMake, или Qt Creator не смог найти путь к нему. В таком случае в окне **Preferences** перейдите в боковое меню **CMake**, затем во вкладку **Tools** в центральной части окна и нажмите кнопку **Add**, чтобы указать путь к установленному CMake.
-
-Убедитесь, что для вашего проекта выбрана Android Platform SDK 33: в главном окне на боковой панели выберите пункт **Projects**, и слева вы увидите раздел **Build & Run**, показывающий различные целевые Android-платформы. Вы можете выбрать любую из них, так как настройка проекта Amnezia VPN разработана таким образом, чтобы все Android-цели могли быть собраны. Перейдите в подраздел **Build** и прокрутите центральную часть окна до раздела **Build Steps**. Нажмите **Details** в заголовке **Build Android APK** (кнопка **Details** может быть скрыта, если окно Qt Creator не запущено в полноэкранном режиме!). Вот здесь выберите **android-33** в качестве Android Build Platform SDK.
-
-### Разработка Android-компонентов
-
-После сборки QT Creator копирует проект в отдельную папку, например, `build-amnezia-client-Android_Qt__Clang_-`. Для разработки Android-компонентов откройте сгенерированный проект в Android Studio, указав папку `build-amnezia-client-Android_Qt__Clang_-/client/android-build` в качестве корневой.
-Изменения в сгенерированном проекте нужно вручную перенести в репозиторий. После этого можно коммитить изменения.
-Если возникают проблемы со сборкой в QT Creator после работы в Android Studio, выполните команду `./gradlew clean` в корневой папке сгенерированного проекта (`/client/android-build/.`).
-
-
## Лицензия
GPL v3.0
@@ -169,7 +63,7 @@ GPL v3.0
Patreon: [https://www.patreon.com/amneziavpn](https://www.patreon.com/amneziavpn)
-Bitcoin: bc1qmhtgcf9637rl3kqyy22r2a8wa8laka4t9rx2mf
+Bitcoin: bc1q26eevjcg9j0wuyywd2e3uc9cs2w58lpkpjxq6p
USDT BEP20: 0x6abD576765a826f87D1D95183438f9408C901bE4
USDT TRC20: TELAitazF1MZGmiNjTcnxDjEiH5oe7LC9d
XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3
diff --git a/client/3rd-prebuilt b/client/3rd-prebuilt
index 840b7b07..ba580dc5 160000
--- a/client/3rd-prebuilt
+++ b/client/3rd-prebuilt
@@ -1 +1 @@
-Subproject commit 840b7b070e6ac8b90dda2fac6e98859b23727c0c
+Subproject commit ba580dc5bd7784f7b1e110ff0365f3286e549a61
diff --git a/client/3rd/OpenVPNAdapter b/client/3rd/OpenVPNAdapter
new file mode 160000
index 00000000..7c821a8d
--- /dev/null
+++ b/client/3rd/OpenVPNAdapter
@@ -0,0 +1 @@
+Subproject commit 7c821a8d5c1ad5ad94e0763b4f25a875b5a6fe1b
diff --git a/client/3rd/amneziawg-apple b/client/3rd/amneziawg-apple
index 811af0a8..76e7db55 160000
--- a/client/3rd/amneziawg-apple
+++ b/client/3rd/amneziawg-apple
@@ -1 +1 @@
-Subproject commit 811af0a83b3faeade89a9093a588595666d32066
+Subproject commit 76e7db556a6d7e2582f9481df91db188a46c009c
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index a454142d..05f9f17c 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -31,8 +31,9 @@ add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}")
add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
add_definitions(-DDEV_S3_ENDPOINT="$ENV{DEV_S3_ENDPOINT}")
-add_definitions(-DFREE_V2_ENDPOINT="$ENV{FREE_V2_ENDPOINT}")
-add_definitions(-DPREM_V1_ENDPOINT="$ENV{PREM_V1_ENDPOINT}")
+if(IOS)
+ set(PACKAGES ${PACKAGES} Multimedia)
+endif()
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
set(PACKAGES ${PACKAGES} Widgets)
@@ -47,6 +48,10 @@ set(LIBS ${LIBS}
Qt6::Core5Compat Qt6::Concurrent
)
+if(IOS)
+ set(LIBS ${LIBS} Qt6::Multimedia)
+endif()
+
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
set(LIBS ${LIBS} Qt6::Widgets)
endif()
@@ -91,6 +96,11 @@ configure_file(${CMAKE_CURRENT_LIST_DIR}/translations/translations.qrc.in ${CMAK
qt6_add_resources(QRC ${I18NQRC} ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
# -- i18n end
+if(IOS)
+ execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/ios/scripts/openvpn.sh args
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
+endif()
+
set(IS_CI ${CI})
if(IS_CI)
message("Detected CI env")
@@ -100,8 +110,8 @@ if(IS_CI)
endif()
endif()
+
include(${CMAKE_CURRENT_LIST_DIR}/cmake/3rdparty.cmake)
-include(${CMAKE_CURRENT_LIST_DIR}/cmake/sources.cmake)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/../ipc
@@ -110,22 +120,165 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}
)
+configure_file(${CMAKE_CURRENT_LIST_DIR}/../version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
+
+set(HEADERS ${HEADERS}
+ ${CMAKE_CURRENT_LIST_DIR}/migrations.h
+ ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc.h
+ ${CMAKE_CURRENT_LIST_DIR}/amnezia_application.h
+ ${CMAKE_CURRENT_LIST_DIR}/containers/containers_defs.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/defs.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/errorstrings.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/scripts_registry.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/server_defs.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/controllers/apiController.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/controllers/serverController.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/controllers/vpnConfigurationController.h
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.h
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/qml_register_protocols.h
+ ${CMAKE_CURRENT_LIST_DIR}/ui/pages.h
+ ${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.h
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.h
+ ${CMAKE_CURRENT_BINARY_DIR}/version.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/sshclient.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/networkUtilities.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/serialization/serialization.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/serialization/transfer.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/enums/apiEnums.h
+ ${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.h
+)
+
+# Mozilla headres
+set(HEADERS ${HEADERS}
+ ${CMAKE_CURRENT_LIST_DIR}/mozilla/models/server.h
+ ${CMAKE_CURRENT_LIST_DIR}/mozilla/shared/ipaddress.h
+ ${CMAKE_CURRENT_LIST_DIR}/mozilla/shared/leakdetector.h
+ ${CMAKE_CURRENT_LIST_DIR}/mozilla/controllerimpl.h
+ ${CMAKE_CURRENT_LIST_DIR}/mozilla/localsocketcontroller.h
+)
+
include_directories(mozilla)
include_directories(mozilla/shared)
include_directories(mozilla/models)
-configure_file(${CMAKE_CURRENT_LIST_DIR}/../version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
+if(NOT IOS)
+ set(HEADERS ${HEADERS}
+ ${CMAKE_CURRENT_LIST_DIR}/platforms/ios/QRCodeReaderBase.h
+ )
+endif()
+
+if(NOT ANDROID)
+ set(HEADERS ${HEADERS}
+ ${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.h
+ )
+endif()
+
+set(SOURCES ${SOURCES}
+ ${CMAKE_CURRENT_LIST_DIR}/migrations.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/amnezia_application.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/containers/containers_defs.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/errorstrings.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/scripts_registry.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/server_defs.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/controllers/apiController.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/controllers/serverController.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/controllers/vpnConfigurationController.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/sshclient.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/networkUtilities.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/serialization/outbound.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/serialization/inbound.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/serialization/ss.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/serialization/ssd.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/serialization/vless.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/serialization/trojan.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess_new.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.cpp
+)
+
+# Mozilla sources
+set(SOURCES ${SOURCES}
+ ${CMAKE_CURRENT_LIST_DIR}/mozilla/models/server.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mozilla/shared/ipaddress.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mozilla/shared/leakdetector.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/mozilla/localsocketcontroller.cpp
+)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(${PROJECT} PRIVATE "MZ_DEBUG")
endif()
+if(NOT IOS)
+ set(SOURCES ${SOURCES}
+ ${CMAKE_CURRENT_LIST_DIR}/platforms/ios/QRCodeReaderBase.cpp
+ )
+endif()
+
+if(NOT ANDROID)
+ set(SOURCES ${SOURCES}
+ ${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.cpp
+ )
+endif()
+
+file(GLOB COMMON_FILES_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/*.h)
+file(GLOB COMMON_FILES_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/*.cpp)
+
+file(GLOB_RECURSE PAGE_LOGIC_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/pages_logic/*.h)
+file(GLOB_RECURSE PAGE_LOGIC_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/pages_logic/*.cpp)
+
+file(GLOB CONFIGURATORS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/configurators/*.h)
+file(GLOB CONFIGURATORS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/configurators/*.cpp)
+
+file(GLOB UI_MODELS_H CONFIGURE_DEPENDS
+ ${CMAKE_CURRENT_LIST_DIR}/ui/models/*.h
+ ${CMAKE_CURRENT_LIST_DIR}/ui/models/protocols/*.h
+ ${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.h
+)
+file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
+ ${CMAKE_CURRENT_LIST_DIR}/ui/models/*.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/ui/models/protocols/*.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.cpp
+)
+
+file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.h)
+file(GLOB UI_CONTROLLERS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.cpp)
+
+set(HEADERS ${HEADERS}
+ ${COMMON_FILES_H}
+ ${PAGE_LOGIC_H}
+ ${CONFIGURATORS_H}
+ ${UI_MODELS_H}
+ ${UI_CONTROLLERS_H}
+)
+set(SOURCES ${SOURCES}
+ ${COMMON_FILES_CPP}
+ ${PAGE_LOGIC_CPP}
+ ${CONFIGURATORS_CPP}
+ ${UI_MODELS_CPP}
+ ${UI_CONTROLLERS_CPP}
+)
+
if(WIN32)
configure_file(
${CMAKE_CURRENT_LIST_DIR}/platforms/windows/amneziavpn.rc.in
${CMAKE_CURRENT_BINARY_DIR}/amneziavpn.rc
)
+ set(HEADERS ${HEADERS}
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.h
+ )
+
+ set(SOURCES ${SOURCES}
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
+ )
+
+ set(RESOURCES ${RESOURCES}
+ ${CMAKE_CURRENT_BINARY_DIR}/amneziavpn.rc
+ )
+
set(LIBS ${LIBS}
user32
rasapi32
@@ -169,6 +322,30 @@ endif()
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
message("Client desktop build")
add_compile_definitions(AMNEZIA_DESKTOP)
+
+ set(HEADERS ${HEADERS}
+ ${CMAKE_CURRENT_LIST_DIR}/core/ipcclient.h
+ ${CMAKE_CURRENT_LIST_DIR}/core/privileged_process.h
+ ${CMAKE_CURRENT_LIST_DIR}/ui/systemtray_notificationhandler.h
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnprotocol.h
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.h
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.h
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.h
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/xrayprotocol.h
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/awgprotocol.h
+ )
+
+ set(SOURCES ${SOURCES}
+ ${CMAKE_CURRENT_LIST_DIR}/core/ipcclient.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/core/privileged_process.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/ui/systemtray_notificationhandler.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnprotocol.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/xrayprotocol.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/protocols/awgprotocol.cpp
+ )
endif()
if(ANDROID)
diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp
index f32d525a..4e25097d 100644
--- a/client/amnezia_application.cpp
+++ b/client/amnezia_application.cpp
@@ -2,8 +2,6 @@
#include
#include
-#include
-#include
#include
#include
#include
@@ -12,16 +10,26 @@
#include
#include
#include
+#include
+#include
#include "logger.h"
-#include "ui/controllers/pageController.h"
#include "ui/models/installedAppsModel.h"
#include "version.h"
#include "platforms/ios/QRCodeReaderBase.h"
+#if defined(Q_OS_ANDROID)
+ #include "core/installedAppsImageProvider.h"
+ #include "platforms/android/android_controller.h"
+#endif
#include "protocols/qml_register_protocols.h"
+#if defined(Q_OS_IOS)
+ #include "platforms/ios/ios_controller.h"
+ #include
+#endif
+
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv)
{
setQuitOnLastWindowClosed(false);
@@ -76,12 +84,79 @@ void AmneziaApplication::init()
m_vpnConnection->moveToThread(&m_vpnConnectionThread);
m_vpnConnectionThread.start();
- m_coreController.reset(new CoreController(m_vpnConnection, m_settings, m_engine));
+ initModels();
+ loadTranslator();
+ initControllers();
+
+#ifdef Q_OS_ANDROID
+ if (!AndroidController::initLogging()) {
+ qFatal("Android logging initialization failed");
+ }
+ AndroidController::instance()->setSaveLogs(m_settings->isSaveLogs());
+ connect(m_settings.get(), &Settings::saveLogsChanged, AndroidController::instance(), &AndroidController::setSaveLogs);
+
+ AndroidController::instance()->setScreenshotsEnabled(m_settings->isScreenshotsEnabled());
+ connect(m_settings.get(), &Settings::screenshotsEnabledChanged, AndroidController::instance(), &AndroidController::setScreenshotsEnabled);
+
+ connect(m_settings.get(), &Settings::serverRemoved, AndroidController::instance(), &AndroidController::resetLastServer);
+
+ connect(m_settings.get(), &Settings::settingsCleared, []() { AndroidController::instance()->resetLastServer(-1); });
+
+ connect(AndroidController::instance(), &AndroidController::initConnectionState, this, [this](Vpn::ConnectionState state) {
+ m_connectionController->onConnectionStateChanged(state);
+ if (m_vpnConnection)
+ m_vpnConnection->restoreConnection();
+ });
+ if (!AndroidController::instance()->initialize()) {
+ qFatal("Android controller initialization failed");
+ }
+
+ connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, this, [this](QString data) {
+ emit m_pageController->goToPageHome();
+ m_importController->extractConfigFromData(data);
+ data.clear();
+ emit m_pageController->goToPageViewConfig();
+ });
+
+ m_engine->addImageProvider(QLatin1String("installedAppImage"), new InstalledAppsImageProvider);
+#endif
+
+#ifdef Q_OS_IOS
+ IosController::Instance()->initialize();
+ connect(IosController::Instance(), &IosController::importConfigFromOutside, this, [this](QString data) {
+ emit m_pageController->goToPageHome();
+ m_importController->extractConfigFromData(data);
+ emit m_pageController->goToPageViewConfig();
+ });
+
+ connect(IosController::Instance(), &IosController::importBackupFromOutside, this, [this](QString filePath) {
+ emit m_pageController->goToPageHome();
+ m_pageController->goToPageSettingsBackup();
+ emit m_settingsController->importBackupFromOutside(filePath);
+ });
+
+ QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled()); });
+
+ connect(m_settings.get(), &Settings::screenshotsEnabledChanged, [](bool enabled) { AmneziaVPN::toggleScreenshots(enabled); });
+#endif
+
+#ifndef Q_OS_ANDROID
+ m_notificationHandler.reset(NotificationHandler::create(nullptr));
+
+ connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(),
+ &NotificationHandler::setConnectionState);
+
+ connect(m_notificationHandler.get(), &NotificationHandler::raiseRequested, m_pageController.get(), &PageController::raiseMainWindow);
+ connect(m_notificationHandler.get(), &NotificationHandler::connectRequested, m_connectionController.get(),
+ static_cast(&ConnectionController::openConnection));
+ connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
+ &ConnectionController::closeConnection);
+ connect(this, &AmneziaApplication::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated);
+#endif
m_engine->addImportPath("qrc:/ui/qml/Modules/");
m_engine->load(url);
-
- m_coreController->setQmlRoot();
+ m_systemController->setQmlRoot(m_engine->rootObjects().value(0));
bool enabled = m_settings->isSaveLogs();
#ifndef Q_OS_ANDROID
@@ -93,13 +168,13 @@ void AmneziaApplication::init()
#endif
Logger::setServiceLogsEnabled(enabled);
-#ifdef Q_OS_WIN //TODO
+#ifdef Q_OS_WIN
if (m_parser.isSet("a"))
- m_coreController->pageController()->showOnStartup();
+ m_pageController->showOnStartup();
else
- emit m_coreController->pageController()->raiseMainWindow();
+ emit m_pageController->raiseMainWindow();
#else
- m_coreController->pageController()->showOnStartup();
+ m_pageController->showOnStartup();
#endif
// Android TextArea clipboard workaround
@@ -156,6 +231,33 @@ void AmneziaApplication::loadFonts()
QFontDatabase::addApplicationFont(":/fonts/pt-root-ui_vf.ttf");
}
+void AmneziaApplication::loadTranslator()
+{
+ auto locale = m_settings->getAppLanguage();
+ m_translator.reset(new QTranslator());
+ updateTranslator(locale);
+}
+
+void AmneziaApplication::updateTranslator(const QLocale &locale)
+{
+ if (!m_translator->isEmpty()) {
+ QCoreApplication::removeTranslator(m_translator.get());
+ }
+
+ QString strFileName = QString(":/translations/amneziavpn") + QLatin1String("_") + locale.name() + ".qm";
+ if (m_translator->load(strFileName)) {
+ if (QCoreApplication::installTranslator(m_translator.get())) {
+ m_settings->setAppLanguage(locale);
+ }
+ } else {
+ m_settings->setAppLanguage(QLocale::English);
+ }
+
+ m_engine->retranslate();
+
+ emit translationsUpdated();
+}
+
bool AmneziaApplication::parseCommands()
{
m_parser.setApplicationDescription(APPLICATION_NAME);
@@ -180,20 +282,19 @@ bool AmneziaApplication::parseCommands()
}
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
-void AmneziaApplication::startLocalServer()
-{
+void AmneziaApplication::startLocalServer() {
const QString serverName("AmneziaVPNInstance");
QLocalServer::removeServer(serverName);
- QLocalServer *server = new QLocalServer(this);
+ QLocalServer* server = new QLocalServer(this);
server->listen(serverName);
QObject::connect(server, &QLocalServer::newConnection, this, [server, this]() {
if (server) {
- QLocalSocket *clientConnection = server->nextPendingConnection();
+ QLocalSocket* clientConnection = server->nextPendingConnection();
clientConnection->deleteLater();
}
- emit m_coreController->pageController()->raiseMainWindow(); //TODO
+ emit m_pageController->raiseMainWindow();
});
}
#endif
@@ -203,12 +304,160 @@ QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
return m_engine;
}
-QNetworkAccessManager *AmneziaApplication::networkManager()
+void AmneziaApplication::initModels()
{
- return m_nam;
+ m_containersModel.reset(new ContainersModel(this));
+ m_engine->rootContext()->setContextProperty("ContainersModel", m_containersModel.get());
+
+ m_defaultServerContainersModel.reset(new ContainersModel(this));
+ m_engine->rootContext()->setContextProperty("DefaultServerContainersModel", m_defaultServerContainersModel.get());
+
+ m_serversModel.reset(new ServersModel(m_settings, this));
+ m_engine->rootContext()->setContextProperty("ServersModel", m_serversModel.get());
+ connect(m_serversModel.get(), &ServersModel::containersUpdated, m_containersModel.get(), &ContainersModel::updateModel);
+ connect(m_serversModel.get(), &ServersModel::defaultServerContainersUpdated, m_defaultServerContainersModel.get(),
+ &ContainersModel::updateModel);
+ m_serversModel->resetModel();
+
+ m_languageModel.reset(new LanguageModel(m_settings, this));
+ m_engine->rootContext()->setContextProperty("LanguageModel", m_languageModel.get());
+ connect(m_languageModel.get(), &LanguageModel::updateTranslations, this, &AmneziaApplication::updateTranslator);
+ connect(this, &AmneziaApplication::translationsUpdated, m_languageModel.get(), &LanguageModel::translationsUpdated);
+
+ m_sitesModel.reset(new SitesModel(m_settings, this));
+ m_engine->rootContext()->setContextProperty("SitesModel", m_sitesModel.get());
+
+ m_appSplitTunnelingModel.reset(new AppSplitTunnelingModel(m_settings, this));
+ m_engine->rootContext()->setContextProperty("AppSplitTunnelingModel", m_appSplitTunnelingModel.get());
+
+ m_protocolsModel.reset(new ProtocolsModel(m_settings, this));
+ m_engine->rootContext()->setContextProperty("ProtocolsModel", m_protocolsModel.get());
+
+ m_openVpnConfigModel.reset(new OpenVpnConfigModel(this));
+ m_engine->rootContext()->setContextProperty("OpenVpnConfigModel", m_openVpnConfigModel.get());
+
+ m_shadowSocksConfigModel.reset(new ShadowSocksConfigModel(this));
+ m_engine->rootContext()->setContextProperty("ShadowSocksConfigModel", m_shadowSocksConfigModel.get());
+
+ m_cloakConfigModel.reset(new CloakConfigModel(this));
+ m_engine->rootContext()->setContextProperty("CloakConfigModel", m_cloakConfigModel.get());
+
+ m_wireGuardConfigModel.reset(new WireGuardConfigModel(this));
+ m_engine->rootContext()->setContextProperty("WireGuardConfigModel", m_wireGuardConfigModel.get());
+
+ m_awgConfigModel.reset(new AwgConfigModel(this));
+ m_engine->rootContext()->setContextProperty("AwgConfigModel", m_awgConfigModel.get());
+
+ m_xrayConfigModel.reset(new XrayConfigModel(this));
+ m_engine->rootContext()->setContextProperty("XrayConfigModel", m_xrayConfigModel.get());
+
+#ifdef Q_OS_WINDOWS
+ m_ikev2ConfigModel.reset(new Ikev2ConfigModel(this));
+ m_engine->rootContext()->setContextProperty("Ikev2ConfigModel", m_ikev2ConfigModel.get());
+#endif
+
+ m_sftpConfigModel.reset(new SftpConfigModel(this));
+ m_engine->rootContext()->setContextProperty("SftpConfigModel", m_sftpConfigModel.get());
+
+ m_socks5ConfigModel.reset(new Socks5ProxyConfigModel(this));
+ m_engine->rootContext()->setContextProperty("Socks5ProxyConfigModel", m_socks5ConfigModel.get());
+
+ m_clientManagementModel.reset(new ClientManagementModel(m_settings, this));
+ m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get());
+ connect(m_clientManagementModel.get(), &ClientManagementModel::adminConfigRevoked, m_serversModel.get(),
+ &ServersModel::clearCachedProfile);
+
+ m_apiServicesModel.reset(new ApiServicesModel(this));
+ m_engine->rootContext()->setContextProperty("ApiServicesModel", m_apiServicesModel.get());
+
+ m_apiCountryModel.reset(new ApiCountryModel(this));
+ m_engine->rootContext()->setContextProperty("ApiCountryModel", m_apiCountryModel.get());
+ connect(m_serversModel.get(), &ServersModel::updateApiLanguageModel, this, [this]() {
+ m_apiCountryModel->updateModel(m_serversModel->getProcessedServerData("apiAvailableCountries").toJsonArray(),
+ m_serversModel->getProcessedServerData("apiServerCountryCode").toString());
+ });
+ connect(m_serversModel.get(), &ServersModel::updateApiServicesModel, this,
+ [this]() { m_apiServicesModel->updateModel(m_serversModel->getProcessedServerData("apiConfig").toJsonObject()); });
}
-QClipboard *AmneziaApplication::getClipboard()
+void AmneziaApplication::initControllers()
{
- return this->clipboard();
+ m_connectionController.reset(
+ new ConnectionController(m_serversModel, m_containersModel, m_clientManagementModel, m_vpnConnection, m_settings));
+ m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get());
+
+ connect(m_connectionController.get(), qOverload(&ConnectionController::connectionErrorOccurred), this,
+ [this](const QString &errorMessage) {
+ emit m_pageController->showErrorMessage(errorMessage);
+ emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
+ });
+
+ connect(m_connectionController.get(), qOverload(&ConnectionController::connectionErrorOccurred), this,
+ [this](ErrorCode errorCode) {
+ emit m_pageController->showErrorMessage(errorCode);
+ emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
+ });
+
+ connect(m_connectionController.get(), &ConnectionController::connectButtonClicked, m_connectionController.get(),
+ &ConnectionController::toggleConnection, Qt::QueuedConnection);
+
+ m_pageController.reset(new PageController(m_serversModel, m_settings));
+ m_engine->rootContext()->setContextProperty("PageController", m_pageController.get());
+
+ m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel, m_clientManagementModel,
+ m_apiServicesModel, m_settings));
+ m_engine->rootContext()->setContextProperty("InstallController", m_installController.get());
+ connect(m_installController.get(), &InstallController::passphraseRequestStarted, m_pageController.get(),
+ &PageController::showPassphraseRequestDrawer);
+ connect(m_pageController.get(), &PageController::passphraseRequestDrawerClosed, m_installController.get(),
+ &InstallController::setEncryptedPassphrase);
+ connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(),
+ &ConnectionController::onCurrentContainerUpdated);
+
+ connect(m_installController.get(), &InstallController::updateServerFromApiFinished, this, [this]() {
+ disconnect(m_reloadConfigErrorOccurredConnection);
+ emit m_connectionController->configFromApiUpdated();
+ });
+
+ connect(m_connectionController.get(), &ConnectionController::updateApiConfigFromGateway, this, [this]() {
+ m_reloadConfigErrorOccurredConnection = connect(
+ m_installController.get(), qOverload(&InstallController::installationErrorOccurred), this,
+ [this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected); },
+ static_cast(Qt::AutoConnection || Qt::SingleShotConnection));
+ m_installController->updateServiceFromApi(m_serversModel->getDefaultServerIndex(), "", "");
+ });
+
+ connect(m_connectionController.get(), &ConnectionController::updateApiConfigFromTelegram, this, [this]() {
+ m_reloadConfigErrorOccurredConnection = connect(
+ m_installController.get(), qOverload(&InstallController::installationErrorOccurred), this,
+ [this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected); },
+ static_cast(Qt::AutoConnection || Qt::SingleShotConnection));
+ m_serversModel->removeApiConfig(m_serversModel->getDefaultServerIndex());
+ m_installController->updateServiceFromTelegram(m_serversModel->getDefaultServerIndex());
+ });
+
+ connect(this, &AmneziaApplication::translationsUpdated, m_connectionController.get(), &ConnectionController::onTranslationsUpdated);
+
+ m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
+ m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
+
+ m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_clientManagementModel, m_settings));
+ m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get());
+
+ m_settingsController.reset(
+ new SettingsController(m_serversModel, m_containersModel, m_languageModel, m_sitesModel, m_appSplitTunnelingModel, m_settings));
+ m_engine->rootContext()->setContextProperty("SettingsController", m_settingsController.get());
+ if (m_settingsController->isAutoConnectEnabled() && m_serversModel->getDefaultServerIndex() >= 0) {
+ QTimer::singleShot(1000, this, [this]() { m_connectionController->openConnection(); });
+ }
+ connect(m_settingsController.get(), &SettingsController::amneziaDnsToggled, m_serversModel.get(), &ServersModel::toggleAmneziaDns);
+
+ m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel));
+ m_engine->rootContext()->setContextProperty("SitesController", m_sitesController.get());
+
+ m_appSplitTunnelingController.reset(new AppSplitTunnelingController(m_settings, m_appSplitTunnelingModel));
+ m_engine->rootContext()->setContextProperty("AppSplitTunnelingController", m_appSplitTunnelingController.get());
+
+ m_systemController.reset(new SystemController(m_settings));
+ m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());
}
diff --git a/client/amnezia_application.h b/client/amnezia_application.h
index ea5f6f52..64566216 100644
--- a/client/amnezia_application.h
+++ b/client/amnezia_application.h
@@ -11,12 +11,43 @@
#else
#include
#endif
-#include
-#include "core/controllers/coreController.h"
#include "settings.h"
#include "vpnconnection.h"
+#include "ui/controllers/connectionController.h"
+#include "ui/controllers/exportController.h"
+#include "ui/controllers/importController.h"
+#include "ui/controllers/installController.h"
+#include "ui/controllers/pageController.h"
+#include "ui/controllers/settingsController.h"
+#include "ui/controllers/sitesController.h"
+#include "ui/controllers/systemController.h"
+#include "ui/controllers/appSplitTunnelingController.h"
+#include "ui/models/containers_model.h"
+#include "ui/models/languageModel.h"
+#include "ui/models/protocols/cloakConfigModel.h"
+#ifndef Q_OS_ANDROID
+ #include "ui/notificationhandler.h"
+#endif
+#ifdef Q_OS_WINDOWS
+ #include "ui/models/protocols/ikev2ConfigModel.h"
+#endif
+#include "ui/models/protocols/awgConfigModel.h"
+#include "ui/models/protocols/openvpnConfigModel.h"
+#include "ui/models/protocols/shadowsocksConfigModel.h"
+#include "ui/models/protocols/wireguardConfigModel.h"
+#include "ui/models/protocols/xrayConfigModel.h"
+#include "ui/models/protocols_model.h"
+#include "ui/models/servers_model.h"
+#include "ui/models/services/sftpConfigModel.h"
+#include "ui/models/services/socks5ProxyConfigModel.h"
+#include "ui/models/sites_model.h"
+#include "ui/models/clientManagementModel.h"
+#include "ui/models/appSplitTunnelingModel.h"
+#include "ui/models/apiServicesModel.h"
+#include "ui/models/apiCountryModel.h"
+
#define amnApp (static_cast(QCoreApplication::instance()))
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
@@ -35,6 +66,8 @@ public:
void init();
void registerTypes();
void loadFonts();
+ void loadTranslator();
+ void updateTranslator(const QLocale &locale);
bool parseCommands();
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
@@ -42,24 +75,67 @@ public:
#endif
QQmlApplicationEngine *qmlEngine() const;
- QNetworkAccessManager *networkManager();
- QClipboard *getClipboard();
+ QNetworkAccessManager *manager() { return m_nam; }
+
+signals:
+ void translationsUpdated();
private:
+ void initModels();
+ void initControllers();
+
QQmlApplicationEngine *m_engine {};
std::shared_ptr m_settings;
- QScopedPointer m_coreController;
-
QSharedPointer m_containerProps;
QSharedPointer m_protocolProps;
+ QSharedPointer m_translator;
QCommandLineParser m_parser;
+ QSharedPointer m_containersModel;
+ QSharedPointer m_defaultServerContainersModel;
+ QSharedPointer m_serversModel;
+ QSharedPointer m_languageModel;
+ QSharedPointer m_protocolsModel;
+ QSharedPointer m_sitesModel;
+ QSharedPointer m_appSplitTunnelingModel;
+ QSharedPointer m_clientManagementModel;
+ QSharedPointer m_apiServicesModel;
+ QSharedPointer m_apiCountryModel;
+
+ QScopedPointer m_openVpnConfigModel;
+ QScopedPointer m_shadowSocksConfigModel;
+ QScopedPointer m_cloakConfigModel;
+ QScopedPointer m_xrayConfigModel;
+ QScopedPointer m_wireGuardConfigModel;
+ QScopedPointer m_awgConfigModel;
+#ifdef Q_OS_WINDOWS
+ QScopedPointer m_ikev2ConfigModel;
+#endif
+
+ QScopedPointer m_sftpConfigModel;
+ QScopedPointer m_socks5ConfigModel;
+
QSharedPointer m_vpnConnection;
QThread m_vpnConnectionThread;
+#ifndef Q_OS_ANDROID
+ QScopedPointer m_notificationHandler;
+#endif
+
+ QScopedPointer m_connectionController;
+ QScopedPointer m_pageController;
+ QScopedPointer m_installController;
+ QScopedPointer m_importController;
+ QScopedPointer m_exportController;
+ QScopedPointer m_settingsController;
+ QScopedPointer m_sitesController;
+ QScopedPointer m_systemController;
+ QScopedPointer m_appSplitTunnelingController;
QNetworkAccessManager *m_nam;
+
+ QMetaObject::Connection m_reloadConfigErrorOccurredConnection;
};
#endif // AMNEZIA_APPLICATION_H
diff --git a/client/android/AndroidManifest.xml b/client/android/AndroidManifest.xml
index b28f754b..9e44e022 100644
--- a/client/android/AndroidManifest.xml
+++ b/client/android/AndroidManifest.xml
@@ -91,13 +91,6 @@
android:exported="false"
android:theme="@style/Translucent" />
-
-
+
+
+
+
\ No newline at end of file
diff --git a/client/android/res/mipmap-hdpi/ic_banner.png b/client/android/res/mipmap-hdpi/ic_banner.png
deleted file mode 100644
index a444777f..00000000
Binary files a/client/android/res/mipmap-hdpi/ic_banner.png and /dev/null differ
diff --git a/client/android/res/mipmap-mdpi/ic_banner.png b/client/android/res/mipmap-mdpi/ic_banner.png
deleted file mode 100644
index b9ad1db7..00000000
Binary files a/client/android/res/mipmap-mdpi/ic_banner.png and /dev/null differ
diff --git a/client/android/res/mipmap-xhdpi/ic_banner_foreground.png b/client/android/res/mipmap-xhdpi/ic_banner_foreground.png
new file mode 100644
index 00000000..1c21902e
Binary files /dev/null and b/client/android/res/mipmap-xhdpi/ic_banner_foreground.png differ
diff --git a/client/android/res/values-ru/strings.xml b/client/android/res/values-ru/strings.xml
index 5e35bba5..8bdabfc0 100644
--- a/client/android/res/values-ru/strings.xml
+++ b/client/android/res/values-ru/strings.xml
@@ -23,6 +23,4 @@
Настройки уведомлений
Для показа уведомлений необходимо включить уведомления в системных настройках
Открыть настройки уведомлений
-
- Пожалуйста, установите приложение для просмотра файлов
\ No newline at end of file
diff --git a/client/android/res/values/ic_banner_background.xml b/client/android/res/values/ic_banner_background.xml
new file mode 100644
index 00000000..fa6f91c7
--- /dev/null
+++ b/client/android/res/values/ic_banner_background.xml
@@ -0,0 +1,4 @@
+
+
+ #1E1E1F
+
\ No newline at end of file
diff --git a/client/android/res/values/strings.xml b/client/android/res/values/strings.xml
index bf8d76d1..5251403b 100644
--- a/client/android/res/values/strings.xml
+++ b/client/android/res/values/strings.xml
@@ -23,6 +23,4 @@
Notification settings
To show notifications, you must enable notifications in the system settings
Open notification settings
-
- Please install a file management utility to browse files
\ No newline at end of file
diff --git a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
index c6db5e29..b2c2ff71 100644
--- a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
+++ b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
@@ -4,7 +4,6 @@ import android.Manifest
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.NotificationManager
-import android.content.ActivityNotFoundException
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Intent
@@ -13,7 +12,6 @@ import android.content.Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.graphics.Bitmap
-import android.net.Uri
import android.net.VpnService
import android.os.Build
import android.os.Bundle
@@ -22,13 +20,8 @@ import android.os.IBinder
import android.os.Looper
import android.os.Message
import android.os.Messenger
-import android.os.ParcelFileDescriptor
-import android.os.SystemClock
-import android.provider.OpenableColumns
import android.provider.Settings
import android.view.MotionEvent
-import android.view.View
-import android.view.ViewGroup
import android.view.WindowManager.LayoutParams
import android.webkit.MimeTypeMap
import android.widget.Toast
@@ -37,7 +30,6 @@ import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import java.io.IOException
import kotlin.LazyThreadSafetyMode.NONE
-import kotlin.coroutines.CoroutineContext
import kotlin.text.RegexOption.IGNORE_CASE
import AppListProvider
import kotlinx.coroutines.CompletableDeferred
@@ -79,7 +71,6 @@ class AmneziaActivity : QtActivity() {
private var isInBoundState = false
private var notificationStateReceiver: BroadcastReceiver? = null
private lateinit var vpnServiceMessenger: IpcMessenger
- private var pfd: ParcelFileDescriptor? = null
private val actionResultHandlers = mutableMapOf()
private val permissionRequestHandlers = mutableMapOf()
@@ -523,25 +514,21 @@ class AmneziaActivity : QtActivity() {
type = "text/*"
putExtra(Intent.EXTRA_TITLE, fileName)
}.also {
- try {
- startActivityForResult(it, CREATE_FILE_ACTION_CODE, ActivityResultHandler(
- onSuccess = {
- it?.data?.let { uri ->
- Log.v(TAG, "Save file to $uri")
- try {
- contentResolver.openOutputStream(uri)?.use { os ->
- os.bufferedWriter().use { it.write(data) }
- }
- } catch (e: IOException) {
- Log.e(TAG, "Failed to save file $uri: $e")
- // todo: send error to Qt
+ startActivityForResult(it, CREATE_FILE_ACTION_CODE, ActivityResultHandler(
+ onSuccess = {
+ it?.data?.let { uri ->
+ Log.v(TAG, "Save file to $uri")
+ try {
+ contentResolver.openOutputStream(uri)?.use { os ->
+ os.bufferedWriter().use { it.write(data) }
}
+ } catch (e: IOException) {
+ Log.e(TAG, "Failed to save file $uri: $e")
+ // todo: send error to Qt
}
}
- ))
- } catch (_: ActivityNotFoundException) {
- Toast.makeText(this@AmneziaActivity, "Unsupported", Toast.LENGTH_LONG).show()
- }
+ }
+ ))
}
}
}
@@ -550,46 +537,35 @@ class AmneziaActivity : QtActivity() {
fun openFile(filter: String?) {
Log.v(TAG, "Open file with filter: $filter")
mainScope.launch {
- val intent = if (!isOnTv()) {
- val mimeTypes = if (!filter.isNullOrEmpty()) {
- val extensionRegex = "\\*\\.([a-z0-9]+)".toRegex(IGNORE_CASE)
- val mime = MimeTypeMap.getSingleton()
- extensionRegex.findAll(filter).map {
- it.groups[1]?.value?.let { mime.getMimeTypeFromExtension(it) } ?: "*/*"
- }.toSet()
- } else emptySet()
+ val mimeTypes = if (!filter.isNullOrEmpty()) {
+ val extensionRegex = "\\*\\.([a-z0-9]+)".toRegex(IGNORE_CASE)
+ val mime = MimeTypeMap.getSingleton()
+ extensionRegex.findAll(filter).map {
+ it.groups[1]?.value?.let { mime.getMimeTypeFromExtension(it) } ?: "*/*"
+ }.toSet()
+ } else emptySet()
- Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
- addCategory(Intent.CATEGORY_OPENABLE)
- Log.v(TAG, "File mimyType filter: $mimeTypes")
- if ("*/*" in mimeTypes) {
- type = "*/*"
- } else {
- when (mimeTypes.size) {
- 1 -> type = mimeTypes.first()
+ Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ Log.v(TAG, "File mimyType filter: $mimeTypes")
+ if ("*/*" in mimeTypes) {
+ type = "*/*"
+ } else {
+ when (mimeTypes.size) {
+ 1 -> type = mimeTypes.first()
- in 2..Int.MAX_VALUE -> {
- type = "*/*"
- putExtra(EXTRA_MIME_TYPES, mimeTypes.toTypedArray())
- }
-
- else -> type = "*/*"
+ in 2..Int.MAX_VALUE -> {
+ type = "*/*"
+ putExtra(EXTRA_MIME_TYPES, mimeTypes.toTypedArray())
}
+
+ else -> type = "*/*"
}
}
- } else {
- Intent(this@AmneziaActivity, TvFilePicker::class.java)
- }
-
- try {
- startActivityForResult(intent, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
+ }.also {
+ startActivityForResult(it, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
onAny = {
- if (isOnTv() && it?.hasExtra("activityNotFound") == true) {
- showNoFileBrowserAlertDialog()
- }
- val uri = it?.data?.apply {
- grantUriPermission(packageName, this, Intent.FLAG_GRANT_READ_URI_PERMISSION)
- }?.toString() ?: ""
+ val uri = it?.data?.toString() ?: ""
Log.v(TAG, "Open file: $uri")
mainScope.launch {
qtInitialized.await()
@@ -597,68 +573,10 @@ class AmneziaActivity : QtActivity() {
}
}
))
- } catch (_: ActivityNotFoundException) {
- showNoFileBrowserAlertDialog()
- mainScope.launch {
- qtInitialized.await()
- QtAndroidController.onFileOpened("")
- }
}
}
}
- private fun showNoFileBrowserAlertDialog() {
- AlertDialog.Builder(this)
- .setMessage(R.string.tvNoFileBrowser)
- .setCancelable(false)
- .setPositiveButton(android.R.string.ok) { _, _ ->
- try {
- startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://webstoreredirect")))
- } catch (_: Throwable) {}
- }
- .show()
- }
-
- @Suppress("unused")
- fun getFd(fileName: String): Int {
- Log.v(TAG, "Get fd for $fileName")
- return blockingCall {
- try {
- pfd = contentResolver.openFileDescriptor(Uri.parse(fileName), "r")
- pfd?.fd ?: -1
- } catch (e: Exception) {
- Log.e(TAG, "Failed to get fd: $e")
- -1
- }
- }
- }
-
- @Suppress("unused")
- fun closeFd() {
- Log.v(TAG, "Close fd")
- mainScope.launch {
- pfd?.close()
- pfd = null
- }
- }
-
- @Suppress("unused")
- fun getFileName(uri: String): String {
- Log.v(TAG, "Get file name for uri: $uri")
- return blockingCall {
- try {
- contentResolver.query(Uri.parse(uri), arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use { cursor ->
- if (cursor.moveToFirst() && !cursor.isNull(0)) {
- return@blockingCall cursor.getString(0) ?: ""
- }
- }
- } catch (e: Exception) {
- Log.e(TAG, "Failed to get file name: $e")
- }
- ""
- }
- }
-
@Suppress("unused")
@SuppressLint("UnsupportedChromeOsCameraSystemFeature")
fun isCameraPresent(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
@@ -803,50 +721,6 @@ class AmneziaActivity : QtActivity() {
}
}
- // method to workaround Qt's problem with calling the keyboard on TVs
- @Suppress("unused")
- fun sendTouch(x: Float, y: Float) {
- Log.v(TAG, "Send touch: $x, $y")
- blockingCall {
- findQtWindow(window.decorView)?.let {
- Log.v(TAG, "Send touch to $it")
- it.dispatchTouchEvent(createEvent(x, y, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN))
- it.dispatchTouchEvent(createEvent(x, y, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP))
- }
- }
- }
-
- private fun findQtWindow(view: View): View? {
- Log.v(TAG, "findQtWindow: process $view")
- if (view::class.simpleName == "QtWindow") return view
- else if (view is ViewGroup) {
- for (i in 0 until view.childCount) {
- val result = findQtWindow(view.getChildAt(i))
- if (result != null) return result
- }
- return null
- } else return null
- }
-
- private fun createEvent(x: Float, y: Float, eventTime: Long, action: Int): MotionEvent =
- MotionEvent.obtain(
- eventTime,
- eventTime,
- action,
- 1,
- arrayOf(MotionEvent.PointerProperties().apply {
- id = 0
- toolType = MotionEvent.TOOL_TYPE_FINGER
- }),
- arrayOf(MotionEvent.PointerCoords().apply {
- this.x = x
- this.y = y
- pressure = 1f
- size = 1f
- }),
- 0, 0, 1.0f, 1.0f, 0, 0, 0,0
- )
-
// workaround for a bug in Qt that causes the mouse click event not to be handled
// also disable right-click, as it causes the application to crash
private var lastButtonState = 0
@@ -896,7 +770,6 @@ class AmneziaActivity : QtActivity() {
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
- Log.v(TAG, "dispatchTouch: $ev")
if (ev != null && ev.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
return handleMouseEvent(ev) { super.dispatchTouchEvent(it) }
}
@@ -911,13 +784,6 @@ class AmneziaActivity : QtActivity() {
/**
* Utils methods
*/
- private fun blockingCall(
- context: CoroutineContext = Dispatchers.Main.immediate,
- block: suspend () -> T
- ) = runBlocking {
- mainScope.async(context) { block() }.await()
- }
-
companion object {
private fun actionCodeToString(actionCode: Int): String =
when (actionCode) {
diff --git a/client/android/src/org/amnezia/vpn/TvFilePicker.kt b/client/android/src/org/amnezia/vpn/TvFilePicker.kt
deleted file mode 100644
index 1ac275eb..00000000
--- a/client/android/src/org/amnezia/vpn/TvFilePicker.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.amnezia.vpn
-
-import android.content.ActivityNotFoundException
-import android.content.Intent
-import android.os.Bundle
-import androidx.activity.ComponentActivity
-import androidx.activity.result.contract.ActivityResultContracts
-import org.amnezia.vpn.util.Log
-
-private const val TAG = "TvFilePicker"
-
-class TvFilePicker : ComponentActivity() {
-
- private val fileChooseResultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) {
- setResult(RESULT_OK, Intent().apply { data = it })
- finish()
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- Log.v(TAG, "onCreate")
- getFile()
- }
-
- override fun onNewIntent(intent: Intent) {
- super.onNewIntent(intent)
- Log.v(TAG, "onNewIntent")
- getFile()
- }
-
- private fun getFile() {
- try {
- Log.v(TAG, "getFile")
- fileChooseResultLauncher.launch("*/*")
- } catch (_: ActivityNotFoundException) {
- Log.w(TAG, "Activity not found")
- setResult(RESULT_CANCELED, Intent().apply { putExtra("activityNotFound", true) })
- finish()
- } catch (e: Exception) {
- Log.e(TAG, "Failed to get file: $e")
- setResult(RESULT_CANCELED)
- finish()
- }
- }
-}
diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
index 42a27de4..80cab96d 100644
--- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
+++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
@@ -120,21 +120,10 @@ open class Wireguard : Protocol() {
configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
configData.optStringOrNull("S1")?.let { setS1(it.toInt()) }
configData.optStringOrNull("S2")?.let { setS2(it.toInt()) }
- configData.optStringOrNull("S3")?.let { setS3(it.toInt()) }
- configData.optStringOrNull("S4")?.let { setS4(it.toInt()) }
configData.optStringOrNull("H1")?.let { setH1(it.toLong()) }
configData.optStringOrNull("H2")?.let { setH2(it.toLong()) }
configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
- configData.optStringOrNull("I1")?.let { setI1(it) }
- configData.optStringOrNull("I2")?.let { setI2(it) }
- configData.optStringOrNull("I3")?.let { setI3(it) }
- configData.optStringOrNull("I4")?.let { setI4(it) }
- configData.optStringOrNull("I5")?.let { setI5(it) }
- configData.optStringOrNull("J1")?.let { setJ1(it) }
- configData.optStringOrNull("J2")?.let { setJ2(it) }
- configData.optStringOrNull("J3")?.let { setJ3(it) }
- configData.optStringOrNull("Itime")?.let { setItime(it.toInt()) }
}
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt
index 2dfbbae8..7ae3d43b 100644
--- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt
+++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt
@@ -20,21 +20,10 @@ open class WireguardConfig protected constructor(
val jmax: Int?,
val s1: Int?,
val s2: Int?,
- val s3: Int?,
- val s4: Int?,
val h1: Long?,
val h2: Long?,
val h3: Long?,
- val h4: Long?,
- var i1: String?,
- var i2: String?,
- var i3: String?,
- var i4: String?,
- var i5: String?,
- var j1: String?,
- var j2: String?,
- var j3: String?,
- var itime: Int?
+ val h4: Long?
) : ProtocolConfig(protocolConfigBuilder) {
protected constructor(builder: Builder) : this(
@@ -50,21 +39,10 @@ open class WireguardConfig protected constructor(
builder.jmax,
builder.s1,
builder.s2,
- builder.s3,
- builder.s4,
builder.h1,
builder.h2,
builder.h3,
- builder.h4,
- builder.i1,
- builder.i2,
- builder.i3,
- builder.i4,
- builder.i5,
- builder.j1,
- builder.j2,
- builder.j3,
- builder.itime
+ builder.h4
)
fun toWgUserspaceString(): String = with(StringBuilder()) {
@@ -83,21 +61,10 @@ open class WireguardConfig protected constructor(
appendLine("jmax=$jmax")
appendLine("s1=$s1")
appendLine("s2=$s2")
- s3?.let { appendLine("s3=$it") }
- s4?.let { appendLine("s4=$it") }
appendLine("h1=$h1")
appendLine("h2=$h2")
appendLine("h3=$h3")
appendLine("h4=$h4")
- i1?.let { appendLine("i1=$it") }
- i2?.let { appendLine("i2=$it") }
- i3?.let { appendLine("i3=$it") }
- i4?.let { appendLine("i4=$it") }
- i5?.let { appendLine("i5=$it") }
- j1?.let { appendLine("j1=$it") }
- j2?.let { appendLine("j2=$it") }
- j3?.let { appendLine("j3=$it") }
- itime?.let { appendLine("itime=$it") }
}
}
@@ -150,21 +117,10 @@ open class WireguardConfig protected constructor(
internal var jmax: Int? = null
internal var s1: Int? = null
internal var s2: Int? = null
- internal var s3: Int? = null
- internal var s4: Int? = null
internal var h1: Long? = null
internal var h2: Long? = null
internal var h3: Long? = null
internal var h4: Long? = null
- internal var i1: String? = null
- internal var i2: String? = null
- internal var i3: String? = null
- internal var i4: String? = null
- internal var i5: String? = null
- internal var j1: String? = null
- internal var j2: String? = null
- internal var j3: String? = null
- internal var itime: Int? = null
fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint }
@@ -183,21 +139,10 @@ open class WireguardConfig protected constructor(
fun setJmax(jmax: Int) = apply { this.jmax = jmax }
fun setS1(s1: Int) = apply { this.s1 = s1 }
fun setS2(s2: Int) = apply { this.s2 = s2 }
- fun setS3(s3: Int) = apply { this.s3 = s3 }
- fun setS4(s4: Int) = apply { this.s4 = s4 }
fun setH1(h1: Long) = apply { this.h1 = h1 }
fun setH2(h2: Long) = apply { this.h2 = h2 }
fun setH3(h3: Long) = apply { this.h3 = h3 }
fun setH4(h4: Long) = apply { this.h4 = h4 }
- fun setI1(i1: String) = apply { this.i1 = i1 }
- fun setI2(i2: String) = apply { this.i2 = i2 }
- fun setI3(i3: String) = apply { this.i3 = i3 }
- fun setI4(i4: String) = apply { this.i4 = i4 }
- fun setI5(i5: String) = apply { this.i5 = i5 }
- fun setJ1(j1: String) = apply { this.j1 = j1 }
- fun setJ2(j2: String) = apply { this.j2 = j2 }
- fun setJ3(j3: String) = apply { this.j3 = j3 }
- fun setItime(itime: Int) = apply { this.itime = itime }
override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) }
}
diff --git a/client/cmake/ios.cmake b/client/cmake/ios.cmake
index a498a5b1..5fda3506 100644
--- a/client/cmake/ios.cmake
+++ b/client/cmake/ios.cmake
@@ -76,22 +76,12 @@ set_target_properties(${PROJECT} PROPERTIES
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks"
XCODE_EMBED_APP_EXTENSIONS networkextension
+ XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution"
+ XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development"
+ XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual
+ XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "match AppStore org.amnezia.AmneziaVPN"
+ XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "match Development org.amnezia.AmneziaVPN"
)
-
-if(DEFINED DEPLOY)
- set_target_properties(${PROJECT} PROPERTIES
- XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution"
- XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development"
- XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual
- XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr ios.org.amnezia.AmneziaVPN"
- XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev ios.org.amnezia.AmneziaVPN"
- )
-else()
- set_target_properties(${PROJECT} PROPERTIES
- XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic
- )
-endif()
-
set_target_properties(${PROJECT} PROPERTIES
XCODE_ATTRIBUTE_SWIFT_VERSION "5.0"
XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES"
@@ -136,9 +126,9 @@ add_subdirectory(ios/networkextension)
add_dependencies(${PROJECT} networkextension)
set_property(TARGET ${PROJECT} PROPERTY XCODE_EMBED_FRAMEWORKS
- "${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-ios/OpenVPNAdapter.framework"
+ "${CMAKE_CURRENT_SOURCE_DIR}/3rd/OpenVPNAdapter/build/Release-iphoneos/OpenVPNAdapter.framework"
)
-set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-ios/)
-target_link_libraries("networkextension" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-ios/OpenVPNAdapter.framework")
+set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rd/OpenVPNAdapter/build/Release-iphoneos)
+target_link_libraries("networkextension" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/3rd/OpenVPNAdapter/build/Release-iphoneos/OpenVPNAdapter.framework")
diff --git a/client/cmake/sources.cmake b/client/cmake/sources.cmake
deleted file mode 100644
index c3af531a..00000000
--- a/client/cmake/sources.cmake
+++ /dev/null
@@ -1,191 +0,0 @@
-set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
-
-set(HEADERS ${HEADERS}
- ${CLIENT_ROOT_DIR}/migrations.h
- ${CLIENT_ROOT_DIR}/../ipc/ipc.h
- ${CLIENT_ROOT_DIR}/amnezia_application.h
- ${CLIENT_ROOT_DIR}/containers/containers_defs.h
- ${CLIENT_ROOT_DIR}/core/defs.h
- ${CLIENT_ROOT_DIR}/core/errorstrings.h
- ${CLIENT_ROOT_DIR}/core/scripts_registry.h
- ${CLIENT_ROOT_DIR}/core/server_defs.h
- ${CLIENT_ROOT_DIR}/core/api/apiDefs.h
- ${CLIENT_ROOT_DIR}/core/qrCodeUtils.h
- ${CLIENT_ROOT_DIR}/core/controllers/coreController.h
- ${CLIENT_ROOT_DIR}/core/controllers/gatewayController.h
- ${CLIENT_ROOT_DIR}/core/controllers/serverController.h
- ${CLIENT_ROOT_DIR}/core/controllers/vpnConfigurationController.h
- ${CLIENT_ROOT_DIR}/protocols/protocols_defs.h
- ${CLIENT_ROOT_DIR}/protocols/qml_register_protocols.h
- ${CLIENT_ROOT_DIR}/ui/pages.h
- ${CLIENT_ROOT_DIR}/ui/qautostart.h
- ${CLIENT_ROOT_DIR}/protocols/vpnprotocol.h
- ${CMAKE_CURRENT_BINARY_DIR}/version.h
- ${CLIENT_ROOT_DIR}/core/sshclient.h
- ${CLIENT_ROOT_DIR}/core/networkUtilities.h
- ${CLIENT_ROOT_DIR}/core/serialization/serialization.h
- ${CLIENT_ROOT_DIR}/core/serialization/transfer.h
- ${CLIENT_ROOT_DIR}/../common/logger/logger.h
- ${CLIENT_ROOT_DIR}/utils/qmlUtils.h
- ${CLIENT_ROOT_DIR}/core/api/apiUtils.h
-)
-
-# Mozilla headres
-set(HEADERS ${HEADERS}
- ${CLIENT_ROOT_DIR}/mozilla/models/server.h
- ${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.h
- ${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.h
- ${CLIENT_ROOT_DIR}/mozilla/controllerimpl.h
- ${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.h
-)
-
-if(NOT IOS)
- set(HEADERS ${HEADERS}
- ${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.h
- )
-endif()
-
-if(NOT ANDROID)
- set(HEADERS ${HEADERS}
- ${CLIENT_ROOT_DIR}/ui/notificationhandler.h
- )
-endif()
-
-set(SOURCES ${SOURCES}
- ${CLIENT_ROOT_DIR}/migrations.cpp
- ${CLIENT_ROOT_DIR}/amnezia_application.cpp
- ${CLIENT_ROOT_DIR}/containers/containers_defs.cpp
- ${CLIENT_ROOT_DIR}/core/errorstrings.cpp
- ${CLIENT_ROOT_DIR}/core/scripts_registry.cpp
- ${CLIENT_ROOT_DIR}/core/server_defs.cpp
- ${CLIENT_ROOT_DIR}/core/qrCodeUtils.cpp
- ${CLIENT_ROOT_DIR}/core/controllers/coreController.cpp
- ${CLIENT_ROOT_DIR}/core/controllers/gatewayController.cpp
- ${CLIENT_ROOT_DIR}/core/controllers/serverController.cpp
- ${CLIENT_ROOT_DIR}/core/controllers/vpnConfigurationController.cpp
- ${CLIENT_ROOT_DIR}/protocols/protocols_defs.cpp
- ${CLIENT_ROOT_DIR}/ui/qautostart.cpp
- ${CLIENT_ROOT_DIR}/protocols/vpnprotocol.cpp
- ${CLIENT_ROOT_DIR}/core/sshclient.cpp
- ${CLIENT_ROOT_DIR}/core/networkUtilities.cpp
- ${CLIENT_ROOT_DIR}/core/serialization/outbound.cpp
- ${CLIENT_ROOT_DIR}/core/serialization/inbound.cpp
- ${CLIENT_ROOT_DIR}/core/serialization/ss.cpp
- ${CLIENT_ROOT_DIR}/core/serialization/ssd.cpp
- ${CLIENT_ROOT_DIR}/core/serialization/vless.cpp
- ${CLIENT_ROOT_DIR}/core/serialization/trojan.cpp
- ${CLIENT_ROOT_DIR}/core/serialization/vmess.cpp
- ${CLIENT_ROOT_DIR}/core/serialization/vmess_new.cpp
- ${CLIENT_ROOT_DIR}/../common/logger/logger.cpp
- ${CLIENT_ROOT_DIR}/utils/qmlUtils.cpp
- ${CLIENT_ROOT_DIR}/core/api/apiUtils.cpp
-)
-
-# Mozilla sources
-set(SOURCES ${SOURCES}
- ${CLIENT_ROOT_DIR}/mozilla/models/server.cpp
- ${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.cpp
- ${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.cpp
- ${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
-)
-
-if(NOT IOS)
- set(SOURCES ${SOURCES}
- ${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.cpp
- )
-endif()
-
-if(NOT ANDROID)
- set(SOURCES ${SOURCES}
- ${CLIENT_ROOT_DIR}/ui/notificationhandler.cpp
- )
-endif()
-
-file(GLOB COMMON_FILES_H CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/*.h)
-file(GLOB COMMON_FILES_CPP CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/*.cpp)
-
-file(GLOB_RECURSE PAGE_LOGIC_H CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/ui/pages_logic/*.h)
-file(GLOB_RECURSE PAGE_LOGIC_CPP CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/ui/pages_logic/*.cpp)
-
-file(GLOB CONFIGURATORS_H CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/configurators/*.h)
-file(GLOB CONFIGURATORS_CPP CONFIGURE_DEPENDS ${CLIENT_ROOT_DIR}/configurators/*.cpp)
-
-file(GLOB UI_MODELS_H CONFIGURE_DEPENDS
- ${CLIENT_ROOT_DIR}/ui/models/*.h
- ${CLIENT_ROOT_DIR}/ui/models/protocols/*.h
- ${CLIENT_ROOT_DIR}/ui/models/services/*.h
- ${CLIENT_ROOT_DIR}/ui/models/api/*.h
-)
-file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
- ${CLIENT_ROOT_DIR}/ui/models/*.cpp
- ${CLIENT_ROOT_DIR}/ui/models/protocols/*.cpp
- ${CLIENT_ROOT_DIR}/ui/models/services/*.cpp
- ${CLIENT_ROOT_DIR}/ui/models/api/*.cpp
-)
-
-file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS
- ${CLIENT_ROOT_DIR}/ui/controllers/*.h
- ${CLIENT_ROOT_DIR}/ui/controllers/api/*.h
-)
-file(GLOB UI_CONTROLLERS_CPP CONFIGURE_DEPENDS
- ${CLIENT_ROOT_DIR}/ui/controllers/*.cpp
- ${CLIENT_ROOT_DIR}/ui/controllers/api/*.cpp
-)
-
-set(HEADERS ${HEADERS}
- ${COMMON_FILES_H}
- ${PAGE_LOGIC_H}
- ${CONFIGURATORS_H}
- ${UI_MODELS_H}
- ${UI_CONTROLLERS_H}
-)
-set(SOURCES ${SOURCES}
- ${COMMON_FILES_CPP}
- ${PAGE_LOGIC_CPP}
- ${CONFIGURATORS_CPP}
- ${UI_MODELS_CPP}
- ${UI_CONTROLLERS_CPP}
-)
-
-if(WIN32)
- set(HEADERS ${HEADERS}
- ${CLIENT_ROOT_DIR}/protocols/ikev2_vpn_protocol_windows.h
- )
-
- set(SOURCES ${SOURCES}
- ${CLIENT_ROOT_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
- )
-
- set(RESOURCES ${RESOURCES}
- ${CMAKE_CURRENT_BINARY_DIR}/amneziavpn.rc
- )
-endif()
-
-if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
- message("Client desktop build")
- add_compile_definitions(AMNEZIA_DESKTOP)
-
- set(HEADERS ${HEADERS}
- ${CLIENT_ROOT_DIR}/core/ipcclient.h
- ${CLIENT_ROOT_DIR}/core/privileged_process.h
- ${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.h
- ${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.h
- ${CLIENT_ROOT_DIR}/protocols/openvpnovercloakprotocol.h
- ${CLIENT_ROOT_DIR}/protocols/shadowsocksvpnprotocol.h
- ${CLIENT_ROOT_DIR}/protocols/wireguardprotocol.h
- ${CLIENT_ROOT_DIR}/protocols/xrayprotocol.h
- ${CLIENT_ROOT_DIR}/protocols/awgprotocol.h
- )
-
- set(SOURCES ${SOURCES}
- ${CLIENT_ROOT_DIR}/core/ipcclient.cpp
- ${CLIENT_ROOT_DIR}/core/privileged_process.cpp
- ${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.cpp
- ${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.cpp
- ${CLIENT_ROOT_DIR}/protocols/openvpnovercloakprotocol.cpp
- ${CLIENT_ROOT_DIR}/protocols/shadowsocksvpnprotocol.cpp
- ${CLIENT_ROOT_DIR}/protocols/wireguardprotocol.cpp
- ${CLIENT_ROOT_DIR}/protocols/xrayprotocol.cpp
- ${CLIENT_ROOT_DIR}/protocols/awgprotocol.cpp
- )
-endif()
diff --git a/client/configurators/awg_configurator.cpp b/client/configurators/awg_configurator.cpp
index f83acb19..21b61ba4 100644
--- a/client/configurators/awg_configurator.cpp
+++ b/client/configurators/awg_configurator.cpp
@@ -1,5 +1,4 @@
#include "awg_configurator.h"
-#include "protocols/protocols_defs.h"
#include
#include
@@ -40,20 +39,6 @@ QString AwgConfigurator::createConfig(const ServerCredentials &credentials, Dock
jsonConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
jsonConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
jsonConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
-
- // jsonConfig[config_key::cookieReplyPacketJunkSize] = configMap.value(config_key::cookieReplyPacketJunkSize);
- // jsonConfig[config_key::transportPacketJunkSize] = configMap.value(config_key::transportPacketJunkSize);
-
- // jsonConfig[config_key::specialJunk1] = configMap.value(amnezia::config_key::specialJunk1);
- // jsonConfig[config_key::specialJunk2] = configMap.value(amnezia::config_key::specialJunk2);
- // jsonConfig[config_key::specialJunk3] = configMap.value(amnezia::config_key::specialJunk3);
- // jsonConfig[config_key::specialJunk4] = configMap.value(amnezia::config_key::specialJunk4);
- // jsonConfig[config_key::specialJunk5] = configMap.value(amnezia::config_key::specialJunk5);
- // jsonConfig[config_key::controlledJunk1] = configMap.value(amnezia::config_key::controlledJunk1);
- // jsonConfig[config_key::controlledJunk2] = configMap.value(amnezia::config_key::controlledJunk2);
- // jsonConfig[config_key::controlledJunk3] = configMap.value(amnezia::config_key::controlledJunk3);
- // jsonConfig[config_key::specialHandshakeTimeout] = configMap.value(amnezia::config_key::specialHandshakeTimeout);
-
jsonConfig[config_key::mtu] =
containerConfig.value(ProtocolProps::protoToString(Proto::Awg)).toObject().value(config_key::mtu).toString(protocols::awg::defaultMtu);
diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp
index f6996320..fafb7c2b 100644
--- a/client/configurators/openvpn_configurator.cpp
+++ b/client/configurators/openvpn_configurator.cpp
@@ -13,10 +13,10 @@
#include
#endif
-#include "core/networkUtilities.h"
#include "containers/containers_defs.h"
#include "core/controllers/serverController.h"
#include "core/scripts_registry.h"
+#include "core/server_defs.h"
#include "settings.h"
#include "utilities.h"
@@ -24,7 +24,6 @@
#include
#include
-
OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr settings, const QSharedPointer &serverController,
QObject *parent)
: ConfiguratorBase(settings, serverController, parent)
@@ -118,22 +117,22 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPairisSitesSplitTunnelingEnabled()) {
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
+
+#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
+ // Prevent ipv6 leak
+ config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
+#endif
config.append("block-ipv6\n");
} else if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
- // no redirect-gateway
+ // no redirect-gateway
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
// Prevent ipv6 leak
+ config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
#endif
config.append("block-ipv6\n");
}
@@ -167,15 +166,10 @@ QString OpenVpnConfigurator::processConfigWithExportSettings(const QPair
#include
#include
-#include
#include
#include
#include
@@ -20,17 +19,13 @@
#include "settings.h"
#include "utilities.h"
-WireguardConfigurator::WireguardConfigurator(std::shared_ptr settings,
- const QSharedPointer &serverController, bool isAwg,
- QObject *parent)
+WireguardConfigurator::WireguardConfigurator(std::shared_ptr settings, const QSharedPointer &serverController,
+ bool isAwg, QObject *parent)
: ConfiguratorBase(settings, serverController, parent), m_isAwg(isAwg)
{
- m_serverConfigPath =
- m_isAwg ? amnezia::protocols::awg::serverConfigPath : amnezia::protocols::wireguard::serverConfigPath;
- m_serverPublicKeyPath =
- m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath : amnezia::protocols::wireguard::serverPublicKeyPath;
- m_serverPskKeyPath =
- m_isAwg ? amnezia::protocols::awg::serverPskKeyPath : amnezia::protocols::wireguard::serverPskKeyPath;
+ m_serverConfigPath = m_isAwg ? amnezia::protocols::awg::serverConfigPath : amnezia::protocols::wireguard::serverConfigPath;
+ m_serverPublicKeyPath = m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath : amnezia::protocols::wireguard::serverPublicKeyPath;
+ m_serverPskKeyPath = m_isAwg ? amnezia::protocols::awg::serverPskKeyPath : amnezia::protocols::wireguard::serverPskKeyPath;
m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template : ProtocolScriptType::wireguard_template;
m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard;
@@ -68,31 +63,9 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
return connData;
}
-QList WireguardConfigurator::getIpsFromConf(const QString &input)
-{
- QRegularExpression regex("AllowedIPs = (\\d+\\.\\d+\\.\\d+\\.\\d+)");
- QRegularExpressionMatchIterator matchIterator = regex.globalMatch(input);
-
- QList ips;
-
- while (matchIterator.hasNext()) {
- QRegularExpressionMatch match = matchIterator.next();
- const QString address_string { match.captured(1) };
- const QHostAddress address { address_string };
- if (address.isNull()) {
- qWarning() << "Couldn't recognize the ip address: " << address_string;
- } else {
- ips << address;
- }
- }
-
- return ips;
-}
-
WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials,
DockerContainer container,
- const QJsonObject &containerConfig,
- ErrorCode &errorCode)
+ const QJsonObject &containerConfig, ErrorCode &errorCode)
{
WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys();
connData.host = credentials.hostName;
@@ -103,45 +76,65 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
return connData;
}
- QString getIpsScript = QString("cat %1 | grep AllowedIPs").arg(m_serverConfigPath);
- QString stdOut;
- auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
- stdOut += data + "\n";
- return ErrorCode::NoError;
- };
+ // Get list of already created clients (only IP addresses)
+ QString nextIpNumber;
+ {
+ QString script = QString("cat %1 | grep AllowedIPs").arg(m_serverConfigPath);
+ QString stdOut;
+ auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
+ stdOut += data + "\n";
+ return ErrorCode::NoError;
+ };
- errorCode = m_serverController->runContainerScript(credentials, container, getIpsScript, cbReadStdOut);
- if (errorCode != ErrorCode::NoError) {
- return connData;
- }
- auto ips = getIpsFromConf(stdOut);
+ errorCode = m_serverController->runContainerScript(credentials, container, script, cbReadStdOut);
+ if (errorCode != ErrorCode::NoError) {
+ return connData;
+ }
- QHostAddress nextIp = [&] {
- QHostAddress result;
- QHostAddress lastIp;
- if (ips.empty()) {
- lastIp.setAddress(containerConfig.value(m_protocolName)
- .toObject()
- .value(config_key::subnet_address)
- .toString(protocols::wireguard::defaultSubnetAddress));
+ stdOut.replace("AllowedIPs = ", "");
+ stdOut.replace("/32", "");
+ QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts);
+
+ // remove extra IPs from each line for case when user manually edited the wg0.conf
+ // and added there more IPs for route his itnernal networks, like:
+ // ...
+ // AllowedIPs = 10.8.1.6/32, 192.168.1.0/24, 192.168.2.0/24, ...
+ // ...
+ // without this code - next IP would be 1 if last item in 'ips' has format above
+ QStringList vpnIps;
+ for (const auto &ip : ips) {
+ vpnIps.append(ip.split(",", Qt::SkipEmptyParts).first().trimmed());
+ }
+ ips = vpnIps;
+
+ // Calc next IP address
+ if (ips.isEmpty()) {
+ nextIpNumber = "2";
} else {
- lastIp = ips.last();
+ int next = ips.last().split(".").last().toInt() + 1;
+ if (next > 254) {
+ errorCode = ErrorCode::AddressPoolError;
+ return connData;
+ }
+ nextIpNumber = QString::number(next);
}
- quint8 lastOctet = static_cast(lastIp.toIPv4Address());
- switch (lastOctet) {
- case 254: result.setAddress(lastIp.toIPv4Address() + 3); break;
- case 255: result.setAddress(lastIp.toIPv4Address() + 2); break;
- default: result.setAddress(lastIp.toIPv4Address() + 1); break;
+ }
+
+ QString subnetIp = containerConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
+ {
+ QStringList l = subnetIp.split(".", Qt::SkipEmptyParts);
+ if (l.isEmpty()) {
+ errorCode = ErrorCode::AddressPoolError;
+ return connData;
}
+ l.removeLast();
+ l.append(nextIpNumber);
- return result;
- }();
-
- connData.clientIP = nextIp.toString();
+ connData.clientIP = l.join(".");
+ }
// Get keys
- connData.serverPubKey =
- m_serverController->getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, errorCode);
+ connData.serverPubKey = m_serverController->getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, errorCode);
connData.serverPubKey.replace("\n", "");
if (errorCode != ErrorCode::NoError) {
return connData;
@@ -168,12 +161,10 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
return connData;
}
- QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'")
- .arg(m_serverConfigPath);
+ QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'").arg(m_serverConfigPath);
errorCode = m_serverController->runScript(
- credentials,
- m_serverController->replaceVars(script, m_serverController->genVarsForScript(credentials, container)));
+ credentials, m_serverController->replaceVars(script, m_serverController->genVarsForScript(credentials, container)));
return connData;
}
@@ -182,8 +173,8 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials
const QJsonObject &containerConfig, ErrorCode &errorCode)
{
QString scriptData = amnezia::scriptData(m_configTemplate, container);
- QString config = m_serverController->replaceVars(
- scriptData, m_serverController->genVarsForScript(credentials, container, containerConfig));
+ QString config =
+ m_serverController->replaceVars(scriptData, m_serverController->genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode);
if (errorCode != ErrorCode::NoError) {
@@ -217,16 +208,16 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials
return QJsonDocument(jConfig).toJson();
}
-QString WireguardConfigurator::processConfigWithLocalSettings(const QPair &dns,
- const bool isApiConfig, QString &protocolConfigString)
+QString WireguardConfigurator::processConfigWithLocalSettings(const QPair &dns, const bool isApiConfig,
+ QString &protocolConfigString)
{
processConfigWithDnsSettings(dns, protocolConfigString);
return protocolConfigString;
}
-QString WireguardConfigurator::processConfigWithExportSettings(const QPair &dns,
- const bool isApiConfig, QString &protocolConfigString)
+QString WireguardConfigurator::processConfigWithExportSettings(const QPair &dns, const bool isApiConfig,
+ QString &protocolConfigString)
{
processConfigWithDnsSettings(dns, protocolConfigString);
diff --git a/client/configurators/wireguard_configurator.h b/client/configurators/wireguard_configurator.h
index a4302e3e..22e8a8be 100644
--- a/client/configurators/wireguard_configurator.h
+++ b/client/configurators/wireguard_configurator.h
@@ -1,7 +1,6 @@
#ifndef WIREGUARD_CONFIGURATOR_H
#define WIREGUARD_CONFIGURATOR_H
-#include
#include
#include
@@ -13,8 +12,8 @@ class WireguardConfigurator : public ConfiguratorBase
{
Q_OBJECT
public:
- WireguardConfigurator(std::shared_ptr settings, const QSharedPointer &serverController,
- bool isAwg, QObject *parent = nullptr);
+ WireguardConfigurator(std::shared_ptr settings, const QSharedPointer &serverController, bool isAwg,
+ QObject *parent = nullptr);
struct ConnectionData
{
@@ -27,18 +26,15 @@ public:
QString port;
};
- QString createConfig(const ServerCredentials &credentials, DockerContainer container,
- const QJsonObject &containerConfig, ErrorCode &errorCode);
+ QString createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
+ ErrorCode &errorCode);
- QString processConfigWithLocalSettings(const QPair &dns, const bool isApiConfig,
- QString &protocolConfigString);
- QString processConfigWithExportSettings(const QPair &dns, const bool isApiConfig,
- QString &protocolConfigString);
+ QString processConfigWithLocalSettings(const QPair &dns, const bool isApiConfig, QString &protocolConfigString);
+ QString processConfigWithExportSettings(const QPair &dns, const bool isApiConfig, QString &protocolConfigString);
static ConnectionData genClientKeys();
private:
- QList getIpsFromConf(const QString &input);
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode &errorCode);
diff --git a/client/containers/containers_defs.cpp b/client/containers/containers_defs.cpp
index 214e2a51..ce673a85 100644
--- a/client/containers/containers_defs.cpp
+++ b/client/containers/containers_defs.cpp
@@ -110,19 +110,22 @@ QMap ContainerProps::containerDescriptions()
QObject::tr("OpenVPN is the most popular VPN protocol, with flexible configuration options. It uses its "
"own security protocol with SSL/TLS for key exchange.") },
{ DockerContainer::ShadowSocks,
- QObject::tr("Shadowsocks masks VPN traffic, making it resemble normal web traffic, but it may still be detected by certain analysis systems.") },
+ QObject::tr("Shadowsocks - masks VPN traffic, making it similar to normal web traffic, but it "
+ "may be recognized by analysis systems in some highly censored regions.") },
{ DockerContainer::Cloak,
QObject::tr("OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against "
- "active-probing detection. It is very resistant to detection, but offers low speed.") },
+ "active-probing detection. Ideal for bypassing blocking in regions with the highest levels "
+ "of censorship.") },
{ DockerContainer::WireGuard,
- QObject::tr("WireGuard - popular VPN protocol with high performance, high speed and low power "
- "consumption.") },
+ QObject::tr("WireGuard - New popular VPN protocol with high performance, high speed and low power "
+ "consumption. Recommended for regions with low levels of censorship.") },
{ DockerContainer::Awg,
- QObject::tr("AmneziaWG is a special protocol from Amnezia based on WireGuard. "
- "It provides high connection speed and ensures stable operation even in the most challenging network conditions.") },
+ QObject::tr("AmneziaWG - Special protocol from Amnezia, based on WireGuard. It's fast like WireGuard, "
+ "but very resistant to blockages. "
+ "Recommended for regions with high levels of censorship.") },
{ DockerContainer::Xray,
- QObject::tr("XRay with REALITY masks VPN traffic as web traffic and protects against active probing. "
- "It is highly resistant to detection and offers high speed.") },
+ QObject::tr("XRay with REALITY - Suitable for countries with the highest level of internet censorship. "
+ "Traffic masking as web traffic at the TLS level, and protection against detection by active probing methods.") },
{ DockerContainer::Ipsec,
QObject::tr("IKEv2/IPsec - Modern stable protocol, a bit faster than others, restores connection after "
"signal loss. It has native support on the latest versions of Android and iOS.") },
@@ -140,83 +143,100 @@ QMap ContainerProps::containerDetailedDescriptions()
{
return {
{ DockerContainer::OpenVpn,
- QObject::tr("OpenVPN is one of the most popular and reliable VPN protocols. "
- "It uses SSL/TLS encryption, supports a wide variety of devices and operating systems, "
- "and is continuously improved by the community due to its open-source nature. "
- "It provides a good balance between speed and security but is easily recognized by DPI systems, "
- "making it susceptible to blocking.\n"
- "\nFeatures:\n"
- "* Available on all AmneziaVPN platforms\n"
- "* Normal battery consumption on mobile devices\n"
- "* Flexible customization for various devices and OS\n"
- "* Operates over both TCP and UDP protocols") },
+ QObject::tr(
+ "OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
+ "It employs its unique security protocol, "
+ "leveraging the strength of SSL/TLS for encryption and key exchange. "
+ "Furthermore, OpenVPN's support for a multitude of authentication methods makes it versatile and adaptable, "
+ "catering to a wide range of devices and operating systems. "
+ "Due to its open-source nature, OpenVPN benefits from extensive scrutiny by the global community, "
+ "which continually reinforces its security. "
+ "With a strong balance of performance, security, and compatibility, "
+ "OpenVPN remains a top choice for privacy-conscious individuals and businesses alike.\n\n"
+ "* Available in the AmneziaVPN across all platforms\n"
+ "* Normal power consumption on mobile devices\n"
+ "* Flexible customisation to suit user needs to work with different operating systems and devices\n"
+ "* Recognised by DPI analysis systems and therefore susceptible to blocking\n"
+ "* Can operate over both TCP and UDP network protocols.") },
{ DockerContainer::ShadowSocks,
- QObject::tr("Shadowsocks is based on the SOCKS5 protocol and encrypts connections using AEAD cipher. "
- "Although designed to be discreet, it doesn't mimic a standard HTTPS connection and can be detected by some DPI systems. "
- "Due to limited support in Amnezia, we recommend using the AmneziaWG protocol.\n"
- "\nFeatures:\n"
- "* Available in AmneziaVPN only on desktop platforms\n"
- "* Customizable encryption protocol\n"
+ QObject::tr("Shadowsocks, inspired by the SOCKS5 protocol, safeguards the connection using the AEAD cipher. "
+ "Although Shadowsocks is designed to be discreet and challenging to identify, it isn't identical to a standard HTTPS connection."
+ "However, certain traffic analysis systems might still detect a Shadowsocks connection. "
+ "Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n"
+ "* Available in the AmneziaVPN only on desktop platforms\n"
+ "* Configurable encryption protocol\n"
"* Detectable by some DPI systems\n"
- "* Operates over TCP protocol\n") },
+ "* Works over TCP network protocol.") },
{ DockerContainer::Cloak,
- QObject::tr("This combination includes the OpenVPN protocol and the Cloak plugin, specifically designed to protect against blocking.\n"
- "\nOpenVPN securely encrypts all internet traffic between your device and the server.\n"
- "\nThe Cloak plugin further protects the connection from DPI detection. "
- "It modifies traffic metadata to disguise VPN traffic as regular web traffic and prevents detection through active probing. "
- "If an incoming connection fails authentication, Cloak serves a fake website, making your VPN invisible to traffic analysis systems.\n"
- "\nIn regions with heavy internet censorship, we strongly recommend using OpenVPN with Cloak from your first connection.\n"
- "\nFeatures:\n"
- "* Available on all AmneziaVPN platforms\n"
+ QObject::tr("This is a combination of the OpenVPN protocol and the Cloak plugin designed specifically for "
+ "protecting against blocking.\n\n"
+ "OpenVPN provides a secure VPN connection by encrypting all internet traffic between the client "
+ "and the server.\n\n"
+ "Cloak protects OpenVPN from detection and blocking. \n\n"
+ "Cloak can modify packet metadata so that it completely masks VPN traffic as normal web traffic, "
+ "and also protects the VPN from detection by Active Probing. This makes it very resistant to "
+ "being detected\n\n"
+ "Immediately after receiving the first data packet, Cloak authenticates the incoming connection. "
+ "If authentication fails, the plugin masks the server as a fake website and your VPN becomes "
+ "invisible to analysis systems.\n\n"
+ "If there is a extreme level of Internet censorship in your region, we advise you to use only "
+ "OpenVPN over Cloak from the first connection\n\n"
+ "* Available in the AmneziaVPN across all platforms\n"
"* High power consumption on mobile devices\n"
- "* Flexible configuration options\n"
- "* Undetectable by DPI systems\n"
- "* Operates over TCP protocol on port 443") },
+ "* Flexible settings\n"
+ "* Not recognised by DPI analysis systems\n"
+ "* Works over TCP network protocol, 443 port.\n") },
{ DockerContainer::WireGuard,
- QObject::tr("WireGuard is a modern, streamlined VPN protocol offering stable connectivity and excellent performance across all devices. "
- "It uses fixed encryption settings, delivering lower latency and higher data transfer speeds compared to OpenVPN. "
- "However, WireGuard is easily identifiable by DPI systems due to its distinctive packet signatures, making it susceptible to blocking.\n"
- "\nFeatures:\n"
- "* Available on all AmneziaVPN platforms\n"
- "* Low power consumption on mobile devices\n"
- "* Minimal configuration required\n"
- "* Easily detected by DPI systems (susceptible to blocking)\n"
- "* Operates over UDP protocol") },
+ QObject::tr("A relatively new popular VPN protocol with a simplified architecture.\n"
+ "WireGuard provides stable VPN connection and high performance on all devices. It uses hard-coded encryption "
+ "settings. WireGuard compared to OpenVPN has lower latency and better data transfer throughput.\n"
+ "WireGuard is very susceptible to blocking due to its distinct packet signatures. "
+ "Unlike some other VPN protocols that employ obfuscation techniques, "
+ "the consistent signature patterns of WireGuard packets can be more easily identified and "
+ "thus blocked by advanced Deep Packet Inspection (DPI) systems and other network monitoring tools.\n\n"
+ "* Available in the AmneziaVPN across all platforms\n"
+ "* Low power consumption\n"
+ "* Minimum number of settings\n"
+ "* Easily recognised by DPI analysis systems, susceptible to blocking\n"
+ "* Works over UDP network protocol.") },
{ DockerContainer::Awg,
- QObject::tr("AmneziaWG is a modern VPN protocol based on WireGuard, "
- "combining simplified architecture with high performance across all devices. "
- "It addresses WireGuard's main vulnerability (easy detection by DPI systems) through advanced obfuscation techniques, "
- "making VPN traffic indistinguishable from regular internet traffic.\n"
- "\nAmneziaWG is an excellent choice for those seeking a fast, stealthy VPN connection.\n"
- "\nFeatures:\n"
- "* Available on all AmneziaVPN platforms\n"
- "* Low battery consumption on mobile devices\n"
- "* Minimal settings required\n"
- "* Undetectable by traffic analysis systems (DPI)\n"
- "* Operates over UDP protocol") },
+ QObject::tr("A modern iteration of the popular VPN protocol, "
+ "AmneziaWG builds upon the foundation set by WireGuard, "
+ "retaining its simplified architecture and high-performance capabilities across devices.\n"
+ "While WireGuard is known for its efficiency, "
+ "it had issues with being easily detected due to its distinct packet signatures. "
+ "AmneziaWG solves this problem by using better obfuscation methods, "
+ "making its traffic blend in with regular internet traffic.\n"
+ "This means that AmneziaWG keeps the fast performance of the original "
+ "while adding an extra layer of stealth, "
+ "making it a great choice for those wanting a fast and discreet VPN connection.\n\n"
+ "* Available in the AmneziaVPN across all platforms\n"
+ "* Low power consumption\n"
+ "* Minimum number of settings\n"
+ "* Not recognised by DPI analysis systems, resistant to blocking\n"
+ "* Works over UDP network protocol.") },
{ DockerContainer::Xray,
- QObject::tr("REALITY is an innovative protocol developed by the creators of XRay, designed specifically to combat high levels of internet censorship. "
- "REALITY identifies censorship systems during the TLS handshake, "
- "redirecting suspicious traffic seamlessly to legitimate websites like google.com while providing genuine TLS certificates. "
- "This allows VPN traffic to blend indistinguishably with regular web traffic without special configuration."
- "\nUnlike older protocols such as VMess, VLESS, and XTLS-Vision, REALITY incorporates an advanced built-in \"friend-or-foe\" detection mechanism, "
- "effectively protecting against DPI and other traffic analysis methods.\n"
- "\nFeatures:\n"
- "* Resistant to active probing and DPI detection\n"
- "* No special configuration required to disguise traffic\n"
- "* Highly effective in heavily censored regions\n"
- "* Minimal battery consumption on devices\n"
- "* Operates over TCP protocol") },
+ QObject::tr("The REALITY protocol, a pioneering development by the creators of XRay, "
+ "is specifically designed to counteract the highest levels of internet censorship through its novel approach to evasion.\n"
+ "It uniquely identifies censors during the TLS handshake phase, seamlessly operating as a proxy for legitimate clients while diverting censors to genuine websites like google.com, "
+ "thus presenting an authentic TLS certificate and data. \n"
+ "This advanced capability differentiates REALITY from similar technologies by its ability to disguise web traffic as coming from random, "
+ "legitimate sites without the need for specific configurations. \n"
+ "Unlike older protocols such as VMess, VLESS, and the XTLS-Vision transport, "
+ "REALITY's innovative \"friend or foe\" recognition at the TLS handshake enhances security and circumvents detection by sophisticated DPI systems employing active probing techniques. "
+ "This makes REALITY a robust solution for maintaining internet freedom in environments with stringent censorship.")
+ },
{ DockerContainer::Ipsec,
- QObject::tr("IKEv2, combined with IPSec encryption, is a modern and reliable VPN protocol. "
- "It reconnects quickly when switching networks or devices, making it ideal for dynamic network environments. "
- "While it provides good security and speed, it's easily recognized by DPI systems and susceptible to blocking.\n"
- "\nFeatures:\n"
- "* Available in AmneziaVPN only on Windows\n"
- "* Low battery consumption on mobile devices\n"
- "* Minimal configuration required\n"
- "* Detectable by DPI analysis systems(easily blocked)\n"
- "* Operates over UDP protocol(ports 500 and 4500)") },
+ QObject::tr("IKEv2, paired with the IPSec encryption layer, stands as a modern and stable VPN protocol.\n"
+ "One of its distinguishing features is its ability to swiftly switch between networks and devices, "
+ "making it particularly adaptive in dynamic network environments. \n"
+ "While it offers a blend of security, stability, and speed, "
+ "it's essential to note that IKEv2 can be easily detected and is susceptible to blocking.\n\n"
+ "* Available in the AmneziaVPN only on Windows\n"
+ "* Low power consumption, on mobile devices\n"
+ "* Minimal configuration\n"
+ "* Recognised by DPI analysis systems\n"
+ "* Works over UDP network protocol, ports 500 and 4500.") },
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("DNS Service") },
@@ -312,7 +332,9 @@ QStringList ContainerProps::fixedPortsForContainer(DockerContainer c)
bool ContainerProps::isEasySetupContainer(DockerContainer container)
{
switch (container) {
+ case DockerContainer::WireGuard: return true;
case DockerContainer::Awg: return true;
+ // case DockerContainer::Cloak: return true;
default: return false;
}
}
@@ -320,7 +342,9 @@ bool ContainerProps::isEasySetupContainer(DockerContainer container)
QString ContainerProps::easySetupHeader(DockerContainer container)
{
switch (container) {
- case DockerContainer::Awg: return tr("Automatic");
+ case DockerContainer::WireGuard: return tr("Low");
+ case DockerContainer::Awg: return tr("High");
+ // case DockerContainer::Cloak: return tr("Extreme");
default: return "";
}
}
@@ -328,8 +352,10 @@ QString ContainerProps::easySetupHeader(DockerContainer container)
QString ContainerProps::easySetupDescription(DockerContainer container)
{
switch (container) {
- case DockerContainer::Awg: return tr("AmneziaWG protocol will be installed. "
- "It provides high connection speed and ensures stable operation even in the most challenging network conditions.");
+ case DockerContainer::WireGuard: return tr("I just want to increase the level of my privacy.");
+ case DockerContainer::Awg: return tr("I want to bypass censorship. This option recommended in most cases.");
+ // case DockerContainer::Cloak:
+ // return tr("Most VPN protocols are blocked. Recommended if other options are not working.");
default: return "";
}
}
@@ -337,7 +363,9 @@ QString ContainerProps::easySetupDescription(DockerContainer container)
int ContainerProps::easySetupOrder(DockerContainer container)
{
switch (container) {
- case DockerContainer::Awg: return 1;
+ case DockerContainer::WireGuard: return 3;
+ case DockerContainer::Awg: return 2;
+ // case DockerContainer::Cloak: return 1;
default: return 0;
}
}
@@ -356,9 +384,9 @@ bool ContainerProps::isShareable(DockerContainer container)
QJsonObject ContainerProps::getProtocolConfigFromContainer(const Proto protocol, const QJsonObject &containerConfig)
{
QString protocolConfigString = containerConfig.value(ProtocolProps::protoToString(protocol))
- .toObject()
- .value(config_key::last_config)
- .toString();
+ .toObject()
+ .value(config_key::last_config)
+ .toString();
return QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
}
diff --git a/client/core/api/apiDefs.h b/client/core/api/apiDefs.h
deleted file mode 100644
index 12c8051f..00000000
--- a/client/core/api/apiDefs.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef APIDEFS_H
-#define APIDEFS_H
-
-#include
-
-namespace apiDefs
-{
- enum ConfigType {
- AmneziaFreeV2 = 0,
- AmneziaFreeV3,
- AmneziaPremiumV1,
- AmneziaPremiumV2,
- SelfHosted,
- ExternalPremium
- };
-
- enum ConfigSource {
- Telegram = 1,
- AmneziaGateway
- };
-
- namespace key
- {
- constexpr QLatin1String configVersion("config_version");
- constexpr QLatin1String apiEndpoint("api_endpoint");
- constexpr QLatin1String apiKey("api_key");
- constexpr QLatin1String description("description");
- constexpr QLatin1String name("name");
- constexpr QLatin1String protocol("protocol");
-
- constexpr QLatin1String apiConfig("api_config");
- constexpr QLatin1String stackType("stack_type");
- constexpr QLatin1String serviceType("service_type");
- constexpr QLatin1String cliVersion("cli_version");
- constexpr QLatin1String supportedProtocols("supported_protocols");
-
- constexpr QLatin1String vpnKey("vpn_key");
- constexpr QLatin1String config("config");
- constexpr QLatin1String configs("configs");
-
- constexpr QLatin1String installationUuid("installation_uuid");
- constexpr QLatin1String workerLastUpdated("worker_last_updated");
- constexpr QLatin1String lastDownloaded("last_downloaded");
- constexpr QLatin1String sourceType("source_type");
-
- constexpr QLatin1String serverCountryCode("server_country_code");
- constexpr QLatin1String serverCountryName("server_country_name");
-
- constexpr QLatin1String osVersion("os_version");
-
- constexpr QLatin1String availableCountries("available_countries");
- constexpr QLatin1String activeDeviceCount("active_device_count");
- constexpr QLatin1String maxDeviceCount("max_device_count");
- constexpr QLatin1String subscriptionEndDate("subscription_end_date");
- constexpr QLatin1String issuedConfigs("issued_configs");
-
- constexpr QLatin1String supportInfo("support_info");
- constexpr QLatin1String email("email");
- constexpr QLatin1String billingEmail("billing_email");
- constexpr QLatin1String website("website");
- constexpr QLatin1String websiteName("website_name");
- constexpr QLatin1String telegram("telegram");
-
- constexpr QLatin1String id("id");
- constexpr QLatin1String orderId("order_id");
- constexpr QLatin1String migrationCode("migration_code");
- }
-
- const int requestTimeoutMsecs = 12 * 1000; // 12 secs
-}
-
-#endif // APIDEFS_H
diff --git a/client/core/api/apiUtils.cpp b/client/core/api/apiUtils.cpp
deleted file mode 100644
index 7f3e6db3..00000000
--- a/client/core/api/apiUtils.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-#include "apiUtils.h"
-
-#include
-#include
-
-namespace
-{
- const QByteArray AMNEZIA_CONFIG_SIGNATURE = QByteArray::fromHex("000000ff");
-
- QString escapeUnicode(const QString &input)
- {
- QString output;
- for (QChar c : input) {
- if (c.unicode() < 0x20 || c.unicode() > 0x7E) {
- output += QString("\\u%1").arg(QString::number(c.unicode(), 16).rightJustified(4, '0'));
- } else {
- output += c;
- }
- }
- return output;
- }
-}
-
-bool apiUtils::isSubscriptionExpired(const QString &subscriptionEndDate)
-{
- QDateTime now = QDateTime::currentDateTime();
- QDateTime endDate = QDateTime::fromString(subscriptionEndDate, Qt::ISODateWithMs);
- return endDate < now;
-}
-
-bool apiUtils::isServerFromApi(const QJsonObject &serverConfigObject)
-{
- auto configVersion = serverConfigObject.value(apiDefs::key::configVersion).toInt();
- switch (configVersion) {
- case apiDefs::ConfigSource::Telegram: return true;
- case apiDefs::ConfigSource::AmneziaGateway: return true;
- default: return false;
- }
-}
-
-apiDefs::ConfigType apiUtils::getConfigType(const QJsonObject &serverConfigObject)
-{
- auto configVersion = serverConfigObject.value(apiDefs::key::configVersion).toInt();
-
- switch (configVersion) {
- case apiDefs::ConfigSource::Telegram: {
- constexpr QLatin1String freeV2Endpoint(FREE_V2_ENDPOINT);
- constexpr QLatin1String premiumV1Endpoint(PREM_V1_ENDPOINT);
-
- auto apiEndpoint = serverConfigObject.value(apiDefs::key::apiEndpoint).toString();
-
- if (apiEndpoint.contains(premiumV1Endpoint)) {
- return apiDefs::ConfigType::AmneziaPremiumV1;
- } else if (apiEndpoint.contains(freeV2Endpoint)) {
- return apiDefs::ConfigType::AmneziaFreeV2;
- }
- };
- case apiDefs::ConfigSource::AmneziaGateway: {
- constexpr QLatin1String servicePremium("amnezia-premium");
- constexpr QLatin1String serviceFree("amnezia-free");
- constexpr QLatin1String serviceExternalPremium("external-premium");
-
- auto apiConfigObject = serverConfigObject.value(apiDefs::key::apiConfig).toObject();
- auto serviceType = apiConfigObject.value(apiDefs::key::serviceType).toString();
-
- if (serviceType == servicePremium) {
- return apiDefs::ConfigType::AmneziaPremiumV2;
- } else if (serviceType == serviceFree) {
- return apiDefs::ConfigType::AmneziaFreeV3;
- } else if (serviceType == serviceExternalPremium) {
- return apiDefs::ConfigType::ExternalPremium;
- }
- }
- default: {
- return apiDefs::ConfigType::SelfHosted;
- }
- };
-}
-
-apiDefs::ConfigSource apiUtils::getConfigSource(const QJsonObject &serverConfigObject)
-{
- return static_cast(serverConfigObject.value(apiDefs::key::configVersion).toInt());
-}
-
-amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList &sslErrors, QNetworkReply *reply)
-{
- const int httpStatusCodeConflict = 409;
- const int httpStatusCodeNotFound = 404;
-
- if (!sslErrors.empty()) {
- qDebug().noquote() << sslErrors;
- return amnezia::ErrorCode::ApiConfigSslError;
- } else if (reply->error() == QNetworkReply::NoError) {
- return amnezia::ErrorCode::NoError;
- } else if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
- || reply->error() == QNetworkReply::NetworkError::TimeoutError) {
- qDebug() << reply->error();
- return amnezia::ErrorCode::ApiConfigTimeoutError;
- } else if (reply->error() == QNetworkReply::NetworkError::OperationNotImplementedError) {
- qDebug() << reply->error();
- return amnezia::ErrorCode::ApiUpdateRequestError;
- } else {
- QString err = reply->errorString();
- int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
- qDebug() << QString::fromUtf8(reply->readAll());
- qDebug() << reply->error();
- qDebug() << err;
- qDebug() << httpStatusCode;
- if (httpStatusCode == httpStatusCodeConflict) {
- return amnezia::ErrorCode::ApiConfigLimitError;
- } else if (httpStatusCode == httpStatusCodeNotFound) {
- return amnezia::ErrorCode::ApiNotFoundError;
- }
- return amnezia::ErrorCode::ApiConfigDownloadError;
- }
-
- qDebug() << "something went wrong";
- return amnezia::ErrorCode::InternalError;
-}
-
-bool apiUtils::isPremiumServer(const QJsonObject &serverConfigObject)
-{
- static const QSet premiumTypes = { apiDefs::ConfigType::AmneziaPremiumV1, apiDefs::ConfigType::AmneziaPremiumV2,
- apiDefs::ConfigType::ExternalPremium };
- return premiumTypes.contains(getConfigType(serverConfigObject));
-}
-
-QString apiUtils::getPremiumV1VpnKey(const QJsonObject &serverConfigObject)
-{
- if (apiUtils::getConfigType(serverConfigObject) != apiDefs::ConfigType::AmneziaPremiumV1) {
- return {};
- }
-
- QList> orderedFields;
- orderedFields.append(qMakePair(apiDefs::key::name, serverConfigObject[apiDefs::key::name].toString()));
- orderedFields.append(qMakePair(apiDefs::key::description, serverConfigObject[apiDefs::key::description].toString()));
- orderedFields.append(qMakePair(apiDefs::key::configVersion, serverConfigObject[apiDefs::key::configVersion].toDouble()));
- orderedFields.append(qMakePair(apiDefs::key::protocol, serverConfigObject[apiDefs::key::protocol].toString()));
- orderedFields.append(qMakePair(apiDefs::key::apiEndpoint, serverConfigObject[apiDefs::key::apiEndpoint].toString()));
- orderedFields.append(qMakePair(apiDefs::key::apiKey, serverConfigObject[apiDefs::key::apiKey].toString()));
-
- QString vpnKeyStr = "{";
- for (int i = 0; i < orderedFields.size(); ++i) {
- const auto &pair = orderedFields[i];
- if (pair.second.typeId() == QMetaType::Type::QString) {
- vpnKeyStr += "\"" + pair.first + "\": \"" + pair.second.toString() + "\"";
- } else if (pair.second.typeId() == QMetaType::Type::Double || pair.second.typeId() == QMetaType::Type::Int) {
- vpnKeyStr += "\"" + pair.first + "\": " + QString::number(pair.second.toDouble(), 'f', 1);
- }
-
- if (i < orderedFields.size() - 1) {
- vpnKeyStr += ", ";
- }
- }
- vpnKeyStr += "}";
-
- QByteArray vpnKeyCompressed = escapeUnicode(vpnKeyStr).toUtf8();
- vpnKeyCompressed = qCompress(vpnKeyCompressed, 6);
- vpnKeyCompressed = vpnKeyCompressed.mid(4);
-
- QByteArray signedData = AMNEZIA_CONFIG_SIGNATURE + vpnKeyCompressed;
-
- return QString("vpn://%1").arg(QString(signedData.toBase64(QByteArray::Base64UrlEncoding)));
-}
diff --git a/client/core/api/apiUtils.h b/client/core/api/apiUtils.h
deleted file mode 100644
index 45eaf2de..00000000
--- a/client/core/api/apiUtils.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef APIUTILS_H
-#define APIUTILS_H
-
-#include
-#include
-
-#include "apiDefs.h"
-#include "core/defs.h"
-
-namespace apiUtils
-{
- bool isServerFromApi(const QJsonObject &serverConfigObject);
-
- bool isSubscriptionExpired(const QString &subscriptionEndDate);
-
- bool isPremiumServer(const QJsonObject &serverConfigObject);
-
- apiDefs::ConfigType getConfigType(const QJsonObject &serverConfigObject);
- apiDefs::ConfigSource getConfigSource(const QJsonObject &serverConfigObject);
-
- amnezia::ErrorCode checkNetworkReplyErrors(const QList &sslErrors, QNetworkReply *reply);
-
- QString getPremiumV1VpnKey(const QJsonObject &serverConfigObject);
-}
-
-#endif // APIUTILS_H
diff --git a/client/core/controllers/apiController.cpp b/client/core/controllers/apiController.cpp
new file mode 100644
index 00000000..6562632a
--- /dev/null
+++ b/client/core/controllers/apiController.cpp
@@ -0,0 +1,509 @@
+#include "apiController.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "QBlockCipher.h"
+#include "QRsa.h"
+
+#include "amnezia_application.h"
+#include "configurators/wireguard_configurator.h"
+#include "core/enums/apiEnums.h"
+#include "utilities.h"
+#include "version.h"
+
+namespace
+{
+ namespace configKey
+ {
+ constexpr char cloak[] = "cloak";
+ constexpr char awg[] = "awg";
+
+ constexpr char apiEdnpoint[] = "api_endpoint";
+ constexpr char accessToken[] = "api_key";
+ constexpr char certificate[] = "certificate";
+ constexpr char publicKey[] = "public_key";
+ constexpr char protocol[] = "protocol";
+
+ constexpr char uuid[] = "installation_uuid";
+ constexpr char osVersion[] = "os_version";
+ constexpr char appVersion[] = "app_version";
+
+ constexpr char userCountryCode[] = "user_country_code";
+ constexpr char serverCountryCode[] = "server_country_code";
+ constexpr char serviceType[] = "service_type";
+ constexpr char serviceInfo[] = "service_info";
+
+ constexpr char aesKey[] = "aes_key";
+ constexpr char aesIv[] = "aes_iv";
+ constexpr char aesSalt[] = "aes_salt";
+
+ constexpr char apiPayload[] = "api_payload";
+ constexpr char keyPayload[] = "key_payload";
+
+ constexpr char apiConfig[] = "api_config";
+ constexpr char authData[] = "auth_data";
+ }
+
+ const int requestTimeoutMsecs = 12 * 1000; // 12 secs
+
+ ErrorCode checkErrors(const QList &sslErrors, QNetworkReply *reply)
+ {
+ if (!sslErrors.empty()) {
+ qDebug().noquote() << sslErrors;
+ return ErrorCode::ApiConfigSslError;
+ } else if (reply->error() == QNetworkReply::NoError) {
+ return ErrorCode::NoError;
+ } else if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
+ || reply->error() == QNetworkReply::NetworkError::TimeoutError) {
+ return ErrorCode::ApiConfigTimeoutError;
+ } else {
+ QString err = reply->errorString();
+ qDebug() << QString::fromUtf8(reply->readAll());
+ qDebug() << reply->error();
+ qDebug() << err;
+ qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+ return ErrorCode::ApiConfigDownloadError;
+ }
+ }
+
+ bool shouldBypassProxy(QNetworkReply *reply, const QByteArray &responseBody, bool checkEncryption, const QByteArray &key = "",
+ const QByteArray &iv = "", const QByteArray &salt = "")
+ {
+ if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
+ || reply->error() == QNetworkReply::NetworkError::TimeoutError) {
+ qDebug() << "Timeout occurred";
+ return true;
+ } else if (responseBody.contains("html")) {
+ qDebug() << "The response contains an html tag";
+ return true;
+ } else if (checkEncryption) {
+ try {
+ QSimpleCrypto::QBlockCipher blockCipher;
+ static_cast(blockCipher.decryptAesBlockCipher(responseBody, key, iv, "", salt));
+ } catch (...) {
+ qDebug() << "Failed to decrypt the data";
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+ApiController::ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent)
+ : QObject(parent), m_gatewayEndpoint(gatewayEndpoint), m_isDevEnvironment(isDevEnvironment)
+{
+}
+
+void ApiController::fillServerConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData,
+ const QByteArray &apiResponseBody, QJsonObject &serverConfig)
+{
+ QString data = QJsonDocument::fromJson(apiResponseBody).object().value(config_key::config).toString();
+
+ data.replace("vpn://", "");
+ QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
+
+ if (ba.isEmpty()) {
+ emit errorOccurred(ErrorCode::ApiConfigEmptyError);
+ return;
+ }
+
+ QByteArray ba_uncompressed = qUncompress(ba);
+ if (!ba_uncompressed.isEmpty()) {
+ ba = ba_uncompressed;
+ }
+
+ QString configStr = ba;
+ if (protocol == configKey::cloak) {
+ configStr.replace("", "\n");
+ configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
+ } else if (protocol == configKey::awg) {
+ configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
+ auto newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
+ auto containers = newServerConfig.value(config_key::containers).toArray();
+ if (containers.isEmpty()) {
+ return; // todo process error
+ }
+ auto container = containers.at(0).toObject();
+ QString containerName = ContainerProps::containerTypeToString(DockerContainer::Awg);
+ auto containerConfig = container.value(containerName).toObject();
+ auto protocolConfig = QJsonDocument::fromJson(containerConfig.value(config_key::last_config).toString().toUtf8()).object();
+ containerConfig[config_key::junkPacketCount] = protocolConfig.value(config_key::junkPacketCount);
+ containerConfig[config_key::junkPacketMinSize] = protocolConfig.value(config_key::junkPacketMinSize);
+ containerConfig[config_key::junkPacketMaxSize] = protocolConfig.value(config_key::junkPacketMaxSize);
+ containerConfig[config_key::initPacketJunkSize] = protocolConfig.value(config_key::initPacketJunkSize);
+ containerConfig[config_key::responsePacketJunkSize] = protocolConfig.value(config_key::responsePacketJunkSize);
+ containerConfig[config_key::initPacketMagicHeader] = protocolConfig.value(config_key::initPacketMagicHeader);
+ containerConfig[config_key::responsePacketMagicHeader] = protocolConfig.value(config_key::responsePacketMagicHeader);
+ containerConfig[config_key::underloadPacketMagicHeader] = protocolConfig.value(config_key::underloadPacketMagicHeader);
+ containerConfig[config_key::transportPacketMagicHeader] = protocolConfig.value(config_key::transportPacketMagicHeader);
+ container[containerName] = containerConfig;
+ containers.replace(0, container);
+ newServerConfig[config_key::containers] = containers;
+ configStr = QString(QJsonDocument(newServerConfig).toJson());
+ }
+
+ QJsonObject newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
+ serverConfig[config_key::dns1] = newServerConfig.value(config_key::dns1);
+ serverConfig[config_key::dns2] = newServerConfig.value(config_key::dns2);
+ serverConfig[config_key::containers] = newServerConfig.value(config_key::containers);
+ serverConfig[config_key::hostName] = newServerConfig.value(config_key::hostName);
+
+ if (newServerConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
+ serverConfig[config_key::configVersion] = newServerConfig.value(config_key::configVersion);
+ serverConfig[config_key::description] = newServerConfig.value(config_key::description);
+ serverConfig[config_key::name] = newServerConfig.value(config_key::name);
+ }
+
+ auto defaultContainer = newServerConfig.value(config_key::defaultContainer).toString();
+ serverConfig[config_key::defaultContainer] = defaultContainer;
+
+ QVariantMap map = serverConfig.value(configKey::apiConfig).toObject().toVariantMap();
+ map.insert(newServerConfig.value(configKey::apiConfig).toObject().toVariantMap());
+ auto apiConfig = QJsonObject::fromVariantMap(map);
+
+ if (newServerConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
+ apiConfig.insert(configKey::serviceInfo, QJsonDocument::fromJson(apiResponseBody).object().value(configKey::serviceInfo).toObject());
+ }
+
+ serverConfig[configKey::apiConfig] = apiConfig;
+
+ return;
+}
+
+QStringList ApiController::getProxyUrls()
+{
+ QNetworkRequest request;
+ request.setTransferTimeout(requestTimeoutMsecs);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ QEventLoop wait;
+ QList sslErrors;
+ QNetworkReply *reply;
+
+ QStringList proxyStorageUrl;
+ if (m_isDevEnvironment) {
+ proxyStorageUrl = QStringList { DEV_S3_ENDPOINT };
+ } else {
+ proxyStorageUrl = QStringList { PROD_S3_ENDPOINT };
+ }
+
+ QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
+
+ for (const auto &proxyStorageUrl : proxyStorageUrl) {
+ request.setUrl(proxyStorageUrl);
+ reply = amnApp->manager()->get(request);
+
+ connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
+ connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
+ wait.exec();
+
+ if (reply->error() == QNetworkReply::NetworkError::NoError) {
+ break;
+ }
+ reply->deleteLater();
+ }
+
+ auto encryptedResponseBody = reply->readAll();
+ reply->deleteLater();
+
+ EVP_PKEY *privateKey = nullptr;
+ QByteArray responseBody;
+ try {
+ if (!m_isDevEnvironment) {
+ QCryptographicHash hash(QCryptographicHash::Sha512);
+ hash.addData(key);
+ QByteArray hashResult = hash.result().toHex();
+
+ QByteArray key = QByteArray::fromHex(hashResult.left(64));
+ QByteArray iv = QByteArray::fromHex(hashResult.mid(64, 32));
+
+ QByteArray ba = QByteArray::fromBase64(encryptedResponseBody);
+
+ QSimpleCrypto::QBlockCipher blockCipher;
+ responseBody = blockCipher.decryptAesBlockCipher(ba, key, iv);
+ } else {
+ responseBody = encryptedResponseBody;
+ }
+ } catch (...) {
+ Utils::logException();
+ qCritical() << "error loading private key from environment variables or decrypting payload";
+ return {};
+ }
+
+ auto endpointsArray = QJsonDocument::fromJson(responseBody).array();
+
+ QStringList endpoints;
+ for (const auto &endpoint : endpointsArray) {
+ endpoints.push_back(endpoint.toString());
+ }
+ return endpoints;
+}
+
+ApiController::ApiPayloadData ApiController::generateApiPayloadData(const QString &protocol)
+{
+ ApiController::ApiPayloadData apiPayload;
+ if (protocol == configKey::cloak) {
+ apiPayload.certRequest = OpenVpnConfigurator::createCertRequest();
+ } else if (protocol == configKey::awg) {
+ auto connData = WireguardConfigurator::genClientKeys();
+ apiPayload.wireGuardClientPubKey = connData.clientPubKey;
+ apiPayload.wireGuardClientPrivKey = connData.clientPrivKey;
+ }
+ return apiPayload;
+}
+
+QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData)
+{
+ QJsonObject obj;
+ if (protocol == configKey::cloak) {
+ obj[configKey::certificate] = apiPayloadData.certRequest.request;
+ } else if (protocol == configKey::awg) {
+ obj[configKey::publicKey] = apiPayloadData.wireGuardClientPubKey;
+ }
+
+ obj[configKey::osVersion] = QSysInfo::productType();
+ obj[configKey::appVersion] = QString(APP_VERSION);
+
+ return obj;
+}
+
+void ApiController::updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig)
+{
+#ifdef Q_OS_IOS
+ IosController::Instance()->requestInetAccess();
+ QThread::msleep(10);
+#endif
+
+ if (serverConfig.value(config_key::configVersion).toInt()) {
+ QNetworkRequest request;
+ request.setTransferTimeout(requestTimeoutMsecs);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Authorization", "Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
+ QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
+ request.setUrl(endpoint);
+
+ QString protocol = serverConfig.value(configKey::protocol).toString();
+
+ ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
+
+ QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
+ apiPayload[configKey::uuid] = installationUuid;
+
+ QByteArray requestBody = QJsonDocument(apiPayload).toJson();
+
+ QNetworkReply *reply = amnApp->manager()->post(request, requestBody);
+
+ QObject::connect(reply, &QNetworkReply::finished, [this, reply, protocol, apiPayloadData, serverIndex, serverConfig]() mutable {
+ if (reply->error() == QNetworkReply::NoError) {
+ auto apiResponseBody = reply->readAll();
+ fillServerConfig(protocol, apiPayloadData, apiResponseBody, serverConfig);
+ emit finished(serverConfig, serverIndex);
+ } else {
+ if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
+ || reply->error() == QNetworkReply::NetworkError::TimeoutError) {
+ emit errorOccurred(ErrorCode::ApiConfigTimeoutError);
+ } else {
+ QString err = reply->errorString();
+ qDebug() << QString::fromUtf8(reply->readAll());
+ qDebug() << reply->error();
+ qDebug() << err;
+ qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+ emit errorOccurred(ErrorCode::ApiConfigDownloadError);
+ }
+ }
+
+ reply->deleteLater();
+ });
+
+ QObject::connect(reply, &QNetworkReply::errorOccurred,
+ [this, reply](QNetworkReply::NetworkError error) { qDebug() << reply->errorString() << error; });
+ connect(reply, &QNetworkReply::sslErrors, [this, reply](const QList &errors) {
+ qDebug().noquote() << errors;
+ emit errorOccurred(ErrorCode::ApiConfigSslError);
+ });
+ }
+}
+
+ErrorCode ApiController::getServicesList(QByteArray &responseBody)
+{
+#ifdef Q_OS_IOS
+ IosController::Instance()->requestInetAccess();
+ QThread::msleep(10);
+#endif
+
+ QNetworkRequest request;
+ request.setTransferTimeout(requestTimeoutMsecs);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ request.setUrl(QString("%1v1/services").arg(m_gatewayEndpoint));
+
+ QNetworkReply *reply;
+ reply = amnApp->manager()->get(request);
+
+ QEventLoop wait;
+ QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
+
+ QList sslErrors;
+ connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
+ wait.exec();
+
+ responseBody = reply->readAll();
+
+ if (sslErrors.isEmpty() && shouldBypassProxy(reply, responseBody, false)) {
+ m_proxyUrls = getProxyUrls();
+ std::random_device randomDevice;
+ std::mt19937 generator(randomDevice());
+ std::shuffle(m_proxyUrls.begin(), m_proxyUrls.end(), generator);
+ for (const QString &proxyUrl : m_proxyUrls) {
+ qDebug() << "Go to the next endpoint";
+ request.setUrl(QString("%1v1/services").arg(proxyUrl));
+ reply->deleteLater(); // delete the previous reply
+ reply = amnApp->manager()->get(request);
+
+ QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
+ connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
+ wait.exec();
+
+ responseBody = reply->readAll();
+ if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, responseBody, false)) {
+ break;
+ }
+ }
+ }
+
+ auto errorCode = checkErrors(sslErrors, reply);
+ reply->deleteLater();
+
+ if (errorCode == ErrorCode::NoError) {
+ if (!responseBody.contains("services")) {
+ return ErrorCode::ApiServicesMissingError;
+ }
+ }
+
+ return errorCode;
+}
+
+ErrorCode ApiController::getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
+ const QString &protocol, const QString &serverCountryCode, const QJsonObject &authData,
+ QJsonObject &serverConfig)
+{
+#ifdef Q_OS_IOS
+ IosController::Instance()->requestInetAccess();
+ QThread::msleep(10);
+#endif
+
+ QNetworkRequest request;
+ request.setTransferTimeout(requestTimeoutMsecs);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ request.setUrl(QString("%1v1/config").arg(m_gatewayEndpoint));
+
+ ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
+
+ QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
+ apiPayload[configKey::userCountryCode] = userCountryCode;
+ if (!serverCountryCode.isEmpty()) {
+ apiPayload[configKey::serverCountryCode] = serverCountryCode;
+ }
+ apiPayload[configKey::serviceType] = serviceType;
+ apiPayload[configKey::uuid] = installationUuid;
+ if (!authData.isEmpty()) {
+ apiPayload[configKey::authData] = authData;
+ }
+
+ QSimpleCrypto::QBlockCipher blockCipher;
+ QByteArray key = blockCipher.generatePrivateSalt(32);
+ QByteArray iv = blockCipher.generatePrivateSalt(32);
+ QByteArray salt = blockCipher.generatePrivateSalt(8);
+
+ QJsonObject keyPayload;
+ keyPayload[configKey::aesKey] = QString(key.toBase64());
+ keyPayload[configKey::aesIv] = QString(iv.toBase64());
+ keyPayload[configKey::aesSalt] = QString(salt.toBase64());
+
+ QByteArray encryptedKeyPayload;
+ QByteArray encryptedApiPayload;
+ try {
+ QSimpleCrypto::QRsa rsa;
+
+ EVP_PKEY *publicKey = nullptr;
+ try {
+ QByteArray rsaKey = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
+ QSimpleCrypto::QRsa rsa;
+ publicKey = rsa.getPublicKeyFromByteArray(rsaKey);
+ } catch (...) {
+ Utils::logException();
+ qCritical() << "error loading public key from environment variables";
+ return ErrorCode::ApiMissingAgwPublicKey;
+ }
+
+ encryptedKeyPayload = rsa.encrypt(QJsonDocument(keyPayload).toJson(), publicKey, RSA_PKCS1_PADDING);
+ EVP_PKEY_free(publicKey);
+
+ encryptedApiPayload = blockCipher.encryptAesBlockCipher(QJsonDocument(apiPayload).toJson(), key, iv, "", salt);
+ } catch (...) { // todo change error handling in QSimpleCrypto?
+ Utils::logException();
+ qCritical() << "error when encrypting the request body";
+ return ErrorCode::ApiConfigDecryptionError;
+ }
+
+ QJsonObject requestBody;
+ requestBody[configKey::keyPayload] = QString(encryptedKeyPayload.toBase64());
+ requestBody[configKey::apiPayload] = QString(encryptedApiPayload.toBase64());
+
+ QNetworkReply *reply = amnApp->manager()->post(request, QJsonDocument(requestBody).toJson());
+
+ QEventLoop wait;
+ connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
+
+ QList sslErrors;
+ connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
+ wait.exec();
+
+ auto encryptedResponseBody = reply->readAll();
+
+ if (sslErrors.isEmpty() && shouldBypassProxy(reply, encryptedResponseBody, true, key, iv, salt)) {
+ m_proxyUrls = getProxyUrls();
+ std::random_device randomDevice;
+ std::mt19937 generator(randomDevice());
+ std::shuffle(m_proxyUrls.begin(), m_proxyUrls.end(), generator);
+ for (const QString &proxyUrl : m_proxyUrls) {
+ qDebug() << "Go to the next endpoint";
+ request.setUrl(QString("%1v1/config").arg(proxyUrl));
+ reply->deleteLater(); // delete the previous reply
+ reply = amnApp->manager()->post(request, QJsonDocument(requestBody).toJson());
+
+ QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
+ connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
+ wait.exec();
+
+ encryptedResponseBody = reply->readAll();
+ if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, encryptedResponseBody, true, key, iv, salt)) {
+ break;
+ }
+ }
+ }
+
+ auto errorCode = checkErrors(sslErrors, reply);
+ reply->deleteLater();
+ if (errorCode) {
+ return errorCode;
+ }
+
+ try {
+ auto responseBody = blockCipher.decryptAesBlockCipher(encryptedResponseBody, key, iv, "", salt);
+ fillServerConfig(protocol, apiPayloadData, responseBody, serverConfig);
+ } catch (...) { // todo change error handling in QSimpleCrypto?
+ Utils::logException();
+ qCritical() << "error when decrypting the request body";
+ return ErrorCode::ApiConfigDecryptionError;
+ }
+
+ return errorCode;
+}
diff --git a/client/core/controllers/apiController.h b/client/core/controllers/apiController.h
new file mode 100644
index 00000000..bcb25f96
--- /dev/null
+++ b/client/core/controllers/apiController.h
@@ -0,0 +1,50 @@
+#ifndef APICONTROLLER_H
+#define APICONTROLLER_H
+
+#include
+
+#include "configurators/openvpn_configurator.h"
+
+#ifdef Q_OS_IOS
+ #include "platforms/ios/ios_controller.h"
+#endif
+
+class ApiController : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent = nullptr);
+
+public slots:
+ void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig);
+
+ ErrorCode getServicesList(QByteArray &responseBody);
+ ErrorCode getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
+ const QString &protocol, const QString &serverCountryCode, const QJsonObject &authData, QJsonObject &serverConfig);
+
+signals:
+ void errorOccurred(ErrorCode errorCode);
+ void finished(const QJsonObject &config, const int serverIndex);
+
+private:
+ struct ApiPayloadData
+ {
+ OpenVpnConfigurator::ConnectionData certRequest;
+
+ QString wireGuardClientPrivKey;
+ QString wireGuardClientPubKey;
+ };
+
+ ApiPayloadData generateApiPayloadData(const QString &protocol);
+ QJsonObject fillApiPayload(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData);
+ void fillServerConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData, const QByteArray &apiResponseBody,
+ QJsonObject &serverConfig);
+ QStringList getProxyUrls();
+
+ QString m_gatewayEndpoint;
+ QStringList m_proxyUrls;
+ bool m_isDevEnvironment = false;
+};
+
+#endif // APICONTROLLER_H
diff --git a/client/core/controllers/coreController.cpp b/client/core/controllers/coreController.cpp
deleted file mode 100644
index 0e72ef1a..00000000
--- a/client/core/controllers/coreController.cpp
+++ /dev/null
@@ -1,399 +0,0 @@
-#include "coreController.h"
-
-#include
-#include
-
-#if defined(Q_OS_ANDROID)
- #include "core/installedAppsImageProvider.h"
- #include "platforms/android/android_controller.h"
-#endif
-
-#if defined(Q_OS_IOS)
- #include "platforms/ios/ios_controller.h"
- #include
-#endif
-
-CoreController::CoreController(const QSharedPointer &vpnConnection, const std::shared_ptr &settings,
- QQmlApplicationEngine *engine, QObject *parent)
- : QObject(parent), m_vpnConnection(vpnConnection), m_settings(settings), m_engine(engine)
-{
- initModels();
- initControllers();
- initSignalHandlers();
-
- initAndroidController();
- initAppleController();
-
- initNotificationHandler();
-
- auto locale = m_settings->getAppLanguage();
- m_translator.reset(new QTranslator());
- updateTranslator(locale);
-}
-
-void CoreController::initModels()
-{
- m_containersModel.reset(new ContainersModel(this));
- m_engine->rootContext()->setContextProperty("ContainersModel", m_containersModel.get());
-
- m_defaultServerContainersModel.reset(new ContainersModel(this));
- m_engine->rootContext()->setContextProperty("DefaultServerContainersModel", m_defaultServerContainersModel.get());
-
- m_serversModel.reset(new ServersModel(m_settings, this));
- m_engine->rootContext()->setContextProperty("ServersModel", m_serversModel.get());
-
- m_languageModel.reset(new LanguageModel(m_settings, this));
- m_engine->rootContext()->setContextProperty("LanguageModel", m_languageModel.get());
-
- m_sitesModel.reset(new SitesModel(m_settings, this));
- m_engine->rootContext()->setContextProperty("SitesModel", m_sitesModel.get());
-
- m_allowedDnsModel.reset(new AllowedDnsModel(m_settings, this));
- m_engine->rootContext()->setContextProperty("AllowedDnsModel", m_allowedDnsModel.get());
-
- m_appSplitTunnelingModel.reset(new AppSplitTunnelingModel(m_settings, this));
- m_engine->rootContext()->setContextProperty("AppSplitTunnelingModel", m_appSplitTunnelingModel.get());
-
- m_protocolsModel.reset(new ProtocolsModel(m_settings, this));
- m_engine->rootContext()->setContextProperty("ProtocolsModel", m_protocolsModel.get());
-
- m_openVpnConfigModel.reset(new OpenVpnConfigModel(this));
- m_engine->rootContext()->setContextProperty("OpenVpnConfigModel", m_openVpnConfigModel.get());
-
- m_shadowSocksConfigModel.reset(new ShadowSocksConfigModel(this));
- m_engine->rootContext()->setContextProperty("ShadowSocksConfigModel", m_shadowSocksConfigModel.get());
-
- m_cloakConfigModel.reset(new CloakConfigModel(this));
- m_engine->rootContext()->setContextProperty("CloakConfigModel", m_cloakConfigModel.get());
-
- m_wireGuardConfigModel.reset(new WireGuardConfigModel(this));
- m_engine->rootContext()->setContextProperty("WireGuardConfigModel", m_wireGuardConfigModel.get());
-
- m_awgConfigModel.reset(new AwgConfigModel(this));
- m_engine->rootContext()->setContextProperty("AwgConfigModel", m_awgConfigModel.get());
-
- m_xrayConfigModel.reset(new XrayConfigModel(this));
- m_engine->rootContext()->setContextProperty("XrayConfigModel", m_xrayConfigModel.get());
-
-#ifdef Q_OS_WINDOWS
- m_ikev2ConfigModel.reset(new Ikev2ConfigModel(this));
- m_engine->rootContext()->setContextProperty("Ikev2ConfigModel", m_ikev2ConfigModel.get());
-#endif
-
- m_sftpConfigModel.reset(new SftpConfigModel(this));
- m_engine->rootContext()->setContextProperty("SftpConfigModel", m_sftpConfigModel.get());
-
- m_socks5ConfigModel.reset(new Socks5ProxyConfigModel(this));
- m_engine->rootContext()->setContextProperty("Socks5ProxyConfigModel", m_socks5ConfigModel.get());
-
- m_clientManagementModel.reset(new ClientManagementModel(m_settings, this));
- m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get());
-
- m_apiServicesModel.reset(new ApiServicesModel(this));
- m_engine->rootContext()->setContextProperty("ApiServicesModel", m_apiServicesModel.get());
-
- m_apiCountryModel.reset(new ApiCountryModel(this));
- m_engine->rootContext()->setContextProperty("ApiCountryModel", m_apiCountryModel.get());
-
- m_apiAccountInfoModel.reset(new ApiAccountInfoModel(this));
- m_engine->rootContext()->setContextProperty("ApiAccountInfoModel", m_apiAccountInfoModel.get());
-
- m_apiDevicesModel.reset(new ApiDevicesModel(m_settings, this));
- m_engine->rootContext()->setContextProperty("ApiDevicesModel", m_apiDevicesModel.get());
-}
-
-void CoreController::initControllers()
-{
- m_connectionController.reset(
- new ConnectionController(m_serversModel, m_containersModel, m_clientManagementModel, m_vpnConnection, m_settings));
- m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get());
-
- m_pageController.reset(new PageController(m_serversModel, m_settings));
- m_engine->rootContext()->setContextProperty("PageController", m_pageController.get());
-
- m_focusController.reset(new FocusController(m_engine, this));
- m_engine->rootContext()->setContextProperty("FocusController", m_focusController.get());
-
- m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel, m_clientManagementModel, m_settings));
- m_engine->rootContext()->setContextProperty("InstallController", m_installController.get());
-
- connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(),
- &ConnectionController::onCurrentContainerUpdated); // TODO remove this
-
- m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
- m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
-
- m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_clientManagementModel, m_settings));
- m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get());
-
- m_settingsController.reset(
- new SettingsController(m_serversModel, m_containersModel, m_languageModel, m_sitesModel, m_appSplitTunnelingModel, m_settings));
- m_engine->rootContext()->setContextProperty("SettingsController", m_settingsController.get());
-
- m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel));
- m_engine->rootContext()->setContextProperty("SitesController", m_sitesController.get());
-
- m_allowedDnsController.reset(new AllowedDnsController(m_settings, m_allowedDnsModel));
- m_engine->rootContext()->setContextProperty("AllowedDnsController", m_allowedDnsController.get());
-
- m_appSplitTunnelingController.reset(new AppSplitTunnelingController(m_settings, m_appSplitTunnelingModel));
- m_engine->rootContext()->setContextProperty("AppSplitTunnelingController", m_appSplitTunnelingController.get());
-
- m_systemController.reset(new SystemController(m_settings));
- m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());
-
- m_apiSettingsController.reset(
- new ApiSettingsController(m_serversModel, m_apiAccountInfoModel, m_apiCountryModel, m_apiDevicesModel, m_settings));
- m_engine->rootContext()->setContextProperty("ApiSettingsController", m_apiSettingsController.get());
-
- m_apiConfigsController.reset(new ApiConfigsController(m_serversModel, m_apiServicesModel, m_settings));
- m_engine->rootContext()->setContextProperty("ApiConfigsController", m_apiConfigsController.get());
-
- m_apiPremV1MigrationController.reset(new ApiPremV1MigrationController(m_serversModel, m_settings, this));
- m_engine->rootContext()->setContextProperty("ApiPremV1MigrationController", m_apiPremV1MigrationController.get());
-}
-
-void CoreController::initAndroidController()
-{
-#ifdef Q_OS_ANDROID
- if (!AndroidController::initLogging()) {
- qFatal("Android logging initialization failed");
- }
- AndroidController::instance()->setSaveLogs(m_settings->isSaveLogs());
- connect(m_settings.get(), &Settings::saveLogsChanged, AndroidController::instance(), &AndroidController::setSaveLogs);
-
- AndroidController::instance()->setScreenshotsEnabled(m_settings->isScreenshotsEnabled());
- connect(m_settings.get(), &Settings::screenshotsEnabledChanged, AndroidController::instance(), &AndroidController::setScreenshotsEnabled);
-
- connect(m_settings.get(), &Settings::serverRemoved, AndroidController::instance(), &AndroidController::resetLastServer);
-
- connect(m_settings.get(), &Settings::settingsCleared, []() { AndroidController::instance()->resetLastServer(-1); });
-
- connect(AndroidController::instance(), &AndroidController::initConnectionState, this, [this](Vpn::ConnectionState state) {
- m_connectionController->onConnectionStateChanged(state);
- if (m_vpnConnection)
- m_vpnConnection->restoreConnection();
- });
- if (!AndroidController::instance()->initialize()) {
- qFatal("Android controller initialization failed");
- }
-
- connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, this, [this](QString data) {
- emit m_pageController->goToPageHome();
- m_importController->extractConfigFromData(data);
- data.clear();
- emit m_pageController->goToPageViewConfig();
- });
-
- m_engine->addImageProvider(QLatin1String("installedAppImage"), new InstalledAppsImageProvider);
-#endif
-}
-
-void CoreController::initAppleController()
-{
-#ifdef Q_OS_IOS
- IosController::Instance()->initialize();
- connect(IosController::Instance(), &IosController::importConfigFromOutside, this, [this](QString data) {
- emit m_pageController->goToPageHome();
- m_importController->extractConfigFromData(data);
- emit m_pageController->goToPageViewConfig();
- });
-
- connect(IosController::Instance(), &IosController::importBackupFromOutside, this, [this](QString filePath) {
- emit m_pageController->goToPageHome();
- m_pageController->goToPageSettingsBackup();
- emit m_settingsController->importBackupFromOutside(filePath);
- });
-
- QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled()); });
-
- connect(m_settings.get(), &Settings::screenshotsEnabledChanged, [](bool enabled) { AmneziaVPN::toggleScreenshots(enabled); });
-#endif
-}
-
-void CoreController::initSignalHandlers()
-{
- initErrorMessagesHandler();
-
- initApiCountryModelUpdateHandler();
- initContainerModelUpdateHandler();
- initAdminConfigRevokedHandler();
- initPassphraseRequestHandler();
- initTranslationsUpdatedHandler();
- initAutoConnectHandler();
- initAmneziaDnsToggledHandler();
- initPrepareConfigHandler();
- initImportPremiumV2VpnKeyHandler();
- initShowMigrationDrawerHandler();
- initStrictKillSwitchHandler();
-}
-
-void CoreController::initNotificationHandler()
-{
-#ifndef Q_OS_ANDROID
- m_notificationHandler.reset(NotificationHandler::create(nullptr));
-
- connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(),
- &NotificationHandler::setConnectionState);
-
- connect(m_notificationHandler.get(), &NotificationHandler::raiseRequested, m_pageController.get(), &PageController::raiseMainWindow);
- connect(m_notificationHandler.get(), &NotificationHandler::connectRequested, m_connectionController.get(),
- static_cast(&ConnectionController::openConnection));
- connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
- &ConnectionController::closeConnection);
- connect(this, &CoreController::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated);
-#endif
-}
-
-void CoreController::updateTranslator(const QLocale &locale)
-{
- if (!m_translator->isEmpty()) {
- QCoreApplication::removeTranslator(m_translator.get());
- }
-
- QStringList availableTranslations;
- QDirIterator it(":/translations", QStringList("amneziavpn_*.qm"), QDir::Files);
- while (it.hasNext()) {
- availableTranslations << it.next();
- }
-
- // This code allow to load translation for the language only, without country code
- const QString lang = locale.name().split("_").first();
- const QString translationFilePrefix = QString(":/translations/amneziavpn_") + lang;
- QString strFileName = QString(":/translations/amneziavpn_%1.qm").arg(locale.name());
- for (const QString &translation : availableTranslations) {
- if (translation.contains(translationFilePrefix)) {
- strFileName = translation;
- break;
- }
- }
-
- if (m_translator->load(strFileName)) {
- if (QCoreApplication::installTranslator(m_translator.get())) {
- m_settings->setAppLanguage(locale);
- }
- } else {
- m_settings->setAppLanguage(QLocale::English);
- }
-
- m_engine->retranslate();
-
- emit translationsUpdated();
-}
-
-void CoreController::initErrorMessagesHandler()
-{
- connect(m_connectionController.get(), &ConnectionController::connectionErrorOccurred, this, [this](ErrorCode errorCode) {
- emit m_pageController->showErrorMessage(errorCode);
- emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
- });
-
- connect(m_apiConfigsController.get(), &ApiConfigsController::errorOccurred, m_pageController.get(),
- qOverload(&PageController::showErrorMessage));
-}
-
-void CoreController::setQmlRoot()
-{
- m_systemController->setQmlRoot(m_engine->rootObjects().value(0));
-}
-
-void CoreController::initApiCountryModelUpdateHandler()
-{
- // TODO
- connect(m_serversModel.get(), &ServersModel::updateApiCountryModel, this, [this]() {
- m_apiCountryModel->updateModel(m_serversModel->getProcessedServerData("apiAvailableCountries").toJsonArray(),
- m_serversModel->getProcessedServerData("apiServerCountryCode").toString());
- });
- connect(m_serversModel.get(), &ServersModel::updateApiServicesModel, this,
- [this]() { m_apiServicesModel->updateModel(m_serversModel->getProcessedServerData("apiConfig").toJsonObject()); });
-}
-
-void CoreController::initContainerModelUpdateHandler()
-{
- connect(m_serversModel.get(), &ServersModel::containersUpdated, m_containersModel.get(), &ContainersModel::updateModel);
- connect(m_serversModel.get(), &ServersModel::defaultServerContainersUpdated, m_defaultServerContainersModel.get(),
- &ContainersModel::updateModel);
- m_serversModel->resetModel();
-}
-
-void CoreController::initAdminConfigRevokedHandler()
-{
- connect(m_clientManagementModel.get(), &ClientManagementModel::adminConfigRevoked, m_serversModel.get(),
- &ServersModel::clearCachedProfile);
-}
-
-void CoreController::initPassphraseRequestHandler()
-{
- connect(m_installController.get(), &InstallController::passphraseRequestStarted, m_pageController.get(),
- &PageController::showPassphraseRequestDrawer);
- connect(m_pageController.get(), &PageController::passphraseRequestDrawerClosed, m_installController.get(),
- &InstallController::setEncryptedPassphrase);
-}
-
-void CoreController::initTranslationsUpdatedHandler()
-{
- connect(m_languageModel.get(), &LanguageModel::updateTranslations, this, &CoreController::updateTranslator);
- connect(this, &CoreController::translationsUpdated, m_languageModel.get(), &LanguageModel::translationsUpdated);
- connect(this, &CoreController::translationsUpdated, m_connectionController.get(), &ConnectionController::onTranslationsUpdated);
-}
-
-void CoreController::initAutoConnectHandler()
-{
- if (m_settingsController->isAutoConnectEnabled() && m_serversModel->getDefaultServerIndex() >= 0) {
- QTimer::singleShot(1000, this, [this]() { m_connectionController->openConnection(); });
- }
-}
-
-void CoreController::initAmneziaDnsToggledHandler()
-{
- connect(m_settingsController.get(), &SettingsController::amneziaDnsToggled, m_serversModel.get(), &ServersModel::toggleAmneziaDns);
-}
-
-void CoreController::initPrepareConfigHandler()
-{
- connect(m_connectionController.get(), &ConnectionController::prepareConfig, this, [this]() {
- emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing);
-
- if (!m_apiConfigsController->isConfigValid()) {
- emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
- return;
- }
-
- if (!m_installController->isConfigValid()) {
- emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
- return;
- }
-
- m_connectionController->openConnection();
- });
-}
-
-void CoreController::initImportPremiumV2VpnKeyHandler()
-{
- connect(m_apiPremV1MigrationController.get(), &ApiPremV1MigrationController::importPremiumV2VpnKey, this, [this](const QString &vpnKey) {
- m_importController->extractConfigFromData(vpnKey);
- m_importController->importConfig();
-
- emit m_apiPremV1MigrationController->migrationFinished();
- });
-}
-
-void CoreController::initShowMigrationDrawerHandler()
-{
- QTimer::singleShot(1000, this, [this]() {
- if (m_apiPremV1MigrationController->isPremV1MigrationReminderActive() && m_apiPremV1MigrationController->hasConfigsToMigration()) {
- m_apiPremV1MigrationController->showMigrationDrawer();
- }
- });
-}
-
-void CoreController::initStrictKillSwitchHandler()
-{
- connect(m_settingsController.get(), &SettingsController::strictKillSwitchEnabledChanged, m_vpnConnection.get(),
- &VpnConnection::onKillSwitchModeChanged);
-}
-
-QSharedPointer CoreController::pageController() const
-{
- return m_pageController;
-}
diff --git a/client/core/controllers/coreController.h b/client/core/controllers/coreController.h
deleted file mode 100644
index 9ae53562..00000000
--- a/client/core/controllers/coreController.h
+++ /dev/null
@@ -1,145 +0,0 @@
-#ifndef CORECONTROLLER_H
-#define CORECONTROLLER_H
-
-#include
-#include
-#include
-
-#include "ui/controllers/api/apiConfigsController.h"
-#include "ui/controllers/api/apiSettingsController.h"
-#include "ui/controllers/api/apiPremV1MigrationController.h"
-#include "ui/controllers/appSplitTunnelingController.h"
-#include "ui/controllers/allowedDnsController.h"
-#include "ui/controllers/connectionController.h"
-#include "ui/controllers/exportController.h"
-#include "ui/controllers/focusController.h"
-#include "ui/controllers/importController.h"
-#include "ui/controllers/installController.h"
-#include "ui/controllers/pageController.h"
-#include "ui/controllers/settingsController.h"
-#include "ui/controllers/sitesController.h"
-#include "ui/controllers/systemController.h"
-
-#include "ui/models/allowed_dns_model.h"
-#include "ui/models/containers_model.h"
-#include "ui/models/languageModel.h"
-#include "ui/models/protocols/cloakConfigModel.h"
-#ifdef Q_OS_WINDOWS
- #include "ui/models/protocols/ikev2ConfigModel.h"
-#endif
-#include "ui/models/api/apiAccountInfoModel.h"
-#include "ui/models/api/apiCountryModel.h"
-#include "ui/models/api/apiDevicesModel.h"
-#include "ui/models/api/apiServicesModel.h"
-#include "ui/models/appSplitTunnelingModel.h"
-#include "ui/models/clientManagementModel.h"
-#include "ui/models/protocols/awgConfigModel.h"
-#include "ui/models/protocols/openvpnConfigModel.h"
-#include "ui/models/protocols/shadowsocksConfigModel.h"
-#include "ui/models/protocols/wireguardConfigModel.h"
-#include "ui/models/protocols/xrayConfigModel.h"
-#include "ui/models/protocols_model.h"
-#include "ui/models/servers_model.h"
-#include "ui/models/services/sftpConfigModel.h"
-#include "ui/models/services/socks5ProxyConfigModel.h"
-#include "ui/models/sites_model.h"
-
-#ifndef Q_OS_ANDROID
- #include "ui/notificationhandler.h"
-#endif
-
-class CoreController : public QObject
-{
- Q_OBJECT
-
-public:
- explicit CoreController(const QSharedPointer &vpnConnection, const std::shared_ptr &settings,
- QQmlApplicationEngine *engine, QObject *parent = nullptr);
-
- QSharedPointer pageController() const;
- void setQmlRoot();
-
-signals:
- void translationsUpdated();
-
-private:
- void initModels();
- void initControllers();
- void initAndroidController();
- void initAppleController();
- void initSignalHandlers();
-
- void initNotificationHandler();
-
- void updateTranslator(const QLocale &locale);
-
- void initErrorMessagesHandler();
-
- void initApiCountryModelUpdateHandler();
- void initContainerModelUpdateHandler();
- void initAdminConfigRevokedHandler();
- void initPassphraseRequestHandler();
- void initTranslationsUpdatedHandler();
- void initAutoConnectHandler();
- void initAmneziaDnsToggledHandler();
- void initPrepareConfigHandler();
- void initImportPremiumV2VpnKeyHandler();
- void initShowMigrationDrawerHandler();
- void initStrictKillSwitchHandler();
-
- QQmlApplicationEngine *m_engine {}; // TODO use parent child system here?
- std::shared_ptr m_settings;
- QSharedPointer m_vpnConnection;
- QSharedPointer m_translator;
-
-#ifndef Q_OS_ANDROID
- QScopedPointer m_notificationHandler;
-#endif
-
- QMetaObject::Connection m_reloadConfigErrorOccurredConnection;
-
- QScopedPointer m_connectionController;
- QScopedPointer m_focusController;
- QSharedPointer m_pageController; // TODO
- QScopedPointer m_installController;
- QScopedPointer m_importController;
- QScopedPointer m_exportController;
- QScopedPointer m_settingsController;
- QScopedPointer m_sitesController;
- QScopedPointer m_systemController;
- QScopedPointer m_appSplitTunnelingController;
- QScopedPointer m_allowedDnsController;
-
- QScopedPointer m_apiSettingsController;
- QScopedPointer m_apiConfigsController;
- QScopedPointer m_apiPremV1MigrationController;
-
- QSharedPointer m_containersModel;
- QSharedPointer m_defaultServerContainersModel;
- QSharedPointer m_serversModel;
- QSharedPointer m_languageModel;
- QSharedPointer m_protocolsModel;
- QSharedPointer m_sitesModel;
- QSharedPointer m_allowedDnsModel;
- QSharedPointer m_appSplitTunnelingModel;
- QSharedPointer m_clientManagementModel;
-
- QSharedPointer m_apiServicesModel;
- QSharedPointer m_apiCountryModel;
- QSharedPointer m_apiAccountInfoModel;
- QSharedPointer m_apiDevicesModel;
-
- QScopedPointer m_openVpnConfigModel;
- QScopedPointer m_shadowSocksConfigModel;
- QScopedPointer m_cloakConfigModel;
- QScopedPointer m_xrayConfigModel;
- QScopedPointer m_wireGuardConfigModel;
- QScopedPointer m_awgConfigModel;
-#ifdef Q_OS_WINDOWS
- QScopedPointer m_ikev2ConfigModel;
-#endif
- QScopedPointer m_sftpConfigModel;
- QScopedPointer m_socks5ConfigModel;
-};
-
-#endif // CORECONTROLLER_H
diff --git a/client/core/controllers/gatewayController.cpp b/client/core/controllers/gatewayController.cpp
deleted file mode 100644
index 26855ae6..00000000
--- a/client/core/controllers/gatewayController.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-#include "gatewayController.h"
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include "QBlockCipher.h"
-#include "QRsa.h"
-
-#include "amnezia_application.h"
-#include "core/api/apiUtils.h"
-#include "core/networkUtilities.h"
-#include "utilities.h"
-
-#ifdef AMNEZIA_DESKTOP
- #include "core/ipcclient.h"
-#endif
-
-namespace
-{
- namespace configKey
- {
- constexpr char aesKey[] = "aes_key";
- constexpr char aesIv[] = "aes_iv";
- constexpr char aesSalt[] = "aes_salt";
-
- constexpr char apiPayload[] = "api_payload";
- constexpr char keyPayload[] = "key_payload";
- }
-
- constexpr QLatin1String errorResponsePattern1("No active configuration found for");
- constexpr QLatin1String errorResponsePattern2("No non-revoked public key found for");
- constexpr QLatin1String errorResponsePattern3("Account not found.");
-
- constexpr QLatin1String updateRequestResponsePattern("client version update is required");
-}
-
-GatewayController::GatewayController(const QString &gatewayEndpoint, const bool isDevEnvironment, const int requestTimeoutMsecs,
- const bool isStrictKillSwitchEnabled, QObject *parent)
- : QObject(parent),
- m_gatewayEndpoint(gatewayEndpoint),
- m_isDevEnvironment(isDevEnvironment),
- m_requestTimeoutMsecs(requestTimeoutMsecs),
- m_isStrictKillSwitchEnabled(isStrictKillSwitchEnabled)
-{
-}
-
-ErrorCode GatewayController::get(const QString &endpoint, QByteArray &responseBody)
-{
-#ifdef Q_OS_IOS
- IosController::Instance()->requestInetAccess();
- QThread::msleep(10);
-#endif
-
- QNetworkRequest request;
- request.setTransferTimeout(m_requestTimeoutMsecs);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
-
- request.setUrl(QString(endpoint).arg(m_gatewayEndpoint));
-
- // bypass killSwitch exceptions for API-gateway
-#ifdef AMNEZIA_DESKTOP
- if (m_isStrictKillSwitchEnabled) {
- QString host = QUrl(request.url()).host();
- QString ip = NetworkUtilities::getIPAddress(host);
- if (!ip.isEmpty()) {
- IpcClient::Interface()->addKillSwitchAllowedRange(QStringList { ip });
- }
- }
-#endif
-
- QNetworkReply *reply;
- reply = amnApp->networkManager()->get(request);
-
- QEventLoop wait;
- QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
-
- QList sslErrors;
- connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
- wait.exec();
-
- responseBody = reply->readAll();
-
- if (sslErrors.isEmpty() && shouldBypassProxy(reply, responseBody, false)) {
- auto requestFunction = [&request, &responseBody](const QString &url) {
- request.setUrl(url);
- return amnApp->networkManager()->get(request);
- };
-
- auto replyProcessingFunction = [&responseBody, &reply, &sslErrors, this](QNetworkReply *nestedReply,
- const QList &nestedSslErrors) {
- responseBody = nestedReply->readAll();
- if (!sslErrors.isEmpty() || !shouldBypassProxy(nestedReply, responseBody, false)) {
- sslErrors = nestedSslErrors;
- reply = nestedReply;
- return true;
- }
- return false;
- };
-
- bypassProxy(endpoint, reply, requestFunction, replyProcessingFunction);
- }
-
- auto errorCode = apiUtils::checkNetworkReplyErrors(sslErrors, reply);
- reply->deleteLater();
-
- return errorCode;
-}
-
-ErrorCode GatewayController::post(const QString &endpoint, const QJsonObject apiPayload, QByteArray &responseBody)
-{
-#ifdef Q_OS_IOS
- IosController::Instance()->requestInetAccess();
- QThread::msleep(10);
-#endif
-
- QNetworkRequest request;
- request.setTransferTimeout(m_requestTimeoutMsecs);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
-
- request.setUrl(endpoint.arg(m_gatewayEndpoint));
-
- // bypass killSwitch exceptions for API-gateway
-#ifdef AMNEZIA_DESKTOP
- if (m_isStrictKillSwitchEnabled) {
- QString host = QUrl(request.url()).host();
- QString ip = NetworkUtilities::getIPAddress(host);
- if (!ip.isEmpty()) {
- IpcClient::Interface()->addKillSwitchAllowedRange(QStringList { ip });
- }
- }
-#endif
-
- QSimpleCrypto::QBlockCipher blockCipher;
- QByteArray key = blockCipher.generatePrivateSalt(32);
- QByteArray iv = blockCipher.generatePrivateSalt(32);
- QByteArray salt = blockCipher.generatePrivateSalt(8);
-
- QJsonObject keyPayload;
- keyPayload[configKey::aesKey] = QString(key.toBase64());
- keyPayload[configKey::aesIv] = QString(iv.toBase64());
- keyPayload[configKey::aesSalt] = QString(salt.toBase64());
-
- QByteArray encryptedKeyPayload;
- QByteArray encryptedApiPayload;
- try {
- QSimpleCrypto::QRsa rsa;
-
- EVP_PKEY *publicKey = nullptr;
- try {
- QByteArray rsaKey = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
- QSimpleCrypto::QRsa rsa;
- publicKey = rsa.getPublicKeyFromByteArray(rsaKey);
- } catch (...) {
- Utils::logException();
- qCritical() << "error loading public key from environment variables";
- return ErrorCode::ApiMissingAgwPublicKey;
- }
-
- encryptedKeyPayload = rsa.encrypt(QJsonDocument(keyPayload).toJson(), publicKey, RSA_PKCS1_PADDING);
- EVP_PKEY_free(publicKey);
-
- encryptedApiPayload = blockCipher.encryptAesBlockCipher(QJsonDocument(apiPayload).toJson(), key, iv, "", salt);
- } catch (...) { // todo change error handling in QSimpleCrypto?
- Utils::logException();
- qCritical() << "error when encrypting the request body";
- return ErrorCode::ApiConfigDecryptionError;
- }
-
- QJsonObject requestBody;
- requestBody[configKey::keyPayload] = QString(encryptedKeyPayload.toBase64());
- requestBody[configKey::apiPayload] = QString(encryptedApiPayload.toBase64());
-
- QNetworkReply *reply = amnApp->networkManager()->post(request, QJsonDocument(requestBody).toJson());
-
- QEventLoop wait;
- connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
-
- QList sslErrors;
- connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
- wait.exec();
-
- QByteArray encryptedResponseBody = reply->readAll();
-
- if (sslErrors.isEmpty() && shouldBypassProxy(reply, encryptedResponseBody, true, key, iv, salt)) {
- auto requestFunction = [&request, &encryptedResponseBody, &requestBody](const QString &url) {
- request.setUrl(url);
- return amnApp->networkManager()->post(request, QJsonDocument(requestBody).toJson());
- };
-
- auto replyProcessingFunction = [&encryptedResponseBody, &reply, &sslErrors, &key, &iv, &salt,
- this](QNetworkReply *nestedReply, const QList &nestedSslErrors) {
- encryptedResponseBody = nestedReply->readAll();
- reply = nestedReply;
- if (!sslErrors.isEmpty() || shouldBypassProxy(nestedReply, encryptedResponseBody, true, key, iv, salt)) {
- sslErrors = nestedSslErrors;
- return false;
- }
- return true;
- };
-
- bypassProxy(endpoint, reply, requestFunction, replyProcessingFunction);
- }
-
- auto errorCode = apiUtils::checkNetworkReplyErrors(sslErrors, reply);
- reply->deleteLater();
- if (errorCode) {
- return errorCode;
- }
-
- try {
- responseBody = blockCipher.decryptAesBlockCipher(encryptedResponseBody, key, iv, "", salt);
- return ErrorCode::NoError;
- } catch (...) { // todo change error handling in QSimpleCrypto?
- Utils::logException();
- qCritical() << "error when decrypting the request body";
- return ErrorCode::ApiConfigDecryptionError;
- }
-}
-
-QStringList GatewayController::getProxyUrls()
-{
- QNetworkRequest request;
- request.setTransferTimeout(m_requestTimeoutMsecs);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
-
- QEventLoop wait;
- QList sslErrors;
- QNetworkReply *reply;
-
- QStringList proxyStorageUrls;
- if (m_isDevEnvironment) {
- proxyStorageUrls = QString(DEV_S3_ENDPOINT).split(", ");
- } else {
- proxyStorageUrls = QString(PROD_S3_ENDPOINT).split(", ");
- }
-
- QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
-
- for (const auto &proxyStorageUrl : proxyStorageUrls) {
- request.setUrl(proxyStorageUrl);
- reply = amnApp->networkManager()->get(request);
-
- connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
- connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
- wait.exec();
-
- if (reply->error() == QNetworkReply::NetworkError::NoError) {
- auto encryptedResponseBody = reply->readAll();
- reply->deleteLater();
-
- EVP_PKEY *privateKey = nullptr;
- QByteArray responseBody;
- try {
- if (!m_isDevEnvironment) {
- QCryptographicHash hash(QCryptographicHash::Sha512);
- hash.addData(key);
- QByteArray hashResult = hash.result().toHex();
-
- QByteArray key = QByteArray::fromHex(hashResult.left(64));
- QByteArray iv = QByteArray::fromHex(hashResult.mid(64, 32));
-
- QByteArray ba = QByteArray::fromBase64(encryptedResponseBody);
-
- QSimpleCrypto::QBlockCipher blockCipher;
- responseBody = blockCipher.decryptAesBlockCipher(ba, key, iv);
- } else {
- responseBody = encryptedResponseBody;
- }
- } catch (...) {
- Utils::logException();
- qCritical() << "error loading private key from environment variables or decrypting payload" << encryptedResponseBody;
- continue;
- }
-
- auto endpointsArray = QJsonDocument::fromJson(responseBody).array();
-
- QStringList endpoints;
- for (const auto &endpoint : endpointsArray) {
- endpoints.push_back(endpoint.toString());
- }
- return endpoints;
- } else {
- apiUtils::checkNetworkReplyErrors(sslErrors, reply);
- qDebug() << "go to the next storage endpoint";
-
- reply->deleteLater();
- }
- }
- return {};
-}
-
-bool GatewayController::shouldBypassProxy(QNetworkReply *reply, const QByteArray &responseBody, bool checkEncryption, const QByteArray &key,
- const QByteArray &iv, const QByteArray &salt)
-{
- if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError || reply->error() == QNetworkReply::NetworkError::TimeoutError) {
- qDebug() << "timeout occurred";
- qDebug() << reply->error();
- return true;
- } else if (responseBody.contains("html")) {
- qDebug() << "the response contains an html tag";
- return true;
- } else if (reply->error() == QNetworkReply::NetworkError::ContentNotFoundError) {
- if (responseBody.contains(errorResponsePattern1) || responseBody.contains(errorResponsePattern2)
- || responseBody.contains(errorResponsePattern3)) {
- return false;
- } else {
- qDebug() << reply->error();
- return true;
- }
- } else if (reply->error() == QNetworkReply::NetworkError::OperationNotImplementedError) {
- if (responseBody.contains(updateRequestResponsePattern)) {
- return false;
- } else {
- qDebug() << reply->error();
- return true;
- }
- } else if (reply->error() != QNetworkReply::NetworkError::NoError) {
- qDebug() << reply->error();
- return true;
- } else if (checkEncryption) {
- try {
- QSimpleCrypto::QBlockCipher blockCipher;
- static_cast(blockCipher.decryptAesBlockCipher(responseBody, key, iv, "", salt));
- } catch (...) {
- qDebug() << "failed to decrypt the data";
- return true;
- }
- }
- return false;
-}
-
-void GatewayController::bypassProxy(const QString &endpoint, QNetworkReply *reply,
- std::function requestFunction,
- std::function &sslErrors)> replyProcessingFunction)
-{
- QStringList proxyUrls = getProxyUrls();
- std::random_device randomDevice;
- std::mt19937 generator(randomDevice());
- std::shuffle(proxyUrls.begin(), proxyUrls.end(), generator);
-
- QEventLoop wait;
- QList sslErrors;
- QByteArray responseBody;
-
- for (const QString &proxyUrl : proxyUrls) {
- qDebug() << "go to the next proxy endpoint";
- reply->deleteLater(); // delete the previous reply
- reply = requestFunction(endpoint.arg(proxyUrl));
-
- QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
- connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
- wait.exec();
-
- if (replyProcessingFunction(reply, sslErrors)) {
- break;
- }
- }
-}
diff --git a/client/core/controllers/gatewayController.h b/client/core/controllers/gatewayController.h
deleted file mode 100644
index 9f91df53..00000000
--- a/client/core/controllers/gatewayController.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef GATEWAYCONTROLLER_H
-#define GATEWAYCONTROLLER_H
-
-#include
-#include
-
-#include "core/defs.h"
-
-#ifdef Q_OS_IOS
- #include "platforms/ios/ios_controller.h"
-#endif
-
-class GatewayController : public QObject
-{
- Q_OBJECT
-
-public:
- explicit GatewayController(const QString &gatewayEndpoint, const bool isDevEnvironment, const int requestTimeoutMsecs,
- const bool isStrictKillSwitchEnabled, QObject *parent = nullptr);
-
- amnezia::ErrorCode get(const QString &endpoint, QByteArray &responseBody);
- amnezia::ErrorCode post(const QString &endpoint, const QJsonObject apiPayload, QByteArray &responseBody);
-
-private:
- QStringList getProxyUrls();
- bool shouldBypassProxy(QNetworkReply *reply, const QByteArray &responseBody, bool checkEncryption, const QByteArray &key = "",
- const QByteArray &iv = "", const QByteArray &salt = "");
- void bypassProxy(const QString &endpoint, QNetworkReply *reply, std::function requestFunction,
- std::function &sslErrors)> replyProcessingFunction);
-
- int m_requestTimeoutMsecs;
- QString m_gatewayEndpoint;
- bool m_isDevEnvironment = false;
- bool m_isStrictKillSwitchEnabled = false;
-};
-
-#endif // GATEWAYCONTROLLER_H
diff --git a/client/core/controllers/serverController.cpp b/client/core/controllers/serverController.cpp
index 3c24edea..b6795a01 100644
--- a/client/core/controllers/serverController.cpp
+++ b/client/core/controllers/serverController.cpp
@@ -138,7 +138,7 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
if (overwriteMode == libssh::ScpOverwriteMode::ScpOverwriteExisting) {
e = runScript(credentials,
- replaceVars(QStringLiteral("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName, path),
+ replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)),
cbReadStd, cbReadStd);
@@ -146,7 +146,7 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
return e;
} else if (overwriteMode == libssh::ScpOverwriteMode::ScpAppendToExisting) {
e = runScript(credentials,
- replaceVars(QStringLiteral("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName, tmpFileName),
+ replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(tmpFileName),
genVarsForScript(credentials, container)),
cbReadStd, cbReadStd);
@@ -154,7 +154,7 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
return e;
e = runScript(credentials,
- replaceVars(QStringLiteral("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName, path),
+ replaceVars(QString("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)),
cbReadStd, cbReadStd);
@@ -177,7 +177,7 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
errorCode = ErrorCode::NoError;
- QString script = QStringLiteral("sudo docker exec -i %1 sh -c \"xxd -p '%2'\"").arg(ContainerProps::containerToString(container), path);
+ QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"").arg(ContainerProps::containerToString(container)).arg(path);
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@@ -346,10 +346,8 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
}
if (container == DockerContainer::Awg) {
- if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
- != newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
- || (oldProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)
- != newProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort))
+ if ((oldProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)
+ != newProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort))
|| (oldProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount)
!= newProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount))
|| (oldProtoConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize)
@@ -366,21 +364,14 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
!= newProtoConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader))
|| (oldProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader)
!= newProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader))
- || (oldProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader))
- != newProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader))
- // || (oldProtoConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize)
- // != newProtoConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize))
- // || (oldProtoConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize)
- // != newProtoConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize))
-
+ || (oldProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader)
+ != newProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader)))
return true;
}
if (container == DockerContainer::WireGuard) {
- if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
- != newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
- || (oldProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)
- != newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)))
+ if (oldProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)
+ != newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort))
return true;
}
@@ -388,13 +379,6 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
return true;
}
- if (container == DockerContainer::Xray) {
- if (oldProtoConfig.value(config_key::port).toString(protocols::xray::defaultPort)
- != newProtoConfig.value(config_key::port).toString(protocols::xray::defaultPort)) {
- return true;
- }
- }
-
return false;
}
@@ -451,24 +435,15 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
stdOut += data + "\n";
return ErrorCode::NoError;
};
- auto cbReadStdErr = [&](const QString &data, libssh::Client &) {
- stdOut += data + "\n";
- return ErrorCode::NoError;
- };
- ErrorCode error =
+ errorCode =
runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)),
- cbReadStdOut, cbReadStdErr);
+ cbReadStdOut);
+ if (errorCode)
+ return errorCode;
- if (stdOut.contains("doesn't work on cgroups v2"))
- return ErrorCode::ServerDockerOnCgroupsV2;
- if (stdOut.contains("cgroup mountpoint does not exist"))
- return ErrorCode::ServerCgroupMountpoint;
- if (stdOut.contains("have reached") && stdOut.contains("pull rate limit"))
- return ErrorCode::DockerPullRateLimit;
-
- return error;
+ return errorCode;
}
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
@@ -632,8 +607,6 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
vars.append({ { "$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() } });
// Amnezia wireguard vars
- vars.append({ { "$AWG_SUBNET_IP",
- amneziaWireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) } });
vars.append({ { "$AWG_SERVER_PORT", amneziaWireguarConfig.value(config_key::port).toString(protocols::awg::defaultPort) } });
vars.append({ { "$JUNK_PACKET_COUNT", amneziaWireguarConfig.value(config_key::junkPacketCount).toString() } });
@@ -646,9 +619,6 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
vars.append({ { "$UNDERLOAD_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::underloadPacketMagicHeader).toString() } });
vars.append({ { "$TRANSPORT_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::transportPacketMagicHeader).toString() } });
- vars.append({ { "$COOKIE_REPLY_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::cookieReplyPacketJunkSize).toString() } });
- vars.append({ { "$TRANSPORT_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::transportPacketJunkSize).toString() } });
-
// Socks5 proxy vars
vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } });
auto username = socks5ProxyConfig.value(config_key::userName).toString();
@@ -733,7 +703,7 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
QString transportProto = containerConfig.value(config_key::transport_proto).toString(defaultTransportProto);
// TODO reimplement with netstat
- QString script = QString("which lsof > /dev/null 2>&1 || true && sudo lsof -i -P -n 2>/dev/null | grep -E ':%1 ").arg(port);
+ QString script = QString("which lsof &>/dev/null || true && sudo lsof -i -P -n 2>/dev/null | grep -E ':%1 ").arg(port);
for (auto &port : fixedPorts) {
script = script.append("|:%1").arg(port);
}
@@ -781,6 +751,10 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, DockerContainer container)
{
+ if (credentials.userName == "root") {
+ return ErrorCode::NoError;
+ }
+
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
@@ -794,16 +768,8 @@ ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, D
const QString scriptData = amnezia::scriptData(SharedScriptType::check_user_in_sudo);
ErrorCode error = runScript(credentials, replaceVars(scriptData, genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
- if (credentials.userName != "root" && stdOut.contains("sudo:") && !stdOut.contains("uname:") && stdOut.contains("not found"))
- return ErrorCode::ServerSudoPackageIsNotPreinstalled;
- if (credentials.userName != "root" && !stdOut.contains("sudo") && !stdOut.contains("wheel"))
+ if (!stdOut.contains("sudo"))
return ErrorCode::ServerUserNotInSudo;
- if (stdOut.contains("can't cd to") || stdOut.contains("Permission denied") || stdOut.contains("No such file or directory"))
- return ErrorCode::ServerUserDirectoryNotAccessible;
- if (stdOut.contains("sudoers") || stdOut.contains("is not allowed to run sudo on"))
- return ErrorCode::ServerUserNotAllowedInSudoers;
- if (stdOut.contains("password is required"))
- return ErrorCode::ServerUserPasswordRequired;
return error;
}
@@ -835,7 +801,7 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
if (stdOut.contains("Packet manager not found"))
return ErrorCode::ServerPacketManagerError;
- if (stdOut.contains("fuser not installed") || stdOut.contains("cat not installed"))
+ if (stdOut.contains("fuser not installed"))
return ErrorCode::NoError;
if (stdOut.isEmpty()) {
diff --git a/client/core/controllers/vpnConfigurationController.cpp b/client/core/controllers/vpnConfigurationController.cpp
index 61287972..52f42c42 100644
--- a/client/core/controllers/vpnConfigurationController.cpp
+++ b/client/core/controllers/vpnConfigurationController.cpp
@@ -77,7 +77,8 @@ ErrorCode VpnConfigurationsController::createProtocolConfigString(const bool isA
}
QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPair &dns, const QJsonObject &serverConfig,
- const QJsonObject &containerConfig, const DockerContainer container)
+ const QJsonObject &containerConfig, const DockerContainer container,
+ ErrorCode &errorCode)
{
QJsonObject vpnConfiguration {};
@@ -102,8 +103,7 @@ QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPair &settings, QSharedPointer serverController,
- QObject *parent = nullptr);
+ explicit VpnConfigurationsController(const std::shared_ptr &settings, QSharedPointer serverController, QObject *parent = nullptr);
public slots:
ErrorCode createProtocolConfigForContainer(const ServerCredentials &credentials, const DockerContainer container,
@@ -22,7 +21,7 @@ public slots:
const DockerContainer container, const QJsonObject &containerConfig, const Proto protocol,
QString &protocolConfigString);
QJsonObject createVpnConfiguration(const QPair &dns, const QJsonObject &serverConfig,
- const QJsonObject &containerConfig, const DockerContainer container);
+ const QJsonObject &containerConfig, const DockerContainer container, ErrorCode &errorCode);
static void updateContainerConfigAfterInstallation(const DockerContainer container, QJsonObject &containerConfig, const QString &stdOut);
signals:
diff --git a/client/core/defs.h b/client/core/defs.h
index 64f52ce6..c0db2e12 100644
--- a/client/core/defs.h
+++ b/client/core/defs.h
@@ -6,6 +6,9 @@
namespace amnezia
{
+
+ constexpr const qint16 qrMagicCode = 1984;
+
struct ServerCredentials
{
QString hostName;
@@ -44,7 +47,6 @@ namespace amnezia
InternalError = 101,
NotImplementedError = 102,
AmneziaServiceNotRunning = 103,
- NotSupportedOnThisPlatform = 104,
// Server errors
ServerCheckFailed = 200,
@@ -54,13 +56,6 @@ namespace amnezia
ServerCancelInstallation = 204,
ServerUserNotInSudo = 205,
ServerPacketManagerError = 206,
- ServerSudoPackageIsNotPreinstalled = 207,
- ServerUserDirectoryNotAccessible = 208,
- ServerUserNotAllowedInSudoers = 209,
- ServerUserPasswordRequired = 210,
- ServerDockerOnCgroupsV2 = 211,
- ServerCgroupMountpoint = 212,
- DockerPullRateLimit = 213,
// Ssh connection errors
SshRequestDeniedError = 300,
@@ -102,7 +97,6 @@ namespace amnezia
// import and install errors
ImportInvalidConfigError = 900,
ImportOpenConfigError = 901,
- NoInstalledContainersError = 902,
// Android errors
AndroidError = 1000,
@@ -116,10 +110,6 @@ namespace amnezia
ApiMissingAgwPublicKey = 1105,
ApiConfigDecryptionError = 1106,
ApiServicesMissingError = 1107,
- ApiConfigLimitError = 1108,
- ApiNotFoundError = 1109,
- ApiMigrationError = 1110,
- ApiUpdateRequestError = 1111,
// QFile errors
OpenError = 1200,
diff --git a/client/core/enums/apiEnums.h b/client/core/enums/apiEnums.h
new file mode 100644
index 00000000..1f050007
--- /dev/null
+++ b/client/core/enums/apiEnums.h
@@ -0,0 +1,9 @@
+#ifndef APIENUMS_H
+#define APIENUMS_H
+
+enum ApiConfigSources {
+ Telegram = 1,
+ AmneziaGateway
+};
+
+#endif // APIENUMS_H
diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp
index bd5ccaba..70f433c6 100644
--- a/client/core/errorstrings.cpp
+++ b/client/core/errorstrings.cpp
@@ -12,7 +12,6 @@ QString errorString(ErrorCode code) {
case(ErrorCode::UnknownError): errorMessage = QObject::tr("Unknown error"); break;
case(ErrorCode::NotImplementedError): errorMessage = QObject::tr("Function not implemented"); break;
case(ErrorCode::AmneziaServiceNotRunning): errorMessage = QObject::tr("Background service is not running"); break;
- case(ErrorCode::NotSupportedOnThisPlatform): errorMessage = QObject::tr("The selected protocol is not supported on the current platform"); break;
// Server errors
case(ErrorCode::ServerCheckFailed): errorMessage = QObject::tr("Server check failed"); break;
@@ -20,15 +19,8 @@ QString errorString(ErrorCode code) {
case(ErrorCode::ServerContainerMissingError): errorMessage = QObject::tr("Server error: Docker container missing"); break;
case(ErrorCode::ServerDockerFailedError): errorMessage = QObject::tr("Server error: Docker failed"); break;
case(ErrorCode::ServerCancelInstallation): errorMessage = QObject::tr("Installation canceled by user"); break;
- case(ErrorCode::ServerUserNotInSudo): errorMessage = QObject::tr("The user is not a member of the sudo group"); break;
- case(ErrorCode::ServerPacketManagerError): errorMessage = QObject::tr("Server error: Package manager error"); break;
- case(ErrorCode::ServerSudoPackageIsNotPreinstalled): errorMessage = QObject::tr("The sudo package is not pre-installed on the server"); break;
- case(ErrorCode::ServerUserDirectoryNotAccessible): errorMessage = QObject::tr("The server user's home directory is not accessible"); break;
- case(ErrorCode::ServerUserNotAllowedInSudoers): errorMessage = QObject::tr("Action not allowed in sudoers"); break;
- case(ErrorCode::ServerUserPasswordRequired): errorMessage = QObject::tr("The user's password is required"); break;
- case(ErrorCode::ServerDockerOnCgroupsV2): errorMessage = QObject::tr("Docker error: runc doesn't work on cgroups v2"); break;
- case(ErrorCode::ServerCgroupMountpoint): errorMessage = QObject::tr("Server error: cgroup mountpoint does not exist"); break;
- case(ErrorCode::DockerPullRateLimit): errorMessage = QObject::tr("Docker error: The pull rate limit has been reached"); break;
+ case(ErrorCode::ServerUserNotInSudo): errorMessage = QObject::tr("The user does not have permission to use sudo"); break;
+ case(ErrorCode::ServerPacketManagerError): errorMessage = QObject::tr("Server error: Packet manager error"); break;
// Libssh errors
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
@@ -59,7 +51,6 @@ QString errorString(ErrorCode code) {
case (ErrorCode::ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break;
case (ErrorCode::ImportOpenConfigError): errorMessage = QObject::tr("Unable to open config file"); break;
- case(ErrorCode::NoInstalledContainersError): errorMessage = QObject::tr("VPN Protocols is not installed.\n Please install VPN container at first"); break;
// Android errors
case (ErrorCode::AndroidError): errorMessage = QObject::tr("VPN connection error"); break;
@@ -73,10 +64,6 @@ QString errorString(ErrorCode code) {
case (ErrorCode::ApiMissingAgwPublicKey): errorMessage = QObject::tr("Missing AGW public key"); break;
case (ErrorCode::ApiConfigDecryptionError): errorMessage = QObject::tr("Failed to decrypt response payload"); break;
case (ErrorCode::ApiServicesMissingError): errorMessage = QObject::tr("Missing list of available services"); break;
- case (ErrorCode::ApiConfigLimitError): errorMessage = QObject::tr("The limit of allowed configurations per subscription has been exceeded"); break;
- case (ErrorCode::ApiNotFoundError): errorMessage = QObject::tr("Error when retrieving configuration from API"); break;
- case (ErrorCode::ApiMigrationError): errorMessage = QObject::tr("A migration error has occurred. Please contact our technical support"); break;
- case (ErrorCode::ApiUpdateRequestError): errorMessage = QObject::tr("Please update the application to use this feature"); break;
// QFile errors
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
diff --git a/client/core/ipcclient.cpp b/client/core/ipcclient.cpp
index 69edcd15..b44da1bf 100644
--- a/client/core/ipcclient.cpp
+++ b/client/core/ipcclient.cpp
@@ -5,12 +5,12 @@ IpcClient *IpcClient::m_instance = nullptr;
IpcClient::IpcClient(QObject *parent) : QObject(parent)
{
+
}
IpcClient::~IpcClient()
{
- if (m_localSocket)
- m_localSocket->close();
+ if (m_localSocket) m_localSocket->close();
}
bool IpcClient::isSocketConnected() const
@@ -25,15 +25,13 @@ IpcClient *IpcClient::Instance()
QSharedPointer IpcClient::Interface()
{
- if (!Instance())
- return nullptr;
+ if (!Instance()) return nullptr;
return Instance()->m_ipcClient;
}
QSharedPointer IpcClient::InterfaceTun2Socks()
{
- if (!Instance())
- return nullptr;
+ if (!Instance()) return nullptr;
return Instance()->m_Tun2SocksClient;
}
@@ -44,28 +42,15 @@ bool IpcClient::init(IpcClient *instance)
Instance()->m_localSocket = new QLocalSocket(Instance());
connect(Instance()->m_localSocket.data(), &QLocalSocket::connected, &Instance()->m_ClientNode, []() {
Instance()->m_ClientNode.addClientSideConnection(Instance()->m_localSocket.data());
- auto cliNode = Instance()->m_ClientNode.acquire();
- cliNode->waitForSource(5000);
- Instance()->m_ipcClient.reset(cliNode);
-
- if (!Instance()->m_ipcClient) {
- qWarning() << "IpcClient is not ready!";
- }
+ Instance()->m_ipcClient.reset(Instance()->m_ClientNode.acquire());
Instance()->m_ipcClient->waitForSource(1000);
if (!Instance()->m_ipcClient->isReplicaValid()) {
qWarning() << "IpcClient replica is not connected!";
}
- auto t2sNode = Instance()->m_ClientNode.acquire();
- t2sNode->waitForSource(5000);
- Instance()->m_Tun2SocksClient.reset(t2sNode);
-
- if (!Instance()->m_Tun2SocksClient) {
- qWarning() << "IpcClient::m_Tun2SocksClient is not ready!";
- }
-
+ Instance()->m_Tun2SocksClient.reset(Instance()->m_ClientNode.acquire());
Instance()->m_Tun2SocksClient->waitForSource(1000);
if (!Instance()->m_Tun2SocksClient->isReplicaValid()) {
@@ -73,8 +58,9 @@ bool IpcClient::init(IpcClient *instance)
}
});
- connect(Instance()->m_localSocket, &QLocalSocket::disconnected,
- [instance]() { instance->m_isSocketConnected = false; });
+ connect(Instance()->m_localSocket, &QLocalSocket::disconnected, [instance](){
+ instance->m_isSocketConnected = false;
+ });
Instance()->m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
Instance()->m_localSocket->waitForConnected();
@@ -91,7 +77,7 @@ bool IpcClient::init(IpcClient *instance)
QSharedPointer IpcClient::CreatePrivilegedProcess()
{
- if (!Instance()->m_ipcClient || !Instance()->m_ipcClient->isReplicaValid()) {
+ if (! Instance()->m_ipcClient || ! Instance()->m_ipcClient->isReplicaValid()) {
qWarning() << "IpcClient::createPrivilegedProcess : IpcClient IpcClient replica is not valid";
return nullptr;
}
@@ -114,15 +100,18 @@ QSharedPointer IpcClient::CreatePrivilegedProcess()
pd->ipcProcess.reset(priv);
if (!pd->ipcProcess) {
qWarning() << "Acquire PrivilegedProcess failed";
- } else {
+ }
+ else {
pd->ipcProcess->waitForSource(1000);
if (!pd->ipcProcess->isReplicaValid()) {
qWarning() << "PrivilegedProcess replica is not connected!";
}
- QObject::connect(pd->ipcProcess.data(), &PrivilegedProcess::destroyed, pd->ipcProcess.data(),
- [pd]() { pd->replicaNode->deleteLater(); });
+ QObject::connect(pd->ipcProcess.data(), &PrivilegedProcess::destroyed, pd->ipcProcess.data(), [pd](){
+ pd->replicaNode->deleteLater();
+ });
}
+
});
pd->localSocket->connectToServer(amnezia::getIpcProcessUrl(pid));
pd->localSocket->waitForConnected();
@@ -130,3 +119,5 @@ QSharedPointer IpcClient::CreatePrivilegedProcess()
auto processReplica = QSharedPointer(pd->ipcProcess);
return processReplica;
}
+
+
diff --git a/client/core/networkUtilities.cpp b/client/core/networkUtilities.cpp
index cf33fa55..a5825f0d 100644
--- a/client/core/networkUtilities.cpp
+++ b/client/core/networkUtilities.cpp
@@ -12,7 +12,6 @@
#include
#include
#include "qendian.h"
- #include
#endif
#ifdef Q_OS_LINUX
#include
@@ -186,17 +185,6 @@ int NetworkUtilities::AdapterIndexTo(const QHostAddress& dst) {
return 0;
}
-bool NetworkUtilities::checkIpv6Enabled() {
-#ifdef Q_OS_WIN
- QSettings RegHLM("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters",
- QSettings::NativeFormat);
- int ret = RegHLM.value("DisabledComponents", 0).toInt();
- qDebug() << "Check for Windows disabled IPv6 return " << ret;
- return (ret != 255);
-#endif
- return true;
-}
-
#ifdef Q_OS_WIN
DWORD GetAdaptersAddressesWrapper(const ULONG Family,
const ULONG Flags,
diff --git a/client/core/networkUtilities.h b/client/core/networkUtilities.h
index 1bd1114c..3057b852 100644
--- a/client/core/networkUtilities.h
+++ b/client/core/networkUtilities.h
@@ -5,7 +5,6 @@
#include
#include
#include
-#include
class NetworkUtilities : public QObject
@@ -16,7 +15,6 @@ public:
static QString getStringBetween(const QString &s, const QString &a, const QString &b);
static bool checkIPv4Format(const QString &ip);
static bool checkIpSubnetFormat(const QString &ip);
- static bool checkIpv6Enabled();
static QString getGatewayAndIface();
// Returns the Interface Index that could Route to dst
static int AdapterIndexTo(const QHostAddress& dst);
@@ -30,7 +28,9 @@ public:
static QString netMaskFromIpWithSubnet(const QString ip);
static QString ipAddressFromIpWithSubnet(const QString ip);
+
static QStringList summarizeRoutes(const QStringList &ips, const QString cidr);
+
};
#endif // NETWORKUTILITIES_H
diff --git a/client/core/qrCodeUtils.cpp b/client/core/qrCodeUtils.cpp
deleted file mode 100644
index a18af172..00000000
--- a/client/core/qrCodeUtils.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "qrCodeUtils.h"
-
-#include
-#include
-
-QList qrCodeUtils::generateQrCodeImageSeries(const QByteArray &data)
-{
- double k = 850;
-
- quint8 chunksCount = std::ceil(data.size() / k);
- QList chunks;
- for (int i = 0; i < data.size(); i = i + k) {
- QByteArray chunk;
- QDataStream s(&chunk, QIODevice::WriteOnly);
- s << qrCodeUtils::qrMagicCode << chunksCount << (quint8)std::round(i / k) << data.mid(i, k);
-
- QByteArray ba = chunk.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
-
- qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(ba, qrcodegen::QrCode::Ecc::LOW);
- QString svg = QString::fromStdString(toSvgString(qr, 1));
- chunks.append(svgToBase64(svg));
- }
-
- return chunks;
-}
-
-QString qrCodeUtils::svgToBase64(const QString &image)
-{
- return "data:image/svg;base64," + QString::fromLatin1(image.toUtf8().toBase64().data());
-}
-
-qrcodegen::QrCode qrCodeUtils::generateQrCode(const QByteArray &data)
-{
- return qrcodegen::QrCode::encodeText(data, qrcodegen::QrCode::Ecc::LOW);
-}
diff --git a/client/core/qrCodeUtils.h b/client/core/qrCodeUtils.h
deleted file mode 100644
index cda0723b..00000000
--- a/client/core/qrCodeUtils.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef QRCODEUTILS_H
-#define QRCODEUTILS_H
-
-#include
-
-#include "qrcodegen.hpp"
-
-namespace qrCodeUtils
-{
- constexpr const qint16 qrMagicCode = 1984;
-
- QList generateQrCodeImageSeries(const QByteArray &data);
- qrcodegen::QrCode generateQrCode(const QByteArray &data);
- QString svgToBase64(const QString &image);
-};
-
-#endif // QRCODEUTILS_H
diff --git a/client/core/serialization/vmess_new.cpp b/client/core/serialization/vmess_new.cpp
index 68d32203..6f3ec3e1 100644
--- a/client/core/serialization/vmess_new.cpp
+++ b/client/core/serialization/vmess_new.cpp
@@ -104,7 +104,7 @@ QJsonObject Deserialize(const QString &vmessStr, QString *alias, QString *errMes
server.users.first().security = "auto";
}
- const auto getQueryValue = [&query](const QString &key, const QString &defaultValue) {
+ const static auto getQueryValue = [&query](const QString &key, const QString &defaultValue) {
if (query.hasQueryItem(key))
return query.queryItemValue(key, QUrl::FullyDecoded);
else
diff --git a/client/daemon/daemon.cpp b/client/daemon/daemon.cpp
index 2faff0ef..a234860b 100644
--- a/client/daemon/daemon.cpp
+++ b/client/daemon/daemon.cpp
@@ -114,23 +114,12 @@ bool Daemon::activate(const InterfaceConfig& config) {
// Bring up the wireguard interface if not already done.
if (!wgutils()->interfaceExists()) {
- // Create the interface.
if (!wgutils()->addInterface(config)) {
logger.error() << "Interface creation failed.";
return false;
}
}
- // Bring the interface up.
- if (supportIPUtils()) {
- if (!iputils()->addInterfaceIPs(config)) {
- return false;
- }
- if (!iputils()->setMTUAndUp(config)) {
- return false;
- }
- }
-
// Configure routing for excluded addresses.
for (const QString& i : config.m_excludedAddresses) {
addExclusionRoute(IPAddress(i));
@@ -146,10 +135,20 @@ bool Daemon::activate(const InterfaceConfig& config) {
return false;
}
+ if (supportIPUtils()) {
+ if (!iputils()->addInterfaceIPs(config)) {
+ return false;
+ }
+ if (!iputils()->setMTUAndUp(config)) {
+ return false;
+ }
+ }
+
// set routing
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
if (!wgutils()->updateRoutePrefix(ip)) {
- logger.debug() << "Routing configuration failed for" << ip.toString();
+ logger.debug() << "Routing configuration failed for"
+ << logger.sensitive(ip.toString());
return false;
}
}
@@ -169,14 +168,11 @@ bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) {
if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
(config.m_hopType == InterfaceConfig::SingleHop)) {
QList resolvers;
- resolvers.append(QHostAddress(config.m_primaryDnsServer));
- if (!config.m_secondaryDnsServer.isEmpty()) {
- resolvers.append(QHostAddress(config.m_secondaryDnsServer));
- }
+ resolvers.append(QHostAddress(config.m_dnsServer));
// If the DNS is not the Gateway, it's a user defined DNS
// thus, not add any other :)
- if (config.m_primaryDnsServer == config.m_serverIpv4Gateway) {
+ if (config.m_dnsServer == config.m_serverIpv4Gateway) {
resolvers.append(QHostAddress(config.m_serverIpv6Gateway));
}
@@ -282,26 +278,15 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
config.m_serverIpv4Gateway = obj.value("serverIpv4Gateway").toString();
config.m_serverIpv6Gateway = obj.value("serverIpv6Gateway").toString();
- if (!obj.contains("primaryDnsServer")) {
- config.m_primaryDnsServer = QString();
+ if (!obj.contains("dnsServer")) {
+ config.m_dnsServer = QString();
} else {
- QJsonValue value = obj.value("primaryDnsServer");
+ QJsonValue value = obj.value("dnsServer");
if (!value.isString()) {
logger.error() << "dnsServer is not a string";
return false;
}
- config.m_primaryDnsServer = value.toString();
- }
-
- if (!obj.contains("secondaryDnsServer")) {
- config.m_secondaryDnsServer = QString();
- } else {
- QJsonValue value = obj.value("secondaryDnsServer");
- if (!value.isString()) {
- logger.error() << "dnsServer is not a string";
- return false;
- }
- config.m_secondaryDnsServer = value.toString();
+ config.m_dnsServer = value.toString();
}
if (!obj.contains("hopType")) {
@@ -384,9 +369,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
if (!parseStringList(obj, "vpnDisabledApps", config.m_vpnDisabledApps)) {
return false;
}
- if (!parseStringList(obj, "allowedDnsServers", config.m_allowedDnsServers)) {
- return false;
- }
config.m_killSwitchEnabled = QVariant(obj.value("killSwitchOption").toString()).toBool();
@@ -405,13 +387,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
if (!obj.value("S2").isNull()) {
config.m_responsePacketJunkSize = obj.value("S2").toString();
}
- if (!obj.value("S3").isNull()) {
- config.m_cookieReplyPacketJunkSize = obj.value("S3").toString();
- }
- if (!obj.value("S4").isNull()) {
- config.m_transportPacketJunkSize = obj.value("S4").toString();
- }
-
if (!obj.value("H1").isNull()) {
config.m_initPacketMagicHeader = obj.value("H1").toString();
}
@@ -425,34 +400,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
config.m_transportPacketMagicHeader = obj.value("H4").toString();
}
- if (!obj.value("I1").isNull()) {
- config.m_specialJunk["I1"] = obj.value("I1").toString();
- }
- if (!obj.value("I2").isNull()) {
- config.m_specialJunk["I2"] = obj.value("I2").toString();
- }
- if (!obj.value("I3").isNull()) {
- config.m_specialJunk["I3"] = obj.value("I3").toString();
- }
- if (!obj.value("I4").isNull()) {
- config.m_specialJunk["I4"] = obj.value("I4").toString();
- }
- if (!obj.value("I5").isNull()) {
- config.m_specialJunk["I5"] = obj.value("I5").toString();
- }
- if (!obj.value("J1").isNull()) {
- config.m_controlledJunk["J1"] = obj.value("J1").toString();
- }
- if (!obj.value("J2").isNull()) {
- config.m_controlledJunk["J2"] = obj.value("J2").toString();
- }
- if (!obj.value("J3").isNull()) {
- config.m_controlledJunk["J3"] = obj.value("J3").toString();
- }
- if (!obj.value("Itime").isNull()) {
- config.m_specialHandshakeTimeout = obj.value("Itime").toString();
- }
-
return true;
}
@@ -495,7 +442,7 @@ bool Daemon::deactivate(bool emitSignals) {
m_connections.clear();
// Delete the interface
- return wgutils()->deleteInterface();
+ return wgutils()->deleteInterface();
}
QString Daemon::logs() {
diff --git a/client/daemon/daemon.h b/client/daemon/daemon.h
index 757c9ff0..3d418d70 100644
--- a/client/daemon/daemon.h
+++ b/client/daemon/daemon.h
@@ -8,8 +8,6 @@
#include