mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-10-30 16:47:39 +09:00
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35e9833fa9 | ||
|
|
3d666c2014 | ||
|
|
a82e0ec5e4 | ||
|
|
12d9fcd712 | ||
|
|
24d13bacea | ||
|
|
4546815941 | ||
|
|
22fda3acc7 | ||
|
|
6b922c9d29 | ||
|
|
5ac34fd12f | ||
|
|
ed50553e17 | ||
|
|
25fcf68b4b | ||
|
|
830872cdbe | ||
|
|
5d7ef63c05 |
No files matched your search
+101
-163
@@ -5,8 +5,38 @@ on:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
# Self-hosted server tests (SelfHostedServerSetup, MultipleExports) install and
|
||||
# remove docker containers on a single shared VPS: two workflow runs executing
|
||||
# simultaneously corrupt each other's state (error 202, "No such container").
|
||||
# Queue runs instead of running them in parallel; do not cancel the active one.
|
||||
concurrency:
|
||||
group: vps-tests
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
QT_MIRROR: https://mirrors.ocf.berkeley.edu/qt/ # https://download.qt.io/static/mirrorlist/
|
||||
QTEST_FUNCTION_TIMEOUT: 7200000
|
||||
SELF_HOSTED_ADMIN_EXPORT_ROUND_TRIP_VPN_KEY: ${{ secrets.SELF_HOSTED_ADMIN_EXPORT_ROUND_TRIP_VPN_KEY }}
|
||||
THIRD_PARTY_AWG_VPN_KEY: ${{ secrets.THIRD_PARTY_AWG_VPN_KEY }}
|
||||
THIRD_PARTY_WIRE_GUARD_VPN_KEY: ${{ secrets.THIRD_PARTY_WIRE_GUARD_VPN_KEY }}
|
||||
THIRD_PARTY_XRAY_VPN_KEY: ${{ secrets.THIRD_PARTY_XRAY_VPN_KEY }}
|
||||
THIRD_PARTY_OPEN_VPN_KEY: ${{ secrets.THIRD_PARTY_OPEN_VPN_KEY }}
|
||||
THIRD_PARTY_CLOAK_VPN_KEY: ${{ secrets.THIRD_PARTY_CLOAK_VPN_KEY }}
|
||||
THIRD_PARTY_SS_VPN_KEY: ${{ secrets.THIRD_PARTY_SS_VPN_KEY }}
|
||||
THIRD_PARTY_IKEV_VPN_KEY: ${{ secrets.THIRD_PARTY_IKEV_VPN_KEY }}
|
||||
THIRD_PARTY_PREMIUM_VPN_KEY: ${{ secrets.THIRD_PARTY_PREMIUM_VPN_KEY }}
|
||||
THIRD_PARTY_VMESS_NEW_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VMESS_NEW_IMPORT_DATA }}
|
||||
THIRD_PARTY_VMESS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VMESS_IMPORT_DATA }}
|
||||
THIRD_PARTY_TROJAN_IMPORT_DATA: ${{ secrets.THIRD_PARTY_TROJAN_IMPORT_DATA }}
|
||||
THIRD_PARTY_VLESS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VLESS_IMPORT_DATA }}
|
||||
THIRD_PARTY_SHADOWSOCKS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_SHADOWSOCKS_IMPORT_DATA }}
|
||||
THIRD_PARTY_SHADOWSOCKS_SUBSCRIPTION_IMPORT_DATA: ${{ secrets.THIRD_PARTY_SHADOWSOCKS_SUBSCRIPTION_IMPORT_DATA }}
|
||||
SELF_HOSTED_SERVER_HOST_NAME: ${{ secrets.SELF_HOSTED_SERVER_HOST_NAME }}
|
||||
SELF_HOSTED_SERVER_USER_NAME: ${{ secrets.SELF_HOSTED_SERVER_USER_NAME }}
|
||||
SELF_HOSTED_SERVER_PASSWORD: ${{ secrets.SELF_HOSTED_SERVER_PASSWORD }}
|
||||
SELF_HOSTED_SERVER_SSH_PORT: ${{ secrets.SELF_HOSTED_SERVER_SSH_PORT }}
|
||||
DNS_LIST_PATH: ${{ github.workspace }}/tests/data/dns_list.json
|
||||
IP_LIST_PATH: ${{ github.workspace }}/tests/data/ip_list.json
|
||||
|
||||
jobs:
|
||||
Detect-Changes:
|
||||
@@ -118,7 +148,6 @@ jobs:
|
||||
shell: bash
|
||||
env:
|
||||
QT_INSTALL_DIR: ${{ runner.temp }}
|
||||
AMNEZIA_BUILD_TESTS: ON
|
||||
run: deploy/build.sh --generator Ninja --installer all
|
||||
|
||||
- name: 'Upload Linux test build'
|
||||
@@ -250,7 +279,6 @@ jobs:
|
||||
shell: cmd
|
||||
env:
|
||||
QT_INSTALL_DIR: ${{ runner.temp }}
|
||||
AMNEZIA_BUILD_TESTS: ON
|
||||
run: |
|
||||
set WIX_ROOT_PATH="${{ env.USERPROFILE }}\.dotnet\tools"
|
||||
deploy\build.bat --installer all
|
||||
@@ -522,7 +550,7 @@ jobs:
|
||||
xcode-version: '26.3.0'
|
||||
|
||||
- name: 'Install Qt'
|
||||
uses: jurplel/install-qt-action@v4.3.1
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'mac'
|
||||
@@ -554,10 +582,29 @@ jobs:
|
||||
NOTARYTOOL_TEAM_ID: ${{ secrets.MAC_TEAM_ID }}
|
||||
NOTARYTOOL_EMAIL: ${{ secrets.APPLE_DEV_EMAIL }}
|
||||
NOTARYTOOL_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
|
||||
AMNEZIA_BUILD_TESTS: ON
|
||||
shell: bash
|
||||
run: deploy/build.sh --generator Ninja --installer all
|
||||
|
||||
- name: 'Prepare macOS test runtime'
|
||||
shell: bash
|
||||
run: |
|
||||
FRAMEWORKS_DIR=$(find deploy/build/_CPack_Packages \
|
||||
-type d \
|
||||
-path '*/AmneziaVPN.app/Contents/Frameworks' \
|
||||
-print -quit)
|
||||
|
||||
echo "Frameworks directory: $FRAMEWORKS_DIR"
|
||||
|
||||
mkdir -p deploy/build/client/tests/openssl
|
||||
|
||||
cp "$FRAMEWORKS_DIR/libssl.3.dylib" \
|
||||
deploy/build/client/tests/openssl/
|
||||
|
||||
cp "$FRAMEWORKS_DIR/libcrypto.3.dylib" \
|
||||
deploy/build/client/tests/openssl/
|
||||
|
||||
ls -la deploy/build/client/tests/openssl
|
||||
|
||||
- name: 'Upload macOS test build'
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
@@ -818,7 +865,7 @@ jobs:
|
||||
submodules: 'true'
|
||||
|
||||
- name: 'Install desktop Qt'
|
||||
uses: jurplel/install-qt-action@v4.3.1
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'linux'
|
||||
@@ -830,10 +877,10 @@ jobs:
|
||||
extra: '--base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install android_x86_64 Qt'
|
||||
uses: jurplel/install-qt-action@v4.3.1
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'all_os'
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_x86_64'
|
||||
modules: ${{ env.QT_MODULES }}
|
||||
@@ -842,10 +889,10 @@ jobs:
|
||||
extra: '--base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install android_x86 Qt'
|
||||
uses: jurplel/install-qt-action@v4.3.1
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'all_os'
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_x86'
|
||||
modules: ${{ env.QT_MODULES }}
|
||||
@@ -854,10 +901,10 @@ jobs:
|
||||
extra: '--base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install android_armv7 Qt'
|
||||
uses: jurplel/install-qt-action@v4.3.1
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'all_os'
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_armv7'
|
||||
modules: ${{ env.QT_MODULES }}
|
||||
@@ -866,10 +913,10 @@ jobs:
|
||||
extra: '--base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install android_arm64_v8a Qt'
|
||||
uses: jurplel/install-qt-action@v4.3.1
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'all_os'
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_arm64_v8a'
|
||||
modules: ${{ env.QT_MODULES }}
|
||||
@@ -1061,21 +1108,6 @@ jobs:
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.10.1
|
||||
QTEST_FUNCTION_TIMEOUT: 7200000
|
||||
THIRD_PARTY_AWG_VPN_KEY: ${{ secrets.THIRD_PARTY_AWG_VPN_KEY }}
|
||||
THIRD_PARTY_WIRE_GUARD_VPN_KEY: ${{ secrets.THIRD_PARTY_WIRE_GUARD_VPN_KEY }}
|
||||
THIRD_PARTY_XRAY_VPN_KEY: ${{ secrets.THIRD_PARTY_XRAY_VPN_KEY }}
|
||||
THIRD_PARTY_OPEN_VPN_KEY: ${{ secrets.THIRD_PARTY_OPEN_VPN_KEY }}
|
||||
THIRD_PARTY_CLOAK_VPN_KEY: ${{ secrets.THIRD_PARTY_CLOAK_VPN_KEY }}
|
||||
THIRD_PARTY_SS_VPN_KEY: ${{ secrets.THIRD_PARTY_SS_VPN_KEY }}
|
||||
THIRD_PARTY_IKEV_VPN_KEY: ${{ secrets.THIRD_PARTY_IKEV_VPN_KEY }}
|
||||
THIRD_PARTY_PREMIUM_VPN_KEY: ${{ secrets.THIRD_PARTY_PREMIUM_VPN_KEY }}
|
||||
THIRD_PARTY_VMESS_NEW_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VMESS_NEW_IMPORT_DATA }}
|
||||
THIRD_PARTY_VMESS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VMESS_IMPORT_DATA }}
|
||||
THIRD_PARTY_TROJAN_IMPORT_DATA: ${{ secrets.THIRD_PARTY_TROJAN_IMPORT_DATA }}
|
||||
THIRD_PARTY_VLESS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VLESS_IMPORT_DATA }}
|
||||
THIRD_PARTY_SHADOWSOCKS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_SHADOWSOCKS_IMPORT_DATA }}
|
||||
THIRD_PARTY_SHADOWSOCKS_SUBSCRIPTION_IMPORT_DATA: ${{ secrets.THIRD_PARTY_SHADOWSOCKS_SUBSCRIPTION_IMPORT_DATA }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -1086,16 +1118,12 @@ jobs:
|
||||
|
||||
- name: Decode backup file
|
||||
if: matrix.filter == 'BackupExportImportTest'
|
||||
shell: bash
|
||||
env:
|
||||
BACKUP_FILE_BASE64: ${{ secrets.BACKUP_FILE_BASE64 }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
if [ -z "$BACKUP_FILE_BASE64" ]; then
|
||||
echo "::error::BACKUP_FILE_BASE64 secret is not set"
|
||||
exit 1
|
||||
fi
|
||||
echo "$BACKUP_FILE_BASE64" | base64 --decode > "$RUNNER_TEMP/test.backup"
|
||||
echo "BACKUP_PATH=$RUNNER_TEMP/test.backup" >> "$GITHUB_ENV"
|
||||
$backup = Join-Path $env:RUNNER_TEMP "test.backup"
|
||||
$bytes = [Convert]::FromBase64String("${{ secrets.BACKUP_FILE_BASE64 }}")
|
||||
[IO.File]::WriteAllBytes($backup, $bytes)
|
||||
"BACKUP_PATH=$backup" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
@@ -1127,6 +1155,7 @@ jobs:
|
||||
- name: Restore executable permissions
|
||||
run: |
|
||||
find deploy/build/client/tests \
|
||||
-maxdepth 1 \
|
||||
-type f \
|
||||
-name "test_*" \
|
||||
-exec chmod +x {} \;
|
||||
@@ -1136,86 +1165,11 @@ jobs:
|
||||
run: |
|
||||
QT_ROOT="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/gcc_64"
|
||||
|
||||
export LD_LIBRARY_PATH="$PWD/deploy/build/client/tests:$QT_ROOT/lib:${LD_LIBRARY_PATH:-}"
|
||||
export LD_LIBRARY_PATH="$QT_ROOT/lib:${LD_LIBRARY_PATH:-}"
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
|
||||
ctest --test-dir deploy/build/client/tests --output-on-failure -VV -R "^${{ matrix.filter }}$"
|
||||
|
||||
# ------------------------------------------------------
|
||||
|
||||
test-vps:
|
||||
name: Test self-hosted VPS
|
||||
needs: Build-Linux-Ubuntu
|
||||
|
||||
# These tests install and remove docker containers on a single shared VPS:
|
||||
# two runs at once corrupt each other's state, so only one job may touch it.
|
||||
concurrency:
|
||||
group: vps-tests
|
||||
cancel-in-progress: false
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.10.1
|
||||
QTEST_FUNCTION_TIMEOUT: 7200000
|
||||
SELF_HOSTED_SERVER_HOST_NAME: ${{ secrets.SELF_HOSTED_SERVER_HOST_NAME }}
|
||||
SELF_HOSTED_SERVER_USER_NAME: ${{ secrets.SELF_HOSTED_SERVER_USER_NAME }}
|
||||
SELF_HOSTED_SERVER_PASSWORD: ${{ secrets.SELF_HOSTED_SERVER_PASSWORD }}
|
||||
SELF_HOSTED_SERVER_SSH_PORT: ${{ secrets.SELF_HOSTED_SERVER_SSH_PORT }}
|
||||
SELF_HOSTED_ADMIN_EXPORT_ROUND_TRIP_VPN_KEY: ${{ secrets.SELF_HOSTED_ADMIN_EXPORT_ROUND_TRIP_VPN_KEY }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
fetch-depth: 10
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: linux
|
||||
target: desktop
|
||||
arch: linux_gcc_64
|
||||
modules: qtremoteobjects qt5compat qtshadertools
|
||||
dir: ${{ runner.temp }}
|
||||
set-env: true
|
||||
aqtversion: '==3.3.0'
|
||||
py7zrversion: '==0.22.*'
|
||||
extra: '--base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: Install system packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
libxkbcommon-x11-0 \
|
||||
libsecret-1-dev
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux-build
|
||||
path: deploy/build/client/tests
|
||||
|
||||
- name: Restore executable permissions
|
||||
run: |
|
||||
find deploy/build/client/tests \
|
||||
-type f \
|
||||
-name "test_*" \
|
||||
-exec chmod +x {} \;
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
QT_ROOT="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/gcc_64"
|
||||
|
||||
export LD_LIBRARY_PATH="$PWD/deploy/build/client/tests:$QT_ROOT/lib:${LD_LIBRARY_PATH:-}"
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
|
||||
ctest --test-dir deploy/build/client/tests --output-on-failure -VV \
|
||||
-R "^(SelfHostedServerSetupTest|MultipleExportsTest|AdminSelfHostedExportTest)$"
|
||||
|
||||
# ------------------------------------------------------
|
||||
|
||||
test-windows:
|
||||
@@ -1248,21 +1202,6 @@ jobs:
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.10.1
|
||||
QTEST_FUNCTION_TIMEOUT: 7200000
|
||||
THIRD_PARTY_AWG_VPN_KEY: ${{ secrets.THIRD_PARTY_AWG_VPN_KEY }}
|
||||
THIRD_PARTY_WIRE_GUARD_VPN_KEY: ${{ secrets.THIRD_PARTY_WIRE_GUARD_VPN_KEY }}
|
||||
THIRD_PARTY_XRAY_VPN_KEY: ${{ secrets.THIRD_PARTY_XRAY_VPN_KEY }}
|
||||
THIRD_PARTY_OPEN_VPN_KEY: ${{ secrets.THIRD_PARTY_OPEN_VPN_KEY }}
|
||||
THIRD_PARTY_CLOAK_VPN_KEY: ${{ secrets.THIRD_PARTY_CLOAK_VPN_KEY }}
|
||||
THIRD_PARTY_SS_VPN_KEY: ${{ secrets.THIRD_PARTY_SS_VPN_KEY }}
|
||||
THIRD_PARTY_IKEV_VPN_KEY: ${{ secrets.THIRD_PARTY_IKEV_VPN_KEY }}
|
||||
THIRD_PARTY_PREMIUM_VPN_KEY: ${{ secrets.THIRD_PARTY_PREMIUM_VPN_KEY }}
|
||||
THIRD_PARTY_VMESS_NEW_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VMESS_NEW_IMPORT_DATA }}
|
||||
THIRD_PARTY_VMESS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VMESS_IMPORT_DATA }}
|
||||
THIRD_PARTY_TROJAN_IMPORT_DATA: ${{ secrets.THIRD_PARTY_TROJAN_IMPORT_DATA }}
|
||||
THIRD_PARTY_VLESS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VLESS_IMPORT_DATA }}
|
||||
THIRD_PARTY_SHADOWSOCKS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_SHADOWSOCKS_IMPORT_DATA }}
|
||||
THIRD_PARTY_SHADOWSOCKS_SUBSCRIPTION_IMPORT_DATA: ${{ secrets.THIRD_PARTY_SHADOWSOCKS_SUBSCRIPTION_IMPORT_DATA }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -1274,15 +1213,9 @@ jobs:
|
||||
- name: Decode backup file
|
||||
if: matrix.filter == 'BackupExportImportTest'
|
||||
shell: pwsh
|
||||
env:
|
||||
BACKUP_FILE_BASE64: ${{ secrets.BACKUP_FILE_BASE64 }}
|
||||
run: |
|
||||
if ([string]::IsNullOrWhiteSpace($env:BACKUP_FILE_BASE64)) {
|
||||
Write-Output "::error::BACKUP_FILE_BASE64 secret is not set"
|
||||
exit 1
|
||||
}
|
||||
$backup = Join-Path $env:RUNNER_TEMP "test.backup"
|
||||
$bytes = [Convert]::FromBase64String($env:BACKUP_FILE_BASE64)
|
||||
$bytes = [Convert]::FromBase64String("${{ secrets.BACKUP_FILE_BASE64 }}")
|
||||
[IO.File]::WriteAllBytes($backup, $bytes)
|
||||
"BACKUP_PATH=$backup" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
|
||||
@@ -1352,21 +1285,6 @@ jobs:
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.10.1
|
||||
QTEST_FUNCTION_TIMEOUT: 7200000
|
||||
THIRD_PARTY_AWG_VPN_KEY: ${{ secrets.THIRD_PARTY_AWG_VPN_KEY }}
|
||||
THIRD_PARTY_WIRE_GUARD_VPN_KEY: ${{ secrets.THIRD_PARTY_WIRE_GUARD_VPN_KEY }}
|
||||
THIRD_PARTY_XRAY_VPN_KEY: ${{ secrets.THIRD_PARTY_XRAY_VPN_KEY }}
|
||||
THIRD_PARTY_OPEN_VPN_KEY: ${{ secrets.THIRD_PARTY_OPEN_VPN_KEY }}
|
||||
THIRD_PARTY_CLOAK_VPN_KEY: ${{ secrets.THIRD_PARTY_CLOAK_VPN_KEY }}
|
||||
THIRD_PARTY_SS_VPN_KEY: ${{ secrets.THIRD_PARTY_SS_VPN_KEY }}
|
||||
THIRD_PARTY_IKEV_VPN_KEY: ${{ secrets.THIRD_PARTY_IKEV_VPN_KEY }}
|
||||
THIRD_PARTY_PREMIUM_VPN_KEY: ${{ secrets.THIRD_PARTY_PREMIUM_VPN_KEY }}
|
||||
THIRD_PARTY_VMESS_NEW_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VMESS_NEW_IMPORT_DATA }}
|
||||
THIRD_PARTY_VMESS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VMESS_IMPORT_DATA }}
|
||||
THIRD_PARTY_TROJAN_IMPORT_DATA: ${{ secrets.THIRD_PARTY_TROJAN_IMPORT_DATA }}
|
||||
THIRD_PARTY_VLESS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_VLESS_IMPORT_DATA }}
|
||||
THIRD_PARTY_SHADOWSOCKS_IMPORT_DATA: ${{ secrets.THIRD_PARTY_SHADOWSOCKS_IMPORT_DATA }}
|
||||
THIRD_PARTY_SHADOWSOCKS_SUBSCRIPTION_IMPORT_DATA: ${{ secrets.THIRD_PARTY_SHADOWSOCKS_SUBSCRIPTION_IMPORT_DATA }}
|
||||
|
||||
steps:
|
||||
- name: Setup Xcode
|
||||
@@ -1382,16 +1300,12 @@ jobs:
|
||||
|
||||
- name: Decode backup file
|
||||
if: matrix.filter == 'BackupExportImportTest'
|
||||
shell: bash
|
||||
env:
|
||||
BACKUP_FILE_BASE64: ${{ secrets.BACKUP_FILE_BASE64 }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
if [ -z "$BACKUP_FILE_BASE64" ]; then
|
||||
echo "::error::BACKUP_FILE_BASE64 secret is not set"
|
||||
exit 1
|
||||
fi
|
||||
echo "$BACKUP_FILE_BASE64" | base64 --decode > "$RUNNER_TEMP/test.backup"
|
||||
echo "BACKUP_PATH=$RUNNER_TEMP/test.backup" >> "$GITHUB_ENV"
|
||||
$backup = Join-Path $env:RUNNER_TEMP "test.backup"
|
||||
$bytes = [Convert]::FromBase64String("${{ secrets.BACKUP_FILE_BASE64 }}")
|
||||
[IO.File]::WriteAllBytes($backup, $bytes)
|
||||
"BACKUP_PATH=$backup" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -1410,9 +1324,23 @@ jobs:
|
||||
dir: ${{ runner.temp }}
|
||||
set-env: true
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Install Conan
|
||||
run: pip install "conan==2.28.0"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew update
|
||||
brew install cmake ninja
|
||||
|
||||
- name: Restore executable permissions
|
||||
run: |
|
||||
find deploy/build/client/tests \
|
||||
-maxdepth 1 \
|
||||
-type f \
|
||||
-name "test_*" \
|
||||
-exec chmod +x {} \;
|
||||
@@ -1422,7 +1350,9 @@ jobs:
|
||||
run: |
|
||||
QT_ROOT="$RUNNER_TEMP/Qt/$QT_VERSION/macos"
|
||||
|
||||
export DYLD_LIBRARY_PATH="$PWD/deploy/build/client/tests:$QT_ROOT/lib:${DYLD_LIBRARY_PATH:-}"
|
||||
export DYLD_LIBRARY_PATH="$PWD/deploy/build/client/tests/openssl:$QT_ROOT/lib:$DYLD_LIBRARY_PATH"
|
||||
|
||||
# export QT_QPA_PLATFORM=offscreen
|
||||
|
||||
ctest --test-dir deploy/build/client/tests -R "${{ matrix.filter }}" --output-on-failure
|
||||
|
||||
@@ -1466,7 +1396,7 @@ jobs:
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
host: 'all_os'
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_x86_64'
|
||||
modules: ${{ env.QT_MODULES }}
|
||||
@@ -1511,8 +1441,7 @@ jobs:
|
||||
-DANDROID_PLATFORM=${{ env.ANDROID_PLATFORM }} \
|
||||
-DCMAKE_ANDROID_NDK=$CMAKE_ANDROID_NDK \
|
||||
-DQT_HOST_PATH=$QT_HOST \
|
||||
-DANDROID_SDK_ROOT=$ANDROID_HOME \
|
||||
-DAMNEZIA_BUILD_TESTS=ON
|
||||
-DANDROID_SDK_ROOT=$ANDROID_HOME
|
||||
|
||||
- name: 'Build Android tests'
|
||||
# env:
|
||||
@@ -1585,6 +1514,15 @@ jobs:
|
||||
EOF
|
||||
chmod +x ci_run_android_tests.sh
|
||||
|
||||
- name: 'Verify Android test files'
|
||||
run: |
|
||||
echo "Runner script:"
|
||||
grep 'local apk=' ci_run_android_tests.sh
|
||||
|
||||
echo
|
||||
echo "APKs:"
|
||||
find build -type f -name '*.apk' -print
|
||||
|
||||
- name: 'Run Android tests on emulator'
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
|
||||
+2
-4
@@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
if(NOT AMNEZIAVPN_VERSION)
|
||||
set(AMNEZIAVPN_VERSION 5.0.3.1 CACHE STRING "Client app version")
|
||||
set(AMNEZIAVPN_VERSION 5.0.2.1 CACHE STRING "Client app version")
|
||||
endif()
|
||||
|
||||
set(QT_CREATOR_SKIP_PACKAGE_MANAGER_SETUP ON CACHE BOOL "" FORCE)
|
||||
@@ -20,8 +20,6 @@ project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
|
||||
HOMEPAGE_URL "https://amnezia.org/"
|
||||
)
|
||||
|
||||
option(AMNEZIA_BUILD_TESTS "Build test executables" OFF)
|
||||
|
||||
# trigger conan to kick off `conan install` globally
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if (PREBUILTS_ONLY)
|
||||
@@ -34,7 +32,7 @@ set(RELEASE_DATE "${CURRENT_DATE}")
|
||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
|
||||
# bump by 2 on every release, because we're releasing two versions on the play store
|
||||
set(APP_ANDROID_VERSION_CODE 2171)
|
||||
set(APP_ANDROID_VERSION_CODE 2161)
|
||||
if(DEFINED APP_ANDROID_VERSION_CODE_OFFSET)
|
||||
math(EXPR APP_ANDROID_VERSION_CODE "${APP_ANDROID_VERSION_CODE} + ${APP_ANDROID_VERSION_CODE_OFFSET}")
|
||||
endif()
|
||||
|
||||
@@ -92,7 +92,6 @@ else()
|
||||
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_hi_IN.ts
|
||||
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_es_ES.ts
|
||||
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_ko_KR.ts
|
||||
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_fr_FR.ts
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -315,6 +314,8 @@ if(OVPN_SCRIPTS)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(AMNEZIA_BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
|
||||
add_subdirectory(tests)
|
||||
@@ -179,9 +179,7 @@ void AmneziaApplication::init()
|
||||
|
||||
m_coreController->setQmlRoot();
|
||||
|
||||
#if CLIENT_ENABLE_APP_UPDATES
|
||||
m_coreController->checkForAppUpdates();
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN //TODO
|
||||
if (m_parser.isSet(m_optAutostart))
|
||||
|
||||
@@ -58,7 +58,3 @@ endif()
|
||||
if(NOT CLIENT_NOTIFICATION_IDENTIFIER)
|
||||
set(CLIENT_NOTIFICATION_IDENTIFIER "${CLIENT_TS_PREFIX}" CACHE STRING "Local notification request identifier")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CLIENT_ENABLE_APP_UPDATES)
|
||||
set(CLIENT_ENABLE_APP_UPDATES 1)
|
||||
endif()
|
||||
@@ -22,7 +22,6 @@ set(HEADERS ${HEADERS}
|
||||
${CLIENT_ROOT_DIR}/core/controllers/coreSignalHandlers.h
|
||||
${CLIENT_ROOT_DIR}/core/controllers/gatewayController.h
|
||||
${CLIENT_ROOT_DIR}/core/utils/selfhosted/sshSession.h
|
||||
${CLIENT_ROOT_DIR}/core/utils/selfhosted/sshExecutor.h
|
||||
${CLIENT_ROOT_DIR}/core/controllers/serversController.h
|
||||
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/usersController.h
|
||||
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/installController.h
|
||||
@@ -108,7 +107,6 @@ set(SOURCES ${SOURCES}
|
||||
${CLIENT_ROOT_DIR}/core/controllers/coreSignalHandlers.cpp
|
||||
${CLIENT_ROOT_DIR}/core/controllers/gatewayController.cpp
|
||||
${CLIENT_ROOT_DIR}/core/utils/selfhosted/sshSession.cpp
|
||||
${CLIENT_ROOT_DIR}/core/utils/selfhosted/sshExecutor.cpp
|
||||
${CLIENT_ROOT_DIR}/core/controllers/serversController.cpp
|
||||
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/usersController.cpp
|
||||
${CLIENT_ROOT_DIR}/core/controllers/selfhosted/installController.cpp
|
||||
|
||||
@@ -188,9 +188,6 @@ ErrorCode StorePurchaseController::importServiceFromMarket(const QString &userCo
|
||||
|
||||
quint16 crc = qChecksum(QJsonDocument(configObject).toJson());
|
||||
|
||||
if (!serverConfigUtils::isConfigFormatVersionSupported(configObject)) {
|
||||
return ErrorCode::ConfigFormatVersionNotSupportedError;
|
||||
}
|
||||
if (configObject.value(configKey::configVersion).toInt() != serverConfigUtils::ConfigSource::AmneziaGateway) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
@@ -239,9 +239,6 @@ ErrorCode SubscriptionController::applyImportedServiceConfig(const QString &user
|
||||
|
||||
updateApiConfigInJson(serverConfigJson, serviceType, serviceProtocol, userCountryCode, responseBody);
|
||||
|
||||
if (!serverConfigUtils::isConfigFormatVersionSupported(serverConfigJson)) {
|
||||
return ErrorCode::ConfigFormatVersionNotSupportedError;
|
||||
}
|
||||
if (serverConfigJson.value(configKey::configVersion).toInt() != serverConfigUtils::ConfigSource::AmneziaGateway) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
@@ -294,9 +291,6 @@ ErrorCode SubscriptionController::importTrialFromGateway(const QString &userCoun
|
||||
}
|
||||
|
||||
QJsonObject configObject = QJsonDocument::fromJson(configBytes).object();
|
||||
if (!serverConfigUtils::isConfigFormatVersionSupported(configObject)) {
|
||||
return ErrorCode::ConfigFormatVersionNotSupportedError;
|
||||
}
|
||||
if (configObject.value(configKey::configVersion).toInt() != serverConfigUtils::ConfigSource::AmneziaGateway) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
@@ -386,9 +380,6 @@ ErrorCode SubscriptionController::applyUpdatedServiceConfig(const QString &serve
|
||||
|
||||
updateApiConfigInJson(serverConfigJson, apiV2->apiConfig.serviceType, serviceProtocol, apiV2->apiConfig.userCountryCode, responseBody);
|
||||
|
||||
if (!serverConfigUtils::isConfigFormatVersionSupported(serverConfigJson)) {
|
||||
return ErrorCode::ConfigFormatVersionNotSupportedError;
|
||||
}
|
||||
if (serverConfigJson.value(configKey::configVersion).toInt() != serverConfigUtils::ConfigSource::AmneziaGateway) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "coreSignalHandlers.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "core/utils/selfhosted/sshSession.h"
|
||||
#include "core/utils/selfhosted/sshExecutor.h"
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/controllers/coreController.h"
|
||||
@@ -145,7 +145,7 @@ void CoreSignalHandlers::initExportControllerHandler()
|
||||
});
|
||||
connect(m_coreController->m_exportController, &ExportController::revokeClientRequested, this,
|
||||
[this](const QString &serverId, int row, DockerContainer container) {
|
||||
SshExecutor::instance().run(serverId, [this, serverId, row, container]() {
|
||||
QtConcurrent::run([this, serverId, row, container]() {
|
||||
m_coreController->m_usersController->revokeClient(serverId, row, container);
|
||||
});
|
||||
});
|
||||
@@ -205,10 +205,8 @@ void CoreSignalHandlers::initAdminConfigRevokedHandler()
|
||||
{
|
||||
connect(m_coreController->m_installController, &InstallController::clientRevocationRequested, this,
|
||||
[this](const QString &serverId, const ContainerConfig &containerConfig, DockerContainer container) {
|
||||
SshExecutor::instance().run(serverId, [this, serverId, containerConfig, container]() {
|
||||
m_coreController->m_usersController->revokeClient(serverId, containerConfig, container);
|
||||
});
|
||||
});
|
||||
m_coreController->m_usersController->revokeClient(serverId, containerConfig, container);
|
||||
}, Qt::DirectConnection);
|
||||
|
||||
connect(m_coreController->m_installController, &InstallController::clientAppendRequested, this,
|
||||
[this](const QString &serverId, const QString &clientId, const QString &clientName, DockerContainer container) {
|
||||
|
||||
@@ -33,18 +33,6 @@ using namespace ProtocolUtils;
|
||||
|
||||
namespace
|
||||
{
|
||||
bool rejectUnsupportedFormatVersion(ImportController::ImportResult &result)
|
||||
{
|
||||
if (serverConfigUtils::isConfigFormatVersionSupported(result.config)) {
|
||||
return false;
|
||||
}
|
||||
qWarning() << "Config format version" << serverConfigUtils::configFormatVersion(result.config)
|
||||
<< "is newer than supported" << serverConfigUtils::currentConfigFormatVersion;
|
||||
result.errorCode = ErrorCode::ConfigFormatVersionNotSupportedError;
|
||||
result.config = {};
|
||||
return true;
|
||||
}
|
||||
|
||||
ConfigTypes checkConfigFormat(const QString &config)
|
||||
{
|
||||
const QString openVpnConfigPatternCli = "client";
|
||||
@@ -219,10 +207,6 @@ ImportController::ImportResult ImportController::extractConfigFromData(const QSt
|
||||
case ConfigTypes::Amnezia: {
|
||||
result.config = QJsonDocument::fromJson(config.toUtf8()).object();
|
||||
|
||||
if (rejectUnsupportedFormatVersion(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (serverConfigUtils::isServerFromApi(result.config)) {
|
||||
auto apiConfig = result.config.value(apiDefs::key::apiConfig).toObject();
|
||||
apiConfig[apiDefs::key::vpnKey] = data;
|
||||
@@ -272,7 +256,6 @@ ImportController::ImportResult ImportController::extractConfigFromQr(const QByte
|
||||
if (!dataObj.isEmpty()) {
|
||||
result.config = dataObj;
|
||||
result.configType = ConfigTypes::Amnezia;
|
||||
rejectUnsupportedFormatVersion(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -284,7 +267,6 @@ ImportController::ImportResult ImportController::extractConfigFromQr(const QByte
|
||||
return result;
|
||||
}
|
||||
result.configType = ConfigTypes::Amnezia;
|
||||
rejectUnsupportedFormatVersion(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -302,7 +284,6 @@ ImportController::ImportResult ImportController::extractConfigFromQr(const QByte
|
||||
return result;
|
||||
}
|
||||
result.configType = ConfigTypes::Amnezia;
|
||||
rejectUnsupportedFormatVersion(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -398,11 +379,6 @@ int ImportController::qrChunksTotal() const
|
||||
|
||||
void ImportController::importConfig(const QJsonObject &config)
|
||||
{
|
||||
if (!serverConfigUtils::isConfigFormatVersionSupported(config)) {
|
||||
emit importErrorOccurred(ErrorCode::ConfigFormatVersionNotSupportedError, false);
|
||||
return;
|
||||
}
|
||||
|
||||
ServerCredentials credentials;
|
||||
credentials.hostName = config.value(configKey::hostName).toString();
|
||||
credentials.port = config.value(configKey::port).toInt();
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "core/utils/containers/containerUtils.h"
|
||||
#include "core/utils/protocolEnum.h"
|
||||
#include "core/utils/selfhosted/sshSession.h"
|
||||
#include "core/utils/selfhosted/sshExecutor.h"
|
||||
#include "core/installers/awgInstaller.h"
|
||||
#include "core/installers/installerBase.h"
|
||||
#include "core/installers/openvpnInstaller.h"
|
||||
@@ -105,7 +104,6 @@ InstallController::~InstallController()
|
||||
ErrorCode InstallController::setupContainer(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config,
|
||||
bool isUpdate)
|
||||
{
|
||||
qDebug().noquote() << "InstallController::setupContainer" << ContainerUtils::containerToString(container);
|
||||
SshSession sshSession;
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
|
||||
@@ -373,7 +371,7 @@ ErrorCode InstallController::validateAndPrepareConfig(const QString &serverId)
|
||||
|
||||
void InstallController::validateConfig(const QString &serverId)
|
||||
{
|
||||
QFuture<ErrorCode> future = SshExecutor::instance().run(serverId, [this, serverId]() {
|
||||
QFuture<ErrorCode> future = QtConcurrent::run([this, serverId]() {
|
||||
return validateAndPrepareConfig(serverId);
|
||||
});
|
||||
|
||||
|
||||
@@ -119,11 +119,6 @@ QByteArray SettingsController::backupAppConfig() const
|
||||
return QJsonDocument(config).toJson();
|
||||
}
|
||||
|
||||
int SettingsController::unsupportedFormatConfigsSkippedCount() const
|
||||
{
|
||||
return m_serversRepository->unsupportedFormatConfigsCount();
|
||||
}
|
||||
|
||||
ErrorCode SettingsController::restoreAppConfigFromData(const QByteArray &data)
|
||||
{
|
||||
if (!m_appSettingsRepository->restoreAppConfig(data)) {
|
||||
|
||||
@@ -39,7 +39,6 @@ public:
|
||||
|
||||
QByteArray backupAppConfig() const;
|
||||
ErrorCode restoreAppConfigFromData(const QByteArray &data);
|
||||
int unsupportedFormatConfigsSkippedCount() const;
|
||||
|
||||
QString getAppVersion() const;
|
||||
|
||||
|
||||
@@ -129,10 +129,6 @@ void UpdateController::setUpdateCheckRunning(bool running)
|
||||
|
||||
void UpdateController::checkForUpdates()
|
||||
{
|
||||
#if !CLIENT_ENABLE_APP_UPDATES
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (m_updateCheckRunning || !m_appSettingsRepository) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,6 @@ QPair<QString, QString> ApiV2ServerConfig::getDnsPair(const QString &primaryDns,
|
||||
QJsonObject ApiV2ServerConfig::toJson() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj[configKey::formatVersion] = serverConfigUtils::currentConfigFormatVersion;
|
||||
|
||||
if (!name.isEmpty()) {
|
||||
obj[configKey::name] = name;
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "core/utils/protocolEnum.h"
|
||||
#include "core/protocols/protocolUtils.h"
|
||||
#include "core/utils/constants/configKeys.h"
|
||||
#include "core/utils/serverConfigUtils.h"
|
||||
#include "core/utils/constants/protocolConstants.h"
|
||||
#include "core/utils/networkUtilities.h"
|
||||
|
||||
@@ -52,7 +51,6 @@ QPair<QString, QString> NativeServerConfig::getDnsPair(const QString &primaryDns
|
||||
QJsonObject NativeServerConfig::toJson() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj[configKey::formatVersion] = serverConfigUtils::currentConfigFormatVersion;
|
||||
|
||||
if (!description.isEmpty()) {
|
||||
obj[configKey::description] = this->description;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "core/utils/containers/containerUtils.h"
|
||||
#include "core/utils/protocolEnum.h"
|
||||
#include "core/utils/networkUtilities.h"
|
||||
#include "core/utils/serverConfigUtils.h"
|
||||
|
||||
namespace amnezia
|
||||
{
|
||||
@@ -84,7 +83,6 @@ QPair<QString, QString> SelfHostedAdminServerConfig::getDnsPair(bool isAmneziaDn
|
||||
QJsonObject SelfHostedAdminServerConfig::toJson() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj[configKey::formatVersion] = serverConfigUtils::currentConfigFormatVersion;
|
||||
|
||||
if (!description.isEmpty()) {
|
||||
obj[configKey::description] = this->description;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "core/protocols/protocolUtils.h"
|
||||
#include "core/utils/constants/configKeys.h"
|
||||
#include "core/utils/serverConfigUtils.h"
|
||||
#include "core/utils/constants/protocolConstants.h"
|
||||
#include "core/utils/containerEnum.h"
|
||||
#include "core/utils/containers/containerUtils.h"
|
||||
@@ -67,7 +66,6 @@ QPair<QString, QString> SelfHostedUserServerConfig::getDnsPair(const QString &pr
|
||||
QJsonObject SelfHostedUserServerConfig::toJson() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj[configKey::formatVersion] = serverConfigUtils::currentConfigFormatVersion;
|
||||
|
||||
if (!description.isEmpty()) {
|
||||
obj[configKey::description] = this->description;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <QJsonValue>
|
||||
#include <QSet>
|
||||
#include <QUuid>
|
||||
#include <QDebug>
|
||||
|
||||
#include "core/utils/serverConfigUtils.h"
|
||||
#include "core/utils/constants/apiKeys.h"
|
||||
@@ -143,7 +142,6 @@ void SecureServersRepository::persistDefaultServerFields()
|
||||
void SecureServersRepository::loadFromStorage()
|
||||
{
|
||||
clearServerStateMaps();
|
||||
m_unsupportedFormatConfigsCount = 0;
|
||||
|
||||
const QJsonArray serversArray =
|
||||
QJsonDocument::fromJson(value(QStringLiteral("Servers/serversList"), QByteArray()).toByteArray())
|
||||
@@ -154,12 +152,6 @@ void SecureServersRepository::loadFromStorage()
|
||||
const QString candidateId = readStorageServerId(json);
|
||||
const QString serverId = normalizedOrGeneratedServerId(candidateId);
|
||||
const QJsonObject strippedJson = withoutStorageServerId(json);
|
||||
if (!serverConfigUtils::isConfigFormatVersionSupported(strippedJson)) {
|
||||
qWarning() << "Skipping stored server config with unsupported format version"
|
||||
<< serverConfigUtils::configFormatVersion(strippedJson);
|
||||
++m_unsupportedFormatConfigsCount;
|
||||
continue;
|
||||
}
|
||||
const serverConfigUtils::ConfigType kind = serverConfigUtils::configTypeFromJson(strippedJson);
|
||||
|
||||
if (m_serverJsonById.contains(serverId) || kind == serverConfigUtils::ConfigType::Invalid) {
|
||||
@@ -192,11 +184,6 @@ void SecureServersRepository::invalidateCache()
|
||||
loadFromStorage();
|
||||
}
|
||||
|
||||
int SecureServersRepository::unsupportedFormatConfigsCount() const
|
||||
{
|
||||
return m_unsupportedFormatConfigsCount;
|
||||
}
|
||||
|
||||
void SecureServersRepository::clearServers()
|
||||
{
|
||||
clearServerStateMaps();
|
||||
@@ -235,8 +222,7 @@ QString SecureServersRepository::addServer(const QString &serverId, const QJsonO
|
||||
return id;
|
||||
}
|
||||
const QJsonObject strippedJson = withoutStorageServerId(serverJson);
|
||||
if (!serverConfigUtils::isConfigFormatVersionSupported(strippedJson)
|
||||
|| serverConfigUtils::configTypeFromJson(strippedJson) != kind) {
|
||||
if (serverConfigUtils::configTypeFromJson(strippedJson) != kind) {
|
||||
return id;
|
||||
}
|
||||
m_serverJsonById.insert(id, embedStorageServerId(id, strippedJson));
|
||||
|
||||
@@ -52,8 +52,6 @@ public:
|
||||
|
||||
void invalidateCache();
|
||||
|
||||
int unsupportedFormatConfigsCount() const;
|
||||
|
||||
signals:
|
||||
void serverAdded(const QString &serverId);
|
||||
void serverEdited(const QString &serverId);
|
||||
@@ -79,7 +77,6 @@ private:
|
||||
QVector<QString> m_orderedServerIds;
|
||||
|
||||
QString m_defaultServerId;
|
||||
int m_unsupportedFormatConfigsCount = 0;
|
||||
};
|
||||
|
||||
#endif // SECURESERVERSREPOSITORY_H
|
||||
@@ -11,6 +11,5 @@
|
||||
#define APP_IOS_BUNDLE_ID "@CLIENT_IOS_BUNDLE_ID@"
|
||||
#define APP_IOS_STORE_URL_FALLBACK "@CLIENT_IOS_STORE_URL_FALLBACK@"
|
||||
#define APP_ANDROID_PACKAGE "@CLIENT_ANDROID_PACKAGE@"
|
||||
#define CLIENT_ENABLE_APP_UPDATES @CLIENT_ENABLE_APP_UPDATES@
|
||||
|
||||
#endif
|
||||
@@ -25,7 +25,6 @@ namespace amnezia
|
||||
constexpr QLatin1String accessToken("api_key");
|
||||
constexpr QLatin1String config("config");
|
||||
constexpr QLatin1String configVersion("config_version");
|
||||
constexpr QLatin1String formatVersion("format_version");
|
||||
|
||||
constexpr QLatin1String sendPayload("send_payload");
|
||||
constexpr QLatin1String sendPayloadEndpoint("endpoint");
|
||||
|
||||
@@ -82,8 +82,6 @@ namespace amnezia
|
||||
RestoreBackupInvalidError = 904,
|
||||
LegacyApiV1NotSupportedError = 905,
|
||||
LegacyContainerNotSupportedError = 906,
|
||||
ConfigFormatVersionNotSupportedError = 907,
|
||||
RestoreBackupUnsupportedConfigsSkipped = 908,
|
||||
|
||||
// Android errors
|
||||
AndroidError = 1000,
|
||||
|
||||
@@ -71,8 +71,6 @@ QString errorString(ErrorCode code) {
|
||||
case (ErrorCode::ImportBackupFileUseRestoreInstead): errorMessage = QObject::tr("Backup files cannot be imported here. Use 'Restore from backup' instead."); break;
|
||||
case (ErrorCode::RestoreBackupInvalidError): errorMessage = QObject::tr("Backup file is corrupted or has invalid format"); break;
|
||||
case (ErrorCode::LegacyApiV1NotSupportedError): errorMessage = QObject::tr("This legacy Amnezia subscription format is no longer supported"); break;
|
||||
case (ErrorCode::ConfigFormatVersionNotSupportedError): errorMessage = QObject::tr("This configuration was created in a newer version of the application and is not fully supported. Please update the application"); break;
|
||||
case (ErrorCode::RestoreBackupUnsupportedConfigsSkipped): errorMessage = QObject::tr("Some configurations from the backup were not restored because they require a newer version of the application"); break;
|
||||
case (ErrorCode::LegacyContainerNotSupportedError): errorMessage = QObject::tr("This protocol is no longer supported. Please select another protocol or remove this container from the server settings."); break;
|
||||
case (ErrorCode::ImportOpenConfigError): errorMessage = QObject::tr("Unable to open config file"); break;
|
||||
case (ErrorCode::NoInstalledContainersError): errorMessage = QObject::tr("VPN Protocols is not installed.\n Please install VPN container at first"); break;
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "sshExecutor.h"
|
||||
|
||||
SshExecutor &SshExecutor::instance()
|
||||
{
|
||||
static SshExecutor executor;
|
||||
return executor;
|
||||
}
|
||||
|
||||
SshExecutor::~SshExecutor()
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
for (QThreadPool *pool : std::as_const(m_pools)) {
|
||||
pool->waitForDone();
|
||||
delete pool;
|
||||
}
|
||||
m_pools.clear();
|
||||
}
|
||||
|
||||
QThreadPool *SshExecutor::poolFor(const QString &serverId)
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
|
||||
auto it = m_pools.find(serverId);
|
||||
if (it != m_pools.end()) {
|
||||
return it.value();
|
||||
}
|
||||
|
||||
auto *pool = new QThreadPool();
|
||||
pool->setMaxThreadCount(1); // serialize all SSH ops for this server
|
||||
pool->setExpiryTimeout(-1); // keep the single worker thread alive between ops
|
||||
m_pools.insert(serverId, pool);
|
||||
return pool;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#ifndef SSHEXECUTOR_H
|
||||
#define SSHEXECUTOR_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QMutex>
|
||||
#include <QString>
|
||||
#include <QThreadPool>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include <utility>
|
||||
|
||||
// Per-server serial executor for long-running self-hosted SSH operations.
|
||||
//
|
||||
// All SSH work for a given serverId is queued onto a dedicated single-thread
|
||||
// pool, so operations to the same server run strictly one at a time (no
|
||||
// concurrent SSH sessions to one host => no races, and a natural guard against
|
||||
// double-run). Operations to different servers still run in parallel.
|
||||
//
|
||||
// NOTE: do NOT route nested workers that are awaited from within an already
|
||||
// queued operation (e.g. InstallController::isServerDpkgBusy) through the same
|
||||
// per-server pool — the single worker thread would block waiting on itself.
|
||||
// Such nested helpers must keep using the global QThreadPool.
|
||||
class SshExecutor
|
||||
{
|
||||
public:
|
||||
static SshExecutor &instance();
|
||||
|
||||
SshExecutor(const SshExecutor &) = delete;
|
||||
SshExecutor &operator=(const SshExecutor &) = delete;
|
||||
|
||||
template <typename Functor>
|
||||
auto run(const QString &serverId, Functor &&functor)
|
||||
{
|
||||
return QtConcurrent::run(poolFor(serverId), std::forward<Functor>(functor));
|
||||
}
|
||||
|
||||
private:
|
||||
SshExecutor() = default;
|
||||
~SshExecutor();
|
||||
|
||||
QThreadPool *poolFor(const QString &serverId);
|
||||
|
||||
QHash<QString, QThreadPool *> m_pools;
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
#endif // SSHEXECUTOR_H
|
||||
@@ -34,16 +34,6 @@ bool hasThirdPartyConfig(const QJsonObject &json)
|
||||
namespace serverConfigUtils
|
||||
{
|
||||
|
||||
int configFormatVersion(const QJsonObject &serverConfigObject)
|
||||
{
|
||||
return serverConfigObject.value(amnezia::configKey::formatVersion).toInt(0);
|
||||
}
|
||||
|
||||
bool isConfigFormatVersionSupported(const QJsonObject &serverConfigObject)
|
||||
{
|
||||
return configFormatVersion(serverConfigObject) <= currentConfigFormatVersion;
|
||||
}
|
||||
|
||||
bool isServerFromApi(const QJsonObject &serverConfigObject)
|
||||
{
|
||||
const int configVersion = serverConfigObject.value(amnezia::configKey::configVersion).toInt();
|
||||
|
||||
@@ -25,12 +25,6 @@ enum ConfigSource {
|
||||
AmneziaGateway
|
||||
};
|
||||
|
||||
constexpr int currentConfigFormatVersion = 1;
|
||||
|
||||
int configFormatVersion(const QJsonObject &serverConfigObject);
|
||||
|
||||
bool isConfigFormatVersionSupported(const QJsonObject &serverConfigObject);
|
||||
|
||||
bool isServerFromApi(const QJsonObject &serverConfigObject);
|
||||
|
||||
ConfigSource getConfigSource(const QJsonObject &serverConfigObject);
|
||||
|
||||
@@ -6,8 +6,15 @@
|
||||
<true/>
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>app-proxy-provider</string>
|
||||
<string>packet-tunnel-provider</string>
|
||||
<string>dns-settings</string>
|
||||
<string>relay</string>
|
||||
<string>content-filter-provider</string>
|
||||
<string>dns-proxy</string>
|
||||
</array>
|
||||
<key>com.apple.developer.system-extension.install</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.networking.vpn.api</key>
|
||||
<array>
|
||||
<string>allow-vpn</string>
|
||||
|
||||
@@ -6,7 +6,12 @@
|
||||
<true/>
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>dns-settings</string>
|
||||
<string>relay</string>
|
||||
<string>packet-tunnel-provider</string>
|
||||
<string>content-filter-provider</string>
|
||||
<string>dns-proxy</string>
|
||||
<string>app-proxy-provider</string>
|
||||
</array>
|
||||
<key>com.apple.developer.networking.vpn.api</key>
|
||||
<array>
|
||||
|
||||
+27
-53
@@ -122,15 +122,6 @@ if(NOT ANDROID)
|
||||
test_common
|
||||
)
|
||||
|
||||
add_executable(test_config_format_version
|
||||
testConfigFormatVersion.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(test_config_format_version PRIVATE
|
||||
Qt6::Test
|
||||
test_common
|
||||
)
|
||||
|
||||
add_executable(test_xray_serialization
|
||||
testXraySerialization.cpp
|
||||
)
|
||||
@@ -203,51 +194,35 @@ if(NOT ANDROID)
|
||||
test_common
|
||||
)
|
||||
|
||||
# Tests run from a bare artifact directory on CI, so the OpenSSL runtime we
|
||||
# compiled against must sit next to the binary (PATH / LD_LIBRARY_PATH /
|
||||
# DYLD_LIBRARY_PATH point there). Otherwise the loader picks up the system
|
||||
# library and the version checks in testOpenSSLLibrary fail.
|
||||
foreach(_ssl_tgt OpenSSL::Crypto OpenSSL::SSL)
|
||||
if(NOT TARGET "${_ssl_tgt}")
|
||||
continue()
|
||||
endif()
|
||||
set(_ssl_loc "")
|
||||
foreach(_prop IMPORTED_LOCATION IMPORTED_LOCATION_RELEASE IMPORTED_LOCATION_DEBUG
|
||||
IMPORTED_LOCATION_MINSIZEREL IMPORTED_LOCATION_RELWITHDEBINFO
|
||||
IMPORTED_LOCATION_NOCONFIG)
|
||||
get_target_property(_candidate "${_ssl_tgt}" "${_prop}")
|
||||
if(_candidate AND NOT _candidate MATCHES "-NOTFOUND")
|
||||
set(_ssl_loc "${_candidate}")
|
||||
break()
|
||||
if(WIN32)
|
||||
# libcrypto-3-x64.dll is a hard import of this binary.
|
||||
# Without copying Conan's DLL here, Windows loads the first match in PATH
|
||||
# (MySQL, Git, PHP...) which differs from the Conan version we compiled against,
|
||||
# causing testRuntimeVersionMatchesCompileTime and testWindowsNoDllHijack to fail.
|
||||
foreach(_ssl_tgt OpenSSL::Crypto OpenSSL::SSL)
|
||||
if(NOT TARGET "${_ssl_tgt}")
|
||||
continue()
|
||||
endif()
|
||||
set(_ssl_dll "")
|
||||
foreach(_prop IMPORTED_LOCATION IMPORTED_LOCATION_RELEASE IMPORTED_LOCATION_DEBUG
|
||||
IMPORTED_LOCATION_MINSIZEREL IMPORTED_LOCATION_RELWITHDEBINFO
|
||||
IMPORTED_LOCATION_NOCONFIG)
|
||||
get_target_property(_candidate "${_ssl_tgt}" "${_prop}")
|
||||
if(_candidate AND NOT _candidate MATCHES "-NOTFOUND" AND _candidate MATCHES "\\.dll$")
|
||||
set(_ssl_dll "${_candidate}")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
if(_ssl_dll)
|
||||
add_custom_command(TARGET test_openssl_library POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${_ssl_dll}" "$<TARGET_FILE_DIR:test_openssl_library>"
|
||||
)
|
||||
else()
|
||||
message(STATUS "No .dll found for ${_ssl_tgt} (IMPORTED_LOCATION may point to .lib) — skipping copy")
|
||||
endif()
|
||||
endforeach()
|
||||
if(NOT _ssl_loc)
|
||||
continue()
|
||||
endif()
|
||||
set(_ssl_files "")
|
||||
if(WIN32)
|
||||
if(_ssl_loc MATCHES "\\.dll$")
|
||||
set(_ssl_files "${_ssl_loc}")
|
||||
endif()
|
||||
else()
|
||||
get_filename_component(_ssl_dir "${_ssl_loc}" DIRECTORY)
|
||||
get_filename_component(_ssl_name "${_ssl_loc}" NAME)
|
||||
string(REGEX REPLACE "\\..*$" "" _ssl_stem "${_ssl_name}")
|
||||
file(GLOB _ssl_files
|
||||
"${_ssl_dir}/${_ssl_stem}.so*"
|
||||
"${_ssl_dir}/${_ssl_stem}.dylib"
|
||||
"${_ssl_dir}/${_ssl_stem}.*.dylib")
|
||||
endif()
|
||||
if(NOT _ssl_files)
|
||||
message(STATUS "No shared runtime found for ${_ssl_tgt} (${_ssl_loc}) - skipping copy")
|
||||
endif()
|
||||
foreach(_ssl_file ${_ssl_files})
|
||||
add_custom_command(TARGET test_openssl_library POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${_ssl_file}" "$<TARGET_FILE_DIR:test_openssl_library>"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
endif()
|
||||
endif() # NOT ANDROID
|
||||
|
||||
if(ANDROID)
|
||||
@@ -403,7 +378,6 @@ if(NOT ANDROID)
|
||||
add_test(NAME SettingsSignalsTest COMMAND test_settings_signals)
|
||||
add_test(NAME UiServersModelAndControllerTest COMMAND test_ui_servers_model_and_controller)
|
||||
add_test(NAME XraySerializationTest COMMAND test_xray_serialization)
|
||||
add_test(NAME ConfigFormatVersionTest COMMAND test_config_format_version)
|
||||
add_test(NAME UiLanguageModelAndControllerTest COMMAND test_ui_language_model_and_controller)
|
||||
add_test(NAME UiIpModelAndControllerTest COMMAND test_ui_ip_model_and_controller)
|
||||
add_test(NAME UiAppSTModelAndControllerTest COMMAND test_ui_app_st_model_and_controller)
|
||||
|
||||
@@ -54,8 +54,6 @@ private slots:
|
||||
if (!isEnvValueConfigured(backup)) {
|
||||
QSKIP("Set BACKUP_PATH");
|
||||
}
|
||||
QVERIFY2(QFileInfo(backup).size() > 0,
|
||||
"BACKUP_PATH file is empty - is the BACKUP_FILE_BASE64 secret configured?");
|
||||
|
||||
QSignalSpy errorOccurredSpy(m_coreController->m_settingsUiController, &SettingsUiController::errorOccurred);
|
||||
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
#include <QUuid>
|
||||
|
||||
#include "utils/testCoreController.h"
|
||||
#include "core/models/api/apiV2ServerConfig.h"
|
||||
#include "core/models/selfhosted/nativeServerConfig.h"
|
||||
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
|
||||
#include "core/models/selfhosted/selfHostedUserServerConfig.h"
|
||||
#include "core/utils/constants/configKeys.h"
|
||||
#include "core/utils/serverConfigUtils.h"
|
||||
#include "secureQSettings.h"
|
||||
#include "vpnConnection.h"
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
namespace
|
||||
{
|
||||
QJsonObject adminConfigJson(const QString &hostName, int formatVersion = -1)
|
||||
{
|
||||
QJsonObject json;
|
||||
json[configKey::hostName] = hostName;
|
||||
json[configKey::userName] = QStringLiteral("root");
|
||||
json[configKey::password] = QStringLiteral("secret");
|
||||
json[configKey::port] = 22;
|
||||
json[configKey::description] = QStringLiteral("Server ") + hostName;
|
||||
if (formatVersion >= 0) {
|
||||
json[configKey::formatVersion] = formatVersion;
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
QByteArray serversListBytes(const QList<QJsonObject> &configs)
|
||||
{
|
||||
QJsonArray array;
|
||||
for (const QJsonObject &config : configs) {
|
||||
array.append(config);
|
||||
}
|
||||
return QJsonDocument(array).toJson();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class TestConfigFormatVersion : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
TestCoreController *m_coreController = nullptr;
|
||||
SecureQSettings *m_settings = nullptr;
|
||||
|
||||
private slots:
|
||||
void initTestCase()
|
||||
{
|
||||
const QString testOrg = "AmneziaVPN-Test-" + QUuid::createUuid().toString();
|
||||
m_settings = new SecureQSettings(testOrg, "amnezia-client", nullptr, false);
|
||||
auto vpnConnection = QSharedPointer<VpnConnection>::create(nullptr, nullptr);
|
||||
m_coreController = new TestCoreController(vpnConnection, m_settings, nullptr, this);
|
||||
}
|
||||
|
||||
void cleanupTestCase()
|
||||
{
|
||||
m_settings->clearSettings();
|
||||
delete m_coreController;
|
||||
delete m_settings;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
m_settings->clearSettings();
|
||||
m_coreController->m_serversRepository->invalidateCache();
|
||||
}
|
||||
|
||||
void testVersionCheckHelpers()
|
||||
{
|
||||
QCOMPARE(serverConfigUtils::configFormatVersion(QJsonObject()), 0);
|
||||
QVERIFY(serverConfigUtils::isConfigFormatVersionSupported(QJsonObject()));
|
||||
QVERIFY(serverConfigUtils::isConfigFormatVersionSupported(
|
||||
adminConfigJson("1.1.1.1", serverConfigUtils::currentConfigFormatVersion)));
|
||||
QVERIFY(!serverConfigUtils::isConfigFormatVersionSupported(
|
||||
adminConfigJson("1.1.1.1", serverConfigUtils::currentConfigFormatVersion + 1)));
|
||||
}
|
||||
|
||||
void testToJsonWritesCurrentFormatVersion()
|
||||
{
|
||||
SelfHostedAdminServerConfig admin;
|
||||
admin.hostName = "1.1.1.1";
|
||||
QCOMPARE(admin.toJson().value(configKey::formatVersion).toInt(-1), serverConfigUtils::currentConfigFormatVersion);
|
||||
|
||||
SelfHostedUserServerConfig user;
|
||||
user.hostName = "1.1.1.1";
|
||||
QCOMPARE(user.toJson().value(configKey::formatVersion).toInt(-1), serverConfigUtils::currentConfigFormatVersion);
|
||||
|
||||
NativeServerConfig native;
|
||||
native.hostName = "1.1.1.1";
|
||||
QCOMPARE(native.toJson().value(configKey::formatVersion).toInt(-1), serverConfigUtils::currentConfigFormatVersion);
|
||||
|
||||
ApiV2ServerConfig api;
|
||||
api.hostName = "1.1.1.1";
|
||||
QCOMPARE(api.toJson().value(configKey::formatVersion).toInt(-1), serverConfigUtils::currentConfigFormatVersion);
|
||||
}
|
||||
|
||||
void testImportAcceptsMissingAndCurrentVersion()
|
||||
{
|
||||
auto *importController = m_coreController->m_importCoreController;
|
||||
QSignalSpy importFinishedSpy(importController, &ImportController::importFinished);
|
||||
|
||||
const QString withoutVersion = QJsonDocument(adminConfigJson("1.1.1.1")).toJson();
|
||||
auto result = importController->extractConfigFromData(withoutVersion);
|
||||
QCOMPARE(result.errorCode, ErrorCode::NoError);
|
||||
importController->importConfig(result.config);
|
||||
|
||||
const QString currentVersion =
|
||||
QJsonDocument(adminConfigJson("2.2.2.2", serverConfigUtils::currentConfigFormatVersion)).toJson();
|
||||
result = importController->extractConfigFromData(currentVersion);
|
||||
QCOMPARE(result.errorCode, ErrorCode::NoError);
|
||||
importController->importConfig(result.config);
|
||||
|
||||
QCOMPARE(importFinishedSpy.count(), 2);
|
||||
QCOMPARE(m_coreController->m_serversRepository->serversCount(), 2);
|
||||
|
||||
const auto stored = m_coreController->m_serversRepository->selfHostedAdminConfig(
|
||||
m_coreController->m_serversRepository->serverIdAt(0));
|
||||
QVERIFY(stored.has_value());
|
||||
QCOMPARE(stored->toJson().value(configKey::formatVersion).toInt(-1), serverConfigUtils::currentConfigFormatVersion);
|
||||
}
|
||||
|
||||
void testImportRejectsNewerVersion()
|
||||
{
|
||||
auto *importController = m_coreController->m_importCoreController;
|
||||
QSignalSpy importFinishedSpy(importController, &ImportController::importFinished);
|
||||
QSignalSpy importErrorSpy(importController, &ImportController::importErrorOccurred);
|
||||
|
||||
const QJsonObject newer = adminConfigJson("3.3.3.3", serverConfigUtils::currentConfigFormatVersion + 1);
|
||||
const QByteArray newerBytes = QJsonDocument(newer).toJson();
|
||||
|
||||
auto result = importController->extractConfigFromData(QString::fromUtf8(newerBytes));
|
||||
QCOMPARE(result.errorCode, ErrorCode::ConfigFormatVersionNotSupportedError);
|
||||
QVERIFY(result.config.isEmpty());
|
||||
|
||||
const QString vpnUrl = "vpn://"
|
||||
+ QString::fromUtf8(qCompress(newerBytes, 8).toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals));
|
||||
result = importController->extractConfigFromData(vpnUrl);
|
||||
QCOMPARE(result.errorCode, ErrorCode::ConfigFormatVersionNotSupportedError);
|
||||
QVERIFY(result.config.isEmpty());
|
||||
|
||||
result = importController->extractConfigFromQr(newerBytes);
|
||||
QCOMPARE(result.errorCode, ErrorCode::ConfigFormatVersionNotSupportedError);
|
||||
QVERIFY(result.config.isEmpty());
|
||||
|
||||
importController->importConfig(newer);
|
||||
QCOMPARE(importErrorSpy.count(), 1);
|
||||
QCOMPARE(importErrorSpy.first().at(0).value<ErrorCode>(), ErrorCode::ConfigFormatVersionNotSupportedError);
|
||||
QCOMPARE(importFinishedSpy.count(), 0);
|
||||
QCOMPARE(m_coreController->m_serversRepository->serversCount(), 0);
|
||||
}
|
||||
|
||||
void testRepositorySkipsNewerVersionOnLoad()
|
||||
{
|
||||
m_settings->setValue("Servers/serversList",
|
||||
serversListBytes({ adminConfigJson("1.1.1.1"),
|
||||
adminConfigJson("2.2.2.2", serverConfigUtils::currentConfigFormatVersion + 1),
|
||||
adminConfigJson("3.3.3.3", serverConfigUtils::currentConfigFormatVersion) }));
|
||||
m_coreController->m_serversRepository->invalidateCache();
|
||||
|
||||
QCOMPARE(m_coreController->m_serversRepository->serversCount(), 2);
|
||||
QCOMPARE(m_coreController->m_serversRepository->unsupportedFormatConfigsCount(), 1);
|
||||
|
||||
const auto rejected = m_coreController->m_serversRepository->addServer(
|
||||
QString(), adminConfigJson("4.4.4.4", serverConfigUtils::currentConfigFormatVersion + 1),
|
||||
serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||
QVERIFY(!rejected.isEmpty());
|
||||
QCOMPARE(m_coreController->m_serversRepository->serversCount(), 2);
|
||||
}
|
||||
|
||||
void testRestoreBackupReportsSkippedConfigs()
|
||||
{
|
||||
QJsonObject backup;
|
||||
backup["Servers/serversList"] = QString::fromUtf8(serversListBytes(
|
||||
{ adminConfigJson("1.1.1.1"),
|
||||
adminConfigJson("2.2.2.2", serverConfigUtils::currentConfigFormatVersion + 1) }));
|
||||
|
||||
QSignalSpy errorSpy(m_coreController->m_settingsUiController, &SettingsUiController::errorOccurred);
|
||||
QSignalSpy restoredSpy(m_coreController->m_settingsUiController, &SettingsUiController::restoreBackupFinished);
|
||||
|
||||
m_coreController->m_settingsUiController->restoreAppConfigFromData(QJsonDocument(backup).toJson());
|
||||
|
||||
QCOMPARE(restoredSpy.count(), 1);
|
||||
QCOMPARE(errorSpy.count(), 1);
|
||||
QCOMPARE(errorSpy.first().at(0).value<ErrorCode>(), ErrorCode::RestoreBackupUnsupportedConfigsSkipped);
|
||||
QCOMPARE(m_coreController->m_serversRepository->serversCount(), 1);
|
||||
|
||||
errorSpy.clear();
|
||||
restoredSpy.clear();
|
||||
QJsonObject cleanBackup;
|
||||
cleanBackup["Servers/serversList"] = QString::fromUtf8(serversListBytes({ adminConfigJson("5.5.5.5") }));
|
||||
m_coreController->m_settingsUiController->restoreAppConfigFromData(QJsonDocument(cleanBackup).toJson());
|
||||
QCOMPARE(restoredSpy.count(), 1);
|
||||
QCOMPARE(errorSpy.count(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(TestConfigFormatVersion)
|
||||
#include "testConfigFormatVersion.moc"
|
||||
@@ -41,11 +41,11 @@ private:
|
||||
|
||||
const auto description = serverDescriptionAt(m_coreController->m_serversRepository, expected-1);
|
||||
QVERIFY2(description.has_value(), "Server config should exist");
|
||||
if (*description != expectedDescription) qWarning() << "Server description should match";
|
||||
if (*description == expectedDescription) qWarning() << "Server description should match";
|
||||
|
||||
if (m_coreController->m_serversModel) {
|
||||
QString modelDesc = m_coreController->m_serversModel->data(m_coreController->m_serversModel->index(expected-1, 0), ServersModel::NameRole).toString();
|
||||
if (modelDesc != expectedDescription) qWarning() << "Server description in model should match";
|
||||
if (modelDesc == expectedDescription) qWarning() << "Server description in model should match";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,8 +145,8 @@ private slots:
|
||||
const auto description0 = serverDescriptionAt(m_coreController->m_serversRepository, 0);
|
||||
const auto description1 = serverDescriptionAt(m_coreController->m_serversRepository, 1);
|
||||
QVERIFY2(description0.has_value() && description1.has_value(), "Server configs should exist");
|
||||
if (*description0 != "AWG Server") qWarning() << "First server description should match";
|
||||
if (*description1 != "Xray Server") qWarning() << "Second server description should match";
|
||||
if (*description0 == "AWG Server") qWarning() << "First server description should match";
|
||||
if (*description1 == "Xray Server") qWarning() << "Second server description should match";
|
||||
|
||||
defaultServerChangedSpy.clear();
|
||||
serverRemovedSpy.clear();
|
||||
@@ -165,7 +165,7 @@ private slots:
|
||||
if (m_coreController->m_serversModel) {
|
||||
QVERIFY2(m_coreController->m_serversModel->rowCount() == 1, "After removing first server, model row count should be 1");
|
||||
QString modelDesc = m_coreController->m_serversModel->data(m_coreController->m_serversModel->index(0, 0), ServersModel::NameRole).toString();
|
||||
if (modelDesc != "Xray Server") qWarning() << "Remaining server description in model should match";
|
||||
if (modelDesc == "Xray Server") qWarning() << "Remaining server description in model should match";
|
||||
}
|
||||
|
||||
defaultServerChangedSpy.clear();
|
||||
@@ -184,11 +184,19 @@ private slots:
|
||||
}
|
||||
|
||||
void testListImports() {
|
||||
const QString dnsListPath = QFINDTESTDATA("data/dns_list.json");
|
||||
const QString ipListPath = QFINDTESTDATA("data/ip_list.json");
|
||||
QString dnsListPath = getEnvValue("DNS_LIST_PATH");
|
||||
QString ipListPath = getEnvValue("IP_LIST_PATH");
|
||||
|
||||
QVERIFY2(!dnsListPath.isEmpty(), "data/dns_list.json not found");
|
||||
QVERIFY2(!ipListPath.isEmpty(), "data/ip_list.json not found");
|
||||
logEnvValueState("DNS_LIST_PATH");
|
||||
logEnvValueState("IP_LIST_PATH");
|
||||
qInfo() << "DNS_LIST_PATH file exists:" << QFile::exists(dnsListPath)
|
||||
<< "size:" << QFileInfo(dnsListPath).size();
|
||||
qInfo() << "IP_LIST_PATH file exists:" << QFile::exists(ipListPath)
|
||||
<< "size:" << QFileInfo(ipListPath).size();
|
||||
|
||||
if (!isEnvValueConfigured(dnsListPath) || !isEnvValueConfigured(ipListPath)) {
|
||||
QSKIP("set DNS_LIST_PATH and IP_LIST_PATH");
|
||||
}
|
||||
|
||||
QSignalSpy dnsErrorOccurredSpy(m_coreController->m_allowedDnsUiController, &AllowedDnsUiController::errorOccurred);
|
||||
QSignalSpy dnsFinishedSpy(m_coreController->m_allowedDnsUiController, &AllowedDnsUiController::finished);
|
||||
|
||||
@@ -55,14 +55,6 @@ private:
|
||||
clientConfig[configKey::specialJunk3] = protocols::awg::defaultSpecialJunk3;
|
||||
clientConfig[configKey::specialJunk4] = protocols::awg::defaultSpecialJunk4;
|
||||
clientConfig[configKey::specialJunk5] = protocols::awg::defaultSpecialJunk5;
|
||||
clientConfig[configKey::initPacketJunkSize] = QString::number(protocols::awg::initPacketJunkSizeMax);
|
||||
clientConfig[configKey::responsePacketJunkSize] = QString::number(protocols::awg::responsePacketJunkSizeMax);
|
||||
clientConfig[configKey::cookieReplyPacketJunkSize] = QString::number(protocols::awg::cookieReplyPacketJunkSizeMax);
|
||||
clientConfig[configKey::transportPacketJunkSize] = protocols::awg::defaultPadding;
|
||||
clientConfig[configKey::initPacketMagicHeader] = protocols::awg::defaultInitPacketMagicHeader;
|
||||
clientConfig[configKey::responsePacketMagicHeader] = protocols::awg::defaultResponsePacketMagicHeader;
|
||||
clientConfig[configKey::underloadPacketMagicHeader] = protocols::awg::defaultUnderloadPacketMagicHeader;
|
||||
clientConfig[configKey::transportPacketMagicHeader] = protocols::awg::defaultTransportPacketMagicHeader;
|
||||
clientConfig[configKey::clientPrivKey] = "test_client_private_key";
|
||||
clientConfig[configKey::clientPubKey] = "test_client_public_key";
|
||||
clientConfig[configKey::serverPubKey] = "test_server_public_key";
|
||||
@@ -79,9 +71,9 @@ private:
|
||||
awgConfig[configKey::junkPacketCount] = protocols::awg::defaultJunkPacketCount;
|
||||
awgConfig[configKey::junkPacketMinSize] = protocols::awg::defaultJunkPacketMinSize;
|
||||
awgConfig[configKey::junkPacketMaxSize] = protocols::awg::defaultJunkPacketMaxSize;
|
||||
awgConfig[configKey::initPacketJunkSize] = QString::number(protocols::awg::initPacketJunkSizeMax);
|
||||
awgConfig[configKey::responsePacketJunkSize] = QString::number(protocols::awg::responsePacketJunkSizeMax);
|
||||
awgConfig[configKey::cookieReplyPacketJunkSize] = QString::number(protocols::awg::cookieReplyPacketJunkSizeMax);
|
||||
awgConfig[configKey::initPacketJunkSize] = protocols::awg::initPacketJunkSizeMax;
|
||||
awgConfig[configKey::responsePacketJunkSize] = protocols::awg::responsePacketJunkSizeMax;
|
||||
awgConfig[configKey::cookieReplyPacketJunkSize] = protocols::awg::cookieReplyPacketJunkSizeMax;
|
||||
awgConfig[configKey::transportPacketJunkSize] = protocols::awg::defaultPadding;
|
||||
awgConfig[configKey::initPacketMagicHeader] = protocols::awg::defaultInitPacketMagicHeader;
|
||||
awgConfig[configKey::responsePacketMagicHeader] = protocols::awg::defaultResponsePacketMagicHeader;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -31,7 +31,6 @@ int LanguageUiController::getCurrentLanguageIndex() const
|
||||
case QLocale::Hindi: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Hindi); break;
|
||||
case QLocale::Korean: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Korean); break;
|
||||
case QLocale::Spanish: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Spanish); break;
|
||||
case QLocale::French: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::French); break;
|
||||
default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +65,6 @@ LanguageSettings::AvailableLanguageEnum LanguageUiController::getSystemLanguageE
|
||||
case QLocale::Korean: return LanguageSettings::AvailableLanguageEnum::Korean;
|
||||
case QLocale::English: return LanguageSettings::AvailableLanguageEnum::English;
|
||||
case QLocale::Spanish: return LanguageSettings::AvailableLanguageEnum::Spanish;
|
||||
case QLocale::French: return LanguageSettings::AvailableLanguageEnum::French;
|
||||
default: return LanguageSettings::AvailableLanguageEnum::English;
|
||||
}
|
||||
}
|
||||
@@ -113,7 +111,6 @@ QString LanguageUiController::getLocalLanguageName(const LanguageSettings::Avail
|
||||
case LanguageSettings::AvailableLanguageEnum::Hindi: strLanguage = "हिन्दी"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Korean: strLanguage = "한국어"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Spanish: strLanguage = "Español"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::French: strLanguage = "Français"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -134,7 +131,6 @@ QLocale LanguageUiController::languageEnumToLocale(const LanguageSettings::Avail
|
||||
case LanguageSettings::AvailableLanguageEnum::Hindi: return QLocale::Hindi;
|
||||
case LanguageSettings::AvailableLanguageEnum::Korean: return QLocale::Korean;
|
||||
case LanguageSettings::AvailableLanguageEnum::Spanish: return QLocale::Spanish;
|
||||
case LanguageSettings::AvailableLanguageEnum::French: return QLocale::French;
|
||||
default: return QLocale::English;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <utility>
|
||||
|
||||
#include "core/utils/api/apiUtils.h"
|
||||
#include "core/utils/selfhosted/sshExecutor.h"
|
||||
#include "core/controllers/selfhosted/installController.h"
|
||||
#include "core/controllers/connectionController.h"
|
||||
#include "core/utils/networkUtilities.h"
|
||||
@@ -348,7 +347,7 @@ void InstallUiController::updateServerConfig(const QString &serverId, int contai
|
||||
ContainerConfig oldConfigCopy = oldContainerConfig;
|
||||
InstallController *installController = m_installController;
|
||||
QFuture<ErrorCode> future =
|
||||
SshExecutor::instance().run(serverId, [installController, serverId, container, oldConfigCopy,
|
||||
QtConcurrent::run([installController, serverId, container, oldConfigCopy,
|
||||
newConfigCopy]() mutable -> ErrorCode {
|
||||
return installController->updateServerConfig(serverId, container, oldConfigCopy, newConfigCopy);
|
||||
});
|
||||
@@ -541,7 +540,7 @@ void InstallUiController::removeContainer(const QString &serverId, int container
|
||||
});
|
||||
|
||||
InstallController *installController = m_installController;
|
||||
QFuture<ErrorCode> future = SshExecutor::instance().run(serverId,
|
||||
QFuture<ErrorCode> future = QtConcurrent::run(
|
||||
[installController, serverId, container]() -> ErrorCode {
|
||||
return installController->removeContainer(serverId, container);
|
||||
});
|
||||
|
||||
@@ -163,10 +163,6 @@ void SettingsUiController::restoreAppConfigFromData(const QByteArray &data)
|
||||
emit restoreBackupFinished();
|
||||
emit autoStartChanged();
|
||||
emit startMinimizedChanged();
|
||||
|
||||
if (m_settingsController->unsupportedFormatConfigsSkippedCount() > 0) {
|
||||
emit errorOccurred(ErrorCode::RestoreBackupUnsupportedConfigsSkipped);
|
||||
}
|
||||
} else {
|
||||
emit errorOccurred(errorCode);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ QString LanguageModel::getLocalLanguageName(const LanguageSettings::AvailableLan
|
||||
case LanguageSettings::AvailableLanguageEnum::Hindi: strLanguage = "हिन्दी"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Spanish: strLanguage = "Español"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Korean: strLanguage = "한국어"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::French: strLanguage = "Français"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ namespace LanguageSettings
|
||||
Urdu,
|
||||
Hindi,
|
||||
Spanish,
|
||||
Korean,
|
||||
French
|
||||
Korean
|
||||
};
|
||||
Q_ENUM_NS(AvailableLanguageEnum)
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.bottomMargin: 24
|
||||
visible: Qt.platform.os === "ios" || IsMacOsNeBuild
|
||||
visible: (Qt.platform.os === "ios" || IsMacOsNeBuild) && !(root.currentPlan && root.currentPlan.hasFreeTrial)
|
||||
spacing: 16
|
||||
|
||||
ParagraphTextType {
|
||||
|
||||
@@ -174,15 +174,6 @@ Window {
|
||||
|
||||
PopupType {
|
||||
id: popupNotificationMessage
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
popupNotificationMessage.close()
|
||||
popupNotificationTimer.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
find_program(CONAN_COMMAND "conan" REQUIRED
|
||||
HINTS
|
||||
"${CMAKE_SOURCE_DIR}/.venv/Scripts"
|
||||
"${CMAKE_SOURCE_DIR}/.venv/bin"
|
||||
"/opt/homebrew/bin"
|
||||
)
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
if(NOT DEFINED SIGNTOOL_SUBJECT_NAME)
|
||||
set(SIGNTOOL_SUBJECT_NAME "$ENV{SIGNTOOL_SUBJECT_NAME}")
|
||||
endif()
|
||||
if(NOT DEFINED SIGNTOOL_CERT_HAS_UI)
|
||||
set(SIGNTOOL_CERT_HAS_UI "$ENV{SIGNTOOL_CERT_HAS_UI}")
|
||||
endif()
|
||||
if(NOT DEFINED CODESIGN_SIGNATURE)
|
||||
set(CODESIGN_SIGNATURE "$ENV{CODESIGN_SIGNATURE}")
|
||||
endif()
|
||||
@@ -12,11 +9,14 @@ if(NOT DEFINED CODESIGN_KEYCHAIN)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(AMNEZIA_PACKAGE_DIR "${CPACK_TEMPORARY_DIRECTORY}/packages/AmneziaVPN/data")
|
||||
if(SIGNTOOL_SUBJECT_NAME)
|
||||
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("${AMNEZIA_PACKAGE_DIR}/*.exe" "${SIGNTOOL_SUBJECT_NAME}" "${SIGNTOOL_CERT_HAS_UI}")
|
||||
signtool_sign_files("${AMNEZIA_PACKAGE_DIR}/*.dll" "${SIGNTOOL_SUBJECT_NAME}" "${SIGNTOOL_CERT_HAS_UI}")
|
||||
signtool_sign_files("${BINARIES}" "${SIGNTOOL_SUBJECT_NAME}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
if(NOT DEFINED SIGNTOOL_SUBJECT_NAME)
|
||||
set(SIGNTOOL_SUBJECT_NAME "$ENV{SIGNTOOL_SUBJECT_NAME}")
|
||||
endif()
|
||||
if(NOT DEFINED SIGNTOOL_CERT_HAS_UI)
|
||||
set(SIGNTOOL_CERT_HAS_UI "$ENV{SIGNTOOL_CERT_HAS_UI}")
|
||||
endif()
|
||||
if(NOT DEFINED NOTARYTOOL_EMAIL)
|
||||
set(NOTARYTOOL_EMAIL "$ENV{NOTARYTOOL_EMAIL}")
|
||||
endif()
|
||||
@@ -18,7 +15,7 @@ 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}" "${SIGNTOOL_CERT_HAS_UI}")
|
||||
signtool_sign_files("${PACKAGE_FILE}" "${SIGNTOOL_SUBJECT_NAME}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
+19
-22
@@ -1,6 +1,10 @@
|
||||
find_program(SIGNTOOL_COMMAND signtool REQUIRED)
|
||||
|
||||
function(signtool_sign_files PACKAGE_FILES SUBJECT_NAME CERT_HAS_UI)
|
||||
function(signtool_sign_files PACKAGE_FILES SUBJECT_NAME)
|
||||
if(NOT SUBJECT_NAME)
|
||||
set(SUBJECT_NAME "Privacy Technologies OU")
|
||||
endif()
|
||||
|
||||
if(PACKAGE_FILES)
|
||||
set(args sign
|
||||
/n ${SUBJECT_NAME}
|
||||
@@ -9,33 +13,26 @@ function(signtool_sign_files PACKAGE_FILES SUBJECT_NAME CERT_HAS_UI)
|
||||
/tr http://timestamp.comodoca.com/?td=sha256
|
||||
)
|
||||
|
||||
if (NOT "${PACKAGE_FILES}" MATCHES "\\.msi$")
|
||||
list(APPEND args /as)
|
||||
endif()
|
||||
foreach(file IN LISTS PACKAGE_FILES)
|
||||
set(local_args ${args})
|
||||
if (NOT "${file}" MATCHES "\\.msi$")
|
||||
list(APPEND local_args /as)
|
||||
endif()
|
||||
|
||||
set(cmd ${SIGNTOOL_COMMAND} ${args} ${PACKAGE_FILES})
|
||||
set(cmd ${SIGNTOOL_COMMAND} ${local_args} ${file})
|
||||
|
||||
list(JOIN cmd " " cmd_str)
|
||||
message(STATUS "${cmd_str}")
|
||||
list(JOIN cmd " " cmd_str)
|
||||
message(STATUS "${cmd_str}")
|
||||
|
||||
if (CERT_HAS_UI)
|
||||
execute_process(
|
||||
COMMAND cmd /c start "" /wait ${cmd}
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
if(NOT result EQUAL 0)
|
||||
message(FATAL_ERROR "signtool failed with code ${result}")
|
||||
endif()
|
||||
else()
|
||||
execute_process(
|
||||
execute_process(
|
||||
COMMAND ${cmd}
|
||||
RESULT_VARIABLE result
|
||||
ERROR_VARIABLE error
|
||||
)
|
||||
if(NOT result EQUAL 0)
|
||||
string(REPLACE "\n" "\n " error " ${error}")
|
||||
message(FATAL_ERROR "signtool failed:\n${error}")
|
||||
endif()
|
||||
endif()
|
||||
if(NOT result EQUAL 0)
|
||||
string(REPLACE "\n" "\n " error " ${error}")
|
||||
message(FATAL_ERROR "signtool failed:\n${error}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
+1
-5
@@ -10,8 +10,6 @@ if /i "%~1" == "-i" set "ARG_BUILD_INSTALLERS=!ARG_BUILD_INSTALLERS!
|
||||
if /i "%~1" == "--installer" set "ARG_BUILD_INSTALLERS=!ARG_BUILD_INSTALLERS! %~2" & shift
|
||||
if /i "%~1" == "-arch" set "ARCH=%~2" & shift
|
||||
if /i "%~1" == "--architecture" set "ARCH=%~2" & shift
|
||||
if /i "%~1" == "--sign-cloud" set "SIGNTOOL_SUBJECT_NAME=%~2" & shift
|
||||
if /i "%~1" == "--sign-phys" set "SIGNTOOL_SUBJECT_NAME=%~2" & set "SIGNTOOL_CERT_HAS_UI=true" & shift
|
||||
shift
|
||||
goto :parse_args
|
||||
:done_args
|
||||
@@ -96,10 +94,8 @@ if exist "%VCVARS_PATH%" (
|
||||
)
|
||||
|
||||
:: build project and installers
|
||||
set "_tests_arg="
|
||||
if defined AMNEZIA_BUILD_TESTS set "_tests_arg=-DAMNEZIA_BUILD_TESTS=%AMNEZIA_BUILD_TESTS%"
|
||||
@echo on
|
||||
cmake -S "%PROJECT_DIR%" -B "%BUILD_DIR%" -DCMAKE_BUILD_TYPE=Release "-DCMAKE_PREFIX_PATH=%QT_ROOT_PATH%\msvc2022_%_qt_postfix_arg%" "-DCMAKE_VS_GLOBALS=UseMultiToolTask=true;EnforceProcessCountAcrossBuilds=true" %_tests_arg% || goto :fail
|
||||
cmake -S "%PROJECT_DIR%" -B "%BUILD_DIR%" -DCMAKE_BUILD_TYPE=Release "-DCMAKE_PREFIX_PATH=%QT_ROOT_PATH%\msvc2022_%_qt_postfix_arg%" "-DCMAKE_VS_GLOBALS=UseMultiToolTask=true;EnforceProcessCountAcrossBuilds=true" || goto :fail
|
||||
cmake --build "%BUILD_DIR%" --config Release -- /m || goto :fail
|
||||
@echo off
|
||||
for %%I in (%ARG_BUILD_INSTALLERS%) do (
|
||||
|
||||
@@ -198,7 +198,6 @@ args=()
|
||||
[[ -n "$CMAKE_OSX_SYSROOT" ]] && args+=("-DCMAKE_OSX_SYSROOT=$CMAKE_OSX_SYSROOT")
|
||||
[[ -n "$MACOS_NE" ]] && args+=("-DMACOS_NE=$MACOS_NE")
|
||||
[[ -n "$DEPLOY" ]] && args+=("-DDEPLOY=$DEPLOY")
|
||||
[[ -n "$AMNEZIA_BUILD_TESTS" ]] && args+=("-DAMNEZIA_BUILD_TESTS=$AMNEZIA_BUILD_TESTS")
|
||||
[[ -n "$ANDROID_ABI" ]] && args+=("-DANDROID_ABI=$ANDROID_ABI")
|
||||
[[ -n "$ANDROID_SDK_ROOT" ]] && args+=("-DANDROID_SDK_ROOT=$ANDROID_SDK_ROOT")
|
||||
[[ -n "$ANDROID_NDK_ROOT" ]] && args+=("-DANDROID_NDK_ROOT=$ANDROID_NDK_ROOT")
|
||||
|
||||
@@ -111,9 +111,8 @@ class AmneziaXrayBindings(ConanFile):
|
||||
env.define("CGO_LDFLAGS", " ".join(ldflags))
|
||||
with env.vars(self).apply():
|
||||
at = Autotools(self)
|
||||
make_build_dir = build_dir.replace("\\", "/") if self._is_windows else build_dir
|
||||
at.make(args=[
|
||||
f"BUILD_DIR={make_build_dir}"
|
||||
f"BUILD_DIR={build_dir.replace("\\", "/") if self._is_windows else build_dir}"
|
||||
])
|
||||
|
||||
if is_apple_os(self) and self._is_multiarch:
|
||||
|
||||
@@ -60,9 +60,9 @@ class HevSocks5Tunnel(ConanFile):
|
||||
self.run(
|
||||
f"libtool -static -o {lib_path}"
|
||||
f" {lib_path}"
|
||||
f" {os.path.join(self.build_folder, 'third-part', 'lwip', 'bin', 'liblwip.a')}"
|
||||
f" {os.path.join(self.build_folder, 'third-part', 'yaml', 'bin', 'libyaml.a')}"
|
||||
f" {os.path.join(self.build_folder, 'third-part', 'hev-task-system', 'bin', 'libhev-task-system.a')}"
|
||||
f" {os.path.join(self.build_folder, "third-part", "lwip", "bin", "liblwip.a")}"
|
||||
f" {os.path.join(self.build_folder, "third-part", "yaml", "bin", "libyaml.a")}"
|
||||
f" {os.path.join(self.build_folder, "third-part", "hev-task-system", "bin", "libhev-task-system.a")}"
|
||||
)
|
||||
|
||||
include_dir = os.path.join(self.build_folder, "framework_include")
|
||||
|
||||
@@ -114,9 +114,8 @@ class Tun2Socks(ConanFile):
|
||||
env.define("CGO_CFLAGS", " ".join(cflags))
|
||||
with env.vars(self).apply():
|
||||
at = Autotools(self)
|
||||
make_build_dir = build_dir.replace("\\", "/") if self._is_windows else build_dir
|
||||
at.make("tun2socks", args=[
|
||||
f"BUILD_DIR={make_build_dir}"
|
||||
f"BUILD_DIR={build_dir.replace("\\", "/") if self._is_windows else build_dir}"
|
||||
])
|
||||
if self._is_windows:
|
||||
os.rename(
|
||||
|
||||
@@ -8,24 +8,23 @@
|
||||
# Apple Silicon have OpenGL emulation bugs that crash Qt apps.
|
||||
#
|
||||
# Prerequisites:
|
||||
# - QT_ROOT points to a Qt installation with desktop + Android kits (e.g. ~/Qt/6.10.1)
|
||||
# - ANDROID_HOME (or ANDROID_SDK_ROOT) points to an Android SDK with NDK $NDK_VERSION
|
||||
# - cmake, ninja, adb, python3 in PATH
|
||||
# - Qt for Android x86_64 (or arm64-v8a for devices) installed via Qt Maintenance Tool
|
||||
# - Android SDK + NDK available via Android Studio
|
||||
# - `adb devices` shows at least one device/emulator
|
||||
# - Conan 2 installed (pip install "conan==2.28.0")
|
||||
#
|
||||
# Usage (from the repository root):
|
||||
# bash client/tests/run_android_tests.sh # x86_64 emulator (default)
|
||||
# bash client/tests/run_android_tests.sh --abi arm64-v8a # physical ARM device
|
||||
# bash client/tests/run_android_tests.sh --test openssl # only openssl test
|
||||
# bash client/tests/run_android_tests.sh --test restore_backup # only restore-backup test
|
||||
# bash client/tests/run_android_tests.sh --wait-boot # wait for emulator to boot first
|
||||
# Usage:
|
||||
# bash run_android_tests.sh # x86_64 emulator (default)
|
||||
# bash run_android_tests.sh --abi arm64-v8a # physical ARM device
|
||||
# bash run_android_tests.sh --test openssl # only openssl test
|
||||
# bash run_android_tests.sh --test restore_backup # only restore-backup test
|
||||
# bash run_android_tests.sh --wait-boot # wait for emulator to boot first
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Configurable defaults ──────────────────────────────────────────────────────
|
||||
QT_ROOT="${QT_ROOT:?set QT_ROOT to your Qt installation, e.g. ~/Qt/6.10.1}"
|
||||
ANDROID_SDK="${ANDROID_HOME:-${ANDROID_SDK_ROOT:?set ANDROID_HOME to your Android SDK}}"
|
||||
QT_ROOT="${QT_ROOT:-/Users/nickpc/Qt/6.10.1}"
|
||||
ANDROID_SDK="${ANDROID_HOME:-/Users/nickpc/Library/Android/sdk}"
|
||||
NDK_VERSION="${NDK_VERSION:-27.3.13750724}"
|
||||
ANDROID_PLATFORM="${ANDROID_PLATFORM:-android-28}"
|
||||
# x86_64: recommended for emulators (HVF/Rosetta hardware acceleration works, no GL crashes)
|
||||
@@ -68,11 +67,7 @@ case "$ABI" in
|
||||
esac
|
||||
|
||||
QT_ANDROID="$QT_ROOT/$QT_ARCH_DIR"
|
||||
case "$(uname -s)" in
|
||||
Darwin) QT_HOST="$QT_ROOT/macos" ;;
|
||||
Linux) QT_HOST="$QT_ROOT/gcc_64" ;;
|
||||
*) echo "Unsupported host: $(uname -s)"; exit 1 ;;
|
||||
esac
|
||||
QT_HOST="$QT_ROOT/macos"
|
||||
NDK_PATH="$ANDROID_SDK/ndk/$NDK_VERSION"
|
||||
|
||||
echo "=== Android test runner (local) ==="
|
||||
@@ -101,32 +96,43 @@ echo ""
|
||||
|
||||
adb devices | grep -qE "device$|emulator" || {
|
||||
echo "ERROR: No Android device/emulator connected."
|
||||
echo " Run: bash client/tests/run_android_tests.sh --list-devices"
|
||||
echo " Then: bash client/tests/run_android_tests.sh --device <serial>"
|
||||
echo " Run: bash run_android_tests.sh --list-devices"
|
||||
echo " Then: bash run_android_tests.sh --device <serial>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
command -v cmake >/dev/null || { echo "ERROR: cmake not found in PATH"; exit 1; }
|
||||
command -v ninja >/dev/null || { echo "ERROR: ninja not found in PATH"; exit 1; }
|
||||
|
||||
# Detect the NDK host tag from what's present in the NDK
|
||||
# (Apple Silicon Macs have only darwin-x86_64 in NDK ≤27, not darwin-aarch64)
|
||||
NDK_HOST_TAG=""
|
||||
for candidate in darwin-x86_64 darwin-aarch64 linux-x86_64; do
|
||||
if [[ -d "$NDK_PATH/toolchains/llvm/prebuilt/$candidate" ]]; then
|
||||
NDK_HOST_TAG="$candidate"
|
||||
break
|
||||
# ── Locate cmake ──────────────────────────────────────────────────────────────
|
||||
if ! command -v cmake &>/dev/null; then
|
||||
QT_CMAKE="/Users/nickpc/Qt/Tools/CMake/CMake.app/Contents/bin"
|
||||
if [[ -x "$QT_CMAKE/cmake" ]]; then
|
||||
export PATH="$QT_CMAKE:$PATH"
|
||||
echo ">>> Using Qt-bundled cmake: $QT_CMAKE/cmake"
|
||||
else
|
||||
echo "ERROR: cmake not found. Install it or add it to PATH."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
[[ -n "$NDK_HOST_TAG" ]] || { echo "ERROR: Cannot detect NDK host tag in $NDK_PATH/toolchains/llvm/prebuilt/"; exit 1; }
|
||||
echo ">>> NDK host tag: $NDK_HOST_TAG"
|
||||
fi
|
||||
|
||||
# ── Locate ninja ──────────────────────────────────────────────────────────────
|
||||
if ! command -v ninja &>/dev/null; then
|
||||
QT_NINJA="/Users/nickpc/Qt/Tools/Ninja"
|
||||
if [[ -x "$QT_NINJA/ninja" ]]; then
|
||||
export PATH="$QT_NINJA:$PATH"
|
||||
echo ">>> Using Qt-bundled ninja: $QT_NINJA/ninja"
|
||||
else
|
||||
echo "ERROR: ninja not found. Install it (brew install ninja) or add it to PATH."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Add NDK toolchain to PATH (provides clang / clang++) ─────────────────────
|
||||
export PATH="$NDK_PATH/toolchains/llvm/prebuilt/$NDK_HOST_TAG/bin:$PATH"
|
||||
NDK_TOOLCHAIN="$NDK_PATH/toolchains/llvm/prebuilt/darwin-x86_64/bin"
|
||||
if [[ -d "$NDK_TOOLCHAIN" ]]; then
|
||||
export PATH="$NDK_TOOLCHAIN:$PATH"
|
||||
fi
|
||||
|
||||
# ── Required env vars for androiddeployqt ────────────────────────────────────
|
||||
export ANDROID_NDK_ROOT="$NDK_PATH"
|
||||
@@ -155,6 +161,18 @@ echo ">>> JAVA_HOME: $JAVA_HOME"
|
||||
QT_TOOLCHAIN="$QT_ANDROID/lib/cmake/Qt6/qt.toolchain.cmake"
|
||||
[[ -f "$QT_TOOLCHAIN" ]] || { echo "ERROR: Qt toolchain not found: $QT_TOOLCHAIN"; exit 1; }
|
||||
|
||||
# Detect the actual NDK host tag from what's present in the NDK
|
||||
# (Apple Silicon Macs have only darwin-x86_64 in NDK ≤27, not darwin-aarch64)
|
||||
NDK_HOST_TAG=""
|
||||
for candidate in darwin-x86_64 darwin-aarch64 linux-x86_64; do
|
||||
if [[ -d "$NDK_PATH/toolchains/llvm/prebuilt/$candidate" ]]; then
|
||||
NDK_HOST_TAG="$candidate"
|
||||
break
|
||||
fi
|
||||
done
|
||||
[[ -n "$NDK_HOST_TAG" ]] || { echo "ERROR: Cannot detect NDK host tag in $NDK_PATH/toolchains/llvm/prebuilt/"; exit 1; }
|
||||
echo ">>> NDK host tag: $NDK_HOST_TAG"
|
||||
|
||||
# ABI → sysroot triple mapping for libc++_shared.so
|
||||
case "$ABI" in
|
||||
arm64-v8a) SYSROOT_TRIPLE="aarch64-linux-android" ;;
|
||||
@@ -175,11 +193,10 @@ cmake -S . -B "$BUILD_DIR" -G Ninja \
|
||||
-DCMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG="$NDK_HOST_TAG" \
|
||||
-DQT_HOST_PATH="$QT_HOST" \
|
||||
-DQt6_DIR="$QT_ANDROID/lib/cmake/Qt6" \
|
||||
-DCMAKE_PREFIX_PATH="$QT_ANDROID" \
|
||||
-DAMNEZIA_BUILD_TESTS=ON
|
||||
-DCMAKE_PREFIX_PATH="$QT_ANDROID"
|
||||
|
||||
# Patch deployment settings JSONs: cmake may leave ndk-host empty on Apple Silicon
|
||||
for json_file in "$BUILD_DIR"/client/tests/android-*-deployment-settings.json; do
|
||||
for json_file in "$BUILD_DIR"/tests/android-*-deployment-settings.json; do
|
||||
[[ -f "$json_file" ]] || continue
|
||||
python3 - "$json_file" "$NDK_HOST_TAG" "$STD_CXX_PATH" <<'PYEOF'
|
||||
import sys, json
|
||||
@@ -204,7 +221,7 @@ ADB_BIN=$(which adb)
|
||||
|
||||
run_test() {
|
||||
local target="$1"
|
||||
local apk_dir="$BUILD_DIR/client/tests/android-build"
|
||||
local apk_dir="$BUILD_DIR/tests/android-build"
|
||||
local apk="$apk_dir/${target}.apk"
|
||||
local pkg_name="org.qtproject.example.${target}"
|
||||
local activity="${pkg_name}/org.qtproject.qt.android.bindings.QtActivity"
|
||||
Reference in new issue
Block a user