Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ff589f47c2 | |||
| c66d8ecca0 | |||
| db535f7e7d | |||
| 89f30d8c31 | |||
| 8bce432824 | |||
| f3539b2632 | |||
| 7a96c212f3 | |||
| 2d5dc54e0f | |||
| cef4c262e9 | |||
| 34309261a8 | |||
| 657eeb40c7 | |||
| b4938c2cc9 | |||
| 524fefc5cb | |||
| 73f13404bb | |||
| f0ca9772d3 | |||
| 5fc68cca83 | |||
| fcb7b8fa8d | |||
| a81e32ff95 | |||
| 23b530a0f8 | |||
| c897052107 | |||
| 4d0efc7ea5 | |||
| a77842c9e3 | |||
| 0ded9db780 | |||
| 58d480fcb5 | |||
| 7154428d26 | |||
| 02a52d0169 | |||
| ec60764072 | |||
| 17d2fa5532 | |||
| 3ca8b534e8 | |||
| e88f7c5e46 | |||
| 511b8fa6cc | |||
| 3ac5d7bd1f | |||
| 19cad00a00 | |||
| 1ea716a163 | |||
| 4551659c2a | |||
| c568bf8c24 | |||
| a412d91105 | |||
| ad01f23bbe | |||
| 656070b132 | |||
| c907f5ca36 | |||
| 94a13b2b54 | |||
| 169f11d9c7 | |||
| 816dc3af95 | |||
| b802863de5 | |||
| 8dc2a4b76c | |||
| beb1c6dbf2 | |||
| 3eb06916c7 | |||
| 30d0f84a4f | |||
| 251f2aa5db | |||
| 16d92ddb7c | |||
| e9d4fd8482 | |||
| 9fdcf5ab13 | |||
| a6e6de33c8 | |||
| 53c7fd4d81 | |||
| 2608ea4367 | |||
| d20ed4ad01 | |||
| eae2936449 | |||
| da8ad1f6ba | |||
| 5472347969 | |||
| a43f7a6926 | |||
| 47f917de0b | |||
| dbeb7edd7a | |||
| 6cede712f5 | |||
| d328739192 | |||
| d15c0bd962 | |||
| d53c794936 | |||
| e5dcb25a4a | |||
| f9002b4f43 | |||
| 0531508a75 | |||
| 174e85a20a | |||
| e9abb6f1e2 | |||
| 5be44f9596 | |||
| 90efaaff92 | |||
| 99b554e7c3 | |||
| ac0ce8a6f6 | |||
| 9f9da885b7 | |||
| f51fd2bf3e | |||
| c8378fd32d | |||
| d767214f10 | |||
| e027c504ae | |||
| 669a95d975 | |||
| a96df5d518 | |||
| c5c81735a0 | |||
| c933745707 | |||
| 6710fd18b3 | |||
| 1b78a71529 | |||
| 38082f9940 | |||
| 71691fa01e | |||
| 62d9bcaf7f | |||
| 5ef8254cba | |||
| f767171c06 | |||
| eff460b227 | |||
| 319043818a | |||
| e730521576 | |||
| 517930dd22 | |||
| 26994c21b1 | |||
| 681eb5aa86 | |||
| 4b86425992 | |||
| 9b41ed66bb | |||
| 8bb4fa3f35 | |||
| e792117be1 |
@@ -255,6 +255,20 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
|
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
|
||||||
QT_VERSION: 6.4.3
|
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_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
@@ -295,7 +309,7 @@ jobs:
|
|||||||
- name: 'Build project'
|
- name: 'Build project'
|
||||||
run: |
|
run: |
|
||||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
||||||
bash deploy/build_macos.sh
|
bash deploy/build_macos.sh -n
|
||||||
|
|
||||||
- name: 'Upload installer artifact'
|
- name: 'Upload installer artifact'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -318,6 +332,20 @@ jobs:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
QT_VERSION: 6.8.0
|
QT_VERSION: 6.8.0
|
||||||
|
|
||||||
|
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_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
@@ -330,7 +358,7 @@ jobs:
|
|||||||
- name: 'Setup xcode'
|
- name: 'Setup xcode'
|
||||||
uses: maxim-lobanov/setup-xcode@v1
|
uses: maxim-lobanov/setup-xcode@v1
|
||||||
with:
|
with:
|
||||||
xcode-version: '15.4.0'
|
xcode-version: '16.2.0'
|
||||||
|
|
||||||
- name: 'Install Qt'
|
- name: 'Install Qt'
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v3
|
||||||
@@ -358,7 +386,7 @@ jobs:
|
|||||||
- name: 'Build project'
|
- name: 'Build project'
|
||||||
run: |
|
run: |
|
||||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
||||||
bash deploy/build_macos.sh
|
bash deploy/build_macos.sh -n
|
||||||
|
|
||||||
- name: 'Upload installer artifact'
|
- name: 'Upload installer artifact'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -374,6 +402,67 @@ jobs:
|
|||||||
path: deploy/build/client/AmneziaVPN.app
|
path: deploy/build/client/AmneziaVPN.app
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
|
Build-MacOS-NE:
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
QT_VERSION: 6.8.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 }}
|
||||||
|
|
||||||
|
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: '16.2.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_ne.sh
|
||||||
|
|
||||||
|
- name: 'Upload unpacked artifact'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: AmneziaVPN_MacOS_unpacked
|
||||||
|
path: deploy/build/client/AmneziaVPN.app
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
# ------------------------------------------------------
|
# ------------------------------------------------------
|
||||||
|
|
||||||
Build-Android:
|
Build-Android:
|
||||||
|
|||||||
@@ -138,3 +138,4 @@ CMakeFiles/
|
|||||||
ios-ne-build.sh
|
ios-ne-build.sh
|
||||||
macos-ne-build.sh
|
macos-ne-build.sh
|
||||||
macos-signed-build.sh
|
macos-signed-build.sh
|
||||||
|
macos-with-sign-build.sh
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||||
|
|
||||||
set(PROJECT AmneziaVPN)
|
set(PROJECT AmneziaVPN)
|
||||||
|
set(AMNEZIAVPN_VERSION 4.8.11.0)
|
||||||
|
|
||||||
project(${PROJECT} VERSION 4.8.8.1
|
project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
|
||||||
DESCRIPTION "AmneziaVPN"
|
DESCRIPTION "AmneziaVPN"
|
||||||
HOMEPAGE_URL "https://amnezia.org/"
|
HOMEPAGE_URL "https://amnezia.org/"
|
||||||
)
|
)
|
||||||
@@ -11,7 +12,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
|||||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||||
|
|
||||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||||
set(APP_ANDROID_VERSION_CODE 2087)
|
set(APP_ANDROID_VERSION_CODE 2095)
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
set(MZ_PLATFORM_NAME "linux")
|
set(MZ_PLATFORM_NAME "linux")
|
||||||
@@ -31,13 +32,19 @@ set(QT_BUILD_TOOLS_WHEN_CROSS_COMPILING ON)
|
|||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
if(APPLE AND NOT IOS)
|
if(APPLE)
|
||||||
set(CMAKE_OSX_ARCHITECTURES "x86_64")
|
if(IOS)
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES "arm64")
|
||||||
|
elseif(MACOS_NE)
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
|
||||||
|
else()
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES "x86_64")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(client)
|
add_subdirectory(client)
|
||||||
|
|
||||||
if(NOT IOS AND NOT ANDROID)
|
if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||||
add_subdirectory(service)
|
add_subdirectory(service)
|
||||||
|
|
||||||
include(${CMAKE_SOURCE_DIR}/deploy/installer/config.cmake)
|
include(${CMAKE_SOURCE_DIR}/deploy/installer/config.cmake)
|
||||||
|
|||||||
@@ -9,17 +9,17 @@
|
|||||||
### [English]([https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md](https://github.com/amnezia-vpn/amnezia-client/tree/dev?tab=readme-ov-file#)) | [Русский](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md)
|
### [English]([https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md](https://github.com/amnezia-vpn/amnezia-client/tree/dev?tab=readme-ov-file#)) | [Русский](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md)
|
||||||
|
|
||||||
|
|
||||||
[Amnezia](https://amnezia.org) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
|
[Amnezia](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
|
||||||
|
|
||||||
[](https://amnezia.org)
|
[](https://amnezia.org)
|
||||||
|
|
||||||
### [Website](https://amnezia.org) | [Alt website link](https://storage.googleapis.com/amnezia/amnezia.org) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
|
### [Website](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) | [Alt website link](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en-mirror) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> If the [Amnezia website](https://amnezia.org) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/amnezia/amnezia.org ).
|
> If the [Amnezia website](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en-mirror).
|
||||||
|
|
||||||
<a href="https://amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
|
<a href="https://amnezia.org/en/downloads?utm_source=github&utm_campaign=amnezia_button-readme-en"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
|
||||||
<a href="https://storage.googleapis.com/amnezia/q9p19109"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-alt.svg" width="150" style="max-width: 100%;"></a>
|
<a href="https://storage.googleapis.com/amnezia/amnezia.org?m-path=/en/downloads&utm_source=github&utm_campaign=amnezia_button-readme-en-mirrow"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-alt.svg" width="150" style="max-width: 100%;"></a>
|
||||||
|
|
||||||
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
|
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
|
||||||
|
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
|
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
|
||||||
|
|
||||||
### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский
|
### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский
|
||||||
[AmneziaVPN](https://amnezia.org) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
|
[AmneziaVPN](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
|
||||||
|
|
||||||
[](https://amnezia.org)
|
[](https://amnezia.org)
|
||||||
|
|
||||||
### [Сайт](https://amnezia.org) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
|
### [Сайт](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru-mirror) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> Если [сайт Amnezia](https://amnezia.org) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org).
|
> Если [сайт Amnezia](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru-mirror).
|
||||||
|
|
||||||
<a href="https://storage.googleapis.com/amnezia/q9p19109"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website-ru.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
|
<a href="https://storage.googleapis.com/amnezia/amnezia.org?m-path=/ru/downloads&utm_source=github&utm_campaign=amnezia_button-readme-ru-mirror"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website-ru.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
|
||||||
|
|
||||||
|
|
||||||
[Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases)
|
[Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
|||||||
set(PROJECT AmneziaVPN)
|
set(PROJECT AmneziaVPN)
|
||||||
project(${PROJECT})
|
project(${PROJECT})
|
||||||
|
|
||||||
|
|
||||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER "Autogen")
|
set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER "Autogen")
|
||||||
set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Autogen")
|
set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Autogen")
|
||||||
@@ -53,6 +52,9 @@ endif()
|
|||||||
|
|
||||||
qt_standard_project_setup()
|
qt_standard_project_setup()
|
||||||
qt_add_executable(${PROJECT} MANUAL_FINALIZATION)
|
qt_add_executable(${PROJECT} MANUAL_FINALIZATION)
|
||||||
|
target_include_directories(${PROJECT} PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||||
|
)
|
||||||
|
|
||||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
if(WIN32 OR (APPLE AND NOT IOS) 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_interface.rep)
|
||||||
@@ -110,6 +112,15 @@ include_directories(
|
|||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(MACOS_NE)
|
||||||
|
message("MACOS_NE is ON")
|
||||||
|
add_definitions(-DQ_OS_MAC)
|
||||||
|
add_definitions(-DMACOS_NE)
|
||||||
|
message("Add macros for MacOS Network Extension")
|
||||||
|
else()
|
||||||
|
message("MACOS_NE is OFF")
|
||||||
|
endif()
|
||||||
|
|
||||||
include_directories(mozilla)
|
include_directories(mozilla)
|
||||||
include_directories(mozilla/shared)
|
include_directories(mozilla/shared)
|
||||||
include_directories(mozilla/models)
|
include_directories(mozilla/models)
|
||||||
@@ -139,7 +150,7 @@ if(WIN32)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
cmake_policy(SET CMP0099 OLD)
|
cmake_policy(SET CMP0099 NEW)
|
||||||
cmake_policy(SET CMP0114 NEW)
|
cmake_policy(SET CMP0114 NEW)
|
||||||
|
|
||||||
if(NOT BUILD_OSX_APP_IDENTIFIER)
|
if(NOT BUILD_OSX_APP_IDENTIFIER)
|
||||||
@@ -158,7 +169,6 @@ if(APPLE)
|
|||||||
set(CMAKE_XCODE_GENERATE_SCHEME FALSE)
|
set(CMAKE_XCODE_GENERATE_SCHEME FALSE)
|
||||||
set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${BUILD_VPN_DEVELOPMENT_TEAM})
|
set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${BUILD_VPN_DEVELOPMENT_TEAM})
|
||||||
set(CMAKE_XCODE_ATTRIBUTE_GROUP_ID_IOS ${BUILD_IOS_GROUP_IDENTIFIER})
|
set(CMAKE_XCODE_ATTRIBUTE_GROUP_ID_IOS ${BUILD_IOS_GROUP_IDENTIFIER})
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(LINUX AND NOT ANDROID)
|
if(LINUX AND NOT ANDROID)
|
||||||
@@ -166,8 +176,7 @@ if(LINUX AND NOT ANDROID)
|
|||||||
link_directories(${CMAKE_CURRENT_LIST_DIR}/platforms/linux)
|
link_directories(${CMAKE_CURRENT_LIST_DIR}/platforms/linux)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32 OR (APPLE AND NOT IOS) 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)
|
add_compile_definitions(AMNEZIA_DESKTOP)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -178,7 +187,9 @@ endif()
|
|||||||
if(IOS)
|
if(IOS)
|
||||||
include(cmake/ios.cmake)
|
include(cmake/ios.cmake)
|
||||||
include(cmake/ios-arch-fixup.cmake)
|
include(cmake/ios-arch-fixup.cmake)
|
||||||
elseif(APPLE AND NOT IOS)
|
elseif(APPLE AND MACOS_NE)
|
||||||
|
include(cmake/macos_ne.cmake)
|
||||||
|
elseif(APPLE)
|
||||||
include(cmake/osxtools.cmake)
|
include(cmake/osxtools.cmake)
|
||||||
include(cmake/macos.cmake)
|
include(cmake/macos.cmake)
|
||||||
endif()
|
endif()
|
||||||
@@ -199,7 +210,7 @@ elseif(APPLE AND NOT IOS)
|
|||||||
set(DEPLOY_PLATFORM_PATH "macos")
|
set(DEPLOY_PLATFORM_PATH "macos")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT IOS AND NOT ANDROID)
|
if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET ${PROJECT} POST_BUILD
|
TARGET ${PROJECT} POST_BUILD
|
||||||
COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:Debug>,copy_directory,true>
|
COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:Debug>,copy_directory,true>
|
||||||
@@ -214,7 +225,6 @@ if(NOT IOS AND NOT ANDROID)
|
|||||||
$<TARGET_FILE_DIR:${PROJECT}>
|
$<TARGET_FILE_DIR:${PROJECT}>
|
||||||
COMMAND_EXPAND_LISTS
|
COMMAND_EXPAND_LISTS
|
||||||
)
|
)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
|
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
#include <QEvent>
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "ui/controllers/pageController.h"
|
#include "ui/controllers/pageController.h"
|
||||||
@@ -21,8 +22,12 @@
|
|||||||
#include "platforms/ios/QRCodeReaderBase.h"
|
#include "platforms/ios/QRCodeReaderBase.h"
|
||||||
|
|
||||||
#include "protocols/qml_register_protocols.h"
|
#include "protocols/qml_register_protocols.h"
|
||||||
|
#include <QtQuick/QQuickWindow> // for QQuickWindow
|
||||||
|
#include <QWindow> // for qobject_cast<QWindow*>
|
||||||
|
|
||||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv)
|
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv),
|
||||||
|
m_optAutostart({QStringLiteral("a"), QStringLiteral("autostart")}, QStringLiteral("System autostart")),
|
||||||
|
m_optCleanup ({QStringLiteral("c"), QStringLiteral("cleanup")}, QStringLiteral("Cleanup logs"))
|
||||||
{
|
{
|
||||||
setQuitOnLastWindowClosed(false);
|
setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
@@ -49,7 +54,6 @@ AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_C
|
|||||||
AmneziaApplication::~AmneziaApplication()
|
AmneziaApplication::~AmneziaApplication()
|
||||||
{
|
{
|
||||||
m_vpnConnectionThread.quit();
|
m_vpnConnectionThread.quit();
|
||||||
m_vpnConnectionThread.wait(3000);
|
|
||||||
|
|
||||||
if (m_engine) {
|
if (m_engine) {
|
||||||
QObject::disconnect(m_engine, 0, 0, 0);
|
QObject::disconnect(m_engine, 0, 0, 0);
|
||||||
@@ -63,15 +67,28 @@ void AmneziaApplication::init()
|
|||||||
|
|
||||||
const QUrl url(QStringLiteral("qrc:/ui/qml/main2.qml"));
|
const QUrl url(QStringLiteral("qrc:/ui/qml/main2.qml"));
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
m_engine, &QQmlApplicationEngine::objectCreated, this,
|
m_engine, &QQmlApplicationEngine::objectCreated, this,
|
||||||
[url](QObject *obj, const QUrl &objUrl) {
|
[this, url](QObject *obj, const QUrl &objUrl) {
|
||||||
if (!obj && url == objUrl)
|
if (!obj && url == objUrl) {
|
||||||
QCoreApplication::exit(-1);
|
QCoreApplication::exit(-1);
|
||||||
},
|
return;
|
||||||
Qt::QueuedConnection);
|
}
|
||||||
|
// install filter on main window
|
||||||
|
if (auto win = qobject_cast<QQuickWindow*>(obj)) {
|
||||||
|
win->installEventFilter(this);
|
||||||
|
win->show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance());
|
m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance());
|
||||||
|
|
||||||
|
#ifdef MACOS_NE
|
||||||
|
m_engine->rootContext()->setContextProperty("IsMacOsNeBuild", true);
|
||||||
|
#else
|
||||||
|
m_engine->rootContext()->setContextProperty("IsMacOsNeBuild", false);
|
||||||
|
#endif
|
||||||
|
|
||||||
m_vpnConnection.reset(new VpnConnection(m_settings));
|
m_vpnConnection.reset(new VpnConnection(m_settings));
|
||||||
m_vpnConnection->moveToThread(&m_vpnConnectionThread);
|
m_vpnConnection->moveToThread(&m_vpnConnectionThread);
|
||||||
m_vpnConnectionThread.start();
|
m_vpnConnectionThread.start();
|
||||||
@@ -94,7 +111,7 @@ void AmneziaApplication::init()
|
|||||||
Logger::setServiceLogsEnabled(enabled);
|
Logger::setServiceLogsEnabled(enabled);
|
||||||
|
|
||||||
#ifdef Q_OS_WIN //TODO
|
#ifdef Q_OS_WIN //TODO
|
||||||
if (m_parser.isSet("a"))
|
if (m_parser.isSet(m_optAutostart))
|
||||||
m_coreController->pageController()->showOnStartup();
|
m_coreController->pageController()->showOnStartup();
|
||||||
else
|
else
|
||||||
emit m_coreController->pageController()->raiseMainWindow();
|
emit m_coreController->pageController()->raiseMainWindow();
|
||||||
@@ -162,15 +179,12 @@ bool AmneziaApplication::parseCommands()
|
|||||||
m_parser.addHelpOption();
|
m_parser.addHelpOption();
|
||||||
m_parser.addVersionOption();
|
m_parser.addVersionOption();
|
||||||
|
|
||||||
QCommandLineOption c_autostart { { "a", "autostart" }, "System autostart" };
|
m_parser.addOption(m_optAutostart);
|
||||||
m_parser.addOption(c_autostart);
|
m_parser.addOption(m_optCleanup);
|
||||||
|
|
||||||
QCommandLineOption c_cleanup { { "c", "cleanup" }, "Cleanup logs" };
|
|
||||||
m_parser.addOption(c_cleanup);
|
|
||||||
|
|
||||||
m_parser.process(*this);
|
m_parser.process(*this);
|
||||||
|
|
||||||
if (m_parser.isSet(c_cleanup)) {
|
if (m_parser.isSet(m_optCleanup)) {
|
||||||
Logger::cleanUp();
|
Logger::cleanUp();
|
||||||
QTimer::singleShot(100, this, [this] { quit(); });
|
QTimer::singleShot(100, this, [this] { quit(); });
|
||||||
exec();
|
exec();
|
||||||
@@ -179,9 +193,8 @@ bool AmneziaApplication::parseCommands()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||||
void AmneziaApplication::startLocalServer()
|
void AmneziaApplication::startLocalServer() {
|
||||||
{
|
|
||||||
const QString serverName("AmneziaVPNInstance");
|
const QString serverName("AmneziaVPNInstance");
|
||||||
QLocalServer::removeServer(serverName);
|
QLocalServer::removeServer(serverName);
|
||||||
|
|
||||||
@@ -198,6 +211,22 @@ void AmneziaApplication::startLocalServer()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool AmneziaApplication::eventFilter(QObject *watched, QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::Close) {
|
||||||
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
|
quit();
|
||||||
|
#else
|
||||||
|
if (m_coreController && m_coreController->pageController()) {
|
||||||
|
m_coreController->pageController()->hideMainWindow();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true; // eat the close
|
||||||
|
}
|
||||||
|
// call base QObject::eventFilter
|
||||||
|
return QObject::eventFilter(watched, event);
|
||||||
|
}
|
||||||
|
|
||||||
QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
|
QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
|
||||||
{
|
{
|
||||||
return m_engine;
|
return m_engine;
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#else
|
#else
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#endif
|
#endif
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
|
|
||||||
@@ -20,9 +20,9 @@
|
|||||||
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
|
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
#define AMNEZIA_BASE_CLASS QGuiApplication
|
#define AMNEZIA_BASE_CLASS QGuiApplication
|
||||||
#else
|
#else
|
||||||
#define AMNEZIA_BASE_CLASS QApplication
|
#define AMNEZIA_BASE_CLASS QApplication
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class AmneziaApplication : public AMNEZIA_BASE_CLASS
|
class AmneziaApplication : public AMNEZIA_BASE_CLASS
|
||||||
@@ -37,7 +37,7 @@ public:
|
|||||||
void loadFonts();
|
void loadFonts();
|
||||||
bool parseCommands();
|
bool parseCommands();
|
||||||
|
|
||||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||||
void startLocalServer();
|
void startLocalServer();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -56,10 +56,15 @@ private:
|
|||||||
|
|
||||||
QCommandLineParser m_parser;
|
QCommandLineParser m_parser;
|
||||||
|
|
||||||
|
QCommandLineOption m_optAutostart;
|
||||||
|
QCommandLineOption m_optCleanup;
|
||||||
|
|
||||||
QSharedPointer<VpnConnection> m_vpnConnection;
|
QSharedPointer<VpnConnection> m_vpnConnection;
|
||||||
QThread m_vpnConnectionThread;
|
QThread m_vpnConnectionThread;
|
||||||
|
|
||||||
QNetworkAccessManager *m_nam;
|
QNetworkAccessManager *m_nam;
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AMNEZIA_APPLICATION_H
|
#endif // AMNEZIA_APPLICATION_H
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import java.nio.channels.FileChannel
|
|||||||
import java.nio.channels.FileLock
|
import java.nio.channels.FileLock
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
import java.time.ZoneOffset
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import org.amnezia.vpn.util.Log.Priority.D
|
import org.amnezia.vpn.util.Log.Priority.D
|
||||||
import org.amnezia.vpn.util.Log.Priority.E
|
import org.amnezia.vpn.util.Log.Priority.E
|
||||||
@@ -135,8 +137,8 @@ object Log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun formatLogMsg(tag: String, msg: String, priority: Priority): String {
|
private fun formatLogMsg(tag: String, msg: String, priority: Priority): String {
|
||||||
val date = LocalDateTime.now().format(dateTimeFormat)
|
val utcDate = ZonedDateTime.now(ZoneOffset.UTC).format(dateTimeFormat)
|
||||||
return "$date ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
|
return "${utcDate}Z ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
|
||||||
"$tag: $msg\n"
|
"$tag: $msg\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,15 @@ if(WIN32)
|
|||||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib")
|
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib")
|
||||||
endif()
|
endif()
|
||||||
elseif(APPLE AND NOT IOS)
|
elseif(APPLE AND NOT IOS)
|
||||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libssh.a")
|
if(MACOS_NE)
|
||||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libz.a")
|
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/universal2/libssh.a")
|
||||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/x86_64")
|
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_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/macos/include")
|
||||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libssl.a")
|
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libssl.a")
|
||||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libcrypto.a")
|
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libcrypto.a")
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ set(SOURCES ${SOURCES}
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/AmneziaSceneDelegateHooks.mm
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,15 @@ set(LIBS ${LIBS}
|
|||||||
${FW_SECURITY}
|
${FW_SECURITY}
|
||||||
${FW_COREWLAN}
|
${FW_COREWLAN}
|
||||||
${FW_NETWORK}
|
${FW_NETWORK}
|
||||||
${FW_USERNOTIFICATIONS}
|
${FW_USER_NOTIFICATIONS}
|
||||||
${FW_NETWORK_EXTENSION}
|
${FW_NETWORK_EXTENSION}
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(${PROJECT} PROPERTIES MACOSX_BUNDLE TRUE)
|
set_target_properties(${PROJECT} PROPERTIES
|
||||||
|
MACOSX_BUNDLE TRUE
|
||||||
|
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_ARCHITECTURES "x86_64" CACHE INTERNAL "" FORCE)
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
||||||
|
|
||||||
@@ -31,6 +35,8 @@ set(SOURCES ${SOURCES}
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/macos_util.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/ui/macos_util.mm
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
set(ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/app.icns)
|
set(ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/app.icns)
|
||||||
set(MACOSX_BUNDLE_ICON_FILE app.icns)
|
set(MACOSX_BUNDLE_ICON_FILE app.icns)
|
||||||
set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||||
@@ -49,4 +55,3 @@ execute_process(
|
|||||||
)
|
)
|
||||||
message("OSX_SDK_PATH is: ${OSX_SDK_PATH}")
|
message("OSX_SDK_PATH is: ${OSX_SDK_PATH}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
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})
|
||||||
|
|
||||||
|
enable_language(OBJC)
|
||||||
|
enable_language(Swift)
|
||||||
|
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS ShaderTools Widgets)
|
||||||
|
# Link Qt Widgets for QWidget, QMenu, QAction etc.
|
||||||
|
set(LIBS ${LIBS} Qt6::ShaderTools Qt6::Widgets)
|
||||||
|
|
||||||
|
find_library(FW_AUTHENTICATIONSERVICES AuthenticationServices)
|
||||||
|
find_library(FW_AVFOUNDATION AVFoundation)
|
||||||
|
find_library(FW_FOUNDATION Foundation)
|
||||||
|
find_library(FW_STOREKIT StoreKit)
|
||||||
|
find_library(FW_SERVICEMGMT ServiceManagement)
|
||||||
|
find_library(FW_USERNOTIFICATIONS UserNotifications)
|
||||||
|
find_library(FW_NETWORKEXTENSION NetworkExtension)
|
||||||
|
|
||||||
|
set(LIBS ${LIBS}
|
||||||
|
${FW_AUTHENTICATIONSERVICES}
|
||||||
|
${FW_AVFOUNDATION}
|
||||||
|
${FW_FOUNDATION}
|
||||||
|
${FW_STOREKIT}
|
||||||
|
${FW_SERVICEMGMT}
|
||||||
|
${FW_USERNOTIFICATIONS}
|
||||||
|
${FW_NETWORKEXTENSION}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
set(HEADERS ${HEADERS}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller_wrapper.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate-C-Interface.h
|
||||||
|
)
|
||||||
|
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h PROPERTIES OBJECTIVE_CPP_HEADER TRUE)
|
||||||
|
|
||||||
|
|
||||||
|
set(SOURCES ${SOURCES}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.mm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller_wrapper.mm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.mm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
|
||||||
|
)
|
||||||
|
|
||||||
|
set(ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/app.icns)
|
||||||
|
set(MACOSX_BUNDLE_ICON_FILE app.icns)
|
||||||
|
set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
set(SOURCES ${SOURCES} ${ICON_FILE})
|
||||||
|
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT} PRIVATE
|
||||||
|
${Qt6Gui_PRIVATE_INCLUDE_DIRS}
|
||||||
|
${Qt6Widgets_PRIVATE_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
set_target_properties(${PROJECT} PROPERTIES
|
||||||
|
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Info.plist.in
|
||||||
|
MACOSX_BUNDLE_ICON_FILE "AppIcon"
|
||||||
|
MACOSX_BUNDLE_INFO_STRING "AmneziaVPN"
|
||||||
|
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPN"
|
||||||
|
MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
|
||||||
|
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}/macos/app/app.entitlements"
|
||||||
|
XCODE_ATTRIBUTE_MARKETING_VERSION "${APPLE_PROJECT_VERSION}"
|
||||||
|
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
|
||||||
|
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPN"
|
||||||
|
XCODE_ATTRIBUTE_BUNDLE_INFO_STRING "AmneziaVPN"
|
||||||
|
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 "NO"
|
||||||
|
XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY "YES"
|
||||||
|
XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "11.0"
|
||||||
|
|
||||||
|
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
|
||||||
|
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks"
|
||||||
|
XCODE_EMBED_APP_EXTENSIONS AmneziaVPNNetworkExtension
|
||||||
|
)
|
||||||
|
|
||||||
|
if(DEPLOY)
|
||||||
|
set_target_properties(${PROJECT} PROPERTIES
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution"
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development"
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual
|
||||||
|
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr macos.org.amnezia.AmneziaVPN"
|
||||||
|
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev macos.org.amnezia.AmneziaVPN"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
set_target_properties(${PROJECT} PROPERTIES
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(${PROJECT} PROPERTIES
|
||||||
|
XCODE_ATTRIBUTE_SWIFT_VERSION "5.0"
|
||||||
|
XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES"
|
||||||
|
XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO"
|
||||||
|
XCODE_ATTRIBUTE_SWIFT_OBJC_INTERFACE_HEADER_NAME "AmneziaVPN-Swift.h"
|
||||||
|
XCODE_ATTRIBUTE_SWIFT_OBJC_INTEROP_MODE "objcxx"
|
||||||
|
)
|
||||||
|
set_target_properties(${PROJECT} PROPERTIES
|
||||||
|
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK"
|
||||||
|
)
|
||||||
|
target_include_directories(${PROJECT} PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
target_compile_options(${PROJECT} PRIVATE
|
||||||
|
-DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\"
|
||||||
|
-DVPN_NE_BUNDLEID=\"${BUILD_IOS_APP_IDENTIFIER}.network-extension\"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/amneziawg-apple/Sources)
|
||||||
|
|
||||||
|
target_sources(${PROJECT} PRIVATE
|
||||||
|
${WG_APPLE_SOURCE_DIR}/WireGuardKitC/x25519.c
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/ios/LogController.swift
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/ios/Log.swift
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/ios/ScreenProtection.swift
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/ios/VPNCController.swift
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(${PROJECT} PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Images.xcassets
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(TARGET ${PROJECT} APPEND PROPERTY RESOURCE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Images.xcassets
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(macos/networkextension)
|
||||||
|
add_dependencies(${PROJECT} AmneziaVPNNetworkExtension)
|
||||||
|
|
||||||
|
get_target_property(QtCore_location Qt6::Core LOCATION)
|
||||||
|
message("QtCore_location")
|
||||||
|
message(${QtCore_location})
|
||||||
|
|
||||||
|
get_filename_component(QT_BIN_DIR_DETECTED "${QtCore_location}/../../../../../bin" ABSOLUTE)
|
||||||
|
|
||||||
|
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"
|
||||||
|
"$<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"
|
||||||
|
)
|
||||||
@@ -36,10 +36,9 @@ set(HEADERS ${HEADERS}
|
|||||||
${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.h
|
${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.h
|
||||||
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.h
|
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.h
|
||||||
${CLIENT_ROOT_DIR}/mozilla/controllerimpl.h
|
${CLIENT_ROOT_DIR}/mozilla/controllerimpl.h
|
||||||
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT IOS)
|
if(NOT IOS AND NOT MACOS_NE)
|
||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.h
|
${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.h
|
||||||
)
|
)
|
||||||
@@ -86,15 +85,28 @@ set(SOURCES ${SOURCES}
|
|||||||
${CLIENT_ROOT_DIR}/mozilla/models/server.cpp
|
${CLIENT_ROOT_DIR}/mozilla/models/server.cpp
|
||||||
${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.cpp
|
${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.cpp
|
||||||
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.cpp
|
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.cpp
|
||||||
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT IOS)
|
if(NOT IOS AND NOT MACOS_NE)
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.cpp
|
${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Include native macOS platform helpers (dock/status-item)
|
||||||
|
if(APPLE AND NOT IOS)
|
||||||
|
list(APPEND HEADERS
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/macos/macosutils.h
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/macos/macosstatusicon.h
|
||||||
|
${CLIENT_ROOT_DIR}/ui/macos_util.h
|
||||||
|
)
|
||||||
|
list(APPEND SOURCES
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/macos/macosutils.mm
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/macos/macosstatusicon.mm
|
||||||
|
${CLIENT_ROOT_DIR}/ui/macos_util.mm
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT ANDROID)
|
if(NOT ANDROID)
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CLIENT_ROOT_DIR}/ui/notificationhandler.cpp
|
${CLIENT_ROOT_DIR}/ui/notificationhandler.cpp
|
||||||
@@ -175,11 +187,13 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
|||||||
${CLIENT_ROOT_DIR}/protocols/wireguardprotocol.h
|
${CLIENT_ROOT_DIR}/protocols/wireguardprotocol.h
|
||||||
${CLIENT_ROOT_DIR}/protocols/xrayprotocol.h
|
${CLIENT_ROOT_DIR}/protocols/xrayprotocol.h
|
||||||
${CLIENT_ROOT_DIR}/protocols/awgprotocol.h
|
${CLIENT_ROOT_DIR}/protocols/awgprotocol.h
|
||||||
|
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CLIENT_ROOT_DIR}/core/ipcclient.cpp
|
${CLIENT_ROOT_DIR}/core/ipcclient.cpp
|
||||||
${CLIENT_ROOT_DIR}/core/privileged_process.cpp
|
${CLIENT_ROOT_DIR}/core/privileged_process.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
|
||||||
${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.cpp
|
${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.cpp
|
||||||
${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.cpp
|
${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.cpp
|
||||||
${CLIENT_ROOT_DIR}/protocols/openvpnovercloakprotocol.cpp
|
${CLIENT_ROOT_DIR}/protocols/openvpnovercloakprotocol.cpp
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPair<QString,
|
|||||||
|
|
||||||
// no redirect-gateway
|
// no redirect-gateway
|
||||||
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
|
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
|
||||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||||
config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
|
config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
|
||||||
// Prevent ipv6 leak
|
// Prevent ipv6 leak
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <qtimer.h>
|
#include <qtimer.h>
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#else
|
#else
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -24,7 +24,7 @@ SshConfigurator::SshConfigurator(std::shared_ptr<Settings> settings, const QShar
|
|||||||
|
|
||||||
QString SshConfigurator::convertOpenSShKey(const QString &key)
|
QString SshConfigurator::convertOpenSShKey(const QString &key)
|
||||||
{
|
{
|
||||||
#ifndef Q_OS_IOS
|
#if !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||||
QProcess p;
|
QProcess p;
|
||||||
p.setProcessChannelMode(QProcess::MergedChannels);
|
p.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
|
||||||
@@ -67,9 +67,10 @@ QString SshConfigurator::convertOpenSShKey(const QString &key)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEAD CODE.
|
||||||
void SshConfigurator::openSshTerminal(const ServerCredentials &credentials)
|
void SshConfigurator::openSshTerminal(const ServerCredentials &credentials)
|
||||||
{
|
{
|
||||||
#ifndef Q_OS_IOS
|
#if !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||||
QProcess *p = new QProcess();
|
QProcess *p = new QProcess();
|
||||||
p->setProcessChannelMode(QProcess::SeparateChannels);
|
p->setProcessChannelMode(QProcess::SeparateChannels);
|
||||||
|
|
||||||
@@ -101,7 +102,7 @@ QProcessEnvironment SshConfigurator::prepareEnv()
|
|||||||
pathEnvVar.clear();
|
pathEnvVar.clear();
|
||||||
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\cygwin;");
|
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\cygwin;");
|
||||||
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn;");
|
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn;");
|
||||||
#elif defined(Q_OS_MACX)
|
#elif defined(Q_OS_MACX) && !defined(MACOS_NE)
|
||||||
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS");
|
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -261,6 +261,7 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
#elif defined(Q_OS_IOS)
|
#elif defined(Q_OS_IOS)
|
||||||
|
// Standard iOS build (without Network Extension limitations)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case DockerContainer::WireGuard: return true;
|
case DockerContainer::WireGuard: return true;
|
||||||
case DockerContainer::OpenVpn: return true;
|
case DockerContainer::OpenVpn: return true;
|
||||||
@@ -269,7 +270,23 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
|||||||
case DockerContainer::Cloak: return true;
|
case DockerContainer::Cloak: return true;
|
||||||
case DockerContainer::SSXray: return true;
|
case DockerContainer::SSXray: return true;
|
||||||
// case DockerContainer::ShadowSocks: return true;
|
// case DockerContainer::ShadowSocks: return true;
|
||||||
default: return false;
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(MACOS_NE)
|
||||||
|
// macOS build using Network Extension – hide OpenVPN-based containers
|
||||||
|
switch (c) {
|
||||||
|
case DockerContainer::WireGuard: return true;
|
||||||
|
case DockerContainer::Awg: return true;
|
||||||
|
case DockerContainer::Xray: return true;
|
||||||
|
case DockerContainer::SSXray: return true;
|
||||||
|
case DockerContainer::OpenVpn:
|
||||||
|
case DockerContainer::Cloak:
|
||||||
|
case DockerContainer::ShadowSocks:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#elif defined(Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace
|
|||||||
|
|
||||||
bool apiUtils::isSubscriptionExpired(const QString &subscriptionEndDate)
|
bool apiUtils::isSubscriptionExpired(const QString &subscriptionEndDate)
|
||||||
{
|
{
|
||||||
QDateTime now = QDateTime::currentDateTime();
|
QDateTime now = QDateTime::currentDateTimeUtc();
|
||||||
QDateTime endDate = QDateTime::fromString(subscriptionEndDate, Qt::ISODateWithMs);
|
QDateTime endDate = QDateTime::fromString(subscriptionEndDate, Qt::ISODateWithMs);
|
||||||
return endDate < now;
|
return endDate < now;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,8 @@ CoreController::CoreController(const QSharedPointer<VpnConnection> &vpnConnectio
|
|||||||
|
|
||||||
initNotificationHandler();
|
initNotificationHandler();
|
||||||
|
|
||||||
auto locale = m_settings->getAppLanguage();
|
|
||||||
m_translator.reset(new QTranslator());
|
m_translator.reset(new QTranslator());
|
||||||
updateTranslator(locale);
|
updateTranslator(m_settings->getAppLanguage());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreController::initModels()
|
void CoreController::initModels()
|
||||||
@@ -120,6 +119,9 @@ void CoreController::initControllers()
|
|||||||
connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(),
|
connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(),
|
||||||
&ConnectionController::onCurrentContainerUpdated); // TODO remove this
|
&ConnectionController::onCurrentContainerUpdated); // TODO remove this
|
||||||
|
|
||||||
|
connect(m_installController.get(), &InstallController::profileCleared,
|
||||||
|
m_protocolsModel.get(), &ProtocolsModel::updateModel);
|
||||||
|
|
||||||
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
|
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
|
||||||
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
|
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
|
||||||
|
|
||||||
@@ -230,7 +232,7 @@ void CoreController::initSignalHandlers()
|
|||||||
|
|
||||||
void CoreController::initNotificationHandler()
|
void CoreController::initNotificationHandler()
|
||||||
{
|
{
|
||||||
#ifndef Q_OS_ANDROID
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||||
m_notificationHandler.reset(NotificationHandler::create(nullptr));
|
m_notificationHandler.reset(NotificationHandler::create(nullptr));
|
||||||
|
|
||||||
connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(),
|
connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(),
|
||||||
@@ -242,7 +244,10 @@ void CoreController::initNotificationHandler()
|
|||||||
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
|
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
|
||||||
&ConnectionController::closeConnection);
|
&ConnectionController::closeConnection);
|
||||||
connect(this, &CoreController::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated);
|
connect(this, &CoreController::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated);
|
||||||
#endif
|
|
||||||
|
auto* trayHandler = qobject_cast<SystemTrayNotificationHandler*>(m_notificationHandler.get());
|
||||||
|
connect(this, &CoreController::websiteUrlChanged, trayHandler, &SystemTrayNotificationHandler::updateWebsiteUrl);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreController::updateTranslator(const QLocale &locale)
|
void CoreController::updateTranslator(const QLocale &locale)
|
||||||
@@ -279,6 +284,7 @@ void CoreController::updateTranslator(const QLocale &locale)
|
|||||||
m_engine->retranslate();
|
m_engine->retranslate();
|
||||||
|
|
||||||
emit translationsUpdated();
|
emit translationsUpdated();
|
||||||
|
emit websiteUrlChanged(m_languageModel->getCurrentSiteUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreController::initErrorMessagesHandler()
|
void CoreController::initErrorMessagesHandler()
|
||||||
@@ -299,13 +305,10 @@ void CoreController::setQmlRoot()
|
|||||||
|
|
||||||
void CoreController::initApiCountryModelUpdateHandler()
|
void CoreController::initApiCountryModelUpdateHandler()
|
||||||
{
|
{
|
||||||
// TODO
|
|
||||||
connect(m_serversModel.get(), &ServersModel::updateApiCountryModel, this, [this]() {
|
connect(m_serversModel.get(), &ServersModel::updateApiCountryModel, this, [this]() {
|
||||||
m_apiCountryModel->updateModel(m_serversModel->getProcessedServerData("apiAvailableCountries").toJsonArray(),
|
m_apiCountryModel->updateModel(m_serversModel->getProcessedServerData("apiAvailableCountries").toJsonArray(),
|
||||||
m_serversModel->getProcessedServerData("apiServerCountryCode").toString());
|
m_serversModel->getProcessedServerData("apiServerCountryCode").toString());
|
||||||
});
|
});
|
||||||
connect(m_serversModel.get(), &ServersModel::updateApiServicesModel, this,
|
|
||||||
[this]() { m_apiServicesModel->updateModel(m_serversModel->getProcessedServerData("apiConfig").toJsonObject()); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreController::initContainerModelUpdateHandler()
|
void CoreController::initContainerModelUpdateHandler()
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||||
|
#include "ui/systemtray_notificationhandler.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ui/controllers/api/apiConfigsController.h"
|
#include "ui/controllers/api/apiConfigsController.h"
|
||||||
#include "ui/controllers/api/apiSettingsController.h"
|
#include "ui/controllers/api/apiSettingsController.h"
|
||||||
#include "ui/controllers/api/apiPremV1MigrationController.h"
|
#include "ui/controllers/api/apiPremV1MigrationController.h"
|
||||||
@@ -44,7 +48,7 @@
|
|||||||
#include "ui/models/services/socks5ProxyConfigModel.h"
|
#include "ui/models/services/socks5ProxyConfigModel.h"
|
||||||
#include "ui/models/sites_model.h"
|
#include "ui/models/sites_model.h"
|
||||||
|
|
||||||
#ifndef Q_OS_ANDROID
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||||
#include "ui/notificationhandler.h"
|
#include "ui/notificationhandler.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -61,6 +65,7 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void translationsUpdated();
|
void translationsUpdated();
|
||||||
|
void websiteUrlChanged(const QString &newUrl);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initModels();
|
void initModels();
|
||||||
@@ -92,7 +97,7 @@ private:
|
|||||||
QSharedPointer<VpnConnection> m_vpnConnection;
|
QSharedPointer<VpnConnection> m_vpnConnection;
|
||||||
QSharedPointer<QTranslator> m_translator;
|
QSharedPointer<QTranslator> m_translator;
|
||||||
|
|
||||||
#ifndef Q_OS_ANDROID
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||||
QScopedPointer<NotificationHandler> m_notificationHandler;
|
QScopedPointer<NotificationHandler> m_notificationHandler;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -60,8 +60,9 @@ ErrorCode GatewayController::get(const QString &endpoint, QByteArray &responseBo
|
|||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setTransferTimeout(m_requestTimeoutMsecs);
|
request.setTransferTimeout(m_requestTimeoutMsecs);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader(QString("X-Client-Request-ID").toUtf8(), QUuid::createUuid().toString(QUuid::WithoutBraces).toUtf8());
|
||||||
|
|
||||||
request.setUrl(QString(endpoint).arg(m_gatewayEndpoint));
|
request.setUrl(QString(endpoint).arg(m_proxyUrl.isEmpty() ? m_gatewayEndpoint : m_proxyUrl));
|
||||||
|
|
||||||
// bypass killSwitch exceptions for API-gateway
|
// bypass killSwitch exceptions for API-gateway
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
@@ -122,8 +123,9 @@ ErrorCode GatewayController::post(const QString &endpoint, const QJsonObject api
|
|||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setTransferTimeout(m_requestTimeoutMsecs);
|
request.setTransferTimeout(m_requestTimeoutMsecs);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
request.setRawHeader(QString("X-Client-Request-ID").toUtf8(), QUuid::createUuid().toString(QUuid::WithoutBraces).toUtf8());
|
||||||
|
|
||||||
request.setUrl(endpoint.arg(m_gatewayEndpoint));
|
request.setUrl(endpoint.arg(m_proxyUrl.isEmpty() ? m_gatewayEndpoint : m_proxyUrl));
|
||||||
|
|
||||||
// bypass killSwitch exceptions for API-gateway
|
// bypass killSwitch exceptions for API-gateway
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
@@ -344,11 +346,14 @@ void GatewayController::bypassProxy(const QString &endpoint, QNetworkReply *repl
|
|||||||
std::mt19937 generator(randomDevice());
|
std::mt19937 generator(randomDevice());
|
||||||
std::shuffle(proxyUrls.begin(), proxyUrls.end(), generator);
|
std::shuffle(proxyUrls.begin(), proxyUrls.end(), generator);
|
||||||
|
|
||||||
QEventLoop wait;
|
|
||||||
QList<QSslError> sslErrors;
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
|
|
||||||
for (const QString &proxyUrl : proxyUrls) {
|
auto bypassFunction = [this](const QString &endpoint, const QString &proxyUrl, QNetworkReply *reply,
|
||||||
|
std::function<QNetworkReply *(const QString &url)> requestFunction,
|
||||||
|
std::function<bool(QNetworkReply * reply, const QList<QSslError> &sslErrors)> replyProcessingFunction) {
|
||||||
|
QEventLoop wait;
|
||||||
|
QList<QSslError> sslErrors;
|
||||||
|
|
||||||
qDebug() << "go to the next proxy endpoint";
|
qDebug() << "go to the next proxy endpoint";
|
||||||
reply->deleteLater(); // delete the previous reply
|
reply->deleteLater(); // delete the previous reply
|
||||||
reply = requestFunction(endpoint.arg(proxyUrl));
|
reply = requestFunction(endpoint.arg(proxyUrl));
|
||||||
@@ -358,6 +363,50 @@ void GatewayController::bypassProxy(const QString &endpoint, QNetworkReply *repl
|
|||||||
wait.exec();
|
wait.exec();
|
||||||
|
|
||||||
if (replyProcessingFunction(reply, sslErrors)) {
|
if (replyProcessingFunction(reply, sslErrors)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (m_proxyUrl.isEmpty()) {
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setTransferTimeout(1000);
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
|
||||||
|
QEventLoop wait;
|
||||||
|
QList<QSslError> sslErrors;
|
||||||
|
QNetworkReply *reply;
|
||||||
|
|
||||||
|
for (const QString &proxyUrl : proxyUrls) {
|
||||||
|
request.setUrl(proxyUrl + "lmbd-health");
|
||||||
|
reply = amnApp->networkManager()->get(request);
|
||||||
|
|
||||||
|
connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||||
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
|
wait.exec();
|
||||||
|
|
||||||
|
if (reply->error() == QNetworkReply::NetworkError::NoError) {
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
m_proxyUrl = proxyUrl;
|
||||||
|
if (!m_proxyUrl.isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_proxyUrl.isEmpty()) {
|
||||||
|
if (bypassFunction(endpoint, m_proxyUrl, reply, requestFunction, replyProcessingFunction)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const QString &proxyUrl : proxyUrls) {
|
||||||
|
if (bypassFunction(endpoint, proxyUrl, reply, requestFunction, replyProcessingFunction)) {
|
||||||
|
m_proxyUrl = proxyUrl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ private:
|
|||||||
QString m_gatewayEndpoint;
|
QString m_gatewayEndpoint;
|
||||||
bool m_isDevEnvironment = false;
|
bool m_isDevEnvironment = false;
|
||||||
bool m_isStrictKillSwitchEnabled = false;
|
bool m_isStrictKillSwitchEnabled = false;
|
||||||
|
|
||||||
|
inline static QString m_proxyUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GATEWAYCONTROLLER_H
|
#endif // GATEWAYCONTROLLER_H
|
||||||
|
|||||||
@@ -197,12 +197,8 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTemporaryFile localFile;
|
// Write directly via SCP without creating a temporary local file.
|
||||||
localFile.open();
|
error = m_sshClient.scpWriteBuffer(overwriteMode, data, remotePath, "non_desc");
|
||||||
localFile.write(data);
|
|
||||||
localFile.close();
|
|
||||||
|
|
||||||
error = m_sshClient.scpFileCopy(overwriteMode, localFile.fileName(), remotePath, "non_desc");
|
|
||||||
|
|
||||||
if (error != ErrorCode::NoError) {
|
if (error != ErrorCode::NoError) {
|
||||||
return error;
|
return error;
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ namespace amnezia
|
|||||||
ApiNotFoundError = 1109,
|
ApiNotFoundError = 1109,
|
||||||
ApiMigrationError = 1110,
|
ApiMigrationError = 1110,
|
||||||
ApiUpdateRequestError = 1111,
|
ApiUpdateRequestError = 1111,
|
||||||
|
ApiSubscriptionExpiredError = 1112,
|
||||||
|
|
||||||
// QFile errors
|
// QFile errors
|
||||||
OpenError = 1200,
|
OpenError = 1200,
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ QString errorString(ErrorCode code) {
|
|||||||
case (ErrorCode::ApiNotFoundError): errorMessage = QObject::tr("Error when retrieving configuration from API"); break;
|
case (ErrorCode::ApiNotFoundError): errorMessage = QObject::tr("Error when retrieving configuration from API"); break;
|
||||||
case (ErrorCode::ApiMigrationError): errorMessage = QObject::tr("A migration error has occurred. Please contact our technical support"); break;
|
case (ErrorCode::ApiMigrationError): errorMessage = QObject::tr("A migration error has occurred. Please contact our technical support"); break;
|
||||||
case (ErrorCode::ApiUpdateRequestError): errorMessage = QObject::tr("Please update the application to use this feature"); break;
|
case (ErrorCode::ApiUpdateRequestError): errorMessage = QObject::tr("Please update the application to use this feature"); break;
|
||||||
|
case (ErrorCode::ApiSubscriptionExpiredError): errorMessage = QObject::tr("Your Amnezia Premium subscription has expired.\n Please check your email for renewal instructions.\n If you haven't received an email, please contact our support."); break;
|
||||||
|
|
||||||
// QFile errors
|
// QFile errors
|
||||||
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
|
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ bool IpcClient::isSocketConnected() const
|
|||||||
return m_isSocketConnected;
|
return m_isSocketConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IpcClient::close()
|
||||||
|
{
|
||||||
|
if (m_localSocket)
|
||||||
|
m_localSocket->close();
|
||||||
|
}
|
||||||
|
|
||||||
IpcClient *IpcClient::Instance()
|
IpcClient *IpcClient::Instance()
|
||||||
{
|
{
|
||||||
return m_instance;
|
return m_instance;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public:
|
|||||||
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
|
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
|
||||||
|
|
||||||
bool isSocketConnected() const;
|
bool isSocketConnected() const;
|
||||||
|
void close();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#if defined(Q_OS_MAC) && !defined(Q_OS_IOS)
|
#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -390,7 +390,7 @@ QString NetworkUtilities::getGatewayAndIface()
|
|||||||
close(sock);
|
close(sock);
|
||||||
return gateway_address;
|
return gateway_address;
|
||||||
#endif
|
#endif
|
||||||
#if defined(Q_OS_MAC) && !defined(Q_OS_IOS)
|
#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||||
QString gateway;
|
QString gateway;
|
||||||
int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_FLAGS, RTF_GATEWAY};
|
int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_FLAGS, RTF_GATEWAY};
|
||||||
int afinet_type[] = {AF_INET, AF_INET6};
|
int afinet_type[] = {AF_INET, AF_INET6};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
const uint32_t S_IRWXU = 0644;
|
const uint32_t S_IRWXU = 0644;
|
||||||
@@ -290,6 +291,54 @@ namespace libssh {
|
|||||||
return watcher.result();
|
return watcher.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorCode Client::scpWriteBuffer(const ScpOverwriteMode overwriteMode, const QByteArray &data, const QString &remotePath, const QString &fileDesc)
|
||||||
|
{
|
||||||
|
m_scpSession = ssh_scp_new(m_session, SSH_SCP_WRITE, remotePath.toStdString().c_str());
|
||||||
|
|
||||||
|
if (m_scpSession == nullptr) {
|
||||||
|
return fromLibsshErrorCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssh_scp_init(m_scpSession) != SSH_OK) {
|
||||||
|
auto errorCode = fromLibsshErrorCode();
|
||||||
|
closeScpSession();
|
||||||
|
return errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFutureWatcher<ErrorCode> watcher;
|
||||||
|
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, this, &Client::scpWriteBufferFinished);
|
||||||
|
QFuture<ErrorCode> future = QtConcurrent::run([this, overwriteMode, &data, &remotePath, &fileDesc]() {
|
||||||
|
const int accessType = O_WRONLY | O_CREAT | overwriteMode;
|
||||||
|
const int totalSize = data.size();
|
||||||
|
|
||||||
|
int result = ssh_scp_push_file(m_scpSession, remotePath.toStdString().c_str(), totalSize, accessType);
|
||||||
|
if (result != SSH_OK) {
|
||||||
|
return fromLibsshErrorCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int bufferSize = 16384;
|
||||||
|
int transferred = 0;
|
||||||
|
while (transferred < totalSize) {
|
||||||
|
const int chunkSize = std::min(bufferSize, totalSize - transferred);
|
||||||
|
result = ssh_scp_write(m_scpSession, data.constData() + transferred, chunkSize);
|
||||||
|
if (result != SSH_OK) {
|
||||||
|
return fromLibsshErrorCode();
|
||||||
|
}
|
||||||
|
transferred += chunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
});
|
||||||
|
watcher.setFuture(future);
|
||||||
|
|
||||||
|
QEventLoop wait;
|
||||||
|
QObject::connect(this, &Client::scpWriteBufferFinished, &wait, &QEventLoop::quit);
|
||||||
|
wait.exec();
|
||||||
|
|
||||||
|
closeScpSession();
|
||||||
|
return watcher.result();
|
||||||
|
}
|
||||||
|
|
||||||
void Client::closeScpSession()
|
void Client::closeScpSession()
|
||||||
{
|
{
|
||||||
if (m_scpSession != nullptr) {
|
if (m_scpSession != nullptr) {
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ namespace libssh {
|
|||||||
const QString &localPath,
|
const QString &localPath,
|
||||||
const QString &remotePath,
|
const QString &remotePath,
|
||||||
const QString &fileDesc);
|
const QString &fileDesc);
|
||||||
|
// Copy data directly without a temporary local file
|
||||||
|
ErrorCode scpWriteBuffer(const ScpOverwriteMode overwriteMode,
|
||||||
|
const QByteArray &data,
|
||||||
|
const QString &remotePath,
|
||||||
|
const QString &fileDesc);
|
||||||
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback);
|
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback);
|
||||||
private:
|
private:
|
||||||
ErrorCode closeChannel();
|
ErrorCode closeChannel();
|
||||||
@@ -52,6 +57,7 @@ namespace libssh {
|
|||||||
signals:
|
signals:
|
||||||
void writeToChannelFinished();
|
void writeToChannelFinished();
|
||||||
void scpFileCopyFinished();
|
void scpFileCopyFinished();
|
||||||
|
void scpWriteBufferFinished();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,10 +101,10 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
|
|||||||
out << "MTU = " << m_deviceMTU << "\n";
|
out << "MTU = " << m_deviceMTU << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_primaryDnsServer.isNull()) {
|
if (!m_primaryDnsServer.isEmpty()) {
|
||||||
QStringList dnsServers;
|
QStringList dnsServers;
|
||||||
dnsServers.append(m_primaryDnsServer);
|
dnsServers.append(m_primaryDnsServer);
|
||||||
if (!m_secondaryDnsServer.isNull()) {
|
if (!m_secondaryDnsServer.isEmpty()) {
|
||||||
dnsServers.append(m_secondaryDnsServer);
|
dnsServers.append(m_secondaryDnsServer);
|
||||||
}
|
}
|
||||||
// If the DNS is not the Gateway, it's a user defined DNS
|
// If the DNS is not the Gateway, it's a user defined DNS
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
#include "ipaddress.h"
|
#include "ipaddress.h"
|
||||||
|
|
||||||
class QJsonObject;
|
class QJsonObject;
|
||||||
|
|||||||
@@ -32,17 +32,41 @@
|
|||||||
<false/>
|
<false/>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>AmneziaVPNLaunchScreen</string>
|
<string>AmneziaVPNLaunchScreen</string>
|
||||||
|
<key>UIApplicationSceneManifest</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
|
<true/>
|
||||||
|
<key>UISceneConfigurations</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIWindowSceneSessionRoleApplication</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UISceneClassName</key>
|
||||||
|
<string>UIWindowScene</string>
|
||||||
|
<key>UISceneConfigurationName</key>
|
||||||
|
<string>Default Configuration</string>
|
||||||
|
<key>UISceneDelegateClassName</key>
|
||||||
|
<string>QIOSWindowSceneDelegate</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
<array/>
|
<array/>
|
||||||
<key>UIRequiresFullScreen</key>
|
<key>UIRequiresFullScreen</key>
|
||||||
<true/>
|
<false/>
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<array/>
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
<key>UIUserInterfaceStyle</key>
|
<key>UIUserInterfaceStyle</key>
|
||||||
<string>Light</string>
|
<string>Light</string>
|
||||||
<key>com.wireguard.ios.app_group_id</key>
|
<key>com.wireguard.ios.app_group_id</key>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 682 B |
|
Before Width: | Height: | Size: 593 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 593 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 340 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -1,6 +1,68 @@
|
|||||||
{
|
{
|
||||||
"info" : {
|
"images": [
|
||||||
"author" : "xcode",
|
{
|
||||||
"version" : 1
|
"idiom": "mac",
|
||||||
|
"size": "16x16",
|
||||||
|
"scale": "1x",
|
||||||
|
"filename": "16.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "mac",
|
||||||
|
"size": "16x16",
|
||||||
|
"scale": "2x",
|
||||||
|
"filename": "16@2x.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "mac",
|
||||||
|
"size": "32x32",
|
||||||
|
"scale": "1x",
|
||||||
|
"filename": "32.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "mac",
|
||||||
|
"size": "32x32",
|
||||||
|
"scale": "2x",
|
||||||
|
"filename": "32@2x.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "mac",
|
||||||
|
"size": "128x128",
|
||||||
|
"scale": "1x",
|
||||||
|
"filename": "128.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "mac",
|
||||||
|
"size": "128x128",
|
||||||
|
"scale": "2x",
|
||||||
|
"filename": "128@2x.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "mac",
|
||||||
|
"size": "256x256",
|
||||||
|
"scale": "1x",
|
||||||
|
"filename": "256.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "mac",
|
||||||
|
"size": "256x256",
|
||||||
|
"scale": "2x",
|
||||||
|
"filename": "256@2x.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "mac",
|
||||||
|
"size": "512x512",
|
||||||
|
"scale": "1x",
|
||||||
|
"filename": "512.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom": "mac",
|
||||||
|
"size": "512x512",
|
||||||
|
"scale": "2x",
|
||||||
|
"filename": "512@2x.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info": {
|
||||||
|
"version": 1,
|
||||||
|
"author": "xcode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
||||||
|
|
||||||
<key>CFBundleAllowMixedLocalizations</key>
|
|
||||||
<true/>
|
|
||||||
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>${EXECUTABLE_NAME}</string>
|
|
||||||
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
||||||
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>$(PRODUCT_NAME)</string>
|
|
||||||
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
|
||||||
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>$(MARKETING_VERSION)</string>
|
|
||||||
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
||||||
|
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
|
||||||
<false/>
|
|
||||||
|
|
||||||
<key>LSApplicationCategoryType</key>
|
|
||||||
<string>public.app-category.utilities</string>
|
|
||||||
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
|
||||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
|
||||||
|
|
||||||
<key>LSMultipleInstancesProhibited</key>
|
|
||||||
<true/>
|
|
||||||
|
|
||||||
<key>NSPrincipalClass</key>
|
|
||||||
<string>NSApplication</string>
|
|
||||||
|
|
||||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
<?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>LSApplicationCategoryType</key>
|
||||||
|
<string>public.app-category.utilities</string>
|
||||||
|
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||||
|
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.wireguard.ios.app_group_id</key>
|
||||||
|
<string>group.org.amnezia.AmneziaVPN</string>
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>Amnezia VPN needs access to the camera for reading QR-codes.</string>
|
||||||
|
<key>NSAppTransportSecurity</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
<false/>
|
||||||
|
<key>NSAllowsLocalNetworking</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>CFBundleIcons</key>
|
||||||
|
<dict/>
|
||||||
|
<key>UTImportedTypeDeclarations</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>Amnezia VPN config</string>
|
||||||
|
<key>UTTypeIconFiles</key>
|
||||||
|
<array/>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>org.amnezia.AmneziaVPN.amnezia-config</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>vpn</string>
|
||||||
|
</array>
|
||||||
|
<key>public.mime-type</key>
|
||||||
|
<array>
|
||||||
|
<string>text/plain</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>WireGuard config</string>
|
||||||
|
<key>UTTypeIconFiles</key>
|
||||||
|
<array/>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>org.amnezia.AmneziaVPN.wireguard-config</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>conf</string>
|
||||||
|
<string>cfg</string>
|
||||||
|
</array>
|
||||||
|
<key>public.mime-type</key>
|
||||||
|
<array>
|
||||||
|
<string>text/plain</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>OpenVPN config</string>
|
||||||
|
<key>UTTypeIconFiles</key>
|
||||||
|
<array/>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>org.amnezia.AmneziaVPN.openvpn-config</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>ovpn</string>
|
||||||
|
</array>
|
||||||
|
<key>public.mime-type</key>
|
||||||
|
<array>
|
||||||
|
<string>text/plain</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>AmneziaVPN backup file</string>
|
||||||
|
<key>UTTypeIconFiles</key>
|
||||||
|
<array/>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>org.amnezia.AmneziaVPN.backup-config</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>backup</string>
|
||||||
|
</array>
|
||||||
|
<key>public.mime-type</key>
|
||||||
|
<array>
|
||||||
|
<string>text/plain</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleDocumentTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeName</key>
|
||||||
|
<string>Amnezia VPN config</string>
|
||||||
|
<key>LSHandlerRank</key>
|
||||||
|
<string>Alternate</string>
|
||||||
|
<key>LSItemContentTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>org.amnezia.AmneziaVPN.amnezia-config</string>
|
||||||
|
<string>org.amnezia.AmneziaVPN.wireguard-config</string>
|
||||||
|
<string>org.amnezia.AmneziaVPN.openvpn-config</string>
|
||||||
|
<string>org.amnezia.AmneziaVPN.backup-config</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>NSExtensions</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.networkextension.packet-tunnel</string>
|
||||||
|
<key>NSExtensionPrincipalClass</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -2,34 +2,40 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.application-identifier</key>
|
<key>com.apple.developer.networking.custom-protocol</key>
|
||||||
<string>$(DEVELOPMENT_TEAM).$(APP_ID_MACOS)</string>
|
<true/>
|
||||||
|
|
||||||
<key>com.apple.developer.networking.networkextension</key>
|
<key>com.apple.developer.networking.networkextension</key>
|
||||||
<array>
|
<array>
|
||||||
|
<string>app-proxy-provider</string>
|
||||||
<string>packet-tunnel-provider</string>
|
<string>packet-tunnel-provider</string>
|
||||||
|
<string>dns-settings</string>
|
||||||
|
<string>relay</string>
|
||||||
|
<string>content-filter-provider</string>
|
||||||
|
<string>dns-proxy</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>com.apple.developer.system-extension.install</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.developer.networking.vpn.api</key>
|
||||||
|
<array>
|
||||||
|
<string>allow-vpn</string>
|
||||||
|
</array>
|
||||||
|
<key>com.apple.security.app-sandbox</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.org.amnezia.AmneziaVPN</string>
|
||||||
|
</array>
|
||||||
|
<key>com.apple.security.files.user-selected.read-only</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.files.user-selected.read-write</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.server</key>
|
||||||
|
<true/>
|
||||||
<key>keychain-access-groups</key>
|
<key>keychain-access-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>$(DEVELOPMENT_TEAM).*</string>
|
<string>$(DEVELOPMENT_TEAM).*</string>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
<key>com.apple.developer.team-identifier</key>
|
|
||||||
<string>$(DEVELOPMENT_TEAM)</string>
|
|
||||||
|
|
||||||
<key>com.apple.security.app-sandbox</key>
|
|
||||||
<true/>
|
|
||||||
|
|
||||||
<key>com.apple.security.application-groups</key>
|
|
||||||
<array>
|
|
||||||
<string>$(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS)</string>
|
|
||||||
</array>
|
|
||||||
|
|
||||||
<key>com.apple.security.network.client</key>
|
|
||||||
<true/>
|
|
||||||
|
|
||||||
<key>com.apple.security.network.server</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -2,41 +2,30 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.application-identifier</key>
|
<key>com.apple.developer.networking.custom-protocol</key>
|
||||||
<string>$(DEVELOPMENT_TEAM).$(NETEXT_ID_MACOS)</string>
|
<true/>
|
||||||
|
|
||||||
<key>com.apple.developer.networking.networkextension</key>
|
<key>com.apple.developer.networking.networkextension</key>
|
||||||
<array>
|
<array>
|
||||||
|
<string>dns-settings</string>
|
||||||
|
<string>relay</string>
|
||||||
<string>packet-tunnel-provider</string>
|
<string>packet-tunnel-provider</string>
|
||||||
|
<string>content-filter-provider</string>
|
||||||
|
<string>dns-proxy</string>
|
||||||
|
<string>app-proxy-provider</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>com.apple.developer.networking.vpn.api</key>
|
||||||
<key>keychain-access-groups</key>
|
|
||||||
<array>
|
<array>
|
||||||
<string>$(DEVELOPMENT_TEAM).*</string>
|
<string>allow-vpn</string>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
<key>com.apple.developer.team-identifier</key>
|
|
||||||
<string>$(DEVELOPMENT_TEAM)</string>
|
|
||||||
|
|
||||||
<key>com.apple.developer.system-extension.install</key>
|
|
||||||
<true/>
|
|
||||||
|
|
||||||
<key>com.apple.security.app-sandbox</key>
|
<key>com.apple.security.app-sandbox</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>$(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS)</string>
|
<string>group.org.amnezia.AmneziaVPN</string>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
<key>com.apple.security.network.client</key>
|
<key>com.apple.security.network.client</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
|
||||||
<key>com.apple.security.network.server</key>
|
<key>com.apple.security.network.server</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.app-sandbox</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.private.network.socket-delegate</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
enable_language(Swift)
|
||||||
|
message("Client message >> macos build >> AmneziaVPNNetworkExtension")
|
||||||
|
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
|
||||||
|
|
||||||
|
add_executable(AmneziaVPNNetworkExtension)
|
||||||
|
|
||||||
|
message("executable_path is: @executable_path/../../Frameworks")
|
||||||
|
set_target_properties(AmneziaVPNNetworkExtension PROPERTIES
|
||||||
|
XCODE_PRODUCT_TYPE com.apple.product-type.app-extension
|
||||||
|
# MACOSX_BUNDLE YES
|
||||||
|
BUNDLE_EXTENSION appex
|
||||||
|
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}"
|
||||||
|
MACOSX_BUNDLE_INFO_STRING "AmneziaVPNNetworkExtension"
|
||||||
|
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPNNetworkExtension"
|
||||||
|
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}.network-extension"
|
||||||
|
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_NAME "${BUILD_IOS_APP_IDENTIFIER}.network-extension"
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/AmneziaVPNNetworkExtension.entitlements
|
||||||
|
XCODE_ATTRIBUTE_MARKETING_VERSION "${APP_MAJOR_VERSION}"
|
||||||
|
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${BUILD_ID}"
|
||||||
|
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPNNetworkExtension"
|
||||||
|
|
||||||
|
XCODE_ATTRIBUTE_APPLICATION_EXTENSION_API_ONLY "YES"
|
||||||
|
XCODE_ATTRIBUTE_ENABLE_BITCODE "NO"
|
||||||
|
XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "11.0"
|
||||||
|
|
||||||
|
XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
|
||||||
|
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../../../../Frameworks @loader_path/../../../../Frameworks"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(DEPLOY)
|
||||||
|
message("DEPLOY is ON")
|
||||||
|
set_target_properties(AmneziaVPNNetworkExtension PROPERTIES
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution"
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development"
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual
|
||||||
|
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr macos.org.amnezia.amneziaVPN.NE"
|
||||||
|
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev macos.org.amnezia.amneziaVPN.NE"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
set_target_properties(AmneziaVPNNetworkExtension PROPERTIES
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(AmneziaVPNNetworkExtension 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("AmneziaVPNNetworkExtension" 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)
|
||||||
|
|
||||||
|
|
||||||
|
# Set the root directory
|
||||||
|
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
|
||||||
|
|
||||||
|
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${FW_LIBRESOLV})
|
||||||
|
|
||||||
|
target_compile_options(AmneziaVPNNetworkExtension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
|
||||||
|
target_compile_options(AmneziaVPNNetworkExtension PRIVATE -DNETWORK_EXTENSION=1)
|
||||||
|
|
||||||
|
set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/amneziawg-apple/Sources)
|
||||||
|
|
||||||
|
message("WG_APPLE_SOURCE_DIR is: ${WG_APPLE_SOURCE_DIR}")
|
||||||
|
message("CLIENT_ROOT_DIR is: ${CLIENT_ROOT_DIR}")
|
||||||
|
|
||||||
|
target_sources(AmneziaVPNNetworkExtension 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/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
|
||||||
|
${WG_APPLE_SOURCE_DIR}/WireGuardKit/Endpoint.swift
|
||||||
|
${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/HevSocksTunnel.swift
|
||||||
|
${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
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+Xray.swift
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/ios/WGConfig.swift
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/ios/XrayConfig.swift
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(AmneziaVPNNetworkExtension PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
|
||||||
|
)
|
||||||
|
|
||||||
|
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})
|
||||||
|
|
||||||
|
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/macos/universal2/libwg-go.a)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/Headers)
|
||||||
@@ -3,27 +3,32 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>en</string>
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>AmneziaVPNNetworkExtension</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>AmneziaVPNNetworkExtension</string>
|
||||||
|
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
<string>org.amnezia.AmneziaVPN.network-extension</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>$(PRODUCT_NAME)</string>
|
<string>AmneziaVPNNetworkExtension</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>$(MARKETING_VERSION)</string>
|
<string>${APPLE_PROJECT_VERSION}</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
<string>${CMAKE_PROJECT_VERSION_TWEAK}</string>
|
||||||
|
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
|
||||||
|
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>AmneziaVPNNetworkExtension</string>
|
||||||
|
|
||||||
<key>NSExtension</key>
|
<key>NSExtension</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionPointIdentifier</key>
|
<key>NSExtensionPointIdentifier</key>
|
||||||
@@ -31,5 +36,11 @@
|
|||||||
<key>NSExtensionPrincipalClass</key>
|
<key>NSExtensionPrincipalClass</key>
|
||||||
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
|
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
|
||||||
|
<key>com.wireguard.ios.app_group_id</key>
|
||||||
|
<string>group.org.amnezia.AmneziaVPN</string>
|
||||||
|
|
||||||
|
<key>com.wireguard.macos.app_group_id</key>
|
||||||
|
<string>${BUILD_VPN_DEVELOPMENT_TEAM}.group.org.amnezia.AmneziaVPN</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSPrivacyAccessedAPITypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>NSPrivacyAccessedAPIType</key>
|
||||||
|
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||||
|
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||||
|
<array>
|
||||||
|
<string>1C8F.1</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>NSPrivacyAccessedAPIType</key>
|
||||||
|
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
|
||||||
|
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||||
|
<array>
|
||||||
|
<string>C617.1</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "macos/gobridge/wireguard.h"
|
|
||||||
#include "wireguard-go-version.h"
|
#include "wireguard-go-version.h"
|
||||||
#include "3rd/awg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
|
#include "3rd/amneziawg-apple/Sources/WireGuardKitGo/wireguard.h"
|
||||||
|
#include "3rd/amneziawg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -23,3 +23,8 @@ bool key_from_hex(uint8_t key[WG_KEY_LEN], const char* hex);
|
|||||||
bool key_eq(const uint8_t key1[WG_KEY_LEN], const uint8_t key2[WG_KEY_LEN]);
|
bool key_eq(const uint8_t key1[WG_KEY_LEN], const uint8_t key2[WG_KEY_LEN]);
|
||||||
|
|
||||||
void write_msg_to_log(const char* tag, const char* msg);
|
void write_msg_to_log(const char* tag, const char* msg);
|
||||||
|
|
||||||
|
// init function definition in C
|
||||||
|
void hev_socks5_tunnel_quit(void);
|
||||||
|
// Updated function definition in C
|
||||||
|
int hev_socks5_tunnel_main(const char* configFile, int fd);
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#ifndef WIREGUARD_GO_VERSION
|
||||||
|
#define WIREGUARD_GO_VERSION "@WG_VERSION_STRING@"
|
||||||
|
#endif // WIREGUARD_GO_VERSION
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||||
bool isAnotherInstanceRunning()
|
bool isAnotherInstanceRunning()
|
||||||
{
|
{
|
||||||
QLocalSocket socket;
|
QLocalSocket socket;
|
||||||
@@ -45,7 +45,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
AmneziaApplication app(argc, argv);
|
AmneziaApplication app(argc, argv);
|
||||||
|
|
||||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||||
if (isAnotherInstanceRunning()) {
|
if (isAnotherInstanceRunning()) {
|
||||||
QTimer::singleShot(1000, &app, [&]() { app.quit(); });
|
QTimer::singleShot(1000, &app, [&]() { app.quit(); });
|
||||||
return app.exec();
|
return app.exec();
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
@@ -12,12 +15,13 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QObject>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include "ipaddress.h"
|
|
||||||
#include "leakdetector.h"
|
#include "leakdetector.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "models/server.h"
|
|
||||||
#include "daemon/daemonerrors.h"
|
#include "daemon/daemonerrors.h"
|
||||||
|
|
||||||
#include "protocols/protocols_defs.h"
|
#include "protocols/protocols_defs.h"
|
||||||
@@ -115,7 +119,6 @@ void LocalSocketController::daemonConnected() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||||
|
|
||||||
QString protocolName = rawConfig.value("protocol").toString();
|
QString protocolName = rawConfig.value("protocol").toString();
|
||||||
|
|
||||||
int splitTunnelType = rawConfig.value("splitTunnelType").toInt();
|
int splitTunnelType = rawConfig.value("splitTunnelType").toInt();
|
||||||
@@ -132,13 +135,16 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
|||||||
// json.insert("hopindex", QJsonValue((double)hop.m_hopindex));
|
// json.insert("hopindex", QJsonValue((double)hop.m_hopindex));
|
||||||
json.insert("privateKey", wgConfig.value(amnezia::config_key::client_priv_key));
|
json.insert("privateKey", wgConfig.value(amnezia::config_key::client_priv_key));
|
||||||
json.insert("deviceIpv4Address", wgConfig.value(amnezia::config_key::client_ip));
|
json.insert("deviceIpv4Address", wgConfig.value(amnezia::config_key::client_ip));
|
||||||
|
m_deviceIpv4 = wgConfig.value(amnezia::config_key::client_ip).toString();
|
||||||
|
|
||||||
// set up IPv6 unique-local-address, ULA, with "fd00::/8" prefix, not globally routable.
|
// set up IPv6 unique-local-address, ULA, with "fd00::/8" prefix, not globally routable.
|
||||||
// this will be default IPv6 gateway, OS recognizes that IPv6 link is local and switches to IPv4.
|
// this will be default IPv6 gateway, OS recognizes that IPv6 link is local and switches to IPv4.
|
||||||
// Otherwise some OSes (Linux) try IPv6 forever and hang.
|
// Otherwise some OSes (Linux) try IPv6 forever and hang.
|
||||||
// https://en.wikipedia.org/wiki/Unique_local_address (RFC 4193)
|
// https://en.wikipedia.org/wiki/Unique_local_address (RFC 4193)
|
||||||
// https://man7.org/linux/man-pages/man5/gai.conf.5.html
|
// https://man7.org/linux/man-pages/man5/gai.conf.5.html
|
||||||
json.insert("deviceIpv6Address", "fd58:baa6:dead::1"); // simply "dead::1" is globally-routable, don't use it
|
|
||||||
|
// simply "dead::1" is globally-routable, don't use it
|
||||||
|
json.insert("deviceIpv6Address", "fd58:baa6:dead::1");
|
||||||
|
|
||||||
json.insert("serverPublicKey", wgConfig.value(amnezia::config_key::server_pub_key));
|
json.insert("serverPublicKey", wgConfig.value(amnezia::config_key::server_pub_key));
|
||||||
json.insert("serverPskKey", wgConfig.value(amnezia::config_key::psk_key));
|
json.insert("serverPskKey", wgConfig.value(amnezia::config_key::psk_key));
|
||||||
@@ -220,7 +226,6 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
|||||||
|
|
||||||
json.insert("allowedIPAddressRanges", jsAllowedIPAddesses);
|
json.insert("allowedIPAddressRanges", jsAllowedIPAddesses);
|
||||||
|
|
||||||
|
|
||||||
QJsonArray jsExcludedAddresses;
|
QJsonArray jsExcludedAddresses;
|
||||||
jsExcludedAddresses.append(wgConfig.value(amnezia::config_key::hostName));
|
jsExcludedAddresses.append(wgConfig.value(amnezia::config_key::hostName));
|
||||||
if (splitTunnelType == 2) {
|
if (splitTunnelType == 2) {
|
||||||
@@ -264,13 +269,13 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
|||||||
&& !wgConfig.value(amnezia::config_key::junkPacketMaxSize).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::junkPacketMaxSize).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::initPacketJunkSize).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::initPacketJunkSize).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::responsePacketJunkSize).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::responsePacketJunkSize).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize).isUndefined()
|
// && !wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::transportPacketJunkSize).isUndefined()
|
// && !wgConfig.value(amnezia::config_key::transportPacketJunkSize).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::initPacketMagicHeader).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::initPacketMagicHeader).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::responsePacketMagicHeader).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::responsePacketMagicHeader).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::underloadPacketMagicHeader).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::underloadPacketMagicHeader).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::transportPacketMagicHeader).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::transportPacketMagicHeader).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::specialJunk1).isUndefined()
|
/* && !wgConfig.value(amnezia::config_key::specialJunk1).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::specialJunk2).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::specialJunk2).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::specialJunk3).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::specialJunk3).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::specialJunk4).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::specialJunk4).isUndefined()
|
||||||
@@ -278,27 +283,27 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
|||||||
&& !wgConfig.value(amnezia::config_key::controlledJunk1).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::controlledJunk1).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::controlledJunk2).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::controlledJunk2).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::controlledJunk3).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::controlledJunk3).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::specialHandshakeTimeout).isUndefined()) {
|
&& !wgConfig.value(amnezia::config_key::specialHandshakeTimeout).isUndefined()*/) {
|
||||||
json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount));
|
json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount));
|
||||||
json.insert(amnezia::config_key::junkPacketMinSize, wgConfig.value(amnezia::config_key::junkPacketMinSize));
|
json.insert(amnezia::config_key::junkPacketMinSize, wgConfig.value(amnezia::config_key::junkPacketMinSize));
|
||||||
json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize));
|
json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize));
|
||||||
json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize));
|
json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize));
|
||||||
json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize));
|
json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize));
|
||||||
json.insert(amnezia::config_key::cookieReplyPacketJunkSize, wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize));
|
// json.insert(amnezia::config_key::cookieReplyPacketJunkSize, wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize));
|
||||||
json.insert(amnezia::config_key::transportPacketJunkSize, wgConfig.value(amnezia::config_key::transportPacketJunkSize));
|
// json.insert(amnezia::config_key::transportPacketJunkSize, wgConfig.value(amnezia::config_key::transportPacketJunkSize));
|
||||||
json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader));
|
json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
|
json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
|
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
|
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::specialJunk1, wgConfig.value(amnezia::config_key::specialJunk1));
|
// json.insert(amnezia::config_key::specialJunk1, wgConfig.value(amnezia::config_key::specialJunk1));
|
||||||
json.insert(amnezia::config_key::specialJunk2, wgConfig.value(amnezia::config_key::specialJunk2));
|
// json.insert(amnezia::config_key::specialJunk2, wgConfig.value(amnezia::config_key::specialJunk2));
|
||||||
json.insert(amnezia::config_key::specialJunk3, wgConfig.value(amnezia::config_key::specialJunk3));
|
// json.insert(amnezia::config_key::specialJunk3, wgConfig.value(amnezia::config_key::specialJunk3));
|
||||||
json.insert(amnezia::config_key::specialJunk4, wgConfig.value(amnezia::config_key::specialJunk4));
|
// json.insert(amnezia::config_key::specialJunk4, wgConfig.value(amnezia::config_key::specialJunk4));
|
||||||
json.insert(amnezia::config_key::specialJunk5, wgConfig.value(amnezia::config_key::specialJunk5));
|
// json.insert(amnezia::config_key::specialJunk5, wgConfig.value(amnezia::config_key::specialJunk5));
|
||||||
json.insert(amnezia::config_key::controlledJunk1, wgConfig.value(amnezia::config_key::controlledJunk1));
|
// json.insert(amnezia::config_key::controlledJunk1, wgConfig.value(amnezia::config_key::controlledJunk1));
|
||||||
json.insert(amnezia::config_key::controlledJunk2, wgConfig.value(amnezia::config_key::controlledJunk2));
|
// json.insert(amnezia::config_key::controlledJunk2, wgConfig.value(amnezia::config_key::controlledJunk2));
|
||||||
json.insert(amnezia::config_key::controlledJunk3, wgConfig.value(amnezia::config_key::controlledJunk3));
|
// json.insert(amnezia::config_key::controlledJunk3, wgConfig.value(amnezia::config_key::controlledJunk3));
|
||||||
json.insert(amnezia::config_key::specialHandshakeTimeout, wgConfig.value(amnezia::config_key::specialHandshakeTimeout));
|
// json.insert(amnezia::config_key::specialHandshakeTimeout, wgConfig.value(amnezia::config_key::specialHandshakeTimeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
write(json);
|
write(json);
|
||||||
@@ -449,6 +454,7 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type == "status") {
|
if (type == "status") {
|
||||||
|
|
||||||
QJsonValue serverIpv4Gateway = obj.value("serverIpv4Gateway");
|
QJsonValue serverIpv4Gateway = obj.value("serverIpv4Gateway");
|
||||||
if (!serverIpv4Gateway.isString()) {
|
if (!serverIpv4Gateway.isString()) {
|
||||||
logger.error() << "Unexpected serverIpv4Gateway value";
|
logger.error() << "Unexpected serverIpv4Gateway value";
|
||||||
@@ -493,6 +499,11 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
|
|||||||
|
|
||||||
logger.debug() << "Handshake completed with:"
|
logger.debug() << "Handshake completed with:"
|
||||||
<< pubkey.toString();
|
<< pubkey.toString();
|
||||||
|
|
||||||
|
checkStatus();
|
||||||
|
|
||||||
|
emit statusUpdated("", m_deviceIpv4, 0, 0);
|
||||||
|
|
||||||
emit connected(pubkey.toString());
|
emit connected(pubkey.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "controllerimpl.h"
|
#include "controllerimpl.h"
|
||||||
|
|
||||||
|
|
||||||
class QJsonObject;
|
class QJsonObject;
|
||||||
|
|
||||||
class LocalSocketController final : public ControllerImpl {
|
class LocalSocketController final : public ControllerImpl {
|
||||||
@@ -58,6 +59,7 @@ class LocalSocketController final : public ControllerImpl {
|
|||||||
|
|
||||||
QByteArray m_buffer;
|
QByteArray m_buffer;
|
||||||
|
|
||||||
|
QString m_deviceIpv4;
|
||||||
std::function<void(const QString&)> m_logCallback = nullptr;
|
std::function<void(const QString&)> m_logCallback = nullptr;
|
||||||
|
|
||||||
QTimer m_initializingTimer;
|
QTimer m_initializingTimer;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
//#include "mozillavpn.h"
|
//#include "mozillavpn.h"
|
||||||
#include "networkwatcherimpl.h"
|
#include "networkwatcherimpl.h"
|
||||||
#include "platforms/dummy/dummynetworkwatcher.h"
|
|
||||||
//#include "settingsholder.h"
|
//#include "settingsholder.h"
|
||||||
|
|
||||||
#ifdef MZ_WINDOWS
|
#ifdef MZ_WINDOWS
|
||||||
@@ -51,7 +50,7 @@ NetworkWatcher::NetworkWatcher() { MZ_COUNT_CTOR(NetworkWatcher); }
|
|||||||
NetworkWatcher::~NetworkWatcher() { MZ_COUNT_DTOR(NetworkWatcher); }
|
NetworkWatcher::~NetworkWatcher() { MZ_COUNT_DTOR(NetworkWatcher); }
|
||||||
|
|
||||||
void NetworkWatcher::initialize() {
|
void NetworkWatcher::initialize() {
|
||||||
logger.debug() << "Initialize";
|
logger.debug() << "Initialize NetworkWatcher";
|
||||||
|
|
||||||
#if defined(MZ_WINDOWS)
|
#if defined(MZ_WINDOWS)
|
||||||
m_impl = new WindowsNetworkWatcher(this);
|
m_impl = new WindowsNetworkWatcher(this);
|
||||||
@@ -69,59 +68,45 @@ void NetworkWatcher::initialize() {
|
|||||||
m_impl = new DummyNetworkWatcher(this);
|
m_impl = new DummyNetworkWatcher(this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
connect(m_impl, &NetworkWatcherImpl::unsecuredNetwork, this,
|
connect(m_impl, &NetworkWatcherImpl::unsecuredNetwork, this,
|
||||||
&NetworkWatcher::unsecuredNetwork);
|
&NetworkWatcher::unsecuredNetwork);
|
||||||
connect(m_impl, &NetworkWatcherImpl::networkChanged, this,
|
connect(m_impl, &NetworkWatcherImpl::networkChanged, this,
|
||||||
&NetworkWatcher::networkChange);
|
&NetworkWatcher::networkChange);
|
||||||
|
connect(m_impl, &NetworkWatcherImpl::sleepMode, this,
|
||||||
|
&NetworkWatcher::onSleepMode);
|
||||||
m_impl->initialize();
|
m_impl->initialize();
|
||||||
|
|
||||||
|
// Enable sleep/wake monitoring for VPN auto-reconnection
|
||||||
// TODO: IMPL FOR AMNEZIA
|
logger.debug() << "Starting NetworkWatcher for sleep/wake monitoring";
|
||||||
#if 0
|
logger.debug() << "About to call m_impl->start()";
|
||||||
SettingsHolder* settingsHolder = SettingsHolder::instance();
|
try {
|
||||||
Q_ASSERT(settingsHolder);
|
|
||||||
|
|
||||||
m_active = settingsHolder->unsecuredNetworkAlert() ||
|
|
||||||
settingsHolder->captivePortalAlert();
|
|
||||||
m_reportUnsecuredNetwork = settingsHolder->unsecuredNetworkAlert();
|
|
||||||
if (m_active) {
|
|
||||||
m_impl->start();
|
m_impl->start();
|
||||||
|
logger.debug() << "m_impl->start() completed successfully";
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
logger.error() << "Exception in m_impl->start():" << e.what();
|
||||||
|
} catch (...) {
|
||||||
|
logger.error() << "Unknown exception in m_impl->start()";
|
||||||
}
|
}
|
||||||
|
m_active = true;
|
||||||
connect(settingsHolder, &SettingsHolder::unsecuredNetworkAlertChanged, this,
|
m_reportUnsecuredNetwork = false; // Disable unsecured network alerts for Amnezia
|
||||||
&NetworkWatcher::settingsChanged);
|
|
||||||
connect(settingsHolder, &SettingsHolder::captivePortalAlertChanged, this,
|
|
||||||
&NetworkWatcher::settingsChanged);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkWatcher::settingsChanged() {
|
void NetworkWatcher::settingsChanged() {
|
||||||
// TODO: IMPL FOR AMNEZIA
|
// For Amnezia: Keep NetworkWatcher always active for sleep/wake monitoring
|
||||||
#if 0
|
logger.debug() << "NetworkWatcher settings changed - keeping sleep monitoring active";
|
||||||
SettingsHolder* settingsHolder = SettingsHolder::instance();
|
}
|
||||||
m_active = settingsHolder->unsecuredNetworkAlert() ||
|
|
||||||
settingsHolder->captivePortalAlert();
|
|
||||||
m_reportUnsecuredNetwork = settingsHolder->unsecuredNetworkAlert();
|
|
||||||
|
|
||||||
if (m_active) {
|
void NetworkWatcher::onSleepMode()
|
||||||
logger.debug()
|
{
|
||||||
<< "Starting Network Watcher; Reporting of Unsecured Networks: "
|
logger.debug() << "Resumed from sleep mode";
|
||||||
<< m_reportUnsecuredNetwork;
|
emit sleepMode();
|
||||||
m_impl->start();
|
|
||||||
} else {
|
|
||||||
logger.debug() << "Stopping Network Watcher";
|
|
||||||
m_impl->stop();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkWatcher::unsecuredNetwork(const QString& networkName,
|
void NetworkWatcher::unsecuredNetwork(const QString& networkName,
|
||||||
const QString& networkId) {
|
const QString& networkId) {
|
||||||
logger.debug() << "Unsecured network:" << logger.sensitive(networkName)
|
logger.debug() << "Unsecured network:" << logger.sensitive(networkName)
|
||||||
<< "id:" << logger.sensitive(networkId);
|
<< "id:" << logger.sensitive(networkId);
|
||||||
|
|
||||||
#ifndef UNIT_TEST
|
#ifndef UNIT_TEST
|
||||||
if (!m_reportUnsecuredNetwork) {
|
if (!m_reportUnsecuredNetwork) {
|
||||||
logger.debug() << "Disabled. Ignoring unsecured network";
|
logger.debug() << "Disabled. Ignoring unsecured network";
|
||||||
|
|||||||
@@ -29,10 +29,13 @@ public:
|
|||||||
// false to restore.
|
// false to restore.
|
||||||
void simulateDisconnection(bool simulatedDisconnection);
|
void simulateDisconnection(bool simulatedDisconnection);
|
||||||
|
|
||||||
|
void onSleepMode();
|
||||||
|
|
||||||
QNetworkInformation::Reachability getReachability();
|
QNetworkInformation::Reachability getReachability();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void networkChange();
|
void networkChange();
|
||||||
|
void sleepMode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void settingsChanged();
|
void settingsChanged();
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ signals:
|
|||||||
// TODO: Only windows-networkwatcher has this, the other plattforms should
|
// TODO: Only windows-networkwatcher has this, the other plattforms should
|
||||||
// too.
|
// too.
|
||||||
void networkChanged(QString newBSSID);
|
void networkChanged(QString newBSSID);
|
||||||
|
void sleepMode();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_active = false;
|
bool m_active = false;
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ void PingHelper::start(const QString& serverIpv4Gateway,
|
|||||||
|
|
||||||
m_gateway = QHostAddress(serverIpv4Gateway);
|
m_gateway = QHostAddress(serverIpv4Gateway);
|
||||||
m_source = QHostAddress(deviceIpv4Address.section('/', 0, 0));
|
m_source = QHostAddress(deviceIpv4Address.section('/', 0, 0));
|
||||||
|
|
||||||
m_pingSender = PingSenderFactory::create(m_source, this);
|
m_pingSender = PingSenderFactory::create(m_source, this);
|
||||||
|
|
||||||
// Some platforms require root access to send and receive ICMP pings. If
|
// Some platforms require root access to send and receive ICMP pings. If
|
||||||
@@ -53,8 +54,10 @@ void PingHelper::start(const QString& serverIpv4Gateway,
|
|||||||
|
|
||||||
connect(m_pingSender, &PingSender::recvPing, this, &PingHelper::pingReceived,
|
connect(m_pingSender, &PingSender::recvPing, this, &PingHelper::pingReceived,
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
connect(m_pingSender, &PingSender::criticalPingError, this,
|
connect(m_pingSender, &PingSender::criticalPingError, this, [this]() {
|
||||||
[]() { logger.info() << "Encountered Unrecoverable ping error"; });
|
logger.info() << "Encountered Unrecoverable ping error";
|
||||||
|
emit connectionLose();
|
||||||
|
});
|
||||||
|
|
||||||
// Reset the ping statistics
|
// Reset the ping statistics
|
||||||
m_sequence = 0;
|
m_sequence = 0;
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ class PingHelper final : public QObject {
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void pingSentAndReceived(qint64 msec);
|
void pingSentAndReceived(qint64 msec);
|
||||||
|
void connectionLose();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void nextPing();
|
void nextPing();
|
||||||
|
|||||||
@@ -5,27 +5,26 @@
|
|||||||
#include "pingsenderfactory.h"
|
#include "pingsenderfactory.h"
|
||||||
|
|
||||||
#if defined(MZ_LINUX) || defined(MZ_ANDROID)
|
#if defined(MZ_LINUX) || defined(MZ_ANDROID)
|
||||||
//# include "platforms/linux/linuxpingsender.h"
|
# include "platforms/linux/linuxpingsender.h"
|
||||||
#elif defined(MZ_MACOS) || defined(MZ_IOS)
|
#elif defined(MZ_MACOS) || defined(MZ_IOS)
|
||||||
# include "platforms/macos/macospingsender.h"
|
# include "platforms/macos/macospingsender.h"
|
||||||
#elif defined(MZ_WINDOWS)
|
#elif defined(MZ_WINDOWS)
|
||||||
# include "platforms/windows/windowspingsender.h"
|
# include "platforms/windows/windowspingsender.h"
|
||||||
#elif defined(MZ_DUMMY) || defined(UNIT_TEST)
|
#elif defined(MZ_WASM) || defined(UNIT_TEST)
|
||||||
# include "platforms/dummy/dummypingsender.h"
|
# include "platforms/dummy/dummypingsender.h"
|
||||||
#else
|
#else
|
||||||
# error "Unsupported platform"
|
# error "Unsupported platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PingSender* PingSenderFactory::create(const QHostAddress& source,
|
PingSender* PingSenderFactory::create(const QHostAddress& source,
|
||||||
QObject* parent) {
|
QObject* parent) {
|
||||||
#if defined(MZ_LINUX) || defined(MZ_ANDROID)
|
#if defined(MZ_LINUX) || defined(MZ_ANDROID)
|
||||||
return nullptr;
|
return new LinuxPingSender(source, parent);
|
||||||
// return new LinuxPingSender(source, parent);
|
|
||||||
#elif defined(MZ_MACOS) || defined(MZ_IOS)
|
#elif defined(MZ_MACOS) || defined(MZ_IOS)
|
||||||
return new MacOSPingSender(source, parent);
|
return new MacOSPingSender(source, parent);
|
||||||
#elif defined(MZ_WINDOWS)
|
#elif defined(MZ_WINDOWS)
|
||||||
return new WindowsPingSender(source, parent);
|
return new WindowsPingSender(source, parent);
|
||||||
#else
|
#else
|
||||||
return new DummyPingSender(source, parent);
|
return new DummyPingSender(source, parent);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ class QHostAddress;
|
|||||||
class QObject;
|
class QObject;
|
||||||
|
|
||||||
class PingSenderFactory final {
|
class PingSenderFactory final {
|
||||||
public:
|
public:
|
||||||
PingSenderFactory() = delete;
|
PingSenderFactory() = delete;
|
||||||
static PingSender* create(const QHostAddress& source, QObject* parent);
|
static PingSender* create(const QHostAddress& source, QObject* parent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // PINGSENDERFACTORY_H
|
#endif // PINGSENDERFACTORY_H
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
#include <dispatch/dispatch.h>
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "ios_controller.h"
|
||||||
|
|
||||||
|
using SceneOpenURLContexts = void (*)(id, SEL, UIScene *, NSSet<UIOpenURLContext *> *);
|
||||||
|
|
||||||
|
static SceneOpenURLContexts g_originalSceneOpenURLContexts = nullptr;
|
||||||
|
|
||||||
|
static void amnezia_handleURL(NSURL *url)
|
||||||
|
{
|
||||||
|
if (!url || !url.isFileURL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString filePath(url.path.UTF8String);
|
||||||
|
if (filePath.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
|
if (filePath.contains("backup")) {
|
||||||
|
IosController::Instance()->importBackupFromOutside(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray data = file.readAll();
|
||||||
|
IosController::Instance()->importConfigFromOutside(QString::fromUtf8(data));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void amnezia_scene_openURLContexts(id self, SEL _cmd, UIScene *scene, NSSet<UIOpenURLContext *> *contexts)
|
||||||
|
{
|
||||||
|
if (g_originalSceneOpenURLContexts) {
|
||||||
|
g_originalSceneOpenURLContexts(self, _cmd, scene, contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contexts || contexts.count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@available(iOS 13.0, *)) {
|
||||||
|
for (UIOpenURLContext *context in contexts) {
|
||||||
|
amnezia_handleURL(context.URL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface AmneziaSceneDelegateHooks : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation AmneziaSceneDelegateHooks
|
||||||
|
|
||||||
|
+ (void)load
|
||||||
|
{
|
||||||
|
Class cls = objc_getClass("QIOSWindowSceneDelegate");
|
||||||
|
if (!cls) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SEL selector = @selector(scene:openURLContexts:);
|
||||||
|
Method method = class_getInstanceMethod(cls, selector);
|
||||||
|
if (method) {
|
||||||
|
g_originalSceneOpenURLContexts = reinterpret_cast<SceneOpenURLContexts>(method_getImplementation(method));
|
||||||
|
method_setImplementation(method, reinterpret_cast<IMP>(amnezia_scene_openURLContexts));
|
||||||
|
} else {
|
||||||
|
const char *types = "v@:@@";
|
||||||
|
class_addMethod(cls, selector, reinterpret_cast<IMP>(amnezia_scene_openURLContexts), types);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -73,7 +73,7 @@ extension PacketTunnelProvider {
|
|||||||
startHandler = completionHandler
|
startHandler = completionHandler
|
||||||
ovpnAdapter?.connect(using: packetFlow)
|
ovpnAdapter?.connect(using: packetFlow)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleOpenVPNStatusMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
|
func handleOpenVPNStatusMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
|
||||||
guard let completionHandler = completionHandler else { return }
|
guard let completionHandler = completionHandler else { return }
|
||||||
let bytesin = ovpnAdapter?.transportStatistics.bytesIn
|
let bytesin = ovpnAdapter?.transportStatistics.bytesIn
|
||||||
|
|||||||
@@ -112,9 +112,19 @@ extension PacketTunnelProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let lastHandshakeString = settingsDictionary["last_handshake_time_sec"]
|
||||||
|
let lastHandshake: Int64
|
||||||
|
|
||||||
|
if let lastHandshakeValue = lastHandshakeString, let handshakeValue = Int64(lastHandshakeValue) {
|
||||||
|
lastHandshake = handshakeValue
|
||||||
|
} else {
|
||||||
|
lastHandshake = -2 // Return an error if there is no value for `last_handshake_time_sec`
|
||||||
|
}
|
||||||
|
|
||||||
let response: [String: Any] = [
|
let response: [String: Any] = [
|
||||||
"rx_bytes": settingsDictionary["rx_bytes"] ?? "0",
|
"rx_bytes": settingsDictionary["rx_bytes"] ?? "0",
|
||||||
"tx_bytes": settingsDictionary["tx_bytes"] ?? "0"
|
"tx_bytes": settingsDictionary["tx_bytes"] ?? "0",
|
||||||
|
"last_handshake_time_sec": lastHandshake
|
||||||
]
|
]
|
||||||
|
|
||||||
completionHandler(try? JSONSerialization.data(withJSONObject: response, options: []))
|
completionHandler(try? JSONSerialization.data(withJSONObject: response, options: []))
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if !MACOS_NE
|
||||||
#include "QRCodeReaderBase.h"
|
#include "QRCodeReaderBase.h"
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
@@ -108,3 +109,19 @@ void QRCodeReader::startReading() {
|
|||||||
void QRCodeReader::stopReading() {
|
void QRCodeReader::stopReading() {
|
||||||
[m_qrCodeReader stopReading];
|
[m_qrCodeReader stopReading];
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
#include "QRCodeReaderBase.h"
|
||||||
|
|
||||||
|
QRCodeReader::QRCodeReader()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect QRCodeReader::cameraSize() {
|
||||||
|
return QRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRCodeReader::startReading() {}
|
||||||
|
void QRCodeReader::stopReading() {}
|
||||||
|
void QRCodeReader::setCameraSize(QRect) {}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
#if !MACOS_NE
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
#endif
|
||||||
@interface QIOSApplicationDelegate
|
@interface QIOSApplicationDelegate
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
|
|
||||||
@implementation QIOSApplicationDelegate (AmneziaVPNDelegate)
|
@implementation QIOSApplicationDelegate (AmneziaVPNDelegate)
|
||||||
|
#if !MACOS_NE
|
||||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||||
{
|
{
|
||||||
[application setMinimumBackgroundFetchInterval: UIApplicationBackgroundFetchIntervalMinimum];
|
[application setMinimumBackgroundFetchInterval: UIApplicationBackgroundFetchIntervalMinimum];
|
||||||
@@ -57,5 +57,5 @@
|
|||||||
}
|
}
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,3 +1,13 @@
|
|||||||
|
#if MACOS_NE
|
||||||
|
public func toggleScreenshots(_ isEnabled: Bool) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScreenProtection {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
public func toggleScreenshots(_ isEnabled: Bool) {
|
public func toggleScreenshots(_ isEnabled: Bool) {
|
||||||
@@ -90,3 +100,4 @@ struct ProtectionPair {
|
|||||||
textField.removeFromSuperview()
|
textField.removeFromSuperview()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public:
|
|||||||
void disconnectVpn();
|
void disconnectVpn();
|
||||||
|
|
||||||
void vpnStatusDidChange(void *pNotification);
|
void vpnStatusDidChange(void *pNotification);
|
||||||
|
|
||||||
void vpnConfigurationDidChange(void *pNotification);
|
void vpnConfigurationDidChange(void *pNotification);
|
||||||
|
|
||||||
void getBackendLogs(std::function<void(const QString &)> &&callback);
|
void getBackendLogs(std::function<void(const QString &)> &&callback);
|
||||||
|
|||||||
@@ -27,15 +27,51 @@ const char* MessageKey::isOnDemand = "is-on-demand";
|
|||||||
const char* MessageKey::SplitTunnelType = "SplitTunnelType";
|
const char* MessageKey::SplitTunnelType = "SplitTunnelType";
|
||||||
const char* MessageKey::SplitTunnelSites = "SplitTunnelSites";
|
const char* MessageKey::SplitTunnelSites = "SplitTunnelSites";
|
||||||
|
|
||||||
|
#if !MACOS_NE
|
||||||
static UIViewController* getViewController() {
|
static UIViewController* getViewController() {
|
||||||
NSArray *windows = [[UIApplication sharedApplication]windows];
|
UIApplication *application = [UIApplication sharedApplication];
|
||||||
for (UIWindow *window in windows) {
|
|
||||||
if (window.isKeyWindow) {
|
if (@available(iOS 13.0, *)) {
|
||||||
|
for (UIScene *scene in application.connectedScenes) {
|
||||||
|
if (scene.activationState != UISceneActivationStateForegroundActive) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![scene isKindOfClass:[UIWindowScene class]]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||||
|
|
||||||
|
for (UIWindow *window in windowScene.windows) {
|
||||||
|
if (window.isKeyWindow && window.rootViewController) {
|
||||||
|
return window.rootViewController;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UIWindow *window in windowScene.windows) {
|
||||||
|
if (!window.isHidden && window.rootViewController) {
|
||||||
|
return window.rootViewController;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UIWindow *window in application.windows) {
|
||||||
|
if (window.isKeyWindow && window.rootViewController) {
|
||||||
return window.rootViewController;
|
return window.rootViewController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (UIWindow *window in application.windows) {
|
||||||
|
if (window.rootViewController) {
|
||||||
|
return window.rootViewController;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Vpn::ConnectionState iosStatusToState(NEVPNStatus status) {
|
Vpn::ConnectionState iosStatusToState(NEVPNStatus status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@@ -249,6 +285,21 @@ void IosController::checkStatus()
|
|||||||
sendVpnExtensionMessage(message, [&](NSDictionary* response){
|
sendVpnExtensionMessage(message, [&](NSDictionary* response){
|
||||||
uint64_t txBytes = [response[@"tx_bytes"] intValue];
|
uint64_t txBytes = [response[@"tx_bytes"] intValue];
|
||||||
uint64_t rxBytes = [response[@"rx_bytes"] intValue];
|
uint64_t rxBytes = [response[@"rx_bytes"] intValue];
|
||||||
|
|
||||||
|
uint64_t last_handshake_time_sec = 0;
|
||||||
|
#if !MACOS_NE
|
||||||
|
if (response[@"last_handshake_time_sec"] && ![response[@"last_handshake_time_sec"] isKindOfClass:[NSNull class]]) {
|
||||||
|
last_handshake_time_sec = [response[@"last_handshake_time_sec"] intValue];
|
||||||
|
} else {
|
||||||
|
qDebug() << "Key last_handshake_time_sec is missing or null";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_handshake_time_sec < 0) {
|
||||||
|
disconnectVpn();
|
||||||
|
qDebug() << "Invalid handshake time, disconnecting VPN.";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
emit bytesChanged(rxBytes - m_rxBytes, txBytes - m_txBytes);
|
emit bytesChanged(rxBytes - m_rxBytes, txBytes - m_txBytes);
|
||||||
m_rxBytes = rxBytes;
|
m_rxBytes = rxBytes;
|
||||||
m_txBytes = txBytes;
|
m_txBytes = txBytes;
|
||||||
@@ -803,14 +854,14 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
|||||||
NSURL *logFileUrl = [[NSURL alloc] initFileURLWithPath:filesToSend[i].toNSString()];
|
NSURL *logFileUrl = [[NSURL alloc] initFileURLWithPath:filesToSend[i].toNSString()];
|
||||||
[sharingItems addObject:logFileUrl];
|
[sharingItems addObject:logFileUrl];
|
||||||
}
|
}
|
||||||
|
#if !MACOS_NE
|
||||||
UIViewController *qtController = getViewController();
|
UIViewController *qtController = getViewController();
|
||||||
if (!qtController) return;
|
if (!qtController) return;
|
||||||
|
|
||||||
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
||||||
|
#endif
|
||||||
__block bool isAccepted = false;
|
__block bool isAccepted = false;
|
||||||
|
#if !MACOS_NE
|
||||||
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
|
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
|
||||||
isAccepted = completed;
|
isAccepted = completed;
|
||||||
emit finished();
|
emit finished();
|
||||||
@@ -823,6 +874,7 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
|||||||
popController.sourceRect = CGRectMake(100, 100, 100, 100);
|
popController.sourceRect = CGRectMake(100, 100, 100, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||||
wait.exec();
|
wait.exec();
|
||||||
@@ -831,6 +883,7 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString IosController::openFile() {
|
QString IosController::openFile() {
|
||||||
|
#if !MACOS_NE
|
||||||
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen];
|
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen];
|
||||||
|
|
||||||
DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init];
|
DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init];
|
||||||
@@ -841,8 +894,9 @@ QString IosController::openFile() {
|
|||||||
|
|
||||||
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
||||||
|
|
||||||
|
#endif
|
||||||
__block QString filePath;
|
__block QString filePath;
|
||||||
|
#if !MACOS_NE
|
||||||
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
||||||
if (path) {
|
if (path) {
|
||||||
filePath = QString::fromUtf8(path.UTF8String);
|
filePath = QString::fromUtf8(path.UTF8String);
|
||||||
@@ -851,7 +905,7 @@ QString IosController::openFile() {
|
|||||||
}
|
}
|
||||||
emit finished();
|
emit finished();
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||||
wait.exec();
|
wait.exec();
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
#import <NetworkExtension/NetworkExtension.h>
|
#import <NetworkExtension/NetworkExtension.h>
|
||||||
#import <NetworkExtension/NETunnelProviderSession.h>
|
#import <NetworkExtension/NETunnelProviderSession.h>
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#if !MACOS_NE
|
||||||
#include <UIKit/UIKit.h>
|
#include <UIKit/UIKit.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <Security/Security.h>
|
#include <Security/Security.h>
|
||||||
|
|
||||||
class IosController;
|
class IosController;
|
||||||
@@ -17,9 +21,10 @@ class IosController;
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
typedef void (^DocumentPickerClosedCallback)(NSString *path);
|
typedef void (^DocumentPickerClosedCallback)(NSString *path);
|
||||||
|
#if !MACOS_NE
|
||||||
@interface DocumentPickerDelegate : NSObject <UIDocumentPickerDelegate>
|
@interface DocumentPickerDelegate : NSObject <UIDocumentPickerDelegate>
|
||||||
|
|
||||||
@property (nonatomic, copy) DocumentPickerClosedCallback documentPickerClosedCallback;
|
@property (nonatomic, copy) DocumentPickerClosedCallback documentPickerClosedCallback;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -26,7 +26,8 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation DocumentPickerDelegate
|
#if !MACOS_NE
|
||||||
|
@implementation DocumentPickerDelegate
|
||||||
|
|
||||||
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {
|
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {
|
||||||
for (NSURL *url in urls) {
|
for (NSURL *url in urls) {
|
||||||
@@ -42,4 +43,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ void IOSNetworkWatcher::initialize() {
|
|||||||
});
|
});
|
||||||
nw_path_monitor_start(m_networkMonitor);
|
nw_path_monitor_start(m_networkMonitor);
|
||||||
|
|
||||||
|
// Call start() to initialize sleep/wake monitoring (will call MacOSNetworkWatcher::start() if this is macOS)
|
||||||
|
this->start();
|
||||||
|
|
||||||
//TODO IMPL FOR AMNEZIA
|
//TODO IMPL FOR AMNEZIA
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#import <UserNotifications/UserNotifications.h>
|
#import <UserNotifications/UserNotifications.h>
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#if !MACOS_NE
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
@interface IOSNotificationDelegate
|
@interface IOSNotificationDelegate
|
||||||
@@ -87,3 +89,86 @@ void IOSNotificationHandler::notify(NotificationHandler::Message type, const QSt
|
|||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Removed the UIResponder and UIApplicationDelegate references as these are not available in macOS
|
||||||
|
@interface IOSNotificationDelegate
|
||||||
|
: NSObject <UNUserNotificationCenterDelegate> {
|
||||||
|
IOSNotificationHandler* m_iosNotificationHandler;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation IOSNotificationDelegate
|
||||||
|
|
||||||
|
- (id)initWithObject:(IOSNotificationHandler*)notification {
|
||||||
|
self = [super init]; // Removed `super init` as it refers to UIResponder, which is iOS specific
|
||||||
|
if (self) {
|
||||||
|
m_iosNotificationHandler = notification;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
|
||||||
|
willPresentNotification:(UNNotification*)notification
|
||||||
|
withCompletionHandler:
|
||||||
|
(void (^)(UNNotificationPresentationOptions options))completionHandler {
|
||||||
|
Q_UNUSED(center)
|
||||||
|
completionHandler(UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
|
||||||
|
didReceiveNotificationResponse:(UNNotificationResponse*)response
|
||||||
|
withCompletionHandler:(void (^)())completionHandler {
|
||||||
|
Q_UNUSED(center)
|
||||||
|
Q_UNUSED(response)
|
||||||
|
completionHandler();
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
IOSNotificationHandler::IOSNotificationHandler(QObject* parent) : NotificationHandler(parent) {
|
||||||
|
|
||||||
|
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
|
||||||
|
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert |
|
||||||
|
UNAuthorizationOptionBadge)
|
||||||
|
completionHandler:^(BOOL granted, NSError* _Nullable error) {
|
||||||
|
Q_UNUSED(granted);
|
||||||
|
if (!error) {
|
||||||
|
m_delegate = [[IOSNotificationDelegate alloc] initWithObject:this];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
IOSNotificationHandler::~IOSNotificationHandler() { }
|
||||||
|
|
||||||
|
void IOSNotificationHandler::notify(NotificationHandler::Message type, const QString& title,
|
||||||
|
const QString& message, int timerMsec) {
|
||||||
|
Q_UNUSED(type);
|
||||||
|
|
||||||
|
if (!m_delegate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
|
||||||
|
content.title = title.toNSString();
|
||||||
|
content.body = message.toNSString();
|
||||||
|
content.sound = [UNNotificationSound defaultSound];
|
||||||
|
|
||||||
|
int timerSec = timerMsec / 1000;
|
||||||
|
UNTimeIntervalNotificationTrigger* trigger =
|
||||||
|
[UNTimeIntervalNotificationTrigger triggerWithTimeInterval:timerSec repeats:NO];
|
||||||
|
|
||||||
|
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"amneziavpn"
|
||||||
|
content:content
|
||||||
|
trigger:trigger];
|
||||||
|
|
||||||
|
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
|
||||||
|
center.delegate = (id<UNUserNotificationCenterDelegate>)m_delegate;
|
||||||
|
|
||||||
|
[center addNotificationRequest:request
|
||||||
|
withCompletionHandler:^(NSError* _Nullable error) {
|
||||||
|
if (error) {
|
||||||
|
NSLog(@"Local Notification failed");
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ void LinuxNetworkWatcher::initialize() {
|
|||||||
connect(m_worker, &LinuxNetworkWatcherWorker::unsecuredNetwork, this,
|
connect(m_worker, &LinuxNetworkWatcherWorker::unsecuredNetwork, this,
|
||||||
&LinuxNetworkWatcher::unsecuredNetwork);
|
&LinuxNetworkWatcher::unsecuredNetwork);
|
||||||
|
|
||||||
|
connect(m_worker, &LinuxNetworkWatcherWorker::sleepMode, this,
|
||||||
|
&NetworkWatcherImpl::sleepMode);
|
||||||
|
|
||||||
// Let's wait a few seconds to allow the UI to be fully loaded and shown.
|
// Let's wait a few seconds to allow the UI to be fully loaded and shown.
|
||||||
// This is not strictly needed, but it's better for user experience because
|
// This is not strictly needed, but it's better for user experience because
|
||||||
// it makes the UI faster to appear, plus it gives a bit of delay between the
|
// it makes the UI faster to appear, plus it gives a bit of delay between the
|
||||||
|
|||||||
@@ -33,7 +33,21 @@
|
|||||||
#define NM_802_11_AP_SEC_WEAK_CRYPTO \
|
#define NM_802_11_AP_SEC_WEAK_CRYPTO \
|
||||||
(NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104)
|
(NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104)
|
||||||
|
|
||||||
|
|
||||||
|
enum NMState {
|
||||||
|
NM_STATE_UNKNOWN = 0,
|
||||||
|
NM_STATE_ASLEEP = 10,
|
||||||
|
NM_STATE_DISCONNECTED = 20,
|
||||||
|
NM_STATE_DISCONNECTING = 30,
|
||||||
|
NM_STATE_CONNECTING = 40,
|
||||||
|
NM_STATE_CONNECTED_LOCAL = 50,
|
||||||
|
NM_STATE_CONNECTED_SITE = 60,
|
||||||
|
NM_STATE_CONNECTED_GLOBAL = 70
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
constexpr const char* DBUS_NETWORKMANAGER = "org.freedesktop.NetworkManager";
|
constexpr const char* DBUS_NETWORKMANAGER = "org.freedesktop.NetworkManager";
|
||||||
|
constexpr const char* DBUS_NETWORKMANAGER_PATH = "/org/freedesktop/NetworkManager";
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Logger logger("LinuxNetworkWatcherWorker");
|
Logger logger("LinuxNetworkWatcherWorker");
|
||||||
@@ -73,7 +87,7 @@ void LinuxNetworkWatcherWorker::initialize() {
|
|||||||
// documentation:
|
// documentation:
|
||||||
// https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html
|
// https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html
|
||||||
|
|
||||||
QDBusInterface nm(DBUS_NETWORKMANAGER, "/org/freedesktop/NetworkManager",
|
QDBusInterface nm(DBUS_NETWORKMANAGER, DBUS_NETWORKMANAGER_PATH,
|
||||||
DBUS_NETWORKMANAGER, QDBusConnection::systemBus());
|
DBUS_NETWORKMANAGER, QDBusConnection::systemBus());
|
||||||
if (!nm.isValid()) {
|
if (!nm.isValid()) {
|
||||||
logger.error()
|
logger.error()
|
||||||
@@ -108,6 +122,12 @@ void LinuxNetworkWatcherWorker::initialize() {
|
|||||||
SLOT(propertyChanged(QString, QVariantMap, QStringList)));
|
SLOT(propertyChanged(QString, QVariantMap, QStringList)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QDBusConnection::systemBus().connect(DBUS_NETWORKMANAGER,
|
||||||
|
DBUS_NETWORKMANAGER_PATH,
|
||||||
|
DBUS_NETWORKMANAGER,
|
||||||
|
"StateChanged",
|
||||||
|
this, SLOT(NMStateChanged(quint32)));
|
||||||
|
|
||||||
if (m_devicePaths.isEmpty()) {
|
if (m_devicePaths.isEmpty()) {
|
||||||
logger.warning() << "No wifi devices found";
|
logger.warning() << "No wifi devices found";
|
||||||
return;
|
return;
|
||||||
@@ -173,5 +193,16 @@ void LinuxNetworkWatcherWorker::checkDevices() {
|
|||||||
emit unsecuredNetwork(ssid, bssid);
|
emit unsecuredNetwork(ssid, bssid);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LinuxNetworkWatcherWorker::NMStateChanged(quint32 state)
|
||||||
|
{
|
||||||
|
if (state == NM_STATE_ASLEEP) {
|
||||||
|
emit sleepMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug() << "NMStateChanged " << state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class LinuxNetworkWatcherWorker final : public QObject {
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void unsecuredNetwork(const QString& networkName, const QString& networkId);
|
void unsecuredNetwork(const QString& networkName, const QString& networkId);
|
||||||
|
void sleepMode();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void initialize();
|
void initialize();
|
||||||
@@ -30,6 +31,7 @@ class LinuxNetworkWatcherWorker final : public QObject {
|
|||||||
private slots:
|
private slots:
|
||||||
void propertyChanged(QString interface, QVariantMap properties,
|
void propertyChanged(QString interface, QVariantMap properties,
|
||||||
QStringList list);
|
QStringList list);
|
||||||
|
void NMStateChanged(quint32 state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// We collect the list of DBus wifi network device paths during the
|
// We collect the list of DBus wifi network device paths during the
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "linuxpingsender.h"
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/filter.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/ip_icmp.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
#include <QtEndian>
|
||||||
|
|
||||||
|
#include "leakdetector.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "qhostaddress.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Logger logger("LinuxPingSender");
|
||||||
|
}
|
||||||
|
|
||||||
|
int LinuxPingSender::createSocket() {
|
||||||
|
// Try creating an ICMP socket. This would be the ideal choice, but it can
|
||||||
|
// fail depending on the kernel config (see: sys.net.ipv4.ping_group_range)
|
||||||
|
m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
|
||||||
|
if (m_socket >= 0) {
|
||||||
|
m_ident = 0;
|
||||||
|
return m_socket;
|
||||||
|
}
|
||||||
|
if ((errno != EPERM) && (errno != EACCES)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// As a fallback, create a raw socket, which requires root permissions
|
||||||
|
// or CAP_NET_RAW to be granted to the VPN client.
|
||||||
|
m_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||||
|
if (m_socket < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
m_ident = getpid() & 0xffff;
|
||||||
|
|
||||||
|
// Attach a BPF filter to discard everything but replies to our echo.
|
||||||
|
struct sock_filter bpf_prog[] = {
|
||||||
|
BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. */
|
||||||
|
BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, m_ident, 1, 0), /* Ours? */
|
||||||
|
BPF_STMT(BPF_RET | BPF_K, 0), /* Unexpected identifier. Reject. */
|
||||||
|
BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
|
||||||
|
BPF_STMT(BPF_RET | BPF_K, 0), /* Unexpected type. Reject. */
|
||||||
|
BPF_STMT(BPF_RET | BPF_K, ~0U), /* Packet passes the filter. */
|
||||||
|
};
|
||||||
|
struct sock_fprog filter = {
|
||||||
|
.len = sizeof(bpf_prog) / sizeof(struct sock_filter),
|
||||||
|
.filter = bpf_prog,
|
||||||
|
};
|
||||||
|
setsockopt(m_socket, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
|
||||||
|
|
||||||
|
return m_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinuxPingSender::LinuxPingSender(const QHostAddress& source, QObject* parent)
|
||||||
|
: PingSender(parent) {
|
||||||
|
MZ_COUNT_CTOR(LinuxPingSender);
|
||||||
|
|
||||||
|
logger.debug() << "LinuxPingSender(" + logger.sensitive(source.toString()) +
|
||||||
|
") created";
|
||||||
|
|
||||||
|
m_socket = createSocket();
|
||||||
|
if (m_socket < 0) {
|
||||||
|
logger.error() << "Socket creation error: " << strerror(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 ipv4addr = INADDR_ANY;
|
||||||
|
if (!source.isNull()) {
|
||||||
|
ipv4addr = source.toIPv4Address();
|
||||||
|
}
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof addr);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = qToBigEndian<quint32>(ipv4addr);
|
||||||
|
|
||||||
|
if (bind(m_socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
|
||||||
|
close(m_socket);
|
||||||
|
m_socket = -1;
|
||||||
|
logger.error() << "bind error:" << strerror(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_notifier = new QSocketNotifier(m_socket, QSocketNotifier::Read, this);
|
||||||
|
if (m_ident) {
|
||||||
|
connect(m_notifier, &QSocketNotifier::activated, this,
|
||||||
|
&LinuxPingSender::rawSocketReady);
|
||||||
|
} else {
|
||||||
|
connect(m_notifier, &QSocketNotifier::activated, this,
|
||||||
|
&LinuxPingSender::icmpSocketReady);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LinuxPingSender::~LinuxPingSender() {
|
||||||
|
MZ_COUNT_DTOR(LinuxPingSender);
|
||||||
|
if (m_socket >= 0) {
|
||||||
|
close(m_socket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxPingSender::sendPing(const QHostAddress& dest, quint16 sequence) {
|
||||||
|
quint32 ipv4dest = dest.toIPv4Address();
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = qToBigEndian<quint32>(ipv4dest);
|
||||||
|
|
||||||
|
struct icmphdr packet;
|
||||||
|
memset(&packet, 0, sizeof(packet));
|
||||||
|
packet.type = ICMP_ECHO;
|
||||||
|
packet.un.echo.id = htons(m_ident);
|
||||||
|
packet.un.echo.sequence = htons(sequence);
|
||||||
|
packet.checksum = inetChecksum(&packet, sizeof(packet));
|
||||||
|
|
||||||
|
int rc = sendto(m_socket, &packet, sizeof(packet), 0, (struct sockaddr*)&addr,
|
||||||
|
sizeof(addr));
|
||||||
|
if (rc < 0) {
|
||||||
|
logger.error() << "failed to send:" << strerror(errno);
|
||||||
|
if (errno == ENETUNREACH) {
|
||||||
|
emit criticalPingError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxPingSender::icmpSocketReady() {
|
||||||
|
socklen_t slen = 0;
|
||||||
|
unsigned char data[2048];
|
||||||
|
int rc = recvfrom(m_socket, data, sizeof(data), MSG_DONTWAIT, NULL, &slen);
|
||||||
|
if (rc <= 0) {
|
||||||
|
logger.error() << "recvfrom failed:" << strerror(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct icmphdr packet;
|
||||||
|
if (rc >= (int)sizeof(packet)) {
|
||||||
|
memcpy(&packet, data, sizeof(packet));
|
||||||
|
if (packet.type == ICMP_ECHOREPLY) {
|
||||||
|
emit recvPing(htons(packet.un.echo.sequence));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxPingSender::rawSocketReady() {
|
||||||
|
socklen_t slen = 0;
|
||||||
|
unsigned char data[2048];
|
||||||
|
int rc = recvfrom(m_socket, data, sizeof(data), MSG_DONTWAIT, NULL, &slen);
|
||||||
|
if (rc <= 0) {
|
||||||
|
logger.error() << "recvfrom failed:" << strerror(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the IP header
|
||||||
|
const struct iphdr* ip = (struct iphdr*)data;
|
||||||
|
int iphdrlen = ip->ihl * 4;
|
||||||
|
if (rc < iphdrlen || iphdrlen < (int)sizeof(struct iphdr)) {
|
||||||
|
logger.error() << "malformed IP packet:" << strerror(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the ICMP packet
|
||||||
|
struct icmphdr packet;
|
||||||
|
if (inetChecksum(data + iphdrlen, rc - iphdrlen) != 0) {
|
||||||
|
logger.warning() << "invalid checksum";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rc >= (iphdrlen + (int)sizeof(packet))) {
|
||||||
|
memcpy(&packet, data + iphdrlen, sizeof(packet));
|
||||||
|
quint16 id = htons(m_ident);
|
||||||
|
if ((packet.type == ICMP_ECHOREPLY) && (packet.un.echo.id == id)) {
|
||||||
|
emit recvPing(htons(packet.un.echo.sequence));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef LINUXPINGSENDER_H
|
||||||
|
#define LINUXPINGSENDER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "../client/mozilla/pingsender.h"
|
||||||
|
|
||||||
|
class QSocketNotifier;
|
||||||
|
|
||||||
|
class LinuxPingSender final : public PingSender {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY_MOVE(LinuxPingSender)
|
||||||
|
|
||||||
|
public:
|
||||||
|
LinuxPingSender(const QHostAddress& source, QObject* parent = nullptr);
|
||||||
|
~LinuxPingSender();
|
||||||
|
|
||||||
|
bool isValid() override { return (m_socket >= 0); };
|
||||||
|
|
||||||
|
void sendPing(const QHostAddress& dest, quint16 sequence) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int createSocket();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void rawSocketReady();
|
||||||
|
void icmpSocketReady();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSocketNotifier* m_notifier = nullptr;
|
||||||
|
int m_socket = -1;
|
||||||
|
quint16 m_ident = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LINUXPINGSENDER_H
|
||||||
@@ -10,8 +10,31 @@
|
|||||||
#include "../ios/iosnetworkwatcher.h"
|
#include "../ios/iosnetworkwatcher.h"
|
||||||
#include "networkwatcherimpl.h"
|
#include "networkwatcherimpl.h"
|
||||||
|
|
||||||
|
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||||
|
#include <IOKit/IOMessage.h>
|
||||||
|
|
||||||
|
|
||||||
class QString;
|
class QString;
|
||||||
|
|
||||||
|
// Inspired by https://ladydebug.com/blog/2020/05/21/programmatically-capture-energy-saver-event-on-mac/
|
||||||
|
class PowerNotificationsListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PowerNotificationsListener(class MacOSNetworkWatcher* watcher) : m_watcher(watcher) {}
|
||||||
|
void registerForNotifications();
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void sleepWakeupCallBack(void *refParam, io_service_t service, natural_t messageType, void *messageArgument);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class MacOSNetworkWatcher* m_watcher = nullptr;
|
||||||
|
IONotificationPortRef notifyPortRef = nullptr; // notification port allocated by IORegisterForSystemPower
|
||||||
|
io_object_t notifierObj = IO_OBJECT_NULL; // notifier object, used to deregister later
|
||||||
|
io_connect_t rootPowerDomain = IO_OBJECT_NULL; // a reference to the Root Power Domain IOService
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class MacOSNetworkWatcher final : public IOSNetworkWatcher {
|
class MacOSNetworkWatcher final : public IOSNetworkWatcher {
|
||||||
public:
|
public:
|
||||||
MacOSNetworkWatcher(QObject* parent);
|
MacOSNetworkWatcher(QObject* parent);
|
||||||
@@ -25,6 +48,7 @@ class MacOSNetworkWatcher final : public IOSNetworkWatcher {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void* m_delegate = nullptr;
|
void* m_delegate = nullptr;
|
||||||
|
PowerNotificationsListener m_powerlistener;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MACOSNETWORKWATCHER_H
|
#endif // MACOSNETWORKWATCHER_H
|
||||||
|
|||||||
@@ -6,6 +6,11 @@
|
|||||||
#include "leakdetector.h"
|
#include "leakdetector.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QMetaObject>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#import <CoreWLAN/CoreWLAN.h>
|
#import <CoreWLAN/CoreWLAN.h>
|
||||||
#import <Network/Network.h>
|
#import <Network/Network.h>
|
||||||
|
|
||||||
@@ -13,6 +18,37 @@ namespace {
|
|||||||
Logger logger("MacOSNetworkWatcher");
|
Logger logger("MacOSNetworkWatcher");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global variables for CFRunLoop thread
|
||||||
|
static pthread_t g_powerThread;
|
||||||
|
static CFRunLoopRef g_powerRunLoop = nullptr;
|
||||||
|
static bool g_shouldStopPowerThread = false;
|
||||||
|
static PowerNotificationsListener* g_powerListener = nullptr;
|
||||||
|
|
||||||
|
// Thread function for dedicated CFRunLoop
|
||||||
|
void* powerMonitoringThread(void* arg) {
|
||||||
|
logger.debug() << "Power monitoring thread started";
|
||||||
|
|
||||||
|
PowerNotificationsListener* listener = static_cast<PowerNotificationsListener*>(arg);
|
||||||
|
|
||||||
|
// Get the runloop for this thread
|
||||||
|
g_powerRunLoop = CFRunLoopGetCurrent();
|
||||||
|
|
||||||
|
// Register for power notifications in this thread
|
||||||
|
listener->registerForNotifications();
|
||||||
|
|
||||||
|
// Run the CFRunLoop - this will block until CFRunLoopStop is called
|
||||||
|
while (!g_shouldStopPowerThread) {
|
||||||
|
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
listener->cleanup();
|
||||||
|
g_powerRunLoop = nullptr;
|
||||||
|
|
||||||
|
logger.debug() << "Power monitoring thread finished";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
@interface MacOSNetworkWatcherDelegate : NSObject <CWEventDelegate> {
|
@interface MacOSNetworkWatcherDelegate : NSObject <CWEventDelegate> {
|
||||||
MacOSNetworkWatcher* m_watcher;
|
MacOSNetworkWatcher* m_watcher;
|
||||||
}
|
}
|
||||||
@@ -38,12 +74,138 @@ Logger logger("MacOSNetworkWatcher");
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
MacOSNetworkWatcher::MacOSNetworkWatcher(QObject* parent) : IOSNetworkWatcher(parent) {
|
void PowerNotificationsListener::registerForNotifications()
|
||||||
|
{
|
||||||
|
logger.debug() << "Registering for system power notifications in dedicated thread";
|
||||||
|
|
||||||
|
rootPowerDomain = IORegisterForSystemPower(this, ¬ifyPortRef, sleepWakeupCallBack, ¬ifierObj);
|
||||||
|
if (rootPowerDomain == IO_OBJECT_NULL) {
|
||||||
|
logger.error() << "Failed to register for system power notifications!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the notification port to the current runloop (dedicated thread)
|
||||||
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
|
||||||
|
logger.debug() << "Power notifications registered successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PowerNotificationsListener::cleanup()
|
||||||
|
{
|
||||||
|
if (notifyPortRef != nullptr) {
|
||||||
|
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
|
||||||
|
IONotificationPortDestroy(notifyPortRef);
|
||||||
|
notifyPortRef = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notifierObj != IO_OBJECT_NULL) {
|
||||||
|
IODeregisterForSystemPower(¬ifierObj);
|
||||||
|
notifierObj = IO_OBJECT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootPowerDomain != IO_OBJECT_NULL) {
|
||||||
|
IOServiceClose(rootPowerDomain);
|
||||||
|
rootPowerDomain = IO_OBJECT_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PowerNotificationsListener::sleepWakeupCallBack(void *refParam, io_service_t service, natural_t messageType, void *messageArgument)
|
||||||
|
{
|
||||||
|
Q_UNUSED(service)
|
||||||
|
|
||||||
|
auto listener = static_cast<PowerNotificationsListener *>(refParam);
|
||||||
|
|
||||||
|
logger.debug() << "Power callback received, messageType:" << messageType;
|
||||||
|
switch (messageType) {
|
||||||
|
case kIOMessageCanSystemSleep:
|
||||||
|
/* Idle sleep is about to kick in. This message will not be sent for forced sleep.
|
||||||
|
* Applications have a chance to prevent sleep by calling IOCancelPowerChange.
|
||||||
|
* Most applications should not prevent idle sleep. Power Management waits up to
|
||||||
|
* 30 seconds for you to either allow or deny idle sleep. If you don’t acknowledge
|
||||||
|
* this power change by calling either IOAllowPowerChange or IOCancelPowerChange,
|
||||||
|
* the system will wait 30 seconds then go to sleep.
|
||||||
|
*/
|
||||||
|
|
||||||
|
logger.debug() << "System power message: can system sleep?";
|
||||||
|
|
||||||
|
// Uncomment to cancel idle sleep
|
||||||
|
// IOCancelPowerChange(thiz->rootPowerDomain, reinterpret_cast<long>(messageArgument));
|
||||||
|
|
||||||
|
// Allow idle sleep
|
||||||
|
IOAllowPowerChange(listener->rootPowerDomain, reinterpret_cast<long>(messageArgument));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kIOMessageSystemWillNotSleep:
|
||||||
|
/* Announces that the system has retracted a previous attempt to sleep; it
|
||||||
|
* follows `kIOMessageCanSystemSleep`.
|
||||||
|
*/
|
||||||
|
logger.debug() << "System power message: system will NOT sleep.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kIOMessageSystemWillSleep:
|
||||||
|
/* The system WILL go to sleep. If you do not call IOAllowPowerChange or
|
||||||
|
* IOCancelPowerChange to acknowledge this message, sleep will be delayed by
|
||||||
|
* 30 seconds.
|
||||||
|
*
|
||||||
|
* NOTE: If you call IOCancelPowerChange to deny sleep it returns kIOReturnSuccess,
|
||||||
|
* however the system WILL still go to sleep.
|
||||||
|
*/
|
||||||
|
|
||||||
|
logger.debug() << "System power message: system WILL sleep";
|
||||||
|
IOAllowPowerChange(listener->rootPowerDomain, reinterpret_cast<long>(messageArgument));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kIOMessageSystemWillPowerOn:
|
||||||
|
/* Announces that the system is beginning to power the device tree; most devices
|
||||||
|
* are still unavailable at this point.
|
||||||
|
*/
|
||||||
|
/* From the documentation:
|
||||||
|
*
|
||||||
|
* - kIOMessageSystemWillPowerOn is delivered at early wakeup time, before most hardware
|
||||||
|
* has been powered on. Be aware that any attempts to access disk, network, the display,
|
||||||
|
* etc. may result in errors or blocking your process until those resources become
|
||||||
|
* available.
|
||||||
|
*
|
||||||
|
* So we do NOT log this event.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kIOMessageSystemHasPoweredOn:
|
||||||
|
/* Announces that the system and its devices have woken up. */
|
||||||
|
logger.debug() << "System has powered on - emitting sleepMode signal from dedicated CFRunLoop thread";
|
||||||
|
if (listener->m_watcher) {
|
||||||
|
// Use QMetaObject::invokeMethod for thread-safe signal emission
|
||||||
|
QMetaObject::invokeMethod(listener->m_watcher, "sleepMode", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger.debug() << "System power message: other event: " << messageType;
|
||||||
|
/* Not a system sleep and wake notification. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MacOSNetworkWatcher::MacOSNetworkWatcher(QObject* parent) : IOSNetworkWatcher(parent), m_powerlistener(this) {
|
||||||
MZ_COUNT_CTOR(MacOSNetworkWatcher);
|
MZ_COUNT_CTOR(MacOSNetworkWatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
MacOSNetworkWatcher::~MacOSNetworkWatcher() {
|
MacOSNetworkWatcher::~MacOSNetworkWatcher() {
|
||||||
MZ_COUNT_DTOR(MacOSNetworkWatcher);
|
MZ_COUNT_DTOR(MacOSNetworkWatcher);
|
||||||
|
|
||||||
|
// Stop the dedicated power monitoring thread
|
||||||
|
if (g_powerListener) {
|
||||||
|
logger.debug() << "Stopping dedicated power monitoring thread";
|
||||||
|
g_shouldStopPowerThread = true;
|
||||||
|
|
||||||
|
if (g_powerRunLoop) {
|
||||||
|
CFRunLoopStop(g_powerRunLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for thread to finish
|
||||||
|
pthread_join(g_powerThread, nullptr);
|
||||||
|
g_powerListener = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_delegate) {
|
if (m_delegate) {
|
||||||
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
|
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
|
||||||
if (!client) {
|
if (!client) {
|
||||||
@@ -66,6 +228,20 @@ void MacOSNetworkWatcher::start() {
|
|||||||
logger.debug() << "Delegate already registered";
|
logger.debug() << "Delegate already registered";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start dedicated power monitoring thread with CFRunLoop
|
||||||
|
if (!g_powerListener) {
|
||||||
|
g_powerListener = &m_powerlistener;
|
||||||
|
g_shouldStopPowerThread = false;
|
||||||
|
|
||||||
|
int result = pthread_create(&g_powerThread, nullptr, powerMonitoringThread, &m_powerlistener);
|
||||||
|
if (result != 0) {
|
||||||
|
logger.error() << "Failed to create power monitoring thread:" << result;
|
||||||
|
g_powerListener = nullptr;
|
||||||
|
} else {
|
||||||
|
logger.debug() << "Power monitoring enabled";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
|
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
|
||||||
if (!client) {
|
if (!client) {
|
||||||
@@ -77,6 +253,8 @@ void MacOSNetworkWatcher::start() {
|
|||||||
m_delegate = [[MacOSNetworkWatcherDelegate alloc] initWithObject:this];
|
m_delegate = [[MacOSNetworkWatcherDelegate alloc] initWithObject:this];
|
||||||
[client setDelegate:static_cast<MacOSNetworkWatcherDelegate*>(m_delegate)];
|
[client setDelegate:static_cast<MacOSNetworkWatcherDelegate*>(m_delegate)];
|
||||||
[client startMonitoringEventWithType:CWEventTypeBSSIDDidChange error:nullptr];
|
[client startMonitoringEventWithType:CWEventTypeBSSIDDidChange error:nullptr];
|
||||||
|
|
||||||
|
logger.debug() << "MacOSNetworkWatcher started successfully";
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacOSNetworkWatcher::checkInterface() {
|
void MacOSNetworkWatcher::checkInterface() {
|
||||||
@@ -87,42 +265,70 @@ void MacOSNetworkWatcher::checkInterface() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
|
// Use wdutil to get reliable WiFi information
|
||||||
if (!client) {
|
QProcess process;
|
||||||
logger.debug() << "Unable to retrieve the CWWiFiClient shared instance";
|
process.start("wdutil", QStringList() << "info");
|
||||||
|
process.waitForFinished(5000);
|
||||||
|
|
||||||
|
QString output = process.readAllStandardOutput();
|
||||||
|
QString errorOutput = process.readAllStandardError();
|
||||||
|
|
||||||
|
logger.debug() << "wdutil exit code:" << process.exitCode();
|
||||||
|
|
||||||
|
if (process.exitCode() != 0) {
|
||||||
|
logger.debug() << "wdutil failed with exit code:" << process.exitCode();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CWInterface* interface = [client interface];
|
// Parse wdutil output to find WiFi connection info
|
||||||
if (!interface) {
|
QStringList lines = output.split('\n');
|
||||||
logger.debug() << "No default wifi interface";
|
QString ssid, interfaceName, security;
|
||||||
return;
|
bool wifiSectionFound = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
QString trimmedLine = lines[i].trimmed();
|
||||||
|
|
||||||
|
if (trimmedLine == "WIFI") {
|
||||||
|
wifiSectionFound = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wifiSectionFound) {
|
||||||
|
// Stop parsing when we reach next section header (all caps after separator line)
|
||||||
|
if (trimmedLine.startsWith("————————")) {
|
||||||
|
if (i + 1 < lines.size()) {
|
||||||
|
QString nextLine = lines[i + 1].trimmed();
|
||||||
|
if (!nextLine.isEmpty() && nextLine.length() > 2 && nextLine.toUpper() == nextLine && nextLine != "WIFI") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue; // Skip separator lines
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trimmedLine.startsWith("Interface Name")) {
|
||||||
|
QStringList parts = trimmedLine.split(":");
|
||||||
|
if (parts.size() >= 2) {
|
||||||
|
interfaceName = parts[1].trimmed();
|
||||||
|
}
|
||||||
|
} else if (trimmedLine.startsWith("SSID")) {
|
||||||
|
QStringList parts = trimmedLine.split(":");
|
||||||
|
if (parts.size() >= 2) {
|
||||||
|
ssid = parts[1].trimmed();
|
||||||
|
}
|
||||||
|
} else if (trimmedLine.startsWith("Security")) {
|
||||||
|
QStringList parts = trimmedLine.split(":");
|
||||||
|
if (parts.size() >= 2) {
|
||||||
|
security = parts[1].trimmed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (![interface powerOn]) {
|
if (!ssid.isEmpty() && !interfaceName.isEmpty()) {
|
||||||
logger.debug() << "The interface is off";
|
logger.debug() << "Found active WiFi connection on" << interfaceName
|
||||||
return;
|
<< "SSID:" << ssid << "Security:" << security;
|
||||||
|
} else {
|
||||||
|
logger.debug() << "No active WiFi connection found";
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* ssidNS = [interface ssid];
|
|
||||||
if (!ssidNS) {
|
|
||||||
logger.debug() << "WiFi is not in used";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ssid = QString::fromNSString(ssidNS);
|
|
||||||
if (ssid.isEmpty()) {
|
|
||||||
logger.debug() << "WiFi doesn't have a valid SSID";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CWSecurity security = [interface security];
|
|
||||||
if (security == kCWSecurityNone || security == kCWSecurityWEP) {
|
|
||||||
logger.debug() << "Unsecured network found!";
|
|
||||||
emit unsecuredNetwork(ssid, ssid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug() << "Secure WiFi interface";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "platforms/windows/daemon/windowsfirewall.h"
|
#include "platforms/windows/daemon/windowsfirewall.h"
|
||||||
#include "platforms/windows/daemon/windowssplittunnel.h"
|
#include "platforms/windows/daemon/windowssplittunnel.h"
|
||||||
#include "platforms/windows/windowscommons.h"
|
|
||||||
#include "windowsfirewall.h"
|
#include "windowsfirewall.h"
|
||||||
|
|
||||||
#include "core/networkUtilities.h"
|
#include "core/networkUtilities.h"
|
||||||
|
|||||||
@@ -32,9 +32,28 @@ WindowsNetworkWatcher::~WindowsNetworkWatcher() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LRESULT WindowsNetworkWatcher::PowerWndProcCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||||
|
auto obj = reinterpret_cast<WindowsNetworkWatcher*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||||
|
if (!obj){
|
||||||
|
logger.debug() << "obj not casted";
|
||||||
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
switch (uMsg) {
|
||||||
|
case WM_POWERBROADCAST:
|
||||||
|
if (wParam == PBT_APMRESUMESUSPEND) {
|
||||||
|
emit obj->sleepMode();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void WindowsNetworkWatcher::initialize() {
|
void WindowsNetworkWatcher::initialize() {
|
||||||
logger.debug() << "initialize";
|
logger.debug() << "initialize";
|
||||||
|
|
||||||
|
|
||||||
DWORD negotiatedVersion;
|
DWORD negotiatedVersion;
|
||||||
if (WlanOpenHandle(2, nullptr, &negotiatedVersion, &m_wlanHandle) !=
|
if (WlanOpenHandle(2, nullptr, &negotiatedVersion, &m_wlanHandle) !=
|
||||||
ERROR_SUCCESS) {
|
ERROR_SUCCESS) {
|
||||||
@@ -51,6 +70,25 @@ void WindowsNetworkWatcher::initialize() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wchar_t* className = L"PowerMonitorClass";
|
||||||
|
WNDCLASS wc = { 0 };
|
||||||
|
wc.lpfnWndProc = &WindowsNetworkWatcher::PowerWndProcCallback;
|
||||||
|
wc.hInstance = GetModuleHandle(NULL);
|
||||||
|
wc.lpszClassName = className;
|
||||||
|
wc.cbWndExtra = sizeof(WindowsNetworkWatcher*);
|
||||||
|
|
||||||
|
if (!RegisterClass(&wc)) {
|
||||||
|
logger.debug() << "Failed to register window class in createPowerMonitorWindow.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND hwnd = CreateWindowEx(0, className, L"Power Monitor", 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), static_cast<LPVOID>(this));
|
||||||
|
if (!hwnd) {
|
||||||
|
logger.debug() << "Failed to create window in createPowerMonitorWindow.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
||||||
|
|
||||||
logger.debug() << "callback registered";
|
logger.debug() << "callback registered";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,4 +175,4 @@ void WindowsNetworkWatcher::processWlan(PWLAN_NOTIFICATION_DATA data) {
|
|||||||
logger.debug() << "Unsecure network:" << logger.sensitive(ssid)
|
logger.debug() << "Unsecure network:" << logger.sensitive(ssid)
|
||||||
<< "id:" << logger.sensitive(bssid);
|
<< "id:" << logger.sensitive(bssid);
|
||||||
emit unsecuredNetwork(ssid, bssid);
|
emit unsecuredNetwork(ssid, bssid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class WindowsNetworkWatcher final : public NetworkWatcherImpl {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static void wlanCallback(PWLAN_NOTIFICATION_DATA data, PVOID context);
|
static void wlanCallback(PWLAN_NOTIFICATION_DATA data, PVOID context);
|
||||||
|
static LRESULT PowerWndProcCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
void processWlan(PWLAN_NOTIFICATION_DATA data);
|
void processWlan(PWLAN_NOTIFICATION_DATA data);
|
||||||
|
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ void WindowsPingSender::pingEventReady() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QString errmsg = WindowsUtils::getErrorMessage();
|
QString errmsg = WindowsUtils::getErrorMessage();
|
||||||
|
emit criticalPingError();
|
||||||
logger.error() << "No ping reply. Code: " << error
|
logger.error() << "No ping reply. Code: " << error
|
||||||
<< " Message: " << errmsg;
|
<< " Message: " << errmsg;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent)
|
|||||||
Ikev2Protocol::~Ikev2Protocol()
|
Ikev2Protocol::~Ikev2Protocol()
|
||||||
{
|
{
|
||||||
qDebug() << "IpsecProtocol::~IpsecProtocol()";
|
qDebug() << "IpsecProtocol::~IpsecProtocol()";
|
||||||
disconnect_vpn();
|
|
||||||
Ikev2Protocol::stop();
|
Ikev2Protocol::stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ void Ikev2Protocol::stop()
|
|||||||
{
|
{
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnecting);
|
setConnectionState(Vpn::ConnectionState::Disconnecting);
|
||||||
{
|
{
|
||||||
if (! disconnect_vpn() ){
|
if (!disconnect_vpn()){
|
||||||
qDebug()<<"We don't disconnect";
|
qDebug()<<"We don't disconnect";
|
||||||
setConnectionState(Vpn::ConnectionState::Error);
|
setConnectionState(Vpn::ConnectionState::Error);
|
||||||
}
|
}
|
||||||
@@ -311,7 +310,9 @@ bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name){
|
|||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
bool Ikev2Protocol::disconnect_vpn(){
|
bool Ikev2Protocol::disconnect_vpn(){
|
||||||
if ( hRasConn != nullptr ){
|
if ( hRasConn != nullptr ){
|
||||||
if ( RasHangUp(hRasConn) != ERROR_SUCCESS)
|
auto ret = RasHangUp(hRasConn);
|
||||||
|
qDebug() << "RasHangUp " << ret;
|
||||||
|
if (ret != ERROR_SUCCESS)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QThread::msleep(3000);
|
QThread::msleep(3000);
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ namespace amnezia
|
|||||||
|
|
||||||
constexpr char defaultPort[] = "51820";
|
constexpr char defaultPort[] = "51820";
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||||
constexpr char defaultMtu[] = "1280";
|
constexpr char defaultMtu[] = "1280";
|
||||||
#else
|
#else
|
||||||
constexpr char defaultMtu[] = "1376";
|
constexpr char defaultMtu[] = "1376";
|
||||||
@@ -212,7 +212,7 @@ namespace amnezia
|
|||||||
namespace awg
|
namespace awg
|
||||||
{
|
{
|
||||||
constexpr char defaultPort[] = "55424";
|
constexpr char defaultPort[] = "55424";
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||||
constexpr char defaultMtu[] = "1280";
|
constexpr char defaultMtu[] = "1280";
|
||||||
#else
|
#else
|
||||||
constexpr char defaultMtu[] = "1376";
|
constexpr char defaultMtu[] = "1376";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "core/errorstrings.h"
|
#include "core/errorstrings.h"
|
||||||
#include "vpnprotocol.h"
|
#include "vpnprotocol.h"
|
||||||
|
|
||||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (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 "openvpnovercloakprotocol.h"
|
||||||
#include "openvpnprotocol.h"
|
#include "openvpnprotocol.h"
|
||||||
#include "shadowsocksvpnprotocol.h"
|
#include "shadowsocksvpnprotocol.h"
|
||||||
@@ -103,13 +103,18 @@ QString VpnProtocol::vpnGateway() const
|
|||||||
return m_vpnGateway;
|
return m_vpnGateway;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString VpnProtocol::vpnLocalAddress() const
|
||||||
|
{
|
||||||
|
return m_vpnLocalAddress;
|
||||||
|
}
|
||||||
|
|
||||||
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &configuration)
|
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &configuration)
|
||||||
{
|
{
|
||||||
switch (container) {
|
switch (container) {
|
||||||
#if defined(Q_OS_WINDOWS)
|
#if defined(Q_OS_WINDOWS)
|
||||||
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
||||||
#endif
|
#endif
|
||||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (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::OpenVpn: return new OpenVpnProtocol(configuration);
|
||||||
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
|
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
|
||||||
case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration);
|
case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration);
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ public:
|
|||||||
|
|
||||||
QString routeGateway() const;
|
QString routeGateway() const;
|
||||||
QString vpnGateway() const;
|
QString vpnGateway() const;
|
||||||
|
QString vpnLocalAddress() const;
|
||||||
|
|
||||||
static VpnProtocol* factory(amnezia::DockerContainer container, const QJsonObject &configuration);
|
static VpnProtocol* factory(amnezia::DockerContainer container, const QJsonObject &configuration);
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *
|
|||||||
[this](const QString &pubkey, const QDateTime &connectionTimestamp) {
|
[this](const QString &pubkey, const QDateTime &connectionTimestamp) {
|
||||||
emit connectionStateChanged(Vpn::ConnectionState::Connected);
|
emit connectionStateChanged(Vpn::ConnectionState::Connected);
|
||||||
});
|
});
|
||||||
|
connect(m_impl.get(), &ControllerImpl::statusUpdated, this,
|
||||||
|
[this](const QString& serverIpv4Gateway,
|
||||||
|
const QString& deviceIpv4Address, uint64_t txBytes,
|
||||||
|
uint64_t rxBytes) {
|
||||||
|
m_vpnLocalAddress = deviceIpv4Address;
|
||||||
|
});
|
||||||
|
|
||||||
connect(m_impl.get(), &ControllerImpl::disconnected, this,
|
connect(m_impl.get(), &ControllerImpl::disconnected, this,
|
||||||
[this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); });
|
[this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); });
|
||||||
m_impl->initialize(nullptr, nullptr);
|
m_impl->initialize(nullptr, nullptr);
|
||||||
|
|||||||
@@ -127,7 +127,7 @@
|
|||||||
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
|
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
|
||||||
<file>ui/qml/Components/ServersListView.qml</file>
|
<file>ui/qml/Components/ServersListView.qml</file>
|
||||||
<file>ui/qml/Components/SettingsContainersListView.qml</file>
|
<file>ui/qml/Components/SettingsContainersListView.qml</file>
|
||||||
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
|
|
||||||
<file>ui/qml/Components/TransportProtoSelector.qml</file>
|
<file>ui/qml/Components/TransportProtoSelector.qml</file>
|
||||||
<file>ui/qml/Components/AddSitePanel.qml</file>
|
<file>ui/qml/Components/AddSitePanel.qml</file>
|
||||||
<file>ui/qml/Config/GlobalConfig.qml</file>
|
<file>ui/qml/Config/GlobalConfig.qml</file>
|
||||||
@@ -228,6 +228,7 @@
|
|||||||
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
|
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
|
||||||
<file>ui/qml/Pages2/PageShare.qml</file>
|
<file>ui/qml/Pages2/PageShare.qml</file>
|
||||||
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
|
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
|
||||||
|
<file>ui/qml/Pages2/PageShareConnection.qml</file>
|
||||||
<file>ui/qml/Pages2/PageStart.qml</file>
|
<file>ui/qml/Pages2/PageStart.qml</file>
|
||||||
<file>ui/qml/Components/RenameServerDrawer.qml</file>
|
<file>ui/qml/Components/RenameServerDrawer.qml</file>
|
||||||
<file>ui/qml/Controls2/ListViewType.qml</file>
|
<file>ui/qml/Controls2/ListViewType.qml</file>
|
||||||
@@ -240,6 +241,7 @@
|
|||||||
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
|
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
|
||||||
<file>ui/qml/Components/OtpCodeDrawer.qml</file>
|
<file>ui/qml/Components/OtpCodeDrawer.qml</file>
|
||||||
<file>ui/qml/Components/AwgTextField.qml</file>
|
<file>ui/qml/Components/AwgTextField.qml</file>
|
||||||
|
<file>ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/countriesFlags">
|
<qresource prefix="/countriesFlags">
|
||||||
<file>images/flagKit/ZW.svg</file>
|
<file>images/flagKit/ZW.svg</file>
|
||||||
|
|||||||
@@ -0,0 +1,519 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
LOG_DATE=$(date -u +'%Y%m%d-%H%M%S')
|
||||||
|
SCRIPT_DIR=$(dirname "$0")
|
||||||
|
LOG_FILE="${SCRIPT_DIR}/server-diagnostics-${LOG_DATE}.log"
|
||||||
|
|
||||||
|
# Logging function (sh compatible)
|
||||||
|
log_and_display() {
|
||||||
|
if [ "$1" = "-n" ]; then
|
||||||
|
shift
|
||||||
|
printf "%s" "$*" | tee -a "$LOG_FILE"
|
||||||
|
else
|
||||||
|
echo "$1" | tee -a "$LOG_FILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Redirect stderr to stdout for logging
|
||||||
|
exec 2>&1
|
||||||
|
|
||||||
|
header() {
|
||||||
|
log_and_display ""
|
||||||
|
log_and_display "=== $1 ==="
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pause for cancellation
|
||||||
|
log_and_display ""
|
||||||
|
log_and_display "VPN Server Diagnostics will start in 9s. Press Ctrl+C to cancel."
|
||||||
|
sleep 9
|
||||||
|
|
||||||
|
log_and_display ""
|
||||||
|
header "STARTING VPN SERVER DIAGNOSTICS"
|
||||||
|
log_and_display ""
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 1. Basic system information
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
header "System Information"
|
||||||
|
|
||||||
|
# Uptime
|
||||||
|
UPTIME_STR=$(awk '{printf "%d:%02d:%02d", int($1/3600), int(($1%3600)/60), int($1%60)}' /proc/uptime 2>/dev/null || echo "unknown")
|
||||||
|
log_and_display "Uptime (H:M:S): $UPTIME_STR"
|
||||||
|
|
||||||
|
# Date/time UTC
|
||||||
|
DATE_UTC=$(date -u +'%d %b %Y|%T' 2>/dev/null || echo "unknown")
|
||||||
|
log_and_display "Date|Time (UTC): $DATE_UTC"
|
||||||
|
|
||||||
|
# Init system (PID 1)
|
||||||
|
INIT_NAME=$(cat /proc/1/status 2>/dev/null | head -1 | awk '{print $2}' 2>/dev/null || echo "unknown")
|
||||||
|
log_and_display "Init system (PID 1): $INIT_NAME"
|
||||||
|
|
||||||
|
# Locale
|
||||||
|
if echo "$LANG" | grep -E '^(en_US.UTF-8|C.UTF-8|C)$' >/dev/null 2>&1; then
|
||||||
|
log_and_display "Locale: $LANG"
|
||||||
|
else
|
||||||
|
log_and_display "Locale: $LANG (not en_US.UTF-8, C.UTF-8 or C)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 2. Package manager detection
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
header "Package Manager Information"
|
||||||
|
|
||||||
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
|
log_and_display "Package Manager: APT"
|
||||||
|
PM="apt-get"
|
||||||
|
PM_VER_OPT="--version"
|
||||||
|
DOCKER_PKG="docker.io"
|
||||||
|
elif command -v dnf >/dev/null 2>&1; then
|
||||||
|
log_and_display "Package Manager: DNF"
|
||||||
|
PM="dnf"
|
||||||
|
PM_VER_OPT="--version"
|
||||||
|
DOCKER_PKG="docker"
|
||||||
|
elif command -v yum >/dev/null 2>&1; then
|
||||||
|
log_and_display "Package Manager: YUM"
|
||||||
|
PM="yum"
|
||||||
|
PM_VER_OPT="--version"
|
||||||
|
DOCKER_PKG="docker"
|
||||||
|
elif command -v zypper >/dev/null 2>&1; then
|
||||||
|
log_and_display "Package Manager: ZYPPER"
|
||||||
|
PM="zypper"
|
||||||
|
PM_VER_OPT="--version"
|
||||||
|
DOCKER_PKG="docker"
|
||||||
|
elif command -v pacman >/dev/null 2>&1; then
|
||||||
|
log_and_display "Package Manager: PACMAN"
|
||||||
|
PM="pacman"
|
||||||
|
PM_VER_OPT="--version"
|
||||||
|
DOCKER_PKG="docker"
|
||||||
|
elif command -v opkg >/dev/null 2>&1; then
|
||||||
|
log_and_display "Package Manager: OPKG - Not supported on this platform"
|
||||||
|
PM="opkg"
|
||||||
|
PM_VER_OPT="--version"
|
||||||
|
DOCKER_PKG="docker"
|
||||||
|
else
|
||||||
|
log_and_display "Package Manager: Unknown"
|
||||||
|
# fallback
|
||||||
|
PM="uname"
|
||||||
|
PM_VER_OPT="-a"
|
||||||
|
DOCKER_PKG="docker"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check package versions
|
||||||
|
log_and_display ""
|
||||||
|
log_and_display "Package versions:"
|
||||||
|
|
||||||
|
# Check sudo
|
||||||
|
if [ "$PM" = "apt-get" ]; then
|
||||||
|
sudo_version=$(dpkg -s "sudo" 2>/dev/null | grep '^Version:' | awk '{print $2}' || echo "not installed")
|
||||||
|
elif [ "$PM" = "dnf" ] || [ "$PM" = "yum" ] || [ "$PM" = "zypper" ]; then
|
||||||
|
sudo_version=$(rpm -q "sudo" 2>/dev/null || echo "not installed")
|
||||||
|
elif [ "$PM" = "pacman" ]; then
|
||||||
|
sudo_version=$(pacman -Q "sudo" 2>/dev/null || echo "not installed")
|
||||||
|
elif [ "$PM" = "opkg" ]; then
|
||||||
|
sudo_version=$(opkg info "sudo" 2>/dev/null | grep '^Version:' | awk '{print $2}' || echo "not installed")
|
||||||
|
else
|
||||||
|
sudo_version="unknown"
|
||||||
|
fi
|
||||||
|
log_and_display " sudo: $sudo_version"
|
||||||
|
|
||||||
|
# Check Docker package
|
||||||
|
if [ "$PM" = "apt-get" ]; then
|
||||||
|
docker_pkg_version=$(dpkg -s "$DOCKER_PKG" 2>/dev/null | grep '^Version:' | awk '{print $2}' || echo "not installed")
|
||||||
|
elif [ "$PM" = "dnf" ] || [ "$PM" = "yum" ] || [ "$PM" = "zypper" ]; then
|
||||||
|
docker_pkg_version=$(rpm -q "$DOCKER_PKG" 2>/dev/null || echo "not installed")
|
||||||
|
elif [ "$PM" = "pacman" ]; then
|
||||||
|
docker_pkg_version=$(pacman -Q "$DOCKER_PKG" 2>/dev/null || echo "not installed")
|
||||||
|
elif [ "$PM" = "opkg" ]; then
|
||||||
|
docker_pkg_version=$(opkg info "$DOCKER_PKG" 2>/dev/null | grep '^Version:' | awk '{print $2}' || echo "not installed")
|
||||||
|
else
|
||||||
|
docker_pkg_version="unknown"
|
||||||
|
fi
|
||||||
|
log_and_display " $DOCKER_PKG: $docker_pkg_version"
|
||||||
|
|
||||||
|
# Check lsof
|
||||||
|
if [ "$PM" = "apt-get" ]; then
|
||||||
|
lsof_version=$(dpkg -s "lsof" 2>/dev/null | grep '^Version:' | awk '{print $2}' || echo "not installed")
|
||||||
|
elif [ "$PM" = "dnf" ] || [ "$PM" = "yum" ] || [ "$PM" = "zypper" ]; then
|
||||||
|
lsof_version=$(rpm -q "lsof" 2>/dev/null || echo "not installed")
|
||||||
|
elif [ "$PM" = "pacman" ]; then
|
||||||
|
lsof_version=$(pacman -Q "lsof" 2>/dev/null || echo "not installed")
|
||||||
|
elif [ "$PM" = "opkg" ]; then
|
||||||
|
lsof_version=$(opkg info "lsof" 2>/dev/null | grep '^Version:' | awk '{print $2}' || echo "not installed")
|
||||||
|
else
|
||||||
|
lsof_version="unknown"
|
||||||
|
fi
|
||||||
|
log_and_display " lsof: $lsof_version"
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 3. Additional system information (hostnamectl / /proc/version)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
header "OS / Kernel Information"
|
||||||
|
|
||||||
|
if command -v hostnamectl >/dev/null 2>&1; then
|
||||||
|
hostnamectl 2>/dev/null | grep -E 'Operating System:|Virtualization:|Kernel:|Architecture:' | sed 's/^[ \t]*//;s/:/: /' | while read line; do
|
||||||
|
log_and_display " $line"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
log_and_display "Operating System: $(cat /proc/version 2>/dev/null || echo 'unknown')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# CPU threads
|
||||||
|
CPU_THREADS=$(nproc 2>/dev/null || grep -c "^processor" /proc/cpuinfo 2>/dev/null || echo "unknown")
|
||||||
|
log_and_display " CPU threads: $CPU_THREADS"
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 4. Memory (RAM) check
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
header "Memory Information"
|
||||||
|
|
||||||
|
if command -v free >/dev/null 2>&1; then
|
||||||
|
# Remove extra spaces in header
|
||||||
|
free -h 2>/dev/null | tee -a "$LOG_FILE" || log_and_display " Error getting memory info"
|
||||||
|
elif command -v vmstat >/dev/null 2>&1; then
|
||||||
|
vmstat -S M -s 2>/dev/null | grep -iE 'total memory|total swap' | sed 's/ *//' | tee -a "$LOG_FILE" || log_and_display " Error getting memory info"
|
||||||
|
else
|
||||||
|
grep -iE 'MemTotal|SwapTotal' /proc/meminfo 2>/dev/null | sed 's/ \+/ /' | tee -a "$LOG_FILE" || log_and_display " Error getting memory info"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v free >/dev/null 2>&1; then
|
||||||
|
log_and_display ""
|
||||||
|
log_and_display "Detailed Memory Info:"
|
||||||
|
free -h 2>/dev/null | awk 'NR==2{printf " Used: %s / %s (%.1f%%)\n", $3, $2, $3/$2*100}' 2>/dev/null | tee -a "$LOG_FILE" || log_and_display " Error calculating memory usage"
|
||||||
|
free -h 2>/dev/null | awk 'NR==3{printf " Swap: %s / %s (%.1f%%)\n", $3, $2, $2>0 ? $3/$2*100 : 0}' 2>/dev/null | tee -a "$LOG_FILE" || log_and_display " Error calculating swap usage"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Disk usage
|
||||||
|
header "Disk Usage"
|
||||||
|
df -h 2>/dev/null | awk '
|
||||||
|
BEGIN {print " Filesystem Size Used Avail Use% Mounted"}
|
||||||
|
NR>1 {printf " %-10s %5s %5s %5s %4s %s\n", $1, $2, $3, $4, $5, $6}' | tee -a "$LOG_FILE" || log_and_display " Error getting disk usage"
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 5. Current user and sudo check
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
header "User Check"
|
||||||
|
|
||||||
|
CUR_USER=$(whoami 2>/dev/null || echo ~ | sed 's/.*\///')
|
||||||
|
USER_GROUP=$(groups "$CUR_USER" 2>/dev/null || echo "")
|
||||||
|
USER_GOOD=0
|
||||||
|
|
||||||
|
log_and_display -n "Current user: $CUR_USER => "
|
||||||
|
|
||||||
|
if [ "$CUR_USER" = "root" ]; then
|
||||||
|
log_and_display "passed.. (is root)"
|
||||||
|
USER_GOOD="r" # root
|
||||||
|
else
|
||||||
|
if echo "$USER_GROUP" | grep -qE '(^|[[:space:]])sudo($|[[:space:]])'; then
|
||||||
|
log_and_display "passed.. (in sudo group)"
|
||||||
|
USER_GOOD=1
|
||||||
|
elif echo "$USER_GROUP" | grep -qE '(^|[[:space:]])wheel($|[[:space:]])'; then
|
||||||
|
log_and_display "passed.. (in wheel group)"
|
||||||
|
USER_GOOD=1
|
||||||
|
elif echo "$USER_GROUP" | grep -qE '(^|[[:space:]])docker($|[[:space:]])'; then
|
||||||
|
log_and_display "failed.. (only in docker group)"
|
||||||
|
USER_GOOD="d"
|
||||||
|
else
|
||||||
|
log_and_display "failed.. (not a member of the sudo or wheel groups)"
|
||||||
|
USER_GOOD=0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if password is required for sudo
|
||||||
|
if [ "$USER_GOOD" = "0" ] || [ "$USER_GOOD" = "d" ]; then
|
||||||
|
log_and_display -n "Passwd request: "
|
||||||
|
log_and_display "check skipped (not sudoer)"
|
||||||
|
else
|
||||||
|
if command -v sudo >/dev/null 2>&1; then
|
||||||
|
# Try sudo without password - more thorough check
|
||||||
|
PASSWD_REQUEST=$(sudo -K 2>&1 && sudo -nu $CUR_USER $PM $PM_VER_OPT 2>&1 >/dev/null && sudo -n $PM $PM_VER_OPT 2>&1 >/dev/null)
|
||||||
|
if [ -n "$PASSWD_REQUEST" ]; then
|
||||||
|
USER_GOOD=0
|
||||||
|
log_and_display -n "Passwd request: "
|
||||||
|
log_and_display "failed.. ($PASSWD_REQUEST)" \
|
||||||
|
| sed "s/$CUR_USER/User/g;s/$(hostname 2>/dev/null || echo 'Server')/Server/g;s/ user / /g"
|
||||||
|
else
|
||||||
|
log_and_display -n "Passwd request: "
|
||||||
|
log_and_display "passed.. (not required)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$USER_GOOD" = "r" ]; then
|
||||||
|
log_and_display -n "Passwd request: "
|
||||||
|
log_and_display "check skipped (sudo not installed, but root user)"
|
||||||
|
else
|
||||||
|
log_and_display "Warning! The sudo package must be pre-installed!"
|
||||||
|
USER_GOOD=0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Home directory check
|
||||||
|
log_and_display -n "Home dir: "
|
||||||
|
if cd ~ 2>/dev/null; then
|
||||||
|
log_and_display "passed.. (accessible)"
|
||||||
|
else
|
||||||
|
log_and_display "failed.. (not accessible)"
|
||||||
|
fi
|
||||||
|
log_and_display "Default shell: $SHELL"
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 6. Important components check (sudo, lsof, fuser, apparmor)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
header "Component Checks"
|
||||||
|
|
||||||
|
log_and_display -n " sudo: "
|
||||||
|
if command -v sudo >/dev/null 2>&1; then
|
||||||
|
log_and_display "passed.. (installed)"
|
||||||
|
else
|
||||||
|
log_and_display "not installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_and_display -n " lsof: "
|
||||||
|
if command -v lsof >/dev/null 2>&1; then
|
||||||
|
log_and_display "passed.. (installed)"
|
||||||
|
else
|
||||||
|
log_and_display "not installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_and_display -n " fuser: "
|
||||||
|
if command -v fuser >/dev/null 2>&1; then
|
||||||
|
log_and_display "passed.. (installed)"
|
||||||
|
else
|
||||||
|
log_and_display "psmisc not installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_and_display -n "apparmor: "
|
||||||
|
AA_ENABLED=$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null || echo "N")
|
||||||
|
if [ "$AA_ENABLED" = "Y" ]; then
|
||||||
|
if command -v apparmor_parser >/dev/null 2>&1; then
|
||||||
|
log_and_display "passed.. (used)"
|
||||||
|
else
|
||||||
|
log_and_display "failed.. (installation required)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if command -v apparmor_parser >/dev/null 2>&1; then
|
||||||
|
log_and_display "passed.. (not used)"
|
||||||
|
else
|
||||||
|
log_and_display "passed.. (not required)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 7. SELinux check
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
header "SELinux Check"
|
||||||
|
|
||||||
|
if command -v getenforce >/dev/null 2>&1; then
|
||||||
|
SELINUX_STATUS=$(getenforce 2>/dev/null || echo "unknown")
|
||||||
|
if [ "$SELINUX_STATUS" = "Enforcing" ]; then
|
||||||
|
log_and_display "SELinux status: $SELINUX_STATUS (strict mode)"
|
||||||
|
elif [ "$SELINUX_STATUS" = "Permissive" ]; then
|
||||||
|
log_and_display "SELinux status: $SELINUX_STATUS (permissive mode)"
|
||||||
|
else
|
||||||
|
log_and_display "SELinux status: $SELINUX_STATUS (disabled)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_and_display "SELinux: not found (or not applicable)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 8. Docker + Docker/Podman service check
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
header "Docker / Podman Status"
|
||||||
|
CHECK_CONTAINERS=0
|
||||||
|
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
log_and_display "Docker: $DOCKER_PKG not installed"
|
||||||
|
else
|
||||||
|
# If user is in sudoers, use sudo without password
|
||||||
|
if [ "$USER_GOOD" = "1" ]; then
|
||||||
|
SUD="sudo -n"
|
||||||
|
elif [ "$USER_GOOD" = "r" ]; then
|
||||||
|
SUD="" # root
|
||||||
|
else
|
||||||
|
SUD=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
DOCKER_VERSION=$($SUD docker -v 2>/dev/null || echo 'docker -v error')
|
||||||
|
log_and_display "Installed: $DOCKER_VERSION"
|
||||||
|
|
||||||
|
# Check for podman
|
||||||
|
if echo "$DOCKER_VERSION" | grep -qi "podman"; then
|
||||||
|
log_and_display " WARNING: Podman detected - not supported at the moment!"
|
||||||
|
log_and_display " Podman (podman-docker) is not supported and is installed by mistake"
|
||||||
|
docker_service="podman.socket"
|
||||||
|
else
|
||||||
|
docker_service="docker.service"
|
||||||
|
fi
|
||||||
|
log_and_display " service: $docker_service"
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
docker_status=$(systemctl is-active "$docker_service" 2>/dev/null || echo "unknown")
|
||||||
|
docker_loading=$(systemctl is-enabled "$docker_service" 2>/dev/null || echo "unknown")
|
||||||
|
else
|
||||||
|
docker_status="unknown (systemctl not found)"
|
||||||
|
docker_loading="unknown"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$docker_status" = "active" ]; then
|
||||||
|
log_and_display " status: passed.. ($docker_status)"
|
||||||
|
CHECK_CONTAINERS=1
|
||||||
|
else
|
||||||
|
log_and_display " status: incorrect.. ($docker_status)"
|
||||||
|
CHECK_CONTAINERS=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$docker_loading" = "enabled" ]; then
|
||||||
|
log_and_display " loading: good (startup $docker_loading)"
|
||||||
|
else
|
||||||
|
log_and_display " loading: bad (startup $docker_loading)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 9. Docker pull test + container check with improved Docker Hub verification
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
header "Docker Hub: pull hello-world test"
|
||||||
|
|
||||||
|
if [ "$CHECK_CONTAINERS" = "1" ] && [ "$USER_GOOD" != "0" ]; then
|
||||||
|
# First check Docker Hub availability
|
||||||
|
log_and_display "Checking Docker Hub connectivity..."
|
||||||
|
|
||||||
|
# Try to execute docker pull with timeout
|
||||||
|
if timeout 30 $SUD docker pull docker.io/library/hello-world >/dev/null 2>&1; then
|
||||||
|
log_and_display "Docker Hub: available"
|
||||||
|
|
||||||
|
# Start container for testing
|
||||||
|
if $SUD docker run --rm docker.io/library/hello-world >/dev/null 2>&1; then
|
||||||
|
log_and_display "Hello-world container: successfully started and completed"
|
||||||
|
else
|
||||||
|
log_and_display "Hello-world container: startup error"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_and_display "Docker Hub: unavailable or blocked (possibly exceeded download limit)"
|
||||||
|
log_and_display "Docker Hub has download limits, try again later"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_and_display ""
|
||||||
|
total_cont=$($SUD docker ps -aq 2>/dev/null | wc -l || echo "0")
|
||||||
|
active_cont=$($SUD docker ps -q 2>/dev/null | wc -l || echo "0")
|
||||||
|
amnezia_cont=$($SUD docker ps -a 2>/dev/null | grep -c amnezia || echo "0")
|
||||||
|
|
||||||
|
log_and_display "Containers check: Total $total_cont / Active $active_cont / Amnezia $amnezia_cont"
|
||||||
|
$SUD docker ps -a --format "{{.Names}} ({{.Image}}) ({{.Status}}) ({{.Ports}})" 2>/dev/null | grep amnezia || true
|
||||||
|
|
||||||
|
# Peers check
|
||||||
|
if $SUD docker ps 2>/dev/null | grep -qE '\<(amnezia-awg|amnezia-wireguard)\>'; then
|
||||||
|
log_and_display ""
|
||||||
|
log_and_display "Peers check (beta):"
|
||||||
|
if $SUD docker ps 2>/dev/null | grep -q amnezia-awg; then
|
||||||
|
AMNEZIA_WG_CONTAINER=$($SUD docker ps 2>/dev/null | grep amnezia-awg | awk '{print $1}' | head -1)
|
||||||
|
if [ -n "$AMNEZIA_WG_CONTAINER" ]; then
|
||||||
|
WG_PEERS=$($SUD docker exec -it "$AMNEZIA_WG_CONTAINER" wg show 2>/dev/null | grep -c 'peer' || echo "0")
|
||||||
|
log_and_display "AmneziaWG peers: $WG_PEERS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if $SUD docker ps 2>/dev/null | grep -q amnezia-wireguard; then
|
||||||
|
WIREGUARD_CONTAINER=$($SUD docker ps 2>/dev/null | grep amnezia-wireguard | awk '{print $1}' | head -1)
|
||||||
|
if [ -n "$WIREGUARD_CONTAINER" ]; then
|
||||||
|
WG_PEERS=$($SUD docker exec -it "$WIREGUARD_CONTAINER" wg show 2>/dev/null | grep -c 'peer' || echo "0")
|
||||||
|
log_and_display "WireGuard peers: $WG_PEERS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_and_display "skipped.."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 10. Additional improvements
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# 10.1. CPU and memory load check (Load average, top processes)
|
||||||
|
#
|
||||||
|
header "CPU & Memory usage (top)"
|
||||||
|
|
||||||
|
# Load average (last 1,5,15 minutes)
|
||||||
|
LOAD_AVG=$(uptime 2>/dev/null | awk -F'load average:' '{print $2}' || echo "unknown")
|
||||||
|
log_and_display "Load average: $LOAD_AVG"
|
||||||
|
|
||||||
|
log_and_display ""
|
||||||
|
log_and_display "Top 5 processes by CPU:"
|
||||||
|
ps aux 2>/dev/null | sort -k3 -nr | head -n 6 | awk '{printf "%s %s %s %s %s\n", $1,$2,$3"%",$4"%",$11}' | column -t 2>/dev/null | tee -a "$LOG_FILE" || log_and_display " Error getting CPU processes"
|
||||||
|
|
||||||
|
log_and_display ""
|
||||||
|
log_and_display "Top 5 processes by MEM:"
|
||||||
|
ps aux 2>/dev/null | sort -k4 -nr | head -n 6 | awk '{printf "%s %s %s %s %s\n", $1,$2,$3"%",$4"%",$11}' | column -t 2>/dev/null | tee -a "$LOG_FILE" || log_and_display " Error getting MEM processes"
|
||||||
|
|
||||||
|
# 10.2. System logs check (latest critical messages)
|
||||||
|
header "Last 10 critical/error messages (journalctl)"
|
||||||
|
|
||||||
|
if command -v journalctl >/dev/null 2>&1; then
|
||||||
|
journalctl -p 3 -n 10 --no-pager 2>/dev/null | tee -a "$LOG_FILE" || log_and_display " Error getting system logs"
|
||||||
|
else
|
||||||
|
log_and_display "journalctl not found (non-systemd system?)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 10.3. System package versions check (examples)
|
||||||
|
|
||||||
|
# Open ports check
|
||||||
|
header "Network Ports Check"
|
||||||
|
if command -v netstat >/dev/null 2>&1; then
|
||||||
|
log_and_display "Listening ports:"
|
||||||
|
netstat -tlnp 2>/dev/null | grep LISTEN | head -10 | while read line; do
|
||||||
|
log_and_display " $line"
|
||||||
|
done
|
||||||
|
elif command -v ss >/dev/null 2>&1; then
|
||||||
|
log_and_display "Listening ports:"
|
||||||
|
ss -tlnp 2>/dev/null | head -10 | while read line; do
|
||||||
|
log_and_display " $line"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
log_and_display "netstat/ss not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# SSH check
|
||||||
|
header "SSH Service Check"
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
ssh_status=$(systemctl is-active ssh 2>/dev/null || systemctl is-active sshd 2>/dev/null || echo "not found")
|
||||||
|
if [ "$ssh_status" = "active" ]; then
|
||||||
|
log_and_display "SSH service: $ssh_status"
|
||||||
|
else
|
||||||
|
log_and_display "SSH service: $ssh_status"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_and_display "systemctl not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Time check
|
||||||
|
header "Time Synchronization"
|
||||||
|
if command -v timedatectl >/dev/null 2>&1; then
|
||||||
|
timedatectl status 2>/dev/null | grep -E "System clock|NTP service" | while read line; do
|
||||||
|
log_and_display " $line"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
log_and_display " System time: $(date 2>/dev/null || echo 'unknown')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Kernel check
|
||||||
|
header "Kernel Information"
|
||||||
|
log_and_display "Kernel version: $(uname -r 2>/dev/null || echo 'unknown')"
|
||||||
|
log_and_display "Kernel architecture: $(uname -m 2>/dev/null || echo 'unknown')"
|
||||||
|
if [ -f /proc/cmdline ]; then
|
||||||
|
log_and_display "Kernel parameters:"
|
||||||
|
cat /proc/cmdline 2>/dev/null | tr ' ' '\n' | head -5 | while read param; do
|
||||||
|
log_and_display " $param"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Completion
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
log_and_display ""
|
||||||
|
header "FINISH"
|
||||||
|
log_and_display ""
|
||||||
|
log_and_display "Diagnostics completed. Log saved to: $LOG_FILE"
|
||||||
|
log_and_display ""
|
||||||
|
|
||||||
|
# Variable cleanup
|
||||||
|
pm="" && opt="" && docker_pkg="" && CUR_USER="" && USER_GOOD="" && USER_GROUP="" && PASSWD_REQUEST="" && CHECK_CONTAINERS="" && SUD="" && docker_service="" && docker_status="" && docker_loading=""
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
FROM alpine:3.15
|
FROM alpine:3.15
|
||||||
LABEL maintainer="AmneziaVPN"
|
LABEL maintainer="AmneziaVPN"
|
||||||
|
|
||||||
ARG XRAY_RELEASE="v1.8.6"
|
ARG XRAY_RELEASE="v25.8.3"
|
||||||
|
|
||||||
RUN apk add --no-cache curl unzip bash openssl netcat-openbsd dumb-init rng-tools xz
|
RUN apk add --no-cache curl unzip bash openssl netcat-openbsd dumb-init rng-tools xz
|
||||||
RUN apk --update upgrade --no-cache
|
RUN apk --update upgrade --no-cache
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ public:
|
|||||||
|
|
||||||
QLocale getAppLanguage()
|
QLocale getAppLanguage()
|
||||||
{
|
{
|
||||||
QString localeStr = m_settings.value("Conf/appLanguage").toString();
|
QString localeStr = m_settings.value("Conf/appLanguage", QLocale::system().name()).toString();
|
||||||
return QLocale(localeStr);
|
return QLocale(localeStr);
|
||||||
};
|
};
|
||||||
void setAppLanguage(QLocale locale)
|
void setAppLanguage(QLocale locale)
|
||||||
|
|||||||