diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 35e740b0..2f24ee9a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -16,10 +16,7 @@ jobs: QT_VERSION: 6.6.2 QIF_VERSION: 4.7 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 }} steps: - name: 'Install Qt' @@ -86,10 +83,7 @@ jobs: QIF_VERSION: 4.7 BUILD_ARCH: 64 PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} - PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }} DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }} - DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }} - DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }} steps: - name: 'Get sources' @@ -145,23 +139,20 @@ jobs: # ------------------------------------------------------ Build-iOS: - runs-on: macos-13 + runs-on: macos-latest env: - QT_VERSION: 6.6.2 + QT_VERSION: 6.8.0 CC: cc CXX: c++ 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 }} steps: - name: 'Setup xcode' uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '15.2' + xcode-version: '15.4.0' - name: 'Install desktop Qt' uses: jurplel/install-qt-action@v3 @@ -217,11 +208,7 @@ jobs: export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/ios/bin" export QT_MACOS_ROOT_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos" export PATH=$PATH:~/go/bin - sh deploy/build_ios.sh | \ - sed -e '/-Xcc -DPROD_AGW_PUBLIC_KEY/,/-Xcc/ { /-Xcc/!d; }' -e '/-Xcc -DPROD_AGW_PUBLIC_KEY/d' | \ - sed -e '/-Xcc -DDEV_AGW_PUBLIC_KEY/,/-Xcc/ { /-Xcc/!d; }' -e '/-Xcc -DDEV_AGW_PUBLIC_KEY/d' | \ - sed -e '/-DPROD_AGW_PUBLIC_KEY/,/-D/ { /-D/!d; }' -e '/-DPROD_AGW_PUBLIC_KEY/d' | \ - sed -e '/-DDEV_AGW_PUBLIC_KEY/,/-D/ { /-D/!d; }' -e '/-DDEV_AGW_PUBLIC_KEY/d' + sh deploy/build_ios.sh env: IOS_TRUST_CERT_BASE64: ${{ secrets.IOS_TRUST_CERT_BASE64 }} IOS_SIGNING_CERT_BASE64: ${{ secrets.IOS_SIGNING_CERT_BASE64 }} @@ -248,19 +235,16 @@ jobs: env: # Keep compat with MacOS 10.15 aka Catalina by Qt 6.4 - QT_VERSION: 6.4.3 + QT_VERSION: 6.8.0 QIF_VERSION: 4.6 PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} - PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }} DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }} - DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }} - DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }} steps: - name: 'Setup xcode' uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '15.4.0' + xcode-version: '16.1.0' - name: 'Install Qt' uses: jurplel/install-qt-action@v3 @@ -310,6 +294,78 @@ jobs: path: deploy/build/client/AmneziaVPN.app retention-days: 7 +# ------------------------------------------------------ + Build-MacOS-NE: + runs-on: macos-latest + + env: + QT_VERSION: 6.8.0 + QIF_VERSION: 4.6 + QT_MIRROR: https://mirrors.ocf.berkeley.edu/qt/ + PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} + DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }} + + steps: + - name: 'Setup Xcode' + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '16.1.0' + + - name: 'Install desktop Qt' + uses: jurplel/install-qt-action@v3 + with: + version: ${{ env.QT_VERSION }} + host: 'mac' + target: 'desktop' + modules: 'qtremoteobjects qt5compat qtshadertools qtmultimedia qtimageformats' + arch: 'clang_64' + dir: ${{ runner.temp }} + set-env: 'true' + extra: '--base ${{ env.QT_MIRROR }}' + - name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}' + run: | + mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework + wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip + unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/ + - name: 'Install Go' + uses: actions/setup-go@v5 + with: + go-version: '1.22.1' + cache: false + + - name: 'Get sources' + uses: actions/checkout@v4 + with: + submodules: 'true' + fetch-depth: 10 + + - name: 'Install dependencies' + run: pip install jsonschema jinja2 + + - name: 'Set execute permissions for deploy script' + run: chmod +x deploy/build_macos_ne.sh + + - name: 'Build and deploy macOS NE' + run: | + export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin" + export QT_MACOS_ROOT_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos" + bash deploy/build_macos_ne.sh + env: + MAC_TRUST_CERT_BASE64: ${{ secrets.MAC_TRUST_CERT_BASE64 }} + MAC_SIGNING_CERT_BASE64: ${{ secrets.MAC_SIGNING_CERT_BASE64 }} + MAC_SIGNING_CERT_PASSWORD: ${{ secrets.MAC_SIGNING_CERT_PASSWORD }} + APPSTORE_CONNECT_MAC_PROVISIONING_BASE64: ${{ secrets.APPSTORE_CONNECT_MAC_PROVISIONING }} + APPSTORE_CONNECT_MAC_NE_PROVISIONING_BASE64: ${{ secrets.APPSTORE_CONNECT_MAC_NE_PROVISIONING }} + APPSTORE_CONNECT_KEY_ID: ${{ secrets.APPSTORE_CONNECT_KEY_ID }} + APPSTORE_CONNECT_ISSUER_ID: ${{ secrets.APPSTORE_CONNECT_ISSUER_ID }} + APPSTORE_CONNECT_PRIVATE_KEY: ${{ secrets.APPSTORE_CONNECT_PRIVATE_KEY }} + - name: 'Upload macOS .dmg and dSYMs to artifacts' + uses: actions/upload-artifact@v4 + with: + name: macos dmg & dsyms + path: | + ${{ github.workspace }}/AmneziaVPN.dmg + retention-days: 7 # ------------------------------------------------------ Build-Android: @@ -317,13 +373,10 @@ jobs: env: ANDROID_BUILD_PLATFORM: android-34 - QT_VERSION: 6.7.3 + QT_VERSION: 6.7.2 QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools' 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 }} steps: - name: 'Install desktop Qt' @@ -335,8 +388,7 @@ jobs: arch: 'linux_gcc_64' modules: ${{ env.QT_MODULES }} dir: ${{ runner.temp }} - py7zrversion: '==0.22.*' - extra: '--base ${{ env.QT_MIRROR }}' + extra: '--external 7z --base ${{ env.QT_MIRROR }}' - name: 'Install android_x86_64 Qt' uses: jurplel/install-qt-action@v4 @@ -347,8 +399,7 @@ jobs: arch: 'android_x86_64' modules: ${{ env.QT_MODULES }} dir: ${{ runner.temp }} - py7zrversion: '==0.22.*' - extra: '--base ${{ env.QT_MIRROR }}' + extra: '--external 7z --base ${{ env.QT_MIRROR }}' - name: 'Install android_x86 Qt' uses: jurplel/install-qt-action@v4 @@ -359,8 +410,7 @@ jobs: arch: 'android_x86' modules: ${{ env.QT_MODULES }} dir: ${{ runner.temp }} - py7zrversion: '==0.22.*' - extra: '--base ${{ env.QT_MIRROR }}' + extra: '--external 7z --base ${{ env.QT_MIRROR }}' - name: 'Install android_armv7 Qt' uses: jurplel/install-qt-action@v4 @@ -371,8 +421,7 @@ jobs: arch: 'android_armv7' modules: ${{ env.QT_MODULES }} dir: ${{ runner.temp }} - py7zrversion: '==0.22.*' - extra: '--base ${{ env.QT_MIRROR }}' + extra: '--external 7z --base ${{ env.QT_MIRROR }}' - name: 'Install android_arm64_v8a Qt' uses: jurplel/install-qt-action@v4 @@ -383,8 +432,7 @@ jobs: arch: 'android_arm64_v8a' modules: ${{ env.QT_MODULES }} dir: ${{ runner.temp }} - py7zrversion: '==0.22.*' - extra: '--base ${{ env.QT_MIRROR }}' + extra: '--external 7z --base ${{ env.QT_MIRROR }}' - name: 'Grant execute permission for qt-cmake' shell: bash @@ -485,4 +533,4 @@ jobs: if: ${{ fromJSON(steps.pull_request.outputs.data)[0].number != '' }} run: | echo "Pull request:" >> $GITHUB_STEP_SUMMARY - echo "[[#${{ fromJSON(steps.pull_request.outputs.data)[0].number }}] ${{ fromJSON(steps.pull_request.outputs.data)[0].title }}](${{ fromJSON(steps.pull_request.outputs.data)[0].html_url }})" >> $GITHUB_STEP_SUMMARY + echo "[[#${{ fromJSON(steps.pull_request.outputs.data)[0].number }}] ${{ fromJSON(steps.pull_request.outputs.data)[0].title }}](${{ fromJSON(steps.pull_request.outputs.data)[0].html_url }})" >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 98397bbb..09c16eeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,13 +31,13 @@ set(QT_BUILD_TOOLS_WHEN_CROSS_COMPILING ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -if(APPLE AND NOT IOS) - set(CMAKE_OSX_ARCHITECTURES "x86_64") +if((APPLE AND NOT IOS) OR (DEFINED MACOS_NE AND MACOS_NE AND NOT IOS)) + set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64") endif() add_subdirectory(client) -if(NOT IOS AND NOT ANDROID) +if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE) add_subdirectory(service) include(${CMAKE_SOURCE_DIR}/deploy/installer/config.cmake) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 5871cbca..f713222d 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -25,17 +25,13 @@ execute_process( add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}") add_definitions(-DPROD_AGW_PUBLIC_KEY="$ENV{PROD_AGW_PUBLIC_KEY}") -add_definitions(-DPROD_S3_ENDPOINT="$ENV{PROD_S3_ENDPOINT}") +add_definitions(-DPROD_PROXY_STORAGE_KEY="$ENV{PROD_PROXY_STORAGE_KEY}") add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}") add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}") -add_definitions(-DDEV_S3_ENDPOINT="$ENV{DEV_S3_ENDPOINT}") -if(IOS) - set(PACKAGES ${PACKAGES} Multimedia) -endif() - -if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID)) +#Macos Network Extension doesn't need Widgets +if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID) OR (NOT MACOS_NE)) set(PACKAGES ${PACKAGES} Widgets) endif() @@ -48,18 +44,16 @@ set(LIBS ${LIBS} Qt6::Core5Compat Qt6::Concurrent ) -if(IOS) - set(LIBS ${LIBS} Qt6::Multimedia) -endif() - -if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID)) +#Macos Network Extension doesn't need Widgets +if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID) OR (APPLE AND NOT MACOS_NE)) set(LIBS ${LIBS} Qt6::Widgets) endif() qt_standard_project_setup() qt_add_executable(${PROJECT} MANUAL_FINALIZATION) -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("Run this block when MACOS_NE is not defined or set to FALSE") qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep) qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_interface.rep) qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_tun2socks.rep) @@ -96,6 +90,19 @@ configure_file(${CMAKE_CURRENT_LIST_DIR}/translations/translations.qrc.in ${CMAK qt6_add_resources(QRC ${I18NQRC} ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc) # -- i18n end +if(IOS) + message("Building for iOS") + execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/ios/scripts/openvpn.sh args + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) +endif() + +# Build openvpn adapter for MacOS Network Extension +if(MACOS_NE) + message("Building for MacOS Network Extension") + execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/macos/scripts/openvpn.sh args + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) +endif() + set(IS_CI ${CI}) if(IS_CI) message("Detected CI env") @@ -141,7 +148,6 @@ set(HEADERS ${HEADERS} ${CMAKE_CURRENT_LIST_DIR}/core/serialization/transfer.h ${CMAKE_CURRENT_LIST_DIR}/core/enums/apiEnums.h ${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.h - ${CMAKE_CURRENT_LIST_DIR}/utils/qmlUtils.h ) # Mozilla headres @@ -157,12 +163,24 @@ include_directories(mozilla) include_directories(mozilla/shared) include_directories(mozilla/models) -if(NOT IOS) +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() + + +if(NOT IOS AND NOT MACOS_NE) + message(" Add header for non-IOS and non-MACOS_NE") set(HEADERS ${HEADERS} ${CMAKE_CURRENT_LIST_DIR}/platforms/ios/QRCodeReaderBase.h ) endif() + if(NOT ANDROID) set(HEADERS ${HEADERS} ${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.h @@ -193,7 +211,6 @@ set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess.cpp ${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess_new.cpp ${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.cpp - ${CMAKE_CURRENT_LIST_DIR}/utils/qmlUtils.cpp ) # Mozilla sources @@ -208,7 +225,7 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_definitions(${PROJECT} PRIVATE "MZ_DEBUG") endif() -if(NOT IOS) +if((NOT IOS) OR (NOT MACOS_NE)) set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/platforms/ios/QRCodeReaderBase.cpp ) @@ -309,6 +326,7 @@ if(APPLE) set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${BUILD_VPN_DEVELOPMENT_TEAM}) set(CMAKE_XCODE_ATTRIBUTE_GROUP_ID_IOS ${BUILD_IOS_GROUP_IDENTIFIER}) + set(MACOSX_DEPLOYMENT_TARGET "12.0") endif() if(LINUX AND NOT ANDROID) @@ -316,10 +334,9 @@ if(LINUX AND NOT ANDROID) link_directories(${CMAKE_CURRENT_LIST_DIR}/platforms/linux) endif() -if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID)) - message("Client desktop build") +# Macos Network Extension doesn't need +if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID)) add_compile_definitions(AMNEZIA_DESKTOP) - set(HEADERS ${HEADERS} ${CMAKE_CURRENT_LIST_DIR}/core/ipcclient.h ${CMAKE_CURRENT_LIST_DIR}/core/privileged_process.h @@ -352,9 +369,11 @@ endif() if(IOS) include(cmake/ios.cmake) include(cmake/ios-arch-fixup.cmake) -elseif(APPLE AND NOT IOS) - include(cmake/osxtools.cmake) +elseif(APPLE AND NOT IOS AND NOT DEFINED MACOS_NE) + # include(cmake/osxtools.cmake) include(cmake/macos.cmake) + elseif(APPLE AND NOT IOS AND MACOS_NE) + include(cmake/macos_ne.cmake) endif() target_link_libraries(${PROJECT} PRIVATE ${LIBS}) @@ -373,7 +392,7 @@ elseif(APPLE AND NOT IOS) set(DEPLOY_PLATFORM_PATH "macos") endif() -if(NOT IOS AND NOT ANDROID) +if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE) add_custom_command( TARGET ${PROJECT} POST_BUILD COMMAND ${CMAKE_COMMAND} -E $,copy_directory,true> @@ -392,4 +411,35 @@ if(NOT IOS AND NOT ANDROID) endif() target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC}) +if(MACOS_NE) + message("Copy MacOS Network Extension files") + add_custom_command(TARGET ${PROJECT} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Contents/Frameworks + + COMMAND ${CMAKE_COMMAND} -E echo "Copying OpenVPNAdapter.framework..." + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/client/3rd/OpenVPNAdapter/build/Release-macos/OpenVPNAdapter.framework/Versions/A + $/Contents/Frameworks/OpenVPNAdapter.framework/Versions/A + + COMMAND ${CMAKE_COMMAND} -E echo "OpenVPNAdapter.framework copied successfully." + ) + + # MacOS specific application deployment + add_custom_command(TARGET ${PROJECT} POST_BUILD + COMMAND ${QT_BIN_DIR_DETECTED}/macdeployqt $ -appstore-compliant -qmldir=${CMAKE_CURRENT_SOURCE_DIR} + ) + + # MacOS specific code signing for Release + if(CMAKE_BUILD_TYPE STREQUAL "Release") + SET(SIGN_CMD codesign --deep --force --sign 'Apple Distribution: Privacy Technologies OU \(X7UJ388FXK\)' --timestamp --options runtime $) + message("Manual signing bundle...") + message(${SIGN_CMD}) + + add_custom_command(TARGET ${PROJECT} POST_BUILD + COMMAND ${SIGN_CMD} + ) + endif() +endif() + qt_finalize_target(${PROJECT}) diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index aeed439b..f22d16a2 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -25,7 +25,7 @@ #include "protocols/qml_register_protocols.h" -#if defined(Q_OS_IOS) +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include "platforms/ios/ios_controller.h" #include #endif @@ -121,7 +121,8 @@ void AmneziaApplication::init() m_engine->addImageProvider(QLatin1String("installedAppImage"), new InstalledAppsImageProvider); #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) +#if defined(MACOS_NE) IosController::Instance()->initialize(); connect(IosController::Instance(), &IosController::importConfigFromOutside, this, [this](QString data) { emit m_pageController->goToPageHome(); @@ -134,6 +135,7 @@ void AmneziaApplication::init() m_pageController->goToPageSettingsBackup(); emit m_settingsController->importBackupFromOutside(filePath); }); +#endif QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled()); }); @@ -269,7 +271,7 @@ bool AmneziaApplication::parseCommands() QCommandLineOption c_cleanup { { "c", "cleanup" }, "Cleanup logs" }; m_parser.addOption(c_cleanup); - + m_parser.process(*this); if (m_parser.isSet(c_cleanup)) { @@ -281,7 +283,7 @@ bool AmneziaApplication::parseCommands() 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() { const QString serverName("AmneziaVPNInstance"); QLocalServer::removeServer(serverName); diff --git a/client/amnezia_application.h b/client/amnezia_application.h index cfeac0d1..9462685d 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -6,7 +6,7 @@ #include #include #include -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) #include #else #include @@ -51,7 +51,7 @@ #define amnApp (static_cast(QCoreApplication::instance())) -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) #define AMNEZIA_BASE_CLASS QGuiApplication #else #define AMNEZIA_BASE_CLASS QApplication @@ -71,7 +71,7 @@ public: void updateTranslator(const QLocale &locale); 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(); #endif diff --git a/client/cmake/3rdparty.cmake b/client/cmake/3rdparty.cmake index 2b5036c5..6bade9f2 100644 --- a/client/cmake/3rdparty.cmake +++ b/client/cmake/3rdparty.cmake @@ -27,9 +27,9 @@ if(WIN32) set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib") endif() elseif(APPLE AND NOT IOS) - 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") + set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/arm64_x86_64/libssh.a") + set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/arm64_x86_64/libz.a") + set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/arm64_x86_64") set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/macos/include") set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libssl.a") set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libcrypto.a") diff --git a/client/cmake/macos_ne.cmake b/client/cmake/macos_ne.cmake new file mode 100644 index 00000000..05c4e4ca --- /dev/null +++ b/client/cmake/macos_ne.cmake @@ -0,0 +1,146 @@ +message("Client ==> MacOS NE build") + +set_target_properties(${PROJECT} PROPERTIES MACOSX_BUNDLE TRUE) +set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64") +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) +set(LIBS ${LIBS} Qt6::ShaderTools) + +find_library(FW_AUTHENTICATIONSERVICES AuthenticationServices) +find_library(FW_AVFOUNDATION AVFoundation) +find_library(FW_FOUNDATION Foundation) +find_library(FW_STOREKIT StoreKit) +find_library(FW_USERNOTIFICATIONS UserNotifications) +find_library(FW_NETWORKEXTENSION NetworkExtension) + +set(LIBS ${LIBS} + ${FW_AUTHENTICATIONSERVICES} + ${FW_AVFOUNDATION} + ${FW_FOUNDATION} + ${FW_STOREKIT} + ${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}) + + +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_LINK_BUILD_PHASE_MODE KNOWN_LOCATION + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks" + XCODE_EMBED_APP_EXTENSIONS networkextension + + # XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution: Privacy Technologies OU (X7UJ388FXK)" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development: TRAN VIET ANH (Y372SYT4WL)" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "Mac AppStore AmneziaVPN" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "org.amnezia.AmneziaVPNManual" +) +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} networkextension) + +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/OpenVPNAdapter/build/Release-macos/OpenVPNAdapter.framework" +) + +set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rd/OpenVPNAdapter/build/Release-macos) +target_link_libraries("networkextension" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/3rd/OpenVPNAdapter/build/Release-macos/OpenVPNAdapter.framework") + diff --git a/client/cmake/osxtools.cmake b/client/cmake/osxtools.cmake index a28c9680..4564bfe0 100644 --- a/client/cmake/osxtools.cmake +++ b/client/cmake/osxtools.cmake @@ -76,7 +76,7 @@ function(osx_bundle_assetcatalog TARGET) ) ## Patch the asset catalog into the target bundle. - if(NOT IOS) + if(NOT IOS AND NOT MACOS_NE) set(XCASSETS_RESOURCE_DIR "Resources") endif() add_custom_command(TARGET ${TARGET} POST_BUILD @@ -141,6 +141,7 @@ function(osx_codesign_target TARGET) endif() foreach(FILE ${CODESIGN_FILES}) + message(STATUS "Signing ${TARGET}: ${FILE}") add_custom_command(TARGET ${TARGET} POST_BUILD VERBATIM COMMAND ${COMMENT_ECHO_COMMAND} "Signing ${TARGET}: ${FILE}" COMMAND ${CODESIGN_BIN} ${CODESIGN_ARGS} ${FILE} diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index fafb7c2b..d02261da 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -7,7 +7,7 @@ #include #include #include -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) #include #else #include @@ -120,7 +120,7 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPairisSitesSplitTunnelingEnabled()) { config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n"); -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) // Prevent ipv6 leak config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); #endif @@ -129,7 +129,7 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPairrouteMode() == 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"); // Prevent ipv6 leak config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); diff --git a/client/configurators/ssh_configurator.cpp b/client/configurators/ssh_configurator.cpp index 308f5947..73752976 100644 --- a/client/configurators/ssh_configurator.cpp +++ b/client/configurators/ssh_configurator.cpp @@ -8,7 +8,7 @@ #include #include #include -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) #include #else #include @@ -24,7 +24,7 @@ SshConfigurator::SshConfigurator(std::shared_ptr settings, const QShar QString SshConfigurator::convertOpenSShKey(const QString &key) { -#ifndef Q_OS_IOS +#if !defined(Q_OS_IOS) && !defined(MACOS_NE) QProcess p; p.setProcessChannelMode(QProcess::MergedChannels); @@ -67,9 +67,10 @@ QString SshConfigurator::convertOpenSShKey(const QString &key) #endif } +// DEAD CODE. void SshConfigurator::openSshTerminal(const ServerCredentials &credentials) { -#ifndef Q_OS_IOS +#if !defined(Q_OS_IOS) && !defined(MACOS_NE) QProcess *p = new QProcess(); p->setProcessChannelMode(QProcess::SeparateChannels); @@ -101,7 +102,7 @@ QProcessEnvironment SshConfigurator::prepareEnv() pathEnvVar.clear(); pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\cygwin;"); pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn;"); -#elif defined(Q_OS_MACX) +#elif defined(Q_OS_MAC) && !defined(MACOS_NE) pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS"); #endif diff --git a/client/containers/containers_defs.cpp b/client/containers/containers_defs.cpp index 52b148c0..35eec36c 100644 --- a/client/containers/containers_defs.cpp +++ b/client/containers/containers_defs.cpp @@ -275,7 +275,7 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c) #ifdef Q_OS_WINDOWS return true; -#elif defined(Q_OS_IOS) +#elif defined(Q_OS_IOS) || defined(MACOS_NE) switch (c) { case DockerContainer::WireGuard: return true; case DockerContainer::OpenVpn: return true; diff --git a/client/core/controllers/apiController.cpp b/client/core/controllers/apiController.cpp index 6562632a..02e704b0 100644 --- a/client/core/controllers/apiController.cpp +++ b/client/core/controllers/apiController.cpp @@ -275,7 +275,7 @@ QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiCont void ApiController::updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig) { -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) IosController::Instance()->requestInetAccess(); QThread::msleep(10); #endif @@ -332,7 +332,7 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c ErrorCode ApiController::getServicesList(QByteArray &responseBody) { -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) IosController::Instance()->requestInetAccess(); QThread::msleep(10); #endif @@ -393,7 +393,7 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co const QString &protocol, const QString &serverCountryCode, const QJsonObject &authData, QJsonObject &serverConfig) { -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) IosController::Instance()->requestInetAccess(); QThread::msleep(10); #endif diff --git a/client/core/controllers/apiController.h b/client/core/controllers/apiController.h index bcb25f96..90d49cb0 100644 --- a/client/core/controllers/apiController.h +++ b/client/core/controllers/apiController.h @@ -5,7 +5,7 @@ #include "configurators/openvpn_configurator.h" -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include "platforms/ios/ios_controller.h" #endif diff --git a/client/core/networkUtilities.cpp b/client/core/networkUtilities.cpp index a5825f0d..284ad51f 100644 --- a/client/core/networkUtilities.cpp +++ b/client/core/networkUtilities.cpp @@ -22,7 +22,7 @@ #include #include #endif -#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(MACOS_NE) #include #include #include @@ -378,7 +378,7 @@ QString NetworkUtilities::getGatewayAndIface() close(sock); return gateway_address; #endif -#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(MACOS_NE) QString gateway; int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_FLAGS, RTF_GATEWAY}; int afinet_type[] = {AF_INET, AF_INET6}; diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/128.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/128.png index 1be4f3f5..e355ae48 100644 Binary files a/client/macos/app/Images.xcassets/AppIcon.appiconset/128.png and b/client/macos/app/Images.xcassets/AppIcon.appiconset/128.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/128@2x.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/128@2x.png index 7ebd9732..89743eca 100644 Binary files a/client/macos/app/Images.xcassets/AppIcon.appiconset/128@2x.png and b/client/macos/app/Images.xcassets/AppIcon.appiconset/128@2x.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/16.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/16.png index 8eec5064..ac8a9346 100644 Binary files a/client/macos/app/Images.xcassets/AppIcon.appiconset/16.png and b/client/macos/app/Images.xcassets/AppIcon.appiconset/16.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/16@2x.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/16@2x.png index d3085f40..7e8391e3 100644 Binary files a/client/macos/app/Images.xcassets/AppIcon.appiconset/16@2x.png and b/client/macos/app/Images.xcassets/AppIcon.appiconset/16@2x.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/256.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/256.png index 95708591..89743eca 100644 Binary files a/client/macos/app/Images.xcassets/AppIcon.appiconset/256.png and b/client/macos/app/Images.xcassets/AppIcon.appiconset/256.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/256@2x.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/256@2x.png index d3b06078..f02ea1b0 100644 Binary files a/client/macos/app/Images.xcassets/AppIcon.appiconset/256@2x.png and b/client/macos/app/Images.xcassets/AppIcon.appiconset/256@2x.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/32.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/32.png index 4f12879d..7e8391e3 100644 Binary files a/client/macos/app/Images.xcassets/AppIcon.appiconset/32.png and b/client/macos/app/Images.xcassets/AppIcon.appiconset/32.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/32@2x.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/32@2x.png index d837424b..3f13a4c7 100644 Binary files a/client/macos/app/Images.xcassets/AppIcon.appiconset/32@2x.png and b/client/macos/app/Images.xcassets/AppIcon.appiconset/32@2x.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/512.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/512.png index 0c636cfe..f02ea1b0 100644 Binary files a/client/macos/app/Images.xcassets/AppIcon.appiconset/512.png and b/client/macos/app/Images.xcassets/AppIcon.appiconset/512.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/512@2x.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/512@2x.png index 018f668e..2f129f12 100644 Binary files a/client/macos/app/Images.xcassets/AppIcon.appiconset/512@2x.png and b/client/macos/app/Images.xcassets/AppIcon.appiconset/512@2x.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/64.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/64.png new file mode 100644 index 00000000..3f13a4c7 Binary files /dev/null and b/client/macos/app/Images.xcassets/AppIcon.appiconset/64.png differ diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/64@2x.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/64@2x.png new file mode 100644 index 00000000..e355ae48 Binary files /dev/null and b/client/macos/app/Images.xcassets/AppIcon.appiconset/64@2x.png differ diff --git a/client/macos/app/Images.xcassets/Contents.json b/client/macos/app/Images.xcassets/Contents.json index 73c00596..ed48d1a9 100644 --- a/client/macos/app/Images.xcassets/Contents.json +++ b/client/macos/app/Images.xcassets/Contents.json @@ -1,6 +1,68 @@ { - "info" : { - "author" : "xcode", - "version" : 1 + "images": [ + { + "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" } } diff --git a/client/macos/app/Info.plist.in b/client/macos/app/Info.plist.in new file mode 100644 index 00000000..1c9ad48e --- /dev/null +++ b/client/macos/app/Info.plist.in @@ -0,0 +1,172 @@ + + + + + CFBundleAllowMixedLocalizations + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${QT_INTERNAL_DOLLAR_VAR}{PRODUCT_NAME} + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + ITSAppUsesNonExemptEncryption + + LSApplicationCategoryType + public.app-category.utilities + + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + LSSupportsOpeningDocumentsInPlace + + com.wireguard.ios.app_group_id + group.org.amnezia.AmneziaVPN + NSCameraUsageDescription + Amnezia VPN needs access to the camera for reading QR-codes. + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsLocalNetworking + + + CFBundleIcons + + UTImportedTypeDeclarations + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Amnezia VPN config + UTTypeIconFiles + + UTTypeIdentifier + org.amnezia.AmneziaVPN.amnezia-config + UTTypeTagSpecification + + public.filename-extension + + vpn + + public.mime-type + + text/plain + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + WireGuard config + UTTypeIconFiles + + UTTypeIdentifier + org.amnezia.AmneziaVPN.wireguard-config + UTTypeTagSpecification + + public.filename-extension + + conf + cfg + + public.mime-type + + text/plain + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + OpenVPN config + UTTypeIconFiles + + UTTypeIdentifier + org.amnezia.AmneziaVPN.openvpn-config + UTTypeTagSpecification + + public.filename-extension + + ovpn + + public.mime-type + + text/plain + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + AmneziaVPN backup file + UTTypeIconFiles + + UTTypeIdentifier + org.amnezia.AmneziaVPN.backup-config + UTTypeTagSpecification + + public.filename-extension + + backup + + public.mime-type + + text/plain + + + + + CFBundleDocumentTypes + + + CFBundleTypeName + Amnezia VPN config + LSHandlerRank + Alternate + LSItemContentTypes + + org.amnezia.AmneziaVPN.amnezia-config + org.amnezia.AmneziaVPN.wireguard-config + org.amnezia.AmneziaVPN.openvpn-config + org.amnezia.AmneziaVPN.backup-config + + + + NSExtensions + + + NSExtensionPointIdentifier + com.apple.networkextension.packet-tunnel + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).PacketTunnelProvider + + + + + diff --git a/client/macos/app/app.entitlements b/client/macos/app/app.entitlements index 1eaae6ec..e8d3d17b 100644 --- a/client/macos/app/app.entitlements +++ b/client/macos/app/app.entitlements @@ -2,9 +2,6 @@ - com.apple.application-identifier - $(DEVELOPMENT_TEAM).$(APP_ID_MACOS) - com.apple.developer.networking.networkextension packet-tunnel-provider @@ -15,15 +12,12 @@ $(DEVELOPMENT_TEAM).* - com.apple.developer.team-identifier - $(DEVELOPMENT_TEAM) - com.apple.security.app-sandbox com.apple.security.application-groups - $(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS) + group.org.amnezia.AmneziaVPN com.apple.security.network.client @@ -31,5 +25,10 @@ com.apple.security.network.server + + com.apple.security.files.user-selected.read-only + + com.apple.security.files.user-selected.read-write + diff --git a/client/macos/app/main.entitlements b/client/macos/app/main.entitlements new file mode 100644 index 00000000..6581632f --- /dev/null +++ b/client/macos/app/main.entitlements @@ -0,0 +1,22 @@ + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + + com.apple.security.application-groups + + group.org.amnezia.AmneziaVPN + + com.apple.security.files.user-selected.read-write + + keychain-access-groups + + $(AppIdentifierPrefix)group.org.amnezia.AmneziaVPN + + com.apple.security.app-sandbox + + + diff --git a/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements b/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements index b4f08784..724cf1bf 100644 --- a/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements +++ b/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements @@ -3,40 +3,56 @@ com.apple.application-identifier - $(DEVELOPMENT_TEAM).$(NETEXT_ID_MACOS) - + X7UJ388FXK.org.amnezia.AmneziaVPN.network-extension com.apple.developer.networking.networkextension packet-tunnel-provider - - keychain-access-groups - - $(DEVELOPMENT_TEAM).* - - com.apple.developer.team-identifier - $(DEVELOPMENT_TEAM) - - com.apple.developer.system-extension.install - - + X7UJ388FXK com.apple.security.app-sandbox - com.apple.security.application-groups - $(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS) + group.org.amnezia.AmneziaVPN - + com.apple.security.assets.movies.read-write + + com.apple.security.assets.music.read-write + + com.apple.security.assets.pictures.read-write + + com.apple.security.device.audio-input + + com.apple.security.device.bluetooth + + com.apple.security.device.camera + + com.apple.security.device.usb + + com.apple.security.files.downloads.read-write + + com.apple.security.files.user-selected.read-write + com.apple.security.network.client - com.apple.security.network.server - com.apple.security.app-sandbox + + com.apple.security.personal-information.addressbook - com.apple.private.network.socket-delegate + com.apple.security.personal-information.calendars + com.apple.security.personal-information.location + + com.apple.security.print + + keychain-access-groups + + $(AppIdentifierPrefix)org.amnezia.AmneziaVPN.network-extension + + diff --git a/client/macos/networkextension/CMakeLists.txt b/client/macos/networkextension/CMakeLists.txt new file mode 100644 index 00000000..c798cef0 --- /dev/null +++ b/client/macos/networkextension/CMakeLists.txt @@ -0,0 +1,138 @@ +enable_language(Swift) +message("Client message >> macos build >> networkextension") +set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) + +add_executable(networkextension) + +if(MACOS_NE) + message("MACOS_NE is ON") + add_definitions(-DQ_OS_MAC) + add_definitions(-DMACOS_NE) +else() + message("MACOS_NE is OFF") +endif() +message("executable_path is: @executable_path/../../Frameworks") +set_target_properties(networkextension PROPERTIES + XCODE_PRODUCT_TYPE com.apple.product-type.app-extension + 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_CODE_SIGN_STYLE Automatic + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "Mac AppStore network-extension" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "amnezia.AmneziaVPN.network-extensionManual" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution: Privacy Technologies OU (X7UJ388FXK)" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development: TRAN VIET ANH (Y372SYT4WL)" + + XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../../../../Frameworks @loader_path/../../../../Frameworks" +) + +set_target_properties(networkextension PROPERTIES + XCODE_ATTRIBUTE_SWIFT_VERSION "5.0" + XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES" + XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/WireGuardNetworkExtension-Bridging-Header.h" + XCODE_ATTRIBUTE_SWIFT_OPTIMIZATION_LEVEL "-Onone" + XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO" +) + +set_target_properties("networkextension" PROPERTIES + XCODE_ATTRIBUTE_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}/../..) + +set(CMAKE_FRAMEWORK_PATH ${CLIENT_ROOT_DIR}/3rd/OpenVPNAdapter/build/Release-macos) + +target_link_libraries(networkextension PRIVATE ${FW_LIBRESOLV}) + +target_compile_options(networkextension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\") +target_compile_options(networkextension PRIVATE -DNETWORK_EXTENSION=1) + +set(WG_APPLE_SOURCE_DIR ${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(networkextension PRIVATE + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/WireGuardAdapter.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/PacketTunnelSettingsGenerator.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/DNSResolver.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardNetworkExtension/ErrorNotifier.swift + ${WG_APPLE_SOURCE_DIR}/Shared/Keychain.swift + ${WG_APPLE_SOURCE_DIR}/Shared/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(networkextension PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy +) + +set_property(TARGET networkextension APPEND PROPERTY RESOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy +) + +## Build wireguard-go-version.h +execute_process( + COMMAND go list -m golang.zx2c4.com/wireguard + WORKING_DIRECTORY ${CLIENT_ROOT_DIR}/3rd/wireguard-apple/Sources/WireGuardKitGo + OUTPUT_VARIABLE WG_VERSION_FULL +) +string(REGEX REPLACE ".*v\([0-9.]*\).*" "\\1" WG_VERSION_STRING 1.1.1) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/wireguard-go-version.h.in + ${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h) +target_sources(networkextension PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h) + +target_include_directories(networkextension PRIVATE ${CLIENT_ROOT_DIR}) +target_include_directories(networkextension PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + +target_link_libraries(networkextension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/macos/arm64_x86_64/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(networkextension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a) + +target_include_directories(networkextension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/Headers) \ No newline at end of file diff --git a/client/macos/networkextension/Info.plist b/client/macos/networkextension/Info.plist.in similarity index 63% rename from client/macos/networkextension/Info.plist rename to client/macos/networkextension/Info.plist.in index 96d82459..fa307001 100644 --- a/client/macos/networkextension/Info.plist +++ b/client/macos/networkextension/Info.plist.in @@ -3,27 +3,32 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - AmneziaVPNNetworkExtension + en CFBundleExecutable - $(EXECUTABLE_NAME) + AmneziaVPNNetworkExtension + CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) + org.amnezia.AmneziaVPN.network-extension CFBundleInfoDictionaryVersion 6.0 CFBundleName - $(PRODUCT_NAME) + AmneziaVPNNetworkExtension CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - $(MARKETING_VERSION) + ${APPLE_PROJECT_VERSION} CFBundleVersion - $(CURRENT_PROJECT_VERSION) + ${CMAKE_PROJECT_VERSION_TWEAK} + ITSAppUsesNonExemptEncryption + LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) + ${CMAKE_OSX_DEPLOYMENT_TARGET} + + CFBundleDisplayName + AmneziaVPNNetworkExtension + NSExtension NSExtensionPointIdentifier @@ -31,5 +36,11 @@ NSExtensionPrincipalClass $(PRODUCT_MODULE_NAME).PacketTunnelProvider + + com.wireguard.ios.app_group_id + group.org.amnezia.AmneziaVPN + + com.wireguard.macos.app_group_id + ${BUILD_VPN_DEVELOPMENT_TEAM}.group.org.amnezia.AmneziaVPN diff --git a/client/macos/networkextension/PrivacyInfo.xcprivacy b/client/macos/networkextension/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..380e0b7b --- /dev/null +++ b/client/macos/networkextension/PrivacyInfo.xcprivacy @@ -0,0 +1,25 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + + diff --git a/client/macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h b/client/macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h index 4ae7bded..12bf89be 100644 --- a/client/macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h +++ b/client/macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h @@ -1,10 +1,10 @@ /* 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 "macos/gobridge/wireguard.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 #include @@ -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]); 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); diff --git a/client/macos/networkextension/wireguard-go-version.h.in b/client/macos/networkextension/wireguard-go-version.h.in new file mode 100644 index 00000000..860bc3c3 --- /dev/null +++ b/client/macos/networkextension/wireguard-go-version.h.in @@ -0,0 +1,3 @@ +#ifndef WIREGUARD_GO_VERSION +#define WIREGUARD_GO_VERSION "@WG_VERSION_STRING@" +#endif // WIREGUARD_GO_VERSION \ No newline at end of file diff --git a/client/main.cpp b/client/main.cpp index aca9e62b..558553c5 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -11,11 +11,11 @@ #include "Windows.h" #endif -#if defined(Q_OS_IOS) +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include "platforms/ios/QtAppDelegate-C-Interface.h" #endif -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) bool isAnotherInstanceRunning() { QLocalSocket socket; @@ -45,7 +45,7 @@ int main(int argc, char *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()) { QTimer::singleShot(1000, &app, [&]() { app.quit(); }); return app.exec(); diff --git a/client/platforms/ios/PacketTunnelProvider+OpenVPN.swift b/client/platforms/ios/PacketTunnelProvider+OpenVPN.swift index 3e0a4a07..bfd1165f 100644 --- a/client/platforms/ios/PacketTunnelProvider+OpenVPN.swift +++ b/client/platforms/ios/PacketTunnelProvider+OpenVPN.swift @@ -73,7 +73,7 @@ extension PacketTunnelProvider { startHandler = completionHandler ovpnAdapter?.connect(using: packetFlow) } - + func handleOpenVPNStatusMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) { guard let completionHandler = completionHandler else { return } let bytesin = ovpnAdapter?.transportStatistics.bytesIn diff --git a/client/platforms/ios/PacketTunnelProvider+WireGuard.swift b/client/platforms/ios/PacketTunnelProvider+WireGuard.swift index 18200c7f..5d6e66de 100644 --- a/client/platforms/ios/PacketTunnelProvider+WireGuard.swift +++ b/client/platforms/ios/PacketTunnelProvider+WireGuard.swift @@ -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] = [ "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: [])) diff --git a/client/platforms/ios/QRCodeReaderBase.mm b/client/platforms/ios/QRCodeReaderBase.mm index af879e2f..963c35a8 100644 --- a/client/platforms/ios/QRCodeReaderBase.mm +++ b/client/platforms/ios/QRCodeReaderBase.mm @@ -1,3 +1,4 @@ +#if !MACOS_NE #include "QRCodeReaderBase.h" #import @@ -108,3 +109,19 @@ void QRCodeReader::startReading() { void 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 diff --git a/client/platforms/ios/QtAppDelegate.h b/client/platforms/ios/QtAppDelegate.h index c2c1d2d3..1668f4c3 100644 --- a/client/platforms/ios/QtAppDelegate.h +++ b/client/platforms/ios/QtAppDelegate.h @@ -1,5 +1,6 @@ +#if !MACOS_NE #import - +#endif @interface QIOSApplicationDelegate @end diff --git a/client/platforms/ios/QtAppDelegate.mm b/client/platforms/ios/QtAppDelegate.mm index bd7ad6b1..64ee9425 100644 --- a/client/platforms/ios/QtAppDelegate.mm +++ b/client/platforms/ios/QtAppDelegate.mm @@ -5,7 +5,7 @@ @implementation QIOSApplicationDelegate (AmneziaVPNDelegate) - +#if !MACOS_NE - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [application setMinimumBackgroundFetchInterval: UIApplicationBackgroundFetchIntervalMinimum]; @@ -57,5 +57,5 @@ } return NO; } - +#endif @end diff --git a/client/platforms/ios/ScreenProtection.swift b/client/platforms/ios/ScreenProtection.swift index 1355dc13..a2b5d7a3 100644 --- a/client/platforms/ios/ScreenProtection.swift +++ b/client/platforms/ios/ScreenProtection.swift @@ -1,3 +1,13 @@ +#if MACOS_NE +public func toggleScreenshots(_ isEnabled: Bool) { + +} + +class ScreenProtection { + + +} +#else import UIKit public func toggleScreenshots(_ isEnabled: Bool) { @@ -85,3 +95,4 @@ struct ProtectionPair { textField.removeFromSuperview() } } +#endif diff --git a/client/platforms/ios/ios_controller.h b/client/platforms/ios/ios_controller.h index 85580769..7e815bde 100644 --- a/client/platforms/ios/ios_controller.h +++ b/client/platforms/ios/ios_controller.h @@ -46,6 +46,7 @@ public: void disconnectVpn(); void vpnStatusDidChange(void *pNotification); + void vpnConfigurationDidChange(void *pNotification); void getBackendLogs(std::function &&callback); diff --git a/client/platforms/ios/ios_controller.mm b/client/platforms/ios/ios_controller.mm index 85fb50b7..9d7525ce 100644 --- a/client/platforms/ios/ios_controller.mm +++ b/client/platforms/ios/ios_controller.mm @@ -27,6 +27,7 @@ const char* MessageKey::isOnDemand = "is-on-demand"; const char* MessageKey::SplitTunnelType = "SplitTunnelType"; const char* MessageKey::SplitTunnelSites = "SplitTunnelSites"; +#if !MACOS_NE static UIViewController* getViewController() { NSArray *windows = [[UIApplication sharedApplication]windows]; for (UIWindow *window in windows) { @@ -36,6 +37,7 @@ static UIViewController* getViewController() { } return nil; } +#endif Vpn::ConnectionState iosStatusToState(NEVPNStatus status) { switch (status) { @@ -249,6 +251,19 @@ void IosController::checkStatus() sendVpnExtensionMessage(message, [&](NSDictionary* response){ uint64_t txBytes = [response[@"tx_bytes"] intValue]; uint64_t rxBytes = [response[@"rx_bytes"] intValue]; + + uint64_t last_handshake_time_sec = 0; + 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."; + } + emit bytesChanged(rxBytes - m_rxBytes, txBytes - m_txBytes); m_rxBytes = rxBytes; m_txBytes = txBytes; @@ -789,14 +804,14 @@ bool IosController::shareText(const QStringList& filesToSend) { NSURL *logFileUrl = [[NSURL alloc] initFileURLWithPath:filesToSend[i].toNSString()]; [sharingItems addObject:logFileUrl]; } - +#if !MACOS_NE UIViewController *qtController = getViewController(); if (!qtController) return; UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil]; - +#endif __block bool isAccepted = false; - +#if !MACOS_NE [activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) { isAccepted = completed; emit finished(); @@ -808,7 +823,7 @@ bool IosController::shareText(const QStringList& filesToSend) { popController.sourceView = qtController.view; popController.sourceRect = CGRectMake(100, 100, 100, 100); } - +#endif QEventLoop wait; QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit); wait.exec(); @@ -817,6 +832,7 @@ bool IosController::shareText(const QStringList& filesToSend) { } QString IosController::openFile() { +#if !MACOS_NE UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen]; DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init]; @@ -826,9 +842,9 @@ QString IosController::openFile() { if (!qtController) return; [qtController presentViewController:documentPicker animated:YES completion:nil]; - +#endif __block QString filePath; - +#if !MACOS_NE documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) { if (path) { filePath = QString::fromUtf8(path.UTF8String); @@ -837,7 +853,7 @@ QString IosController::openFile() { } emit finished(); }; - +#endif QEventLoop wait; QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit); wait.exec(); diff --git a/client/platforms/ios/ios_controller_wrapper.h b/client/platforms/ios/ios_controller_wrapper.h index f0333d77..ab325154 100644 --- a/client/platforms/ios/ios_controller_wrapper.h +++ b/client/platforms/ios/ios_controller_wrapper.h @@ -1,7 +1,11 @@ #import #import #import + +#if !MACOS_NE #include +#endif + #include class IosController; @@ -17,9 +21,10 @@ class IosController; @end typedef void (^DocumentPickerClosedCallback)(NSString *path); - +#if !MACOS_NE @interface DocumentPickerDelegate : NSObject @property (nonatomic, copy) DocumentPickerClosedCallback documentPickerClosedCallback; @end +#endif diff --git a/client/platforms/ios/ios_controller_wrapper.mm b/client/platforms/ios/ios_controller_wrapper.mm index 1f8c938f..38eb2d22 100644 --- a/client/platforms/ios/ios_controller_wrapper.mm +++ b/client/platforms/ios/ios_controller_wrapper.mm @@ -26,7 +26,8 @@ @end -@implementation DocumentPickerDelegate +#if !MACOS_NE +@implementation DocumentPickerDelegate - (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray *)urls { for (NSURL *url in urls) { @@ -42,4 +43,5 @@ } } -@end \ No newline at end of file +@end +#endif diff --git a/client/platforms/ios/iosnotificationhandler.mm b/client/platforms/ios/iosnotificationhandler.mm index efa48385..773c6297 100644 --- a/client/platforms/ios/iosnotificationhandler.mm +++ b/client/platforms/ios/iosnotificationhandler.mm @@ -6,6 +6,8 @@ #import #import + +#if !MACOS_NE #import @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 { + 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)m_delegate; + + [center addNotificationRequest:request + withCompletionHandler:^(NSError* _Nullable error) { + if (error) { + NSLog(@"Local Notification failed"); + } + }]; +} +#endif diff --git a/client/protocols/protocols_defs.h b/client/protocols/protocols_defs.h index 865edae4..881d1633 100644 --- a/client/protocols/protocols_defs.h +++ b/client/protocols/protocols_defs.h @@ -177,7 +177,7 @@ namespace amnezia 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"; #else constexpr char defaultMtu[] = "1376"; @@ -197,7 +197,7 @@ namespace amnezia namespace awg { 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"; #else constexpr char defaultMtu[] = "1376"; diff --git a/client/protocols/vpnprotocol.cpp b/client/protocols/vpnprotocol.cpp index 056089b8..4b3edca5 100644 --- a/client/protocols/vpnprotocol.cpp +++ b/client/protocols/vpnprotocol.cpp @@ -4,7 +4,7 @@ #include "core/errorstrings.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 "openvpnprotocol.h" #include "shadowsocksvpnprotocol.h" @@ -109,7 +109,7 @@ VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject & #if defined(Q_OS_WINDOWS) case DockerContainer::Ipsec: return new Ikev2Protocol(configuration); #endif -#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) +#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) and !defined MACOS_NE || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration); case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration); case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration); diff --git a/client/ui/controllers/connectionController.cpp b/client/ui/controllers/connectionController.cpp index f9491d4e..02c13862 100644 --- a/client/ui/controllers/connectionController.cpp +++ b/client/ui/controllers/connectionController.cpp @@ -1,6 +1,6 @@ #include "connectionController.h" -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) #include #else #include @@ -34,7 +34,7 @@ ConnectionController::ConnectionController(const QSharedPointer &s void ConnectionController::openConnection() { -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true)) { emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning); diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp index 28bbc9f6..ea13d5d5 100644 --- a/client/ui/controllers/importController.cpp +++ b/client/ui/controllers/importController.cpp @@ -15,7 +15,7 @@ #ifdef Q_OS_ANDROID #include "platforms/android/android_controller.h" #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include #endif @@ -544,7 +544,7 @@ void ImportController::startDecodingQr() m_totalQrCodeChunksCount = 0; m_receivedQrCodeChunksCount = 0; - #if defined Q_OS_IOS + #if defined(Q_OS_IOS) || defined(MACOS_NE) m_isQrCodeProcessed = true; #endif #if defined Q_OS_ANDROID diff --git a/client/ui/controllers/pageController.cpp b/client/ui/controllers/pageController.cpp index d515df49..97ddf5d8 100644 --- a/client/ui/controllers/pageController.cpp +++ b/client/ui/controllers/pageController.cpp @@ -2,7 +2,7 @@ #include "utils/converter.h" #include "core/errorstrings.h" -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) #include #else #include @@ -11,7 +11,7 @@ #ifdef Q_OS_ANDROID #include "platforms/android/android_controller.h" #endif -#if defined Q_OS_MAC +#if defined Q_OS_MAC && !defined(MACOS_NE) #include "ui/macos_util.h" #endif @@ -24,7 +24,7 @@ PageController::PageController(const QSharedPointer &serversModel, AndroidController::instance()->setNavigationBarColor(initialPageNavigationBarColor); #endif -#if defined Q_OS_MACX +#if defined Q_OS_MAC and !defined MACOS_NE connect(this, &PageController::raiseMainWindow, []() { setDockIconVisible(true); }); connect(this, &PageController::hideMainWindow, []() { setDockIconVisible(false); }); #endif @@ -114,7 +114,7 @@ void PageController::showOnStartup() } else { #if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) emit hideMainWindow(); -#elif defined Q_OS_MACX +#elif defined Q_OS_MACX and !defined MACOS_NE setDockIconVisible(false); #endif } diff --git a/client/ui/controllers/settingsController.cpp b/client/ui/controllers/settingsController.cpp index f4e3d83d..b38ea3a7 100644 --- a/client/ui/controllers/settingsController.cpp +++ b/client/ui/controllers/settingsController.cpp @@ -10,7 +10,7 @@ #include "platforms/android/android_controller.h" #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include #endif @@ -76,7 +76,7 @@ bool SettingsController::isLoggingEnabled() void SettingsController::toggleLogging(bool enable) { m_settings->setSaveLogs(enable); -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) AmneziaVPN::toggleLogging(enable); #endif if (enable == true) { @@ -131,8 +131,12 @@ void SettingsController::backupAppConfig(const QString &fileName) void SettingsController::restoreAppConfig(const QString &fileName) { - QByteArray data; - SystemController::readFile(fileName, data); + QFile file(fileName); + + file.open(QIODevice::ReadOnly); + + QByteArray data = file.readAll(); + restoreAppConfigFromData(data); } @@ -169,7 +173,7 @@ void SettingsController::clearSettings() emit changeSettingsFinished(tr("All settings have been reset to default values")); -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) AmneziaVPN::clearSettings(); #endif } @@ -321,14 +325,3 @@ bool SettingsController::isOnTv() return false; #endif } - -bool SettingsController::isHomeAdLabelVisible() -{ - return m_settings->isHomeAdLabelVisible(); -} - -void SettingsController::disableHomeAdLabel() -{ - m_settings->disableHomeAdLabel(); - emit isHomeAdLabelVisibleChanged(false); -} diff --git a/client/ui/controllers/systemController.cpp b/client/ui/controllers/systemController.cpp index 52ca1294..f8b47350 100644 --- a/client/ui/controllers/systemController.cpp +++ b/client/ui/controllers/systemController.cpp @@ -14,7 +14,7 @@ #include "platforms/android/android_controller.h" #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include "platforms/ios/ios_controller.h" #include #endif diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp index b72b10c3..28370f85 100644 --- a/client/ui/models/servers_model.cpp +++ b/client/ui/models/servers_model.cpp @@ -4,7 +4,7 @@ #include "core/enums/apiEnums.h" #include "core/networkUtilities.h" -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include #endif @@ -760,7 +760,7 @@ void ServersModel::removeApiConfig(const int serverIndex) { auto serverConfig = getServerConfig(serverIndex); -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) QString vpncName = QString("%1 (%2) %3") .arg(serverConfig[config_key::description].toString()) .arg(serverConfig[config_key::hostName].toString()) diff --git a/client/ui/notificationhandler.cpp b/client/ui/notificationhandler.cpp index 5efb45c4..3dea619c 100644 --- a/client/ui/notificationhandler.cpp +++ b/client/ui/notificationhandler.cpp @@ -5,15 +5,16 @@ #include #include "notificationhandler.h" -#if defined(Q_OS_IOS) +#if defined(Q_OS_IOS) || defined(MACOS_NE) # include "platforms/ios/iosnotificationhandler.h" #else # include "systemtray_notificationhandler.h" #endif + // static NotificationHandler* NotificationHandler::create(QObject* parent) { -#if defined(Q_OS_IOS) +#if defined(Q_OS_IOS) || defined(MACOS_NE) return new IOSNotificationHandler(parent); #else diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index f145127f..b20b13ff 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -25,29 +25,32 @@ PageType { } } - ListView { - id: listView + defaultActiveFocusItem: focusItem - anchors.fill: parent + FlickableType { + id: fl + anchors.top: parent.top + anchors.bottom: parent.bottom + contentHeight: content.height - property bool isFocusable: true + ColumnLayout { + id: content - ScrollBar.vertical: ScrollBarType {} + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right - model: variants + spacing: 0 - clip: true + Item { + id: focusItem + KeyNavigation.tab: textKey.textField + } - reuseItems: true - - header: ColumnLayout { - width: listView.width HeaderType { - id: moreButton - property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible() - + Layout.fillWidth: true Layout.topMargin: 24 Layout.rightMargin: 16 @@ -57,7 +60,7 @@ PageType { actionButtonImage: isVisible ? "qrc:/images/controls/more-vertical.svg" : "" actionButtonFunction: function() { - moreActionsDrawer.openTriggered() + moreActionsDrawer.open() } DrawerType2 { @@ -68,7 +71,7 @@ PageType { anchors.fill: parent expandedHeight: root.height * 0.5 - expandedStateContent: ColumnLayout { + expandedContent: ColumnLayout { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right @@ -128,8 +131,6 @@ PageType { } ParagraphTextType { - objectName: "insertKeyLabel" - Layout.fillWidth: true Layout.topMargin: 32 Layout.rightMargin: 16 @@ -153,6 +154,8 @@ PageType { textField.text = "" textField.paste() } + + KeyNavigation.tab: continueButton } BasicButtonType { @@ -163,12 +166,13 @@ PageType { Layout.rightMargin: 16 Layout.leftMargin: 16 - visible: textKey.textField.text !== "" + visible: textKey.textFieldText !== "" text: qsTr("Continue") + Keys.onTabPressed: lastItemTabClicked(focusItem) clickedFunc: function() { - if (ImportController.extractConfigFromData(textKey.textField.text)) { + if (ImportController.extractConfigFromData(textKey.textFieldText)) { PageController.goToPage(PageEnum.PageSetupWizardViewConfig) } } @@ -184,157 +188,143 @@ PageType { color: AmneziaStyle.color.charcoalGray text: qsTr("Other connection options") } - } - - delegate: ColumnLayout { - width: listView.width CardWithIconsType { + id: apiInstalling + Layout.fillWidth: true Layout.rightMargin: 16 Layout.leftMargin: 16 Layout.bottomMargin: 16 - visible: isVisible - - headerText: title - bodyText: description + headerText: qsTr("VPN by Amnezia") + bodyText: qsTr("Connect to classic paid and free VPN services from Amnezia") rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: imageSource + leftImageSource: "qrc:/images/controls/amnezia.svg" - onClicked: { handler() } + onClicked: function() { + PageController.showBusyIndicator(true) + var result = InstallController.fillAvailableServices() + PageController.showBusyIndicator(false) + if (result) { + PageController.goToPage(PageEnum.PageSetupWizardApiServicesList) + } + } } - } - footer: ColumnLayout { - width: listView.width + CardWithIconsType { + id: manualInstalling - BasicButtonType { - id: siteLink2 - Layout.topMargin: 24 + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 Layout.bottomMargin: 16 - Layout.alignment: Qt.AlignHCenter - implicitHeight: 32 - visible: Qt.platform.os !== "ios" + headerText: qsTr("Self-hosted VPN") + bodyText: qsTr("Configure Amnezia VPN on your own server") - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.goldenApricot + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: "qrc:/images/controls/server.svg" - text: qsTr("Site Amnezia") + onClicked: { + PageController.goToPage(PageEnum.PageSetupWizardCredentials) + } + } - rightImageSource: "qrc:/images/controls/external-link.svg" + CardWithIconsType { + id: backupRestore - clickedFunc: function() { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + visible: PageController.isStartPageVisible() + + headerText: qsTr("Restore from backup") + + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: "qrc:/images/controls/archive-restore.svg" + + onClicked: { + var filePath = SystemController.getFileName(qsTr("Open backup file"), + qsTr("Backup files (*.backup)")) + if (filePath !== "") { + PageController.showBusyIndicator(true) + SettingsController.restoreAppConfig(filePath) + PageController.showBusyIndicator(false) + } + } + } + + CardWithIconsType { + id: openFile + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + headerText: qsTr("File with connection settings") + + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: "qrc:/images/controls/folder-search-2.svg" + + onClicked: { + var nameFilter = !ServersModel.getServersCount() ? "Config or backup files (*.vpn *.ovpn *.conf *.json *.backup)" : + "Config files (*.vpn *.ovpn *.conf *.json)" + var fileName = SystemController.getFileName(qsTr("Open config file"), nameFilter) + if (fileName !== "") { + if (ImportController.extractConfigFromFile(fileName)) { + PageController.goToPage(PageEnum.PageSetupWizardViewConfig) + } + } + } + } + + CardWithIconsType { + id: scanQr + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + visible: (Qt.platform.os === "android" || Qt.platform.os === "ios") && SettingsController.isCameraPresent() + + headerText: qsTr("QR code") + + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: "qrc:/images/controls/scan-line.svg" + + onClicked: { + ImportController.startDecodingQr() + if (Qt.platform.os === "ios") { + PageController.goToPage(PageEnum.PageSetupWizardQrReader) + } + } + } + + CardWithIconsType { + id: siteLink + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + visible: PageController.isStartPageVisible() + + headerText: qsTr("I have nothing") + + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: "qrc:/images/controls/help-circle.svg" + + onClicked: { Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl()) } } } } - - property list variants: [ - amneziaVpn, - selfHostVpn, - backupRestore, - fileOpen, - qrScan, - siteLink - ] - - QtObject { - id: amneziaVpn - - property string title: qsTr("VPN by Amnezia") - property string description: qsTr("Connect to classic paid and free VPN services from Amnezia") - property string imageSource: "qrc:/images/controls/amnezia.svg" - property bool isVisible: true - property var handler: function() { - PageController.showBusyIndicator(true) - var result = InstallController.fillAvailableServices() - PageController.showBusyIndicator(false) - if (result) { - PageController.goToPage(PageEnum.PageSetupWizardApiServicesList) - } - } - } - - QtObject { - id: selfHostVpn - - property string title: qsTr("Self-hosted VPN") - property string description: qsTr("Configure Amnezia VPN on your own server") - property string imageSource: "qrc:/images/controls/server.svg" - property bool isVisible: true - property var handler: function() { - PageController.goToPage(PageEnum.PageSetupWizardCredentials) - } - } - - QtObject { - id: backupRestore - - property string title: qsTr("Restore from backup") - property string description: qsTr("") - property string imageSource: "qrc:/images/controls/archive-restore.svg" - property bool isVisible: PageController.isStartPageVisible() - property var handler: function() { - var filePath = SystemController.getFileName(qsTr("Open backup file"), - qsTr("Backup files (*.backup)")) - if (filePath !== "") { - PageController.showBusyIndicator(true) - SettingsController.restoreAppConfig(filePath) - PageController.showBusyIndicator(false) - } - } - } - - QtObject { - id: fileOpen - - property string title: qsTr("File with connection settings") - property string description: qsTr("") - property string imageSource: "qrc:/images/controls/folder-search-2.svg" - property bool isVisible: true - property var handler: function() { - var nameFilter = !ServersModel.getServersCount() ? "Config or backup files (*.vpn *.ovpn *.conf *.json *.backup)" : - "Config files (*.vpn *.ovpn *.conf *.json)" - var fileName = SystemController.getFileName(qsTr("Open config file"), nameFilter) - if (fileName !== "") { - if (ImportController.extractConfigFromFile(fileName)) { - PageController.goToPage(PageEnum.PageSetupWizardViewConfig) - } - } - } - } - - QtObject { - id: qrScan - - property string title: qsTr("QR code") - property string description: qsTr("") - property string imageSource: "qrc:/images/controls/scan-line.svg" - property bool isVisible: SettingsController.isCameraPresent() - property var handler: function() { - ImportController.startDecodingQr() - if (Qt.platform.os === "ios") { - PageController.goToPage(PageEnum.PageSetupWizardQrReader) - } - } - } - - QtObject { - id: siteLink - - property string title: qsTr("I have nothing") - property string description: qsTr("") - property string imageSource: "qrc:/images/controls/help-circle.svg" - property bool isVisible: PageController.isStartPageVisible() && Qt.platform.os !== "ios" - property var handler: function() { - Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl()) - } - } } diff --git a/client/utilities.cpp b/client/utilities.cpp index 61944e51..51a9885a 100755 --- a/client/utilities.cpp +++ b/client/utilities.cpp @@ -190,7 +190,7 @@ bool Utils::processIsRunning(const QString &fileName, const bool fullFlag) CloseHandle(hSnapshot); return false; -#elif defined(Q_OS_IOS) || defined(Q_OS_ANDROID) +#elif defined(Q_OS_IOS) || defined(Q_OS_ANDROID) || defined(MACOS_NE) return false; #else QProcess process; diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 042c51c7..7e22d73f 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -22,7 +22,7 @@ #include "platforms/android/android_controller.h" #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include "platforms/ios/ios_controller.h" #endif @@ -33,7 +33,7 @@ VpnConnection::VpnConnection(std::shared_ptr settings, QObject *parent : QObject(parent), m_settings(settings), m_checkTimer(new QTimer(this)) { m_checkTimer.setInterval(1000); -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) connect(IosController::Instance(), &IosController::connectionStateChanged, this, &VpnConnection::onConnectionStateChanged); connect(IosController::Instance(), &IosController::bytesChanged, this, &VpnConnection::onBytesChanged); @@ -101,7 +101,7 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state) } #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) if (state == Vpn::ConnectionState::Connected) { m_checkTimer.start(); } else { @@ -215,10 +215,11 @@ ErrorCode VpnConnection::lastError() const void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration) { - qDebug() << QString("Trying to connect to VPN, server index is %1, container is %2") + qDebug() << QString("ConnectToVpn, Server index is %1, container is %2, route mode is") .arg(serverIndex) - .arg(ContainerProps::containerToString(container)); -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) + .arg(ContainerProps::containerToString(container)) + << m_settings->routeMode(); +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) if (!m_IpcClient) { m_IpcClient = new IpcClient(this); } @@ -249,7 +250,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede appendSplitTunnelingConfig(); -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) m_vpnProtocol.reset(VpnProtocol::factory(container, m_vpnConfiguration)); if (!m_vpnProtocol) { emit connectionStateChanged(Vpn::ConnectionState::Error); @@ -261,7 +262,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede createAndroidConnections(); m_vpnProtocol.reset(androidVpnProtocol); -#elif defined Q_OS_IOS +#elif defined Q_OS_IOS || defined(MACOS_NE) Proto proto = ContainerProps::defaultProtocol(container); IosController::Instance()->connectVpn(proto, m_vpnConfiguration); connect(&m_checkTimer, &QTimer::timeout, IosController::Instance(), &IosController::checkStatus); @@ -340,26 +341,26 @@ void VpnConnection::appendSplitTunnelingConfig() } } - Settings::RouteMode sitesRouteMode = Settings::RouteMode::VpnAllSites; + Settings::RouteMode routeMode = Settings::RouteMode::VpnAllSites; QJsonArray sitesJsonArray; if (m_settings->isSitesSplitTunnelingEnabled()) { - sitesRouteMode = m_settings->routeMode(); + routeMode = m_settings->routeMode(); if (allowSiteBasedSplitTunneling) { - auto sites = m_settings->getVpnIps(sitesRouteMode); + auto sites = m_settings->getVpnIps(routeMode); for (const auto &site : sites) { sitesJsonArray.append(site); } // Allow traffic to Amnezia DNS - if (sitesRouteMode == Settings::VpnOnlyForwardSites) { + if (routeMode == Settings::VpnOnlyForwardSites) { sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns1).toString()); sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns2).toString()); } } } - m_vpnConfiguration.insert(config_key::splitTunnelType, sitesRouteMode); + m_vpnConfiguration.insert(config_key::splitTunnelType, routeMode); m_vpnConfiguration.insert(config_key::splitTunnelSites, sitesJsonArray); Settings::AppsRouteMode appsRouteMode = Settings::AppsRouteMode::VpnAllApps; @@ -375,13 +376,6 @@ void VpnConnection::appendSplitTunnelingConfig() m_vpnConfiguration.insert(config_key::appSplitTunnelType, appsRouteMode); m_vpnConfiguration.insert(config_key::splitTunnelApps, appsJsonArray); - - qDebug() << QString("Site split tunneling is %1, route mode is %2") - .arg(m_settings->isSitesSplitTunnelingEnabled() ? "enabled" : "disabled") - .arg(sitesRouteMode); - qDebug() << QString("App split tunneling is %1, route mode is %2") - .arg(m_settings->isAppsSplitTunnelingEnabled() ? "enabled" : "disabled") - .arg(appsRouteMode); } #ifdef Q_OS_ANDROID @@ -443,7 +437,7 @@ void VpnConnection::disconnectFromVpn() } #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) IosController::Instance()->disconnectVpn(); disconnect(&m_checkTimer, &QTimer::timeout, IosController::Instance(), &IosController::checkStatus); #endif diff --git a/deploy/build_macos_ne.sh b/deploy/build_macos_ne.sh new file mode 100755 index 00000000..066bf4f6 --- /dev/null +++ b/deploy/build_macos_ne.sh @@ -0,0 +1,123 @@ +#!/bin/bash +echo "Build script for macOS Network Extension started ..." + +set -o errexit -o nounset + +while getopts n flag +do + case "${flag}" in + n) NOTARIZE_APP=1;; + esac +done + +# Hold on to current directory +PROJECT_DIR=$(pwd) +DEPLOY_DIR=$PROJECT_DIR/deploy + +mkdir -p $DEPLOY_DIR/build-macos +BUILD_DIR=$DEPLOY_DIR/build-macos + +echo "Project dir: ${PROJECT_DIR}" +echo "Build dir: ${BUILD_DIR}" + +APP_NAME=AmneziaVPN +APP_FILENAME=$APP_NAME.app +APP_DOMAIN=org.amneziavpn.package +PLIST_NAME=$APP_NAME.plist + +OUT_APP_DIR=$BUILD_DIR/client +BUNDLE_DIR=$OUT_APP_DIR/$APP_FILENAME + +PREBUILT_DEPLOY_DATA_DIR=$PROJECT_DIR/deploy/data/deploy-prebuilt/macos +DEPLOY_DATA_DIR=$PROJECT_DIR/deploy/data/macos + +INSTALLER_DATA_DIR=$BUILD_DIR/installer/packages/$APP_DOMAIN/data +INSTALLER_BUNDLE_DIR=$BUILD_DIR/installer/$APP_FILENAME +DMG_FILENAME=$PROJECT_DIR/${APP_NAME}.dmg + +echo "Import certificate" + +TRUST_CERT_CER=$BUILD_DIR/trust-cert.cer +SIGNING_CERT_P12=$BUILD_DIR/signing-cert.p12 + +echo $MAC_TRUST_CERT_BASE64 | base64 --decode > $TRUST_CERT_CER +echo $MAC_SIGNING_CERT_BASE64 | base64 --decode > $SIGNING_CERT_P12 + +shasum -a 256 $TRUST_CERT_CER +shasum -a 256 $SIGNING_CERT_P12 +KEYCHAIN_PASS=$MAC_SIGNING_CERT_PASSWORD + +# Keychain setup +KEYCHAIN=amnezia.build.macos.keychain +TEMP_PASS=tmp_pass +KEYCHAIN_FILE=$HOME/Library/Keychains/$KEYCHAIN-db + +security create-keychain -p $TEMP_PASS $KEYCHAIN || true +security default-keychain -s $KEYCHAIN +security unlock-keychain -p $TEMP_PASS $KEYCHAIN + +security default-keychain +security list-keychains + +# Import certificates into keychain +security import $TRUST_CERT_CER -k $KEYCHAIN -P "" -T /usr/bin/codesign || true +security import $SIGNING_CERT_P12 -k $KEYCHAIN -P $MAC_SIGNING_CERT_PASSWORD -T /usr/bin/codesign || true + +# Configure keychain settings +security set-key-partition-list -S apple-tool:,apple: -k $TEMP_PASS $KEYCHAIN +security find-identity -p codesigning + +# Setup provisioning profiles for main app and NE +echo "Setting up provisioning profiles..." + +PROVISIONING_PROFILE_PATH=$BUILD_DIR/macos_app_provisioning.mobileprovision +echo $APPSTORE_CONNECT_MAC_PROVISIONING_BASE64 | base64 --decode > "$PROVISIONING_PROFILE_PATH" +shasum -a 256 "$PROVISIONING_PROFILE_PATH" + +NE_PROVISIONING_PROFILE_PATH=$BUILD_DIR/macos_ne_provisioning.mobileprovision +echo $APPSTORE_CONNECT_MAC_NE_PROVISIONING_BASE64 | base64 --decode > "$NE_PROVISIONING_PROFILE_PATH" +shasum -a 256 "$NE_PROVISIONING_PROFILE_PATH" + +# setup environment +QT_MACOS_BIN=$QT_BIN_DIR +export PATH=$PATH:~/go/bin +echo "QT_BIN_DIR: $QT_BIN_DIR" + + +# Build the Network Extension app +echo "Building MAC Network Extension App..." +mkdir -p build-macos + +$QT_MACOS_BIN/qt-cmake . -B build-macos -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR -DMACOS_NE=TRUE -DCMAKE_BUILD_TYPE=Release + +# Build and run tests here + +echo "____________________________________" +echo "............Deploying..............." +echo "____________________________________" +echo "Deploying MAC Network Extension App..." + +mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles/ +echo $APPSTORE_CONNECT_MAC_PROVISIONING_BASE64 | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/macos_app.mobileprovision +echo $APPSTORE_CONNECT_MAC_NE_PROVISIONING_BASE64 | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/macos_ne.mobileprovision + +echo "xcode build" +xcodebuild \ +"OTHER_CODE_SIGN_FLAGS=--keychain '$KEYCHAIN_FILE'" \ +-configuration Release \ +-scheme AmneziaVPN \ +-destination "platform=macOS" \ +-project $PROJECT_DIR/build-macos/AmneziaVPN.xcodeproj + +echo "Packaging MAC Network Extension App..." +hdiutil create -volname "$APP_NAME" \ + -srcfolder "$PROJECT_DIR/build-macos/client/Release/$APP_FILENAME" \ + -ov \ + -format UDZO \ + "$DMG_FILENAME" + +# Restore keychain to default +echo "Restoring default keychain..." +security default-keychain -s "/Users/runner/Library/Keychains/login.keychain-db" + +echo "Build and signing process completed successfully!" \ No newline at end of file diff --git a/deploy/installer/config.cmake b/deploy/installer/config.cmake index 13f09986..f3ab11a4 100644 --- a/deploy/installer/config.cmake +++ b/deploy/installer/config.cmake @@ -4,7 +4,7 @@ if(WIN32) ${CMAKE_CURRENT_LIST_DIR}/config/windows.xml.in ${CMAKE_BINARY_DIR}/installer/config/windows.xml ) -elseif(APPLE AND NOT IOS) +elseif(APPLE AND NOT IOS AND NOT MACOS_NE) configure_file( ${CMAKE_CURRENT_LIST_DIR}/config/macos.xml.in ${CMAKE_BINARY_DIR}/installer/config/macos.xml diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt index f05dbb23..02a21631 100644 --- a/service/CMakeLists.txt +++ b/service/CMakeLists.txt @@ -6,6 +6,6 @@ project(${PROJECT}) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -if(NOT IOS AND NOT ANDROID) +if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE) add_subdirectory(server) endif()