mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-24 02:00:24 +07:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| acf8185ddb | |||
| aaf2c9ddeb | |||
| dbbc7119ec | |||
| c57162c4cc | |||
| 40e39895c9 | |||
| ec3ab2a03c | |||
| ddecfcad26 | |||
| 67bd880cdf | |||
| 477afb9d85 | |||
| f969fcdbb8 | |||
| b0ca16d861 | |||
| 9963359948 | |||
| ca639d293d | |||
| 83d045af64 | |||
| aea8ff4961 | |||
| 1892db4375 | |||
| c86a641e05 | |||
| befb2bf19a | |||
| 7ad6bc340c | |||
| 9164e38c34 | |||
| 8f7559f01b | |||
| af56200735 | |||
| 3874050fae | |||
| 3087163e34 | |||
| 1fa152845c | |||
| 50e23ef233 | |||
| ea648466de | |||
| b782775016 | |||
| 89a7fe1081 | |||
| e8bb096025 | |||
| fd5c7c8322 | |||
| e798d0f503 | |||
| bbb0abb596 | |||
| 0925aec86a | |||
| b084c4c284 | |||
| 87288ebccd | |||
| fcd7eadf4c | |||
| 0373338fb7 | |||
| 42f070fe9d |
@@ -1,56 +0,0 @@
|
||||
# .github/actions/setup-keychain/action.yml
|
||||
name: Setup apple keychain
|
||||
description: Creates and configures a temporary build keychain
|
||||
|
||||
inputs:
|
||||
keychain-path:
|
||||
description: Name of the keychain
|
||||
required: true
|
||||
keychain-password:
|
||||
description: Temporary keychain password
|
||||
required: true
|
||||
app-cert-base64:
|
||||
description: Base64-encoded P12 app certificate
|
||||
required: true
|
||||
app-cert-password:
|
||||
description: Application certificate password
|
||||
required: true
|
||||
installer-cert-base64:
|
||||
description: Base64-encoded P12 installer certificate
|
||||
required: true
|
||||
installer-cert-password:
|
||||
description: Installer certificate password
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Create keychain
|
||||
shell: bash
|
||||
env:
|
||||
KEYCHAIN_PATH: ${{ inputs.keychain-path }}
|
||||
KEYCHAIN_PASSWORD: ${{ inputs.keychain-password }}
|
||||
APP_CERT_BASE64: ${{ inputs.app-cert-base64 }}
|
||||
APP_CERT_PASSWORD: ${{ inputs.app-cert-password }}
|
||||
INSTALLER_CERT_BASE64: ${{ inputs.installer-cert-base64 }}
|
||||
INSTALLER_CERT_PASSWORD: ${{ inputs.installer-cert-password }}
|
||||
run: |
|
||||
set -e
|
||||
|
||||
APP_CERT_PATH=$RUNNER_TEMP/DeveloperIdApplicationCertificate.p12
|
||||
INSTALLER_CERT_PATH=$RUNNER_TEMP/DeveloperIdInstallerCertificate.p12
|
||||
|
||||
echo -n "$APP_CERT_BASE64" | base64 --decode -o "$APP_CERT_PATH"
|
||||
echo -n "$INSTALLER_CERT_BASE64" | base64 --decode -o "$INSTALLER_CERT_PATH"
|
||||
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
security default-keychain -s "$KEYCHAIN_PATH"
|
||||
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
|
||||
security import "${{ github.action_path }}/DeveloperIDG2CA.cer" -k "$KEYCHAIN_PATH" -A
|
||||
security import "$APP_CERT_PATH" -k "$KEYCHAIN_PATH" -P "$APP_CERT_PASSWORD" -A -t cert -f pkcs12
|
||||
security import "$INSTALLER_CERT_PATH" -k "$KEYCHAIN_PATH" -P "$INSTALLER_CERT_PASSWORD" -A -t cert -f pkcs12
|
||||
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
security list-keychain -d user -s "$KEYCHAIN_PATH"
|
||||
+199
-92
@@ -40,34 +40,44 @@ jobs:
|
||||
py7zrversion: '==0.22.*'
|
||||
extra: '--base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Setup python'
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.14
|
||||
|
||||
- name: 'Install conan'
|
||||
run: pip install "conan==2.26.2"
|
||||
|
||||
- name: 'Install system packages'
|
||||
run: sudo apt-get install libxkbcommon-x11-0 libsecret-1-dev
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: 'Get version from CMakeLists.txt'
|
||||
id: get_version
|
||||
run: |
|
||||
VERSION=$(grep 'set(AMNEZIAVPN_VERSION' CMakeLists.txt | sed -E 's/.*AMNEZIAVPN_VERSION ([0-9]+.[0-9]+.[0-9]+.[0-9]+)\)/\1/')
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
echo "Version: $VERSION"
|
||||
|
||||
# - name: 'Setup ccache'
|
||||
# uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Build project'
|
||||
shell: bash
|
||||
env:
|
||||
QT_INSTALL_DIR: ${{ runner.temp }}
|
||||
run: ./deploy/build.sh
|
||||
run: |
|
||||
sudo apt-get install libxkbcommon-x11-0 libsecret-1-dev
|
||||
export QT_BIN_DIR=${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/gcc_64/bin
|
||||
export QIF_BIN_DIR=${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin
|
||||
bash deploy/build_linux.sh
|
||||
|
||||
- name: 'Pack installer'
|
||||
run: cd deploy && tar -cf AmneziaVPN_Linux_Installer.tar AmneziaVPN_Linux_Installer.bin && zip AmneziaVPN_${VERSION}_linux_x64.tar.zip AmneziaVPN_Linux_Installer.tar
|
||||
|
||||
- name: 'Upload installer artifact'
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: deploy/build/AmneziaVPN-*-Linux.run
|
||||
archive: false
|
||||
name: AmneziaVPN_${{ env.VERSION }}_linux_x64.tar.zip
|
||||
path: deploy/AmneziaVPN_${{ env.VERSION }}_linux_x64.tar.zip
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload unpacked artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_Linux_unpacked
|
||||
path: deploy/AppDir
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload translations artifact'
|
||||
@@ -85,6 +95,7 @@ jobs:
|
||||
env:
|
||||
QT_VERSION: 6.10.1
|
||||
QIF_VERSION: 4.7
|
||||
BUILD_ARCH: 64
|
||||
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 }}
|
||||
@@ -100,6 +111,17 @@ jobs:
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: 'Get version from CMakeLists.txt'
|
||||
id: get_version
|
||||
shell: bash
|
||||
run: |
|
||||
VERSION=$(grep 'set(AMNEZIAVPN_VERSION' CMakeLists.txt | sed -E 's/.*AMNEZIAVPN_VERSION ([0-9]+.[0-9]+.[0-9]+.[0-9]+)\)/\1/')
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
echo "Version: $VERSION"
|
||||
|
||||
# - name: 'Setup ccache'
|
||||
# uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Install Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
@@ -136,34 +158,39 @@ jobs:
|
||||
$wixBinDir = Join-Path $env:USERPROFILE ".dotnet\tools"
|
||||
echo "WIX_BIN_DIR=$wixBinDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
|
||||
- name: 'Setup python'
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.14
|
||||
|
||||
- name: 'Install conan'
|
||||
run: pip install "conan==2.26.2"
|
||||
|
||||
- name: 'Build project'
|
||||
shell: cmd
|
||||
env:
|
||||
QT_INSTALL_DIR: ${{ runner.temp }}
|
||||
run: |
|
||||
set WIX_ROOT_PATH="${{ env.USERPROFILE }}\.dotnet\tools"
|
||||
deploy\build.bat --installer all
|
||||
set BUILD_ARCH=${{ env.BUILD_ARCH }}
|
||||
set QT_BIN_DIR="${{ runner.temp }}\\Qt\\${{ env.QT_VERSION }}\\msvc2022_64\\bin"
|
||||
set QIF_BIN_DIR="${{ runner.temp }}\\Qt\\Tools\\QtInstallerFramework\\${{ env.QIF_VERSION }}\\bin"
|
||||
set WIX_BIN_DIR=%USERPROFILE%\.dotnet\tools
|
||||
call deploy\\build_windows.bat
|
||||
|
||||
- name: 'Upload WIX installer artifact'
|
||||
uses: actions/upload-artifact@v7
|
||||
- name: 'Rename Windows installer'
|
||||
shell: cmd
|
||||
run: |
|
||||
copy AmneziaVPN_x${{ env.BUILD_ARCH }}.exe AmneziaVPN_%VERSION%_x64.exe
|
||||
|
||||
- name: 'Upload installer artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: deploy/build/AmneziaVPN-*-win64.msi
|
||||
archive: false
|
||||
name: AmneziaVPN_${{ env.VERSION }}_x64.exe
|
||||
path: AmneziaVPN_${{ env.VERSION }}_x64.exe
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload IFW installer artifact'
|
||||
uses: actions/upload-artifact@v7
|
||||
- name: 'Upload MSI installer artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: deploy/build/AmneziaVPN-*-win64.exe
|
||||
archive: false
|
||||
name: AmneziaVPN_Windows_MSI_installer
|
||||
path: AmneziaVPN_x${{ env.BUILD_ARCH }}.msi
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload unpacked artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_Windows_unpacked
|
||||
path: deploy\\build_${{ env.BUILD_ARCH }}\\client\\Release
|
||||
retention-days: 7
|
||||
|
||||
# ------------------------------------------------------
|
||||
@@ -231,13 +258,11 @@ jobs:
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: 'Setup python'
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.14
|
||||
# - name: 'Setup ccache'
|
||||
# uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Install deps'
|
||||
run: pip install "conan==2.26.2" jsonschema jinja2
|
||||
- name: 'Install dependencies'
|
||||
run: pip install jsonschema jinja2
|
||||
|
||||
- name: 'Build project'
|
||||
run: |
|
||||
@@ -260,6 +285,93 @@ jobs:
|
||||
IOS_APP_PROVISIONING_PROFILE: ${{ secrets.IOS_APP_PROVISIONING_PROFILE }}
|
||||
IOS_NE_PROVISIONING_PROFILE: ${{ secrets.IOS_NE_PROVISIONING_PROFILE }}
|
||||
|
||||
# - name: 'Upload appstore .ipa and dSYMs to artifacts'
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: app-store ipa & dsyms
|
||||
# path: |
|
||||
# ${{ github.workspace }}/AmneziaVPN-iOS.ipa
|
||||
# ${{ github.workspace }}/*.app.dSYM.zip
|
||||
# retention-days: 7
|
||||
|
||||
# ------------------------------------------------------
|
||||
|
||||
Build-MacOS-old:
|
||||
runs-on: macos-latest
|
||||
|
||||
env:
|
||||
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
|
||||
QT_VERSION: 6.4.3
|
||||
|
||||
MAC_TEAM_ID: ${{ secrets.MAC_TEAM_ID }}
|
||||
|
||||
MAC_APP_CERT_CERT: ${{ secrets.MAC_APP_CERT_CERT }}
|
||||
MAC_SIGNER_ID: ${{ secrets.MAC_SIGNER_ID }}
|
||||
MAC_APP_CERT_PW: ${{ secrets.MAC_APP_CERT_PW }}
|
||||
|
||||
MAC_INSTALLER_SIGNER_CERT: ${{ secrets.MAC_INSTALLER_SIGNER_CERT }}
|
||||
MAC_INSTALLER_SIGNER_ID: ${{ secrets.MAC_INSTALLER_SIGNER_ID }}
|
||||
MAC_INSTALL_CERT_PW: ${{ secrets.MAC_INSTALL_CERT_PW }}
|
||||
|
||||
APPLE_DEV_EMAIL: ${{ secrets.APPLE_DEV_EMAIL }}
|
||||
APPLE_DEV_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
|
||||
|
||||
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 -n
|
||||
|
||||
- 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:
|
||||
@@ -267,8 +379,19 @@ jobs:
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.10.1
|
||||
KEYCHAIN_NAME: "build.keychain"
|
||||
KEYCHAIN_PASSWORD: ""
|
||||
|
||||
MAC_TEAM_ID: ${{ secrets.MAC_TEAM_ID }}
|
||||
|
||||
MAC_APP_CERT_CERT: ${{ secrets.MAC_APP_CERT_CERT }}
|
||||
MAC_SIGNER_ID: ${{ secrets.MAC_SIGNER_ID }}
|
||||
MAC_APP_CERT_PW: ${{ secrets.MAC_APP_CERT_PW }}
|
||||
|
||||
MAC_INSTALLER_SIGNER_CERT: ${{ secrets.MAC_INSTALLER_SIGNER_CERT }}
|
||||
MAC_INSTALLER_SIGNER_ID: ${{ secrets.MAC_INSTALLER_SIGNER_ID }}
|
||||
MAC_INSTALL_CERT_PW: ${{ secrets.MAC_INSTALL_CERT_PW }}
|
||||
|
||||
APPLE_DEV_EMAIL: ${{ secrets.APPLE_DEV_EMAIL }}
|
||||
APPLE_DEV_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
|
||||
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||
@@ -299,48 +422,45 @@ jobs:
|
||||
py7zrversion: '==0.22.*'
|
||||
extra: '--base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Setup python'
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.14
|
||||
|
||||
- name: 'Install conan'
|
||||
run: pip install "conan==2.26.2"
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: 'Install certs'
|
||||
uses: ./.github/actions/setup-keychain
|
||||
with:
|
||||
keychain-path: ${{ env.KEYCHAIN_NAME }}
|
||||
keychain-password: ${{ env.KEYCHAIN_PASSWORD }}
|
||||
app-cert-base64: ${{ secrets.MAC_APP_CERT_CERT }}
|
||||
app-cert-password: ${{ secrets.MAC_APP_CERT_PW }}
|
||||
installer-cert-base64: ${{ secrets.MAC_INSTALLER_SIGNER_CERT }}
|
||||
installer-cert-password: ${{ secrets.MAC_INSTALL_CERT_PW }}
|
||||
- name: 'Get version from CMakeLists.txt'
|
||||
id: get_version
|
||||
run: |
|
||||
VERSION=$(grep 'set(AMNEZIAVPN_VERSION' CMakeLists.txt | sed -E 's/.*AMNEZIAVPN_VERSION ([0-9]+.[0-9]+.[0-9]+.[0-9]+)\)/\1/')
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
echo "Version: $VERSION"
|
||||
|
||||
# - name: 'Setup ccache'
|
||||
# uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Build project'
|
||||
env:
|
||||
QT_INSTALL_DIR: ${{ runner.temp }}
|
||||
CODESIGN_KEYCHAIN: ${{ env.KEYCHAIN_NAME }}
|
||||
CODESIGN_SIGNATURE: ${{ secrets.MAC_SIGNER_ID }}
|
||||
CODESIGN_INSTALLER_KEYCHAIN: ${{ env.KEYCHAIN_NAME }}
|
||||
CODESIGN_INSTALLER_SIGNATURE: ${{ secrets.MAC_INSTALLER_SIGNER_ID }}
|
||||
NOTARYTOOL_TEAM_ID: ${{ secrets.MAC_TEAM_ID }}
|
||||
NOTARYTOOL_EMAIL: ${{ secrets.APPLE_DEV_EMAIL }}
|
||||
NOTARYTOOL_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
|
||||
shell: bash
|
||||
run: deploy/build.sh
|
||||
run: |
|
||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
||||
bash deploy/build_macos.sh -n
|
||||
|
||||
- name: 'Pack macOS installer'
|
||||
run: |
|
||||
cd deploy/build/pkg
|
||||
zip -r ../../AmneziaVPN_${VERSION}_macos.zip AmneziaVPN.pkg
|
||||
cd ../../..
|
||||
|
||||
- name: 'Upload installer artifact'
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: deploy/build/AmneziaVPN-*-Darwin.pkg
|
||||
archive: false
|
||||
name: AmneziaVPN_${{ env.VERSION }}_macos.zip
|
||||
path: deploy/AmneziaVPN_${{ env.VERSION }}_macos.zip
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload unpacked artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_MacOS_unpacked
|
||||
path: deploy/build/client/AmneziaVPN.app
|
||||
retention-days: 7
|
||||
|
||||
Build-MacOS-NE:
|
||||
@@ -399,13 +519,8 @@ jobs:
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: 'Setup python'
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.14
|
||||
|
||||
- name: 'Install conan'
|
||||
run: pip install "conan==2.26.2"
|
||||
# - name: 'Setup ccache'
|
||||
# uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: 'Build project'
|
||||
run: |
|
||||
@@ -537,14 +652,6 @@ jobs:
|
||||
run: |
|
||||
echo $KEYSTORE_BASE64 | base64 --decode > android.keystore
|
||||
|
||||
- name: 'Setup python'
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.14
|
||||
|
||||
- name: 'Install conan'
|
||||
run: pip install "conan==2.26.2"
|
||||
|
||||
- name: 'Build project'
|
||||
env:
|
||||
ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
|
||||
+40
-15
@@ -1,14 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
set(AMNEZIAVPN_VERSION 4.8.13.1)
|
||||
|
||||
set(QT_CREATOR_SKIP_PACKAGE_MANAGER_SETUP ON CACHE BOOL "" FORCE)
|
||||
set(CMAKE_PROJECT_TOP_LEVEL_INCLUDES
|
||||
${CMAKE_SOURCE_DIR}/cmake/platform_settings.cmake
|
||||
${CMAKE_SOURCE_DIR}/cmake/recipes_bootstrap.cmake
|
||||
${CMAKE_SOURCE_DIR}/cmake/conan_provider.cmake
|
||||
CACHE STRING "" FORCE)
|
||||
set(AMNEZIAVPN_VERSION 4.8.14.5)
|
||||
|
||||
project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
|
||||
DESCRIPTION "AmneziaVPN"
|
||||
@@ -19,7 +12,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 2107)
|
||||
set(APP_ANDROID_VERSION_CODE 2118)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(MZ_PLATFORM_NAME "linux")
|
||||
@@ -31,8 +24,6 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
|
||||
set(MZ_PLATFORM_NAME "android")
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "iOS")
|
||||
set(MZ_PLATFORM_NAME "ios")
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS")
|
||||
set(MZ_PLATFORM_NAME "ios")
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
|
||||
set(MZ_PLATFORM_NAME "wasm")
|
||||
endif()
|
||||
@@ -42,7 +33,7 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(APPLE)
|
||||
if(IOS OR CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||
if(IOS)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64")
|
||||
elseif(MACOS_NE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
|
||||
@@ -53,10 +44,44 @@ endif()
|
||||
|
||||
add_subdirectory(client)
|
||||
|
||||
if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||
if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||
add_subdirectory(service)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/deploy/installer/config.cmake)
|
||||
endif()
|
||||
|
||||
if ((LINUX AND NOT ANDROID) OR (APPLE AND NOT IOS AND NOT MACOS_NE AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS") OR (WIN32))
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/CPack.cmake)
|
||||
set(AMNEZIA_STAGE_DIR "${CMAKE_BINARY_DIR}/stage")
|
||||
|
||||
if(WIN32 AND NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||
file(TO_CMAKE_PATH "${AMNEZIA_STAGE_DIR}" AMNEZIA_STAGE_DIR_CMAKE)
|
||||
|
||||
set(CPACK_GENERATOR "WIX")
|
||||
set(CPACK_WIX_VERSION 4)
|
||||
set(CPACK_PACKAGE_NAME "AmneziaVPN")
|
||||
set(CPACK_PACKAGE_VENDOR "AmneziaVPN")
|
||||
set(CPACK_PACKAGE_VERSION ${AMNEZIAVPN_VERSION})
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "AmneziaVPN client")
|
||||
set(AMNEZIA_LICENSE_TXT "${CMAKE_BINARY_DIR}/LICENSE.txt")
|
||||
configure_file("${CMAKE_SOURCE_DIR}/LICENSE" "${AMNEZIA_LICENSE_TXT}" COPYONLY)
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${AMNEZIA_LICENSE_TXT}")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "AmneziaVPN")
|
||||
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
set(CPACK_PACKAGE_EXECUTABLES "AmneziaVPN" "AmneziaVPN")
|
||||
set(CPACK_WIX_UPGRADE_GUID "{2D55AC62-96D6-4692-8C05-0D85BBF95485}")
|
||||
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_SOURCE_DIR}/client/images/app.ico")
|
||||
|
||||
# WiX patches
|
||||
set(_AMNEZIA_WIX_PATCH_SERVICE "${CMAKE_SOURCE_DIR}/deploy/installer/wix/service_install_patch.xml")
|
||||
set(_AMNEZIA_WIX_PATCH_CLOSE_APP "${CMAKE_SOURCE_DIR}/deploy/installer/wix/close_client_patch.xml")
|
||||
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_SERVICE}" _AMNEZIA_WIX_PATCH_SERVICE_CMAKE)
|
||||
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_CLOSE_APP}" _AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE)
|
||||
set(CPACK_WIX_PATCH_FILE "${_AMNEZIA_WIX_PATCH_SERVICE_CMAKE};${_AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE}")
|
||||
|
||||
# WiX v4 Util extension for CloseApplication + namespace for util
|
||||
set(CPACK_WIX_EXTENSIONS "${CPACK_WIX_EXTENSIONS};WixToolset.Util.wixext")
|
||||
set(CPACK_WIX_CUSTOM_XMLNS "util=http://wixtoolset.org/schemas/v4/wxs/util")
|
||||
|
||||
set(CPACK_INSTALLED_DIRECTORIES "${AMNEZIA_STAGE_DIR_CMAKE};/")
|
||||
|
||||
include(CPack)
|
||||
endif()
|
||||
|
||||
@@ -179,7 +179,7 @@ You may face compiling issues in QT Creator after you've worked in Android Studi
|
||||
|
||||
## License
|
||||
|
||||
GPL v3.0
|
||||
This project is licensed under the GNU General Public License v3.0 (see LICENSE) and also includes third-party components distributed under their own terms (see THIRD_PARTY_LICENSES.md).
|
||||
|
||||
## Donate
|
||||
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
# Third-Party Licenses
|
||||
|
||||
This project is licensed under the GNU General Public License v3.0.
|
||||
This file lists third-party software components used by this repository.
|
||||
Each component is distributed under its own license as linked below.
|
||||
|
||||
---
|
||||
|
||||
## QtKeychain
|
||||
|
||||
- Source: https://github.com/frankosterfeld/qtkeychain
|
||||
- License: BSD License
|
||||
- License Text: https://www.gnu.org/licenses/license-list.html#ModifiedBSD
|
||||
|
||||
---
|
||||
|
||||
## QSimpleCrypto
|
||||
|
||||
- Source: https://github.com/n1flh31mur/QSimpleCrypto
|
||||
- License: Apache License 2.0
|
||||
- License Text: https://github.com/n1flh31mur/QSimpleCrypto/blob/master/LICENSE
|
||||
|
||||
---
|
||||
|
||||
## SortFilterProxyModel
|
||||
|
||||
- Source: https://github.com/oKcerG/SortFilterProxyModel
|
||||
- License: MIT License
|
||||
- License Text: https://github.com/oKcerG/SortFilterProxyModel/blob/master/LICENSE
|
||||
|
||||
---
|
||||
|
||||
## QJsonStruct
|
||||
|
||||
- Source: https://github.com/Qv2ray/QJsonStruct
|
||||
- License: MIT License
|
||||
- License Text: https://github.com/Qv2ray/QJsonStruct/blob/master/LICENSE
|
||||
|
||||
---
|
||||
|
||||
## QR Code Generator (qrcodegen)
|
||||
|
||||
- Source: https://github.com/nayuki/QR-Code-generator
|
||||
- License: MIT License
|
||||
- License Text: https://www.nayuki.io/page/qr-code-generator-library
|
||||
|
||||
---
|
||||
|
||||
## Qt Gamepad
|
||||
|
||||
- Source: https://github.com/qt/qtgamepad
|
||||
- License: GNU General Public License v3.0 (GPL-3.0)
|
||||
- License Text: https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
|
||||
---
|
||||
|
||||
## AmneziaWG Apple (WireGuard)
|
||||
|
||||
- Source: https://github.com/amnezia-vpn/amneziawg-apple
|
||||
- License: MIT License
|
||||
- License Text: https://github.com/amnezia-vpn/amneziawg-apple/blob/master/COPYING
|
||||
|
||||
---
|
||||
|
||||
## AmneziaWG Android
|
||||
|
||||
- Source: https://github.com/amnezia-vpn/amneziawg-go
|
||||
- License: MIT License
|
||||
- License Text: https://github.com/amnezia-vpn/amneziawg-go/blob/master/LICENSE
|
||||
|
||||
---
|
||||
|
||||
## Xray Core
|
||||
|
||||
- Source: https://github.com/XTLS/Xray-core
|
||||
- License: Mozilla Public License 2.0 (MPL-2.0)
|
||||
- License Text: https://github.com/XTLS/Xray-core/blob/main/LICENSE
|
||||
|
||||
---
|
||||
|
||||
## Cloak
|
||||
|
||||
- Source: https://github.com/cbeuw/Cloak
|
||||
- License: GNU General Public License v3.0 (GPL-3.0)
|
||||
- License Text: https://github.com/cbeuw/Cloak/blob/master/LICENSE
|
||||
|
||||
---
|
||||
|
||||
## Shadowsocks
|
||||
|
||||
- Source: https://github.com/shadowsocks/shadowsocks-libev
|
||||
- License: GPL-3.0-or-later
|
||||
- License Text: http://www.gnu.org/licenses/
|
||||
|
||||
---
|
||||
|
||||
## OpenSSL
|
||||
|
||||
- Source: https://github.com/openssl/openssl
|
||||
- License: Apache License 2.0
|
||||
- License Text: https://www.openssl.org/source/license.html
|
||||
|
||||
---
|
||||
|
||||
## libssh
|
||||
|
||||
- Source: https://www.libssh.org/
|
||||
- License: GNU Lesser General Public License (LGPL)
|
||||
- License Text: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
|
||||
|
||||
---
|
||||
|
||||
## OpenVPNAdapter
|
||||
|
||||
- Source: https://github.com/ss-abramchuk/OpenVPNAdapter
|
||||
- License: GNU Affero General Public License v3.0 (AGPL-3.0)
|
||||
- License Text: https://github.com/ss-abramchuk/OpenVPNAdapter/blob/master/LICENSE
|
||||
|
||||
---
|
||||
|
||||
## Wintun
|
||||
|
||||
- Source: https://www.wintun.net/
|
||||
- License: Prebuilt Binaries License
|
||||
- License Text: https://github.com/WireGuard/wintun/blob/master/prebuilt-binaries-license.txt
|
||||
|
||||
---
|
||||
|
||||
## Mullvad Split Tunnel Driver
|
||||
|
||||
- Source: https://github.com/mullvad/win-split-tunnel
|
||||
- License: GNU General Public License v3.0 (GPL-3.0) and Mozilla Public License Version 2.0
|
||||
- License Text: https://github.com/mullvad/win-split-tunnel/blob/master/LICENSE-GPL.md https://github.com/mullvad/win-split-tunnel/blob/master/LICENSE-MPL.txt
|
||||
|
||||
---
|
||||
|
||||
## tun2socks
|
||||
|
||||
- Source: https://github.com/eycorsican/go-tun2socks
|
||||
- License: MIT License
|
||||
- License Text: https://github.com/eycorsican/go-tun2socks/blob/master/LICENSE
|
||||
|
||||
---
|
||||
|
||||
## TAP-Windows Driver
|
||||
|
||||
- Source: https://github.com/OpenVPN/tap-windows6
|
||||
- License: tap-windows6 license
|
||||
- License Text: https://github.com/OpenVPN/tap-windows6/blob/master/COPYING
|
||||
@@ -1,340 +0,0 @@
|
||||
# AmneziaVPN Apple TV Build
|
||||
|
||||
This document describes how to build the current branch for Apple TV from the repository root.
|
||||
|
||||
The pipeline is:
|
||||
|
||||
1. Use a separately built static Qt 6.9.2 for `tvOS`.
|
||||
2. Let Conan build/provide C/C++ dependencies.
|
||||
3. Generate an Xcode project with `qt-cmake`.
|
||||
4. Build the `.app` and embedded Network Extension with `xcodebuild`.
|
||||
|
||||
Important:
|
||||
|
||||
- Run the project commands from the repository root.
|
||||
- This is a device build for `appletvos`, not a simulator build.
|
||||
- `xcodebuild build` produces `.app`.
|
||||
- `.ipa` is produced later via `archive` and `-exportArchive`.
|
||||
- The current tvOS Network Extension scope is WireGuard-only.
|
||||
- The temporary tvOS WireGuard bridge prebuilt is opt-in. The Conan recipe does not contain machine-specific fallback paths.
|
||||
- Do not initialize or update submodules just for this build. If a clean checkout has empty `client/3rd` folders, pass `AMNEZIA_THIRDPARTY_ROOT` to an already initialized read-only `client/3rd` tree.
|
||||
|
||||
## 1. Environment
|
||||
|
||||
Set these paths for your machine:
|
||||
|
||||
```bash
|
||||
export REPO_ROOT="$PWD"
|
||||
export QT_DESKTOP_PREFIX="$HOME/Qt/6.9.2/macos"
|
||||
export QT_TVOS_SRC="$HOME/Qt_tv/qt-6.9.2-tvos-src"
|
||||
export QT_TVOS_PREFIX="$HOME/Qt_tv/6.9.2/tvos-device"
|
||||
export BUILD_DIR="$REPO_ROOT/build-tvos-device-conan"
|
||||
```
|
||||
|
||||
If this checkout does not have initialized `client/3rd` sources, point CMake at an initialized tree:
|
||||
|
||||
```bash
|
||||
export AMNEZIA_THIRDPARTY_ROOT="/path/to/initialized/amnezia/client/3rd"
|
||||
```
|
||||
|
||||
If you are using a temporary prebuilt tvOS WireGuard bridge, point Conan at it explicitly:
|
||||
|
||||
```bash
|
||||
export AMNEZIA_TVOS_AWG_PREBUILT_DIR="/path/to/WireGuardKitGo-appletvos"
|
||||
export AMNEZIA_TVOS_AWG_VERSION_HEADER_DIR="/path/to/directory/with/wireguard-go-version.h"
|
||||
```
|
||||
|
||||
`AMNEZIA_TVOS_AWG_PREBUILT_DIR` must contain `libwg-go.a`.
|
||||
|
||||
`AMNEZIA_TVOS_AWG_VERSION_HEADER_DIR` is optional when `wireguard-go-version.h` lives in the same directory as `libwg-go.a`.
|
||||
|
||||
If the env vars are not set, the recipe uses the normal source build path. Rebuilding and publishing the tvOS WireGuard bridge through the registry is a separate task.
|
||||
|
||||
## 2. Required Local Tools
|
||||
|
||||
Conan must be available:
|
||||
|
||||
```bash
|
||||
uv tool install conan
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
conan --version
|
||||
```
|
||||
|
||||
Validated version:
|
||||
|
||||
```text
|
||||
Conan version 2.27.1
|
||||
```
|
||||
|
||||
The build uses Xcode's AppleTVOS SDK:
|
||||
|
||||
```bash
|
||||
xcrun --sdk appletvos --show-sdk-path
|
||||
```
|
||||
|
||||
## 3. Prepare Qt Sources
|
||||
|
||||
Do not edit the installed Qt sources in place. Copy them into a separate tvOS fork:
|
||||
|
||||
```bash
|
||||
mkdir -p "$HOME/Qt_tv"
|
||||
rsync -a "$HOME/Qt/6.9.2/Src/" "$QT_TVOS_SRC/"
|
||||
```
|
||||
|
||||
Recommended for reproducibility:
|
||||
|
||||
```bash
|
||||
cd "$QT_TVOS_SRC"
|
||||
git init
|
||||
git add .
|
||||
git commit -m "Qt 6.9.2 source snapshot"
|
||||
```
|
||||
|
||||
## 4. Apply the Qt tvOS Patchset
|
||||
|
||||
Apply the local Qt tvOS patchset to `$QT_TVOS_SRC`.
|
||||
|
||||
If you need to recreate the patchset from a fresh copy, compare these files against `$HOME/Qt/6.9.2/Src` and reapply the same changes:
|
||||
|
||||
- `qtbase/cmake/QtBaseGlobalTargets.cmake`
|
||||
- `qtbase/cmake/QtBaseHelpers.cmake`
|
||||
- `qtbase/cmake/QtBuildPathsHelpers.cmake`
|
||||
- `qtbase/cmake/QtMkspecHelpers.cmake`
|
||||
- `qtbase/cmake/QtConfig.cmake.in`
|
||||
- `qtbase/mkspecs/unsupported/macx-tvos-clang/qplatformdefs.h`
|
||||
- `qtbase/src/corelib/CMakeLists.txt`
|
||||
- `qtbase/src/corelib/platform/darwin/qdarwinpermissionplugin_location.mm`
|
||||
- `qtbase/src/gui/CMakeLists.txt`
|
||||
- `qtbase/src/widgets/CMakeLists.txt`
|
||||
- `qtbase/src/network/kernel/qnetworkproxy_darwin.cpp`
|
||||
- `qtbase/src/testlib/qtestcrashhandler.cpp`
|
||||
- `qtbase/src/plugins/platforms/ios/qiosapplicationdelegate.mm`
|
||||
- `qtbase/src/plugins/platforms/ios/qiosscreen.mm`
|
||||
- `qtbase/src/plugins/platforms/ios/qiostheme.mm`
|
||||
- `qtbase/src/plugins/platforms/ios/quiview.mm`
|
||||
- `qtbase/src/plugins/platforms/ios/qiosclipboard.mm`
|
||||
|
||||
Recommended after patching:
|
||||
|
||||
```bash
|
||||
git -C "$QT_TVOS_SRC" diff > "$HOME/Qt_tv/qt-6.9.2-tvos.patch"
|
||||
```
|
||||
|
||||
Do not use `QT_APPLE_SDK=appletvos`. The working path is `CMAKE_SYSTEM_NAME=tvOS` with `CMAKE_OSX_SYSROOT=appletvos`.
|
||||
|
||||
## 5. Build Qt 6.9.2 for Apple TV
|
||||
|
||||
Only the modules required by this project are built.
|
||||
|
||||
```bash
|
||||
mkdir -p /private/tmp/qt6.9.2-tvos-device-build
|
||||
cd /private/tmp/qt6.9.2-tvos-device-build
|
||||
|
||||
"$QT_TVOS_SRC/configure" \
|
||||
-release -static -appstore-compliant \
|
||||
-nomake tests -nomake examples \
|
||||
-submodules qtbase,qtdeclarative,qtshadertools,qtremoteobjects,qtsvg,qt5compat,qttools \
|
||||
-qt-host-path "$QT_DESKTOP_PREFIX" \
|
||||
-prefix "$QT_TVOS_PREFIX" \
|
||||
-- \
|
||||
-G Ninja \
|
||||
-DQT_QMAKE_TARGET_MKSPEC=macx-tvos-clang \
|
||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||
-DCMAKE_OSX_SYSROOT=appletvos \
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64 \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=17.0 \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DQT_NO_APPLE_SDK_MAX_VERSION_CHECK=ON
|
||||
|
||||
cmake --build . --parallel 8
|
||||
cmake --install .
|
||||
```
|
||||
|
||||
Sanity checks:
|
||||
|
||||
```bash
|
||||
"$QT_TVOS_PREFIX/bin/qt-cmake" --version
|
||||
"$QT_TVOS_PREFIX/bin/qmake" -query QMAKE_XSPEC
|
||||
```
|
||||
|
||||
Expected `QMAKE_XSPEC`:
|
||||
|
||||
```text
|
||||
macx-tvos-clang
|
||||
```
|
||||
|
||||
Return to the repository root after building Qt:
|
||||
|
||||
```bash
|
||||
cd "$REPO_ROOT"
|
||||
```
|
||||
|
||||
## 6. Conan Dependency Behavior
|
||||
|
||||
For `CMAKE_SYSTEM_NAME=tvOS`, the project-level Conan graph is intentionally reduced:
|
||||
|
||||
- included: `awg-apple/2.0.1`
|
||||
- included: `libssh/0.11.3@amnezia`
|
||||
- included: `openssl/3.6.1` with `no_apps=True`
|
||||
- excluded: `openvpnadapter`
|
||||
- excluded: `hev-socks5-tunnel`
|
||||
|
||||
This keeps the current Apple TV target in the same practical scope as before: app plus WireGuard-only Network Extension.
|
||||
|
||||
`libssh` is built with `WITH_EXEC=OFF` on tvOS because tvOS does not provide `fork()` or `execv()`.
|
||||
|
||||
## 7. Configure the Project
|
||||
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
"$QT_TVOS_PREFIX/bin/qt-cmake" \
|
||||
-B"$BUILD_DIR" \
|
||||
-GXcode \
|
||||
-DQT_HOST_PATH="$QT_DESKTOP_PREFIX" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||
-DCMAKE_OSX_SYSROOT=appletvos
|
||||
```
|
||||
|
||||
If you need to provide an external initialized `client/3rd` tree:
|
||||
|
||||
```bash
|
||||
"$QT_TVOS_PREFIX/bin/qt-cmake" \
|
||||
-B"$BUILD_DIR" \
|
||||
-GXcode \
|
||||
-DQT_HOST_PATH="$QT_DESKTOP_PREFIX" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||
-DCMAKE_OSX_SYSROOT=appletvos \
|
||||
-DAMNEZIA_THIRDPARTY_ROOT="$AMNEZIA_THIRDPARTY_ROOT"
|
||||
```
|
||||
|
||||
Expected non-fatal configure warnings:
|
||||
|
||||
```text
|
||||
Warning: plug-in QIOSIntegrationPlugin is not known to the current Qt installation.
|
||||
Warning: plug-in QJpegPlugin is not known to the current Qt installation.
|
||||
...
|
||||
```
|
||||
|
||||
In this repo those warnings are tolerated because `client/cmake/ios.cmake` also links the static plugin targets explicitly when available.
|
||||
|
||||
## 8. Build the Apple TV App
|
||||
|
||||
```bash
|
||||
xcodebuild -quiet \
|
||||
-project "$BUILD_DIR/AmneziaVPN.xcodeproj" \
|
||||
-scheme AmneziaVPN \
|
||||
-configuration RelWithDebInfo \
|
||||
-sdk appletvos \
|
||||
CODE_SIGNING_ALLOWED=NO \
|
||||
build
|
||||
```
|
||||
|
||||
Outputs:
|
||||
|
||||
- `$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app`
|
||||
- `$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/PlugIns/AmneziaVPNNetworkExtension.appex`
|
||||
|
||||
Verification:
|
||||
|
||||
```bash
|
||||
file "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/AmneziaVPN"
|
||||
file "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/PlugIns/AmneziaVPNNetworkExtension.appex/AmneziaVPNNetworkExtension"
|
||||
lipo -info "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/AmneziaVPN"
|
||||
lipo -info "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/PlugIns/AmneziaVPNNetworkExtension.appex/AmneziaVPNNetworkExtension"
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
Mach-O 64-bit executable arm64
|
||||
Non-fat file: ... is architecture: arm64
|
||||
```
|
||||
|
||||
Useful plist checks:
|
||||
|
||||
```bash
|
||||
plutil -p "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/Info.plist" | rg 'CFBundleIdentifier|DTPlatformName|UIDeviceFamily|MinimumOSVersion' -C 1
|
||||
plutil -p "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/PlugIns/AmneziaVPNNetworkExtension.appex/Info.plist" | rg 'CFBundleIdentifier|NSExtension|DTPlatformName|MinimumOSVersion' -C 1
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `DTPlatformName => appletvos`
|
||||
- `UIDeviceFamily => 3`
|
||||
- `MinimumOSVersion => 17.0`
|
||||
- extension point `com.apple.networkextension.packet-tunnel`
|
||||
|
||||
## 9. `.app` vs `.ipa`
|
||||
|
||||
This is the normal sequence:
|
||||
|
||||
1. `xcodebuild build` -> `.app`
|
||||
2. `xcodebuild archive` -> `.xcarchive`
|
||||
3. `xcodebuild -exportArchive` -> `.ipa`
|
||||
|
||||
So seeing `.app` after a successful `build` is correct.
|
||||
|
||||
## 10. Optional Archive and Export
|
||||
|
||||
The commands below are the next step for packaging, but signing and provisioning must be configured first.
|
||||
|
||||
Archive:
|
||||
|
||||
```bash
|
||||
xcodebuild \
|
||||
-project "$BUILD_DIR/AmneziaVPN.xcodeproj" \
|
||||
-scheme AmneziaVPN \
|
||||
-configuration RelWithDebInfo \
|
||||
-sdk appletvos \
|
||||
-archivePath "$BUILD_DIR/AmneziaVPN-tvos.xcarchive" \
|
||||
archive
|
||||
```
|
||||
|
||||
Export:
|
||||
|
||||
```bash
|
||||
xcodebuild -exportArchive \
|
||||
-archivePath "$BUILD_DIR/AmneziaVPN-tvos.xcarchive" \
|
||||
-exportPath "$BUILD_DIR/export-tvos" \
|
||||
-exportOptionsPlist /absolute/path/to/ExportOptions.plist
|
||||
```
|
||||
|
||||
The resulting `.ipa` should appear under:
|
||||
|
||||
```text
|
||||
$BUILD_DIR/export-tvos
|
||||
```
|
||||
|
||||
## 11. Known Non-Fatal Warnings
|
||||
|
||||
The validated `xcodebuild` still prints warnings that do not break the build:
|
||||
|
||||
- missing Swift search path under the active Xcode Metal toolchain
|
||||
- `SDKROOT[sdk=...]` target-level warnings generated by Xcode project export
|
||||
- Swift conditional compilation flag warnings such as `GROUP_ID="..."`
|
||||
- asset catalog warnings because the current icon set is still iOS-shaped, not a full tvOS Top Shelf asset set
|
||||
- Go/WireGuard umbrella-header warnings from the temporary local `libwg-go.a` bridge
|
||||
- deprecated libssh SCP API warnings in existing app code
|
||||
- `qt_import_plugins()` warnings shown during configure
|
||||
|
||||
If the static platform plugin is not linked correctly, the typical failure is:
|
||||
|
||||
- `_OBJC_CLASS_$_QIOSApplicationDelegate`
|
||||
- `_qt_main_wrapper`
|
||||
|
||||
Those are cleanup tasks, not blockers for the current build proof.
|
||||
|
||||
## 12. Fast Rebuild Checklist
|
||||
|
||||
If everything is already built once:
|
||||
|
||||
1. Reuse `$QT_TVOS_PREFIX`
|
||||
2. Reuse Conan cache under `$HOME/.conan2`
|
||||
3. Reuse or pass an initialized `AMNEZIA_THIRDPARTY_ROOT`
|
||||
4. Re-run `qt-cmake` into `$BUILD_DIR`
|
||||
5. Re-run `xcodebuild -quiet ... build`
|
||||
+1
-1
Submodule client/3rd-prebuilt updated: b8c229288d...51bb4703a4
+36
-36
@@ -3,9 +3,6 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||
set(PROJECT AmneziaVPN)
|
||||
project(${PROJECT})
|
||||
|
||||
set(AMNEZIA_THIRDPARTY_ROOT "${CMAKE_CURRENT_LIST_DIR}/3rd" CACHE PATH "Path to Amnezia client/3rd sources")
|
||||
get_filename_component(AMNEZIA_THIRDPARTY_CLIENT_ROOT "${AMNEZIA_THIRDPARTY_ROOT}/.." ABSOLUTE)
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER "Autogen")
|
||||
set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Autogen")
|
||||
@@ -36,7 +33,7 @@ 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(WIN32 OR (APPLE AND NOT IOS AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS") OR (LINUX AND NOT ANDROID))
|
||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||
set(PACKAGES ${PACKAGES} Widgets)
|
||||
endif()
|
||||
|
||||
@@ -49,7 +46,7 @@ set(LIBS ${LIBS}
|
||||
Qt6::Core5Compat Qt6::Concurrent
|
||||
)
|
||||
|
||||
if(WIN32 OR (APPLE AND NOT IOS AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS") OR (LINUX AND NOT ANDROID))
|
||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||
set(LIBS ${LIBS} Qt6::Widgets)
|
||||
endif()
|
||||
|
||||
@@ -59,7 +56,7 @@ target_include_directories(${PROJECT} PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
)
|
||||
|
||||
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS") OR (LINUX AND NOT ANDROID))
|
||||
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
|
||||
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep)
|
||||
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_interface.rep)
|
||||
endif()
|
||||
@@ -81,6 +78,7 @@ set(AMNEZIAVPN_TS_FILES
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE AMNEZIAVPN_TS_SOURCES *.qrc *.cpp *.h *.ui)
|
||||
list(FILTER AMNEZIAVPN_TS_SOURCES EXCLUDE REGEX "qtgamepad/examples")
|
||||
|
||||
qt_create_translation(AMNEZIAVPN_QM_FILES ${AMNEZIAVPN_TS_SOURCES} ${AMNEZIAVPN_TS_FILES})
|
||||
|
||||
@@ -111,7 +109,6 @@ include_directories(
|
||||
${CMAKE_CURRENT_LIST_DIR}/../ipc
|
||||
${CMAKE_CURRENT_LIST_DIR}/../common/logger
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${AMNEZIA_THIRDPARTY_CLIENT_ROOT}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
@@ -179,7 +176,7 @@ if(LINUX AND NOT ANDROID)
|
||||
link_directories(${CMAKE_CURRENT_LIST_DIR}/platforms/linux)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS") OR (LINUX AND NOT ANDROID))
|
||||
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
|
||||
add_compile_definitions(AMNEZIA_DESKTOP)
|
||||
endif()
|
||||
|
||||
@@ -187,8 +184,7 @@ if(ANDROID)
|
||||
include(cmake/android.cmake)
|
||||
endif()
|
||||
|
||||
if(IOS OR CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||
option(AMNEZIA_IOS_ENABLE_APPLETV_TARGET "Enable Apple TV target settings for iOS/Xcode projects" OFF)
|
||||
if(IOS)
|
||||
include(cmake/ios.cmake)
|
||||
include(cmake/ios-arch-fixup.cmake)
|
||||
elseif(APPLE AND MACOS_NE)
|
||||
@@ -201,6 +197,36 @@ endif()
|
||||
target_link_libraries(${PROJECT} PRIVATE ${LIBS})
|
||||
target_compile_definitions(${PROJECT} PRIVATE "MZ_$<UPPER_CASE:${MZ_PLATFORM_NAME}>")
|
||||
|
||||
# deploy artifacts required to run the application to the debug build folder
|
||||
if(WIN32)
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
set(DEPLOY_PLATFORM_PATH "windows/x64")
|
||||
else()
|
||||
set(DEPLOY_PLATFORM_PATH "windows/x32")
|
||||
endif()
|
||||
elseif(LINUX)
|
||||
set(DEPLOY_PLATFORM_PATH "linux/client")
|
||||
elseif(APPLE AND NOT IOS)
|
||||
set(DEPLOY_PLATFORM_PATH "macos")
|
||||
endif()
|
||||
|
||||
if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:Debug>,copy_directory,true>
|
||||
${CMAKE_SOURCE_DIR}/deploy/data/${DEPLOY_PLATFORM_PATH}
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:Debug>,copy_directory,true>
|
||||
${CMAKE_SOURCE_DIR}/client/3rd-prebuilt/deploy-prebuilt/${DEPLOY_PLATFORM_PATH}
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
|
||||
|
||||
# Finalize the executable so Qt can gather/deploy QML modules and plugins correctly (Android needs this).
|
||||
@@ -212,29 +238,3 @@ if(COMMAND qt_finalize_executable)
|
||||
else()
|
||||
qt_finalize_target(${PROJECT})
|
||||
endif()
|
||||
|
||||
if(NOT IOS AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||
install(TARGETS ${PROJECT}
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
COMPONENT AmneziaVPN
|
||||
)
|
||||
install(FILES $<TARGET_RUNTIME_DLLS:${PROJECT}>
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
COMPONENT AmneziaVPN
|
||||
)
|
||||
|
||||
set(deploy_tool_options "")
|
||||
if(WIN32)
|
||||
set(deploy_tool_options "--force-openssl --force")
|
||||
endif()
|
||||
|
||||
qt_generate_deploy_qml_app_script(
|
||||
TARGET ${PROJECT}
|
||||
OUTPUT_SCRIPT QT_DEPLOY_SCRIPT
|
||||
NO_UNSUPPORTED_PLATFORM_ERROR
|
||||
DEPLOY_TOOL_OPTIONS ${deploy_tool_options}
|
||||
)
|
||||
install(SCRIPT ${QT_DEPLOY_SCRIPT}
|
||||
COMPONENT AmneziaVPN
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -109,6 +109,16 @@ void AmneziaApplication::init()
|
||||
// install filter on main window
|
||||
if (auto win = qobject_cast<QQuickWindow*>(obj)) {
|
||||
win->installEventFilter(this);
|
||||
#ifdef Q_OS_ANDROID
|
||||
QObject::connect(win, &QQuickWindow::sceneGraphError,
|
||||
[](QQuickWindow::SceneGraphError, const QString &msg) {
|
||||
qWarning() << "Scene graph error (suppressed):" << msg;
|
||||
});
|
||||
// Keep graphics context alive across hide/show cycles to avoid
|
||||
// eglSwapBuffers/makeCurrent being called on a context Android has reclaimed.
|
||||
win->setPersistentSceneGraph(true);
|
||||
win->setPersistentGraphics(true);
|
||||
#endif
|
||||
win->show();
|
||||
}
|
||||
},
|
||||
@@ -250,7 +260,7 @@ bool AmneziaApplication::parseCommands()
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
void AmneziaApplication::startLocalServer() {
|
||||
const QString serverName("AmneziaVPNInstance");
|
||||
QLocalServer::removeServer(serverName);
|
||||
@@ -271,7 +281,7 @@ void AmneziaApplication::startLocalServer() {
|
||||
bool AmneziaApplication::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::Close) {
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
quit();
|
||||
#else
|
||||
if (m_forceQuit) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QThread>
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
#include <QGuiApplication>
|
||||
#else
|
||||
#include <QApplication>
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
#define AMNEZIA_BASE_CLASS QGuiApplication
|
||||
#else
|
||||
#define AMNEZIA_BASE_CLASS QApplication
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
void loadFonts();
|
||||
bool parseCommands();
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
void startLocalServer();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[versions]
|
||||
agp = "8.6.1"
|
||||
agp = "8.5.2"
|
||||
kotlin = "1.9.24"
|
||||
androidx-core = "1.13.1"
|
||||
androidx-activity = "1.9.1"
|
||||
androidx-annotation = "1.8.2"
|
||||
androidx-biometric = "1.2.0-alpha05"
|
||||
androidx-camera = "1.5.3"
|
||||
androidx-camera = "1.3.4"
|
||||
androidx-fragment = "1.8.2"
|
||||
androidx-security-crypto = "1.1.0-alpha06"
|
||||
androidx-datastore = "1.1.1"
|
||||
|
||||
@@ -75,6 +75,8 @@ private const val OPEN_FILE_ACTION_CODE = 3
|
||||
private const val CHECK_NOTIFICATION_PERMISSION_ACTION_CODE = 4
|
||||
|
||||
private const val PREFS_NOTIFICATION_PERMISSION_ASKED = "NOTIFICATION_PERMISSION_ASKED"
|
||||
private const val OPEN_FILE_AFTER_RESUME_DELAY_MS = 400L
|
||||
private const val KEY_PENDING_OPEN_FILE_URI = "pending_open_file_uri"
|
||||
|
||||
class AmneziaActivity : QtActivity() {
|
||||
|
||||
@@ -94,6 +96,8 @@ class AmneziaActivity : QtActivity() {
|
||||
private var isActivityResumed = false
|
||||
private var hasWindowFocus = false
|
||||
private val resumeHandler = Handler(Looper.getMainLooper())
|
||||
private var pendingOpenFileUri: String? = null
|
||||
private var openFileDeliveryScheduled = false
|
||||
|
||||
private val vpnServiceEventHandler: Handler by lazy(NONE) {
|
||||
object : Handler(Looper.getMainLooper()) {
|
||||
@@ -196,14 +200,24 @@ class AmneziaActivity : QtActivity() {
|
||||
doBindService()
|
||||
}
|
||||
)
|
||||
pendingOpenFileUri = savedInstanceState?.getString(KEY_PENDING_OPEN_FILE_URI)
|
||||
openFileDeliveryScheduled = false
|
||||
registerBroadcastReceivers()
|
||||
intent?.let(::processIntent)
|
||||
runBlocking { vpnProto = proto.await() }
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
pendingOpenFileUri?.let { outState.putString(KEY_PENDING_OPEN_FILE_URI, it) }
|
||||
}
|
||||
|
||||
private fun loadLibs() {
|
||||
listOf(
|
||||
"rsapss"
|
||||
"rsapss",
|
||||
"crypto_3",
|
||||
"ssl_3",
|
||||
"ssh"
|
||||
).forEach {
|
||||
loadSharedLibrary(this.applicationContext, it)
|
||||
}
|
||||
@@ -267,6 +281,7 @@ class AmneziaActivity : QtActivity() {
|
||||
hasWindowFocus = false
|
||||
// Cancel all pending operations when activity stops
|
||||
resumeHandler.removeCallbacksAndMessages(null)
|
||||
openFileDeliveryScheduled = false
|
||||
Log.d(TAG, "Stop Amnezia activity")
|
||||
doUnbindService()
|
||||
mainScope.launch {
|
||||
@@ -288,35 +303,31 @@ class AmneziaActivity : QtActivity() {
|
||||
}
|
||||
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
val deviceId = event.deviceId
|
||||
val keyCode = event.keyCode
|
||||
val pressed = event.action == KeyEvent.ACTION_DOWN
|
||||
val source = event.source
|
||||
|
||||
if (deviceId < 0 && pressed) {
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_BUTTON_A,
|
||||
KeyEvent.KEYCODE_BUTTON_B,
|
||||
KeyEvent.KEYCODE_BUTTON_X,
|
||||
KeyEvent.KEYCODE_BUTTON_Y,
|
||||
KeyEvent.KEYCODE_BUTTON_START,
|
||||
KeyEvent.KEYCODE_BUTTON_SELECT,
|
||||
KeyEvent.KEYCODE_DPAD_CENTER -> {
|
||||
nativeGamepadKeyEvent(0, keyCode, true)
|
||||
nativeGamepadKeyEvent(0, keyCode, false)
|
||||
KeyEvent.KEYCODE_BUTTON_SELECT -> {
|
||||
nativeGamepadKeyEvent(0, keyCode, pressed)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Real gamepad events (deviceId >= 0)
|
||||
if (deviceId >= 0) {
|
||||
val isGamepad = (source and InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD
|
||||
val isJoystick = (source and InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
|
||||
val isDpad = (source and InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
|
||||
if (isGamepad || isJoystick || isDpad) {
|
||||
nativeGamepadKeyEvent(deviceId, keyCode, pressed)
|
||||
return true
|
||||
KeyEvent.KEYCODE_DPAD_CENTER,
|
||||
KeyEvent.KEYCODE_DPAD_UP,
|
||||
KeyEvent.KEYCODE_DPAD_DOWN,
|
||||
KeyEvent.KEYCODE_DPAD_LEFT,
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||
val syntheticKeyCode = if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) KeyEvent.KEYCODE_ENTER else keyCode
|
||||
val synthetic = KeyEvent(
|
||||
event.downTime, event.eventTime, event.action, syntheticKeyCode,
|
||||
event.repeatCount, event.metaState, -1, event.scanCode,
|
||||
event.flags, InputDevice.SOURCE_KEYBOARD
|
||||
)
|
||||
return super.dispatchKeyEvent(synthetic)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,6 +341,7 @@ class AmneziaActivity : QtActivity() {
|
||||
isActivityResumed = false
|
||||
// Cancel all pending operations when activity pauses
|
||||
resumeHandler.removeCallbacksAndMessages(null)
|
||||
openFileDeliveryScheduled = false
|
||||
Log.d(TAG, "Pause Amnezia activity")
|
||||
}
|
||||
|
||||
@@ -338,6 +350,21 @@ class AmneziaActivity : QtActivity() {
|
||||
isActivityResumed = true
|
||||
Log.d(TAG, "Resume Amnezia activity")
|
||||
|
||||
if (pendingOpenFileUri != null && !openFileDeliveryScheduled) {
|
||||
val uri = pendingOpenFileUri!!
|
||||
openFileDeliveryScheduled = true
|
||||
resumeHandler.postDelayed({
|
||||
if (!isFinishing && !isDestroyed) {
|
||||
pendingOpenFileUri = null
|
||||
openFileDeliveryScheduled = false
|
||||
mainScope.launch {
|
||||
qtInitialized.await()
|
||||
QtAndroidController.onFileOpened(uri)
|
||||
}
|
||||
}
|
||||
}, OPEN_FILE_AFTER_RESUME_DELAY_MS)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
window.decorView.apply {
|
||||
invalidate()
|
||||
@@ -754,11 +781,15 @@ class AmneziaActivity : QtActivity() {
|
||||
grantUriPermission(packageName, this, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}?.toString() ?: ""
|
||||
Log.v(TAG, "Open file: $uri")
|
||||
if (uri.isNotEmpty()) {
|
||||
pendingOpenFileUri = uri
|
||||
} else {
|
||||
mainScope.launch {
|
||||
qtInitialized.await()
|
||||
QtAndroidController.onFileOpened(uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
showNoFileBrowserAlertDialog()
|
||||
@@ -785,7 +816,7 @@ class AmneziaActivity : QtActivity() {
|
||||
@Suppress("unused")
|
||||
fun getFd(fileName: String): Int {
|
||||
Log.v(TAG, "Get fd for $fileName")
|
||||
return blockingCall {
|
||||
return blockingCall(Dispatchers.IO) {
|
||||
try {
|
||||
pfd = contentResolver.openFileDescriptor(Uri.parse(fileName), "r")
|
||||
pfd?.fd ?: -1
|
||||
|
||||
@@ -33,7 +33,10 @@ class TvFilePicker : ComponentActivity() {
|
||||
return intent
|
||||
}
|
||||
}) {
|
||||
setResult(RESULT_OK, Intent().apply { data = it })
|
||||
setResult(RESULT_OK, Intent().apply {
|
||||
data = it
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
})
|
||||
finish()
|
||||
}
|
||||
|
||||
|
||||
+80
-12
@@ -1,19 +1,88 @@
|
||||
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||
set(AMNEZIA_THIRDPARTY_ROOT "${CLIENT_ROOT_DIR}/3rd" CACHE PATH "Path to Amnezia client/3rd sources")
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Modules;${CMAKE_MODULE_PATH}")
|
||||
|
||||
add_subdirectory(${AMNEZIA_THIRDPARTY_ROOT}/SortFilterProxyModel ${CMAKE_CURRENT_BINARY_DIR}/3rd/SortFilterProxyModel)
|
||||
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/SortFilterProxyModel)
|
||||
set(LIBS ${LIBS} SortFilterProxyModel)
|
||||
include(${CLIENT_ROOT_DIR}/cmake/QSimpleCrypto.cmake)
|
||||
|
||||
include(${AMNEZIA_THIRDPARTY_ROOT}/qrcodegen/qrcodegen.cmake)
|
||||
include(${CLIENT_ROOT_DIR}/3rd/qrcodegen/qrcodegen.cmake)
|
||||
|
||||
set(LIBSSH_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/libssh/")
|
||||
set(OPENSSL_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/openssl/")
|
||||
|
||||
set(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib")
|
||||
|
||||
if(WIN32)
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/windows/include")
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/windows/x86_64/ssh.lib")
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/windows/x86_64")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/windows/win64/libssl.lib")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win64/libcrypto.lib")
|
||||
else()
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/windows/x86/ssh.lib")
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/windows/x86")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libssl.lib")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib")
|
||||
endif()
|
||||
elseif(APPLE AND NOT IOS)
|
||||
if(MACOS_NE)
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/universal2/libssh.a")
|
||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/universal2/libz.a")
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/universal2")
|
||||
else()
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libssh.a")
|
||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libz.a")
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/x86_64")
|
||||
endif()
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/macos/include")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libssl.a")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libcrypto.a")
|
||||
elseif(IOS)
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/ios/arm64")
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/ios/arm64/libssh.a")
|
||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/ios/arm64/libz.a")
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/ios/iphone/include")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/ios/iphone/lib/libssl.a")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/ios/iphone/lib/libcrypto.a")
|
||||
elseif(ANDROID)
|
||||
set(abi ${CMAKE_ANDROID_ARCH_ABI})
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/android/${abi}")
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/android/${abi}/libssh.so")
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/android/include")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/android/${abi}/libssl.a")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/android/${abi}/libcrypto.a")
|
||||
set(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/android/${abi}")
|
||||
elseif(LINUX)
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/linux/x86_64")
|
||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/linux/x86_64/libz.a")
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/linux/x86_64/libssh.a")
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/linux/include")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/linux/x86_64/libssl.a")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/linux/x86_64/libcrypto.a")
|
||||
endif()
|
||||
|
||||
file(COPY ${OPENSSL_LIB_SSL_PATH} ${OPENSSL_LIB_CRYPTO_PATH}
|
||||
DESTINATION ${OPENSSL_LIBRARIES_DIR})
|
||||
|
||||
set(OPENSSL_USE_STATIC_LIBS TRUE)
|
||||
|
||||
set(LIBS ${LIBS}
|
||||
${LIBSSH_LIB_PATH}
|
||||
${ZLIB_LIB_PATH}
|
||||
)
|
||||
|
||||
set(LIBS ${LIBS}
|
||||
${OPENSSL_LIB_SSL_PATH}
|
||||
${OPENSSL_LIB_CRYPTO_PATH}
|
||||
)
|
||||
|
||||
add_compile_definitions(_WINSOCKAPI_)
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_WITH_QT6 ON)
|
||||
add_subdirectory(${AMNEZIA_THIRDPARTY_ROOT}/qtkeychain ${CMAKE_CURRENT_BINARY_DIR}/3rd/qtkeychain EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/qtkeychain)
|
||||
|
||||
if(ANDROID)
|
||||
# Use qtgamepad from amnezia-vpn/qtgamepad repository
|
||||
@@ -37,13 +106,12 @@ endif()
|
||||
set(LIBS ${LIBS} qt6keychain)
|
||||
|
||||
include_directories(
|
||||
${AMNEZIA_THIRDPARTY_ROOT}/QSimpleCrypto/src/include
|
||||
${AMNEZIA_THIRDPARTY_ROOT}/qtkeychain/qtkeychain
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${LIBSSH_INCLUDE_DIR}/include
|
||||
${LIBSSH_ROOT_DIR}/include
|
||||
${CLIENT_ROOT_DIR}/3rd/libssh/include
|
||||
${CLIENT_ROOT_DIR}/3rd/QSimpleCrypto/src/include
|
||||
${CLIENT_ROOT_DIR}/3rd/qtkeychain/qtkeychain
|
||||
${CMAKE_CURRENT_BINARY_DIR}/3rd/qtkeychain
|
||||
${CMAKE_CURRENT_BINARY_DIR}/3rd/libssh/include
|
||||
)
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
list(APPEND LIBS OpenSSL::SSL OpenSSL::Crypto)
|
||||
|
||||
find_package(libssh REQUIRED)
|
||||
list(APPEND LIBS ssh::ssh)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||
set(AMNEZIA_THIRDPARTY_ROOT "${CLIENT_ROOT_DIR}/3rd" CACHE PATH "Path to Amnezia client/3rd sources")
|
||||
set(QSIMPLECRYPTO_DIR ${AMNEZIA_THIRDPARTY_ROOT}/QSimpleCrypto/src)
|
||||
set(QSIMPLECRYPTO_DIR ${CLIENT_ROOT_DIR}/3rd/QSimpleCrypto/src)
|
||||
|
||||
include_directories(${QSIMPLECRYPTO_DIR})
|
||||
|
||||
|
||||
+14
-10
@@ -42,14 +42,18 @@ set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.cpp
|
||||
)
|
||||
|
||||
foreach(abi IN ITEMS ${QT_ANDROID_ABIS})
|
||||
set_property(TARGET ${PROJECT} PROPERTY QT_ANDROID_EXTRA_LIBS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/amneziawg/android/${abi}/libwg-go.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/libck-ovpn-plugin.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/libovpn3.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/libovpnutil.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/librsapss.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openssl/android/${abi}/libcrypto_3.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openssl/android/${abi}/libssl_3.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/libssh/android/${abi}/libssh.so
|
||||
)
|
||||
endforeach()
|
||||
|
||||
find_package(awg-android REQUIRED)
|
||||
set(LIBS ${LIBS} amnezia::awg-android)
|
||||
set_property(TARGET ${PROJECT} APPEND PROPERTY QT_ANDROID_EXTRA_LIBS ${AMNEZIA_ANDROID_LIBWG_PATH} ${AMNEZIA_ANDROID_LIBWG_QUICK_PATH})
|
||||
|
||||
find_package(amnezia-libxray REQUIRED)
|
||||
file(COPY ${AMNEZIA_LIBXRAY_PATH} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/android/xray/libXray)
|
||||
|
||||
find_package(openvpn-pt-android REQUIRED)
|
||||
set(LIBS ${LIBS} amnezia::openvpn-pt-android)
|
||||
set_property(TARGET ${PROJECT} APPEND PROPERTY QT_ANDROID_EXTRA_LIBS ${OPENVPN_PT_ANDROID_LIBCK_OVPN_PLUGIN_PATH})
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/xray/android/libxray.aar
|
||||
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/android/xray/libXray)
|
||||
|
||||
@@ -39,7 +39,5 @@ while(IOS_TARGETS)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES
|
||||
XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64"
|
||||
XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64"
|
||||
XCODE_ATTRIBUTE_ARCHS[sdk=appletvos*] "arm64"
|
||||
XCODE_ATTRIBUTE_ARCHS[sdk=appletvsimulator*] "arm64"
|
||||
)
|
||||
endwhile()
|
||||
+27
-132
@@ -1,19 +1,7 @@
|
||||
message("Client iOS build")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 13.0)
|
||||
set(APPLE_PROJECT_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
set(AMNEZIA_IOS_APPLETV ${AMNEZIA_IOS_ENABLE_APPLETV_TARGET})
|
||||
|
||||
if(AMNEZIA_IOS_APPLETV)
|
||||
message("Apple TV target mode is ON")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 17.0)
|
||||
set(QT_NO_SET_DEFAULT_IOS_LAUNCH_SCREEN TRUE)
|
||||
set(QT_NO_ADD_IOS_LAUNCH_SCREEN_TO_BUNDLE TRUE)
|
||||
set(IOS_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/ios/app/Info-tvOS.plist.in)
|
||||
set(IOS_LAUNCHSCREEN_STORYBOARD ${CMAKE_CURRENT_SOURCE_DIR}/ios/app/tvOS/AmneziaVPNLaunchScreen.storyboard)
|
||||
else()
|
||||
message("Apple TV target mode is OFF")
|
||||
set(IOS_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/ios/app/Info.plist.in)
|
||||
set(IOS_LAUNCHSCREEN_STORYBOARD ${CMAKE_CURRENT_SOURCE_DIR}/ios/app/AmneziaVPNLaunchScreen.storyboard)
|
||||
endif()
|
||||
|
||||
enable_language(OBJC)
|
||||
enable_language(OBJCXX)
|
||||
@@ -22,23 +10,13 @@ enable_language(Swift)
|
||||
find_package(Qt6 REQUIRED COMPONENTS ShaderTools)
|
||||
set(LIBS ${LIBS} Qt6::ShaderTools)
|
||||
|
||||
if(AMNEZIA_IOS_APPLETV)
|
||||
# Use framework linker flags directly for tvOS to avoid iPhoneOS SDK absolute paths.
|
||||
set(FW_AUTHENTICATIONSERVICES "-framework AuthenticationServices")
|
||||
set(FW_UIKIT "-framework UIKit")
|
||||
set(FW_AVFOUNDATION "-framework AVFoundation")
|
||||
set(FW_FOUNDATION "-framework Foundation")
|
||||
set(FW_STOREKIT "-framework StoreKit")
|
||||
set(FW_USERNOTIFICATIONS "-framework UserNotifications")
|
||||
else()
|
||||
find_library(FW_AUTHENTICATIONSERVICES AuthenticationServices)
|
||||
find_library(FW_UIKIT UIKit)
|
||||
find_library(FW_AVFOUNDATION AVFoundation)
|
||||
find_library(FW_FOUNDATION Foundation)
|
||||
find_library(FW_STOREKIT StoreKit)
|
||||
find_library(FW_USERNOTIFICATIONS UserNotifications)
|
||||
find_library(FW_NETWORKEXTENSION NetworkExtension)
|
||||
endif()
|
||||
find_library(FW_AUTHENTICATIONSERVICES AuthenticationServices)
|
||||
find_library(FW_UIKIT UIKit)
|
||||
find_library(FW_AVFOUNDATION AVFoundation)
|
||||
find_library(FW_FOUNDATION Foundation)
|
||||
find_library(FW_STOREKIT StoreKit)
|
||||
find_library(FW_USERNOTIFICATIONS UserNotifications)
|
||||
find_library(FW_NETWORKEXTENSION NetworkExtension)
|
||||
|
||||
set(LIBS ${LIBS}
|
||||
${FW_AUTHENTICATIONSERVICES}
|
||||
@@ -47,12 +25,9 @@ set(LIBS ${LIBS}
|
||||
${FW_FOUNDATION}
|
||||
${FW_STOREKIT}
|
||||
${FW_USERNOTIFICATIONS}
|
||||
${FW_NETWORKEXTENSION}
|
||||
)
|
||||
|
||||
if(NOT AMNEZIA_IOS_APPLETV)
|
||||
set(LIBS ${LIBS} ${FW_NETWORKEXTENSION})
|
||||
endif()
|
||||
|
||||
|
||||
set(HEADERS ${HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h
|
||||
@@ -82,7 +57,7 @@ target_include_directories(${PROJECT} PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
|
||||
|
||||
set_target_properties(${PROJECT} PROPERTIES
|
||||
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
|
||||
MACOSX_BUNDLE_INFO_PLIST ${IOS_INFO_PLIST}
|
||||
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/ios/app/Info.plist.in
|
||||
MACOSX_BUNDLE_ICON_FILE "AppIcon"
|
||||
MACOSX_BUNDLE_INFO_STRING "AmneziaVPN"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPN"
|
||||
@@ -91,6 +66,7 @@ set_target_properties(${PROJECT} PROPERTIES
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${APPLE_PROJECT_VERSION}-${CMAKE_PROJECT_VERSION_TWEAK}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}"
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/ios/app/main.entitlements"
|
||||
XCODE_ATTRIBUTE_MARKETING_VERSION "${APPLE_PROJECT_VERSION}"
|
||||
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
|
||||
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPN"
|
||||
@@ -98,36 +74,13 @@ set_target_properties(${PROJECT} PROPERTIES
|
||||
XCODE_GENERATE_SCHEME TRUE
|
||||
XCODE_ATTRIBUTE_ENABLE_BITCODE "NO"
|
||||
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon"
|
||||
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
|
||||
XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY ON
|
||||
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
|
||||
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks"
|
||||
XCODE_EMBED_APP_EXTENSIONS networkextension
|
||||
)
|
||||
|
||||
if(AMNEZIA_IOS_APPLETV)
|
||||
set_target_properties(${PROJECT} PROPERTIES
|
||||
XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "appletvos appletvsimulator"
|
||||
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "3"
|
||||
XCODE_ATTRIBUTE_TVOS_DEPLOYMENT_TARGET "${CMAKE_OSX_DEPLOYMENT_TARGET}"
|
||||
XCODE_ATTRIBUTE_SDKROOT "appletvos"
|
||||
XCODE_ATTRIBUTE_SDKROOT[sdk=appletvos*] "appletvos"
|
||||
XCODE_ATTRIBUTE_SDKROOT[sdk=appletvsimulator*] "appletvsimulator"
|
||||
XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS "$(inherited) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)"
|
||||
XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS[sdk=appletvos*] "$(inherited) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)"
|
||||
XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS[sdk=appletvsimulator*] "$(inherited) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)"
|
||||
XCODE_ATTRIBUTE_EXCLUDED_LIBRARY_SEARCH_PATHS "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS*.sdk/usr/lib/swift"
|
||||
XCODE_ATTRIBUTE_EXCLUDED_FRAMEWORK_SEARCH_PATHS "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS*.sdk/System/Library/Frameworks"
|
||||
)
|
||||
set_target_properties(${PROJECT} PROPERTIES
|
||||
QT_IOS_PERMISSIONS ""
|
||||
)
|
||||
else()
|
||||
set_target_properties(${PROJECT} PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/ios/app/main.entitlements"
|
||||
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DEFINED DEPLOY)
|
||||
set_target_properties(${PROJECT} PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution"
|
||||
@@ -158,61 +111,7 @@ target_compile_options(${PROJECT} PRIVATE
|
||||
-DVPN_NE_BUNDLEID=\"${BUILD_IOS_APP_IDENTIFIER}.network-extension\"
|
||||
)
|
||||
|
||||
if(AMNEZIA_IOS_APPLETV)
|
||||
# qscnetworkreachability plugin links IOKit, which is unavailable on tvOS.
|
||||
qt_import_plugins(${PROJECT}
|
||||
NO_DEFAULT
|
||||
INCLUDE
|
||||
QIOSIntegrationPlugin
|
||||
QJpegPlugin
|
||||
QSvgPlugin
|
||||
QGifPlugin
|
||||
QICOPlugin
|
||||
QSvgIconPlugin
|
||||
QSecureTransportBackendPlugin
|
||||
EXCLUDE
|
||||
QSCNetworkReachabilityNetworkInformationPlugin
|
||||
QDarwinCameraPermissionPlugin
|
||||
)
|
||||
|
||||
# Static tvOS Qt build doesn't auto-link these plugin archives into the
|
||||
# Xcode target, but the app entry point lives in QIOSIntegrationPlugin.
|
||||
set(_amnezia_tvos_static_plugins
|
||||
Qt6::QIOSIntegrationPlugin
|
||||
Qt6::QIOSIntegrationPlugin_init
|
||||
Qt6::QJpegPlugin
|
||||
Qt6::QJpegPlugin_init
|
||||
Qt6::QSvgPlugin
|
||||
Qt6::QSvgPlugin_init
|
||||
Qt6::QGifPlugin
|
||||
Qt6::QGifPlugin_init
|
||||
Qt6::QICOPlugin
|
||||
Qt6::QICOPlugin_init
|
||||
Qt6::QSvgIconPlugin
|
||||
Qt6::QSvgIconPlugin_init
|
||||
Qt6::QSecureTransportBackendPlugin
|
||||
Qt6::QSecureTransportBackendPlugin_init
|
||||
)
|
||||
foreach(_amnezia_tvos_static_plugin IN LISTS _amnezia_tvos_static_plugins)
|
||||
if(TARGET ${_amnezia_tvos_static_plugin})
|
||||
target_link_libraries(${PROJECT} PRIVATE ${_amnezia_tvos_static_plugin})
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_amnezia_tvos_static_plugin)
|
||||
unset(_amnezia_tvos_static_plugins)
|
||||
|
||||
# Qt 6.9.2 iOS package links IOKit via Qt6::Core interface, but tvOS SDK
|
||||
# does not provide IOKit. Strip this single framework for Apple TV builds.
|
||||
get_target_property(_qtcore_iface_libs Qt6::Core INTERFACE_LINK_LIBRARIES)
|
||||
if(_qtcore_iface_libs)
|
||||
string(REPLACE "-framework IOKit;" "" _qtcore_iface_libs "${_qtcore_iface_libs}")
|
||||
string(REPLACE ";-framework IOKit" "" _qtcore_iface_libs "${_qtcore_iface_libs}")
|
||||
set_property(TARGET Qt6::Core PROPERTY INTERFACE_LINK_LIBRARIES "${_qtcore_iface_libs}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(AMNEZIA_THIRDPARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rd" CACHE PATH "Path to Amnezia client/3rd sources")
|
||||
set(WG_APPLE_SOURCE_DIR ${AMNEZIA_THIRDPARTY_ROOT}/amneziawg-apple/Sources)
|
||||
set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/amneziawg-apple/Sources)
|
||||
|
||||
target_sources(${PROJECT} PRIVATE
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosvpnprotocol.swift
|
||||
@@ -224,29 +123,25 @@ target_sources(${PROJECT} PRIVATE
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/VPNCController.swift
|
||||
)
|
||||
|
||||
if(IOS_LAUNCHSCREEN_STORYBOARD)
|
||||
target_sources(${PROJECT} PRIVATE
|
||||
${IOS_LAUNCHSCREEN_STORYBOARD}
|
||||
target_sources(${PROJECT} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/AmneziaVPNLaunchScreen.storyboard
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/Media.xcassets
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
|
||||
)
|
||||
)
|
||||
|
||||
set_property(TARGET ${PROJECT} APPEND PROPERTY RESOURCE
|
||||
${IOS_LAUNCHSCREEN_STORYBOARD}
|
||||
set_property(TARGET ${PROJECT} APPEND PROPERTY RESOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/AmneziaVPNLaunchScreen.storyboard
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/Media.xcassets
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
|
||||
)
|
||||
else()
|
||||
target_sources(${PROJECT} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/Media.xcassets
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
|
||||
)
|
||||
|
||||
set_property(TARGET ${PROJECT} APPEND PROPERTY RESOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/Media.xcassets
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
|
||||
)
|
||||
endif()
|
||||
)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@ set_target_properties(${PROJECT} PROPERTIES
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
|
||||
)
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE INTERNAL "" FORCE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
||||
|
||||
|
||||
set(HEADERS ${HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/macos_util.h
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
message("Client ==> MacOS NE build")
|
||||
|
||||
set_target_properties(${PROJECT} PROPERTIES MACOSX_BUNDLE TRUE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
||||
|
||||
set(APPLE_PROJECT_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
|
||||
@@ -151,6 +152,19 @@ message(${QtCore_location})
|
||||
|
||||
get_filename_component(QT_BIN_DIR_DETECTED "${QtCore_location}/../../../../../bin" ABSOLUTE)
|
||||
|
||||
add_custom_command(TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${QT_BIN_DIR_DETECTED}/macdeployqt $<TARGET_BUNDLE_DIR:AmneziaVPN> -appstore-compliant -qmldir=${CMAKE_CURRENT_SOURCE_DIR}
|
||||
set_property(TARGET ${PROJECT} PROPERTY XCODE_EMBED_FRAMEWORKS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos/OpenVPNAdapter.framework"
|
||||
)
|
||||
|
||||
set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos)
|
||||
target_link_libraries("AmneziaVPNNetworkExtension" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos/OpenVPNAdapter.framework")
|
||||
|
||||
add_custom_command(TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
$<TARGET_BUNDLE_DIR:AmneziaVPN>/Contents/Frameworks
|
||||
COMMAND /usr/bin/find "$<TARGET_BUNDLE_DIR:AmneziaVPN>/Contents/Frameworks/OpenVPNAdapter.framework" -name "*.sha256" -delete
|
||||
COMMAND /usr/bin/codesign --force --sign "Apple Distribution: Privacy Technologies OU"
|
||||
"$<TARGET_BUNDLE_DIR:AmneziaVPN>/Contents/Frameworks/OpenVPNAdapter.framework/Versions/Current/OpenVPNAdapter"
|
||||
COMMAND ${QT_BIN_DIR_DETECTED}/macdeployqt $<TARGET_BUNDLE_DIR:AmneziaVPN> -appstore-compliant -qmldir=${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Signing OpenVPNAdapter framework"
|
||||
)
|
||||
|
||||
@@ -39,7 +39,7 @@ set(HEADERS ${HEADERS}
|
||||
${CLIENT_ROOT_DIR}/mozilla/controllerimpl.h
|
||||
)
|
||||
|
||||
if(NOT IOS AND NOT MACOS_NE AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||
if(NOT IOS AND NOT MACOS_NE)
|
||||
set(HEADERS ${HEADERS}
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.h
|
||||
)
|
||||
@@ -89,14 +89,14 @@ set(SOURCES ${SOURCES}
|
||||
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.cpp
|
||||
)
|
||||
|
||||
if(NOT IOS AND NOT MACOS_NE AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||
if(NOT IOS AND NOT MACOS_NE)
|
||||
set(SOURCES ${SOURCES}
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
# Include native macOS platform helpers (dock/status-item)
|
||||
if(APPLE AND NOT IOS AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||
if(APPLE AND NOT IOS)
|
||||
list(APPEND HEADERS
|
||||
${CLIENT_ROOT_DIR}/platforms/macos/macosutils.h
|
||||
${CLIENT_ROOT_DIR}/platforms/macos/macosstatusicon.h
|
||||
@@ -175,7 +175,7 @@ if(WIN32)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS") OR (LINUX AND NOT ANDROID))
|
||||
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
|
||||
message("Client desktop build")
|
||||
add_compile_definitions(AMNEZIA_DESKTOP)
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
#include "openvpn_configurator.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QProcess>
|
||||
#include <QString>
|
||||
#include <QTemporaryDir>
|
||||
#include <QTemporaryFile>
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
#include <QGuiApplication>
|
||||
#else
|
||||
#include <QApplication>
|
||||
#endif
|
||||
|
||||
#include "core/networkUtilities.h"
|
||||
#include "containers/containers_defs.h"
|
||||
@@ -161,7 +165,7 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPair<QString,
|
||||
QString dnsConf = QString("\nscript-security 2\n"
|
||||
"up %1/update-resolv-conf.sh\n"
|
||||
"down %1/update-resolv-conf.sh\n")
|
||||
.arg(QCoreApplication::applicationDirPath());
|
||||
.arg(qApp->applicationDirPath());
|
||||
|
||||
config.append(dnsConf);
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "ssh_configurator.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QString>
|
||||
@@ -9,6 +8,11 @@
|
||||
#include <QTemporaryFile>
|
||||
#include <QThread>
|
||||
#include <qtimer.h>
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include <QGuiApplication>
|
||||
#else
|
||||
#include <QApplication>
|
||||
#endif
|
||||
|
||||
#include "core/server_defs.h"
|
||||
#include "utilities.h"
|
||||
@@ -20,7 +24,7 @@ SshConfigurator::SshConfigurator(std::shared_ptr<Settings> settings, const QShar
|
||||
|
||||
QString SshConfigurator::convertOpenSShKey(const QString &key)
|
||||
{
|
||||
#if !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)
|
||||
#if !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
QProcess p;
|
||||
p.setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
@@ -66,13 +70,13 @@ QString SshConfigurator::convertOpenSShKey(const QString &key)
|
||||
// DEAD CODE.
|
||||
void SshConfigurator::openSshTerminal(const ServerCredentials &credentials)
|
||||
{
|
||||
#if !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)
|
||||
#if !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
QProcess *p = new QProcess();
|
||||
p->setProcessChannelMode(QProcess::SeparateChannels);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
p->setProcessEnvironment(prepareEnv());
|
||||
p->setProgram(QCoreApplication::applicationDirPath() + "\\cygwin\\putty.exe");
|
||||
p->setProgram(qApp->applicationDirPath() + "\\cygwin\\putty.exe");
|
||||
|
||||
if (credentials.secretData.contains("PRIVATE KEY")) {
|
||||
// todo: connect by key
|
||||
@@ -96,10 +100,10 @@ QProcessEnvironment SshConfigurator::prepareEnv()
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
pathEnvVar.clear();
|
||||
pathEnvVar.prepend(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()) + "\\cygwin;");
|
||||
pathEnvVar.prepend(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()) + "\\openvpn;");
|
||||
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\cygwin;");
|
||||
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn;");
|
||||
#elif defined(Q_OS_MACX) && !defined(MACOS_NE)
|
||||
pathEnvVar.prepend(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()) + "/Contents/MacOS");
|
||||
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS");
|
||||
#endif
|
||||
|
||||
env.insert("PATH", pathEnvVar);
|
||||
|
||||
@@ -10,8 +10,10 @@ namespace apiDefs
|
||||
AmneziaFreeV3,
|
||||
AmneziaPremiumV1,
|
||||
AmneziaPremiumV2,
|
||||
AmneziaTrialV2,
|
||||
SelfHosted,
|
||||
ExternalPremium
|
||||
ExternalPremium,
|
||||
ExternalTrial
|
||||
};
|
||||
|
||||
enum ConfigSource {
|
||||
|
||||
@@ -58,18 +58,24 @@ apiDefs::ConfigType apiUtils::getConfigType(const QJsonObject &serverConfigObjec
|
||||
};
|
||||
case apiDefs::ConfigSource::AmneziaGateway: {
|
||||
constexpr QLatin1String servicePremium("amnezia-premium");
|
||||
constexpr QLatin1String serviceTrial("amnezia-trial");
|
||||
constexpr QLatin1String serviceFree("amnezia-free");
|
||||
constexpr QLatin1String serviceExternalPremium("external-premium");
|
||||
constexpr QLatin1String serviceExternalTrial("external-trial");
|
||||
|
||||
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 == serviceTrial) {
|
||||
return apiDefs::ConfigType::AmneziaTrialV2;
|
||||
} else if (serviceType == serviceFree) {
|
||||
return apiDefs::ConfigType::AmneziaFreeV3;
|
||||
} else if (serviceType == serviceExternalPremium) {
|
||||
return apiDefs::ConfigType::ExternalPremium;
|
||||
} else if (serviceType == serviceExternalTrial) {
|
||||
return apiDefs::ConfigType::ExternalTrial;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
@@ -133,7 +139,8 @@ amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList<QSslError> &ssl
|
||||
bool apiUtils::isPremiumServer(const QJsonObject &serverConfigObject)
|
||||
{
|
||||
static const QSet<apiDefs::ConfigType> premiumTypes = { apiDefs::ConfigType::AmneziaPremiumV1, apiDefs::ConfigType::AmneziaPremiumV2,
|
||||
apiDefs::ConfigType::ExternalPremium };
|
||||
apiDefs::ConfigType::AmneziaTrialV2, apiDefs::ConfigType::ExternalPremium,
|
||||
apiDefs::ConfigType::ExternalTrial };
|
||||
return premiumTypes.contains(getConfigType(serverConfigObject));
|
||||
}
|
||||
|
||||
@@ -177,7 +184,9 @@ QString apiUtils::getPremiumV1VpnKey(const QJsonObject &serverConfigObject)
|
||||
|
||||
QString apiUtils::getPremiumV2VpnKey(const QJsonObject &serverConfigObject)
|
||||
{
|
||||
if (apiUtils::getConfigType(serverConfigObject) != apiDefs::ConfigType::AmneziaPremiumV2) {
|
||||
auto configType = apiUtils::getConfigType(serverConfigObject);
|
||||
if (configType != apiDefs::ConfigType::AmneziaPremiumV2 && configType != apiDefs::ConfigType::AmneziaTrialV2
|
||||
&& configType != apiDefs::ConfigType::ExternalPremium && configType != apiDefs::ConfigType::ExternalTrial) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#if defined(Q_OS_IOS)
|
||||
#include "platforms/ios/ios_controller.h"
|
||||
#include <AmneziaVPN-Swift.h>
|
||||
#endif
|
||||
@@ -135,7 +135,7 @@ void CoreController::initControllers()
|
||||
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_sitesController.reset(new SitesController(m_settings, m_sitesModel));
|
||||
m_engine->rootContext()->setContextProperty("SitesController", m_sitesController.get());
|
||||
|
||||
m_allowedDnsController.reset(new AllowedDnsController(m_settings, m_allowedDnsModel));
|
||||
@@ -196,7 +196,7 @@ void CoreController::initAndroidController()
|
||||
|
||||
void CoreController::initAppleController()
|
||||
{
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#ifdef Q_OS_IOS
|
||||
IosController::Instance()->initialize();
|
||||
connect(IosController::Instance(), &IosController::importConfigFromOutside, this, [this](QString data) {
|
||||
emit m_pageController->goToPageHome();
|
||||
@@ -233,7 +233,7 @@ void CoreController::initSignalHandlers()
|
||||
|
||||
void CoreController::initNotificationHandler()
|
||||
{
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS)
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
m_notificationHandler.reset(NotificationHandler::create(nullptr));
|
||||
|
||||
connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(),
|
||||
@@ -368,7 +368,11 @@ void CoreController::initPrepareConfigHandler()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_installController->isConfigValid()) {
|
||||
m_installController->validateConfig();
|
||||
});
|
||||
|
||||
connect(m_installController.get(), &InstallController::configValidated, this, [this](bool isValid) {
|
||||
if (!isValid) {
|
||||
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <QQmlContext>
|
||||
#include <QThread>
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS)
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
#include "ui/systemtray_notificationhandler.h"
|
||||
#endif
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
#include "ui/models/sites_model.h"
|
||||
#include "ui/models/newsModel.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS)
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
#include "ui/notificationhandler.h"
|
||||
#endif
|
||||
|
||||
@@ -99,7 +99,7 @@ private:
|
||||
QSharedPointer<VpnConnection> m_vpnConnection;
|
||||
QSharedPointer<QTranslator> m_translator;
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS)
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
QScopedPointer<NotificationHandler> m_notificationHandler;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -337,6 +337,9 @@ QStringList GatewayController::getProxyUrls(const QString &serviceType, const QS
|
||||
} else {
|
||||
baseUrls = QString(PROD_S3_ENDPOINT).split(", ");
|
||||
}
|
||||
std::random_device randomDevice;
|
||||
std::mt19937 generator(randomDevice());
|
||||
std::shuffle(baseUrls.begin(), baseUrls.end(), generator);
|
||||
|
||||
QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)
|
||||
#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -404,7 +404,7 @@ QPair<QString, QNetworkInterface> NetworkUtilities::getGatewayAndIface()
|
||||
close(sock);
|
||||
return { gateway_address, QNetworkInterface::interfaceFromName(interface) };
|
||||
#endif
|
||||
#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)
|
||||
#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
QString gateway;
|
||||
int index = -1;
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleAllowMixedLocalizations</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${QT_INTERNAL_DOLLAR_VAR}{PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array/>
|
||||
<key>UIRequiresFullScreen</key>
|
||||
<true/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>AmneziaVPNLaunchScreen</string>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>Light</string>
|
||||
<key>com.wireguard.ios.app_group_id</key>
|
||||
<string>group.org.amnezia.AmneziaVPN</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<false/>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="13122.16" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<viewLayoutGuide key="safeArea" id="wu6-TO-1qx"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,14 +1,6 @@
|
||||
enable_language(Swift)
|
||||
|
||||
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
|
||||
set(AMNEZIA_THIRDPARTY_ROOT "${CLIENT_ROOT_DIR}/3rd" CACHE PATH "Path to Amnezia client/3rd sources")
|
||||
set(AMNEZIA_IOS_APPLETV ${AMNEZIA_IOS_ENABLE_APPLETV_TARGET})
|
||||
|
||||
if(AMNEZIA_IOS_APPLETV)
|
||||
message("Network Extension tvOS mode is ON")
|
||||
else()
|
||||
message("Network Extension tvOS mode is OFF")
|
||||
endif()
|
||||
|
||||
add_executable(networkextension)
|
||||
set_target_properties(networkextension PROPERTIES
|
||||
@@ -36,23 +28,6 @@ set_target_properties(networkextension PROPERTIES
|
||||
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../../Frameworks"
|
||||
)
|
||||
|
||||
if(AMNEZIA_IOS_APPLETV)
|
||||
set_target_properties(networkextension PROPERTIES
|
||||
XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "appletvos appletvsimulator"
|
||||
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "3"
|
||||
XCODE_ATTRIBUTE_TVOS_DEPLOYMENT_TARGET "${CMAKE_OSX_DEPLOYMENT_TARGET}"
|
||||
XCODE_ATTRIBUTE_SDKROOT "appletvos"
|
||||
XCODE_ATTRIBUTE_SDKROOT[sdk=appletvos*] "appletvos"
|
||||
XCODE_ATTRIBUTE_SDKROOT[sdk=appletvsimulator*] "appletvsimulator"
|
||||
XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS "$(inherited) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)"
|
||||
XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS[sdk=appletvos*] "$(inherited) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)"
|
||||
XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS[sdk=appletvsimulator*] "$(inherited) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)"
|
||||
XCODE_ATTRIBUTE_EXCLUDED_LIBRARY_SEARCH_PATHS "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS*.sdk/usr/lib/swift"
|
||||
XCODE_ATTRIBUTE_EXCLUDED_FRAMEWORK_SEARCH_PATHS "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS*.sdk/System/Library/Frameworks"
|
||||
LINKER_LANGUAGE Swift
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DEPLOY)
|
||||
set_target_properties(networkextension PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution"
|
||||
@@ -70,49 +45,38 @@ endif()
|
||||
set_target_properties(networkextension PROPERTIES
|
||||
XCODE_ATTRIBUTE_SWIFT_VERSION "5.0"
|
||||
XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES"
|
||||
XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/WireGuardNetworkExtension-Bridging-Header.h"
|
||||
XCODE_ATTRIBUTE_SWIFT_OPTIMIZATION_LEVEL "-Onone"
|
||||
XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO"
|
||||
)
|
||||
|
||||
set_target_properties(networkextension PROPERTIES
|
||||
XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/WireGuardNetworkExtension-Bridging-Header.h"
|
||||
)
|
||||
|
||||
set_target_properties("networkextension" PROPERTIES
|
||||
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK"
|
||||
)
|
||||
|
||||
find_library(FW_ASSETS_LIBRARY AssetsLibrary)
|
||||
find_library(FW_MOBILE_CORE MobileCoreServices)
|
||||
find_library(FW_UI_KIT UIKit)
|
||||
find_library(FW_LIBRESOLV libresolv.9.tbd)
|
||||
|
||||
if(NOT AMNEZIA_IOS_APPLETV)
|
||||
target_link_libraries(networkextension PRIVATE ${FW_UI_KIT})
|
||||
target_link_libraries(networkextension PRIVATE ${FW_LIBRESOLV})
|
||||
else()
|
||||
target_link_libraries(networkextension PRIVATE -lresolv)
|
||||
endif()
|
||||
target_link_libraries(networkextension PRIVATE ${FW_ASSETS_LIBRARY})
|
||||
target_link_libraries(networkextension PRIVATE ${FW_MOBILE_CORE})
|
||||
target_link_libraries(networkextension PRIVATE ${FW_UI_KIT})
|
||||
target_link_libraries(networkextension PRIVATE ${FW_LIBRESOLV})
|
||||
|
||||
target_compile_options(networkextension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
|
||||
target_compile_options(networkextension PRIVATE -DNETWORK_EXTENSION=1)
|
||||
|
||||
set(WG_APPLE_SOURCE_DIR ${AMNEZIA_THIRDPARTY_ROOT}/amneziawg-apple/Sources)
|
||||
set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/amneziawg-apple/Sources)
|
||||
|
||||
set(NE_COMMON_SOURCES
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/NELogController.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/Log.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift
|
||||
)
|
||||
|
||||
set(NE_WIREGUARD_SOURCES
|
||||
target_sources(networkextension PRIVATE
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/WireGuardAdapter.swift
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/PacketTunnelSettingsGenerator.swift
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/DNSResolver.swift
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardNetworkExtension/ErrorNotifier.swift
|
||||
${WG_APPLE_SOURCE_DIR}/Shared/Keychain.swift
|
||||
${WG_APPLE_SOURCE_DIR}/Shared/FileManager+Extension.swift
|
||||
${WG_APPLE_SOURCE_DIR}/Shared/Model/NETunnelProviderProtocol+Extension.swift
|
||||
${WG_APPLE_SOURCE_DIR}/Shared/Model/TunnelConfiguration+WgQuickConfig.swift
|
||||
${WG_APPLE_SOURCE_DIR}/Shared/Model/NETunnelProviderProtocol+Extension.swift
|
||||
${WG_APPLE_SOURCE_DIR}/Shared/Model/String+ArrayConversion.swift
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/TunnelConfiguration.swift
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/IPAddressRange.swift
|
||||
@@ -120,50 +84,24 @@ set(NE_WIREGUARD_SOURCES
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/DNSServer.swift
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/InterfaceConfiguration.swift
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/PeerConfiguration.swift
|
||||
${WG_APPLE_SOURCE_DIR}/Shared/FileManager+Extension.swift
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKitC/x25519.c
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/Array+ConcurrentMap.swift
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/IPAddress+AddrInfo.swift
|
||||
${WG_APPLE_SOURCE_DIR}/WireGuardKit/PrivateKey.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+WireGuard.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/WGConfig.swift
|
||||
)
|
||||
|
||||
set(NE_XRAY_SOURCES
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/HevSocksTunnel.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+Xray.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/XrayConfig.swift
|
||||
)
|
||||
|
||||
set(NE_OPENVPN_SOURCES
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/NELogController.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/Log.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+WireGuard.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+OpenVPN.swift
|
||||
)
|
||||
|
||||
set(NE_APPLE_GLUE_SOURCES
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+Xray.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/WGConfig.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/XrayConfig.swift
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm
|
||||
)
|
||||
|
||||
if(AMNEZIA_IOS_APPLETV)
|
||||
list(APPEND NE_APPLE_GLUE_SOURCES
|
||||
${CLIENT_ROOT_DIR}/platforms/ios/tvos_cgo_stubs.c
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(networkextension PRIVATE ${NE_COMMON_SOURCES})
|
||||
|
||||
if(NOT AMNEZIA_IOS_APPLETV)
|
||||
target_sources(networkextension PRIVATE
|
||||
${NE_WIREGUARD_SOURCES}
|
||||
${NE_OPENVPN_SOURCES}
|
||||
${NE_XRAY_SOURCES}
|
||||
${NE_APPLE_GLUE_SOURCES}
|
||||
)
|
||||
else()
|
||||
target_sources(networkextension PRIVATE
|
||||
${NE_WIREGUARD_SOURCES}
|
||||
${NE_APPLE_GLUE_SOURCES}
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(networkextension PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
|
||||
)
|
||||
@@ -172,16 +110,21 @@ set_property(TARGET networkextension APPEND PROPERTY RESOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
|
||||
)
|
||||
|
||||
## Build wireguard-go-version.h
|
||||
execute_process(
|
||||
COMMAND go list -m golang.zx2c4.com/wireguard
|
||||
WORKING_DIRECTORY ${CLIENT_ROOT_DIR}/3rd/wireguard-apple/Sources/WireGuardKitGo
|
||||
OUTPUT_VARIABLE WG_VERSION_FULL
|
||||
)
|
||||
string(REGEX REPLACE ".*v\([0-9.]*\).*" "\\1" WG_VERSION_STRING 1.1.1)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/wireguard-go-version.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h)
|
||||
target_sources(networkextension PRIVATE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h)
|
||||
|
||||
target_include_directories(networkextension PRIVATE ${CLIENT_ROOT_DIR})
|
||||
target_include_directories(networkextension PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
find_package(awg-apple REQUIRED)
|
||||
target_link_libraries(networkextension PRIVATE amnezia::awg-apple)
|
||||
target_link_libraries(networkextension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/ios/arm64/libwg-go.a)
|
||||
|
||||
if(NOT AMNEZIA_IOS_APPLETV)
|
||||
find_package(openvpnadapter REQUIRED)
|
||||
target_link_libraries(networkextension PRIVATE amnezia::openvpnadapter)
|
||||
|
||||
find_package(hev-socks5-tunnel REQUIRED)
|
||||
target_link_libraries(networkextension PRIVATE heiher::hev-socks5-tunnel)
|
||||
endif()
|
||||
target_link_libraries(networkextension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef WIREGUARD_GO_VERSION
|
||||
#define WIREGUARD_GO_VERSION "@WG_VERSION_STRING@"
|
||||
#endif // WIREGUARD_GO_VERSION
|
||||
@@ -114,14 +114,25 @@ set_property(TARGET AmneziaVPNNetworkExtension APPEND PROPERTY RESOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
|
||||
)
|
||||
|
||||
## Build wireguard-go-version.h
|
||||
execute_process(
|
||||
COMMAND go list -m golang.zx2c4.com/wireguard
|
||||
WORKING_DIRECTORY ${CLIENT_ROOT_DIR}/3rd/wireguard-apple/Sources/WireGuardKitGo
|
||||
OUTPUT_VARIABLE WG_VERSION_FULL
|
||||
)
|
||||
string(REGEX REPLACE ".*v\([0-9.]*\).*" "\\1" WG_VERSION_STRING 1.1.1)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/wireguard-go-version.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h)
|
||||
target_sources(AmneziaVPNNetworkExtension PRIVATE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h)
|
||||
|
||||
target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR})
|
||||
target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
find_package(openvpnadapter REQUIRED)
|
||||
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE amnezia::openvpnadapter)
|
||||
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/macos/universal2/libwg-go.a)
|
||||
|
||||
find_package(awg-apple REQUIRED)
|
||||
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE amnezia::awg-apple)
|
||||
message(${CLIENT_ROOT_DIR})
|
||||
message(${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a)
|
||||
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a)
|
||||
|
||||
find_package(hev-socks5-tunnel REQUIRED)
|
||||
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE heiher::hev-socks5-tunnel)
|
||||
target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/Headers)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef WIREGUARD_GO_VERSION
|
||||
#define WIREGUARD_GO_VERSION "@WG_VERSION_STRING@"
|
||||
#endif // WIREGUARD_GO_VERSION
|
||||
+4
-3
@@ -12,11 +12,11 @@
|
||||
#include "Windows.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#if defined(Q_OS_IOS)
|
||||
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
||||
#endif
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
bool isAnotherInstanceRunning()
|
||||
{
|
||||
QLocalSocket socket;
|
||||
@@ -47,7 +47,7 @@ int main(int argc, char *argv[])
|
||||
AmneziaApplication app(argc, argv);
|
||||
OsSignalHandler::setup();
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
if (isAnotherInstanceRunning()) {
|
||||
QTimer::singleShot(1000, &app, [&]() { app.quit(); });
|
||||
return app.exec();
|
||||
@@ -75,6 +75,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
qInfo().noquote() << QString("Started %1 version %2 %3").arg(APPLICATION_NAME, APP_VERSION, GIT_COMMIT_HASH);
|
||||
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||
qInfo().noquote() << QString("SSL backend: %1").arg(QSslSocket::sslLibraryVersionString());
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -126,8 +126,13 @@ extension PacketTunnelProvider {
|
||||
}
|
||||
|
||||
vpnReachability.startTracking { [weak self] status in
|
||||
guard status == .reachableViaWiFi else { return }
|
||||
self?.ovpnAdapter?.reconnect(afterTimeInterval: 5)
|
||||
switch status {
|
||||
case .reachableViaWiFi, .reachableViaWWAN:
|
||||
ovpnLog(.info, message: "Reachability changed, reconnecting OpenVPN session")
|
||||
self?.ovpnAdapter?.reconnect(afterTimeInterval: 1)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
startHandler = completionHandler
|
||||
|
||||
@@ -21,6 +21,44 @@ extension Constants {
|
||||
}
|
||||
|
||||
extension PacketTunnelProvider {
|
||||
private func applyXraySplitTunnel(_ xrayConfig: XrayConfig,
|
||||
settings: NEPacketTunnelNetworkSettings) {
|
||||
guard let splitTunnelType = xrayConfig.splitTunnelType else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let splitTunnelSites = xrayConfig.splitTunnelSites else {
|
||||
xrayLog(.error, message: "Split tunnel sites are not set")
|
||||
return
|
||||
}
|
||||
|
||||
if splitTunnelType == 1 {
|
||||
var ipv4IncludedRoutes = [NEIPv4Route]()
|
||||
|
||||
for allowedIPString in splitTunnelSites {
|
||||
if let allowedIP = IPAddressRange(from: allowedIPString) {
|
||||
ipv4IncludedRoutes.append(NEIPv4Route(
|
||||
destinationAddress: "\(allowedIP.address)",
|
||||
subnetMask: "\(allowedIP.subnetMask())"))
|
||||
}
|
||||
}
|
||||
|
||||
settings.ipv4Settings?.includedRoutes = ipv4IncludedRoutes
|
||||
} else if splitTunnelType == 2 {
|
||||
var ipv4ExcludedRoutes = [NEIPv4Route]()
|
||||
|
||||
for excludedIPString in splitTunnelSites {
|
||||
if let excludedIP = IPAddressRange(from: excludedIPString) {
|
||||
ipv4ExcludedRoutes.append(NEIPv4Route(
|
||||
destinationAddress: "\(excludedIP.address)",
|
||||
subnetMask: "\(excludedIP.subnetMask())"))
|
||||
}
|
||||
}
|
||||
|
||||
settings.ipv4Settings?.excludedRoutes = ipv4ExcludedRoutes
|
||||
}
|
||||
}
|
||||
|
||||
func startXray(completionHandler: @escaping (Error?) -> Void) {
|
||||
|
||||
// Xray configuration
|
||||
@@ -72,6 +110,7 @@ extension PacketTunnelProvider {
|
||||
settings.dnsSettings = !dnsArray.isEmpty
|
||||
? NEDNSSettings(servers: dnsArray)
|
||||
: NEDNSSettings(servers: ["1.1.1.1"])
|
||||
applyXraySplitTunnel(xrayConfig, settings: settings)
|
||||
|
||||
let xrayConfigData = xrayConfig.config.data(using: .utf8)
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@ import NetworkExtension
|
||||
import Network
|
||||
import os
|
||||
import Darwin
|
||||
#if !os(tvOS)
|
||||
import OpenVPNAdapter
|
||||
#endif
|
||||
|
||||
enum TunnelProtoType: String {
|
||||
case wireguard, openvpn, xray
|
||||
@@ -40,22 +38,21 @@ struct Constants {
|
||||
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
var wgAdapter: WireGuardAdapter?
|
||||
#if !os(tvOS)
|
||||
var ovpnAdapter: OpenVPNAdapter?
|
||||
private lazy var openVPNPacketFlowAdapter = PacketTunnelFlowAdapter(flow: packetFlow)
|
||||
#endif
|
||||
private let pathMonitorQueue = DispatchQueue(label: Constants.processQueueName + ".path-monitor")
|
||||
private let networkChangeQueue = DispatchQueue(label: Constants.processQueueName + ".network-change")
|
||||
private let pathMonitor = NWPathMonitor()
|
||||
private var didReceiveInitialPathUpdate = false
|
||||
private var currentPath: Network.NWPath?
|
||||
private var currentPathSignature: String?
|
||||
private var pendingNetworkChangeWorkItem: DispatchWorkItem?
|
||||
private var isApplyingNetworkChange = false
|
||||
|
||||
var splitTunnelType: Int?
|
||||
var splitTunnelSites: [String]?
|
||||
|
||||
#if !os(tvOS)
|
||||
let vpnReachability = OpenVPNReachability()
|
||||
#endif
|
||||
|
||||
var startHandler: ((Error?) -> Void)?
|
||||
var stopHandler: (() -> Void)?
|
||||
@@ -63,11 +60,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
|
||||
var activeIfaceIdx: UInt32 = 0
|
||||
|
||||
#if !os(tvOS)
|
||||
func openVPNPacketFlow() -> OpenVPNAdapterPacketFlow {
|
||||
openVPNPacketFlowAdapter
|
||||
}
|
||||
#endif
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
@@ -86,14 +81,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
|
||||
guard hasMeaningfulChange, let proto = self.protoType else { return }
|
||||
|
||||
// WireGuard/AWG manages network changes internally; avoid restarting the tunnel here.
|
||||
if proto == .wireguard {
|
||||
// OpenVPN and WireGuard/AWG handle network changes internally.
|
||||
// Restarting them here can race their own reconnect logic and break tunnel setup.
|
||||
if proto == .wireguard || proto == .openvpn {
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.handle(networkChange: path) { _ in }
|
||||
}
|
||||
self.scheduleNetworkChangeHandling(for: proto, path: path)
|
||||
}
|
||||
pathMonitor.start(queue: pathMonitorQueue)
|
||||
|
||||
@@ -214,21 +208,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
errorNotifier: errorNotifier,
|
||||
completionHandler: completionHandler)
|
||||
case .openvpn:
|
||||
#if os(tvOS)
|
||||
completionHandler(NSError(domain: "org.amnezia.ne",
|
||||
code: -1002,
|
||||
userInfo: [NSLocalizedDescriptionKey: "OpenVPN backend is not available for tvOS in this build"]))
|
||||
#else
|
||||
startOpenVPN(completionHandler: completionHandler)
|
||||
#endif
|
||||
case .xray:
|
||||
#if os(tvOS)
|
||||
completionHandler(NSError(domain: "org.amnezia.ne",
|
||||
code: -1003,
|
||||
userInfo: [NSLocalizedDescriptionKey: "Xray backend is not available for tvOS in this build"]))
|
||||
#else
|
||||
startXray(completionHandler: completionHandler)
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
@@ -245,18 +227,10 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
stopWireguard(with: reason,
|
||||
completionHandler: completionHandler)
|
||||
case .openvpn:
|
||||
#if os(tvOS)
|
||||
completionHandler()
|
||||
#else
|
||||
stopOpenVPN(with: reason,
|
||||
completionHandler: completionHandler)
|
||||
#endif
|
||||
case .xray:
|
||||
#if os(tvOS)
|
||||
completionHandler()
|
||||
#else
|
||||
stopXray(completionHandler: completionHandler)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,11 +244,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
case .wireguard:
|
||||
handleWireguardStatusMessage(messageData, completionHandler: completionHandler)
|
||||
case .openvpn:
|
||||
#if !os(tvOS)
|
||||
handleOpenVPNStatusMessage(messageData, completionHandler: completionHandler)
|
||||
#else
|
||||
completionHandler?(nil)
|
||||
#endif
|
||||
case .xray:
|
||||
break;
|
||||
}
|
||||
@@ -291,9 +261,47 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
}
|
||||
|
||||
private func handle(networkChange changePath: Network.NWPath, completion: @escaping (Error?) -> Void) {
|
||||
guard protoType == .xray else {
|
||||
updateActiveInterfaceIndex(for: changePath)
|
||||
neLog(.info, message: "Tunnel restarted.")
|
||||
startTunnel(options: nil, completionHandler: completion)
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
|
||||
updateActiveInterfaceIndex(for: changePath)
|
||||
reasserting = true
|
||||
xrayLog(.info, message: "Applying network change to xray tunnel")
|
||||
stopXray { }
|
||||
startXray { [weak self] error in
|
||||
self?.reasserting = false
|
||||
completion(error)
|
||||
}
|
||||
}
|
||||
|
||||
private func scheduleNetworkChangeHandling(for proto: TunnelProtoType, path: Network.NWPath) {
|
||||
guard proto == .xray else { return }
|
||||
|
||||
pendingNetworkChangeWorkItem?.cancel()
|
||||
|
||||
let workItem = DispatchWorkItem { [weak self] in
|
||||
guard let self else { return }
|
||||
|
||||
if self.isApplyingNetworkChange {
|
||||
xrayLog(.debug, message: "Skipping network change while restart is already in progress")
|
||||
return
|
||||
}
|
||||
|
||||
self.isApplyingNetworkChange = true
|
||||
DispatchQueue.main.async {
|
||||
self.handle(networkChange: path) { [weak self] _ in
|
||||
self?.networkChangeQueue.async {
|
||||
self?.isApplyingNetworkChange = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pendingNetworkChangeWorkItem = workItem
|
||||
networkChangeQueue.asyncAfter(deadline: .now() + 1.0, execute: workItem)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +361,6 @@ extension WireGuardLogLevel {
|
||||
}
|
||||
}
|
||||
|
||||
#if !os(tvOS)
|
||||
final class PacketTunnelFlowAdapter: NSObject, OpenVPNAdapterPacketFlow {
|
||||
private let flow: NEPacketTunnelFlow
|
||||
|
||||
@@ -372,7 +379,6 @@ final class PacketTunnelFlowAdapter: NSObject, OpenVPNAdapterPacketFlow {
|
||||
flow.writePackets(packets, withProtocols: protocols)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
extension NEProviderStopReason {
|
||||
var amneziaDescription: String {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if !MACOS_NE && !TARGET_OS_TV
|
||||
#if !MACOS_NE
|
||||
#include "QRCodeReaderBase.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@@ -1,14 +1,91 @@
|
||||
#import "QtAppDelegate.h"
|
||||
#import "ios_controller.h"
|
||||
#import <StoreKit/StoreKit.h>
|
||||
|
||||
#include <QFile>
|
||||
|
||||
namespace {
|
||||
constexpr NSInteger kReviewRequestOpenInterval = 20;
|
||||
NSString *const kAppOpenCountKey = @"AmneziaVPN.AppOpenCount";
|
||||
BOOL gShouldRequestReviewOnBecomeActive = NO;
|
||||
id gSceneWillEnterForegroundObserver = nil;
|
||||
id gSceneDidActivateObserver = nil;
|
||||
|
||||
void scheduleAppStoreReviewIfNeededOnOpen()
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
const NSInteger openCount = [defaults integerForKey:kAppOpenCountKey] + 1;
|
||||
[defaults setInteger:openCount forKey:kAppOpenCountKey];
|
||||
|
||||
gShouldRequestReviewOnBecomeActive =
|
||||
(openCount > 0 && openCount % kReviewRequestOpenInterval == 0);
|
||||
|
||||
NSLog(@"[Review] scene open count=%ld interval=%ld scheduled=%@",
|
||||
(long)openCount,
|
||||
(long)kReviewRequestOpenInterval,
|
||||
gShouldRequestReviewOnBecomeActive ? @"YES" : @"NO");
|
||||
}
|
||||
|
||||
void requestAppStoreReviewForScene(UIScene *scene)
|
||||
{
|
||||
if (@available(iOS 14.0, *)) {
|
||||
if ([scene isKindOfClass:[UIWindowScene class]] &&
|
||||
scene.activationState == UISceneActivationStateForegroundActive) {
|
||||
[SKStoreReviewController requestReviewInScene:(UIWindowScene *)scene];
|
||||
NSLog(@"[Review] requestReviewInScene invoked");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (@available(iOS 10.3, *)) {
|
||||
[SKStoreReviewController requestReview];
|
||||
NSLog(@"[Review] requestReview fallback invoked");
|
||||
}
|
||||
}
|
||||
|
||||
void setupSceneReviewObservers()
|
||||
{
|
||||
if (gSceneWillEnterForegroundObserver || gSceneDidActivateObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
gSceneWillEnterForegroundObserver =
|
||||
[center addObserverForName:UISceneWillEnterForegroundNotification
|
||||
object:nil
|
||||
queue:[NSOperationQueue mainQueue]
|
||||
usingBlock:^(__unused NSNotification *note) {
|
||||
scheduleAppStoreReviewIfNeededOnOpen();
|
||||
}];
|
||||
|
||||
gSceneDidActivateObserver =
|
||||
[center addObserverForName:UISceneDidActivateNotification
|
||||
object:nil
|
||||
queue:[NSOperationQueue mainQueue]
|
||||
usingBlock:^(NSNotification *note) {
|
||||
if (!gShouldRequestReviewOnBecomeActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
gShouldRequestReviewOnBecomeActive = NO;
|
||||
UIScene *scene = [note.object isKindOfClass:[UIScene class]] ? (UIScene *)note.object : nil;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
requestAppStoreReviewForScene(scene);
|
||||
});
|
||||
}];
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
@implementation QIOSApplicationDelegate (AmneziaVPNDelegate)
|
||||
#if !MACOS_NE
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
[application setMinimumBackgroundFetchInterval: UIApplicationBackgroundFetchIntervalMinimum];
|
||||
setupSceneReviewObservers();
|
||||
// Override point for customization after application launch.
|
||||
NSLog(@"Application didFinishLaunchingWithOptions");
|
||||
return YES;
|
||||
|
||||
@@ -3,5 +3,7 @@ import Foundation
|
||||
struct XrayConfig: Decodable {
|
||||
let dns1: String?
|
||||
let dns2: String?
|
||||
let splitTunnelType: Int?
|
||||
let splitTunnelSites: [String]?
|
||||
let config: String
|
||||
}
|
||||
|
||||
@@ -684,6 +684,15 @@ bool IosController::setupXray()
|
||||
QJsonObject finalConfig;
|
||||
finalConfig.insert(config_key::dns1, m_rawConfig[config_key::dns1].toString());
|
||||
finalConfig.insert(config_key::dns2, m_rawConfig[config_key::dns2].toString());
|
||||
finalConfig.insert(config_key::splitTunnelType, m_rawConfig[config_key::splitTunnelType]);
|
||||
|
||||
QJsonArray splitTunnelSites = m_rawConfig[config_key::splitTunnelSites].toArray();
|
||||
|
||||
for(int index = 0; index < splitTunnelSites.count(); index++) {
|
||||
splitTunnelSites[index] = splitTunnelSites[index].toString().remove(" ");
|
||||
}
|
||||
|
||||
finalConfig.insert(config_key::splitTunnelSites, splitTunnelSites);
|
||||
finalConfig.insert(config_key::config, xrayConfigStr);
|
||||
|
||||
QJsonDocument finalConfigDoc(finalConfig);
|
||||
@@ -959,10 +968,6 @@ void IosController::sendVpnExtensionMessage(NSDictionary* message, std::function
|
||||
}
|
||||
|
||||
bool IosController::shareText(const QStringList& filesToSend) {
|
||||
#if defined(Q_OS_TVOS)
|
||||
Q_UNUSED(filesToSend)
|
||||
return false;
|
||||
#else
|
||||
NSMutableArray *sharingItems = [NSMutableArray new];
|
||||
|
||||
for (int i = 0; i < filesToSend.size(); i++) {
|
||||
@@ -971,7 +976,7 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
||||
}
|
||||
#if !MACOS_NE
|
||||
UIViewController *qtController = getViewController();
|
||||
if (!qtController) return false;
|
||||
if (!qtController) return;
|
||||
|
||||
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
||||
#endif
|
||||
@@ -995,25 +1000,23 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
||||
wait.exec();
|
||||
|
||||
return isAccepted;
|
||||
#endif
|
||||
}
|
||||
|
||||
QString IosController::openFile() {
|
||||
#if defined(Q_OS_TVOS)
|
||||
return QString();
|
||||
#elif !MACOS_NE
|
||||
#if !MACOS_NE
|
||||
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen];
|
||||
|
||||
DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init];
|
||||
documentPicker.delegate = documentPickerDelegate;
|
||||
|
||||
UIViewController *qtController = getViewController();
|
||||
if (!qtController) return QString();
|
||||
if (!qtController) return;
|
||||
|
||||
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
||||
|
||||
#endif
|
||||
__block QString filePath;
|
||||
#if !MACOS_NE && !defined(Q_OS_TVOS)
|
||||
#if !MACOS_NE
|
||||
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
||||
if (path) {
|
||||
filePath = QString::fromUtf8(path.UTF8String);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#import <NetworkExtension/NetworkExtension.h>
|
||||
#import <NetworkExtension/NETunnelProviderSession.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#if !MACOS_NE
|
||||
#include <UIKit/UIKit.h>
|
||||
@@ -22,7 +21,7 @@ class IosController;
|
||||
@end
|
||||
|
||||
typedef void (^DocumentPickerClosedCallback)(NSString *path);
|
||||
#if !MACOS_NE && !TARGET_OS_TV
|
||||
#if !MACOS_NE
|
||||
@interface DocumentPickerDelegate : NSObject <UIDocumentPickerDelegate>
|
||||
|
||||
@property (nonatomic, copy) DocumentPickerClosedCallback documentPickerClosedCallback;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
@end
|
||||
|
||||
#if !MACOS_NE && !TARGET_OS_TV
|
||||
#if !MACOS_NE
|
||||
@implementation DocumentPickerDelegate
|
||||
|
||||
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {
|
||||
|
||||
@@ -7,24 +7,6 @@
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if defined(Q_OS_TVOS)
|
||||
|
||||
IOSNotificationHandler::IOSNotificationHandler(QObject* parent) : NotificationHandler(parent) {}
|
||||
|
||||
IOSNotificationHandler::~IOSNotificationHandler() {}
|
||||
|
||||
void IOSNotificationHandler::notify(NotificationHandler::Message type,
|
||||
const QString& title,
|
||||
const QString& message,
|
||||
int timerMsec) {
|
||||
Q_UNUSED(type)
|
||||
Q_UNUSED(title)
|
||||
Q_UNUSED(message)
|
||||
Q_UNUSED(timerMsec)
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if !MACOS_NE
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@@ -190,5 +172,3 @@ void IOSNotificationHandler::notify(NotificationHandler::Message type, const QSt
|
||||
}];
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // Q_OS_TVOS
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
/*
|
||||
* tvOS does not export these iOS runtime helpers used by Go cgo archives.
|
||||
* WireGuardKitGo references them indirectly; provide no-op stubs for tvOS.
|
||||
*/
|
||||
void darwin_arm_init_mach_exception_handler(void) {}
|
||||
void darwin_arm_init_thread_exception_port(void) {}
|
||||
@@ -80,7 +80,7 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
|
||||
|
||||
QDir appPath(QCoreApplication::applicationDirPath());
|
||||
QStringList wgArgs = {"-f", "amn0"};
|
||||
m_tunnel.start(appPath.filePath("amneziawg-go"), wgArgs);
|
||||
m_tunnel.start(appPath.filePath("../../client/bin/wireguard-go"), wgArgs);
|
||||
if (!m_tunnel.waitForStarted(WG_TUN_PROC_TIMEOUT)) {
|
||||
logger.error() << "Unable to start tunnel process due to timeout";
|
||||
m_tunnel.kill();
|
||||
|
||||
@@ -79,7 +79,7 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) {
|
||||
|
||||
QDir appPath(QCoreApplication::applicationDirPath());
|
||||
QStringList wgArgs = {"-f", "utun"};
|
||||
m_tunnel.start(appPath.filePath("amneziawg-go"), wgArgs);
|
||||
m_tunnel.start(appPath.filePath("wireguard-go"), wgArgs);
|
||||
if (!m_tunnel.waitForStarted(WG_TUN_PROC_TIMEOUT)) {
|
||||
logger.error() << "Unable to start tunnel process due to timeout";
|
||||
m_tunnel.kill();
|
||||
|
||||
@@ -190,7 +190,7 @@ namespace amnezia
|
||||
|
||||
constexpr char defaultPort[] = "51820";
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
constexpr char defaultMtu[] = "1280";
|
||||
#else
|
||||
constexpr char defaultMtu[] = "1376";
|
||||
@@ -210,7 +210,7 @@ namespace amnezia
|
||||
namespace awg
|
||||
{
|
||||
constexpr char defaultPort[] = "55424";
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
constexpr char defaultMtu[] = "1280";
|
||||
#else
|
||||
constexpr char defaultMtu[] = "1376";
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "core/errorstrings.h"
|
||||
#include "vpnprotocol.h"
|
||||
|
||||
#if defined(Q_OS_WINDOWS) || (defined(Q_OS_MACX) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) and !defined MACOS_NE || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
#include "openvpnovercloakprotocol.h"
|
||||
#include "openvpnprotocol.h"
|
||||
#include "shadowsocksvpnprotocol.h"
|
||||
@@ -114,7 +114,7 @@ VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
||||
#endif
|
||||
#if defined(Q_OS_WINDOWS) || (defined(Q_OS_MACX) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) and !defined MACOS_NE || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration);
|
||||
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
|
||||
case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration);
|
||||
|
||||
@@ -124,14 +124,14 @@ ErrorCode XrayProtocol::startTun2Socks()
|
||||
m_tun2socksProcess->setProgram(PermittedProcess::Tun2Socks);
|
||||
m_tun2socksProcess->setArguments({"-device", QString("tun://%1").arg(tunName), "-proxy", "socks5://127.0.0.1:10808" });
|
||||
|
||||
connect(m_tun2socksProcess.data(), &IpcProcessInterfaceReplica::readyReadStandardError, this, [this]() {
|
||||
auto readAllStandardError = m_tun2socksProcess->readAllStandardError();
|
||||
if (!readAllStandardError.waitForFinished()) {
|
||||
connect(m_tun2socksProcess.data(), &IpcProcessInterfaceReplica::readyReadStandardOutput, this, [this]() {
|
||||
auto readAllStandardOutput = m_tun2socksProcess->readAllStandardOutput();
|
||||
if (!readAllStandardOutput.waitForFinished()) {
|
||||
qWarning() << "Failed to read output from tun2socks";
|
||||
return;
|
||||
}
|
||||
|
||||
const QString line = readAllStandardError.returnValue();
|
||||
const QString line = readAllStandardOutput.returnValue();
|
||||
|
||||
if (!line.contains("[TCP]") && !line.contains("[UDP]"))
|
||||
qDebug() << "[tun2socks]:" << line;
|
||||
|
||||
+14
-21
@@ -35,13 +35,12 @@ SecureQSettings::SecureQSettings(const QString &organization, const QString &app
|
||||
}
|
||||
}
|
||||
m_settings.setValue("Conf/encrypted", true);
|
||||
m_settings.sync();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue) const
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
if (m_cache.contains(key)) {
|
||||
return m_cache.value(key);
|
||||
@@ -85,7 +84,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue
|
||||
|
||||
void SecureQSettings::setValue(const QString &key, const QVariant &value)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
if (encryptionRequired() && encryptedKeys.contains(key)) {
|
||||
if (!getEncKey().isEmpty() && !getEncIv().isEmpty()) {
|
||||
@@ -107,26 +106,20 @@ void SecureQSettings::setValue(const QString &key, const QVariant &value)
|
||||
}
|
||||
|
||||
m_cache.insert(key, value);
|
||||
sync();
|
||||
}
|
||||
|
||||
void SecureQSettings::remove(const QString &key)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
m_settings.remove(key);
|
||||
m_cache.remove(key);
|
||||
|
||||
sync();
|
||||
}
|
||||
|
||||
void SecureQSettings::sync()
|
||||
{
|
||||
m_settings.sync();
|
||||
}
|
||||
|
||||
QByteArray SecureQSettings::backupAppConfig() const
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
QJsonObject cfg;
|
||||
|
||||
const auto needToBackup = [this](const auto &key) {
|
||||
@@ -161,6 +154,8 @@ QByteArray SecureQSettings::backupAppConfig() const
|
||||
|
||||
bool SecureQSettings::restoreAppConfig(const QByteArray &json)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
QJsonObject cfg = QJsonDocument::fromJson(json).object();
|
||||
if (cfg.isEmpty())
|
||||
return false;
|
||||
@@ -173,10 +168,16 @@ bool SecureQSettings::restoreAppConfig(const QByteArray &json)
|
||||
setValue(key, cfg.value(key).toVariant());
|
||||
}
|
||||
|
||||
sync();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SecureQSettings::clearSettings()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_settings.clear();
|
||||
m_cache.clear();
|
||||
}
|
||||
|
||||
QByteArray SecureQSettings::encryptText(const QByteArray &value) const
|
||||
{
|
||||
QSimpleCrypto::QBlockCipher cipher;
|
||||
@@ -294,11 +295,3 @@ void SecureQSettings::setSecTag(const QString &tag, const QByteArray &data)
|
||||
qCritical() << "SecureQSettings::setSecTag Error:" << job->errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void SecureQSettings::clearSettings()
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
m_settings.clear();
|
||||
m_cache.clear();
|
||||
sync();
|
||||
}
|
||||
|
||||
@@ -16,14 +16,16 @@ public:
|
||||
explicit SecureQSettings(const QString &organization, const QString &application = QString(),
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
||||
Q_INVOKABLE void setValue(const QString &key, const QVariant &value);
|
||||
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
||||
void setValue(const QString &key, const QVariant &value);
|
||||
void remove(const QString &key);
|
||||
void sync();
|
||||
|
||||
QByteArray backupAppConfig() const;
|
||||
bool restoreAppConfig(const QByteArray &json);
|
||||
|
||||
void clearSettings();
|
||||
|
||||
private:
|
||||
QByteArray encryptText(const QByteArray &value) const;
|
||||
QByteArray decryptText(const QByteArray &ba) const;
|
||||
|
||||
@@ -35,9 +37,6 @@ public:
|
||||
static QByteArray getSecTag(const QString &tag);
|
||||
static void setSecTag(const QString &tag, const QByteArray &data);
|
||||
|
||||
void clearSettings();
|
||||
|
||||
private:
|
||||
QSettings m_settings;
|
||||
|
||||
mutable QHash<QString, QVariant> m_cache;
|
||||
@@ -53,7 +52,7 @@ private:
|
||||
|
||||
const QByteArray magicString { "EncData" }; // Magic keyword used for mark encrypted QByteArray
|
||||
|
||||
mutable QMutex mutex;
|
||||
mutable QRecursiveMutex m_mutex;
|
||||
};
|
||||
|
||||
#endif // SECUREQSETTINGS_H
|
||||
|
||||
+34
-57
@@ -21,10 +21,10 @@ Settings::Settings(QObject *parent) : QObject(parent), m_settings(ORGANIZATION_N
|
||||
{
|
||||
// Import old settings
|
||||
if (serversCount() == 0) {
|
||||
QString user = value("Server/userName").toString();
|
||||
QString password = value("Server/password").toString();
|
||||
QString serverName = value("Server/serverName").toString();
|
||||
int port = value("Server/serverPort").toInt();
|
||||
QString user = m_settings.value("Server/userName").toString();
|
||||
QString password = m_settings.value("Server/password").toString();
|
||||
QString serverName = m_settings.value("Server/serverName").toString();
|
||||
int port = m_settings.value("Server/serverPort").toInt();
|
||||
|
||||
if (!user.isEmpty() && !password.isEmpty() && !serverName.isEmpty()) {
|
||||
QJsonObject server;
|
||||
@@ -222,7 +222,7 @@ QString Settings::nextAvailableServerName() const
|
||||
|
||||
void Settings::setSaveLogs(bool enabled)
|
||||
{
|
||||
setValue("Conf/saveLogs", enabled);
|
||||
m_settings.setValue("Conf/saveLogs", enabled);
|
||||
#ifndef Q_OS_ANDROID
|
||||
if (!isSaveLogs()) {
|
||||
Logger::deInit();
|
||||
@@ -242,12 +242,12 @@ void Settings::setSaveLogs(bool enabled)
|
||||
|
||||
QDateTime Settings::getLogEnableDate()
|
||||
{
|
||||
return value("Conf/logEnableDate").toDateTime();
|
||||
return m_settings.value("Conf/logEnableDate").toDateTime();
|
||||
}
|
||||
|
||||
void Settings::setLogEnableDate(QDateTime date)
|
||||
{
|
||||
setValue("Conf/logEnableDate", date);
|
||||
m_settings.setValue("Conf/logEnableDate", date);
|
||||
}
|
||||
|
||||
QString Settings::routeModeString(RouteMode mode) const
|
||||
@@ -261,17 +261,17 @@ QString Settings::routeModeString(RouteMode mode) const
|
||||
|
||||
Settings::RouteMode Settings::routeMode() const
|
||||
{
|
||||
return static_cast<RouteMode>(value("Conf/routeMode", 0).toInt());
|
||||
return static_cast<RouteMode>(m_settings.value("Conf/routeMode", 0).toInt());
|
||||
}
|
||||
|
||||
bool Settings::isSitesSplitTunnelingEnabled() const
|
||||
{
|
||||
return value("Conf/sitesSplitTunnelingEnabled", false).toBool();
|
||||
return m_settings.value("Conf/sitesSplitTunnelingEnabled", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setSitesSplitTunnelingEnabled(bool enabled)
|
||||
{
|
||||
setValue("Conf/sitesSplitTunnelingEnabled", enabled);
|
||||
m_settings.setValue("Conf/sitesSplitTunnelingEnabled", enabled);
|
||||
}
|
||||
|
||||
bool Settings::addVpnSite(RouteMode mode, const QString &site, const QString &ip)
|
||||
@@ -359,12 +359,12 @@ void Settings::removeAllVpnSites(RouteMode mode)
|
||||
|
||||
QString Settings::primaryDns() const
|
||||
{
|
||||
return value("Conf/primaryDns", cloudFlareNs1).toString();
|
||||
return m_settings.value("Conf/primaryDns", cloudFlareNs1).toString();
|
||||
}
|
||||
|
||||
QString Settings::secondaryDns() const
|
||||
{
|
||||
return value("Conf/secondaryDns", cloudFlareNs2).toString();
|
||||
return m_settings.value("Conf/secondaryDns", cloudFlareNs2).toString();
|
||||
}
|
||||
|
||||
void Settings::clearSettings()
|
||||
@@ -386,18 +386,18 @@ QString Settings::appsRouteModeString(AppsRouteMode mode) const
|
||||
|
||||
Settings::AppsRouteMode Settings::getAppsRouteMode() const
|
||||
{
|
||||
return static_cast<AppsRouteMode>(value("Conf/appsRouteMode", 0).toInt());
|
||||
return static_cast<AppsRouteMode>(m_settings.value("Conf/appsRouteMode", 0).toInt());
|
||||
}
|
||||
|
||||
void Settings::setAppsRouteMode(AppsRouteMode mode)
|
||||
{
|
||||
setValue("Conf/appsRouteMode", mode);
|
||||
m_settings.setValue("Conf/appsRouteMode", mode);
|
||||
}
|
||||
|
||||
QVector<InstalledAppInfo> Settings::getVpnApps(AppsRouteMode mode) const
|
||||
{
|
||||
QVector<InstalledAppInfo> apps;
|
||||
auto appsArray = value("Conf/" + appsRouteModeString(mode)).toJsonArray();
|
||||
auto appsArray = m_settings.value("Conf/" + appsRouteModeString(mode)).toJsonArray();
|
||||
for (const auto &app : appsArray) {
|
||||
InstalledAppInfo appInfo;
|
||||
appInfo.appName = app.toObject().value("appName").toString();
|
||||
@@ -419,43 +419,42 @@ void Settings::setVpnApps(AppsRouteMode mode, const QVector<InstalledAppInfo> &a
|
||||
appInfo.insert("appPath", app.appPath);
|
||||
appsArray.push_back(appInfo);
|
||||
}
|
||||
setValue("Conf/" + appsRouteModeString(mode), appsArray);
|
||||
m_settings.sync();
|
||||
m_settings.setValue("Conf/" + appsRouteModeString(mode), appsArray);
|
||||
}
|
||||
|
||||
bool Settings::isAppsSplitTunnelingEnabled() const
|
||||
{
|
||||
return value("Conf/appsSplitTunnelingEnabled", false).toBool();
|
||||
return m_settings.value("Conf/appsSplitTunnelingEnabled", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setAppsSplitTunnelingEnabled(bool enabled)
|
||||
{
|
||||
setValue("Conf/appsSplitTunnelingEnabled", enabled);
|
||||
m_settings.setValue("Conf/appsSplitTunnelingEnabled", enabled);
|
||||
}
|
||||
|
||||
bool Settings::isKillSwitchEnabled() const
|
||||
{
|
||||
return value("Conf/killSwitchEnabled", true).toBool();
|
||||
return m_settings.value("Conf/killSwitchEnabled", true).toBool();
|
||||
}
|
||||
|
||||
void Settings::setKillSwitchEnabled(bool enabled)
|
||||
{
|
||||
setValue("Conf/killSwitchEnabled", enabled);
|
||||
m_settings.setValue("Conf/killSwitchEnabled", enabled);
|
||||
}
|
||||
|
||||
bool Settings::isStrictKillSwitchEnabled() const
|
||||
{
|
||||
return value("Conf/strictKillSwitchEnabled", false).toBool();
|
||||
return m_settings.value("Conf/strictKillSwitchEnabled", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setStrictKillSwitchEnabled(bool enabled)
|
||||
{
|
||||
setValue("Conf/strictKillSwitchEnabled", enabled);
|
||||
m_settings.setValue("Conf/strictKillSwitchEnabled", enabled);
|
||||
}
|
||||
|
||||
QString Settings::getInstallationUuid(const bool needCreate)
|
||||
{
|
||||
auto uuid = value("Conf/installationUuid", "").toString();
|
||||
auto uuid = m_settings.value("Conf/installationUuid", "").toString();
|
||||
if (needCreate && uuid.isEmpty()) {
|
||||
uuid = QUuid::createUuid().toString();
|
||||
|
||||
@@ -476,7 +475,7 @@ QString Settings::getInstallationUuid(const bool needCreate)
|
||||
|
||||
void Settings::setInstallationUuid(const QString &uuid)
|
||||
{
|
||||
setValue("Conf/installationUuid", uuid);
|
||||
m_settings.setValue("Conf/installationUuid", uuid);
|
||||
}
|
||||
|
||||
ServerCredentials Settings::defaultServerCredentials() const
|
||||
@@ -497,28 +496,6 @@ ServerCredentials Settings::serverCredentials(int index) const
|
||||
return credentials;
|
||||
}
|
||||
|
||||
QVariant Settings::value(const QString &key, const QVariant &defaultValue) const
|
||||
{
|
||||
QVariant returnValue;
|
||||
if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
|
||||
returnValue = m_settings.value(key, defaultValue);
|
||||
} else {
|
||||
QMetaObject::invokeMethod(&m_settings, "value", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariant, returnValue),
|
||||
Q_ARG(const QString &, key), Q_ARG(const QVariant &, defaultValue));
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void Settings::setValue(const QString &key, const QVariant &value)
|
||||
{
|
||||
if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
|
||||
m_settings.setValue(key, value);
|
||||
} else {
|
||||
QMetaObject::invokeMethod(&m_settings, "setValue", Qt::BlockingQueuedConnection, Q_ARG(const QString &, key),
|
||||
Q_ARG(const QVariant &, value));
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::resetGatewayEndpoint()
|
||||
{
|
||||
m_gatewayEndpoint = gatewayEndpoint;
|
||||
@@ -541,50 +518,50 @@ QString Settings::getGatewayEndpoint(bool isTestPurchase)
|
||||
|
||||
bool Settings::isDevGatewayEnv(bool isTestPurchase)
|
||||
{
|
||||
return isTestPurchase ? true : value("Conf/devGatewayEnv", false).toBool();
|
||||
return isTestPurchase ? true : m_settings.value("Conf/devGatewayEnv", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::toggleDevGatewayEnv(bool enabled)
|
||||
{
|
||||
setValue("Conf/devGatewayEnv", enabled);
|
||||
m_settings.setValue("Conf/devGatewayEnv", enabled);
|
||||
}
|
||||
|
||||
bool Settings::isHomeAdLabelVisible()
|
||||
{
|
||||
return value("Conf/homeAdLabelVisible", true).toBool();
|
||||
return m_settings.value("Conf/homeAdLabelVisible", true).toBool();
|
||||
}
|
||||
|
||||
void Settings::disableHomeAdLabel()
|
||||
{
|
||||
setValue("Conf/homeAdLabelVisible", false);
|
||||
m_settings.setValue("Conf/homeAdLabelVisible", false);
|
||||
}
|
||||
|
||||
bool Settings::isPremV1MigrationReminderActive()
|
||||
{
|
||||
return value("Conf/premV1MigrationReminderActive", true).toBool();
|
||||
return m_settings.value("Conf/premV1MigrationReminderActive", true).toBool();
|
||||
}
|
||||
|
||||
void Settings::disablePremV1MigrationReminder()
|
||||
{
|
||||
setValue("Conf/premV1MigrationReminderActive", false);
|
||||
m_settings.setValue("Conf/premV1MigrationReminderActive", false);
|
||||
}
|
||||
|
||||
QStringList Settings::allowedDnsServers() const
|
||||
{
|
||||
return value("Conf/allowedDnsServers").toStringList();
|
||||
return m_settings.value("Conf/allowedDnsServers").toStringList();
|
||||
}
|
||||
|
||||
void Settings::setAllowedDnsServers(const QStringList &servers)
|
||||
{
|
||||
setValue("Conf/allowedDnsServers", servers);
|
||||
m_settings.setValue("Conf/allowedDnsServers", servers);
|
||||
}
|
||||
|
||||
QStringList Settings::readNewsIds() const
|
||||
{
|
||||
return value("News/readIds").toStringList();
|
||||
return m_settings.value("News/readIds").toStringList();
|
||||
}
|
||||
|
||||
void Settings::setReadNewsIds(const QStringList &ids)
|
||||
{
|
||||
setValue("News/readIds", ids);
|
||||
m_settings.setValue("News/readIds", ids);
|
||||
}
|
||||
|
||||
+21
-25
@@ -29,11 +29,11 @@ public:
|
||||
|
||||
QJsonArray serversArray() const
|
||||
{
|
||||
return QJsonDocument::fromJson(value("Servers/serversList").toByteArray()).array();
|
||||
return QJsonDocument::fromJson(m_settings.value("Servers/serversList").toByteArray()).array();
|
||||
}
|
||||
void setServersArray(const QJsonArray &servers)
|
||||
{
|
||||
setValue("Servers/serversList", QJsonDocument(servers).toJson());
|
||||
m_settings.setValue("Servers/serversList", QJsonDocument(servers).toJson());
|
||||
}
|
||||
|
||||
// Servers section
|
||||
@@ -45,11 +45,11 @@ public:
|
||||
|
||||
int defaultServerIndex() const
|
||||
{
|
||||
return value("Servers/defaultServerIndex", 0).toInt();
|
||||
return m_settings.value("Servers/defaultServerIndex", 0).toInt();
|
||||
}
|
||||
void setDefaultServer(int index)
|
||||
{
|
||||
setValue("Servers/defaultServerIndex", index);
|
||||
m_settings.setValue("Servers/defaultServerIndex", index);
|
||||
}
|
||||
QJsonObject defaultServer() const
|
||||
{
|
||||
@@ -78,34 +78,34 @@ public:
|
||||
// App settings section
|
||||
bool isAutoConnect() const
|
||||
{
|
||||
return value("Conf/autoConnect", false).toBool();
|
||||
return m_settings.value("Conf/autoConnect", false).toBool();
|
||||
}
|
||||
void setAutoConnect(bool enabled)
|
||||
{
|
||||
setValue("Conf/autoConnect", enabled);
|
||||
m_settings.setValue("Conf/autoConnect", enabled);
|
||||
}
|
||||
|
||||
bool isStartMinimized() const
|
||||
{
|
||||
return value("Conf/startMinimized", false).toBool();
|
||||
return m_settings.value("Conf/startMinimized", false).toBool();
|
||||
}
|
||||
void setStartMinimized(bool enabled)
|
||||
{
|
||||
setValue("Conf/startMinimized", enabled);
|
||||
m_settings.setValue("Conf/startMinimized", enabled);
|
||||
}
|
||||
|
||||
bool isNewsNotifications() const
|
||||
{
|
||||
return value("Conf/newsNotifications", true).toBool();
|
||||
return m_settings.value("Conf/newsNotifications", true).toBool();
|
||||
}
|
||||
void setNewsNotifications(bool enabled)
|
||||
{
|
||||
setValue("Conf/newsNotifications", enabled);
|
||||
m_settings.setValue("Conf/newsNotifications", enabled);
|
||||
}
|
||||
|
||||
bool isSaveLogs() const
|
||||
{
|
||||
return value("Conf/saveLogs", false).toBool();
|
||||
return m_settings.value("Conf/saveLogs", false).toBool();
|
||||
}
|
||||
void setSaveLogs(bool enabled);
|
||||
|
||||
@@ -122,19 +122,18 @@ public:
|
||||
QString routeModeString(RouteMode mode) const;
|
||||
|
||||
RouteMode routeMode() const;
|
||||
void setRouteMode(RouteMode mode) { setValue("Conf/routeMode", mode); }
|
||||
void setRouteMode(RouteMode mode) { m_settings.setValue("Conf/routeMode", mode); }
|
||||
|
||||
bool isSitesSplitTunnelingEnabled() const;
|
||||
void setSitesSplitTunnelingEnabled(bool enabled);
|
||||
|
||||
QVariantMap vpnSites(RouteMode mode) const
|
||||
{
|
||||
return value("Conf/" + routeModeString(mode)).toMap();
|
||||
return m_settings.value("Conf/" + routeModeString(mode)).toMap();
|
||||
}
|
||||
void setVpnSites(RouteMode mode, const QVariantMap &sites)
|
||||
{
|
||||
setValue("Conf/" + routeModeString(mode), sites);
|
||||
m_settings.sync();
|
||||
m_settings.setValue("Conf/" + routeModeString(mode), sites);
|
||||
}
|
||||
bool addVpnSite(RouteMode mode, const QString &site, const QString &ip = "");
|
||||
void addVpnSites(RouteMode mode, const QMap<QString, QString> &sites); // map <site, ip>
|
||||
@@ -147,11 +146,11 @@ public:
|
||||
|
||||
bool useAmneziaDns() const
|
||||
{
|
||||
return value("Conf/useAmneziaDns", true).toBool();
|
||||
return m_settings.value("Conf/useAmneziaDns", true).toBool();
|
||||
}
|
||||
void setUseAmneziaDns(bool enabled)
|
||||
{
|
||||
setValue("Conf/useAmneziaDns", enabled);
|
||||
m_settings.setValue("Conf/useAmneziaDns", enabled);
|
||||
}
|
||||
|
||||
QString primaryDns() const;
|
||||
@@ -160,13 +159,13 @@ public:
|
||||
// QString primaryDns() const { return m_primaryDns; }
|
||||
void setPrimaryDns(const QString &primaryDns)
|
||||
{
|
||||
setValue("Conf/primaryDns", primaryDns);
|
||||
m_settings.setValue("Conf/primaryDns", primaryDns);
|
||||
}
|
||||
|
||||
// QString secondaryDns() const { return m_secondaryDns; }
|
||||
void setSecondaryDns(const QString &secondaryDns)
|
||||
{
|
||||
setValue("Conf/secondaryDns", secondaryDns);
|
||||
m_settings.setValue("Conf/secondaryDns", secondaryDns);
|
||||
}
|
||||
|
||||
// static constexpr char openNicNs5[] = "94.103.153.176";
|
||||
@@ -188,16 +187,16 @@ public:
|
||||
};
|
||||
void setAppLanguage(QLocale locale)
|
||||
{
|
||||
setValue("Conf/appLanguage", locale.name());
|
||||
m_settings.setValue("Conf/appLanguage", locale.name());
|
||||
};
|
||||
|
||||
bool isScreenshotsEnabled() const
|
||||
{
|
||||
return value("Conf/screenshotsEnabled", true).toBool();
|
||||
return m_settings.value("Conf/screenshotsEnabled", true).toBool();
|
||||
}
|
||||
void setScreenshotsEnabled(bool enabled)
|
||||
{
|
||||
setValue("Conf/screenshotsEnabled", enabled);
|
||||
m_settings.setValue("Conf/screenshotsEnabled", enabled);
|
||||
emit screenshotsEnabledChanged(enabled);
|
||||
}
|
||||
|
||||
@@ -255,9 +254,6 @@ signals:
|
||||
void settingsCleared();
|
||||
|
||||
private:
|
||||
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
||||
void setValue(const QString &key, const QVariant &value);
|
||||
|
||||
void setInstallationUuid(const QString &uuid);
|
||||
|
||||
mutable SecureQSettings m_settings;
|
||||
|
||||
+846
-1393
File diff suppressed because it is too large
Load Diff
+851
-1386
File diff suppressed because it is too large
Load Diff
+846
-1393
File diff suppressed because it is too large
Load Diff
+845
-1396
File diff suppressed because it is too large
Load Diff
@@ -199,7 +199,7 @@
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="116"/>
|
||||
<source>%1 $</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 $</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="118"/>
|
||||
@@ -672,32 +672,32 @@ Thank you for staying with us!</source>
|
||||
<translation>Порт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="418"/>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="422"/>
|
||||
<source>Save</source>
|
||||
<translation>Сохранить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="427"/>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="431"/>
|
||||
<source>Save settings?</source>
|
||||
<translation>Сохранить настройки?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="428"/>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="432"/>
|
||||
<source>Only the settings for this device will be changed</source>
|
||||
<translation>Будут изменены настройки только для этого устройства</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="429"/>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="433"/>
|
||||
<source>Continue</source>
|
||||
<translation>Продолжить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="430"/>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="434"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Отменить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="434"/>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="438"/>
|
||||
<source>Unable change settings while there is an active connection</source>
|
||||
<translation>Невозможно изменить настройки во время активного соединения</translation>
|
||||
</message>
|
||||
@@ -1651,7 +1651,7 @@ Thank you for staying with us!</source>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="204"/>
|
||||
<source>mailto:support@amnezia.org</source>
|
||||
<translation></translation>
|
||||
<translation>mailto:support@amnezia.org</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="211"/>
|
||||
@@ -1775,72 +1775,72 @@ Thank you for staying with us!</source>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="22"/>
|
||||
<source>Windows</source>
|
||||
<translation></translation>
|
||||
<translation>Windows</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="29"/>
|
||||
<source>macOS</source>
|
||||
<translation></translation>
|
||||
<translation>macOS</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="36"/>
|
||||
<source>Android</source>
|
||||
<translation></translation>
|
||||
<translation>Android</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="43"/>
|
||||
<source>AndroidTV</source>
|
||||
<translation></translation>
|
||||
<translation>Android TV</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="50"/>
|
||||
<source>iOS</source>
|
||||
<translation></translation>
|
||||
<translation>iOS</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="57"/>
|
||||
<source>Linux</source>
|
||||
<translation></translation>
|
||||
<translation>Linux</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="64"/>
|
||||
<source>Routers</source>
|
||||
<translation></translation>
|
||||
<translation>Маршрутизаторы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="23"/>
|
||||
<source>documentation/instructions/connect-amnezia-premium#windows</source>
|
||||
<translation></translation>
|
||||
<translation>documentation/instructions/connect-amnezia-premium#windows</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="30"/>
|
||||
<source>documentation/instructions/connect-amnezia-premium#macos</source>
|
||||
<translation></translation>
|
||||
<translation>documentation/instructions/connect-amnezia-premium#macos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="37"/>
|
||||
<source>documentation/instructions/connect-amnezia-premium#android</source>
|
||||
<translation></translation>
|
||||
<translation>documentation/instructions/connect-amnezia-premium#android</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="44"/>
|
||||
<source>documentation/instructions/android_tv_connect/</source>
|
||||
<translation></translation>
|
||||
<translation>documentation/instructions/android_tv_connect/</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="51"/>
|
||||
<source>documentation/instructions/connect-amnezia-premium#ios</source>
|
||||
<translation></translation>
|
||||
<translation>documentation/instructions/connect-amnezia-premium#ios</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="58"/>
|
||||
<source>documentation/instructions/connect-amnezia-premium#linux</source>
|
||||
<translation></translation>
|
||||
<translation>documentation/instructions/connect-amnezia-premium#linux</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="65"/>
|
||||
<source>documentation/instructions/connect-amnezia-premium#routers</source>
|
||||
<translation></translation>
|
||||
<translation>documentation/instructions/connect-amnezia-premium#routers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="101"/>
|
||||
@@ -2111,7 +2111,7 @@ Thank you for staying with us!</source>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="22"/>
|
||||
<source>Telegram</source>
|
||||
<translation></translation>
|
||||
<translation>Telegram</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="30"/>
|
||||
@@ -2141,7 +2141,7 @@ Thank you for staying with us!</source>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="110"/>
|
||||
<source>Support tag</source>
|
||||
<translation></translation>
|
||||
<translation>Идентификатор поддержки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="120"/>
|
||||
@@ -2272,12 +2272,12 @@ Thank you for staying with us!</source>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApplication.qml" line="180"/>
|
||||
<source>News Notification</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Уведомления о новостях</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApplication.qml" line="181"/>
|
||||
<source>Show notification icon when has unread news</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>Show a notification icon for unread news</source>
|
||||
<translation>Показывать значок уведомления, если есть непрочитанные новости</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApplication.qml" line="221"/>
|
||||
@@ -3115,17 +3115,17 @@ Thank you for staying with us!</source>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="113"/>
|
||||
<source>Charged to your Apple ID at confirmation. Renews automatically unless auto-renew is turned off at least 24 hours before period end. Manage in Apple ID settings.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Списание с Apple ID при подтверждении. Продление автоматическое, если автопродление не отключено минимум за 24 часа до окончания периода. Управление в настройках Apple ID.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="125"/>
|
||||
<source>Subscribe Now</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Подписаться сейчас</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="158"/>
|
||||
<source>By continuing, you agree to the <a href="%1" style="color: #FBB26A;">Terms of Use</a> and <a href="%2" style="color: #FBB26A;">Privacy Policy</a></source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Продолжая, вы соглашаетесь с <a href="%1" style="color: #FBB26A;">Условиями использования</a> и <a href="%2" style="color: #FBB26A;">Политикой конфиденциальности</a></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="186"/>
|
||||
@@ -3697,7 +3697,7 @@ Thank you for staying with us!</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="270"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="566"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="572"/>
|
||||
<source>Users</source>
|
||||
<translation>Пользователи</translation>
|
||||
</message>
|
||||
@@ -3707,72 +3707,72 @@ Thank you for staying with us!</source>
|
||||
<translation>Имя пользователя</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="582"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="588"/>
|
||||
<source>Search</source>
|
||||
<translation>Поиск</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="711"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="717"/>
|
||||
<source>Creation date: %1</source>
|
||||
<translation>Дата создания: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="723"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="729"/>
|
||||
<source>Latest handshake: %1</source>
|
||||
<translation>Последнее рукопожатие: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="735"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="741"/>
|
||||
<source>Data received: %1</source>
|
||||
<translation>Получено данных: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="747"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="753"/>
|
||||
<source>Data sent: %1</source>
|
||||
<translation>Отправлено данных: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="757"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="763"/>
|
||||
<source>Allowed IPs: %1</source>
|
||||
<translation>Разрешенные подсети: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="772"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="778"/>
|
||||
<source>Rename</source>
|
||||
<translation>Переименовать</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="797"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="803"/>
|
||||
<source>Client name</source>
|
||||
<translation>Имя клиента</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="808"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="814"/>
|
||||
<source>Save</source>
|
||||
<translation>Сохранить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="844"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="850"/>
|
||||
<source>Revoke</source>
|
||||
<translation>Отозвать</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="847"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="853"/>
|
||||
<source>Revoke the config for a user - %1?</source>
|
||||
<translation>Отозвать конфигурацию для пользователя - %1?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="848"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="854"/>
|
||||
<source>The user will no longer be able to connect to your server.</source>
|
||||
<translation>Пользователь больше не сможет подключаться к вашему серверу.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="849"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="855"/>
|
||||
<source>Continue</source>
|
||||
<translation>Продолжить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="850"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="856"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Отменить</translation>
|
||||
</message>
|
||||
@@ -3795,7 +3795,7 @@ Thank you for staying with us!</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="220"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="548"/>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="554"/>
|
||||
<source>Share</source>
|
||||
<translation>Поделиться</translation>
|
||||
</message>
|
||||
@@ -4241,7 +4241,7 @@ Thank you for staying with us!</source>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="32"/>
|
||||
<source>Server error: Linux kernel is too old</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ошибка сервера: ядро Linux слишком старое</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="35"/>
|
||||
@@ -5020,47 +5020,47 @@ FileZilla или другие SFTP-клиенты, а также смонтир
|
||||
<context>
|
||||
<name>SitesController</name>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="24"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="22"/>
|
||||
<source>Hostname not look like ip adress or domain name</source>
|
||||
<translation>Имя хоста не похоже на IP-адрес или доменное имя</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="66"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="52"/>
|
||||
<source>New site added: %1</source>
|
||||
<translation>Добавлен новый сайт: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="78"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="61"/>
|
||||
<source>Site removed: %1</source>
|
||||
<translation>Сайт удален: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="85"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="68"/>
|
||||
<source>Site list cleared!</source>
|
||||
<translation>Список сайтов очищен!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="92"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="75"/>
|
||||
<source>Can't open file: %1</source>
|
||||
<translation>Невозможно открыть файл: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="98"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="81"/>
|
||||
<source>Failed to parse JSON data from file: %1</source>
|
||||
<translation>Не удалось разобрать JSON-данные из файла: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="103"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="86"/>
|
||||
<source>The JSON data is not an array in file: %1</source>
|
||||
<translation>JSON-данные не являются массивом в файле: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="133"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="114"/>
|
||||
<source>Import completed</source>
|
||||
<translation>Импорт завершен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="152"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="133"/>
|
||||
<source>Export completed</source>
|
||||
<translation>Экспорт завершен</translation>
|
||||
</message>
|
||||
|
||||
+863
-1406
File diff suppressed because it is too large
Load Diff
+847
-1390
File diff suppressed because it is too large
Load Diff
+873
-1400
File diff suppressed because it is too large
Load Diff
@@ -447,7 +447,7 @@ bool ApiConfigsController::importService()
|
||||
importSerivceFromAppStore();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
} else if (m_apiServicesModel->getSelectedServiceType() == serviceType::amneziaFree) {
|
||||
importServiceFromGateway();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#include "connectionController.h"
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include <QGuiApplication>
|
||||
#else
|
||||
#include <QApplication>
|
||||
#endif
|
||||
|
||||
#include "utilities.h"
|
||||
#include "core/controllers/vpnConfigurationController.h"
|
||||
#include "version.h"
|
||||
@@ -27,7 +33,7 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
|
||||
|
||||
void ConnectionController::openConnection()
|
||||
{
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true))
|
||||
{
|
||||
emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning);
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <QFileInfo>
|
||||
#include <QImage>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "core/controllers/vpnConfigurationController.h"
|
||||
#include "core/qrCodeUtils.h"
|
||||
#include "core/serialization/serialization.h"
|
||||
@@ -170,8 +169,7 @@ void ExportController::generateWireGuardConfig(const QString &clientName)
|
||||
m_config.append(line + "\n");
|
||||
}
|
||||
|
||||
auto qr = qrCodeUtils::generateQrCode(m_config.toUtf8());
|
||||
m_qrCodes << qrCodeUtils::svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
|
||||
m_qrCodes = qrCodeUtils::generateQrCodeImageSeries(m_config.toUtf8());
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
@@ -191,8 +189,7 @@ void ExportController::generateAwgConfig(const QString &clientName)
|
||||
m_config.append(line + "\n");
|
||||
}
|
||||
|
||||
auto qr = qrCodeUtils::generateQrCode(m_config.toUtf8());
|
||||
m_qrCodes << qrCodeUtils::svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
|
||||
m_qrCodes = qrCodeUtils::generateQrCodeImageSeries(m_config.toUtf8());
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
@@ -604,14 +604,14 @@ bool ImportController::decodeQrCode(const QString &code)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS || defined(Q_OS_TVOS)
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
void ImportController::startDecodingQr()
|
||||
{
|
||||
m_qrCodeChunks.clear();
|
||||
m_totalQrCodeChunksCount = 0;
|
||||
m_receivedQrCodeChunksCount = 0;
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
m_isQrCodeProcessed = true;
|
||||
#endif
|
||||
#if defined Q_OS_ANDROID
|
||||
|
||||
@@ -38,7 +38,7 @@ public slots:
|
||||
QString getConfigFileName();
|
||||
QString getMaliciousWarningText();
|
||||
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS || defined(Q_OS_TVOS)
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
void startDecodingQr();
|
||||
bool parseQrCodeChunk(const QString &code);
|
||||
|
||||
@@ -70,7 +70,7 @@ private:
|
||||
|
||||
void processAmneziaConfig(QJsonObject &config);
|
||||
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS || defined(Q_OS_TVOS)
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
void stopDecodingQr();
|
||||
#endif
|
||||
|
||||
@@ -83,7 +83,7 @@ private:
|
||||
ConfigTypes m_configType;
|
||||
QString m_maliciousWarningText;
|
||||
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS || defined(Q_OS_TVOS)
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
QMap<int, QByteArray> m_qrCodeChunks;
|
||||
bool m_isQrCodeProcessed;
|
||||
int m_totalQrCodeChunksCount;
|
||||
|
||||
@@ -83,8 +83,8 @@ void InstallController::install(DockerContainer container, int port, TransportPr
|
||||
|
||||
int s1 = QRandomGenerator::global()->bounded(15, 150);
|
||||
int s2 = QRandomGenerator::global()->bounded(15, 150);
|
||||
int s3 = QRandomGenerator::global()->bounded(0, 64);
|
||||
int s4 = QRandomGenerator::global()->bounded(0, 20);
|
||||
int s3 = QRandomGenerator::global()->bounded(1, 64);
|
||||
int s4 = QRandomGenerator::global()->bounded(1, 20);
|
||||
|
||||
// Ensure all values are unique and don't create equal packet sizes
|
||||
QSet<int> usedValues;
|
||||
@@ -97,12 +97,12 @@ void InstallController::install(DockerContainer container, int port, TransportPr
|
||||
|
||||
while (usedValues.contains(s3) || s1 + AwgConstant::messageInitiationSize == s3 + AwgConstant::messageCookieReplySize
|
||||
|| s2 + AwgConstant::messageResponseSize == s3 + AwgConstant::messageCookieReplySize) {
|
||||
s3 = QRandomGenerator::global()->bounded(0, 64);
|
||||
s3 = QRandomGenerator::global()->bounded(1, 64);
|
||||
}
|
||||
usedValues.insert(s3);
|
||||
|
||||
while (usedValues.contains(s4)) {
|
||||
s4 = QRandomGenerator::global()->bounded(0, 20);
|
||||
s4 = QRandomGenerator::global()->bounded(1, 20);
|
||||
}
|
||||
|
||||
QString initPacketJunkSize = QString::number(s1);
|
||||
@@ -987,37 +987,33 @@ void InstallController::addEmptyServer()
|
||||
emit installServerFinished(tr("Server added successfully"));
|
||||
}
|
||||
|
||||
bool InstallController::isConfigValid()
|
||||
void InstallController::validateConfig()
|
||||
{
|
||||
int serverIndex = m_serversModel->getDefaultServerIndex();
|
||||
QJsonObject serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
||||
|
||||
if (apiUtils::isServerFromApi(serverConfigObject)) {
|
||||
return true;
|
||||
emit configValidated(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
|
||||
emit noInstalledContainers();
|
||||
return false;
|
||||
emit configValidated(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DockerContainer container = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
|
||||
|
||||
if (container == DockerContainer::None) {
|
||||
emit installationErrorOccurred(ErrorCode::NoInstalledContainersError);
|
||||
return false;
|
||||
emit configValidated(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
|
||||
|
||||
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
|
||||
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
|
||||
|
||||
QFutureWatcher<ErrorCode> watcher;
|
||||
|
||||
QFuture<ErrorCode> future = QtConcurrent::run([this, container, &credentials, &containerConfig, &serverController]() {
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
|
||||
auto isProtocolConfigExists = [](const QJsonObject &containerConfig, const DockerContainer container) {
|
||||
for (Proto protocol : ContainerProps::protocolsForContainer(container)) {
|
||||
@@ -1031,35 +1027,54 @@ bool InstallController::isConfigValid()
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!isProtocolConfigExists(containerConfig, container)) {
|
||||
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
|
||||
errorCode = vpnConfigurationController.createProtocolConfigForContainer(credentials, container, containerConfig);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
return errorCode;
|
||||
if (isProtocolConfigExists(containerConfig, container)) {
|
||||
emit configValidated(true);
|
||||
return;
|
||||
}
|
||||
m_serversModel->updateContainerConfig(container, containerConfig);
|
||||
|
||||
errorCode = m_clientManagementModel->appendClient(container, credentials, containerConfig,
|
||||
QString("Admin [%1]").arg(QSysInfo::prettyProductName()), serverController);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
return errorCode;
|
||||
struct ValidationResult {
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
QJsonObject containerConfig;
|
||||
};
|
||||
|
||||
QFuture<ValidationResult> future =
|
||||
QtConcurrent::run([settings = m_settings, serverController, credentials, containerConfig, container]() mutable {
|
||||
ValidationResult result;
|
||||
result.containerConfig = containerConfig;
|
||||
|
||||
VpnConfigurationsController vpnConfigurationController(settings, serverController);
|
||||
result.errorCode = vpnConfigurationController.createProtocolConfigForContainer(credentials, container,
|
||||
result.containerConfig);
|
||||
return result;
|
||||
});
|
||||
|
||||
QEventLoop wait;
|
||||
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, &wait, &QEventLoop::quit);
|
||||
watcher.setFuture(future);
|
||||
wait.exec();
|
||||
auto *watcher = new QFutureWatcher<ValidationResult>(this);
|
||||
connect(watcher, &QFutureWatcher<ValidationResult>::finished, this,
|
||||
[this, watcher, container, credentials, serverController]() {
|
||||
auto result = watcher->result();
|
||||
watcher->deleteLater();
|
||||
|
||||
ErrorCode errorCode = watcher.result();
|
||||
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
return false;
|
||||
if (result.errorCode != ErrorCode::NoError) {
|
||||
emit installationErrorOccurred(result.errorCode);
|
||||
emit configValidated(false);
|
||||
return;
|
||||
}
|
||||
return true;
|
||||
|
||||
m_serversModel->updateContainerConfig(container, result.containerConfig);
|
||||
|
||||
ErrorCode appendError = m_clientManagementModel->appendClient(
|
||||
container, credentials, result.containerConfig,
|
||||
QString("Admin [%1]").arg(QSysInfo::prettyProductName()), serverController);
|
||||
|
||||
if (appendError != ErrorCode::NoError) {
|
||||
emit installationErrorOccurred(appendError);
|
||||
emit configValidated(false);
|
||||
return;
|
||||
}
|
||||
|
||||
emit configValidated(true);
|
||||
});
|
||||
watcher->setFuture(future);
|
||||
}
|
||||
|
||||
bool InstallController::isUpdateDockerContainerRequired(const DockerContainer container, const QJsonObject &oldConfig,
|
||||
@@ -1070,7 +1085,7 @@ bool InstallController::isUpdateDockerContainerRequired(const DockerContainer co
|
||||
const QJsonObject &oldProtoConfig = oldConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
|
||||
const QJsonObject &newProtoConfig = newConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
|
||||
|
||||
if (container == DockerContainer::Awg2) {
|
||||
if (ContainerProps::isAwgContainer(container)) {
|
||||
const AwgConfig oldConfig(oldProtoConfig);
|
||||
const AwgConfig newConfig(newProtoConfig);
|
||||
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
#define INSTALLCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#if !defined(Q_OS_IOS) && !defined(Q_OS_TVOS)
|
||||
#include <QProcess>
|
||||
#endif
|
||||
#include <QProcess>
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "core/defs.h"
|
||||
@@ -52,9 +50,10 @@ public slots:
|
||||
|
||||
void addEmptyServer();
|
||||
|
||||
bool isConfigValid();
|
||||
void validateConfig();
|
||||
|
||||
signals:
|
||||
void configValidated(bool isValid);
|
||||
void installContainerFinished(const QString &finishMessage, bool isServiceInstall);
|
||||
void installServerFinished(const QString &finishMessage);
|
||||
|
||||
@@ -113,7 +112,7 @@ private:
|
||||
|
||||
QString m_privateKeyPassphrase;
|
||||
|
||||
#if !defined(Q_OS_IOS) && !defined(Q_OS_TVOS)
|
||||
#ifndef Q_OS_IOS
|
||||
QList<QSharedPointer<QProcess>> m_sftpMountProcesses;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#include "pageController.h"
|
||||
#include "utils/converter.h"
|
||||
#include "core/errorstrings.h"
|
||||
#include <QCoreApplication>
|
||||
#if defined(MACOS_NE)
|
||||
#include "platforms/ios/ios_controller.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include <QGuiApplication>
|
||||
#else
|
||||
#include <QApplication>
|
||||
@@ -15,7 +14,7 @@
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
#if defined(Q_OS_MACX) && !defined(Q_OS_TVOS)
|
||||
#if defined Q_OS_MAC
|
||||
#include "ui/macos_util.h"
|
||||
#endif
|
||||
|
||||
@@ -28,7 +27,7 @@ PageController::PageController(const QSharedPointer<ServersModel> &serversModel,
|
||||
AndroidController::instance()->setNavigationBarColor(initialPageNavigationBarColor);
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MACX) && !defined(Q_OS_TVOS)
|
||||
#if defined Q_OS_MACX
|
||||
connect(this, &PageController::raiseMainWindow, []() {
|
||||
setDockIconVisible(true);
|
||||
});
|
||||
@@ -65,7 +64,7 @@ QString PageController::getPagePath(PageLoader::PageEnum page)
|
||||
void PageController::closeWindow()
|
||||
{
|
||||
// On mobile platforms, quit app on close; on desktop, just hide window
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
qApp->quit();
|
||||
#else
|
||||
emit hideMainWindow();
|
||||
@@ -119,7 +118,7 @@ void PageController::showOnStartup()
|
||||
} else {
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
emit hideMainWindow();
|
||||
#elif defined(Q_OS_MACX) && !defined(Q_OS_TVOS)
|
||||
#elif defined(Q_OS_MACX)
|
||||
setDockIconVisible(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include <AmneziaVPN-Swift.h>
|
||||
#endif
|
||||
|
||||
@@ -57,8 +57,6 @@ QString getPlatformName()
|
||||
return "Windows";
|
||||
#elif defined(Q_OS_ANDROID)
|
||||
return "Android";
|
||||
#elif defined(Q_OS_TVOS)
|
||||
return "tvOS";
|
||||
#elif defined(Q_OS_LINUX)
|
||||
return "Linux";
|
||||
#elif defined(Q_OS_MACX)
|
||||
@@ -111,7 +109,7 @@ bool SettingsController::isLoggingEnabled()
|
||||
void SettingsController::toggleLogging(bool enable)
|
||||
{
|
||||
m_settings->setSaveLogs(enable);
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#if defined(Q_OS_IOS)
|
||||
AmneziaVPN::toggleLogging(enable);
|
||||
#endif
|
||||
if (enable == true) {
|
||||
@@ -160,6 +158,7 @@ void SettingsController::clearLogs()
|
||||
|
||||
qInfo().noquote() << QString("Started %1 version %2 %3").arg(APPLICATION_NAME, APP_VERSION, GIT_COMMIT_HASH);
|
||||
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||
qInfo().noquote() << QString("SSL backend: %1").arg(QSslSocket::sslLibraryVersionString());
|
||||
}
|
||||
|
||||
void SettingsController::backupAppConfig(const QString &fileName)
|
||||
@@ -179,12 +178,11 @@ void SettingsController::backupAppConfig(const QString &fileName)
|
||||
|
||||
void SettingsController::restoreAppConfig(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
||||
QByteArray data = file.readAll();
|
||||
|
||||
QByteArray data;
|
||||
if (!SystemController::readFile(fileName, data)) {
|
||||
emit changeSettingsErrorOccurred(tr("Can't open file: %1").arg(fileName));
|
||||
return;
|
||||
}
|
||||
restoreAppConfigFromData(data);
|
||||
}
|
||||
|
||||
@@ -194,7 +192,7 @@ void SettingsController::restoreAppConfigFromData(const QByteArray &data)
|
||||
if (ok) {
|
||||
QJsonObject newConfigData = QJsonDocument::fromJson(data).object();
|
||||
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) || (defined(Q_OS_MACX) && !defined(Q_OS_TVOS))
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) || defined(Q_OS_MACX)
|
||||
bool autoStart = false;
|
||||
if (newConfigData.contains("Conf/autoStart")) {
|
||||
autoStart = newConfigData["Conf/autoStart"].toBool();
|
||||
@@ -231,7 +229,7 @@ void SettingsController::restoreAppConfigFromData(const QByteArray &data)
|
||||
m_sitesModel->setRouteMode(siteSplitTunnelingRouteMode);
|
||||
m_sitesModel->toggleSplitTunneling(siteSplittunnelingEnabled);
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
m_settings->setAutoConnect(false);
|
||||
m_settings->setStartMinimized(false);
|
||||
m_settings->setKillSwitchEnabled(false);
|
||||
@@ -270,7 +268,7 @@ void SettingsController::clearSettings()
|
||||
|
||||
emit changeSettingsFinished(tr("All settings have been reset to default values"));
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
AmneziaVPN::clearSettings();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -7,10 +7,8 @@
|
||||
#include "systemController.h"
|
||||
#include "core/networkUtilities.h"
|
||||
|
||||
SitesController::SitesController(const std::shared_ptr<Settings> &settings,
|
||||
const QSharedPointer<VpnConnection> &vpnConnection,
|
||||
const QSharedPointer<SitesModel> &sitesModel, QObject *parent)
|
||||
: QObject(parent), m_settings(settings), m_vpnConnection(vpnConnection), m_sitesModel(sitesModel)
|
||||
SitesController::SitesController(const std::shared_ptr<Settings> &settings, const QSharedPointer<SitesModel> &sitesModel, QObject *parent)
|
||||
: QObject(parent), m_settings(settings), m_sitesModel(sitesModel)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -34,32 +32,20 @@ void SitesController::addSite(QString hostname)
|
||||
hostname = hostname.split("/", Qt::SkipEmptyParts).first();
|
||||
}
|
||||
|
||||
const auto &processSite = [this](const QString &hostname, const QString &ip) {
|
||||
m_sitesModel->addSite(hostname, ip);
|
||||
|
||||
if (!ip.isEmpty()) {
|
||||
QMetaObject::invokeMethod(m_vpnConnection.get(), "addRoutes", Qt::QueuedConnection,
|
||||
Q_ARG(QStringList, QStringList() << ip));
|
||||
} else if (NetworkUtilities::ipAddressWithSubnetRegExp().exactMatch(hostname)) {
|
||||
QMetaObject::invokeMethod(m_vpnConnection.get(), "addRoutes", Qt::QueuedConnection,
|
||||
Q_ARG(QStringList, QStringList() << hostname));
|
||||
}
|
||||
};
|
||||
|
||||
const auto &resolveCallback = [this, processSite](const QHostInfo &hostInfo) {
|
||||
const auto &resolveCallback = [this](const QHostInfo &hostInfo) {
|
||||
const QList<QHostAddress> &addresses = hostInfo.addresses();
|
||||
for (const QHostAddress &addr : hostInfo.addresses()) {
|
||||
if (addr.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) {
|
||||
processSite(hostInfo.hostName(), addr.toString());
|
||||
m_sitesModel->addSite(hostInfo.hostName(), addr.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (NetworkUtilities::ipAddressWithSubnetRegExp().exactMatch(hostname)) {
|
||||
processSite(hostname, "");
|
||||
m_sitesModel->addSite(hostname, "");
|
||||
} else {
|
||||
processSite(hostname, "");
|
||||
m_sitesModel->addSite(hostname, "");
|
||||
QHostInfo::lookupHost(hostname, this, resolveCallback);
|
||||
}
|
||||
|
||||
@@ -72,9 +58,6 @@ void SitesController::removeSite(int index)
|
||||
auto hostname = m_sitesModel->data(modelIndex, SitesModel::Roles::UrlRole).toString();
|
||||
m_sitesModel->removeSite(modelIndex);
|
||||
|
||||
QMetaObject::invokeMethod(m_vpnConnection.get(), "deleteRoutes", Qt::QueuedConnection,
|
||||
Q_ARG(QStringList, QStringList() << hostname));
|
||||
|
||||
emit finished(tr("Site removed: %1").arg(hostname));
|
||||
}
|
||||
|
||||
@@ -128,8 +111,6 @@ void SitesController::importSites(const QString &fileName, bool replaceExisting)
|
||||
|
||||
m_sitesModel->addSites(sites, replaceExisting);
|
||||
|
||||
QMetaObject::invokeMethod(m_vpnConnection.get(), "addRoutes", Qt::QueuedConnection, Q_ARG(QStringList, ips));
|
||||
|
||||
emit finished(tr("Import completed"));
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,8 @@ class SitesController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SitesController(const std::shared_ptr<Settings> &settings,
|
||||
const QSharedPointer<VpnConnection> &vpnConnection,
|
||||
const QSharedPointer<SitesModel> &sitesModel, QObject *parent = nullptr);
|
||||
explicit SitesController(const std::shared_ptr<Settings> &settings, const QSharedPointer<SitesModel> &sitesModel,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void addSite(QString hostname);
|
||||
@@ -31,8 +30,6 @@ signals:
|
||||
|
||||
private:
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
QSharedPointer<VpnConnection> m_vpnConnection;
|
||||
QSharedPointer<SitesModel> m_sitesModel;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include "platforms/ios/ios_controller.h"
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
@@ -31,7 +31,7 @@ void SystemController::saveFile(const QString &fileName, const QString &data)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#ifdef Q_OS_IOS
|
||||
QUrl fileUrl = QDir::tempPath() + "/" + fileName;
|
||||
QFile file(fileUrl.toString());
|
||||
#else
|
||||
@@ -43,7 +43,7 @@ void SystemController::saveFile(const QString &fileName, const QString &data)
|
||||
file.write(data.toUtf8());
|
||||
file.close();
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#ifdef Q_OS_IOS
|
||||
QStringList filesToSend;
|
||||
filesToSend.append(fileUrl.toString());
|
||||
// todo check if save successful
|
||||
@@ -98,7 +98,7 @@ QString SystemController::getFileName(const QString &acceptLabel, const QString
|
||||
return AndroidController::instance()->openFile(nameFilter);
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#ifdef Q_OS_IOS
|
||||
|
||||
fileName = IosController::Instance()->openFile();
|
||||
if (fileName.isEmpty()) {
|
||||
|
||||
@@ -52,7 +52,9 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
case IsComponentVisibleRole: {
|
||||
return m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2
|
||||
|| m_accountInfoData.configType == apiDefs::ConfigType::ExternalPremium;
|
||||
|| m_accountInfoData.configType == apiDefs::ConfigType::AmneziaTrialV2
|
||||
|| m_accountInfoData.configType == apiDefs::ConfigType::ExternalPremium
|
||||
|| m_accountInfoData.configType == apiDefs::ConfigType::ExternalTrial;
|
||||
}
|
||||
case HasExpiredWorkerRole: {
|
||||
for (int i = 0; i < m_issuedConfigsInfo.size(); i++) {
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace
|
||||
{
|
||||
constexpr char amneziaFree[] = "amnezia-free";
|
||||
constexpr char amneziaPremium[] = "amnezia-premium";
|
||||
constexpr char amneziaTrial[] = "amnezia-trial";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
case CardDescriptionRole: {
|
||||
auto speed = apiServiceData.serviceInfo.speed;
|
||||
if (serviceType == serviceType::amneziaPremium) {
|
||||
if (serviceType == serviceType::amneziaPremium || serviceType == serviceType::amneziaTrial) {
|
||||
return apiServiceData.serviceInfo.cardDescription.arg(speed);
|
||||
} else if (serviceType == serviceType::amneziaFree) {
|
||||
QString description = apiServiceData.serviceInfo.cardDescription;
|
||||
@@ -124,8 +125,10 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||
case OrderRole: {
|
||||
if (serviceType == serviceType::amneziaPremium) {
|
||||
return 0;
|
||||
} else if (serviceType == serviceType::amneziaFree) {
|
||||
} else if (serviceType == serviceType::amneziaTrial) {
|
||||
return 1;
|
||||
} else if (serviceType == serviceType::amneziaFree) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,10 +141,12 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
|
||||
serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
||||
m_serverProtocolConfig[config_key::responsePacketJunkSize] =
|
||||
serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
|
||||
if (protocolVersion == protocols::awg::awgV2) {
|
||||
m_serverProtocolConfig[config_key::cookieReplyPacketJunkSize] =
|
||||
serverProtocolConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize);
|
||||
m_serverProtocolConfig[config_key::transportPacketJunkSize] =
|
||||
serverProtocolConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize);
|
||||
}
|
||||
m_serverProtocolConfig[config_key::initPacketMagicHeader] =
|
||||
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
||||
m_serverProtocolConfig[config_key::responsePacketMagicHeader] =
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <QDebug>
|
||||
#include "notificationhandler.h"
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#if defined(Q_OS_IOS)
|
||||
# include "platforms/ios/iosnotificationhandler.h"
|
||||
#else
|
||||
# include "systemtray_notificationhandler.h"
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
// static
|
||||
NotificationHandler* NotificationHandler::create(QObject* parent) {
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||
#if defined(Q_OS_IOS)
|
||||
return new IOSNotificationHandler(parent);
|
||||
#else
|
||||
return new SystemTrayNotificationHandler(parent);
|
||||
|
||||
@@ -58,7 +58,7 @@ QString Autostart::appPath() {
|
||||
return QCoreApplication::applicationFilePath() + " --autostart";
|
||||
}
|
||||
|
||||
#elif defined(Q_OS_MACX) && !defined(Q_OS_TVOS)
|
||||
#elif defined Q_OS_MACX
|
||||
|
||||
bool Autostart::isAutostart() {
|
||||
QProcess process;
|
||||
|
||||
@@ -8,9 +8,10 @@ Item {
|
||||
id: root
|
||||
|
||||
property StackView stackView: StackView.view
|
||||
property bool enableTimer: true
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
if (visible && enableTimer) {
|
||||
timer.start()
|
||||
}
|
||||
}
|
||||
@@ -24,6 +25,6 @@ Item {
|
||||
FocusController.setFocusOnDefaultItem()
|
||||
}
|
||||
repeat: false // Stop the timer after one trigger
|
||||
running: true // Start the timer
|
||||
running: enableTimer // Start the timer
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,6 +330,8 @@ PageType {
|
||||
AwgTextField {
|
||||
id: cookieReplyPacketJunkSizeTextField
|
||||
|
||||
visible: isAwg2
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
@@ -342,6 +344,8 @@ PageType {
|
||||
AwgTextField {
|
||||
id: transportPacketJunkSizeTextField
|
||||
|
||||
visible: isAwg2
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ PageType {
|
||||
Layout.margins: 16
|
||||
|
||||
text: qsTr("News Notification")
|
||||
descriptionText: qsTr("Show notification icon when has unread news")
|
||||
descriptionText: qsTr("Show a notification icon for unread news")
|
||||
|
||||
checked: SettingsController.isNewsNotificationsEnabled()
|
||||
onToggled: function() {
|
||||
|
||||
@@ -122,7 +122,7 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: ApiServicesModel.getSelectedServiceType() === "amnezia-premium" ? qsTr("Subscribe Now") : qsTr("Connect")
|
||||
text: ApiServicesModel.getSelectedServiceType() === "amnezia-premium" ? qsTr("Subscribe Now") : (ApiServicesModel.getSelectedServiceType() === "amnezia-trial" ? qsTr("Try Trial") : qsTr("Connect"))
|
||||
|
||||
clickedFunc: function() {
|
||||
PageController.showBusyIndicator(true)
|
||||
|
||||
@@ -79,11 +79,23 @@ PageType {
|
||||
}
|
||||
|
||||
textField.onTextChanged: {
|
||||
if (headerText == qsTr("Password or SSH private key")) {
|
||||
if (headerText === qsTr("Password or SSH private key")) {
|
||||
buttonImageSource = textField.text !== "" ? imageSource : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WarningType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 8
|
||||
|
||||
visible: title === qsTr("Password or SSH private key")
|
||||
backGroundColor: AmneziaStyle.color.translucentWhite
|
||||
iconPath: "qrc:/images/controls/alert-circle.svg"
|
||||
textString: qsTr("SSH key requirements: supported ED25519 or RSA in PEM. Paste the private key including BEGIN/END lines. If your key doesn’t work, generate a compatible one.")
|
||||
}
|
||||
}
|
||||
|
||||
footer: ColumnLayout {
|
||||
|
||||
@@ -13,6 +13,7 @@ import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
enableTimer: (SettingsController.isOnTv()) ? false : true
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
@@ -45,4 +46,22 @@ PageType {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 250
|
||||
running: SettingsController.isOnTv()
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
startButton.forceActiveFocus()
|
||||
if (startButton.activeFocus) {
|
||||
running = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible && SettingsController.isOnTv()) {
|
||||
startButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +505,13 @@ PageType {
|
||||
exportTypeSelector.currentIndex = 0
|
||||
}
|
||||
selectedIndex = exportTypeSelector.currentIndex
|
||||
exportTypeSelector.text = selectedText
|
||||
if (model.length > 0 && model[selectedIndex] && model[selectedIndex].name !== undefined) {
|
||||
exportTypeSelectorListView.selectedText = model[selectedIndex].name
|
||||
exportTypeSelector.text = model[selectedIndex].name
|
||||
} else {
|
||||
exportTypeSelectorListView.selectedText = ""
|
||||
exportTypeSelector.text = ""
|
||||
}
|
||||
}
|
||||
|
||||
rootWidth: root.width
|
||||
|
||||
@@ -278,7 +278,6 @@ PageType {
|
||||
}
|
||||
|
||||
Keys.onPressed: function(event) {
|
||||
console.debug(">>>> ", event.key, " Event is caught by StartPage")
|
||||
switch (event.key) {
|
||||
case Qt.Key_Tab:
|
||||
case Qt.Key_Down:
|
||||
|
||||
+12
-3
@@ -21,10 +21,14 @@ Window {
|
||||
function onStateChanged() {
|
||||
if (Qt.platform.os === "android") {
|
||||
if (Qt.application.state === Qt.ApplicationActive) {
|
||||
root.visible = true
|
||||
refreshTimer.restart()
|
||||
} else if (Qt.application.state === Qt.ApplicationSuspended ||
|
||||
Qt.application.state === Qt.ApplicationInactive) {
|
||||
console.log("QML: Application going to background, state:", Qt.application.state)
|
||||
} else if (Qt.application.state === Qt.ApplicationSuspended) {
|
||||
// Hide window to stop the Qt render loop and prevent
|
||||
// eglSwapBuffers from being called on a lost EGL context.
|
||||
// NOTE: Do NOT hide on ApplicationInactive — that fires on any
|
||||
// focus change (IME, notifications) and would blank the screen.
|
||||
root.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,6 +60,11 @@ Window {
|
||||
PageController.closeWindow()
|
||||
}
|
||||
|
||||
onSceneGraphError: function(error, message) {
|
||||
// Prevent qFatal crash on Android when EGL context is lost
|
||||
console.warn("Scene graph error:", error, message)
|
||||
}
|
||||
|
||||
title: "AmneziaVPN"
|
||||
|
||||
Item { // This item is needed for focus handling
|
||||
|
||||
+20
-4
@@ -190,7 +190,7 @@ bool Utils::processIsRunning(const QString &fileName, const bool fullFlag)
|
||||
CloseHandle(hSnapshot);
|
||||
return false;
|
||||
|
||||
#elif defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(Q_OS_ANDROID) || defined(MACOS_NE)
|
||||
#elif defined(Q_OS_IOS) || defined(Q_OS_ANDROID) || defined(MACOS_NE)
|
||||
return false;
|
||||
#else
|
||||
QProcess process;
|
||||
@@ -250,7 +250,7 @@ bool Utils::killProcessByName(const QString &name)
|
||||
|
||||
CloseHandle(hSnapshot);
|
||||
return success;
|
||||
#elif defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(Q_OS_ANDROID)
|
||||
#elif defined Q_OS_IOS || defined(Q_OS_ANDROID)
|
||||
return false;
|
||||
#else
|
||||
return QProcess::execute("pkill", { name }) == 0;
|
||||
@@ -259,7 +259,15 @@ bool Utils::killProcessByName(const QString &name)
|
||||
|
||||
QString Utils::openVpnExecPath()
|
||||
{
|
||||
return Utils::executable("openvpn", true);
|
||||
#ifdef Q_OS_WIN
|
||||
return Utils::executable("openvpn/openvpn", true);
|
||||
#elif defined Q_OS_LINUX
|
||||
// We have service that runs OpenVPN on Linux. We need to make same
|
||||
// path for client and service.
|
||||
return Utils::executable("../../client/bin/openvpn", true);
|
||||
#else
|
||||
return Utils::executable("/openvpn", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString Utils::wireguardExecPath()
|
||||
@@ -287,7 +295,15 @@ QString Utils::certUtilPath()
|
||||
|
||||
QString Utils::tun2socksPath()
|
||||
{
|
||||
return Utils::executable("tun2socks", true);
|
||||
#ifdef Q_OS_WIN
|
||||
return Utils::executable("xray/tun2socks", true);
|
||||
#elif defined Q_OS_LINUX
|
||||
// We have service that runs OpenVPN on Linux. We need to make same
|
||||
// path for client and service.
|
||||
return Utils::executable("../../client/bin/tun2socks", true);
|
||||
#else
|
||||
return Utils::executable("/tun2socks", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include "platforms/ios/ios_controller.h"
|
||||
#endif
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
VpnConnection::VpnConnection(std::shared_ptr<Settings> settings, QObject *parent)
|
||||
: QObject(parent), m_settings(settings), m_checkTimer(new QTimer(this))
|
||||
{
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
m_checkTimer.setInterval(1000);
|
||||
connect(IosController::Instance(), &IosController::connectionStateChanged, this, &VpnConnection::onConnectionStateChanged);
|
||||
connect(IosController::Instance(), &IosController::connectionStateChanged, this, &VpnConnection::setConnectionState);
|
||||
connect(IosController::Instance(), &IosController::bytesChanged, this, &VpnConnection::onBytesChanged);
|
||||
#endif
|
||||
}
|
||||
@@ -127,7 +127,7 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
});
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
if (state == Vpn::ConnectionState::Connected ||
|
||||
state == Vpn::ConnectionState::Connecting ||
|
||||
state == Vpn::ConnectionState::Reconnecting) {
|
||||
@@ -243,7 +243,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
|
||||
|
||||
appendSplitTunnelingConfig();
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !defined(MACOS_NE)
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
m_vpnProtocol.reset(VpnProtocol::factory(container, m_vpnConfiguration));
|
||||
if (!m_vpnProtocol) {
|
||||
setConnectionState(Vpn::ConnectionState::Error);
|
||||
@@ -255,7 +255,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
|
||||
createAndroidConnections();
|
||||
|
||||
m_vpnProtocol.reset(androidVpnProtocol);
|
||||
#elif defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#elif defined Q_OS_IOS || defined(MACOS_NE)
|
||||
Proto proto = ContainerProps::defaultProtocol(container);
|
||||
IosController::Instance()->connectVpn(proto, m_vpnConfiguration);
|
||||
connect(&m_checkTimer, &QTimer::timeout, IosController::Instance(), &IosController::checkStatus);
|
||||
@@ -446,7 +446,7 @@ void VpnConnection::reconnectToVpn() {
|
||||
|
||||
void VpnConnection::disconnectFromVpn()
|
||||
{
|
||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) || defined(MACOS_NE)
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
// iOS/macOS NE use IosController directly; m_vpnProtocol is not set there.
|
||||
IosController::Instance()->disconnectVpn();
|
||||
disconnect(&m_checkTimer, &QTimer::timeout, IosController::Instance(), &IosController::checkStatus);
|
||||
@@ -464,7 +464,7 @@ void VpnConnection::disconnectFromVpn()
|
||||
*connection = connect(AndroidController::instance(), &AndroidController::vpnStateChanged, this,
|
||||
[this, connection](AndroidController::ConnectionState state) {
|
||||
if (state == AndroidController::ConnectionState::DISCONNECTED) {
|
||||
onConnectionStateChanged(Vpn::ConnectionState::Disconnected);
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
disconnect(*connection);
|
||||
delete connection;
|
||||
}
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
set(CPACK_PACKAGE_VENDOR AmneziaVPN)
|
||||
set(CPACK_PACKAGE_VERSION ${AMNEZIAVPN_VERSION})
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY AmneziaVPN)
|
||||
set(CPACK_PACKAGE_EXECUTABLES AmneziaVPN AmneziaVPN)
|
||||
set(CPACK_PRE_BUILD_SCRIPTS ${CMAKE_CURRENT_LIST_DIR}/sign_binaries.cmake)
|
||||
set(CPACK_POST_BUILD_SCRIPTS ${CMAKE_CURRENT_LIST_DIR}/sign_packages.cmake)
|
||||
set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_CURRENT_LIST_DIR}/CPackOptions.cmake)
|
||||
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/deploy/data/LICENSE.txt)
|
||||
|
||||
list(PREPEND CPACK_COMPONENTS_ALL AmneziaVPN)
|
||||
|
||||
if(APPLE)
|
||||
set(CPACK_GENERATOR productbuild)
|
||||
else()
|
||||
set(CPACK_GENERATOR IFW)
|
||||
endif()
|
||||
|
||||
# === CPack IFW generator settings ===
|
||||
set(CPACK_IFW_PACKAGE_NAME AmneziaVPN)
|
||||
set(CPACK_IFW_PACKAGE_TITLE AmneziaVPN)
|
||||
set(CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH 600)
|
||||
set(CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT 380)
|
||||
set(CPACK_IFW_PACKAGE_WIZARD_STYLE Modern)
|
||||
set(CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR ON)
|
||||
set(CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH ON)
|
||||
set(CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS ON)
|
||||
set(CPACK_IFW_PACKAGE_CONTROL_SCRIPT ${CMAKE_SOURCE_DIR}/deploy/installer/qif/controlscript.js)
|
||||
|
||||
# === CPack WIX generator settings ===
|
||||
set(CPACK_WIX_VERSION 4)
|
||||
set(CPACK_WIX_UPGRADE_GUID "{2D55AC62-96D6-4692-8C05-0D85BBF95485}")
|
||||
set(CPACK_WIX_PRODUCT_ICON ${CMAKE_SOURCE_DIR}/client/images/app.ico)
|
||||
set(CPACK_WIX_CUSTOM_XMLNS "util=http://wixtoolset.org/schemas/v4/wxs/util")
|
||||
set(_AMNEZIA_WIX_PATCH_SERVICE ${CMAKE_SOURCE_DIR}/deploy/installer/wix/service_install_patch.xml)
|
||||
set(_AMNEZIA_WIX_PATCH_CLOSE_APP ${CMAKE_SOURCE_DIR}/deploy/installer/wix/close_client_patch.xml)
|
||||
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_SERVICE}" _AMNEZIA_WIX_PATCH_SERVICE_CMAKE)
|
||||
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_CLOSE_APP}" _AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE)
|
||||
list(APPEND CPACK_WIX_PATCH_FILE "${_AMNEZIA_WIX_PATCH_SERVICE_CMAKE}" "${_AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE}")
|
||||
list(APPEND CPACK_WIX_EXTENSIONS "WixToolset.Util.wixext")
|
||||
|
||||
# === CPack productbuild generator settings ===
|
||||
set(CPACK_PRODUCTBUILD_IDENTIFIER org.amneziavpn)
|
||||
set(CPACK_PREFLIGHT_AMNEZIAVPN_SCRIPT ${CMAKE_SOURCE_DIR}/deploy/data/macos/post_uninstall.sh)
|
||||
set(CPACK_POSTFLIGHT_AMNEZIAVPN_SCRIPT ${CMAKE_SOURCE_DIR}/deploy/data/macos/post_install.sh)
|
||||
set(CPACK_POSTFLIGHT_UNINSTALL_SCRIPT ${CMAKE_SOURCE_DIR}/deploy/data/macos/post_uninstall.sh)
|
||||
# provide custom CPack.distribution.dist.in
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/deploy/data/macos)
|
||||
|
||||
if(LINUX AND NOT ANDROID)
|
||||
install(FILES
|
||||
${CMAKE_SOURCE_DIR}/deploy/data/linux/AmneziaVPN.service
|
||||
${CMAKE_SOURCE_DIR}/deploy/data/linux/AmneziaVPN.png
|
||||
${CMAKE_SOURCE_DIR}/deploy/data/linux/AmneziaVPN.desktop
|
||||
${CMAKE_SOURCE_DIR}/deploy/data/linux/post_install.sh
|
||||
${CMAKE_SOURCE_DIR}/deploy/data/linux/post_uninstall.sh
|
||||
DESTINATION "."
|
||||
COMPONENT AmneziaVPN
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
install(FILES
|
||||
${CMAKE_SOURCE_DIR}/deploy/data/windows/post_install.cmd
|
||||
${CMAKE_SOURCE_DIR}/deploy/data/windows/post_uninstall.cmd
|
||||
DESTINATION "."
|
||||
COMPONENT AmneziaVPN
|
||||
)
|
||||
endif()
|
||||
|
||||
if (APPLE AND NOT IOS AND NOT MACOS_NE)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/deploy/data/macos/AmneziaVPN.plist
|
||||
DESTINATION "AmneziaVPN.app/Contents/Resources"
|
||||
COMPONENT AmneziaVPN
|
||||
)
|
||||
endif()
|
||||
|
||||
include(CPackIFW)
|
||||
cpack_ifw_configure_component(AmneziaVPN
|
||||
VERSION ${AMNEZIAVPN_VERSION}
|
||||
RELEASE_DATE ${RELEASE_DATE}
|
||||
REQUIRES_ADMIN_RIGHTS
|
||||
FORCED_INSTALLATION
|
||||
SCRIPT ${CMAKE_SOURCE_DIR}/deploy/installer/qif/componentscript.js
|
||||
)
|
||||
|
||||
include(CPack)
|
||||
cpack_add_component(Uninstall
|
||||
DISPLAY_NAME "Uninstall AmneziaVPN"
|
||||
REQUIRES_ADMIN_RIGHTS
|
||||
DISABLED
|
||||
)
|
||||
@@ -1,17 +0,0 @@
|
||||
set(CPACK_COMPONENTS_ALL AmneziaVPN)
|
||||
|
||||
if (CPACK_GENERATOR STREQUAL productbuild)
|
||||
list(APPEND CPACK_COMPONENTS_ALL Uninstall)
|
||||
endif()
|
||||
|
||||
if(NOT CODESIGN_INSTALLER_SIGNATURE)
|
||||
set(CODESIGN_INSTALLER_SIGNATURE "$ENV{CODESIGN_INSTALLER_SIGNATURE}")
|
||||
endif()
|
||||
set(CPACK_PRODUCTBUILD_IDENTITY_NAME "${CODESIGN_INSTALLER_SIGNATURE}")
|
||||
set(CPACK_PKGBUILD_IDENTITY_NAME "${CODESIGN_INSTALLER_SIGNATURE}")
|
||||
|
||||
if(NOT CODESIGN_INSTALLER_KEYCHAIN)
|
||||
set(CODESIGN_INSTALLER_KEYCHAIN "$ENV{CODESIGN_INSTALLER_KEYCHAIN}")
|
||||
endif()
|
||||
set(CPACK_PRODUCTBUILD_KEYCHAIN_PATH "${CODESIGN_INSTALLER_KEYCHAIN}")
|
||||
set(CPACK_PKGBUILD_KEYCHAIN_PATH "${CODESIGN_INSTALLER_KEYCHAIN}")
|
||||
@@ -1,722 +0,0 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2024 JFrog
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
set(CONAN_MINIMUM_VERSION 2.0.5)
|
||||
|
||||
# Create a new policy scope and set the minimum required cmake version so the
|
||||
# features behind a policy setting like if(... IN_LIST ...) behaves as expected
|
||||
# even if the parent project does not specify a minimum cmake version or a minimum
|
||||
# version less than this module requires (e.g. 3.0) before the first project() call.
|
||||
# (see: https://cmake.org/cmake/help/latest/variable/CMAKE_PROJECT_TOP_LEVEL_INCLUDES.html)
|
||||
#
|
||||
# The policy-affecting calls like cmake_policy(SET...) or `cmake_minimum_required` only
|
||||
# affects the current policy scope, i.e. between the PUSH and POP in this case.
|
||||
#
|
||||
# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Policies.html#the-policy-stack
|
||||
cmake_policy(PUSH)
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
|
||||
function(detect_os os os_api_level os_sdk os_subsystem os_version)
|
||||
# it could be cross compilation
|
||||
message(STATUS "CMake-Conan: cmake_system_name=${CMAKE_SYSTEM_NAME}")
|
||||
if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set(${os} Macos PARENT_SCOPE)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "QNX")
|
||||
set(${os} Neutrino PARENT_SCOPE)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "CYGWIN")
|
||||
set(${os} Windows PARENT_SCOPE)
|
||||
set(${os_subsystem} cygwin PARENT_SCOPE)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "^MSYS")
|
||||
set(${os} Windows PARENT_SCOPE)
|
||||
set(${os_subsystem} msys2 PARENT_SCOPE)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
||||
# https://github.com/emscripten-core/emscripten/blob/4.0.6/cmake/Modules/Platform/Emscripten.cmake#L17C1-L17C34
|
||||
set(${os} Emscripten PARENT_SCOPE)
|
||||
else()
|
||||
set(${os} ${CMAKE_SYSTEM_NAME} PARENT_SCOPE)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
if(DEFINED ANDROID_PLATFORM)
|
||||
string(REGEX MATCH "[0-9]+" _os_api_level ${ANDROID_PLATFORM})
|
||||
elseif(DEFINED CMAKE_SYSTEM_VERSION)
|
||||
set(_os_api_level ${CMAKE_SYSTEM_VERSION})
|
||||
endif()
|
||||
message(STATUS "CMake-Conan: android api level=${_os_api_level}")
|
||||
set(${os_api_level} ${_os_api_level} PARENT_SCOPE)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS")
|
||||
# CMAKE_OSX_SYSROOT contains the full path to the SDK for MakeFile/Ninja
|
||||
# generators, but just has the original input string for Xcode.
|
||||
if(NOT IS_DIRECTORY ${CMAKE_OSX_SYSROOT})
|
||||
set(_os_sdk ${CMAKE_OSX_SYSROOT})
|
||||
else()
|
||||
if(CMAKE_OSX_SYSROOT MATCHES Simulator)
|
||||
set(apple_platform_suffix simulator)
|
||||
else()
|
||||
set(apple_platform_suffix os)
|
||||
endif()
|
||||
if(CMAKE_OSX_SYSROOT MATCHES AppleTV)
|
||||
set(_os_sdk "appletv${apple_platform_suffix}")
|
||||
elseif(CMAKE_OSX_SYSROOT MATCHES iPhone)
|
||||
set(_os_sdk "iphone${apple_platform_suffix}")
|
||||
elseif(CMAKE_OSX_SYSROOT MATCHES Watch)
|
||||
set(_os_sdk "watch${apple_platform_suffix}")
|
||||
endif()
|
||||
endif()
|
||||
if(DEFINED os_sdk)
|
||||
message(STATUS "CMake-Conan: cmake_osx_sysroot=${CMAKE_OSX_SYSROOT}")
|
||||
set(${os_sdk} ${_os_sdk} PARENT_SCOPE)
|
||||
endif()
|
||||
if(DEFINED CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
message(STATUS "CMake-Conan: cmake_osx_deployment_target=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
set(${os_version} ${CMAKE_OSX_DEPLOYMENT_TARGET} PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(detect_arch arch)
|
||||
# CMAKE_OSX_ARCHITECTURES can contain multiple architectures, but Conan only supports one.
|
||||
# Therefore this code only finds one. If the recipes support multiple architectures, the
|
||||
# build will work. Otherwise, there will be a linker error for the missing architecture(s).
|
||||
if(DEFINED CMAKE_OSX_ARCHITECTURES)
|
||||
string(REPLACE " " ";" apple_arch_list "${CMAKE_OSX_ARCHITECTURES}")
|
||||
list(LENGTH apple_arch_list apple_arch_count)
|
||||
if(apple_arch_count GREATER 1)
|
||||
message(WARNING "CMake-Conan: Multiple architectures detected, this will only work if Conan recipe(s) produce fat binaries.")
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS" AND NOT CMAKE_OSX_ARCHITECTURES STREQUAL "")
|
||||
set(host_arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
elseif(MSVC)
|
||||
set(host_arch ${CMAKE_CXX_COMPILER_ARCHITECTURE_ID})
|
||||
else()
|
||||
set(host_arch ${CMAKE_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
if(host_arch MATCHES "aarch64|arm64|ARM64")
|
||||
list(APPEND _arch armv8)
|
||||
endif()
|
||||
if(host_arch MATCHES "armv7|armv7-a|armv7l|ARMV7")
|
||||
list(APPEND _arch armv7)
|
||||
endif()
|
||||
if(host_arch MATCHES armv7s)
|
||||
list(APPEND _arch armv7s)
|
||||
endif()
|
||||
if(host_arch MATCHES "i686|i386|X86")
|
||||
list(APPEND _arch x86)
|
||||
endif()
|
||||
if(host_arch MATCHES "AMD64|amd64|x86_64|x64")
|
||||
list(APPEND _arch x86_64)
|
||||
endif()
|
||||
if(EMSCRIPTEN)
|
||||
# https://github.com/emscripten-core/emscripten/blob/4.0.6/cmake/Modules/Platform/Emscripten.cmake#L294C1-L294C80
|
||||
list(APPEND _arch wasm)
|
||||
endif()
|
||||
message(STATUS "CMake-Conan: cmake_system_processor=${_arch}")
|
||||
list(JOIN _arch "|" _arch)
|
||||
set(${arch} ${_arch} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(detect_cxx_standard compiler cxx_standard)
|
||||
set(${cxx_standard} ${CMAKE_CXX_STANDARD} PARENT_SCOPE)
|
||||
if(CMAKE_CXX_EXTENSIONS)
|
||||
if(compiler STREQUAL "msvc")
|
||||
set(${cxx_standard} "${CMAKE_CXX_STANDARD}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${cxx_standard} "gnu${CMAKE_CXX_STANDARD}" PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(detect_gnu_libstdcxx)
|
||||
# _conan_is_gnu_libstdcxx true if GNU libstdc++
|
||||
check_cxx_source_compiles("
|
||||
#include <cstddef>
|
||||
#if !defined(__GLIBCXX__) && !defined(__GLIBCPP__)
|
||||
static_assert(false);
|
||||
#endif
|
||||
int main(){}" _conan_is_gnu_libstdcxx)
|
||||
|
||||
# _conan_gnu_libstdcxx_is_cxx11_abi true if C++11 ABI
|
||||
check_cxx_source_compiles("
|
||||
#include <string>
|
||||
static_assert(sizeof(std::string) != sizeof(void*), \"using libstdc++\");
|
||||
int main () {}" _conan_gnu_libstdcxx_is_cxx11_abi)
|
||||
|
||||
set(_conan_gnu_libstdcxx_suffix "")
|
||||
if(_conan_gnu_libstdcxx_is_cxx11_abi)
|
||||
set(_conan_gnu_libstdcxx_suffix "11")
|
||||
endif()
|
||||
unset (_conan_gnu_libstdcxx_is_cxx11_abi)
|
||||
endmacro()
|
||||
|
||||
|
||||
macro(detect_libcxx)
|
||||
# _conan_is_libcxx true if LLVM libc++
|
||||
check_cxx_source_compiles("
|
||||
#include <cstddef>
|
||||
#if !defined(_LIBCPP_VERSION)
|
||||
static_assert(false);
|
||||
#endif
|
||||
int main(){}" _conan_is_libcxx)
|
||||
endmacro()
|
||||
|
||||
|
||||
function(detect_lib_cxx lib_cxx)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
message(STATUS "CMake-Conan: android_stl=${CMAKE_ANDROID_STL_TYPE}")
|
||||
set(${lib_cxx} ${CMAKE_ANDROID_STL_TYPE} PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
detect_gnu_libstdcxx()
|
||||
set(${lib_cxx} "libstdc++${_conan_gnu_libstdcxx_suffix}" PARENT_SCOPE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
|
||||
set(${lib_cxx} "libc++" PARENT_SCOPE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
# Check for libc++
|
||||
detect_libcxx()
|
||||
if(_conan_is_libcxx)
|
||||
set(${lib_cxx} "libc++" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Check for libstdc++
|
||||
detect_gnu_libstdcxx()
|
||||
if(_conan_is_gnu_libstdcxx)
|
||||
set(${lib_cxx} "libstdc++${_conan_gnu_libstdcxx_suffix}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# TODO: it would be an error if we reach this point
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
# Do nothing - compiler.runtime and compiler.runtime_type
|
||||
# should be handled separately: https://github.com/conan-io/cmake-conan/pull/516
|
||||
return()
|
||||
else()
|
||||
# TODO: unable to determine, ask user to provide a full profile file instead
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(detect_compiler compiler compiler_version compiler_runtime compiler_runtime_type)
|
||||
if(DEFINED CMAKE_CXX_COMPILER_ID)
|
||||
set(_compiler ${CMAKE_CXX_COMPILER_ID})
|
||||
set(_compiler_version ${CMAKE_CXX_COMPILER_VERSION})
|
||||
else()
|
||||
if(NOT DEFINED CMAKE_C_COMPILER_ID)
|
||||
message(FATAL_ERROR "C or C++ compiler not defined")
|
||||
endif()
|
||||
set(_compiler ${CMAKE_C_COMPILER_ID})
|
||||
set(_compiler_version ${CMAKE_C_COMPILER_VERSION})
|
||||
endif()
|
||||
|
||||
message(STATUS "CMake-Conan: CMake compiler=${_compiler}")
|
||||
message(STATUS "CMake-Conan: CMake compiler version=${_compiler_version}")
|
||||
|
||||
if(_compiler MATCHES MSVC)
|
||||
set(_compiler "msvc")
|
||||
string(SUBSTRING ${MSVC_VERSION} 0 3 _compiler_version)
|
||||
# Configure compiler.runtime and compiler.runtime_type settings for MSVC
|
||||
if(CMAKE_MSVC_RUNTIME_LIBRARY)
|
||||
set(_msvc_runtime_library ${CMAKE_MSVC_RUNTIME_LIBRARY})
|
||||
else()
|
||||
set(_msvc_runtime_library MultiThreaded$<$<CONFIG:Debug>:Debug>DLL) # default value documented by CMake
|
||||
endif()
|
||||
|
||||
set(_KNOWN_MSVC_RUNTIME_VALUES "")
|
||||
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded MultiThreadedDLL)
|
||||
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreadedDebug MultiThreadedDebugDLL)
|
||||
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded$<$<CONFIG:Debug>:Debug> MultiThreaded$<$<CONFIG:Debug>:Debug>DLL)
|
||||
|
||||
# only accept the 6 possible values, otherwise we don't don't know to map this
|
||||
if(NOT _msvc_runtime_library IN_LIST _KNOWN_MSVC_RUNTIME_VALUES)
|
||||
message(FATAL_ERROR "CMake-Conan: unable to map MSVC runtime: ${_msvc_runtime_library} to Conan settings")
|
||||
endif()
|
||||
|
||||
# Runtime is "dynamic" in all cases if it ends in DLL
|
||||
if(_msvc_runtime_library MATCHES ".*DLL$")
|
||||
set(_compiler_runtime "dynamic")
|
||||
else()
|
||||
set(_compiler_runtime "static")
|
||||
endif()
|
||||
message(STATUS "CMake-Conan: CMake compiler.runtime=${_compiler_runtime}")
|
||||
|
||||
# Only define compiler.runtime_type when explicitly requested
|
||||
# If a generator expression is used, let Conan handle it conditional on build_type
|
||||
if(NOT _msvc_runtime_library MATCHES "<CONFIG:Debug>:Debug>")
|
||||
if(_msvc_runtime_library MATCHES "Debug")
|
||||
set(_compiler_runtime_type "Debug")
|
||||
else()
|
||||
set(_compiler_runtime_type "Release")
|
||||
endif()
|
||||
message(STATUS "CMake-Conan: CMake compiler.runtime_type=${_compiler_runtime_type}")
|
||||
endif()
|
||||
|
||||
unset(_KNOWN_MSVC_RUNTIME_VALUES)
|
||||
|
||||
elseif(_compiler MATCHES AppleClang)
|
||||
set(_compiler "apple-clang")
|
||||
string(REPLACE "." ";" VERSION_LIST ${_compiler_version})
|
||||
list(GET VERSION_LIST 0 _compiler_version)
|
||||
elseif(_compiler MATCHES Clang)
|
||||
set(_compiler "clang")
|
||||
string(REPLACE "." ";" VERSION_LIST ${_compiler_version})
|
||||
list(GET VERSION_LIST 0 _compiler_version)
|
||||
elseif(_compiler MATCHES GNU)
|
||||
set(_compiler "gcc")
|
||||
string(REPLACE "." ";" VERSION_LIST ${_compiler_version})
|
||||
list(GET VERSION_LIST 0 _compiler_version)
|
||||
endif()
|
||||
|
||||
message(STATUS "CMake-Conan: [settings] compiler=${_compiler}")
|
||||
message(STATUS "CMake-Conan: [settings] compiler.version=${_compiler_version}")
|
||||
if (_compiler_runtime)
|
||||
message(STATUS "CMake-Conan: [settings] compiler.runtime=${_compiler_runtime}")
|
||||
endif()
|
||||
if (_compiler_runtime_type)
|
||||
message(STATUS "CMake-Conan: [settings] compiler.runtime_type=${_compiler_runtime_type}")
|
||||
endif()
|
||||
|
||||
set(${compiler} ${_compiler} PARENT_SCOPE)
|
||||
set(${compiler_version} ${_compiler_version} PARENT_SCOPE)
|
||||
set(${compiler_runtime} ${_compiler_runtime} PARENT_SCOPE)
|
||||
set(${compiler_runtime_type} ${_compiler_runtime_type} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(detect_build_type build_type)
|
||||
get_property(multiconfig_generator GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(NOT multiconfig_generator)
|
||||
# Only set when we know we are in a single-configuration generator
|
||||
# Note: we may want to fail early if `CMAKE_BUILD_TYPE` is not defined
|
||||
set(${build_type} ${CMAKE_BUILD_TYPE} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(set_conan_compiler_if_appleclang lang command output_variable)
|
||||
if(CMAKE_${lang}_COMPILER_ID STREQUAL "AppleClang")
|
||||
execute_process(COMMAND xcrun --find ${command}
|
||||
OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
cmake_path(GET _xcrun_out PARENT_PATH _xcrun_toolchain_path)
|
||||
cmake_path(GET CMAKE_${lang}_COMPILER PARENT_PATH _compiler_parent_path)
|
||||
if ("${_xcrun_toolchain_path}" STREQUAL "${_compiler_parent_path}")
|
||||
set(${output_variable} "")
|
||||
endif()
|
||||
unset(_xcrun_out)
|
||||
unset(_xcrun_toolchain_path)
|
||||
unset(_compiler_parent_path)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
macro(append_compiler_executables_configuration)
|
||||
set(_conan_c_compiler "")
|
||||
set(_conan_cpp_compiler "")
|
||||
set(_conan_rc_compiler "")
|
||||
set(_conan_compilers_list "")
|
||||
if(CMAKE_C_COMPILER)
|
||||
set(_conan_c_compiler "\"c\":\"${CMAKE_C_COMPILER}\"")
|
||||
set_conan_compiler_if_appleclang(C cc _conan_c_compiler)
|
||||
list(APPEND _conan_compilers_list ${_conan_c_compiler})
|
||||
else()
|
||||
message(WARNING "CMake-Conan: The C compiler is not defined. "
|
||||
"Please define CMAKE_C_COMPILER or enable the C language.")
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER)
|
||||
set(_conan_cpp_compiler "\"cpp\":\"${CMAKE_CXX_COMPILER}\"")
|
||||
set_conan_compiler_if_appleclang(CXX c++ _conan_cpp_compiler)
|
||||
list(APPEND _conan_compilers_list ${_conan_cpp_compiler})
|
||||
else()
|
||||
message(WARNING "CMake-Conan: The C++ compiler is not defined. "
|
||||
"Please define CMAKE_CXX_COMPILER or enable the C++ language.")
|
||||
endif()
|
||||
if(CMAKE_RC_COMPILER)
|
||||
set(_conan_rc_compiler "\"rc\":\"${CMAKE_RC_COMPILER}\"")
|
||||
list(APPEND _conan_compilers_list ${_conan_rc_compiler})
|
||||
# Not necessary to warn if RC not defined
|
||||
endif()
|
||||
if(NOT "x${_conan_compilers_list}" STREQUAL "x")
|
||||
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
string(REPLACE ";" "," _conan_compilers_list "${_conan_compilers_list}")
|
||||
string(APPEND profile "tools.build:compiler_executables={${_conan_compilers_list}}\n")
|
||||
endif()
|
||||
endif()
|
||||
unset(_conan_c_compiler)
|
||||
unset(_conan_cpp_compiler)
|
||||
unset(_conan_rc_compiler)
|
||||
unset(_conan_compilers_list)
|
||||
endmacro()
|
||||
|
||||
|
||||
function(detect_host_profile output_file)
|
||||
detect_os(os os_api_level os_sdk os_subsystem os_version)
|
||||
detect_arch(arch)
|
||||
detect_compiler(compiler compiler_version compiler_runtime compiler_runtime_type)
|
||||
detect_cxx_standard(${compiler} compiler_cppstd)
|
||||
detect_lib_cxx(compiler_libcxx)
|
||||
detect_build_type(build_type)
|
||||
|
||||
set(profile "")
|
||||
string(APPEND profile "[settings]\n")
|
||||
if(arch)
|
||||
string(APPEND profile arch=${arch} "\n")
|
||||
endif()
|
||||
if(os)
|
||||
string(APPEND profile os=${os} "\n")
|
||||
endif()
|
||||
if(os_api_level)
|
||||
string(APPEND profile os.api_level=${os_api_level} "\n")
|
||||
endif()
|
||||
if(os_version)
|
||||
string(APPEND profile os.version=${os_version} "\n")
|
||||
endif()
|
||||
if(os_sdk)
|
||||
string(APPEND profile os.sdk=${os_sdk} "\n")
|
||||
endif()
|
||||
if(os_subsystem)
|
||||
string(APPEND profile os.subsystem=${os_subsystem} "\n")
|
||||
endif()
|
||||
if(compiler)
|
||||
string(APPEND profile compiler=${compiler} "\n")
|
||||
endif()
|
||||
if(compiler_version)
|
||||
string(APPEND profile compiler.version=${compiler_version} "\n")
|
||||
endif()
|
||||
if(compiler_runtime)
|
||||
string(APPEND profile compiler.runtime=${compiler_runtime} "\n")
|
||||
endif()
|
||||
if(compiler_runtime_type)
|
||||
string(APPEND profile compiler.runtime_type=${compiler_runtime_type} "\n")
|
||||
endif()
|
||||
if(compiler_cppstd)
|
||||
string(APPEND profile compiler.cppstd=${compiler_cppstd} "\n")
|
||||
endif()
|
||||
if(compiler_libcxx)
|
||||
string(APPEND profile compiler.libcxx=${compiler_libcxx} "\n")
|
||||
endif()
|
||||
if(build_type)
|
||||
string(APPEND profile "build_type=${build_type}\n")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED output_file)
|
||||
set(file_name "${CMAKE_BINARY_DIR}/profile")
|
||||
else()
|
||||
set(file_name ${output_file})
|
||||
endif()
|
||||
|
||||
string(APPEND profile "[conf]\n")
|
||||
string(APPEND profile "tools.cmake.cmaketoolchain:generator=${CMAKE_GENERATOR}\n")
|
||||
|
||||
# propagate compilers via profile
|
||||
append_compiler_executables_configuration()
|
||||
|
||||
if(os STREQUAL "Android")
|
||||
string(APPEND profile "tools.android:ndk_path=${CMAKE_ANDROID_NDK}\n")
|
||||
endif()
|
||||
|
||||
message(STATUS "CMake-Conan: Creating profile ${file_name}")
|
||||
file(WRITE ${file_name} ${profile})
|
||||
message(STATUS "CMake-Conan: Profile: \n${profile}")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(conan_profile_detect_default)
|
||||
message(STATUS "CMake-Conan: Checking if a default profile exists")
|
||||
execute_process(COMMAND ${CONAN_COMMAND} profile path default
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE conan_stdout
|
||||
ERROR_VARIABLE conan_stderr
|
||||
ECHO_ERROR_VARIABLE # show the text output regardless
|
||||
ECHO_OUTPUT_VARIABLE
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
if(NOT ${return_code} EQUAL "0")
|
||||
message(STATUS "CMake-Conan: The default profile doesn't exist, detecting it.")
|
||||
execute_process(COMMAND ${CONAN_COMMAND} profile detect
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE conan_stdout
|
||||
ERROR_VARIABLE conan_stderr
|
||||
ECHO_ERROR_VARIABLE # show the text output regardless
|
||||
ECHO_OUTPUT_VARIABLE
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(conan_install)
|
||||
set(conan_output_folder ${CMAKE_BINARY_DIR}/conan)
|
||||
# Invoke "conan install" with the provided arguments
|
||||
set(conan_args -of=${conan_output_folder})
|
||||
message(STATUS "CMake-Conan: conan install ${CMAKE_SOURCE_DIR} ${conan_args} ${ARGN}")
|
||||
|
||||
|
||||
# In case there was not a valid cmake executable in the PATH, we inject the
|
||||
# same we used to invoke the provider to the PATH
|
||||
if(DEFINED PATH_TO_CMAKE_BIN)
|
||||
set(old_path $ENV{PATH})
|
||||
set(ENV{PATH} "$ENV{PATH}:${PATH_TO_CMAKE_BIN}")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${CONAN_COMMAND} install ${CMAKE_SOURCE_DIR} ${conan_args} ${ARGN} --format=json
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE conan_stdout
|
||||
ERROR_VARIABLE conan_stderr
|
||||
ECHO_ERROR_VARIABLE # show the text output regardless
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
if(DEFINED PATH_TO_CMAKE_BIN)
|
||||
set(ENV{PATH} "${old_path}")
|
||||
endif()
|
||||
|
||||
if(NOT "${return_code}" STREQUAL "0")
|
||||
message(FATAL_ERROR "Conan install failed='${return_code}'")
|
||||
endif()
|
||||
|
||||
# the files are generated in a folder that depends on the layout used, if
|
||||
# one is specified, but we don't know a priori where this is.
|
||||
# TODO: this can be made more robust if Conan can provide this in the json output
|
||||
string(JSON conan_generators_folder GET "${conan_stdout}" graph nodes 0 generators_folder)
|
||||
cmake_path(CONVERT ${conan_generators_folder} TO_CMAKE_PATH_LIST conan_generators_folder)
|
||||
|
||||
message(STATUS "CMake-Conan: CONAN_GENERATORS_FOLDER=${conan_generators_folder}")
|
||||
set_property(GLOBAL PROPERTY CONAN_GENERATORS_FOLDER "${conan_generators_folder}")
|
||||
# reconfigure on conanfile changes
|
||||
string(JSON conanfile GET "${conan_stdout}" graph nodes 0 label)
|
||||
message(STATUS "CMake-Conan: CONANFILE=${CMAKE_SOURCE_DIR}/${conanfile}")
|
||||
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/${conanfile}")
|
||||
# success
|
||||
set_property(GLOBAL PROPERTY CONAN_INSTALL_SUCCESS TRUE)
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
function(conan_get_version conan_command conan_current_version)
|
||||
execute_process(
|
||||
COMMAND ${conan_command} --version
|
||||
OUTPUT_VARIABLE conan_output
|
||||
RESULT_VARIABLE conan_result
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(conan_result)
|
||||
message(FATAL_ERROR "CMake-Conan: Error when trying to run Conan")
|
||||
endif()
|
||||
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" conan_version ${conan_output})
|
||||
set(${conan_current_version} ${conan_version} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(conan_version_check)
|
||||
set(options )
|
||||
set(one_value_args MINIMUM CURRENT)
|
||||
set(multi_value_args )
|
||||
cmake_parse_arguments(conan_version_check
|
||||
"${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
|
||||
|
||||
if(NOT conan_version_check_MINIMUM)
|
||||
message(FATAL_ERROR "CMake-Conan: Required parameter MINIMUM not set!")
|
||||
endif()
|
||||
if(NOT conan_version_check_CURRENT)
|
||||
message(FATAL_ERROR "CMake-Conan: Required parameter CURRENT not set!")
|
||||
endif()
|
||||
|
||||
if(conan_version_check_CURRENT VERSION_LESS conan_version_check_MINIMUM)
|
||||
message(FATAL_ERROR "CMake-Conan: Conan version must be ${conan_version_check_MINIMUM} or later")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(construct_profile_argument argument_variable profile_list)
|
||||
set(${argument_variable} "")
|
||||
if("${profile_list}" STREQUAL "CONAN_HOST_PROFILE")
|
||||
set(_arg_flag "--profile:host=")
|
||||
elseif("${profile_list}" STREQUAL "CONAN_BUILD_PROFILE")
|
||||
set(_arg_flag "--profile:build=")
|
||||
endif()
|
||||
|
||||
set(_profile_list "${${profile_list}}")
|
||||
list(TRANSFORM _profile_list REPLACE "auto-cmake" "${CMAKE_BINARY_DIR}/conan_host_profile")
|
||||
list(TRANSFORM _profile_list PREPEND ${_arg_flag})
|
||||
set(${argument_variable} ${_profile_list})
|
||||
|
||||
unset(_arg_flag)
|
||||
unset(_profile_list)
|
||||
endmacro()
|
||||
|
||||
|
||||
macro(conan_provide_dependency method package_name)
|
||||
set_property(GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED TRUE)
|
||||
get_property(_conan_install_success GLOBAL PROPERTY CONAN_INSTALL_SUCCESS)
|
||||
if(NOT _conan_install_success)
|
||||
find_program(CONAN_COMMAND "conan" REQUIRED)
|
||||
conan_get_version(${CONAN_COMMAND} CONAN_CURRENT_VERSION)
|
||||
conan_version_check(MINIMUM ${CONAN_MINIMUM_VERSION} CURRENT ${CONAN_CURRENT_VERSION})
|
||||
message(STATUS "CMake-Conan: first find_package() found. Installing dependencies with Conan")
|
||||
if("default" IN_LIST CONAN_HOST_PROFILE OR "default" IN_LIST CONAN_BUILD_PROFILE)
|
||||
conan_profile_detect_default()
|
||||
endif()
|
||||
if("auto-cmake" IN_LIST CONAN_HOST_PROFILE)
|
||||
detect_host_profile(${CMAKE_BINARY_DIR}/conan_host_profile)
|
||||
endif()
|
||||
construct_profile_argument(_host_profile_flags CONAN_HOST_PROFILE)
|
||||
construct_profile_argument(_build_profile_flags CONAN_BUILD_PROFILE)
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/conanfile.py")
|
||||
file(READ "${CMAKE_SOURCE_DIR}/conanfile.py" outfile)
|
||||
if(NOT "${outfile}" MATCHES ".*CMakeConfigDeps.*")
|
||||
message(WARNING "Cmake-conan: CMakeConfigDeps generator was not defined in the conanfile")
|
||||
endif()
|
||||
elseif (EXISTS "${CMAKE_SOURCE_DIR}/conanfile.txt")
|
||||
file(READ "${CMAKE_SOURCE_DIR}/conanfile.txt" outfile)
|
||||
if(NOT "${outfile}" MATCHES ".*CMakeConfigDeps.*")
|
||||
message(WARNING "Cmake-conan: CMakeConfigDeps generator was not defined in the conanfile")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_property(_multiconfig_generator GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
|
||||
if(DEFINED CONAN_INSTALL_BUILD_CONFIGURATIONS)
|
||||
# Configurations are specified by the project or user
|
||||
set(_build_configs "${CONAN_INSTALL_BUILD_CONFIGURATIONS}")
|
||||
list(LENGTH _build_configs _build_configs_length)
|
||||
if(NOT _multiconfig_generator AND _build_configs_length GREATER 1)
|
||||
message(FATAL_ERROR "cmake-conan: when using a single-config CMake generator, "
|
||||
"please only specify a single configuration in CONAN_INSTALL_BUILD_CONFIGURATIONS")
|
||||
endif()
|
||||
unset(_build_configs_length)
|
||||
else()
|
||||
# No configuration overrides, provide sensible defaults
|
||||
if(_multiconfig_generator)
|
||||
set(_build_configs Release Debug)
|
||||
else()
|
||||
set(_build_configs ${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
list(JOIN _build_configs ", " _build_configs_msg)
|
||||
message(STATUS "CMake-Conan: Installing configuration(s): ${_build_configs_msg}")
|
||||
foreach(_build_config IN LISTS _build_configs)
|
||||
set(_self_build_config "")
|
||||
if(NOT _multiconfig_generator AND NOT _build_config STREQUAL "${CMAKE_BUILD_TYPE}")
|
||||
set(_self_build_config -s &:build_type=${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=${_build_config} ${_self_build_config} ${CONAN_INSTALL_ARGS})
|
||||
endforeach()
|
||||
|
||||
get_property(_conan_generators_folder GLOBAL PROPERTY CONAN_GENERATORS_FOLDER)
|
||||
if(EXISTS "${_conan_generators_folder}/conan_cmakedeps_paths.cmake")
|
||||
message(STATUS "CMake-Conan: Loading conan_cmakedeps_paths.cmake file")
|
||||
include(${_conan_generators_folder}/conan_cmakedeps_paths.cmake)
|
||||
endif()
|
||||
|
||||
unset(_self_build_config)
|
||||
unset(_multiconfig_generator)
|
||||
unset(_build_configs)
|
||||
unset(_build_configs_msg)
|
||||
unset(_host_profile_flags)
|
||||
unset(_build_profile_flags)
|
||||
unset(_conan_install_success)
|
||||
else()
|
||||
message(STATUS "CMake-Conan: find_package(${ARGV1}) found, 'conan install' already ran")
|
||||
unset(_conan_install_success)
|
||||
endif()
|
||||
|
||||
get_property(_conan_generators_folder GLOBAL PROPERTY CONAN_GENERATORS_FOLDER)
|
||||
|
||||
# Ensure that we consider Conan-provided packages ahead of any other,
|
||||
# irrespective of other settings that modify the search order or search paths
|
||||
# This follows the guidelines from the find_package documentation
|
||||
# (https://cmake.org/cmake/help/latest/command/find_package.html):
|
||||
# find_package (<PackageName> PATHS paths... NO_DEFAULT_PATH)
|
||||
# find_package (<PackageName>)
|
||||
|
||||
# Filter out `REQUIRED` from the argument list, as the first call may fail
|
||||
set(_find_args_${package_name} "${ARGN}")
|
||||
list(REMOVE_ITEM _find_args_${package_name} "REQUIRED")
|
||||
if(NOT "MODULE" IN_LIST _find_args_${package_name})
|
||||
find_package(${package_name} ${_find_args_${package_name}} BYPASS_PROVIDER PATHS "${_conan_generators_folder}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
|
||||
unset(_find_args_${package_name})
|
||||
endif()
|
||||
|
||||
# Invoke find_package a second time - if the first call succeeded,
|
||||
# this will simply reuse the result. If not, fall back to CMake default search
|
||||
# behaviour, also allowing modules to be searched.
|
||||
if(NOT ${package_name}_FOUND)
|
||||
list(FIND CMAKE_MODULE_PATH "${_conan_generators_folder}" _index)
|
||||
if(_index EQUAL -1)
|
||||
list(PREPEND CMAKE_MODULE_PATH "${_conan_generators_folder}")
|
||||
endif()
|
||||
unset(_index)
|
||||
find_package(${package_name} ${ARGN} BYPASS_PROVIDER)
|
||||
list(REMOVE_ITEM CMAKE_MODULE_PATH "${_conan_generators_folder}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
cmake_language(
|
||||
SET_DEPENDENCY_PROVIDER conan_provide_dependency
|
||||
SUPPORTED_METHODS FIND_PACKAGE
|
||||
)
|
||||
|
||||
|
||||
macro(conan_provide_dependency_check)
|
||||
set(_conan_provide_dependency_invoked FALSE)
|
||||
get_property(_conan_provide_dependency_invoked GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED)
|
||||
if(NOT _conan_provide_dependency_invoked)
|
||||
message(WARNING "Conan is correctly configured as dependency provider, "
|
||||
"but Conan has not been invoked. Please add at least one "
|
||||
"call to `find_package()`.")
|
||||
if(DEFINED CONAN_COMMAND)
|
||||
# supress warning in case `CONAN_COMMAND` was specified but unused.
|
||||
set(_conan_command ${CONAN_COMMAND})
|
||||
unset(_conan_command)
|
||||
endif()
|
||||
endif()
|
||||
unset(_conan_provide_dependency_invoked)
|
||||
endmacro()
|
||||
|
||||
|
||||
# Add a deferred call at the end of processing the top-level directory
|
||||
# to check if the dependency provider was invoked at all.
|
||||
cmake_language(DEFER DIRECTORY "${CMAKE_SOURCE_DIR}" CALL conan_provide_dependency_check)
|
||||
|
||||
# Configurable variables for Conan profiles
|
||||
set(CONAN_HOST_PROFILE "default;auto-cmake" CACHE STRING "Conan host profile")
|
||||
set(CONAN_BUILD_PROFILE "default" CACHE STRING "Conan build profile")
|
||||
set(CONAN_INSTALL_ARGS "--build=missing" CACHE STRING "Command line arguments for conan install")
|
||||
|
||||
find_program(_cmake_program NAMES cmake NO_PACKAGE_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH NO_CMAKE_FIND_ROOT_PATH)
|
||||
if(NOT _cmake_program)
|
||||
get_filename_component(PATH_TO_CMAKE_BIN "${CMAKE_COMMAND}" DIRECTORY)
|
||||
set(PATH_TO_CMAKE_BIN "${PATH_TO_CMAKE_BIN}" CACHE INTERNAL "Path where the CMake executable is")
|
||||
endif()
|
||||
|
||||
cmake_policy(POP)
|
||||
@@ -1,40 +0,0 @@
|
||||
if(APPLE)
|
||||
get_property(generator_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if (generator_is_multi_config)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||
set(CONAN_INSTALL_BUILD_CONFIGURATIONS RelWithDebInfo)
|
||||
else()
|
||||
set(CONAN_INSTALL_BUILD_CONFIGURATIONS Release Debug MinSizeRel RelWithDebInfo)
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "14.0" CACHE STRING "" FORCE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "" FORCE)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||
set(CONAN_INSTALL_ARGS "--build=missing;-o;openssl/3.6.1:no_apps=True" CACHE STRING "" FORCE)
|
||||
set(AMNEZIA_IOS_ENABLE_APPLETV_TARGET ON CACHE BOOL "" FORCE)
|
||||
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" CACHE STRING "" FORCE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "17.0" CACHE STRING "" FORCE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "" FORCE)
|
||||
elseif(MACOS_NE)
|
||||
set(CONAN_INSTALL_ARGS "--build=missing;-o=&:macos_ne=True" CACHE STRING "" FORCE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "" FORCE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
else()
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "" FORCE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
set(CONAN_INSTALL_ARGS
|
||||
"--build=missing"
|
||||
"-c=tools.android:cmake_legacy_toolchain=false"
|
||||
"-c=tools.build:sharedlinkflags=['-Wl,-z,max-page-size=16384']"
|
||||
"-c=tools.build:exelinkflags=['-Wl,-z,max-page-size=16384']"
|
||||
CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if (WIN32 OR APPLE)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
endif()
|
||||
@@ -1,9 +0,0 @@
|
||||
find_program(CONAN_COMMAND "conan" REQUIRED)
|
||||
|
||||
file(GLOB_RECURSE LOCAL_RECIPES "${CMAKE_SOURCE_DIR}/recipes/*/conanfile.py")
|
||||
foreach(RECIPE ${LOCAL_RECIPES})
|
||||
get_filename_component(RECIPE_DIR ${RECIPE} DIRECTORY)
|
||||
execute_process(
|
||||
COMMAND ${CONAN_COMMAND} export ${RECIPE_DIR}
|
||||
)
|
||||
endforeach()
|
||||
@@ -1,49 +0,0 @@
|
||||
if(NOT DEFINED SIGNTOOL_SUBJECT_NAME)
|
||||
set(SIGNTOOL_SUBJECT_NAME "$ENV{SIGNTOOL_SUBJECT_NAME}")
|
||||
endif()
|
||||
if(NOT DEFINED CODESIGN_SIGNATURE)
|
||||
set(CODESIGN_SIGNATURE "$ENV{CODESIGN_SIGNATURE}")
|
||||
endif()
|
||||
if(NOT DEFINED CODESIGN_KEYCHAIN)
|
||||
set(CODESIGN_KEYCHAIN "$ENV{CODESIGN_KEYCHAIN}")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
file(GLOB_RECURSE BINARIES
|
||||
"${CPACK_TEMPORARY_DIRECTORY}/*.dll"
|
||||
"${CPACK_TEMPORARY_DIRECTORY}/*.exe"
|
||||
)
|
||||
|
||||
if(BINARIES AND SIGNTOOL_SUBJECT_NAME)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/util/signtool.cmake)
|
||||
signtool_sign_files("${BINARIES}" "${SIGNTOOL_SUBJECT_NAME}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
file(GLOB_RECURSE all_subdirs LIST_DIRECTORIES true "${CPACK_TEMPORARY_DIRECTORY}/*")
|
||||
|
||||
set(frameworks ${all_subdirs})
|
||||
list(FILTER frameworks INCLUDE REGEX [[.*\.framework$]])
|
||||
|
||||
file(GLOB_RECURSE dylibs "${CPACK_TEMPORARY_DIRECTORY}/*.dylib")
|
||||
|
||||
set(bundle ${all_subdirs})
|
||||
list(FILTER bundle INCLUDE REGEX [[.*\.app$]])
|
||||
list(GET bundle 0 bundle)
|
||||
|
||||
file(GLOB_RECURSE execs "${bundle}/Contents/MacOS/*")
|
||||
set(client_exec ${execs})
|
||||
list(FILTER client_exec INCLUDE REGEX [[AmneziaVPN$]])
|
||||
set(service_exec ${execs})
|
||||
list(FILTER service_exec INCLUDE REGEX [[AmneziaVPN-service$]])
|
||||
set(other_execs ${execs})
|
||||
list(FILTER other_execs EXCLUDE REGEX [[AmneziaVPN$|AmneziaVPN-service$]])
|
||||
|
||||
list(APPEND files "${frameworks}" "${dylibs}" "${other_execs}" "${service_exec}" "${client_exec}" "${bundle}")
|
||||
|
||||
if (files AND CODESIGN_SIGNATURE)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/util/codesign.cmake)
|
||||
codesign_sign_files("${files}" "${CODESIGN_SIGNATURE}" "${CODESIGN_KEYCHAIN}")
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,30 +0,0 @@
|
||||
if(NOT DEFINED SIGNTOOL_SUBJECT_NAME)
|
||||
set(SIGNTOOL_SUBJECT_NAME "$ENV{SIGNTOOL_SUBJECT_NAME}")
|
||||
endif()
|
||||
if(NOT DEFINED NOTARYTOOL_EMAIL)
|
||||
set(NOTARYTOOL_EMAIL "$ENV{NOTARYTOOL_EMAIL}")
|
||||
endif()
|
||||
if(NOT DEFINED NOTARYTOOL_TEAM_ID)
|
||||
set(NOTARYTOOL_TEAM_ID "$ENV{NOTARYTOOL_TEAM_ID}")
|
||||
endif()
|
||||
if(NOT DEFINED NOTARYTOOL_PASSWORD)
|
||||
set(NOTARYTOOL_PASSWORD "$ENV{NOTARYTOOL_PASSWORD}")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
if (SIGNTOOL_SUBJECT_NAME)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/util/signtool.cmake)
|
||||
foreach(PACKAGE_FILE IN LISTS CPACK_PACKAGE_FILES)
|
||||
signtool_sign_files("${PACKAGE_FILE}" "${SIGNTOOL_SUBJECT_NAME}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
if(NOTARYTOOL_EMAIL AND NOTARYTOOL_TEAM_ID AND NOTARYTOOL_PASSWORD)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/util/notarytool.cmake)
|
||||
foreach(file IN LISTS CPACK_PACKAGE_FILES)
|
||||
notarize_and_staple_file("${file}" "${NOTARYTOOL_EMAIL}" "${NOTARYTOOL_TEAM_ID}" "${NOTARYTOOL_PASSWORD}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,36 +0,0 @@
|
||||
find_program(CODESIGN_COMMAND codesign REQUIRED)
|
||||
|
||||
function(codesign_sign_files files signature keychain)
|
||||
if (NOT signature)
|
||||
message(FATAL_ERROR "codesign failed: signature is required")
|
||||
endif()
|
||||
|
||||
set(args
|
||||
--force
|
||||
--verbose
|
||||
--timestamp
|
||||
--options runtime
|
||||
--sign "${signature}"
|
||||
)
|
||||
|
||||
if(keychain)
|
||||
list(APPEND args --keychain "${keychain}")
|
||||
endif()
|
||||
|
||||
foreach(file IN LISTS files)
|
||||
set(cmd ${CODESIGN_COMMAND} ${args} "${file}")
|
||||
|
||||
list(JOIN cmd " " cmd_str)
|
||||
message(STATUS "${cmd_str}")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${cmd}
|
||||
RESULT_VARIABLE result
|
||||
ERROR_VARIABLE error
|
||||
)
|
||||
if(NOT result EQUAL 0)
|
||||
string(REPLACE "\n" "\n " error " ${error}")
|
||||
message(FATAL_ERROR "codesign failed:\n${error}")
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user