diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 0c9dfb32..3cef327f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -149,10 +149,10 @@ 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 }} @@ -167,7 +167,7 @@ jobs: - 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 @@ -219,6 +219,7 @@ jobs: - name: 'Build project' run: | + set -o pipefail git submodule update --init --recursive export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/ios/bin" export QT_MACOS_ROOT_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos" @@ -255,6 +256,7 @@ jobs: env: # Keep compat with MacOS 10.15 aka Catalina by Qt 6.4 QT_VERSION: 6.4.3 + QIF_VERSION: 4.6 PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }} DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }} @@ -282,6 +284,11 @@ jobs: set-env: 'true' extra: '--external 7z --base ${{ env.QT_MIRROR }}' + - name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}' + run: | + mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework + wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip + unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/ - name: 'Get sources' uses: actions/checkout@v4 @@ -295,13 +302,14 @@ jobs: - name: 'Build project' run: | export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin" + export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin" bash deploy/build_macos.sh - name: 'Upload installer artifact' uses: actions/upload-artifact@v4 with: name: AmneziaVPN_MacOS_old_installer - path: deploy/build/pkg/AmneziaVPN.pkg + path: AmneziaVPN.dmg retention-days: 7 - name: 'Upload unpacked artifact' @@ -318,6 +326,7 @@ jobs: env: QT_VERSION: 6.8.0 + QIF_VERSION: 4.8.1 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 }} @@ -330,7 +339,7 @@ jobs: - name: 'Setup xcode' uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '15.4.0' + xcode-version: '15.4' - name: 'Install Qt' uses: jurplel/install-qt-action@v3 @@ -345,6 +354,11 @@ jobs: set-env: 'true' extra: '--external 7z --base ${{ env.QT_MIRROR }}' + - name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}' + run: | + mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework + wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip + unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/ - name: 'Get sources' uses: actions/checkout@v4 @@ -357,14 +371,20 @@ jobs: - name: 'Build project' run: | + set -o pipefail export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin" - bash deploy/build_macos.sh + export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin" + bash deploy/build_macos.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' - name: 'Upload installer artifact' uses: actions/upload-artifact@v4 with: name: AmneziaVPN_MacOS_installer - path: deploy/build/pkg/AmneziaVPN.pkg + path: AmneziaVPN.dmg retention-days: 7 - name: 'Upload unpacked artifact' @@ -374,6 +394,87 @@ jobs: path: deploy/build/client/AmneziaVPN.app retention-days: 7 +# ------------------------------------------------------ + Build-MacOS-NE: + runs-on: macos-15 + + 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 }} + 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: '16.2' + + - 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: | + set -o pipefail + 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 + # sed -u -e '/-Xcc -DPROD_AGW_PUBLIC_KEY/,/-Xcc/ { /-Xcc/!d; }' -e '/-Xcc -DPROD_AGW_PUBLIC_KEY/d' | \ + # sed -u -e '/-Xcc -DDEV_AGW_PUBLIC_KEY/,/-Xcc/ { /-Xcc/!d; }' -e '/-Xcc -DDEV_AGW_PUBLIC_KEY/d' | \ + # sed -u -e '/-DPROD_AGW_PUBLIC_KEY/,/-D/ { /-D/!d; }' -e '/-DPROD_AGW_PUBLIC_KEY/d' | \ + # sed -u -e '/-DDEV_AGW_PUBLIC_KEY/,/-D/ { /-D/!d; }' -e '/-DDEV_AGW_PUBLIC_KEY/d' + + 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 }} + MAC_APP_PROVISIONING_PROFILE: ${{ secrets.APPSTORE_CONNECT_MAC_PROVISIONING }} + MAC_NE_PROVISIONING_PROFILE: ${{ 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 .app and dSYMs to artifacts' + uses: actions/upload-artifact@v4 + with: + name: macos app & dsyms + path: | + ${{ github.workspace }}/AmneziaVPN.app + retention-days: 7 # ------------------------------------------------------ Build-Android: diff --git a/.gitmodules b/.gitmodules index 90edb582..decab9b7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,6 @@ [submodule "client/3rd-prebuilt"] path = client/3rd-prebuilt url = https://github.com/amnezia-vpn/3rd-prebuilt - branch = feature/special-handshake [submodule "client/3rd/amneziawg-apple"] path = client/3rd/amneziawg-apple url = https://github.com/amnezia-vpn/amneziawg-apple diff --git a/CMakeLists.txt b/CMakeLists.txt index fec613de..a6e50934 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR) set(PROJECT AmneziaVPN) -project(${PROJECT} VERSION 4.8.8.1 +project(${PROJECT} VERSION 4.8.7.0 DESCRIPTION "AmneziaVPN" HOMEPAGE_URL "https://amnezia.org/" ) @@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d") set(RELEASE_DATE "${CURRENT_DATE}") set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}) -set(APP_ANDROID_VERSION_CODE 2087) +set(APP_ANDROID_VERSION_CODE 2084) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(MZ_PLATFORM_NAME "linux") @@ -31,13 +31,19 @@ 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) + if(IOS) + set(CMAKE_OSX_ARCHITECTURES "arm64") + elseif(MACOS_NE) + set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") + else() + set(CMAKE_OSX_ARCHITECTURES "x86_64") + endif() endif() 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/3rd-prebuilt b/client/3rd-prebuilt index 840b7b07..f5d8deeb 160000 --- a/client/3rd-prebuilt +++ b/client/3rd-prebuilt @@ -1 +1 @@ -Subproject commit 840b7b070e6ac8b90dda2fac6e98859b23727c0c +Subproject commit f5d8deeb828343e21a72a95df5e428dfd589810a diff --git a/client/3rd/amneziawg-apple b/client/3rd/amneziawg-apple index 811af0a8..25f7657e 160000 --- a/client/3rd/amneziawg-apple +++ b/client/3rd/amneziawg-apple @@ -1 +1 @@ -Subproject commit 811af0a83b3faeade89a9093a588595666d32066 +Subproject commit 25f7657eb593ae00cb722358f0fb8c777a509424 diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index a454142d..96cb0424 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR) set(PROJECT AmneziaVPN) project(${PROJECT}) - set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER "Autogen") set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Autogen") @@ -53,6 +52,9 @@ endif() qt_standard_project_setup() qt_add_executable(${PROJECT} MANUAL_FINALIZATION) +target_include_directories(${PROJECT} PUBLIC + $ +) if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID)) qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep) @@ -110,6 +112,15 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) +if(MACOS_NE) + message("MACOS_NE is ON") + add_definitions(-DQ_OS_MAC) + add_definitions(-DMACOS_NE) + message("Add macros for MacOS Network Extension") +else() + message("MACOS_NE is OFF") +endif() + include_directories(mozilla) include_directories(mozilla/shared) include_directories(mozilla/models) @@ -139,7 +150,7 @@ if(WIN32) endif() if(APPLE) - cmake_policy(SET CMP0099 OLD) + cmake_policy(SET CMP0099 NEW) cmake_policy(SET CMP0114 NEW) if(NOT BUILD_OSX_APP_IDENTIFIER) @@ -158,7 +169,6 @@ if(APPLE) set(CMAKE_XCODE_GENERATE_SCHEME FALSE) set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${BUILD_VPN_DEVELOPMENT_TEAM}) set(CMAKE_XCODE_ATTRIBUTE_GROUP_ID_IOS ${BUILD_IOS_GROUP_IDENTIFIER}) - endif() if(LINUX AND NOT ANDROID) @@ -166,8 +176,7 @@ 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") +if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID)) add_compile_definitions(AMNEZIA_DESKTOP) endif() @@ -178,7 +187,9 @@ endif() if(IOS) include(cmake/ios.cmake) include(cmake/ios-arch-fixup.cmake) -elseif(APPLE AND NOT IOS) +elseif(APPLE AND MACOS_NE) + include(cmake/macos_ne.cmake) +elseif(APPLE) include(cmake/osxtools.cmake) include(cmake/macos.cmake) endif() @@ -199,7 +210,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> @@ -214,7 +225,6 @@ if(NOT IOS AND NOT ANDROID) $ COMMAND_EXPAND_LISTS ) - endif() target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC}) diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index f32d525a..4a585ac0 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "logger.h" #include "ui/controllers/pageController.h" @@ -21,6 +22,8 @@ #include "platforms/ios/QRCodeReaderBase.h" #include "protocols/qml_register_protocols.h" +#include // for QQuickWindow +#include // for qobject_cast AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv) { @@ -63,12 +66,19 @@ void AmneziaApplication::init() const QUrl url(QStringLiteral("qrc:/ui/qml/main2.qml")); QObject::connect( - m_engine, &QQmlApplicationEngine::objectCreated, this, - [url](QObject *obj, const QUrl &objUrl) { - if (!obj && url == objUrl) - QCoreApplication::exit(-1); - }, - Qt::QueuedConnection); + m_engine, &QQmlApplicationEngine::objectCreated, this, + [this, url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) { + QCoreApplication::exit(-1); + return; + } + // install filter on main window + if (auto win = qobject_cast(obj)) { + win->installEventFilter(this); + win->show(); + } + }, + Qt::QueuedConnection); m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance()); @@ -167,7 +177,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)) { @@ -179,9 +189,8 @@ bool AmneziaApplication::parseCommands() return true; } -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) -void AmneziaApplication::startLocalServer() -{ +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) +void AmneziaApplication::startLocalServer() { const QString serverName("AmneziaVPNInstance"); QLocalServer::removeServer(serverName); @@ -198,6 +207,22 @@ void AmneziaApplication::startLocalServer() } #endif +bool AmneziaApplication::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::Close) { +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + quit(); +#else + if (m_coreController && m_coreController->pageController()) { + m_coreController->pageController()->hideMainWindow(); + } +#endif + return true; // eat the close + } + // call base QObject::eventFilter + return QObject::eventFilter(watched, event); +} + QQmlApplicationEngine *AmneziaApplication::qmlEngine() const { return m_engine; diff --git a/client/amnezia_application.h b/client/amnezia_application.h index ea5f6f52..28aefab0 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -7,9 +7,9 @@ #include #include #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - #include + #include #else - #include + #include #endif #include @@ -20,9 +20,9 @@ #define amnApp (static_cast(QCoreApplication::instance())) #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - #define AMNEZIA_BASE_CLASS QGuiApplication + #define AMNEZIA_BASE_CLASS QGuiApplication #else - #define AMNEZIA_BASE_CLASS QApplication + #define AMNEZIA_BASE_CLASS QApplication #endif class AmneziaApplication : public AMNEZIA_BASE_CLASS @@ -37,7 +37,7 @@ public: void loadFonts(); 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 @@ -60,6 +60,8 @@ private: QThread m_vpnConnectionThread; QNetworkAccessManager *m_nam; +protected: + bool eventFilter(QObject *watched, QEvent *event) override; }; #endif // AMNEZIA_APPLICATION_H diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt index 42a27de4..80cab96d 100644 --- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt +++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt @@ -120,21 +120,10 @@ open class Wireguard : Protocol() { configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) } configData.optStringOrNull("S1")?.let { setS1(it.toInt()) } configData.optStringOrNull("S2")?.let { setS2(it.toInt()) } - configData.optStringOrNull("S3")?.let { setS3(it.toInt()) } - configData.optStringOrNull("S4")?.let { setS4(it.toInt()) } configData.optStringOrNull("H1")?.let { setH1(it.toLong()) } configData.optStringOrNull("H2")?.let { setH2(it.toLong()) } configData.optStringOrNull("H3")?.let { setH3(it.toLong()) } configData.optStringOrNull("H4")?.let { setH4(it.toLong()) } - configData.optStringOrNull("I1")?.let { setI1(it) } - configData.optStringOrNull("I2")?.let { setI2(it) } - configData.optStringOrNull("I3")?.let { setI3(it) } - configData.optStringOrNull("I4")?.let { setI4(it) } - configData.optStringOrNull("I5")?.let { setI5(it) } - configData.optStringOrNull("J1")?.let { setJ1(it) } - configData.optStringOrNull("J2")?.let { setJ2(it) } - configData.optStringOrNull("J3")?.let { setJ3(it) } - configData.optStringOrNull("Itime")?.let { setItime(it.toInt()) } } private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) { diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt index 2dfbbae8..7ae3d43b 100644 --- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt +++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt @@ -20,21 +20,10 @@ open class WireguardConfig protected constructor( val jmax: Int?, val s1: Int?, val s2: Int?, - val s3: Int?, - val s4: Int?, val h1: Long?, val h2: Long?, val h3: Long?, - val h4: Long?, - var i1: String?, - var i2: String?, - var i3: String?, - var i4: String?, - var i5: String?, - var j1: String?, - var j2: String?, - var j3: String?, - var itime: Int? + val h4: Long? ) : ProtocolConfig(protocolConfigBuilder) { protected constructor(builder: Builder) : this( @@ -50,21 +39,10 @@ open class WireguardConfig protected constructor( builder.jmax, builder.s1, builder.s2, - builder.s3, - builder.s4, builder.h1, builder.h2, builder.h3, - builder.h4, - builder.i1, - builder.i2, - builder.i3, - builder.i4, - builder.i5, - builder.j1, - builder.j2, - builder.j3, - builder.itime + builder.h4 ) fun toWgUserspaceString(): String = with(StringBuilder()) { @@ -83,21 +61,10 @@ open class WireguardConfig protected constructor( appendLine("jmax=$jmax") appendLine("s1=$s1") appendLine("s2=$s2") - s3?.let { appendLine("s3=$it") } - s4?.let { appendLine("s4=$it") } appendLine("h1=$h1") appendLine("h2=$h2") appendLine("h3=$h3") appendLine("h4=$h4") - i1?.let { appendLine("i1=$it") } - i2?.let { appendLine("i2=$it") } - i3?.let { appendLine("i3=$it") } - i4?.let { appendLine("i4=$it") } - i5?.let { appendLine("i5=$it") } - j1?.let { appendLine("j1=$it") } - j2?.let { appendLine("j2=$it") } - j3?.let { appendLine("j3=$it") } - itime?.let { appendLine("itime=$it") } } } @@ -150,21 +117,10 @@ open class WireguardConfig protected constructor( internal var jmax: Int? = null internal var s1: Int? = null internal var s2: Int? = null - internal var s3: Int? = null - internal var s4: Int? = null internal var h1: Long? = null internal var h2: Long? = null internal var h3: Long? = null internal var h4: Long? = null - internal var i1: String? = null - internal var i2: String? = null - internal var i3: String? = null - internal var i4: String? = null - internal var i5: String? = null - internal var j1: String? = null - internal var j2: String? = null - internal var j3: String? = null - internal var itime: Int? = null fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint } @@ -183,21 +139,10 @@ open class WireguardConfig protected constructor( fun setJmax(jmax: Int) = apply { this.jmax = jmax } fun setS1(s1: Int) = apply { this.s1 = s1 } fun setS2(s2: Int) = apply { this.s2 = s2 } - fun setS3(s3: Int) = apply { this.s3 = s3 } - fun setS4(s4: Int) = apply { this.s4 = s4 } fun setH1(h1: Long) = apply { this.h1 = h1 } fun setH2(h2: Long) = apply { this.h2 = h2 } fun setH3(h3: Long) = apply { this.h3 = h3 } fun setH4(h4: Long) = apply { this.h4 = h4 } - fun setI1(i1: String) = apply { this.i1 = i1 } - fun setI2(i2: String) = apply { this.i2 = i2 } - fun setI3(i3: String) = apply { this.i3 = i3 } - fun setI4(i4: String) = apply { this.i4 = i4 } - fun setI5(i5: String) = apply { this.i5 = i5 } - fun setJ1(j1: String) = apply { this.j1 = j1 } - fun setJ2(j2: String) = apply { this.j2 = j2 } - fun setJ3(j3: String) = apply { this.j3 = j3 } - fun setItime(itime: Int) = apply { this.itime = itime } override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) } } diff --git a/client/cmake/3rdparty.cmake b/client/cmake/3rdparty.cmake index 2b5036c5..6c372614 100644 --- a/client/cmake/3rdparty.cmake +++ b/client/cmake/3rdparty.cmake @@ -27,9 +27,15 @@ 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") + if(MACOS_NE) + set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/universal2/libssh.a") + set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/universal2/libz.a") + set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/universal2") + else() + set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libssh.a") + set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libz.a") + set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/x86_64") + endif() set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/macos/include") set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libssl.a") set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libcrypto.a") diff --git a/client/cmake/ios.cmake b/client/cmake/ios.cmake index a498a5b1..cb66924f 100644 --- a/client/cmake/ios.cmake +++ b/client/cmake/ios.cmake @@ -83,8 +83,8 @@ if(DEFINED DEPLOY) XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution" XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development" XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual - XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr ios.org.amnezia.AmneziaVPN" - XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev ios.org.amnezia.AmneziaVPN" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "match AppStore org.amnezia.AmneziaVPN" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "match Development org.amnezia.AmneziaVPN" ) else() set_target_properties(${PROJECT} PROPERTIES diff --git a/client/cmake/macos.cmake b/client/cmake/macos.cmake index 7b7cd381..3cf605ae 100644 --- a/client/cmake/macos.cmake +++ b/client/cmake/macos.cmake @@ -31,6 +31,8 @@ set(SOURCES ${SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/ui/macos_util.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) diff --git a/client/cmake/macos_ne.cmake b/client/cmake/macos_ne.cmake new file mode 100644 index 00000000..90876a35 --- /dev/null +++ b/client/cmake/macos_ne.cmake @@ -0,0 +1,168 @@ +message("Client ==> MacOS NE build") + +set_target_properties(${PROJECT} PROPERTIES MACOSX_BUNDLE TRUE) +set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15) + +set(APPLE_PROJECT_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}) + +enable_language(OBJC) +enable_language(Swift) + +find_package(Qt6 REQUIRED COMPONENTS ShaderTools Widgets) +# Link Qt Widgets for QWidget, QMenu, QAction etc. +set(LIBS ${LIBS} Qt6::ShaderTools Qt6::Widgets) + +find_library(FW_AUTHENTICATIONSERVICES AuthenticationServices) +find_library(FW_AVFOUNDATION AVFoundation) +find_library(FW_FOUNDATION Foundation) +find_library(FW_STOREKIT StoreKit) +find_library(FW_SERVICEMGMT ServiceManagement) +find_library(FW_USERNOTIFICATIONS UserNotifications) +find_library(FW_NETWORKEXTENSION NetworkExtension) + +set(LIBS ${LIBS} + ${FW_AUTHENTICATIONSERVICES} + ${FW_AVFOUNDATION} + ${FW_FOUNDATION} + ${FW_STOREKIT} + ${FW_SERVICEMGMT} + ${FW_USERNOTIFICATIONS} + ${FW_NETWORKEXTENSION} +) + + +set(HEADERS ${HEADERS} + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller_wrapper.h + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.h + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.h + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate-C-Interface.h +) +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h PROPERTIES OBJECTIVE_CPP_HEADER TRUE) + + +set(SOURCES ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.mm + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller_wrapper.mm + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.mm + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm +) + +set(ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/app.icns) +set(MACOSX_BUNDLE_ICON_FILE app.icns) +set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) +set(SOURCES ${SOURCES} ${ICON_FILE}) + + +target_include_directories(${PROJECT} PRIVATE + ${Qt6Gui_PRIVATE_INCLUDE_DIRS} + ${Qt6Widgets_PRIVATE_INCLUDE_DIRS} +) + + +set_target_properties(${PROJECT} PROPERTIES + XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Info.plist.in + MACOSX_BUNDLE_ICON_FILE "AppIcon" + MACOSX_BUNDLE_INFO_STRING "AmneziaVPN" + MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPN" + MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}" + MACOSX_BUNDLE_LONG_VERSION_STRING "${APPLE_PROJECT_VERSION}-${CMAKE_PROJECT_VERSION_TWEAK}" + MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}" + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/macos/app/app.entitlements" + XCODE_ATTRIBUTE_MARKETING_VERSION "${APPLE_PROJECT_VERSION}" + XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}" + XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPN" + XCODE_ATTRIBUTE_BUNDLE_INFO_STRING "AmneziaVPN" + XCODE_GENERATE_SCHEME TRUE + XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon" + XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" + XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY "NO" + XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY "YES" + XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "11.0" + + XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks" + XCODE_EMBED_APP_EXTENSIONS AmneziaVPNNetworkExtension +) + +if(DEPLOY) + set_target_properties(${PROJECT} PROPERTIES + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development" + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr macos.org.amnezia.AmneziaVPN" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev macos.org.amnezia.AmneziaVPN" + ) +else() + set_target_properties(${PROJECT} PROPERTIES + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic + ) +endif() + +set_target_properties(${PROJECT} PROPERTIES + XCODE_ATTRIBUTE_SWIFT_VERSION "5.0" + XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES" + XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO" + XCODE_ATTRIBUTE_SWIFT_OBJC_INTERFACE_HEADER_NAME "AmneziaVPN-Swift.h" + XCODE_ATTRIBUTE_SWIFT_OBJC_INTEROP_MODE "objcxx" +) +set_target_properties(${PROJECT} PROPERTIES + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK" +) +target_include_directories(${PROJECT} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) +target_compile_options(${PROJECT} PRIVATE + -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\" + -DVPN_NE_BUNDLEID=\"${BUILD_IOS_APP_IDENTIFIER}.network-extension\" +) + +set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/amneziawg-apple/Sources) + +target_sources(${PROJECT} PRIVATE + ${WG_APPLE_SOURCE_DIR}/WireGuardKitC/x25519.c + ${CLIENT_ROOT_DIR}/platforms/ios/LogController.swift + ${CLIENT_ROOT_DIR}/platforms/ios/Log.swift + ${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift + ${CLIENT_ROOT_DIR}/platforms/ios/ScreenProtection.swift + ${CLIENT_ROOT_DIR}/platforms/ios/VPNCController.swift +) + +target_sources(${PROJECT} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Images.xcassets + ${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy +) + +set_property(TARGET ${PROJECT} APPEND PROPERTY RESOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Images.xcassets + ${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy +) + +add_subdirectory(macos/networkextension) +add_dependencies(${PROJECT} AmneziaVPNNetworkExtension) + +get_target_property(QtCore_location Qt6::Core LOCATION) +message("QtCore_location") +message(${QtCore_location}) + +get_filename_component(QT_BIN_DIR_DETECTED "${QtCore_location}/../../../../../bin" ABSOLUTE) + +set_property(TARGET ${PROJECT} PROPERTY XCODE_EMBED_FRAMEWORKS + "${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos/OpenVPNAdapter.framework" +) + +set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos) +target_link_libraries("AmneziaVPNNetworkExtension" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos/OpenVPNAdapter.framework") + +add_custom_command(TARGET ${PROJECT} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Contents/Frameworks + COMMAND /usr/bin/find "$/Contents/Frameworks/OpenVPNAdapter.framework" -name "*.sha256" -delete + COMMAND /usr/bin/codesign --force --sign "Apple Distribution" + "$/Contents/Frameworks/OpenVPNAdapter.framework/Versions/Current/OpenVPNAdapter" + COMMAND ${QT_BIN_DIR_DETECTED}/macdeployqt $ -appstore-compliant -qmldir=${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Signing OpenVPNAdapter framework" +) diff --git a/client/cmake/sources.cmake b/client/cmake/sources.cmake index c3af531a..3161be58 100644 --- a/client/cmake/sources.cmake +++ b/client/cmake/sources.cmake @@ -39,7 +39,7 @@ set(HEADERS ${HEADERS} ${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.h ) -if(NOT IOS) +if(NOT IOS AND NOT MACOS_NE) set(HEADERS ${HEADERS} ${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.h ) @@ -89,12 +89,24 @@ set(SOURCES ${SOURCES} ${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp ) -if(NOT IOS) +if(NOT IOS AND NOT MACOS_NE) set(SOURCES ${SOURCES} ${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.cpp ) endif() +# Include native macOS platform helpers (dock/status-item) +if(APPLE AND NOT IOS) + list(APPEND HEADERS + ${CLIENT_ROOT_DIR}/platforms/macos/macosutils.h + ${CLIENT_ROOT_DIR}/platforms/macos/macosstatusicon.h + ) + list(APPEND SOURCES + ${CLIENT_ROOT_DIR}/platforms/macos/macosutils.mm + ${CLIENT_ROOT_DIR}/platforms/macos/macosstatusicon.mm + ) +endif() + if(NOT ANDROID) set(SOURCES ${SOURCES} ${CLIENT_ROOT_DIR}/ui/notificationhandler.cpp diff --git a/client/configurators/awg_configurator.cpp b/client/configurators/awg_configurator.cpp index f83acb19..21b61ba4 100644 --- a/client/configurators/awg_configurator.cpp +++ b/client/configurators/awg_configurator.cpp @@ -1,5 +1,4 @@ #include "awg_configurator.h" -#include "protocols/protocols_defs.h" #include #include @@ -40,20 +39,6 @@ QString AwgConfigurator::createConfig(const ServerCredentials &credentials, Dock jsonConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader); jsonConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader); jsonConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader); - - // jsonConfig[config_key::cookieReplyPacketJunkSize] = configMap.value(config_key::cookieReplyPacketJunkSize); - // jsonConfig[config_key::transportPacketJunkSize] = configMap.value(config_key::transportPacketJunkSize); - - // jsonConfig[config_key::specialJunk1] = configMap.value(amnezia::config_key::specialJunk1); - // jsonConfig[config_key::specialJunk2] = configMap.value(amnezia::config_key::specialJunk2); - // jsonConfig[config_key::specialJunk3] = configMap.value(amnezia::config_key::specialJunk3); - // jsonConfig[config_key::specialJunk4] = configMap.value(amnezia::config_key::specialJunk4); - // jsonConfig[config_key::specialJunk5] = configMap.value(amnezia::config_key::specialJunk5); - // jsonConfig[config_key::controlledJunk1] = configMap.value(amnezia::config_key::controlledJunk1); - // jsonConfig[config_key::controlledJunk2] = configMap.value(amnezia::config_key::controlledJunk2); - // jsonConfig[config_key::controlledJunk3] = configMap.value(amnezia::config_key::controlledJunk3); - // jsonConfig[config_key::specialHandshakeTimeout] = configMap.value(amnezia::config_key::specialHandshakeTimeout); - jsonConfig[config_key::mtu] = containerConfig.value(ProtocolProps::protoToString(Proto::Awg)).toObject().value(config_key::mtu).toString(protocols::awg::defaultMtu); diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index f6996320..4f7a035c 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -118,12 +118,6 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPairisSitesSplitTunnelingEnabled()) { config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n"); config.append("block-ipv6\n"); @@ -131,7 +125,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 #endif @@ -167,12 +161,6 @@ QString OpenVpnConfigurator::processConfigWithExportSettings(const QPair #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_MACX) && !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 214e2a51..3fff3e20 100644 --- a/client/containers/containers_defs.cpp +++ b/client/containers/containers_defs.cpp @@ -260,7 +260,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/api/apiDefs.h b/client/core/api/apiDefs.h index 12c8051f..6d1a27fa 100644 --- a/client/core/api/apiDefs.h +++ b/client/core/api/apiDefs.h @@ -31,8 +31,6 @@ namespace apiDefs constexpr QLatin1String apiConfig("api_config"); constexpr QLatin1String stackType("stack_type"); constexpr QLatin1String serviceType("service_type"); - constexpr QLatin1String cliVersion("cli_version"); - constexpr QLatin1String supportedProtocols("supported_protocols"); constexpr QLatin1String vpnKey("vpn_key"); constexpr QLatin1String config("config"); diff --git a/client/core/api/apiUtils.cpp b/client/core/api/apiUtils.cpp index 7f3e6db3..f85d2207 100644 --- a/client/core/api/apiUtils.cpp +++ b/client/core/api/apiUtils.cpp @@ -41,34 +41,32 @@ bool apiUtils::isServerFromApi(const QJsonObject &serverConfigObject) apiDefs::ConfigType apiUtils::getConfigType(const QJsonObject &serverConfigObject) { auto configVersion = serverConfigObject.value(apiDefs::key::configVersion).toInt(); - switch (configVersion) { case apiDefs::ConfigSource::Telegram: { - constexpr QLatin1String freeV2Endpoint(FREE_V2_ENDPOINT); - constexpr QLatin1String premiumV1Endpoint(PREM_V1_ENDPOINT); - - auto apiEndpoint = serverConfigObject.value(apiDefs::key::apiEndpoint).toString(); - - if (apiEndpoint.contains(premiumV1Endpoint)) { - return apiDefs::ConfigType::AmneziaPremiumV1; - } else if (apiEndpoint.contains(freeV2Endpoint)) { - return apiDefs::ConfigType::AmneziaFreeV2; - } }; case apiDefs::ConfigSource::AmneziaGateway: { constexpr QLatin1String servicePremium("amnezia-premium"); constexpr QLatin1String serviceFree("amnezia-free"); constexpr QLatin1String serviceExternalPremium("external-premium"); + constexpr QLatin1String freeV2Endpoint(FREE_V2_ENDPOINT); + constexpr QLatin1String premiumV1Endpoint(PREM_V1_ENDPOINT); + auto apiConfigObject = serverConfigObject.value(apiDefs::key::apiConfig).toObject(); auto serviceType = apiConfigObject.value(apiDefs::key::serviceType).toString(); + auto apiEndpoint = serverConfigObject.value(apiDefs::key::apiEndpoint).toString(); + if (serviceType == servicePremium) { return apiDefs::ConfigType::AmneziaPremiumV2; } else if (serviceType == serviceFree) { return apiDefs::ConfigType::AmneziaFreeV3; } else if (serviceType == serviceExternalPremium) { return apiDefs::ConfigType::ExternalPremium; + } else if (apiEndpoint.contains(premiumV1Endpoint)) { + return apiDefs::ConfigType::AmneziaPremiumV1; + } else if (apiEndpoint.contains(freeV2Endpoint)) { + return apiDefs::ConfigType::AmneziaFreeV2; } } default: { @@ -96,9 +94,6 @@ amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList &ssl || reply->error() == QNetworkReply::NetworkError::TimeoutError) { qDebug() << reply->error(); return amnezia::ErrorCode::ApiConfigTimeoutError; - } else if (reply->error() == QNetworkReply::NetworkError::OperationNotImplementedError) { - qDebug() << reply->error(); - return amnezia::ErrorCode::ApiUpdateRequestError; } else { QString err = reply->errorString(); int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); diff --git a/client/core/controllers/gatewayController.cpp b/client/core/controllers/gatewayController.cpp index 26855ae6..9a7ee6e5 100644 --- a/client/core/controllers/gatewayController.cpp +++ b/client/core/controllers/gatewayController.cpp @@ -36,8 +36,6 @@ namespace constexpr QLatin1String errorResponsePattern1("No active configuration found for"); constexpr QLatin1String errorResponsePattern2("No non-revoked public key found for"); constexpr QLatin1String errorResponsePattern3("Account not found."); - - constexpr QLatin1String updateRequestResponsePattern("client version update is required"); } GatewayController::GatewayController(const QString &gatewayEndpoint, const bool isDevEnvironment, const int requestTimeoutMsecs, @@ -313,13 +311,6 @@ bool GatewayController::shouldBypassProxy(QNetworkReply *reply, const QByteArray qDebug() << reply->error(); return true; } - } else if (reply->error() == QNetworkReply::NetworkError::OperationNotImplementedError) { - if (responseBody.contains(updateRequestResponsePattern)) { - return false; - } else { - qDebug() << reply->error(); - return true; - } } else if (reply->error() != QNetworkReply::NetworkError::NoError) { qDebug() << reply->error(); return true; diff --git a/client/core/controllers/serverController.cpp b/client/core/controllers/serverController.cpp index 3c24edea..8ff6b6c8 100644 --- a/client/core/controllers/serverController.cpp +++ b/client/core/controllers/serverController.cpp @@ -349,7 +349,7 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) != newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)) || (oldProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort) - != newProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)) + != newProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)) || (oldProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount) != newProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount)) || (oldProtoConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize) @@ -366,13 +366,8 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c != newProtoConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader)) || (oldProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader) != newProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader)) - || (oldProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader)) - != newProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader)) - // || (oldProtoConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize) - // != newProtoConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize)) - // || (oldProtoConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize) - // != newProtoConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize)) - + || (oldProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader) + != newProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader))) return true; } @@ -380,7 +375,7 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) != newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)) || (oldProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) - != newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort))) + != newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort))) return true; } @@ -460,13 +455,11 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden runScript(credentials, replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)), cbReadStdOut, cbReadStdErr); - + if (stdOut.contains("doesn't work on cgroups v2")) return ErrorCode::ServerDockerOnCgroupsV2; if (stdOut.contains("cgroup mountpoint does not exist")) return ErrorCode::ServerCgroupMountpoint; - if (stdOut.contains("have reached") && stdOut.contains("pull rate limit")) - return ErrorCode::DockerPullRateLimit; return error; } @@ -646,9 +639,6 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential vars.append({ { "$UNDERLOAD_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::underloadPacketMagicHeader).toString() } }); vars.append({ { "$TRANSPORT_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::transportPacketMagicHeader).toString() } }); - vars.append({ { "$COOKIE_REPLY_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::cookieReplyPacketJunkSize).toString() } }); - vars.append({ { "$TRANSPORT_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::transportPacketJunkSize).toString() } }); - // Socks5 proxy vars vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } }); auto username = socks5ProxyConfig.value(config_key::userName).toString(); @@ -835,7 +825,7 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential if (stdOut.contains("Packet manager not found")) return ErrorCode::ServerPacketManagerError; - if (stdOut.contains("fuser not installed") || stdOut.contains("cat not installed")) + if (stdOut.contains("fuser not installed")) return ErrorCode::NoError; if (stdOut.isEmpty()) { diff --git a/client/core/defs.h b/client/core/defs.h index 64f52ce6..674d1add 100644 --- a/client/core/defs.h +++ b/client/core/defs.h @@ -60,7 +60,6 @@ namespace amnezia ServerUserPasswordRequired = 210, ServerDockerOnCgroupsV2 = 211, ServerCgroupMountpoint = 212, - DockerPullRateLimit = 213, // Ssh connection errors SshRequestDeniedError = 300, @@ -119,7 +118,6 @@ namespace amnezia ApiConfigLimitError = 1108, ApiNotFoundError = 1109, ApiMigrationError = 1110, - ApiUpdateRequestError = 1111, // QFile errors OpenError = 1200, diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp index bd5ccaba..e141b3c7 100644 --- a/client/core/errorstrings.cpp +++ b/client/core/errorstrings.cpp @@ -28,7 +28,6 @@ QString errorString(ErrorCode code) { case(ErrorCode::ServerUserPasswordRequired): errorMessage = QObject::tr("The user's password is required"); break; case(ErrorCode::ServerDockerOnCgroupsV2): errorMessage = QObject::tr("Docker error: runc doesn't work on cgroups v2"); break; case(ErrorCode::ServerCgroupMountpoint): errorMessage = QObject::tr("Server error: cgroup mountpoint does not exist"); break; - case(ErrorCode::DockerPullRateLimit): errorMessage = QObject::tr("Docker error: The pull rate limit has been reached"); break; // Libssh errors case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break; @@ -76,7 +75,6 @@ QString errorString(ErrorCode code) { case (ErrorCode::ApiConfigLimitError): errorMessage = QObject::tr("The limit of allowed configurations per subscription has been exceeded"); break; case (ErrorCode::ApiNotFoundError): errorMessage = QObject::tr("Error when retrieving configuration from API"); break; case (ErrorCode::ApiMigrationError): errorMessage = QObject::tr("A migration error has occurred. Please contact our technical support"); break; - case (ErrorCode::ApiUpdateRequestError): errorMessage = QObject::tr("Please update the application to use this feature"); break; // QFile errors case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break; diff --git a/client/core/networkUtilities.cpp b/client/core/networkUtilities.cpp index cf33fa55..9c245948 100644 --- a/client/core/networkUtilities.cpp +++ b/client/core/networkUtilities.cpp @@ -23,7 +23,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 @@ -390,7 +390,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/daemon/daemon.cpp b/client/daemon/daemon.cpp index 2faff0ef..e4b0ab3d 100644 --- a/client/daemon/daemon.cpp +++ b/client/daemon/daemon.cpp @@ -149,7 +149,8 @@ bool Daemon::activate(const InterfaceConfig& config) { // set routing for (const IPAddress& ip : config.m_allowedIPAddressRanges) { if (!wgutils()->updateRoutePrefix(ip)) { - logger.debug() << "Routing configuration failed for" << ip.toString(); + logger.debug() << "Routing configuration failed for" + << logger.sensitive(ip.toString()); return false; } } @@ -169,14 +170,11 @@ bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) { if ((config.m_hopType == InterfaceConfig::MultiHopExit) || (config.m_hopType == InterfaceConfig::SingleHop)) { QList resolvers; - resolvers.append(QHostAddress(config.m_primaryDnsServer)); - if (!config.m_secondaryDnsServer.isEmpty()) { - resolvers.append(QHostAddress(config.m_secondaryDnsServer)); - } + resolvers.append(QHostAddress(config.m_dnsServer)); // If the DNS is not the Gateway, it's a user defined DNS // thus, not add any other :) - if (config.m_primaryDnsServer == config.m_serverIpv4Gateway) { + if (config.m_dnsServer == config.m_serverIpv4Gateway) { resolvers.append(QHostAddress(config.m_serverIpv6Gateway)); } @@ -282,26 +280,15 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) { config.m_serverIpv4Gateway = obj.value("serverIpv4Gateway").toString(); config.m_serverIpv6Gateway = obj.value("serverIpv6Gateway").toString(); - if (!obj.contains("primaryDnsServer")) { - config.m_primaryDnsServer = QString(); + if (!obj.contains("dnsServer")) { + config.m_dnsServer = QString(); } else { - QJsonValue value = obj.value("primaryDnsServer"); + QJsonValue value = obj.value("dnsServer"); if (!value.isString()) { logger.error() << "dnsServer is not a string"; return false; } - config.m_primaryDnsServer = value.toString(); - } - - if (!obj.contains("secondaryDnsServer")) { - config.m_secondaryDnsServer = QString(); - } else { - QJsonValue value = obj.value("secondaryDnsServer"); - if (!value.isString()) { - logger.error() << "dnsServer is not a string"; - return false; - } - config.m_secondaryDnsServer = value.toString(); + config.m_dnsServer = value.toString(); } if (!obj.contains("hopType")) { @@ -405,13 +392,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) { if (!obj.value("S2").isNull()) { config.m_responsePacketJunkSize = obj.value("S2").toString(); } - if (!obj.value("S3").isNull()) { - config.m_cookieReplyPacketJunkSize = obj.value("S3").toString(); - } - if (!obj.value("S4").isNull()) { - config.m_transportPacketJunkSize = obj.value("S4").toString(); - } - if (!obj.value("H1").isNull()) { config.m_initPacketMagicHeader = obj.value("H1").toString(); } @@ -425,34 +405,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) { config.m_transportPacketMagicHeader = obj.value("H4").toString(); } - if (!obj.value("I1").isNull()) { - config.m_specialJunk["I1"] = obj.value("I1").toString(); - } - if (!obj.value("I2").isNull()) { - config.m_specialJunk["I2"] = obj.value("I2").toString(); - } - if (!obj.value("I3").isNull()) { - config.m_specialJunk["I3"] = obj.value("I3").toString(); - } - if (!obj.value("I4").isNull()) { - config.m_specialJunk["I4"] = obj.value("I4").toString(); - } - if (!obj.value("I5").isNull()) { - config.m_specialJunk["I5"] = obj.value("I5").toString(); - } - if (!obj.value("J1").isNull()) { - config.m_controlledJunk["J1"] = obj.value("J1").toString(); - } - if (!obj.value("J2").isNull()) { - config.m_controlledJunk["J2"] = obj.value("J2").toString(); - } - if (!obj.value("J3").isNull()) { - config.m_controlledJunk["J3"] = obj.value("J3").toString(); - } - if (!obj.value("Itime").isNull()) { - config.m_specialHandshakeTimeout = obj.value("Itime").toString(); - } - return true; } @@ -495,7 +447,7 @@ bool Daemon::deactivate(bool emitSignals) { m_connections.clear(); // Delete the interface - return wgutils()->deleteInterface(); + return wgutils()->deleteInterface(); } QString Daemon::logs() { diff --git a/client/daemon/interfaceconfig.cpp b/client/daemon/interfaceconfig.cpp index 53da5d36..f0adcc92 100644 --- a/client/daemon/interfaceconfig.cpp +++ b/client/daemon/interfaceconfig.cpp @@ -28,8 +28,7 @@ QJsonObject InterfaceConfig::toJson() const { (m_hopType == InterfaceConfig::SingleHop)) { json.insert("serverIpv4Gateway", QJsonValue(m_serverIpv4Gateway)); json.insert("serverIpv6Gateway", QJsonValue(m_serverIpv6Gateway)); - json.insert("primaryDnsServer", QJsonValue(m_primaryDnsServer)); - json.insert("secondaryDnsServer", QJsonValue(m_secondaryDnsServer)); + json.insert("dnsServer", QJsonValue(m_dnsServer)); } QJsonArray allowedIPAddesses; @@ -101,15 +100,11 @@ QString InterfaceConfig::toWgConf(const QMap& extra) const { out << "MTU = " << m_deviceMTU << "\n"; } - if (!m_primaryDnsServer.isNull()) { - QStringList dnsServers; - dnsServers.append(m_primaryDnsServer); - if (!m_secondaryDnsServer.isNull()) { - dnsServers.append(m_secondaryDnsServer); - } + if (!m_dnsServer.isNull()) { + QStringList dnsServers(m_dnsServer); // If the DNS is not the Gateway, it's a user defined DNS // thus, not add any other :) - if (m_primaryDnsServer == m_serverIpv4Gateway) { + if (m_dnsServer == m_serverIpv4Gateway) { dnsServers.append(m_serverIpv6Gateway); } out << "DNS = " << dnsServers.join(", ") << "\n"; @@ -130,12 +125,6 @@ QString InterfaceConfig::toWgConf(const QMap& extra) const { if (!m_responsePacketJunkSize.isNull()) { out << "S2 = " << m_responsePacketJunkSize << "\n"; } - if (!m_cookieReplyPacketJunkSize.isNull()) { - out << "S3 = " << m_cookieReplyPacketJunkSize << "\n"; - } - if (!m_transportPacketJunkSize.isNull()) { - out << "S4 = " << m_transportPacketJunkSize << "\n"; - } if (!m_initPacketMagicHeader.isNull()) { out << "H1 = " << m_initPacketMagicHeader << "\n"; } @@ -149,16 +138,6 @@ QString InterfaceConfig::toWgConf(const QMap& extra) const { out << "H4 = " << m_transportPacketMagicHeader << "\n"; } - for (const QString& key : m_specialJunk.keys()) { - out << key << " = " << m_specialJunk[key] << "\n"; - } - for (const QString& key : m_controlledJunk.keys()) { - out << key << " = " << m_controlledJunk[key] << "\n"; - } - if (!m_specialHandshakeTimeout.isNull()) { - out << "Itime = " << m_specialHandshakeTimeout << "\n"; - } - // If any extra config was provided, append it now. for (const QString& key : extra.keys()) { out << key << " = " << extra[key] << "\n"; diff --git a/client/daemon/interfaceconfig.h b/client/daemon/interfaceconfig.h index 06288e80..ee43a253 100644 --- a/client/daemon/interfaceconfig.h +++ b/client/daemon/interfaceconfig.h @@ -32,8 +32,7 @@ class InterfaceConfig { QString m_serverIpv4AddrIn; QString m_serverPskKey; QString m_serverIpv6AddrIn; - QString m_primaryDnsServer; - QString m_secondaryDnsServer; + QString m_dnsServer; int m_serverPort = 0; int m_deviceMTU = 1420; QList m_allowedIPAddressRanges; @@ -50,15 +49,10 @@ class InterfaceConfig { QString m_junkPacketMaxSize; QString m_initPacketJunkSize; QString m_responsePacketJunkSize; - QString m_cookieReplyPacketJunkSize; - QString m_transportPacketJunkSize; QString m_initPacketMagicHeader; QString m_responsePacketMagicHeader; QString m_underloadPacketMagicHeader; QString m_transportPacketMagicHeader; - QMap m_specialJunk; - QMap m_controlledJunk; - QString m_specialHandshakeTimeout; QJsonObject toJson() const; QString toWgConf( diff --git a/client/ios/networkextension/CMakeLists.txt b/client/ios/networkextension/CMakeLists.txt index 64b1c3c4..329bf3bc 100644 --- a/client/ios/networkextension/CMakeLists.txt +++ b/client/ios/networkextension/CMakeLists.txt @@ -33,8 +33,8 @@ if(DEPLOY) XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution" XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development" XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual - XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr ios.org.amnezia.AmneziaVPN" - XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev ios.org.amnezia.AmneziaVPN" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "match AppStore org.amnezia.AmneziaVPN.network-extension" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "match Development org.amnezia.AmneziaVPN.network-extension" ) else() set_target_properties(networkextension PROPERTIES 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..d4d7195f 100644 --- a/client/macos/app/app.entitlements +++ b/client/macos/app/app.entitlements @@ -2,34 +2,40 @@ - com.apple.application-identifier - $(DEVELOPMENT_TEAM).$(APP_ID_MACOS) - + com.apple.developer.networking.custom-protocol + com.apple.developer.networking.networkextension + app-proxy-provider packet-tunnel-provider + dns-settings + relay + content-filter-provider + dns-proxy - + com.apple.developer.system-extension.install + + com.apple.developer.networking.vpn.api + + allow-vpn + + com.apple.security.app-sandbox + + com.apple.security.application-groups + + group.org.amnezia.AmneziaVPN + + com.apple.security.files.user-selected.read-only + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + com.apple.security.network.server + keychain-access-groups $(DEVELOPMENT_TEAM).* - - com.apple.developer.team-identifier - $(DEVELOPMENT_TEAM) - - com.apple.security.app-sandbox - - - com.apple.security.application-groups - - $(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS) - - - com.apple.security.network.client - - - com.apple.security.network.server - diff --git a/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements b/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements index b4f08784..7e2b2072 100644 --- a/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements +++ b/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements @@ -2,41 +2,30 @@ - com.apple.application-identifier - $(DEVELOPMENT_TEAM).$(NETEXT_ID_MACOS) - + com.apple.developer.networking.custom-protocol + com.apple.developer.networking.networkextension + dns-settings + relay packet-tunnel-provider + content-filter-provider + dns-proxy + app-proxy-provider - - keychain-access-groups + com.apple.developer.networking.vpn.api - $(DEVELOPMENT_TEAM).* + allow-vpn - - com.apple.developer.team-identifier - $(DEVELOPMENT_TEAM) - - com.apple.developer.system-extension.install - - com.apple.security.app-sandbox - com.apple.security.application-groups - $(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS) + group.org.amnezia.AmneziaVPN - com.apple.security.network.client - com.apple.security.network.server - com.apple.security.app-sandbox - - com.apple.private.network.socket-delegate - diff --git a/client/macos/networkextension/CMakeLists.txt b/client/macos/networkextension/CMakeLists.txt new file mode 100644 index 00000000..efe1b835 --- /dev/null +++ b/client/macos/networkextension/CMakeLists.txt @@ -0,0 +1,138 @@ +enable_language(Swift) +message("Client message >> macos build >> AmneziaVPNNetworkExtension") +set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) + +add_executable(AmneziaVPNNetworkExtension) + +message("executable_path is: @executable_path/../../Frameworks") +set_target_properties(AmneziaVPNNetworkExtension PROPERTIES + XCODE_PRODUCT_TYPE com.apple.product-type.app-extension + # MACOSX_BUNDLE YES + BUNDLE_EXTENSION appex + MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}" + MACOSX_BUNDLE_INFO_STRING "AmneziaVPNNetworkExtension" + MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPNNetworkExtension" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}.network-extension" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_NAME "${BUILD_IOS_APP_IDENTIFIER}.network-extension" + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/AmneziaVPNNetworkExtension.entitlements + XCODE_ATTRIBUTE_MARKETING_VERSION "${APP_MAJOR_VERSION}" + XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${BUILD_ID}" + XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPNNetworkExtension" + + XCODE_ATTRIBUTE_APPLICATION_EXTENSION_API_ONLY "YES" + XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" + XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "11.0" + + XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../../../../Frameworks @loader_path/../../../../Frameworks" +) + +if(DEPLOY) + message("DEPLOY is ON") + set_target_properties(AmneziaVPNNetworkExtension PROPERTIES + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development" + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr macos.org.amnezia.amneziaVPN.NE" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev macos.org.amnezia.amneziaVPN.NE" + ) +else() + set_target_properties(AmneziaVPNNetworkExtension PROPERTIES + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic + ) +endif() + +set_target_properties(AmneziaVPNNetworkExtension PROPERTIES + XCODE_ATTRIBUTE_SWIFT_VERSION "5.0" + XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES" + XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/WireGuardNetworkExtension-Bridging-Header.h" + XCODE_ATTRIBUTE_SWIFT_OPTIMIZATION_LEVEL "-Onone" + XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO" +) + +set_target_properties("AmneziaVPNNetworkExtension" PROPERTIES + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK" +) + +find_library(FW_ASSETS_LIBRARY AssetsLibrary) +find_library(FW_MOBILE_CORE MobileCoreServices) +find_library(FW_UI_KIT UIKit) +find_library(FW_LIBRESOLV libresolv.9.tbd) + + +# Set the root directory +set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) + +target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${FW_LIBRESOLV}) + +target_compile_options(AmneziaVPNNetworkExtension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\") +target_compile_options(AmneziaVPNNetworkExtension PRIVATE -DNETWORK_EXTENSION=1) + +set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/amneziawg-apple/Sources) + +message("WG_APPLE_SOURCE_DIR is: ${WG_APPLE_SOURCE_DIR}") +message("CLIENT_ROOT_DIR is: ${CLIENT_ROOT_DIR}") + +target_sources(AmneziaVPNNetworkExtension PRIVATE + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/WireGuardAdapter.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/PacketTunnelSettingsGenerator.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/DNSResolver.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardNetworkExtension/ErrorNotifier.swift + ${WG_APPLE_SOURCE_DIR}/Shared/Keychain.swift + ${WG_APPLE_SOURCE_DIR}/Shared/Model/TunnelConfiguration+WgQuickConfig.swift + ${WG_APPLE_SOURCE_DIR}/Shared/Model/NETunnelProviderProtocol+Extension.swift + ${WG_APPLE_SOURCE_DIR}/Shared/Model/String+ArrayConversion.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/TunnelConfiguration.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/IPAddressRange.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/Endpoint.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/DNSServer.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/InterfaceConfiguration.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/PeerConfiguration.swift + ${WG_APPLE_SOURCE_DIR}/Shared/FileManager+Extension.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKitC/x25519.c + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/Array+ConcurrentMap.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/IPAddress+AddrInfo.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/PrivateKey.swift + ${CLIENT_ROOT_DIR}/platforms/ios/HevSocksTunnel.swift + ${CLIENT_ROOT_DIR}/platforms/ios/NELogController.swift + ${CLIENT_ROOT_DIR}/platforms/ios/Log.swift + ${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift + ${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift + ${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+WireGuard.swift + ${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+OpenVPN.swift + ${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+Xray.swift + ${CLIENT_ROOT_DIR}/platforms/ios/WGConfig.swift + ${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm + ${CLIENT_ROOT_DIR}/platforms/ios/XrayConfig.swift +) + +target_sources(AmneziaVPNNetworkExtension PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy +) + +set_property(TARGET AmneziaVPNNetworkExtension APPEND PROPERTY RESOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy +) + +## Build wireguard-go-version.h +execute_process( + COMMAND go list -m golang.zx2c4.com/wireguard + WORKING_DIRECTORY ${CLIENT_ROOT_DIR}/3rd/wireguard-apple/Sources/WireGuardKitGo + OUTPUT_VARIABLE WG_VERSION_FULL +) +string(REGEX REPLACE ".*v\([0-9.]*\).*" "\\1" WG_VERSION_STRING 1.1.1) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/wireguard-go-version.h.in + ${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h) +target_sources(AmneziaVPNNetworkExtension PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h) + +target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}) +target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + +target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/macos/universal2/libwg-go.a) + +message(${CLIENT_ROOT_DIR}) +message(${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a) +target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a) + +target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/Headers) 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..40af3f7e 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -15,7 +15,7 @@ #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/mozilla/localsocketcontroller.cpp b/client/mozilla/localsocketcontroller.cpp index 9abab81c..afa29c47 100644 --- a/client/mozilla/localsocketcontroller.cpp +++ b/client/mozilla/localsocketcontroller.cpp @@ -38,7 +38,7 @@ LocalSocketController::LocalSocketController() { m_socket = new QLocalSocket(this); connect(m_socket, &QLocalSocket::connected, this, &LocalSocketController::daemonConnected); - connect(m_socket, &QLocalSocket::disconnected, this, + connect(m_socket, &QLocalSocket::disconnected, this, [&] { errorOccurred(QLocalSocket::PeerClosedError); }); connect(m_socket, &QLocalSocket::errorOccurred, this, &LocalSocketController::errorOccurred); @@ -135,7 +135,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) { // set up IPv6 unique-local-address, ULA, with "fd00::/8" prefix, not globally routable. // this will be default IPv6 gateway, OS recognizes that IPv6 link is local and switches to IPv4. - // Otherwise some OSes (Linux) try IPv6 forever and hang. + // Otherwise some OSes (Linux) try IPv6 forever and hang. // https://en.wikipedia.org/wiki/Unique_local_address (RFC 4193) // https://man7.org/linux/man-pages/man5/gai.conf.5.html json.insert("deviceIpv6Address", "fd58:baa6:dead::1"); // simply "dead::1" is globally-routable, don't use it @@ -149,14 +149,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) { json.insert("serverPort", wgConfig.value(amnezia::config_key::port).toInt()); json.insert("serverIpv4Gateway", wgConfig.value(amnezia::config_key::hostName)); // json.insert("serverIpv6Gateway", QJsonValue(hop.m_server.ipv6Gateway())); - - json.insert("primaryDnsServer", rawConfig.value(amnezia::config_key::dns1)); - - // We don't use secondary DNS if primary DNS is AmneziaDNS - if (!rawConfig.value(amnezia::config_key::dns1).toString(). - contains(amnezia::protocols::dns::amneziaDnsIp)) { - json.insert("secondaryDnsServer", rawConfig.value(amnezia::config_key::dns2)); - } + json.insert("dnsServer", rawConfig.value(amnezia::config_key::dns1)); QJsonArray jsAllowedIPAddesses; @@ -244,61 +237,28 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) { json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize)); json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize)); json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize)); - json.insert(amnezia::config_key::cookieReplyPacketJunkSize, wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize)); - json.insert(amnezia::config_key::transportPacketJunkSize, wgConfig.value(amnezia::config_key::transportPacketJunkSize)); json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader)); json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader)); json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader)); json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader)); - json.insert(amnezia::config_key::specialJunk1, wgConfig.value(amnezia::config_key::specialJunk1)); - json.insert(amnezia::config_key::specialJunk2, wgConfig.value(amnezia::config_key::specialJunk2)); - json.insert(amnezia::config_key::specialJunk3, wgConfig.value(amnezia::config_key::specialJunk3)); - json.insert(amnezia::config_key::specialJunk4, wgConfig.value(amnezia::config_key::specialJunk4)); - json.insert(amnezia::config_key::specialJunk5, wgConfig.value(amnezia::config_key::specialJunk5)); - json.insert(amnezia::config_key::controlledJunk1, wgConfig.value(amnezia::config_key::controlledJunk1)); - json.insert(amnezia::config_key::controlledJunk2, wgConfig.value(amnezia::config_key::controlledJunk2)); - json.insert(amnezia::config_key::controlledJunk3, wgConfig.value(amnezia::config_key::controlledJunk3)); - json.insert(amnezia::config_key::specialHandshakeTimeout, wgConfig.value(amnezia::config_key::specialHandshakeTimeout)); } else if (!wgConfig.value(amnezia::config_key::junkPacketCount).isUndefined() && !wgConfig.value(amnezia::config_key::junkPacketMinSize).isUndefined() && !wgConfig.value(amnezia::config_key::junkPacketMaxSize).isUndefined() && !wgConfig.value(amnezia::config_key::initPacketJunkSize).isUndefined() && !wgConfig.value(amnezia::config_key::responsePacketJunkSize).isUndefined() - && !wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize).isUndefined() - && !wgConfig.value(amnezia::config_key::transportPacketJunkSize).isUndefined() && !wgConfig.value(amnezia::config_key::initPacketMagicHeader).isUndefined() && !wgConfig.value(amnezia::config_key::responsePacketMagicHeader).isUndefined() && !wgConfig.value(amnezia::config_key::underloadPacketMagicHeader).isUndefined() - && !wgConfig.value(amnezia::config_key::transportPacketMagicHeader).isUndefined() - && !wgConfig.value(amnezia::config_key::specialJunk1).isUndefined() - && !wgConfig.value(amnezia::config_key::specialJunk2).isUndefined() - && !wgConfig.value(amnezia::config_key::specialJunk3).isUndefined() - && !wgConfig.value(amnezia::config_key::specialJunk4).isUndefined() - && !wgConfig.value(amnezia::config_key::specialJunk5).isUndefined() - && !wgConfig.value(amnezia::config_key::controlledJunk1).isUndefined() - && !wgConfig.value(amnezia::config_key::controlledJunk2).isUndefined() - && !wgConfig.value(amnezia::config_key::controlledJunk3).isUndefined() - && !wgConfig.value(amnezia::config_key::specialHandshakeTimeout).isUndefined()) { + && !wgConfig.value(amnezia::config_key::transportPacketMagicHeader).isUndefined()) { json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount)); json.insert(amnezia::config_key::junkPacketMinSize, wgConfig.value(amnezia::config_key::junkPacketMinSize)); json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize)); json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize)); json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize)); - json.insert(amnezia::config_key::cookieReplyPacketJunkSize, wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize)); - json.insert(amnezia::config_key::transportPacketJunkSize, wgConfig.value(amnezia::config_key::transportPacketJunkSize)); json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader)); json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader)); json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader)); json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader)); - json.insert(amnezia::config_key::specialJunk1, wgConfig.value(amnezia::config_key::specialJunk1)); - json.insert(amnezia::config_key::specialJunk2, wgConfig.value(amnezia::config_key::specialJunk2)); - json.insert(amnezia::config_key::specialJunk3, wgConfig.value(amnezia::config_key::specialJunk3)); - json.insert(amnezia::config_key::specialJunk4, wgConfig.value(amnezia::config_key::specialJunk4)); - json.insert(amnezia::config_key::specialJunk5, wgConfig.value(amnezia::config_key::specialJunk5)); - json.insert(amnezia::config_key::controlledJunk1, wgConfig.value(amnezia::config_key::controlledJunk1)); - json.insert(amnezia::config_key::controlledJunk2, wgConfig.value(amnezia::config_key::controlledJunk2)); - json.insert(amnezia::config_key::controlledJunk3, wgConfig.value(amnezia::config_key::controlledJunk3)); - json.insert(amnezia::config_key::specialHandshakeTimeout, wgConfig.value(amnezia::config_key::specialHandshakeTimeout)); } write(json); 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 200cf0cb..98758f30 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) { @@ -90,3 +100,4 @@ struct ProtectionPair { textField.removeFromSuperview() } } +#endif diff --git a/client/platforms/ios/WGConfig.swift b/client/platforms/ios/WGConfig.swift index 537687f1..e3b67efe 100644 --- a/client/platforms/ios/WGConfig.swift +++ b/client/platforms/ios/WGConfig.swift @@ -4,10 +4,7 @@ struct WGConfig: Decodable { let initPacketMagicHeader, responsePacketMagicHeader: String? let underloadPacketMagicHeader, transportPacketMagicHeader: String? let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String? - let initPacketJunkSize, responsePacketJunkSize, cookieReplyPacketJunkSize, transportPacketJunkSize: String? - let specialJunk1, specialJunk2, specialJunk3, specialJunk4, specialJunk5: String? - let controlledJunk1, controlledJunk2, controlledJunk3: String? - let specialHandshakeTimeout: String? + let initPacketJunkSize, responsePacketJunkSize: String? let dns1: String let dns2: String let mtu: String @@ -26,10 +23,7 @@ struct WGConfig: Decodable { case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2" case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4" case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax" - case initPacketJunkSize = "S1", responsePacketJunkSize = "S2", cookieReplyPacketJunkSize = "S3", transportPacketJunkSize = "S4" - case specialJunk1 = "I1", specialJunk2 = "I2", specialJunk3 = "I3", specialJunk4 = "I4", specialJunk5 = "I5" - case controlledJunk1 = "J1", controlledJunk2 = "J2", controlledJunk3 = "J3" - case specialHandshakeTimeout = "Itime" + case initPacketJunkSize = "S1", responsePacketJunkSize = "S2" case dns1 case dns2 case mtu @@ -46,59 +40,19 @@ struct WGConfig: Decodable { } var settings: String { - guard junkPacketCount != nil else { return "" } - - var settingsLines: [String] = [] - - // Required parameters when junkPacketCount is present - settingsLines.append("Jc = \(junkPacketCount!)") - settingsLines.append("Jmin = \(junkPacketMinSize!)") - settingsLines.append("Jmax = \(junkPacketMaxSize!)") - settingsLines.append("S1 = \(initPacketJunkSize!)") - settingsLines.append("S2 = \(responsePacketJunkSize!)") - - settingsLines.append("H1 = \(initPacketMagicHeader!)") - settingsLines.append("H2 = \(responsePacketMagicHeader!)") - settingsLines.append("H3 = \(underloadPacketMagicHeader!)") - settingsLines.append("H4 = \(transportPacketMagicHeader!)") + junkPacketCount == nil ? "" : + """ + Jc = \(junkPacketCount!) + Jmin = \(junkPacketMinSize!) + Jmax = \(junkPacketMaxSize!) + S1 = \(initPacketJunkSize!) + S2 = \(responsePacketJunkSize!) + H1 = \(initPacketMagicHeader!) + H2 = \(responsePacketMagicHeader!) + H3 = \(underloadPacketMagicHeader!) + H4 = \(transportPacketMagicHeader!) - // Optional parameters - only add if not nil and not empty - if let s3 = cookieReplyPacketJunkSize, !s3.isEmpty { - settingsLines.append("S3 = \(s3)") - } - if let s4 = transportPacketJunkSize, !s4.isEmpty { - settingsLines.append("S4 = \(s4)") - } - - if let i1 = specialJunk1, !i1.isEmpty { - settingsLines.append("I1 = \(i1)") - } - if let i2 = specialJunk2, !i2.isEmpty { - settingsLines.append("I2 = \(i2)") - } - if let i3 = specialJunk3, !i3.isEmpty { - settingsLines.append("I3 = \(i3)") - } - if let i4 = specialJunk4, !i4.isEmpty { - settingsLines.append("I4 = \(i4)") - } - if let i5 = specialJunk5, !i5.isEmpty { - settingsLines.append("I5 = \(i5)") - } - if let j1 = controlledJunk1, !j1.isEmpty { - settingsLines.append("J1 = \(j1)") - } - if let j2 = controlledJunk2, !j2.isEmpty { - settingsLines.append("J2 = \(j2)") - } - if let j3 = controlledJunk3, !j3.isEmpty { - settingsLines.append("J3 = \(j3)") - } - if let itime = specialHandshakeTimeout, !itime.isEmpty { - settingsLines.append("Itime = \(itime)") - } - - return settingsLines.joined(separator: "\n") + """ } var str: String { 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 e64c6dce..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; @@ -507,8 +522,6 @@ bool IosController::setupWireGuard() wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]); wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]); - wgConfig.insert(config_key::cookieReplyPacketJunkSize, config[config_key::cookieReplyPacketJunkSize]); - wgConfig.insert(config_key::transportPacketJunkSize, config[config_key::transportPacketJunkSize]); wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]); wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]); @@ -607,23 +620,11 @@ bool IosController::setupAwg() wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]); wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]); - wgConfig.insert(config_key::cookieReplyPacketJunkSize, config[config_key::cookieReplyPacketJunkSize]); - wgConfig.insert(config_key::transportPacketJunkSize, config[config_key::transportPacketJunkSize]); wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]); wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]); wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]); - wgConfig.insert(config_key::specialJunk1, config[config_key::specialJunk1]); - wgConfig.insert(config_key::specialJunk2, config[config_key::specialJunk2]); - wgConfig.insert(config_key::specialJunk3, config[config_key::specialJunk3]); - wgConfig.insert(config_key::specialJunk4, config[config_key::specialJunk4]); - wgConfig.insert(config_key::specialJunk5, config[config_key::specialJunk5]); - wgConfig.insert(config_key::controlledJunk1, config[config_key::controlledJunk1]); - wgConfig.insert(config_key::controlledJunk2, config[config_key::controlledJunk2]); - wgConfig.insert(config_key::controlledJunk3, config[config_key::controlledJunk3]); - wgConfig.insert(config_key::specialHandshakeTimeout, config[config_key::specialHandshakeTimeout]); - QJsonDocument wgConfigDoc(wgConfig); QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact)); @@ -803,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(); @@ -822,15 +823,16 @@ 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(); - + return isAccepted; } QString IosController::openFile() { +#if !MACOS_NE UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen]; DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init]; @@ -840,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); @@ -851,11 +853,11 @@ QString IosController::openFile() { } emit finished(); }; - +#endif QEventLoop wait; QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit); wait.exec(); - + return filePath; } 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/platforms/linux/daemon/iputilslinux.cpp b/client/platforms/linux/daemon/iputilslinux.cpp index 25d4f631..63bd92f9 100644 --- a/client/platforms/linux/daemon/iputilslinux.cpp +++ b/client/platforms/linux/daemon/iputilslinux.cpp @@ -97,7 +97,7 @@ bool IPUtilsLinux::addIP4AddressToDevice(const InterfaceConfig& config) { // Set ifr to interface int ret = ioctl(sockfd, SIOCSIFADDR, &ifr); if (ret) { - logger.error() << "Failed to set IPv4: " << deviceAddr + logger.error() << "Failed to set IPv4: " << logger.sensitive(deviceAddr) << "error:" << strerror(errno); return false; } @@ -138,7 +138,7 @@ bool IPUtilsLinux::addIP6AddressToDevice(const InterfaceConfig& config) { // Set ifr6 to the interface ret = ioctl(sockfd, SIOCSIFADDR, &ifr6); if (ret && (errno != EEXIST)) { - logger.error() << "Failed to set IPv6: " << deviceAddr + logger.error() << "Failed to set IPv6: " << logger.sensitive(deviceAddr) << "error:" << strerror(errno); return false; } diff --git a/client/platforms/linux/daemon/wireguardutilslinux.cpp b/client/platforms/linux/daemon/wireguardutilslinux.cpp index cfde73e2..0fbb65a8 100644 --- a/client/platforms/linux/daemon/wireguardutilslinux.cpp +++ b/client/platforms/linux/daemon/wireguardutilslinux.cpp @@ -121,12 +121,6 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) { if (!config.m_responsePacketJunkSize.isEmpty()) { out << "s2=" << config.m_responsePacketJunkSize << "\n"; } - if (!config.m_cookieReplyPacketJunkSize.isEmpty()) { - out << "s3=" << config.m_cookieReplyPacketJunkSize << "\n"; - } - if (!config.m_transportPacketJunkSize.isEmpty()) { - out << "s4=" << config.m_transportPacketJunkSize << "\n"; - } if (!config.m_initPacketMagicHeader.isEmpty()) { out << "h1=" << config.m_initPacketMagicHeader << "\n"; } @@ -140,26 +134,13 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) { out << "h4=" << config.m_transportPacketMagicHeader << "\n"; } - for (const QString& key : config.m_specialJunk.keys()) { - out << key.toLower() << "=" << config.m_specialJunk.value(key) << "\n"; - } - for (const QString& key : config.m_controlledJunk.keys()) { - out << key.toLower() << "=" << config.m_controlledJunk.value(key) << "\n"; - } - if (!config.m_specialHandshakeTimeout.isEmpty()) { - out << "itime=" << config.m_specialHandshakeTimeout << "\n"; - } - int err = uapiErrno(uapiCommand(message)); if (err != 0) { logger.error() << "Interface configuration failed:" << strerror(err); } else { if (config.m_killSwitchEnabled) { FirewallParams params { }; - params.dnsServers.append(config.m_primaryDnsServer); - if (!config.m_secondaryDnsServer.isEmpty()) { - params.dnsServers.append(config.m_secondaryDnsServer); - } + params.dnsServers.append(config.m_dnsServer); if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) { params.blockAll = true; if (config.m_excludedAddresses.size()) { diff --git a/client/platforms/macos/daemon/iputilsmacos.cpp b/client/platforms/macos/daemon/iputilsmacos.cpp index 901436ae..0599e2eb 100644 --- a/client/platforms/macos/daemon/iputilsmacos.cpp +++ b/client/platforms/macos/daemon/iputilsmacos.cpp @@ -122,7 +122,7 @@ bool IPUtilsMacos::addIP4AddressToDevice(const InterfaceConfig& config) { // Set ifr to interface int ret = ioctl(sockfd, SIOCAIFADDR, &ifr); if (ret) { - logger.error() << "Failed to set IPv4: " << deviceAddr + logger.error() << "Failed to set IPv4: " << logger.sensitive(deviceAddr) << "error:" << strerror(errno); return false; } @@ -162,7 +162,7 @@ bool IPUtilsMacos::addIP6AddressToDevice(const InterfaceConfig& config) { // Set ifr to interface int ret = ioctl(sockfd, SIOCAIFADDR_IN6, &ifr6); if (ret) { - logger.error() << "Failed to set IPv6: " << deviceAddr + logger.error() << "Failed to set IPv6: " << logger.sensitive(deviceAddr) << "error:" << strerror(errno); return false; } diff --git a/client/platforms/macos/daemon/macosfirewall.cpp b/client/platforms/macos/daemon/macosfirewall.cpp index 5211c440..0fe51f23 100644 --- a/client/platforms/macos/daemon/macosfirewall.cpp +++ b/client/platforms/macos/daemon/macosfirewall.cpp @@ -43,16 +43,8 @@ namespace { #include "macosfirewall.h" -#include -#include - -// Read-only rules bundled with the application. -#define ResourceDir (qApp->applicationDirPath() + "/pf") - -// Writable location that does NOT live inside the signed bundle. Using a -// constant path under /Library/Application Support keeps the signature intact -// and is accessible to the root helper. -#define DaemonDataDir QStringLiteral("/Library/Application Support/AmneziaVPN/pf") +#define ResourceDir qApp->applicationDirPath() + "/pf" +#define DaemonDataDir qApp->applicationDirPath() + "/pf" #include @@ -129,8 +121,6 @@ void MacOSFirewall::install() logger.info() << "Installing PF root anchor"; installRootAnchors(); - // Ensure writable directory exists, then store the token there. - QDir().mkpath(DaemonDataDir); execute(QStringLiteral("pfctl -E 2>&1 | grep -F 'Token : ' | cut -c9- > '%1/pf.token'").arg(DaemonDataDir)); } diff --git a/client/platforms/macos/daemon/macosroutemonitor.cpp b/client/platforms/macos/daemon/macosroutemonitor.cpp index 062f97f3..bd991c01 100644 --- a/client/platforms/macos/daemon/macosroutemonitor.cpp +++ b/client/platforms/macos/daemon/macosroutemonitor.cpp @@ -144,7 +144,7 @@ void MacosRouteMonitor::handleRtmDelete(const struct rt_msghdr* rtm, for (const IPAddress& prefix : m_exclusionRoutes) { if (prefix.address().protocol() == protocol) { logger.debug() << "Removing exclusion route to" - << prefix.toString(); + << logger.sensitive(prefix.toString()); rtmSendRoute(RTM_DELETE, prefix, rtm->rtm_index, nullptr); } } @@ -259,7 +259,7 @@ void MacosRouteMonitor::handleRtmUpdate(const struct rt_msghdr* rtm, for (const IPAddress& prefix : m_exclusionRoutes) { if (prefix.address().protocol() == protocol) { logger.debug() << "Updating exclusion route to" - << prefix.toString(); + << logger.sensitive(prefix.toString()); rtmSendRoute(rtm_type, prefix, ifindex, addrlist[1].constData()); } } @@ -510,7 +510,8 @@ bool MacosRouteMonitor::deleteRoute(const IPAddress& prefix, int flags) { } bool MacosRouteMonitor::addExclusionRoute(const IPAddress& prefix) { - logger.debug() << "Adding exclusion route for" << prefix.toString(); + logger.debug() << "Adding exclusion route for" + << logger.sensitive(prefix.toString()); if (m_exclusionRoutes.contains(prefix)) { logger.warning() << "Exclusion route already exists"; @@ -535,7 +536,8 @@ bool MacosRouteMonitor::addExclusionRoute(const IPAddress& prefix) { } bool MacosRouteMonitor::deleteExclusionRoute(const IPAddress& prefix) { - logger.debug() << "Deleting exclusion route for" << prefix.toString(); + logger.debug() << "Deleting exclusion route for" + << logger.sensitive(prefix.toString()); m_exclusionRoutes.removeAll(prefix); if (prefix.address().protocol() == QAbstractSocket::IPv4Protocol) { diff --git a/client/platforms/macos/daemon/wireguardutilsmacos.cpp b/client/platforms/macos/daemon/wireguardutilsmacos.cpp index cce4afab..1d8aa6e0 100644 --- a/client/platforms/macos/daemon/wireguardutilsmacos.cpp +++ b/client/platforms/macos/daemon/wireguardutilsmacos.cpp @@ -119,12 +119,6 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) { if (!config.m_responsePacketJunkSize.isEmpty()) { out << "s2=" << config.m_responsePacketJunkSize << "\n"; } - if (!config.m_cookieReplyPacketJunkSize.isEmpty()) { - out << "s3=" << config.m_cookieReplyPacketJunkSize << "\n"; - } - if (!config.m_transportPacketJunkSize.isEmpty()) { - out << "s4=" << config.m_transportPacketJunkSize << "\n"; - } if (!config.m_initPacketMagicHeader.isEmpty()) { out << "h1=" << config.m_initPacketMagicHeader << "\n"; } @@ -138,43 +132,30 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) { out << "h4=" << config.m_transportPacketMagicHeader << "\n"; } - for (const QString& key : config.m_specialJunk.keys()) { - out << key.toLower() << "=" << config.m_specialJunk.value(key) << "\n"; - } - for (const QString& key : config.m_controlledJunk.keys()) { - out << key.toLower() << "=" << config.m_controlledJunk.value(key) << "\n"; - } - if (!config.m_specialHandshakeTimeout.isEmpty()) { - out << "itime=" << config.m_specialHandshakeTimeout << "\n"; - } - int err = uapiErrno(uapiCommand(message)); if (err != 0) { logger.error() << "Interface configuration failed:" << strerror(err); } else { - if (config.m_killSwitchEnabled) { - FirewallParams params { }; - params.dnsServers.append(config.m_primaryDnsServer); - if (!config.m_secondaryDnsServer.isEmpty()) { - params.dnsServers.append(config.m_secondaryDnsServer); - } + if (config.m_killSwitchEnabled) { + FirewallParams params { }; + params.dnsServers.append(config.m_dnsServer); - if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) { + if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) { params.blockAll = true; if (config.m_excludedAddresses.size()) { - params.allowNets = true; - foreach (auto net, config.m_excludedAddresses) { - params.allowAddrs.append(net.toUtf8()); - } + params.allowNets = true; + foreach (auto net, config.m_excludedAddresses) { + params.allowAddrs.append(net.toUtf8()); + } } - } else { + } else { params.blockNets = true; foreach (auto net, config.m_allowedIPAddressRanges) { - params.blockAddrs.append(net.toString()); + params.blockAddrs.append(net.toString()); } + } + applyFirewallRules(params); } - applyFirewallRules(params); - } } return (err == 0); } diff --git a/client/platforms/windows/daemon/windowsfirewall.cpp b/client/platforms/windows/daemon/windowsfirewall.cpp index 2556c417..1834452e 100644 --- a/client/platforms/windows/daemon/windowsfirewall.cpp +++ b/client/platforms/windows/daemon/windowsfirewall.cpp @@ -291,32 +291,15 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) { "Block Internet", config.m_serverPublicKey)) { return false; } - if (!config.m_primaryDnsServer.isEmpty()) { - if (!allowTrafficTo(QHostAddress(config.m_primaryDnsServer), 53, HIGH_WEIGHT, + if (!config.m_dnsServer.isEmpty()) { + if (!allowTrafficTo(QHostAddress(config.m_dnsServer), 53, HIGH_WEIGHT, "Allow DNS-Server", config.m_serverPublicKey)) { return false; } // In some cases, we might configure a 2nd DNS server for IPv6, however // this should probably be cleaned up by converting m_dnsServer into // a QStringList instead. - if (config.m_primaryDnsServer == config.m_serverIpv4Gateway) { - if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53, - HIGH_WEIGHT, "Allow extra IPv6 DNS-Server", - config.m_serverPublicKey)) { - return false; - } - } - } - - if (!config.m_secondaryDnsServer.isEmpty()) { - if (!allowTrafficTo(QHostAddress(config.m_secondaryDnsServer), 53, HIGH_WEIGHT, - "Allow DNS-Server", config.m_serverPublicKey)) { - return false; - } - // In some cases, we might configure a 2nd DNS server for IPv6, however - // this should probably be cleaned up by converting m_dnsServer into - // a QStringList instead. - if (config.m_secondaryDnsServer == config.m_serverIpv4Gateway) { + if (config.m_dnsServer == config.m_serverIpv4Gateway) { if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53, HIGH_WEIGHT, "Allow extra IPv6 DNS-Server", config.m_serverPublicKey)) { diff --git a/client/platforms/windows/daemon/windowsroutemonitor.cpp b/client/platforms/windows/daemon/windowsroutemonitor.cpp index 1d0ce4c2..fb0fbf7e 100644 --- a/client/platforms/windows/daemon/windowsroutemonitor.cpp +++ b/client/platforms/windows/daemon/windowsroutemonitor.cpp @@ -303,7 +303,8 @@ void WindowsRouteMonitor::updateCapturedRoutes(int family, void* ptable) { data->Age++; continue; } - logger.debug() << "Capturing route to" << prefix.toString(); + logger.debug() << "Capturing route to" + << logger.sensitive(prefix.toString()); // Clone the route and direct it into the VPN tunnel. data = new MIB_IPFORWARD_ROW2; @@ -353,7 +354,8 @@ void WindowsRouteMonitor::updateCapturedRoutes(int family, void* ptable) { continue; } - logger.debug() << "Removing route capture for" << i.key().toString(); + logger.debug() << "Removing route capture for" + << logger.sensitive(i.key().toString()); // Otherwise, this route is no longer in use. DWORD result = DeleteIpForwardEntry2(data); @@ -366,7 +368,8 @@ void WindowsRouteMonitor::updateCapturedRoutes(int family, void* ptable) { } bool WindowsRouteMonitor::addExclusionRoute(const IPAddress& prefix) { - logger.debug() << "Adding exclusion route for" << prefix.toString(); + logger.debug() << "Adding exclusion route for" + << logger.sensitive(prefix.toString()); // Silently ignore non-routeable addresses. QHostAddress addr = prefix.address(); @@ -434,7 +437,7 @@ bool WindowsRouteMonitor::addExclusionRoute(const IPAddress& prefix) { bool WindowsRouteMonitor::deleteExclusionRoute(const IPAddress& prefix) { logger.debug() << "Deleting exclusion route for" - << prefix.address().toString(); + << logger.sensitive(prefix.address().toString()); MIB_IPFORWARD_ROW2* data = m_exclusionRoutes.take(prefix); if (data == nullptr) { @@ -444,7 +447,7 @@ bool WindowsRouteMonitor::deleteExclusionRoute(const IPAddress& prefix) { DWORD result = DeleteIpForwardEntry2(data); if ((result != ERROR_NOT_FOUND) && (result != NO_ERROR)) { logger.error() << "Failed to delete route to" - << prefix.toString() + << logger.sensitive(prefix.toString()) << "result:" << result; } @@ -462,7 +465,7 @@ void WindowsRouteMonitor::flushRouteTable( DWORD result = DeleteIpForwardEntry2(data); if ((result != ERROR_NOT_FOUND) && (result != NO_ERROR)) { logger.error() << "Failed to delete route to" - << i.key().toString() + << logger.sensitive(i.key().toString()) << "result:" << result; } delete data; diff --git a/client/platforms/windows/daemon/wireguardutilswindows.cpp b/client/platforms/windows/daemon/wireguardutilswindows.cpp index a5c9c84d..d01ef54a 100644 --- a/client/platforms/windows/daemon/wireguardutilswindows.cpp +++ b/client/platforms/windows/daemon/wireguardutilswindows.cpp @@ -130,7 +130,6 @@ bool WireguardUtilsWindows::addInterface(const InterfaceConfig& config) { // Enable the windows firewall NET_IFINDEX ifindex; ConvertInterfaceLuidToIndex(&luid, &ifindex); - m_firewall->allowAllTraffic(); m_firewall->enableInterface(ifindex); } diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index 0bbdbd07..429b85a6 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -343,7 +343,7 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line) // killSwitch toggle if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { - IpcClient::Interface()->enableKillSwitch(m_configData, netInterfaces.at(i).index()); + IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index()); } m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index()); m_configData.insert("vpnGateway", m_vpnGateway); diff --git a/client/protocols/protocols_defs.h b/client/protocols/protocols_defs.h index b4cbb6de..e59c8ac3 100644 --- a/client/protocols/protocols_defs.h +++ b/client/protocols/protocols_defs.h @@ -72,21 +72,10 @@ namespace amnezia constexpr char junkPacketMaxSize[] = "Jmax"; constexpr char initPacketJunkSize[] = "S1"; constexpr char responsePacketJunkSize[] = "S2"; - constexpr char cookieReplyPacketJunkSize[] = "S3"; - constexpr char transportPacketJunkSize[] = "S4"; constexpr char initPacketMagicHeader[] = "H1"; constexpr char responsePacketMagicHeader[] = "H2"; constexpr char underloadPacketMagicHeader[] = "H3"; constexpr char transportPacketMagicHeader[] = "H4"; - constexpr char specialJunk1[] = "I1"; - constexpr char specialJunk2[] = "I2"; - constexpr char specialJunk3[] = "I3"; - constexpr char specialJunk4[] = "I4"; - constexpr char specialJunk5[] = "I5"; - constexpr char controlledJunk1[] = "J1"; - constexpr char controlledJunk2[] = "J2"; - constexpr char controlledJunk3[] = "J3"; - constexpr char specialHandshakeTimeout[] = "Itime"; constexpr char openvpn[] = "openvpn"; constexpr char wireguard[] = "wireguard"; @@ -114,8 +103,6 @@ namespace amnezia constexpr char clientId[] = "clientId"; - constexpr char nameOverriddenByUser[] = "nameOverriddenByUser"; - } namespace protocols @@ -192,7 +179,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"; @@ -212,7 +199,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"; @@ -227,22 +214,10 @@ namespace amnezia constexpr char defaultJunkPacketMaxSize[] = "30"; constexpr char defaultInitPacketJunkSize[] = "15"; constexpr char defaultResponsePacketJunkSize[] = "18"; - constexpr char defaultCookieReplyPacketJunkSize[] = "20"; - constexpr char defaultTransportPacketJunkSize[] = "23"; - constexpr char defaultInitPacketMagicHeader[] = "1020325451"; constexpr char defaultResponsePacketMagicHeader[] = "3288052141"; constexpr char defaultTransportPacketMagicHeader[] = "2528465083"; constexpr char defaultUnderloadPacketMagicHeader[] = "1766607858"; - constexpr char defaultSpecialJunk1[] = ""; - constexpr char defaultSpecialJunk2[] = ""; - constexpr char defaultSpecialJunk3[] = ""; - constexpr char defaultSpecialJunk4[] = ""; - constexpr char defaultSpecialJunk5[] = ""; - constexpr char defaultControlledJunk1[] = ""; - constexpr char defaultControlledJunk2[] = ""; - constexpr char defaultControlledJunk3[] = ""; - constexpr char defaultSpecialHandshakeTimeout[] = ""; } namespace socks5Proxy 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/protocols/xrayprotocol.cpp b/client/protocols/xrayprotocol.cpp index 84922634..faad8e94 100755 --- a/client/protocols/xrayprotocol.cpp +++ b/client/protocols/xrayprotocol.cpp @@ -98,13 +98,8 @@ ErrorCode XrayProtocol::startTun2Sock() if (vpnState == Vpn::ConnectionState::Connected) { setConnectionState(Vpn::ConnectionState::Connecting); QList dnsAddr; - dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString())); - // We don't use secondary DNS if primary DNS is AmneziaDNS - if (!m_configData.value(amnezia::config_key::dns1).toString(). - contains(amnezia::protocols::dns::amneziaDnsIp)) { - dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString())); - } + dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString())); #ifdef Q_OS_WIN QThread::msleep(8000); #endif @@ -139,7 +134,7 @@ ErrorCode XrayProtocol::startTun2Sock() // killSwitch toggle if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { - IpcClient::Interface()->enableKillSwitch(m_configData, netInterfaces.at(i).index()); + IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index()); } m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index()); m_configData.insert("vpnGateway", m_vpnGateway); diff --git a/client/resources.qrc b/client/resources.qrc index 54b5846c..72eb15c7 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -239,7 +239,6 @@ ui/qml/Components/ApiPremV1MigrationDrawer.qml ui/qml/Components/ApiPremV1SubListDrawer.qml ui/qml/Components/OtpCodeDrawer.qml - ui/qml/Components/AwgTextField.qml images/flagKit/ZW.svg diff --git a/client/server_scripts/awg/Dockerfile b/client/server_scripts/awg/Dockerfile index a6118a84..8c536fc7 100644 --- a/client/server_scripts/awg/Dockerfile +++ b/client/server_scripts/awg/Dockerfile @@ -10,7 +10,7 @@ RUN mkdir -p /opt/amnezia RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh RUN chmod a+x /opt/amnezia/start.sh -# Tune network +# Tune network RUN echo -e " \n\ fs.file-max = 51200 \n\ \n\ @@ -40,8 +40,7 @@ RUN echo -e " \n\ echo -e " \n\ * soft nofile 51200 \n\ * hard nofile 51200 \n\ - " | sed -e 's/^\s\+//g' | tee -a /etc/security/limits.conf + " | sed -e 's/^\s\+//g' | tee -a /etc/security/limits.conf ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ] CMD [ "" ] - diff --git a/client/server_scripts/awg/configure_container.sh b/client/server_scripts/awg/configure_container.sh index e327f080..2000c965 100644 --- a/client/server_scripts/awg/configure_container.sh +++ b/client/server_scripts/awg/configure_container.sh @@ -23,5 +23,4 @@ H1 = $INIT_PACKET_MAGIC_HEADER H2 = $RESPONSE_PACKET_MAGIC_HEADER H3 = $UNDERLOAD_PACKET_MAGIC_HEADER H4 = $TRANSPORT_PACKET_MAGIC_HEADER - EOF diff --git a/client/server_scripts/check_server_is_busy.sh b/client/server_scripts/check_server_is_busy.sh index feddfed3..4e6a2c26 100644 --- a/client/server_scripts/check_server_is_busy.sh +++ b/client/server_scripts/check_server_is_busy.sh @@ -1,7 +1,6 @@ -if which apt-get > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/lib/dpkg/lock-frontend";\ -elif which dnf > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/cache/dnf/* /var/run/dnf/* /var/lib/dnf/* /var/lib/rpm/*";\ -elif which yum > /dev/null 2>&1; then LOCK_CMD="cat"; LOCK_FILE="/var/run/yum.pid";\ -elif which zypper > /dev/null 2>&1; then LOCK_CMD="cat"; LOCK_FILE="/var/run/zypp.pid";\ -elif which pacman > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/lib/pacman/db.lck";\ +if which apt-get > /dev/null 2>&1; then LOCK_FILE="/var/lib/dpkg/lock-frontend";\ +elif which dnf > /dev/null 2>&1; then LOCK_FILE="/var/run/dnf.pid";\ +elif which yum > /dev/null 2>&1; then LOCK_FILE="/var/run/yum.pid";\ +elif which pacman > /dev/null 2>&1; then LOCK_FILE="/var/lib/pacman/db.lck";\ else echo "Packet manager not found"; echo "Internal error"; exit 1; fi;\ -if command -v $LOCK_CMD > /dev/null 2>&1; then sudo $LOCK_CMD $LOCK_FILE 2>/dev/null; else echo "$LOCK_CMD not installed"; fi +if command -v fuser > /dev/null 2>&1; then sudo fuser $LOCK_FILE 2>/dev/null; else echo "fuser not installed"; fi diff --git a/client/server_scripts/check_user_in_sudo.sh b/client/server_scripts/check_user_in_sudo.sh index f83f2fd7..685e6a18 100644 --- a/client/server_scripts/check_user_in_sudo.sh +++ b/client/server_scripts/check_user_in_sudo.sh @@ -1,7 +1,6 @@ if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); opt="--version";\ elif which dnf > /dev/null 2>&1; then pm=$(which dnf); opt="--version";\ elif which yum > /dev/null 2>&1; then pm=$(which yum); opt="--version";\ -elif which zypper > /dev/null 2>&1; then pm=$(which zypper); opt="--version";\ elif which pacman > /dev/null 2>&1; then pm=$(which pacman); opt="--version";\ else pm="uname"; opt="-a";\ fi;\ diff --git a/client/server_scripts/install_docker.sh b/client/server_scripts/install_docker.sh index 1e41bb5a..619b08d6 100644 --- a/client/server_scripts/install_docker.sh +++ b/client/server_scripts/install_docker.sh @@ -1,7 +1,6 @@ if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\ elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\ elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\ -elif which zypper > /dev/null 2>&1; then pm=$(which zypper); silent_inst="-nq install"; check_pkgs="-nq refresh"; docker_pkg="docker"; dist="opensuse";\ elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="-Sup"; docker_pkg="docker"; dist="archlinux";\ else echo "Packet manager not found"; exit 1; fi;\ echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg";\ diff --git a/client/settings.h b/client/settings.h index 7c244cd4..eec6cc44 100644 --- a/client/settings.h +++ b/client/settings.h @@ -174,12 +174,11 @@ public: QLocale getAppLanguage() { - QString localeStr = m_settings.value("Conf/appLanguage").toString(); - return QLocale(localeStr); + return value("Conf/appLanguage", QLocale()).toLocale(); }; void setAppLanguage(QLocale locale) { - setValue("Conf/appLanguage", locale.name()); + setValue("Conf/appLanguage", locale); }; bool isScreenshotsEnabled() const diff --git a/client/translations/amneziavpn_ru_RU.ts b/client/translations/amneziavpn_ru_RU.ts index 1d8766ac..833db3d9 100644 --- a/client/translations/amneziavpn_ru_RU.ts +++ b/client/translations/amneziavpn_ru_RU.ts @@ -89,17 +89,17 @@ ApiConfigsController - + %1 installed successfully. %1 успешно установлен. - + API config reloaded Конфигурация API перезагружена - + Successfully changed the country of connection to %1 Страна подключения изменена на %1 @@ -134,7 +134,7 @@ <li>Personal dashboard to manage your subscription</li> - <li>Личный кабинет для управления подпиской</li> + Личный кабинет для управления подпиской @@ -358,7 +358,7 @@ ContextMenuType - + C&ut Вырезать @@ -368,12 +368,12 @@ Копировать - + &Paste Вставить - + &SelectAll Выбрать всё @@ -2013,12 +2013,12 @@ Thank you for staying with us! Наши специалисты технической поддержки всегда готовы помочь вам. - + Support tag - + Copied Скопировано @@ -2412,42 +2412,42 @@ Thank you for staying with us! Доступ в интернет блокируется при разрыве VPN-соединения - + Strict KillSwitch Strict KillSwitch - + Internet connection is blocked even when VPN is turned off manually or hasn't started Доступ в интернет блокируется, даже если VPN отключен вручную или не был запущен - + Just a little heads-up Небольшое предупреждение - + If the VPN disconnects or drops while Strict KillSwitch is enabled, internet access will be blocked. To restore access, reconnect VPN or disable/change the KillSwitch. Если VPN отключится или соединение прервётся при включённом Strict KillSwitch, доступ в интернет будет заблокирован. Чтобы восстановить доступ, снова подключитесь к VPN или отключите (измените) режим KillSwitch. - + Continue Продолжить - + Cancel Отменить - + DNS Exceptions Исключения для DNS - + DNS servers listed here will remain accessible when KillSwitch is active. DNS-серверы из этого списка останутся доступными при активном KillSwitch. @@ -4085,12 +4085,7 @@ Thank you for staying with us! Произошла ошибка миграции. Обратитесь в нашу техническую поддержку - - Please update the application to use this feature - Пожалуйста, обновите приложение, чтобы использовать эту функцию - - - + ErrorCode: %1. Код ошибки: %1. @@ -4201,37 +4196,37 @@ Thank you for staying with us! Произошла ошибка миграции. Обратитесь в нашу техническую поддержку - + QFile error: The file could not be opened Ошибка QFile: не удалось открыть файл - + QFile error: An error occurred when reading from the file Ошибка QFile: произошла ошибка при чтении из файла - + QFile error: The file could not be accessed Ошибка QFile: не удалось получить доступ к файлу - + QFile error: An unspecified error occurred Ошибка QFile: произошла неизвестная ошибка - + QFile error: A fatal error occurred Ошибка QFile: произошла фатальная ошибка - + QFile error: The operation was aborted Ошибка QFile: операция была прервана - + Internal error Внутренняя ошибка diff --git a/client/ui/Controls2 b/client/ui/Controls2 new file mode 100644 index 00000000..13f01bb7 --- /dev/null +++ b/client/ui/Controls2 @@ -0,0 +1,34 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +TextArea { + id: root + + width: parent.width + + topPadding: 16 + leftPadding: 16 + + color: "#D7D8DB" + selectionColor: "#412102" + selectedTextColor: "#D7D8DB" + placeholderTextColor: "#878B91" + + font.pixelSize: 16 + font.weight: Font.Medium + font.family: "PT Root UI VF" + + wrapMode: Text.Wrap + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: contextMenu.open() + } + + ContextMenuType { + id: contextMenu + textObj: textField + } +} diff --git a/client/ui/controllers/api/apiConfigsController.cpp b/client/ui/controllers/api/apiConfigsController.cpp index 0f42beb7..21d371bb 100644 --- a/client/ui/controllers/api/apiConfigsController.cpp +++ b/client/ui/controllers/api/apiConfigsController.cpp @@ -18,7 +18,6 @@ namespace { constexpr char cloak[] = "cloak"; constexpr char awg[] = "awg"; - constexpr char vless[] = "vless"; constexpr char apiEndpoint[] = "api_endpoint"; constexpr char accessToken[] = "api_key"; @@ -36,6 +35,10 @@ namespace constexpr char serviceInfo[] = "service_info"; constexpr char serviceProtocol[] = "service_protocol"; + constexpr char aesKey[] = "aes_key"; + constexpr char aesIv[] = "aes_iv"; + constexpr char aesSalt[] = "aes_salt"; + constexpr char apiPayload[] = "api_payload"; constexpr char keyPayload[] = "key_payload"; @@ -44,185 +47,6 @@ namespace constexpr char config[] = "config"; } - - struct ProtocolData - { - OpenVpnConfigurator::ConnectionData certRequest; - - QString wireGuardClientPrivKey; - QString wireGuardClientPubKey; - - QString xrayUuid; - }; - - struct GatewayRequestData - { - QString osVersion; - QString appVersion; - - QString installationUuid; - - QString userCountryCode; - QString serverCountryCode; - QString serviceType; - QString serviceProtocol; - - QJsonObject authData; - - QJsonObject toJsonObject() const - { - QJsonObject obj; - if (!osVersion.isEmpty()) { - obj[configKey::osVersion] = osVersion; - } - if (!appVersion.isEmpty()) { - obj[configKey::appVersion] = appVersion; - } - if (!installationUuid.isEmpty()) { - obj[configKey::uuid] = installationUuid; - } - if (!userCountryCode.isEmpty()) { - obj[configKey::userCountryCode] = userCountryCode; - } - if (!serverCountryCode.isEmpty()) { - obj[configKey::serverCountryCode] = serverCountryCode; - } - if (!serviceType.isEmpty()) { - obj[configKey::serviceType] = serviceType; - } - if (!serviceProtocol.isEmpty()) { - obj[configKey::serviceProtocol] = serviceProtocol; - } - if (!authData.isEmpty()) { - obj[configKey::authData] = authData; - } - return obj; - } - }; - - ProtocolData generateProtocolData(const QString &protocol) - { - ProtocolData protocolData; - if (protocol == configKey::cloak) { - protocolData.certRequest = OpenVpnConfigurator::createCertRequest(); - } else if (protocol == configKey::awg) { - auto connData = WireguardConfigurator::genClientKeys(); - protocolData.wireGuardClientPubKey = connData.clientPubKey; - protocolData.wireGuardClientPrivKey = connData.clientPrivKey; - } else if (protocol == configKey::vless) { - protocolData.xrayUuid = QUuid::createUuid().toString(QUuid::WithoutBraces); - } - - return protocolData; - } - - void appendProtocolDataToApiPayload(const QString &protocol, const ProtocolData &protocolData, QJsonObject &apiPayload) - { - if (protocol == configKey::cloak) { - apiPayload[configKey::certificate] = protocolData.certRequest.request; - } else if (protocol == configKey::awg) { - apiPayload[configKey::publicKey] = protocolData.wireGuardClientPubKey; - } else if (protocol == configKey::vless) { - apiPayload[configKey::publicKey] = protocolData.xrayUuid; - } - } - - ErrorCode fillServerConfig(const QString &protocol, const ProtocolData &apiPayloadData, const QByteArray &apiResponseBody, - QJsonObject &serverConfig) - { - QString data = QJsonDocument::fromJson(apiResponseBody).object().value(config_key::config).toString(); - - data.replace("vpn://", ""); - QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); - - if (ba.isEmpty()) { - qDebug() << "empty vpn key"; - return ErrorCode::ApiConfigEmptyError; - } - - QByteArray ba_uncompressed = qUncompress(ba); - if (!ba_uncompressed.isEmpty()) { - ba = ba_uncompressed; - } - - QString configStr = ba; - if (protocol == configKey::cloak) { - configStr.replace("", "\n"); - configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey); - } else if (protocol == configKey::awg) { - configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey); - auto newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object(); - auto containers = newServerConfig.value(config_key::containers).toArray(); - if (containers.isEmpty()) { - qDebug() << "missing containers field"; - return ErrorCode::ApiConfigEmptyError; - } - auto container = containers.at(0).toObject(); - QString containerName = ContainerProps::containerTypeToString(DockerContainer::Awg); - auto serverProtocolConfig = container.value(containerName).toObject(); - auto clientProtocolConfig = - QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object(); - - //TODO looks like this block can be removed after v1 configs EOL - - serverProtocolConfig[config_key::junkPacketCount] = clientProtocolConfig.value(config_key::junkPacketCount); - serverProtocolConfig[config_key::junkPacketMinSize] = clientProtocolConfig.value(config_key::junkPacketMinSize); - serverProtocolConfig[config_key::junkPacketMaxSize] = clientProtocolConfig.value(config_key::junkPacketMaxSize); - serverProtocolConfig[config_key::initPacketJunkSize] = clientProtocolConfig.value(config_key::initPacketJunkSize); - serverProtocolConfig[config_key::responsePacketJunkSize] = clientProtocolConfig.value(config_key::responsePacketJunkSize); - serverProtocolConfig[config_key::initPacketMagicHeader] = clientProtocolConfig.value(config_key::initPacketMagicHeader); - serverProtocolConfig[config_key::responsePacketMagicHeader] = clientProtocolConfig.value(config_key::responsePacketMagicHeader); - serverProtocolConfig[config_key::underloadPacketMagicHeader] = clientProtocolConfig.value(config_key::underloadPacketMagicHeader); - serverProtocolConfig[config_key::transportPacketMagicHeader] = clientProtocolConfig.value(config_key::transportPacketMagicHeader); - - serverProtocolConfig[config_key::cookieReplyPacketJunkSize] = clientProtocolConfig.value(config_key::cookieReplyPacketJunkSize); - serverProtocolConfig[config_key::transportPacketJunkSize] = clientProtocolConfig.value(config_key::transportPacketJunkSize); - serverProtocolConfig[config_key::specialJunk1] = clientProtocolConfig.value(config_key::specialJunk1); - serverProtocolConfig[config_key::specialJunk2] = clientProtocolConfig.value(config_key::specialJunk2); - serverProtocolConfig[config_key::specialJunk3] = clientProtocolConfig.value(config_key::specialJunk3); - serverProtocolConfig[config_key::specialJunk4] = clientProtocolConfig.value(config_key::specialJunk4); - serverProtocolConfig[config_key::specialJunk5] = clientProtocolConfig.value(config_key::specialJunk5); - serverProtocolConfig[config_key::controlledJunk1] = clientProtocolConfig.value(config_key::controlledJunk1); - serverProtocolConfig[config_key::controlledJunk2] = clientProtocolConfig.value(config_key::controlledJunk2); - serverProtocolConfig[config_key::controlledJunk3] = clientProtocolConfig.value(config_key::controlledJunk3); - serverProtocolConfig[config_key::specialHandshakeTimeout] = clientProtocolConfig.value(config_key::specialHandshakeTimeout); - - // - - container[containerName] = serverProtocolConfig; - containers.replace(0, container); - newServerConfig[config_key::containers] = containers; - configStr = QString(QJsonDocument(newServerConfig).toJson()); - } - - QJsonObject newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object(); - serverConfig[config_key::dns1] = newServerConfig.value(config_key::dns1); - serverConfig[config_key::dns2] = newServerConfig.value(config_key::dns2); - serverConfig[config_key::containers] = newServerConfig.value(config_key::containers); - serverConfig[config_key::hostName] = newServerConfig.value(config_key::hostName); - - if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) { - serverConfig[config_key::configVersion] = newServerConfig.value(config_key::configVersion); - serverConfig[config_key::description] = newServerConfig.value(config_key::description); - serverConfig[config_key::name] = newServerConfig.value(config_key::name); - } - - auto defaultContainer = newServerConfig.value(config_key::defaultContainer).toString(); - serverConfig[config_key::defaultContainer] = defaultContainer; - - QVariantMap map = serverConfig.value(configKey::apiConfig).toObject().toVariantMap(); - map.insert(newServerConfig.value(configKey::apiConfig).toObject().toVariantMap()); - auto apiConfig = QJsonObject::fromVariantMap(map); - - if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) { - apiConfig.insert(apiDefs::key::supportedProtocols, - QJsonDocument::fromJson(apiResponseBody).object().value(apiDefs::key::supportedProtocols).toArray()); - } - - serverConfig[configKey::apiConfig] = apiConfig; - - return ErrorCode::NoError; - } } ApiConfigsController::ApiConfigsController(const QSharedPointer &serversModel, @@ -239,26 +63,23 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode, return false; } + GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs, + m_settings->isStrictKillSwitchEnabled()); + auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex()); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); - GatewayRequestData gatewayRequestData { QSysInfo::productType(), - QString(APP_VERSION), - m_settings->getInstallationUuid(true), - apiConfigObject.value(configKey::userCountryCode).toString(), - serverCountryCode, - apiConfigObject.value(configKey::serviceType).toString(), - m_apiServicesModel->getSelectedServiceProtocol(), - serverConfigObject.value(configKey::authData).toObject() }; - QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString(); - ProtocolData protocolData = generateProtocolData(protocol); + ApiPayloadData apiPayloadData = generateApiPayloadData(protocol); - QJsonObject apiPayload = gatewayRequestData.toJsonObject(); - appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload); + QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData); + apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode); + apiPayload[configKey::serverCountryCode] = serverCountryCode; + apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType); + apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData); QByteArray responseBody; - ErrorCode errorCode = executeRequest(QString("%1v1/native_config"), apiPayload, responseBody); + ErrorCode errorCode = gatewayController.post(QString("%1v1/native_config"), apiPayload, responseBody); if (errorCode != ErrorCode::NoError) { emit errorOccurred(errorCode); return false; @@ -266,7 +87,7 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode, QJsonObject jsonConfig = QJsonDocument::fromJson(responseBody).object(); QString nativeConfig = jsonConfig.value(configKey::config).toString(); - nativeConfig.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", protocolData.wireGuardClientPrivKey); + nativeConfig.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey); SystemController::saveFile(fileName, nativeConfig); return true; @@ -274,22 +95,23 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode, bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode) { + GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs, + m_settings->isStrictKillSwitchEnabled()); + auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex()); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); - GatewayRequestData gatewayRequestData { QSysInfo::productType(), - QString(APP_VERSION), - m_settings->getInstallationUuid(true), - apiConfigObject.value(configKey::userCountryCode).toString(), - serverCountryCode, - apiConfigObject.value(configKey::serviceType).toString(), - m_apiServicesModel->getSelectedServiceProtocol(), - serverConfigObject.value(configKey::authData).toObject() }; + QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString(); + ApiPayloadData apiPayloadData = generateApiPayloadData(protocol); - QJsonObject apiPayload = gatewayRequestData.toJsonObject(); + QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData); + apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode); + apiPayload[configKey::serverCountryCode] = serverCountryCode; + apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType); + apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData); QByteArray responseBody; - ErrorCode errorCode = executeRequest(QString("%1v1/revoke_native_config"), apiPayload, responseBody); + ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_native_config"), apiPayload, responseBody); if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) { emit errorOccurred(errorCode); return false; @@ -320,11 +142,14 @@ void ApiConfigsController::copyVpnKeyToClipboard() bool ApiConfigsController::fillAvailableServices() { + GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs, + m_settings->isStrictKillSwitchEnabled()); + QJsonObject apiPayload; apiPayload[configKey::osVersion] = QSysInfo::productType(); QByteArray responseBody; - ErrorCode errorCode = executeRequest(QString("%1v1/services"), apiPayload, responseBody); + ErrorCode errorCode = gatewayController.post(QString("%1v1/services"), apiPayload, responseBody); if (errorCode == ErrorCode::NoError) { if (!responseBody.contains("services")) { errorCode = ErrorCode::ApiServicesMissingError; @@ -343,36 +168,33 @@ bool ApiConfigsController::fillAvailableServices() bool ApiConfigsController::importServiceFromGateway() { - GatewayRequestData gatewayRequestData { QSysInfo::productType(), - QString(APP_VERSION), - m_settings->getInstallationUuid(true), - m_apiServicesModel->getCountryCode(), - "", - m_apiServicesModel->getSelectedServiceType(), - m_apiServicesModel->getSelectedServiceProtocol(), - QJsonObject() }; - - if (m_serversModel->isServerFromApiAlreadyExists(gatewayRequestData.userCountryCode, gatewayRequestData.serviceType, - gatewayRequestData.serviceProtocol)) { + if (m_serversModel->isServerFromApiAlreadyExists(m_apiServicesModel->getCountryCode(), m_apiServicesModel->getSelectedServiceType(), + m_apiServicesModel->getSelectedServiceProtocol())) { emit errorOccurred(ErrorCode::ApiConfigAlreadyAdded); return false; } - ProtocolData protocolData = generateProtocolData(gatewayRequestData.serviceProtocol); + GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs, + m_settings->isStrictKillSwitchEnabled()); - QJsonObject apiPayload = gatewayRequestData.toJsonObject(); - appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload); + auto installationUuid = m_settings->getInstallationUuid(true); + auto userCountryCode = m_apiServicesModel->getCountryCode(); + auto serviceType = m_apiServicesModel->getSelectedServiceType(); + auto serviceProtocol = m_apiServicesModel->getSelectedServiceProtocol(); + + ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol); + + QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData); + apiPayload[configKey::userCountryCode] = userCountryCode; + apiPayload[configKey::serviceType] = serviceType; + apiPayload[configKey::uuid] = installationUuid; QByteArray responseBody; - ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody); + ErrorCode errorCode = gatewayController.post(QString("%1v1/config"), apiPayload, responseBody); QJsonObject serverConfig; if (errorCode == ErrorCode::NoError) { - errorCode = fillServerConfig(gatewayRequestData.serviceProtocol, protocolData, responseBody, serverConfig); - if (errorCode != ErrorCode::NoError) { - emit errorOccurred(errorCode); - return false; - } + fillServerConfig(serviceProtocol, apiPayloadData, responseBody, serverConfig); QJsonObject apiConfig = serverConfig.value(configKey::apiConfig).toObject(); apiConfig.insert(configKey::userCountryCode, m_apiServicesModel->getCountryCode()); @@ -393,33 +215,38 @@ bool ApiConfigsController::importServiceFromGateway() bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName, bool reloadServiceConfig) { + GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs, + m_settings->isStrictKillSwitchEnabled()); + auto serverConfig = m_serversModel->getServerConfig(serverIndex); auto apiConfig = serverConfig.value(configKey::apiConfig).toObject(); + auto authData = serverConfig.value(configKey::authData).toObject(); - GatewayRequestData gatewayRequestData { QSysInfo::productType(), - QString(APP_VERSION), - m_settings->getInstallationUuid(true), - apiConfig.value(configKey::userCountryCode).toString(), - newCountryCode, - apiConfig.value(configKey::serviceType).toString(), - apiConfig.value(configKey::serviceProtocol).toString(), - serverConfig.value(configKey::authData).toObject() }; + auto installationUuid = m_settings->getInstallationUuid(true); + auto userCountryCode = apiConfig.value(configKey::userCountryCode).toString(); + auto serviceType = apiConfig.value(configKey::serviceType).toString(); + auto serviceProtocol = apiConfig.value(configKey::serviceProtocol).toString(); - ProtocolData protocolData = generateProtocolData(gatewayRequestData.serviceProtocol); + ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol); - QJsonObject apiPayload = gatewayRequestData.toJsonObject(); - appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload); + QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData); + apiPayload[configKey::userCountryCode] = userCountryCode; + apiPayload[configKey::serviceType] = serviceType; + apiPayload[configKey::uuid] = installationUuid; + + if (!newCountryCode.isEmpty()) { + apiPayload[configKey::serverCountryCode] = newCountryCode; + } + if (!authData.isEmpty()) { + apiPayload[configKey::authData] = authData; + } QByteArray responseBody; - ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody); + ErrorCode errorCode = gatewayController.post(QString("%1v1/config"), apiPayload, responseBody); QJsonObject newServerConfig; if (errorCode == ErrorCode::NoError) { - errorCode = fillServerConfig(gatewayRequestData.serviceProtocol, protocolData, responseBody, newServerConfig); - if (errorCode != ErrorCode::NoError) { - emit errorOccurred(errorCode); - return false; - } + fillServerConfig(serviceProtocol, apiPayloadData, responseBody, newServerConfig); QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject(); newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode)); @@ -428,12 +255,8 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const newApiConfig.insert(apiDefs::key::vpnKey, apiConfig.value(apiDefs::key::vpnKey)); newServerConfig.insert(configKey::apiConfig, newApiConfig); - newServerConfig.insert(configKey::authData, gatewayRequestData.authData); + newServerConfig.insert(configKey::authData, authData); - if (serverConfig.value(config_key::nameOverriddenByUser).toBool()) { - newServerConfig.insert(config_key::name, serverConfig.value(config_key::name)); - newServerConfig.insert(config_key::nameOverriddenByUser, true); - } m_serversModel->editServer(newServerConfig, serverIndex); if (reloadServiceConfig) { emit reloadServerFromApiFinished(tr("API config reloaded")); @@ -463,13 +286,10 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex) auto installationUuid = m_settings->getInstallationUuid(true); QString serviceProtocol = serverConfig.value(configKey::protocol).toString(); - ProtocolData protocolData = generateProtocolData(serviceProtocol); + ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol); - QJsonObject apiPayload; - appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload); + QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData); apiPayload[configKey::uuid] = installationUuid; - apiPayload[configKey::osVersion] = QSysInfo::productType(); - apiPayload[configKey::appVersion] = QString(APP_VERSION); apiPayload[configKey::accessToken] = serverConfig.value(configKey::accessToken).toString(); apiPayload[configKey::apiEndpoint] = serverConfig.value(configKey::apiEndpoint).toString(); @@ -477,11 +297,7 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex) ErrorCode errorCode = gatewayController.post(QString("%1v1/proxy_config"), apiPayload, responseBody); if (errorCode == ErrorCode::NoError) { - errorCode = fillServerConfig(serviceProtocol, protocolData, responseBody, serverConfig); - if (errorCode != ErrorCode::NoError) { - emit errorOccurred(errorCode); - return false; - } + fillServerConfig(serviceProtocol, apiPayloadData, responseBody, serverConfig); m_serversModel->editServer(serverConfig, serverIndex); emit updateServerFromApiFinished(); @@ -494,6 +310,9 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex) bool ApiConfigsController::deactivateDevice() { + GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs, + m_settings->isStrictKillSwitchEnabled()); + auto serverIndex = m_serversModel->getProcessedServerIndex(); auto serverConfigObject = m_serversModel->getServerConfig(serverIndex); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); @@ -502,19 +321,18 @@ bool ApiConfigsController::deactivateDevice() return true; } - GatewayRequestData gatewayRequestData { QSysInfo::productType(), - QString(APP_VERSION), - m_settings->getInstallationUuid(true), - apiConfigObject.value(configKey::userCountryCode).toString(), - apiConfigObject.value(configKey::serverCountryCode).toString(), - apiConfigObject.value(configKey::serviceType).toString(), - "", - serverConfigObject.value(configKey::authData).toObject() }; + QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString(); + ApiPayloadData apiPayloadData = generateApiPayloadData(protocol); - QJsonObject apiPayload = gatewayRequestData.toJsonObject(); + QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData); + apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode); + apiPayload[configKey::serverCountryCode] = apiConfigObject.value(configKey::serverCountryCode); + apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType); + apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData); + apiPayload[configKey::uuid] = m_settings->getInstallationUuid(true); QByteArray responseBody; - ErrorCode errorCode = executeRequest(QString("%1v1/revoke_config"), apiPayload, responseBody); + ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_config"), apiPayload, responseBody); if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) { emit errorOccurred(errorCode); return false; @@ -528,6 +346,9 @@ bool ApiConfigsController::deactivateDevice() bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const QString &serverCountryCode) { + GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs, + m_settings->isStrictKillSwitchEnabled()); + auto serverIndex = m_serversModel->getProcessedServerIndex(); auto serverConfigObject = m_serversModel->getServerConfig(serverIndex); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); @@ -536,19 +357,18 @@ bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const Q return true; } - GatewayRequestData gatewayRequestData { QSysInfo::productType(), - QString(APP_VERSION), - uuid, - apiConfigObject.value(configKey::userCountryCode).toString(), - serverCountryCode, - apiConfigObject.value(configKey::serviceType).toString(), - "", - serverConfigObject.value(configKey::authData).toObject() }; + QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString(); + ApiPayloadData apiPayloadData = generateApiPayloadData(protocol); - QJsonObject apiPayload = gatewayRequestData.toJsonObject(); + QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData); + apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode); + apiPayload[configKey::serverCountryCode] = serverCountryCode; + apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType); + apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData); + apiPayload[configKey::uuid] = uuid; QByteArray responseBody; - ErrorCode errorCode = executeRequest(QString("%1v1/revoke_config"), apiPayload, responseBody); + ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_config"), apiPayload, responseBody); if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) { emit errorOccurred(errorCode); return false; @@ -587,29 +407,108 @@ bool ApiConfigsController::isConfigValid() return true; } -void ApiConfigsController::setCurrentProtocol(const QString &protocolName) +ApiConfigsController::ApiPayloadData ApiConfigsController::generateApiPayloadData(const QString &protocol) { - auto serverIndex = m_serversModel->getProcessedServerIndex(); - auto serverConfigObject = m_serversModel->getServerConfig(serverIndex); - auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); - - apiConfigObject[configKey::serviceProtocol] = protocolName; - - serverConfigObject.insert(configKey::apiConfig, apiConfigObject); - - m_serversModel->editServer(serverConfigObject, serverIndex); + ApiConfigsController::ApiPayloadData apiPayload; + if (protocol == configKey::cloak) { + apiPayload.certRequest = OpenVpnConfigurator::createCertRequest(); + } else if (protocol == configKey::awg) { + auto connData = WireguardConfigurator::genClientKeys(); + apiPayload.wireGuardClientPubKey = connData.clientPubKey; + apiPayload.wireGuardClientPrivKey = connData.clientPrivKey; + } + return apiPayload; } -bool ApiConfigsController::isVlessProtocol() +QJsonObject ApiConfigsController::fillApiPayload(const QString &protocol, const ApiPayloadData &apiPayloadData) { - auto serverIndex = m_serversModel->getProcessedServerIndex(); - auto serverConfigObject = m_serversModel->getServerConfig(serverIndex); - auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); - - if (apiConfigObject[configKey::serviceProtocol].toString() == "vless") { - return true; + QJsonObject obj; + if (protocol == configKey::cloak) { + obj[configKey::certificate] = apiPayloadData.certRequest.request; + } else if (protocol == configKey::awg) { + obj[configKey::publicKey] = apiPayloadData.wireGuardClientPubKey; } - return false; + + obj[configKey::osVersion] = QSysInfo::productType(); + obj[configKey::appVersion] = QString(APP_VERSION); + + return obj; +} + +void ApiConfigsController::fillServerConfig(const QString &protocol, const ApiPayloadData &apiPayloadData, + const QByteArray &apiResponseBody, QJsonObject &serverConfig) +{ + QString data = QJsonDocument::fromJson(apiResponseBody).object().value(config_key::config).toString(); + + data.replace("vpn://", ""); + QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + + if (ba.isEmpty()) { + emit errorOccurred(ErrorCode::ApiConfigEmptyError); + return; + } + + QByteArray ba_uncompressed = qUncompress(ba); + if (!ba_uncompressed.isEmpty()) { + ba = ba_uncompressed; + } + + QString configStr = ba; + if (protocol == configKey::cloak) { + configStr.replace("", "\n"); + configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey); + } else if (protocol == configKey::awg) { + configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey); + auto newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object(); + auto containers = newServerConfig.value(config_key::containers).toArray(); + if (containers.isEmpty()) { + return; // todo process error + } + auto container = containers.at(0).toObject(); + QString containerName = ContainerProps::containerTypeToString(DockerContainer::Awg); + auto containerConfig = container.value(containerName).toObject(); + auto protocolConfig = QJsonDocument::fromJson(containerConfig.value(config_key::last_config).toString().toUtf8()).object(); + containerConfig[config_key::junkPacketCount] = protocolConfig.value(config_key::junkPacketCount); + containerConfig[config_key::junkPacketMinSize] = protocolConfig.value(config_key::junkPacketMinSize); + containerConfig[config_key::junkPacketMaxSize] = protocolConfig.value(config_key::junkPacketMaxSize); + containerConfig[config_key::initPacketJunkSize] = protocolConfig.value(config_key::initPacketJunkSize); + containerConfig[config_key::responsePacketJunkSize] = protocolConfig.value(config_key::responsePacketJunkSize); + containerConfig[config_key::initPacketMagicHeader] = protocolConfig.value(config_key::initPacketMagicHeader); + containerConfig[config_key::responsePacketMagicHeader] = protocolConfig.value(config_key::responsePacketMagicHeader); + containerConfig[config_key::underloadPacketMagicHeader] = protocolConfig.value(config_key::underloadPacketMagicHeader); + containerConfig[config_key::transportPacketMagicHeader] = protocolConfig.value(config_key::transportPacketMagicHeader); + container[containerName] = containerConfig; + containers.replace(0, container); + newServerConfig[config_key::containers] = containers; + configStr = QString(QJsonDocument(newServerConfig).toJson()); + } + + QJsonObject newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object(); + serverConfig[config_key::dns1] = newServerConfig.value(config_key::dns1); + serverConfig[config_key::dns2] = newServerConfig.value(config_key::dns2); + serverConfig[config_key::containers] = newServerConfig.value(config_key::containers); + serverConfig[config_key::hostName] = newServerConfig.value(config_key::hostName); + + if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) { + serverConfig[config_key::configVersion] = newServerConfig.value(config_key::configVersion); + serverConfig[config_key::description] = newServerConfig.value(config_key::description); + serverConfig[config_key::name] = newServerConfig.value(config_key::name); + } + + auto defaultContainer = newServerConfig.value(config_key::defaultContainer).toString(); + serverConfig[config_key::defaultContainer] = defaultContainer; + + QVariantMap map = serverConfig.value(configKey::apiConfig).toObject().toVariantMap(); + map.insert(newServerConfig.value(configKey::apiConfig).toObject().toVariantMap()); + auto apiConfig = QJsonObject::fromVariantMap(map); + + if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) { + apiConfig.insert(configKey::serviceInfo, QJsonDocument::fromJson(apiResponseBody).object().value(configKey::serviceInfo).toObject()); + } + + serverConfig[configKey::apiConfig] = apiConfig; + + return; } QList ApiConfigsController::getQrCodes() @@ -626,10 +525,3 @@ QString ApiConfigsController::getVpnKey() { return m_vpnKey; } - -ErrorCode ApiConfigsController::executeRequest(const QString &endpoint, const QJsonObject &apiPayload, QByteArray &responseBody) -{ - GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs, - m_settings->isStrictKillSwitchEnabled()); - return gatewayController.post(endpoint, apiPayload, responseBody); -} diff --git a/client/ui/controllers/api/apiConfigsController.h b/client/ui/controllers/api/apiConfigsController.h index a04a142c..2fe981e4 100644 --- a/client/ui/controllers/api/apiConfigsController.h +++ b/client/ui/controllers/api/apiConfigsController.h @@ -35,9 +35,6 @@ public slots: bool isConfigValid(); - void setCurrentProtocol(const QString &protocolName); - bool isVlessProtocol(); - signals: void errorOccurred(ErrorCode errorCode); @@ -49,12 +46,23 @@ signals: void vpnKeyExportReady(); private: + struct ApiPayloadData + { + OpenVpnConfigurator::ConnectionData certRequest; + + QString wireGuardClientPrivKey; + QString wireGuardClientPubKey; + }; + + ApiPayloadData generateApiPayloadData(const QString &protocol); + QJsonObject fillApiPayload(const QString &protocol, const ApiPayloadData &apiPayloadData); + void fillServerConfig(const QString &protocol, const ApiPayloadData &apiPayloadData, const QByteArray &apiResponseBody, + QJsonObject &serverConfig); + QList getQrCodes(); int getQrCodesCount(); QString getVpnKey(); - ErrorCode executeRequest(const QString &endpoint, const QJsonObject &apiPayload, QByteArray &responseBody); - QList m_qrCodes; QString m_vpnKey; diff --git a/client/ui/controllers/api/apiSettingsController.cpp b/client/ui/controllers/api/apiSettingsController.cpp index c4a75a5b..f20f92bf 100644 --- a/client/ui/controllers/api/apiSettingsController.cpp +++ b/client/ui/controllers/api/apiSettingsController.cpp @@ -5,7 +5,6 @@ #include "core/api/apiUtils.h" #include "core/controllers/gatewayController.h" -#include "version.h" namespace { @@ -61,7 +60,6 @@ bool ApiSettingsController::getAccountInfo(bool reload) apiPayload[configKey::userCountryCode] = apiConfig.value(configKey::userCountryCode).toString(); apiPayload[configKey::serviceType] = apiConfig.value(configKey::serviceType).toString(); apiPayload[configKey::authData] = authData; - apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION); QByteArray responseBody; diff --git a/client/ui/controllers/connectionController.cpp b/client/ui/controllers/connectionController.cpp index 9fc60493..c85367da 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 @@ -32,8 +32,9 @@ ConnectionController::ConnectionController(const QSharedPointer &s void ConnectionController::openConnection() { -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true)) { +#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); return; } diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp index ea1d5d8e..69488eb8 100644 --- a/client/ui/controllers/importController.cpp +++ b/client/ui/controllers/importController.cpp @@ -12,14 +12,13 @@ #include "core/errorstrings.h" #include "core/qrCodeUtils.h" #include "core/serialization/serialization.h" -#include "protocols/protocols_defs.h" #include "systemController.h" #include "utilities.h" #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 @@ -287,19 +286,6 @@ void ImportController::processNativeWireGuardConfig() clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3"; clientProtocolConfig[config_key::transportPacketMagicHeader] = "4"; - // clientProtocolConfig[config_key::cookieReplyPacketJunkSize] = "0"; - // clientProtocolConfig[config_key::transportPacketJunkSize] = "0"; - - // clientProtocolConfig[config_key::specialJunk1] = ""; - // clientProtocolConfig[config_key::specialJunk2] = ""; - // clientProtocolConfig[config_key::specialJunk3] = ""; - // clientProtocolConfig[config_key::specialJunk4] = ""; - // clientProtocolConfig[config_key::specialJunk5] = ""; - // clientProtocolConfig[config_key::controlledJunk1] = ""; - // clientProtocolConfig[config_key::controlledJunk2] = ""; - // clientProtocolConfig[config_key::controlledJunk3] = ""; - // clientProtocolConfig[config_key::specialHandshakeTimeout] = "0"; - clientProtocolConfig[config_key::isObfuscationEnabled] = true; serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson()); @@ -452,33 +438,21 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data) lastConfig[config_key::allowed_ips] = allowedIpsJsonArray; QString protocolName = "wireguard"; - - const QStringList requiredJunkFields = { config_key::junkPacketCount, config_key::junkPacketMinSize, - config_key::junkPacketMaxSize, config_key::initPacketJunkSize, - config_key::responsePacketJunkSize, config_key::initPacketMagicHeader, - config_key::responsePacketMagicHeader, config_key::underloadPacketMagicHeader, - config_key::transportPacketMagicHeader }; - - const QStringList optionalJunkFields = { // config_key::cookieReplyPacketJunkSize, - // config_key::transportPacketJunkSize, - config_key::specialJunk1, config_key::specialJunk2, config_key::specialJunk3, - config_key::specialJunk4, config_key::specialJunk5, config_key::controlledJunk1, - config_key::controlledJunk2, config_key::controlledJunk3, config_key::specialHandshakeTimeout - }; - - bool hasAllRequiredFields = std::all_of(requiredJunkFields.begin(), requiredJunkFields.end(), - [&configMap](const QString &field) { return !configMap.value(field).isEmpty(); }); - if (hasAllRequiredFields) { - for (const QString &field : requiredJunkFields) { - lastConfig[field] = configMap.value(field); - } - - for (const QString &field : optionalJunkFields) { - if (!configMap.value(field).isEmpty()) { - lastConfig[field] = configMap.value(field); - } - } - + if (!configMap.value(config_key::junkPacketCount).isEmpty() && !configMap.value(config_key::junkPacketMinSize).isEmpty() + && !configMap.value(config_key::junkPacketMaxSize).isEmpty() && !configMap.value(config_key::initPacketJunkSize).isEmpty() + && !configMap.value(config_key::responsePacketJunkSize).isEmpty() && !configMap.value(config_key::initPacketMagicHeader).isEmpty() + && !configMap.value(config_key::responsePacketMagicHeader).isEmpty() + && !configMap.value(config_key::underloadPacketMagicHeader).isEmpty() + && !configMap.value(config_key::transportPacketMagicHeader).isEmpty()) { + lastConfig[config_key::junkPacketCount] = configMap.value(config_key::junkPacketCount); + lastConfig[config_key::junkPacketMinSize] = configMap.value(config_key::junkPacketMinSize); + lastConfig[config_key::junkPacketMaxSize] = configMap.value(config_key::junkPacketMaxSize); + lastConfig[config_key::initPacketJunkSize] = configMap.value(config_key::initPacketJunkSize); + lastConfig[config_key::responsePacketJunkSize] = configMap.value(config_key::responsePacketJunkSize); + lastConfig[config_key::initPacketMagicHeader] = configMap.value(config_key::initPacketMagicHeader); + lastConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader); + lastConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader); + lastConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader); protocolName = "awg"; m_configType = ConfigTypes::Awg; } @@ -595,7 +569,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/installController.cpp b/client/ui/controllers/installController.cpp index d7f9dfbc..eab8979a 100755 --- a/client/ui/controllers/installController.cpp +++ b/client/ui/controllers/installController.cpp @@ -8,7 +8,6 @@ #include #include -#include "core/api/apiUtils.h" #include "core/controllers/serverController.h" #include "core/controllers/vpnConfigurationController.h" #include "core/networkUtilities.h" @@ -16,6 +15,7 @@ #include "ui/models/protocols/awgConfigModel.h" #include "ui/models/protocols/wireguardConfigModel.h" #include "utilities.h" +#include "core/api/apiUtils.h" namespace { @@ -79,36 +79,12 @@ void InstallController::install(DockerContainer container, int port, TransportPr int s1 = QRandomGenerator::global()->bounded(15, 150); int s2 = QRandomGenerator::global()->bounded(15, 150); - // int s3 = QRandomGenerator::global()->bounded(15, 150); - // int s4 = QRandomGenerator::global()->bounded(15, 150); - - // Ensure all values are unique and don't create equal packet sizes - QSet usedValues; - usedValues.insert(s1); - - while (usedValues.contains(s2) || s1 + AwgConstant::messageInitiationSize == s2 + AwgConstant::messageResponseSize) { + while (s1 + AwgConstant::messageInitiationSize == s2 + AwgConstant::messageResponseSize) { s2 = QRandomGenerator::global()->bounded(15, 150); } - usedValues.insert(s2); - - // while (usedValues.contains(s3) - // || s1 + AwgConstant::messageInitiationSize == s3 + AwgConstant::messageCookieReplySize - // || s2 + AwgConstant::messageResponseSize == s3 + AwgConstant::messageCookieReplySize) { - // s3 = QRandomGenerator::global()->bounded(15, 150); - // } - // usedValues.insert(s3); - - // while (usedValues.contains(s4) - // || s1 + AwgConstant::messageInitiationSize == s4 + AwgConstant::messageTransportSize - // || s2 + AwgConstant::messageResponseSize == s4 + AwgConstant::messageTransportSize - // || s3 + AwgConstant::messageCookieReplySize == s4 + AwgConstant::messageTransportSize) { - // s4 = QRandomGenerator::global()->bounded(15, 150); - // } QString initPacketJunkSize = QString::number(s1); QString responsePacketJunkSize = QString::number(s2); - // QString cookieReplyPacketJunkSize = QString::number(s3); - // QString transportPacketJunkSize = QString::number(s4); QSet headersValue; while (headersValue.size() != 4) { @@ -132,21 +108,6 @@ void InstallController::install(DockerContainer container, int port, TransportPr containerConfig[config_key::responsePacketMagicHeader] = responsePacketMagicHeader; containerConfig[config_key::underloadPacketMagicHeader] = underloadPacketMagicHeader; containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader; - - // TODO: - // containerConfig[config_key::cookieReplyPacketJunkSize] = cookieReplyPacketJunkSize; - // containerConfig[config_key::transportPacketJunkSize] = transportPacketJunkSize; - - // containerConfig[config_key::specialJunk1] = specialJunk1; - // containerConfig[config_key::specialJunk2] = specialJunk2; - // containerConfig[config_key::specialJunk3] = specialJunk3; - // containerConfig[config_key::specialJunk4] = specialJunk4; - // containerConfig[config_key::specialJunk5] = specialJunk5; - // containerConfig[config_key::controlledJunk1] = controlledJunk1; - // containerConfig[config_key::controlledJunk2] = controlledJunk2; - // containerConfig[config_key::controlledJunk3] = controlledJunk3; - // containerConfig[config_key::specialHandshakeTimeout] = specialHandshakeTimeout; - } else if (container == DockerContainer::Sftp) { containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName); containerConfig.insert(config_key::password, Utils::getRandomString(16)); @@ -440,19 +401,6 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia containerConfig[config_key::transportPacketMagicHeader] = serverConfigMap.value(config_key::transportPacketMagicHeader); - // containerConfig[config_key::cookieReplyPacketJunkSize] = serverConfigMap.value(config_key::cookieReplyPacketJunkSize); - // containerConfig[config_key::transportPacketJunkSize] = serverConfigMap.value(config_key::transportPacketJunkSize); - - // containerConfig[config_key::specialJunk1] = serverConfigMap.value(config_key::specialJunk1); - // containerConfig[config_key::specialJunk2] = serverConfigMap.value(config_key::specialJunk2); - // containerConfig[config_key::specialJunk3] = serverConfigMap.value(config_key::specialJunk3); - // containerConfig[config_key::specialJunk4] = serverConfigMap.value(config_key::specialJunk4); - // containerConfig[config_key::specialJunk5] = serverConfigMap.value(config_key::specialJunk5); - // containerConfig[config_key::controlledJunk1] = serverConfigMap.value(config_key::controlledJunk1); - // containerConfig[config_key::controlledJunk2] = serverConfigMap.value(config_key::controlledJunk2); - // containerConfig[config_key::controlledJunk3] = serverConfigMap.value(config_key::controlledJunk3); - // containerConfig[config_key::specialHandshakeTimeout] = serverConfigMap.value(config_key::specialHandshakeTimeout); - } else if (protocol == Proto::WireGuard) { QString serverConfig = serverController->getTextFileFromContainer(container, credentials, protocols::wireguard::serverConfigPath, errorCode); diff --git a/client/ui/controllers/pageController.cpp b/client/ui/controllers/pageController.cpp index d515df49..b8e32a0e 100644 --- a/client/ui/controllers/pageController.cpp +++ b/client/ui/controllers/pageController.cpp @@ -1,8 +1,11 @@ #include "pageController.h" #include "utils/converter.h" #include "core/errorstrings.h" +#if defined(MACOS_NE) +#include "platforms/ios/ios_controller.h" +#endif -#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 +14,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 +27,7 @@ PageController::PageController(const QSharedPointer &serversModel, AndroidController::instance()->setNavigationBarColor(initialPageNavigationBarColor); #endif -#if defined Q_OS_MACX +#if defined Q_OS_MACX and !defined MACOS_NE connect(this, &PageController::raiseMainWindow, []() { setDockIconVisible(true); }); connect(this, &PageController::hideMainWindow, []() { setDockIconVisible(false); }); #endif @@ -56,14 +59,11 @@ QString PageController::getPagePath(PageLoader::PageEnum page) void PageController::closeWindow() { -#ifdef Q_OS_ANDROID +// On mobile platforms, quit app on close; on desktop, just hide window +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) qApp->quit(); #else - if (m_serversModel->getServersCount() == 0) { - qApp->quit(); - } else { - emit hideMainWindow(); - } + emit hideMainWindow(); #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) && !defined(MACOS_NE) setDockIconVisible(false); #endif } diff --git a/client/ui/controllers/settingsController.cpp b/client/ui/controllers/settingsController.cpp index f8e97a1f..bc1d5c40 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) { @@ -126,19 +126,17 @@ void SettingsController::clearLogs() void SettingsController::backupAppConfig(const QString &fileName) { - QByteArray data = m_settings->backupAppConfig(); - QJsonDocument doc = QJsonDocument::fromJson(data); - QJsonObject config = doc.object(); - - config["Conf/autoStart"] = Autostart::isAutostart(); - - SystemController::saveFile(fileName, QJsonDocument(config).toJson()); + SystemController::saveFile(fileName, m_settings->backupAppConfig()); } 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); } @@ -146,30 +144,9 @@ void SettingsController::restoreAppConfigFromData(const QByteArray &data) { bool ok = m_settings->restoreAppConfig(data); if (ok) { - QJsonObject newConfigData = QJsonDocument::fromJson(data).object(); - -#if defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) || defined(Q_OS_MACX) - bool autoStart = false; - if (newConfigData.contains("Conf/autoStart")) { - autoStart = newConfigData["Conf/autoStart"].toBool(); - } - toggleAutoStart(autoStart); -#endif m_serversModel->resetModel(); m_languageModel->changeLanguage( static_cast(m_languageModel->getCurrentLanguageIndex())); - -#if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID) - int appSplitTunnelingRouteMode = newConfigData.value("Conf/appsRouteMode").toInt(); - bool appSplittunnelingEnabled = newConfigData.value("Conf/appsSplitTunnelingEnabled").toBool(); - m_appSplitTunnelingModel->setRouteMode(appSplitTunnelingRouteMode); - m_appSplitTunnelingModel->toggleSplitTunneling(appSplittunnelingEnabled); -#endif - int siteSplitTunnelingRouteMode = newConfigData.value("Conf/routeMode").toInt(); - bool siteSplittunnelingEnabled = newConfigData.value("Conf/sitesSplitTunnelingEnabled").toBool(); - m_sitesModel->setRouteMode(siteSplitTunnelingRouteMode); - m_sitesModel->toggleSplitTunneling(siteSplittunnelingEnabled); - emit restoreBackupFinished(); } else { emit changeSettingsErrorOccurred(tr("Backup file is corrupted")); @@ -194,11 +171,9 @@ void SettingsController::clearSettings() m_appSplitTunnelingModel->setRouteMode(Settings::AppsRouteMode::VpnAllExceptApps); m_appSplitTunnelingModel->toggleSplitTunneling(false); - toggleAutoStart(false); - 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 } diff --git a/client/ui/controllers/systemController.cpp b/client/ui/controllers/systemController.cpp index 52ca1294..12b86990 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 @@ -58,8 +58,10 @@ void SystemController::saveFile(const QString &fileName, const QString &data) const auto url = fi.absoluteDir().absolutePath(); #endif +#ifndef MACOS_NE QDesktopServices::openUrl(url); #endif +#endif } bool SystemController::readFile(const QString &fileName, QByteArray &data) diff --git a/client/ui/models/api/apiAccountInfoModel.cpp b/client/ui/models/api/apiAccountInfoModel.cpp index bd3027a4..fdd4e2ca 100644 --- a/client/ui/models/api/apiAccountInfoModel.cpp +++ b/client/ui/models/api/apiAccountInfoModel.cpp @@ -75,12 +75,6 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const } return false; } - case IsProtocolSelectionSupportedRole: { - if (m_accountInfoData.supportedProtocols.size() > 1) { - return true; - } - return false; - } } return QVariant(); @@ -101,10 +95,6 @@ void ApiAccountInfoModel::updateModel(const QJsonObject &accountInfoObject, cons accountInfoData.configType = apiUtils::getConfigType(serverConfig); - for (const auto &protocol : accountInfoObject.value(apiDefs::key::supportedProtocols).toArray()) { - accountInfoData.supportedProtocols.push_back(protocol.toString()); - } - m_accountInfoData = accountInfoData; m_supportInfo = accountInfoObject.value(apiDefs::key::supportInfo).toObject(); @@ -169,7 +159,6 @@ QHash ApiAccountInfoModel::roleNames() const roles[ServiceDescriptionRole] = "serviceDescription"; roles[IsComponentVisibleRole] = "isComponentVisible"; roles[HasExpiredWorkerRole] = "hasExpiredWorker"; - roles[IsProtocolSelectionSupportedRole] = "isProtocolSelectionSupported"; return roles; } diff --git a/client/ui/models/api/apiAccountInfoModel.h b/client/ui/models/api/apiAccountInfoModel.h index f0203967..ead92488 100644 --- a/client/ui/models/api/apiAccountInfoModel.h +++ b/client/ui/models/api/apiAccountInfoModel.h @@ -18,8 +18,7 @@ public: ServiceDescriptionRole, EndDateRole, IsComponentVisibleRole, - HasExpiredWorkerRole, - IsProtocolSelectionSupportedRole + HasExpiredWorkerRole }; explicit ApiAccountInfoModel(QObject *parent = nullptr); @@ -52,8 +51,6 @@ private: int maxDeviceCount; apiDefs::ConfigType configType; - - QStringList supportedProtocols; }; AccountInfoData m_accountInfoData; diff --git a/client/ui/models/protocols/awgConfigModel.cpp b/client/ui/models/protocols/awgConfigModel.cpp index e14a3152..860c8395 100644 --- a/client/ui/models/protocols/awgConfigModel.cpp +++ b/client/ui/models/protocols/awgConfigModel.cpp @@ -28,17 +28,7 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in case Roles::ClientJunkPacketCountRole: m_clientProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break; case Roles::ClientJunkPacketMinSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break; case Roles::ClientJunkPacketMaxSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break; - case Roles::ClientSpecialJunk1Role: m_clientProtocolConfig.insert(config_key::specialJunk1, value.toString()); break; - case Roles::ClientSpecialJunk2Role: m_clientProtocolConfig.insert(config_key::specialJunk2, value.toString()); break; - case Roles::ClientSpecialJunk3Role: m_clientProtocolConfig.insert(config_key::specialJunk3, value.toString()); break; - case Roles::ClientSpecialJunk4Role: m_clientProtocolConfig.insert(config_key::specialJunk4, value.toString()); break; - case Roles::ClientSpecialJunk5Role: m_clientProtocolConfig.insert(config_key::specialJunk5, value.toString()); break; - case Roles::ClientControlledJunk1Role: m_clientProtocolConfig.insert(config_key::controlledJunk1, value.toString()); break; - case Roles::ClientControlledJunk2Role: m_clientProtocolConfig.insert(config_key::controlledJunk2, value.toString()); break; - case Roles::ClientControlledJunk3Role: m_clientProtocolConfig.insert(config_key::controlledJunk3, value.toString()); break; - case Roles::ClientSpecialHandshakeTimeoutRole: - m_clientProtocolConfig.insert(config_key::specialHandshakeTimeout, value.toString()); - break; + case Roles::ServerJunkPacketCountRole: m_serverProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break; case Roles::ServerJunkPacketMinSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break; case Roles::ServerJunkPacketMaxSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break; @@ -46,12 +36,6 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in case Roles::ServerResponsePacketJunkSizeRole: m_serverProtocolConfig.insert(config_key::responsePacketJunkSize, value.toString()); break; - // case Roles::ServerCookieReplyPacketJunkSizeRole: - // m_serverProtocolConfig.insert(config_key::cookieReplyPacketJunkSize, value.toString()); - // break; - // case Roles::ServerTransportPacketJunkSizeRole: - // m_serverProtocolConfig.insert(config_key::transportPacketJunkSize, value.toString()); - // break; case Roles::ServerInitPacketMagicHeaderRole: m_serverProtocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); break; case Roles::ServerResponsePacketMagicHeaderRole: m_serverProtocolConfig.insert(config_key::responsePacketMagicHeader, value.toString()); @@ -82,23 +66,12 @@ QVariant AwgConfigModel::data(const QModelIndex &index, int role) const case Roles::ClientJunkPacketCountRole: return m_clientProtocolConfig.value(config_key::junkPacketCount); case Roles::ClientJunkPacketMinSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMinSize); case Roles::ClientJunkPacketMaxSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMaxSize); - case Roles::ClientSpecialJunk1Role: return m_clientProtocolConfig.value(config_key::specialJunk1); - case Roles::ClientSpecialJunk2Role: return m_clientProtocolConfig.value(config_key::specialJunk2); - case Roles::ClientSpecialJunk3Role: return m_clientProtocolConfig.value(config_key::specialJunk3); - case Roles::ClientSpecialJunk4Role: return m_clientProtocolConfig.value(config_key::specialJunk4); - case Roles::ClientSpecialJunk5Role: return m_clientProtocolConfig.value(config_key::specialJunk5); - case Roles::ClientControlledJunk1Role: return m_clientProtocolConfig.value(config_key::controlledJunk1); - case Roles::ClientControlledJunk2Role: return m_clientProtocolConfig.value(config_key::controlledJunk2); - case Roles::ClientControlledJunk3Role: return m_clientProtocolConfig.value(config_key::controlledJunk3); - case Roles::ClientSpecialHandshakeTimeoutRole: return m_clientProtocolConfig.value(config_key::specialHandshakeTimeout); case Roles::ServerJunkPacketCountRole: return m_serverProtocolConfig.value(config_key::junkPacketCount); case Roles::ServerJunkPacketMinSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMinSize); case Roles::ServerJunkPacketMaxSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMaxSize); case Roles::ServerInitPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::initPacketJunkSize); case Roles::ServerResponsePacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::responsePacketJunkSize); - // case Roles::ServerCookieReplyPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::cookieReplyPacketJunkSize); - // case Roles::ServerTransportPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::transportPacketJunkSize); case Roles::ServerInitPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::initPacketMagicHeader); case Roles::ServerResponsePacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::responsePacketMagicHeader); case Roles::ServerUnderloadPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::underloadPacketMagicHeader); @@ -121,8 +94,7 @@ void AwgConfigModel::updateModel(const QJsonObject &config) m_serverProtocolConfig.insert(config_key::transport_proto, serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config); - m_serverProtocolConfig[config_key::subnet_address] = - serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress); + m_serverProtocolConfig[config_key::subnet_address] = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress); m_serverProtocolConfig[config_key::port] = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort); m_serverProtocolConfig[config_key::junkPacketCount] = serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount); @@ -134,10 +106,6 @@ void AwgConfigModel::updateModel(const QJsonObject &config) serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); m_serverProtocolConfig[config_key::responsePacketJunkSize] = serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize); - // m_serverProtocolConfig[config_key::cookieReplyPacketJunkSize] = - // serverProtocolConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize); - // m_serverProtocolConfig[config_key::transportPacketJunkSize] = - // serverProtocolConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize); m_serverProtocolConfig[config_key::initPacketMagicHeader] = serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); m_serverProtocolConfig[config_key::responsePacketMagicHeader] = @@ -156,24 +124,6 @@ void AwgConfigModel::updateModel(const QJsonObject &config) clientProtocolConfig.value(config_key::junkPacketMinSize).toString(m_serverProtocolConfig[config_key::junkPacketMinSize].toString()); m_clientProtocolConfig[config_key::junkPacketMaxSize] = clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(m_serverProtocolConfig[config_key::junkPacketMaxSize].toString()); - m_clientProtocolConfig[config_key::specialJunk1] = - clientProtocolConfig.value(config_key::specialJunk1).toString(protocols::awg::defaultSpecialJunk1); - m_clientProtocolConfig[config_key::specialJunk2] = - clientProtocolConfig.value(config_key::specialJunk2).toString(protocols::awg::defaultSpecialJunk2); - m_clientProtocolConfig[config_key::specialJunk3] = - clientProtocolConfig.value(config_key::specialJunk3).toString(protocols::awg::defaultSpecialJunk3); - m_clientProtocolConfig[config_key::specialJunk4] = - clientProtocolConfig.value(config_key::specialJunk4).toString(protocols::awg::defaultSpecialJunk4); - m_clientProtocolConfig[config_key::specialJunk5] = - clientProtocolConfig.value(config_key::specialJunk5).toString(protocols::awg::defaultSpecialJunk5); - m_clientProtocolConfig[config_key::controlledJunk1] = - clientProtocolConfig.value(config_key::controlledJunk1).toString(protocols::awg::defaultControlledJunk1); - m_clientProtocolConfig[config_key::controlledJunk2] = - clientProtocolConfig.value(config_key::controlledJunk2).toString(protocols::awg::defaultControlledJunk2); - m_clientProtocolConfig[config_key::controlledJunk3] = - clientProtocolConfig.value(config_key::controlledJunk3).toString(protocols::awg::defaultControlledJunk3); - m_clientProtocolConfig[config_key::specialHandshakeTimeout] = - clientProtocolConfig.value(config_key::specialHandshakeTimeout).toString(protocols::awg::defaultSpecialHandshakeTimeout); endResetModel(); } @@ -191,15 +141,6 @@ QJsonObject AwgConfigModel::getConfig() jsonConfig[config_key::junkPacketCount] = m_clientProtocolConfig[config_key::junkPacketCount]; jsonConfig[config_key::junkPacketMinSize] = m_clientProtocolConfig[config_key::junkPacketMinSize]; jsonConfig[config_key::junkPacketMaxSize] = m_clientProtocolConfig[config_key::junkPacketMaxSize]; - jsonConfig[config_key::specialJunk1] = m_clientProtocolConfig[config_key::specialJunk1]; - jsonConfig[config_key::specialJunk2] = m_clientProtocolConfig[config_key::specialJunk2]; - jsonConfig[config_key::specialJunk3] = m_clientProtocolConfig[config_key::specialJunk3]; - jsonConfig[config_key::specialJunk4] = m_clientProtocolConfig[config_key::specialJunk4]; - jsonConfig[config_key::specialJunk5] = m_clientProtocolConfig[config_key::specialJunk5]; - jsonConfig[config_key::controlledJunk1] = m_clientProtocolConfig[config_key::controlledJunk1]; - jsonConfig[config_key::controlledJunk2] = m_clientProtocolConfig[config_key::controlledJunk2]; - jsonConfig[config_key::controlledJunk3] = m_clientProtocolConfig[config_key::controlledJunk3]; - jsonConfig[config_key::specialHandshakeTimeout] = m_clientProtocolConfig[config_key::specialHandshakeTimeout]; m_serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson()); } @@ -218,17 +159,6 @@ bool AwgConfigModel::isPacketSizeEqual(const int s1, const int s2) return (AwgConstant::messageInitiationSize + s1 == AwgConstant::messageResponseSize + s2); } -// bool AwgConfigModel::isPacketSizeEqual(const int s1, const int s2, const int s3, const int s4) -// { -// int initSize = AwgConstant::messageInitiationSize + s1; -// int responseSize = AwgConstant::messageResponseSize + s2; -// int cookieSize = AwgConstant::messageCookieReplySize + s3; -// int transportSize = AwgConstant::messageTransportSize + s4; - -// return (initSize == responseSize || initSize == cookieSize || initSize == transportSize || responseSize == cookieSize -// || responseSize == transportSize || cookieSize == transportSize); -// } - bool AwgConfigModel::isServerSettingsEqual() { const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject()); @@ -248,24 +178,12 @@ QHash AwgConfigModel::roleNames() const roles[ClientJunkPacketCountRole] = "clientJunkPacketCount"; roles[ClientJunkPacketMinSizeRole] = "clientJunkPacketMinSize"; roles[ClientJunkPacketMaxSizeRole] = "clientJunkPacketMaxSize"; - roles[ClientSpecialJunk1Role] = "clientSpecialJunk1"; - roles[ClientSpecialJunk2Role] = "clientSpecialJunk2"; - roles[ClientSpecialJunk3Role] = "clientSpecialJunk3"; - roles[ClientSpecialJunk4Role] = "clientSpecialJunk4"; - roles[ClientSpecialJunk5Role] = "clientSpecialJunk5"; - roles[ClientControlledJunk1Role] = "clientControlledJunk1"; - roles[ClientControlledJunk2Role] = "clientControlledJunk2"; - roles[ClientControlledJunk3Role] = "clientControlledJunk3"; - roles[ClientSpecialHandshakeTimeoutRole] = "clientSpecialHandshakeTimeout"; roles[ServerJunkPacketCountRole] = "serverJunkPacketCount"; roles[ServerJunkPacketMinSizeRole] = "serverJunkPacketMinSize"; roles[ServerJunkPacketMaxSizeRole] = "serverJunkPacketMaxSize"; roles[ServerInitPacketJunkSizeRole] = "serverInitPacketJunkSize"; roles[ServerResponsePacketJunkSizeRole] = "serverResponsePacketJunkSize"; - roles[ServerCookieReplyPacketJunkSizeRole] = "serverCookieReplyPacketJunkSize"; - roles[ServerTransportPacketJunkSizeRole] = "serverTransportPacketJunkSize"; - roles[ServerInitPacketMagicHeaderRole] = "serverInitPacketMagicHeader"; roles[ServerResponsePacketMagicHeaderRole] = "serverResponsePacketMagicHeader"; roles[ServerUnderloadPacketMagicHeaderRole] = "serverUnderloadPacketMagicHeader"; @@ -282,16 +200,6 @@ AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig) clientJunkPacketCount = clientProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount); clientJunkPacketMinSize = clientProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize); clientJunkPacketMaxSize = clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize); - clientSpecialJunk1 = clientProtocolConfig.value(config_key::specialJunk1).toString(protocols::awg::defaultSpecialJunk1); - clientSpecialJunk2 = clientProtocolConfig.value(config_key::specialJunk2).toString(protocols::awg::defaultSpecialJunk2); - clientSpecialJunk3 = clientProtocolConfig.value(config_key::specialJunk3).toString(protocols::awg::defaultSpecialJunk3); - clientSpecialJunk4 = clientProtocolConfig.value(config_key::specialJunk4).toString(protocols::awg::defaultSpecialJunk4); - clientSpecialJunk5 = clientProtocolConfig.value(config_key::specialJunk5).toString(protocols::awg::defaultSpecialJunk5); - clientControlledJunk1 = clientProtocolConfig.value(config_key::controlledJunk1).toString(protocols::awg::defaultControlledJunk1); - clientControlledJunk2 = clientProtocolConfig.value(config_key::controlledJunk2).toString(protocols::awg::defaultControlledJunk2); - clientControlledJunk3 = clientProtocolConfig.value(config_key::controlledJunk3).toString(protocols::awg::defaultControlledJunk3); - clientSpecialHandshakeTimeout = - clientProtocolConfig.value(config_key::specialHandshakeTimeout).toString(protocols::awg::defaultSpecialHandshakeTimeout); subnetAddress = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress); port = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort); @@ -301,10 +209,6 @@ AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig) serverInitPacketJunkSize = serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); serverResponsePacketJunkSize = serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize); - // serverCookieReplyPacketJunkSize = - // serverProtocolConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize); - // serverTransportPacketJunkSize = - // serverProtocolConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize); serverInitPacketMagicHeader = serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); serverResponsePacketMagicHeader = @@ -320,8 +224,6 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const if (subnetAddress != other.subnetAddress || port != other.port || serverJunkPacketCount != other.serverJunkPacketCount || serverJunkPacketMinSize != other.serverJunkPacketMinSize || serverJunkPacketMaxSize != other.serverJunkPacketMaxSize || serverInitPacketJunkSize != other.serverInitPacketJunkSize || serverResponsePacketJunkSize != other.serverResponsePacketJunkSize - // || serverCookieReplyPacketJunkSize != other.serverCookieReplyPacketJunkSize - // || serverTransportPacketJunkSize != other.serverTransportPacketJunkSize || serverInitPacketMagicHeader != other.serverInitPacketMagicHeader || serverResponsePacketMagicHeader != other.serverResponsePacketMagicHeader || serverUnderloadPacketMagicHeader != other.serverUnderloadPacketMagicHeader @@ -334,12 +236,7 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const bool AwgConfig::hasEqualClientSettings(const AwgConfig &other) const { if (clientMtu != other.clientMtu || clientJunkPacketCount != other.clientJunkPacketCount - || clientJunkPacketMinSize != other.clientJunkPacketMinSize || clientJunkPacketMaxSize != other.clientJunkPacketMaxSize - || clientSpecialJunk1 != other.clientSpecialJunk1 || clientSpecialJunk2 != other.clientSpecialJunk2 - || clientSpecialJunk3 != other.clientSpecialJunk3 || clientSpecialJunk4 != other.clientSpecialJunk4 - || clientSpecialJunk5 != other.clientSpecialJunk5 || clientControlledJunk1 != other.clientControlledJunk1 - || clientControlledJunk2 != other.clientControlledJunk2 || clientControlledJunk3 != other.clientControlledJunk3 - || clientSpecialHandshakeTimeout != other.clientSpecialHandshakeTimeout) { + || clientJunkPacketMinSize != other.clientJunkPacketMinSize || clientJunkPacketMaxSize != other.clientJunkPacketMaxSize) { return false; } return true; diff --git a/client/ui/models/protocols/awgConfigModel.h b/client/ui/models/protocols/awgConfigModel.h index 0c2374fc..c1f8bb27 100644 --- a/client/ui/models/protocols/awgConfigModel.h +++ b/client/ui/models/protocols/awgConfigModel.h @@ -6,12 +6,9 @@ #include "containers/containers_defs.h" -namespace AwgConstant -{ +namespace AwgConstant { const int messageInitiationSize = 148; const int messageResponseSize = 92; - const int messageCookieReplySize = 64; - const int messageTransportSize = 32; } struct AwgConfig @@ -25,23 +22,12 @@ struct AwgConfig QString clientJunkPacketCount; QString clientJunkPacketMinSize; QString clientJunkPacketMaxSize; - QString clientSpecialJunk1; - QString clientSpecialJunk2; - QString clientSpecialJunk3; - QString clientSpecialJunk4; - QString clientSpecialJunk5; - QString clientControlledJunk1; - QString clientControlledJunk2; - QString clientControlledJunk3; - QString clientSpecialHandshakeTimeout; QString serverJunkPacketCount; QString serverJunkPacketMinSize; QString serverJunkPacketMaxSize; QString serverInitPacketJunkSize; QString serverResponsePacketJunkSize; - QString serverCookieReplyPacketJunkSize; - QString serverTransportPacketJunkSize; QString serverInitPacketMagicHeader; QString serverResponsePacketMagicHeader; QString serverUnderloadPacketMagicHeader; @@ -49,6 +35,7 @@ struct AwgConfig bool hasEqualServerSettings(const AwgConfig &other) const; bool hasEqualClientSettings(const AwgConfig &other) const; + }; class AwgConfigModel : public QAbstractListModel @@ -64,28 +51,16 @@ public: ClientJunkPacketCountRole, ClientJunkPacketMinSizeRole, ClientJunkPacketMaxSizeRole, - ClientSpecialJunk1Role, - ClientSpecialJunk2Role, - ClientSpecialJunk3Role, - ClientSpecialJunk4Role, - ClientSpecialJunk5Role, - ClientControlledJunk1Role, - ClientControlledJunk2Role, - ClientControlledJunk3Role, - ClientSpecialHandshakeTimeoutRole, ServerJunkPacketCountRole, ServerJunkPacketMinSizeRole, ServerJunkPacketMaxSizeRole, ServerInitPacketJunkSizeRole, ServerResponsePacketJunkSizeRole, - ServerCookieReplyPacketJunkSizeRole, - ServerTransportPacketJunkSizeRole, - ServerInitPacketMagicHeaderRole, ServerResponsePacketMagicHeaderRole, ServerUnderloadPacketMagicHeaderRole, - ServerTransportPacketMagicHeaderRole, + ServerTransportPacketMagicHeaderRole }; explicit AwgConfigModel(QObject *parent = nullptr); @@ -100,7 +75,7 @@ public slots: QJsonObject getConfig(); bool isHeadersEqual(const QString &h1, const QString &h2, const QString &h3, const QString &h4); - bool isPacketSizeEqual(const int s1, const int s2/*, const int s3, const int s4*/); + bool isPacketSizeEqual(const int s1, const int s2); bool isServerSettingsEqual(); diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp index 22813312..67cc292b 100644 --- a/client/ui/models/servers_model.cpp +++ b/client/ui/models/servers_model.cpp @@ -4,12 +4,10 @@ #include "core/controllers/serverController.h" #include "core/networkUtilities.h" -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include #endif -#include "core/api/apiUtils.h" - namespace { namespace configKey @@ -68,7 +66,6 @@ bool ServersModel::setData(const QModelIndex &index, const QVariant &value, int } else { server.insert(config_key::description, value.toString()); } - server.insert(config_key::nameOverriddenByUser, true); m_settings->editServer(index.row(), server); m_servers.replace(index.row(), server); if (index.row() == m_defaultServerIndex) { @@ -429,7 +426,7 @@ void ServersModel::updateDefaultServerContainersModel() emit defaultServerContainersUpdated(containers); } -QJsonObject ServersModel::getServerConfig(const int serverIndex) const +QJsonObject ServersModel::getServerConfig(const int serverIndex) { return m_servers.at(serverIndex).toObject(); } @@ -782,7 +779,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()) @@ -816,8 +813,3 @@ const QString ServersModel::getDefaultServerImagePathCollapsed() } return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode.toUpper()); } - -bool ServersModel::processedServerIsPremium() const -{ - return apiUtils::isPremiumServer(getServerConfig(m_processedServerIndex)); -} diff --git a/client/ui/models/servers_model.h b/client/ui/models/servers_model.h index c36b6534..c4803708 100644 --- a/client/ui/models/servers_model.h +++ b/client/ui/models/servers_model.h @@ -63,9 +63,6 @@ public: Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged) Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged) - Q_PROPERTY(bool processedServerIsPremium READ processedServerIsPremium NOTIFY processedServerChanged) - - bool processedServerIsPremium() const; public slots: void setDefaultServerIndex(const int index); @@ -95,7 +92,7 @@ public slots: void removeServer(); void removeServer(const int serverIndex); - QJsonObject getServerConfig(const int serverIndex) const; + QJsonObject getServerConfig(const int serverIndex); void reloadDefaultServerContainerConfig(); void updateContainerConfig(const int containerIndex, const QJsonObject config); diff --git a/client/ui/ne_notificationhandler.h b/client/ui/ne_notificationhandler.h new file mode 100644 index 00000000..e84d8068 --- /dev/null +++ b/client/ui/ne_notificationhandler.h @@ -0,0 +1,36 @@ +#ifndef NE_NOTIFICATION_HANDLER_H +#define NE_NOTIFICATION_HANDLER_H + +#include "notificationhandler.h" +#include +#include + +class MacOSStatusIcon; + +class NEStatusBarNotificationHandler : public NotificationHandler { + Q_OBJECT +public: + explicit NEStatusBarNotificationHandler(QObject* parent); + ~NEStatusBarNotificationHandler() override; + + void setConnectionState(Vpn::ConnectionState state) override; + void onTranslationsUpdated() override; + +protected: + void notify(Message type, const QString& title, + const QString& message, int timerMsec) override; + +private: + void buildMenu(); + + QMenu m_menu; + MacOSStatusIcon* m_statusIcon; + + QAction* m_actionShow; + QAction* m_actionConnect; + QAction* m_actionDisconnect; + QAction* m_actionVisitWebsite; + QAction* m_actionQuit; +}; + +#endif // NE_NOTIFICATION_HANDLER_H diff --git a/client/ui/notificationhandler.cpp b/client/ui/notificationhandler.cpp index 5efb45c4..4ccdcdf1 100644 --- a/client/ui/notificationhandler.cpp +++ b/client/ui/notificationhandler.cpp @@ -11,18 +11,12 @@ # include "systemtray_notificationhandler.h" #endif + // static NotificationHandler* NotificationHandler::create(QObject* parent) { #if defined(Q_OS_IOS) return new IOSNotificationHandler(parent); #else - -# if defined(Q_OS_LINUX) - //if (LinuxSystemTrayNotificationHandler::requiredCustomImpl()) { - // return new LinuxSystemTrayNotificationHandler(parent); - //} -# endif - return new SystemTrayNotificationHandler(parent); #endif } diff --git a/client/ui/qml/Components/AwgTextField.qml b/client/ui/qml/Components/AwgTextField.qml deleted file mode 100644 index 87b023d9..00000000 --- a/client/ui/qml/Components/AwgTextField.qml +++ /dev/null @@ -1,15 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts - -import "../Controls2" - -TextFieldWithHeaderType { - Layout.fillWidth: true - Layout.topMargin: 16 - - textField.validator: IntValidator { bottom: 0 } - - checkEmptyText: true -} diff --git a/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml index d97d09e8..b8cf5f93 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml @@ -115,10 +115,14 @@ PageType { KeyNavigation.tab: junkPacketCountTextField.textField } - AwgTextField { + TextFieldWithHeaderType { id: junkPacketCountTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: "Jc - Junk packet count" textField.text: clientJunkPacketCount + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { if (textField.text !== clientJunkPacketCount) { @@ -126,13 +130,19 @@ PageType { } } + checkEmptyText: true + KeyNavigation.tab: junkPacketMinSizeTextField.textField } - AwgTextField { + TextFieldWithHeaderType { id: junkPacketMinSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: "Jmin - Junk packet minimum size" textField.text: clientJunkPacketMinSize + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { if (textField.text !== clientJunkPacketMinSize) { @@ -140,144 +150,28 @@ PageType { } } + checkEmptyText: true + KeyNavigation.tab: junkPacketMaxSizeTextField.textField } - AwgTextField { + TextFieldWithHeaderType { id: junkPacketMaxSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: "Jmax - Junk packet maximum size" textField.text: clientJunkPacketMaxSize + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { if (textField.text !== clientJunkPacketMaxSize) { clientJunkPacketMaxSize = textField.text } } - } - AwgTextField { - id: specialJunk1TextField - headerText: qsTr("I1 - First special junk packet") - textField.text: clientSpecialJunk1 - textField.validator: null - checkEmptyText: false + checkEmptyText: true - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk1) { - clientSpecialJunk1 = textField.text - } - } - } - - AwgTextField { - id: specialJunk2TextField - headerText: qsTr("I2 - Second special junk packet") - textField.text: clientSpecialJunk2 - textField.validator: null - checkEmptyText: false - - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk2) { - clientSpecialJunk2 = textField.text - } - } - } - - AwgTextField { - id: specialJunk3TextField - headerText: qsTr("I3 - Third special junk packet") - textField.text: clientSpecialJunk3 - textField.validator: null - checkEmptyText: false - - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk3) { - clientSpecialJunk3 = textField.text - } - } - } - - AwgTextField { - id: specialJunk4TextField - headerText: qsTr("I4 - Fourth special junk packet") - textField.text: clientSpecialJunk4 - textField.validator: null - checkEmptyText: false - - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk4) { - clientSpecialJunk4 = textField.text - } - } - } - - AwgTextField { - id: specialJunk5TextField - headerText: qsTr("I5 - Fifth special junk packet") - textField.text: clientSpecialJunk5 - textField.validator: null - checkEmptyText: false - - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk5 ) { - clientSpecialJunk5 = textField.text - } - } - } - - AwgTextField { - id: controlledJunk1TextField - headerText: qsTr("J1 - First controlled junk packet") - textField.text: clientControlledJunk1 - textField.validator: null - checkEmptyText: false - - textField.onEditingFinished: { - if (textField.text !== clientControlledJunk1) { - clientControlledJunk1 = textField.text - } - } - } - - AwgTextField { - id: controlledJunk2TextField - headerText: qsTr("J2 - Second controlled junk packet") - textField.text: clientControlledJunk2 - textField.validator: null - checkEmptyText: false - - textField.onEditingFinished: { - if (textField.text !== clientControlledJunk2) { - clientControlledJunk2 = textField.text - } - } - } - - AwgTextField { - id: controlledJunk3TextField - headerText: qsTr("J3 - Third controlled junk packet") - textField.text: clientControlledJunk3 - textField.validator: null - checkEmptyText: false - - textField.onEditingFinished: { - if (textField.text !== clientControlledJunk3) { - clientControlledJunk3 = textField.text - } - } - } - - AwgTextField { - id: iTimeTextField - headerText: qsTr("Itime - Special handshake timeout") - textField.text: clientSpecialHandshakeTimeout - checkEmptyText: false - - textField.onEditingFinished: { - if (textField.text !== clientSpecialHandshakeTimeout) { - clientSpecialHandshakeTimeout = textField.text - } - } } Header2TextType { @@ -287,78 +181,82 @@ PageType { text: qsTr("Server settings") } - AwgTextField { + TextFieldWithHeaderType { id: portTextField + Layout.fillWidth: true + Layout.topMargin: 8 + enabled: false headerText: qsTr("Port") textField.text: port } - AwgTextField { + TextFieldWithHeaderType { id: initPacketJunkSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + enabled: false headerText: "S1 - Init packet junk size" textField.text: serverInitPacketJunkSize } - AwgTextField { + TextFieldWithHeaderType { id: responsePacketJunkSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + enabled: false headerText: "S2 - Response packet junk size" textField.text: serverResponsePacketJunkSize } - // AwgTextField { - // id: cookieReplyPacketJunkSizeTextField - // enabled: false - - // headerText: "S3 - Cookie Reply packet junk size" - // textField.text: serverCookieReplyPacketJunkSize - // } - - // AwgTextField { - // id: transportPacketJunkSizeTextField - // enabled: false - - // headerText: "S4 - Transport packet junk size" - // textField.text: serverTransportPacketJunkSize - // } - - AwgTextField { + TextFieldWithHeaderType { id: initPacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + enabled: false headerText: "H1 - Init packet magic header" textField.text: serverInitPacketMagicHeader } - AwgTextField { + TextFieldWithHeaderType { id: responsePacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + enabled: false headerText: "H2 - Response packet magic header" textField.text: serverResponsePacketMagicHeader } - AwgTextField { + TextFieldWithHeaderType { id: underloadPacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + enabled: false headerText: "H3 - Underload packet magic header" textField.text: serverUnderloadPacketMagicHeader } - AwgTextField { + TextFieldWithHeaderType { id: transportPacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + enabled: false headerText: "H4 - Transport packet magic header" textField.text: serverTransportPacketMagicHeader } - } } } diff --git a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml index 699ae724..e8fd2b94 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml @@ -138,138 +138,183 @@ PageType { checkEmptyText: true } - AwgTextField { + TextFieldWithHeaderType { id: junkPacketCountTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: qsTr("Jc - Junk packet count") textField.text: serverJunkPacketCount + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { + if (textField.text === "") { + textField.text = "0" + } + if (textField.text !== serverJunkPacketCount) { serverJunkPacketCount = textField.text } } + + checkEmptyText: true } - AwgTextField { + TextFieldWithHeaderType { id: junkPacketMinSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: qsTr("Jmin - Junk packet minimum size") textField.text: serverJunkPacketMinSize + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { if (textField.text !== serverJunkPacketMinSize) { serverJunkPacketMinSize = textField.text } } + + checkEmptyText: true } - AwgTextField { + TextFieldWithHeaderType { id: junkPacketMaxSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: qsTr("Jmax - Junk packet maximum size") textField.text: serverJunkPacketMaxSize + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { if (textField.text !== serverJunkPacketMaxSize) { serverJunkPacketMaxSize = textField.text } } + + checkEmptyText: true } - AwgTextField { + TextFieldWithHeaderType { id: initPacketJunkSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: qsTr("S1 - Init packet junk size") textField.text: serverInitPacketJunkSize + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { if (textField.text !== serverInitPacketJunkSize) { serverInitPacketJunkSize = textField.text } } + + checkEmptyText: true + + onActiveFocusChanged: { + if(activeFocus) { + listview.positionViewAtEnd() + } + } } - AwgTextField { + TextFieldWithHeaderType { id: responsePacketJunkSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: qsTr("S2 - Response packet junk size") textField.text: serverResponsePacketJunkSize + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { if (textField.text !== serverResponsePacketJunkSize) { serverResponsePacketJunkSize = textField.text } } + + checkEmptyText: true + + onActiveFocusChanged: { + if(activeFocus) { + listview.positionViewAtEnd() + } + } } - // AwgTextField { - // id: cookieReplyPacketJunkSizeTextField - // headerText: qsTr("S3 - Cookie reply packet junk size") - // textField.text: serverCookieReplyPacketJunkSize - - // textField.onEditingFinished: { - // if (textField.text !== serverCookieReplyPacketJunkSize) { - // serverCookieReplyPacketJunkSize = textField.text - // } - // } - // } - - // AwgTextField { - // id: transportPacketJunkSizeTextField - // headerText: qsTr("S4 - Transport packet junk size") - // textField.text: serverTransportPacketJunkSize - - // textField.onEditingFinished: { - // if (textField.text !== serverTransportPacketJunkSize) { - // serverTransportPacketJunkSize = textField.text - // } - // } - // } - - AwgTextField { + TextFieldWithHeaderType { id: initPacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: qsTr("H1 - Init packet magic header") textField.text: serverInitPacketMagicHeader + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { if (textField.text !== serverInitPacketMagicHeader) { serverInitPacketMagicHeader = textField.text } } + + checkEmptyText: true } - AwgTextField { + TextFieldWithHeaderType { id: responsePacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: qsTr("H2 - Response packet magic header") textField.text: serverResponsePacketMagicHeader + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { if (textField.text !== serverResponsePacketMagicHeader) { serverResponsePacketMagicHeader = textField.text } } + + checkEmptyText: true } - AwgTextField { - id: underloadPacketMagicHeaderTextField - headerText: qsTr("H3 - Underload packet magic header") - textField.text: serverUnderloadPacketMagicHeader - - textField.onEditingFinished: { - if (textField.text !== serverUnderloadPacketMagicHeader) { - serverUnderloadPacketMagicHeader = textField.text - } - } - } - - AwgTextField { + TextFieldWithHeaderType { id: transportPacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: qsTr("H4 - Transport packet magic header") textField.text: serverTransportPacketMagicHeader + textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { if (textField.text !== serverTransportPacketMagicHeader) { serverTransportPacketMagicHeader = textField.text } } + + checkEmptyText: true } + TextFieldWithHeaderType { + id: underloadPacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + headerText: qsTr("H3 - Underload packet magic header") + textField.text: serverUnderloadPacketMagicHeader + textField.validator: IntValidator { bottom: 0 } + + textField.onEditingFinished: { + if (textField.text !== serverUnderloadPacketMagicHeader) { + serverUnderloadPacketMagicHeader = textField.text + } + } + + checkEmptyText: true + } BasicButtonType { id: saveRestartButton @@ -283,8 +328,6 @@ PageType { responsePacketMagicHeaderTextField.errorText === "" && initPacketMagicHeaderTextField.errorText === "" && responsePacketJunkSizeTextField.errorText === "" && - // cookieReplyHeaderJunkTextField.errorText === "" && - // transportHeaderJunkTextField.errorText === "" && initPacketJunkSizeTextField.errorText === "" && junkPacketMaxSizeTextField.errorText === "" && junkPacketMinSizeTextField.errorText === "" && @@ -317,13 +360,6 @@ PageType { PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)")) return } - // if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text), - // parseInt(responsePacketJunkSizeTextField.textField.text), - // parseInt(cookieReplyPacketJunkSizeTextField.textField.text), - // parseInt(transportPacketJunkSizeTextField.textField.text))) { - // PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) + S3 + cookie reply size (64) + S4 + transport packet size (32)")) - // return - // } } var headerText = qsTr("Save settings?") diff --git a/client/ui/qml/Pages2/PageProtocolCloakSettings.qml b/client/ui/qml/Pages2/PageProtocolCloakSettings.qml index 8e5129b0..7a0fafbd 100644 --- a/client/ui/qml/Pages2/PageProtocolCloakSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolCloakSettings.qml @@ -59,14 +59,11 @@ PageType { model: CloakConfigModel delegate: Item { - id: delegateItem - - property alias trafficFromField: trafficFromField - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() - implicitWidth: listview.width implicitHeight: col.implicitHeight + property alias trafficFromField: trafficFromField + ColumnLayout { id: col @@ -81,6 +78,7 @@ PageType { BaseHeaderType { Layout.fillWidth: true + headerText: qsTr("Cloak settings") } @@ -90,8 +88,6 @@ PageType { Layout.fillWidth: true Layout.topMargin: 32 - enabled: delegateItem.isEnabled - headerText: qsTr("Disguised as traffic from") textField.text: site @@ -108,8 +104,6 @@ PageType { } } } - - checkEmptyText: true } TextFieldWithHeaderType { @@ -118,8 +112,6 @@ PageType { Layout.fillWidth: true Layout.topMargin: 16 - enabled: delegateItem.isEnabled - headerText: qsTr("Port") textField.text: port textField.maximumLength: 5 @@ -130,8 +122,6 @@ PageType { port = textField.text } } - - checkEmptyText: true } DropDownType { @@ -139,8 +129,6 @@ PageType { Layout.fillWidth: true Layout.topMargin: 16 - enabled: delegateItem.isEnabled - descriptionText: qsTr("Cipher") headerText: qsTr("Cipher") @@ -178,46 +166,25 @@ PageType { } BasicButtonType { - id: saveButton + id: saveRestartButton Layout.fillWidth: true Layout.topMargin: 24 Layout.bottomMargin: 24 - enabled: trafficFromField.errorText === "" && - portTextField.errorText === "" - text: qsTr("Save") clickedFunc: function() { forceActiveFocus() - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling) - InstallController.updateContainer(CloakConfigModel.getConfig()) + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(CloakConfigModel.getConfig()) } - - Keys.onEnterPressed: saveButton.clicked() - Keys.onReturnPressed: saveButton.clicked() } } } diff --git a/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml b/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml index 62cbd1f6..2e00d54a 100644 --- a/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml @@ -58,14 +58,11 @@ PageType { model: OpenVpnConfigModel delegate: Item { - id: delegateItem - - property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() - implicitWidth: listview.width implicitHeight: col.implicitHeight + property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField + ColumnLayout { id: col @@ -80,6 +77,7 @@ PageType { BaseHeaderType { Layout.fillWidth: true + headerText: qsTr("OpenVPN settings") } @@ -89,8 +87,6 @@ PageType { Layout.fillWidth: true Layout.topMargin: 32 - enabled: delegateItem.isEnabled - headerText: qsTr("VPN address subnet") textField.text: subnetAddress @@ -101,8 +97,6 @@ PageType { subnetAddress = textField.text } } - - checkEmptyText: true } ParagraphTextType { @@ -140,7 +134,7 @@ PageType { Layout.topMargin: 40 parentFlickable: fl - enabled: delegateItem.isEnabled + enabled: isPortEditable headerText: qsTr("Port") textField.text: port @@ -152,8 +146,6 @@ PageType { port = textField.text } } - - checkEmptyText: true } SwitcherType { @@ -396,45 +388,26 @@ PageType { } BasicButtonType { - id: saveButton + id: saveRestartButton Layout.fillWidth: true Layout.topMargin: 24 Layout.bottomMargin: 24 - enabled: vpnAddressSubnetTextField.errorText === "" && - portTextField.errorText === "" - text: qsTr("Save") parentFlickable: fl - onClicked: function() { + clickedFunc: function() { forceActiveFocus() - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.updateContainer(OpenVpnConfigModel.getConfig()) + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(OpenVpnConfigModel.getConfig()) } - - Keys.onEnterPressed: saveButton.clicked() - Keys.onReturnPressed: saveButton.clicked() } } } diff --git a/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml b/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml index 92df3ec7..63e60dcb 100644 --- a/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml @@ -57,13 +57,15 @@ PageType { model: ShadowSocksConfigModel delegate: Item { - id: delegateItem - - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() - implicitWidth: listview.width implicitHeight: col.implicitHeight + property var focusItemId: portTextField.enabled ? + portTextField : + cipherDropDown.enabled ? + cipherDropDown : + saveRestartButton + ColumnLayout { id: col @@ -78,6 +80,7 @@ PageType { BaseHeaderType { Layout.fillWidth: true + headerText: qsTr("Shadowsocks settings") } @@ -87,7 +90,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 40 - enabled: delegateItem.isEnabled + enabled: isPortEditable headerText: qsTr("Port") textField.text: port @@ -99,8 +102,6 @@ PageType { port = textField.text } } - - checkEmptyText: true } DropDownType { @@ -108,7 +109,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 20 - enabled: delegateItem.isEnabled + enabled: isCipherEditable descriptionText: qsTr("Cipher") headerText: qsTr("Cipher") @@ -148,43 +149,27 @@ PageType { } BasicButtonType { - id: saveButton + id: saveRestartButton Layout.fillWidth: true Layout.topMargin: 24 Layout.bottomMargin: 24 - enabled: portTextField.errorText === "" + enabled: isPortEditable | isCipherEditable text: qsTr("Save") clickedFunc: function() { forceActiveFocus() - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.updateContainer(ShadowSocksConfigModel.getConfig()) + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(ShadowSocksConfigModel.getConfig()) } - - Keys.onEnterPressed: saveButton.clicked() - Keys.onReturnPressed: saveButton.clicked() } } } diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml index 21b35bc1..7b5180f3 100644 --- a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml @@ -152,7 +152,7 @@ PageType { } var noButtonFunction = function() { if (!GC.isMobile()) { - saveButton.forceActiveFocus() + saveRestartButton.forceActiveFocus() } } showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) diff --git a/client/ui/qml/Pages2/PageProtocolXraySettings.qml b/client/ui/qml/Pages2/PageProtocolXraySettings.qml index 0bcd14de..d22e31a2 100644 --- a/client/ui/qml/Pages2/PageProtocolXraySettings.qml +++ b/client/ui/qml/Pages2/PageProtocolXraySettings.qml @@ -58,10 +58,7 @@ PageType { model: XrayConfigModel delegate: Item { - id: delegateItem - property alias focusItemId: textFieldWithHeaderType.textField - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() implicitWidth: listview.width implicitHeight: col.implicitHeight @@ -88,8 +85,6 @@ PageType { Layout.fillWidth: true Layout.topMargin: 32 - enabled: delegateItem.isEnabled - headerText: qsTr("Disguised as traffic from") textField.text: site @@ -106,8 +101,6 @@ PageType { } } } - - checkEmptyText: true } TextFieldWithHeaderType { @@ -137,38 +130,23 @@ PageType { Layout.topMargin: 24 Layout.bottomMargin: 24 - enabled: portTextField.errorText === "" - text: qsTr("Save") - onClicked: function() { + onClicked: { forceActiveFocus() - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.updateContainer(XrayConfigModel.getConfig()) - //focusItem.forceActiveFocus() + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(XrayConfigModel.getConfig()) + focusItem.forceActiveFocus() } - Keys.onEnterPressed: saveButton.clicked() - Keys.onReturnPressed: saveButton.clicked() + Keys.onEnterPressed: basicButton.clicked() + Keys.onReturnPressed: basicButton.clicked() } } } diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml index 75832fa6..93118755 100644 --- a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml @@ -158,32 +158,6 @@ PageType { readonly property bool isVisibleForAmneziaFree: ApiAccountInfoModel.data("isComponentVisible") - SwitcherType { - id: switcher - - readonly property bool isVlessProtocol: ApiConfigsController.isVlessProtocol() - - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.rightMargin: 16 - Layout.leftMargin: 16 - - visible: ApiAccountInfoModel.data("isProtocolSelectionSupported") - - text: qsTr("Use VLESS protocol") - checked: switcher.isVlessProtocol - onToggled: function() { - if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { - PageController.showNotificationMessage(qsTr("Cannot change protocol during active connection")) - } else { - PageController.showBusyIndicator(true) - ApiConfigsController.setCurrentProtocol(switcher.isVlessProtocol ? "awg" : "vless") - ApiConfigsController.updateServiceFromGateway(ServersModel.processedIndex, "", "", true) - PageController.showBusyIndicator(false) - } - } - } - WarningType { id: warning diff --git a/client/ui/qml/Pages2/PageSettingsKillSwitch.qml b/client/ui/qml/Pages2/PageSettingsKillSwitch.qml index d6d73b20..444eb415 100644 --- a/client/ui/qml/Pages2/PageSettingsKillSwitch.qml +++ b/client/ui/qml/Pages2/PageSettingsKillSwitch.qml @@ -81,9 +81,7 @@ PageType { Layout.leftMargin: 16 Layout.rightMargin: 16 - visible: false - enabled: false - // enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected + enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected checked: SettingsController.strictKillSwitchEnabled text: qsTr("Strict KillSwitch") @@ -105,9 +103,7 @@ PageType { } } - DividerType { - visible: false - } + DividerType {} LabelWithButtonType { Layout.topMargin: 32 diff --git a/client/ui/qml/Pages2/PageSettingsServerData.qml b/client/ui/qml/Pages2/PageSettingsServerData.qml index 82552958..995ca74b 100644 --- a/client/ui/qml/Pages2/PageSettingsServerData.qml +++ b/client/ui/qml/Pages2/PageSettingsServerData.qml @@ -260,7 +260,7 @@ PageType { LabelWithButtonType { id: labelWithButton6 - visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium + visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") Layout.fillWidth: true text: qsTr("Switch to the new Amnezia Premium subscription") @@ -273,7 +273,7 @@ PageType { } DividerType { - visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium + visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") } } } diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 0f0976bc..48f74acf 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -429,11 +429,6 @@ PageType { fillConnectionTypeModel() - if (exportTypeSelector.currentIndex >= root.connectionTypesModel.length) { - exportTypeSelector.currentIndex = 0 - exportTypeSelector.text = root.connectionTypesModel[0].name - } - if (accessTypeSelector.currentIndex === 1) { PageController.showBusyIndicator(true) ExportController.updateClientManagementModel(ContainersModel.getProcessedContainerIndex(), diff --git a/client/ui/qml/main2.qml b/client/ui/qml/main2.qml index 7cd5790b..69c244d3 100644 --- a/client/ui/qml/main2.qml +++ b/client/ui/qml/main2.qml @@ -26,7 +26,8 @@ Window { color: AmneziaStyle.color.midnightBlack - onClosing: function() { + onClosing: function(close) { + close.accepted = false PageController.closeWindow() } diff --git a/client/ui/systemtray_notificationhandler.cpp b/client/ui/systemtray_notificationhandler.cpp index e1361302..34268d14 100644 --- a/client/ui/systemtray_notificationhandler.cpp +++ b/client/ui/systemtray_notificationhandler.cpp @@ -22,6 +22,9 @@ SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) : m_systemTrayIcon(parent) { +#ifdef MACOS_NE + MacOSUtils::hideDockIcon(); +#endif m_systemTrayIcon.show(); connect(&m_systemTrayIcon, &QSystemTrayIcon::activated, this, &SystemTrayNotificationHandler::onTrayActivated); @@ -38,9 +41,11 @@ SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) : QDesktopServices::openUrl(QUrl("https://amnezia.org")); }); - m_trayActionQuit = m_menu.addAction(QIcon(":/images/tray/cancel.png"), tr("Quit") + " " + APPLICATION_NAME, this, [&](){ - qApp->quit(); - }); + // Quit action: disconnect VPN first on macOS NE, else quit directly + m_trayActionQuit = m_menu.addAction(QIcon(":/images/tray/cancel.png"), + tr("Quit") + " " + APPLICATION_NAME, + this, + [&](){ qApp->quit(); }); m_systemTrayIcon.setContextMenu(&m_menu); setTrayState(Vpn::ConnectionState::Disconnected); 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 3de0f035..4f31d99f 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); @@ -123,7 +123,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 { @@ -237,10 +237,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); } @@ -271,7 +272,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); @@ -283,7 +284,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); @@ -363,20 +364,20 @@ 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); } if (sitesJsonArray.isEmpty()) { - sitesRouteMode = Settings::RouteMode::VpnAllSites; - } else if (sitesRouteMode == Settings::VpnOnlyForwardSites) { + routeMode = Settings::RouteMode::VpnAllSites; + } else if (routeMode == Settings::VpnOnlyForwardSites) { // Allow traffic to Amnezia DNS sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns1).toString()); sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns2).toString()); @@ -384,7 +385,7 @@ void VpnConnection::appendSplitTunnelingConfig() } } - 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; @@ -404,13 +405,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 @@ -472,7 +466,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/DeveloperIDG2CA.cer b/deploy/DeveloperIDG2CA.cer deleted file mode 100644 index 8cbcf6f4..00000000 Binary files a/deploy/DeveloperIDG2CA.cer and /dev/null differ diff --git a/deploy/build_ios.sh b/deploy/build_ios.sh index 5dc11ff1..7619e146 100755 --- a/deploy/build_ios.sh +++ b/deploy/build_ios.sh @@ -32,7 +32,7 @@ cmake --version clang -v # Generate XCodeProj -$QT_BIN_DIR/qt-cmake . -B $BUILD_DIR -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR +$QT_BIN_DIR/qt-cmake . -B $BUILD_DIR -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR -DDEPLOY=ON KEYCHAIN=amnezia.build.ios.keychain KEYCHAIN_FILE=$HOME/Library/Keychains/${KEYCHAIN}-db diff --git a/deploy/build_macos.sh b/deploy/build_macos.sh old mode 100644 new mode 100755 index 03f286fc..5f6e9786 --- a/deploy/build_macos.sh +++ b/deploy/build_macos.sh @@ -1,15 +1,4 @@ #!/bin/bash -# ----------------------------------------------------------------------------- -# Usage: -# Export the required signing credentials before running this script, e.g.: -# export MAC_APP_CERT_PW='pw-for-DeveloperID-Application' -# export MAC_INSTALL_CERT_PW='pw-for-DeveloperID-Installer' -# export MAC_SIGNER_ID='Developer ID Application: Some Company Name (XXXXXXXXXX)' -# export MAC_INSTALLER_SIGNER_ID='Developer ID Installer: Some Company Name (XXXXXXXXXX)' -# export APPLE_DEV_EMAIL='your@email.com' -# export APPLE_DEV_PASSWORD='' -# bash deploy/build_macos.sh [-n] -# ----------------------------------------------------------------------------- echo "Build script started ..." set -o errexit -o nounset @@ -25,10 +14,10 @@ done PROJECT_DIR=$(pwd) DEPLOY_DIR=$PROJECT_DIR/deploy -mkdir -p "$DEPLOY_DIR/build" -BUILD_DIR="$DEPLOY_DIR/build" +mkdir -p $DEPLOY_DIR/build +BUILD_DIR=$DEPLOY_DIR/build -echo "Project dir: ${PROJECT_DIR}" +echo "Project dir: ${PROJECT_DIR}" echo "Build dir: ${BUILD_DIR}" APP_NAME=AmneziaVPN @@ -39,45 +28,39 @@ PLIST_NAME=$APP_NAME.plist OUT_APP_DIR=$BUILD_DIR/client BUNDLE_DIR=$OUT_APP_DIR/$APP_FILENAME -# Prebuilt deployment assets are available via the symlink under deploy/data 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 # Search Qt if [ -z "${QT_VERSION+x}" ]; then -QT_VERSION=6.8.3; +QT_VERSION=6.4.3; +QIF_VERSION=4.6 QT_BIN_DIR=$HOME/Qt/$QT_VERSION/macos/bin +QIF_BIN_DIR=$QT_BIN_DIR/../../../Tools/QtInstallerFramework/$QIF_VERSION/bin fi echo "Using Qt in $QT_BIN_DIR" +echo "Using QIF in $QIF_BIN_DIR" # Checking env -"$QT_BIN_DIR/qt-cmake" --version +$QT_BIN_DIR/qt-cmake --version cmake --version clang -v # Build App echo "Building App..." -cd "$BUILD_DIR" +cd $BUILD_DIR -"$QT_BIN_DIR/qt-cmake" -S "$PROJECT_DIR" -B "$BUILD_DIR" +$QT_BIN_DIR/qt-cmake -S $PROJECT_DIR -B $BUILD_DIR cmake --build . --config release --target all # Build and run tests here -# Create a temporary keychain and import certificates -KEYCHAIN_PATH="$PROJECT_DIR/mac_sign.keychain" -trap 'echo "Cleaning up mac_sign.keychain..."; security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true; rm -f "$KEYCHAIN_PATH" 2>/dev/null || true' EXIT -KEYCHAIN=$(security default-keychain -d user | tr -d '"[:space:]"') -security list-keychains -d user -s "$KEYCHAIN_PATH" "$KEYCHAIN" "$(security list-keychains -d user | tr '\n' ' ')" -security create-keychain -p "" "$KEYCHAIN_PATH" -security import "$DEPLOY_DIR/DeveloperIdApplicationCertificate.p12" -k "$KEYCHAIN_PATH" -P "$MAC_APP_CERT_PW" -T /usr/bin/codesign -security import "$DEPLOY_DIR/DeveloperIdInstallerCertificate.p12" -k "$KEYCHAIN_PATH" -P "$MAC_INSTALL_CERT_PW" -T /usr/bin/codesign -security import "$DEPLOY_DIR/DeveloperIDG2CA.cer" -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -security list-keychains -d user -s "$KEYCHAIN_PATH" - echo "____________________________________" echo "............Deploy.................." echo "____________________________________" @@ -86,159 +69,102 @@ echo "____________________________________" echo "Packaging ..." -cp -Rv "$PREBUILT_DEPLOY_DATA_DIR"/* "$BUNDLE_DIR/Contents/macOS" -"$QT_BIN_DIR/macdeployqt" "$OUT_APP_DIR/$APP_FILENAME" -always-overwrite -qmldir="$PROJECT_DIR" -cp -av "$BUILD_DIR/service/server/$APP_NAME-service" "$BUNDLE_DIR/Contents/macOS" -rsync -av --exclude="$PLIST_NAME" --exclude=post_install.sh --exclude=post_uninstall.sh "$DEPLOY_DATA_DIR/" "$BUNDLE_DIR/Contents/macOS/" +cp -Rv $PREBUILT_DEPLOY_DATA_DIR/* $BUNDLE_DIR/Contents/macOS +$QT_BIN_DIR/macdeployqt $OUT_APP_DIR/$APP_FILENAME -always-overwrite -qmldir=$PROJECT_DIR +cp -av $BUILD_DIR/service/server/$APP_NAME-service $BUNDLE_DIR/Contents/macOS +cp -Rv $PROJECT_DIR/deploy/data/macos/* $BUNDLE_DIR/Contents/macOS +rm -f $BUNDLE_DIR/Contents/macOS/post_install.sh $BUNDLE_DIR/Contents/macOS/post_uninstall.sh -if [ "${MAC_APP_CERT_PW+x}" ]; then +if [ "${MAC_CERT_PW+x}" ]; then - # Path to the p12 that contains the Developer ID *Application* certificate - CERTIFICATE_P12=$DEPLOY_DIR/DeveloperIdApplicationCertificate.p12 + CERTIFICATE_P12=$DEPLOY_DIR/PrivacyTechAppleCertDeveloperId.p12 + WWDRCA=$DEPLOY_DIR/WWDRCA.cer + KEYCHAIN=amnezia.build.macos.keychain + TEMP_PASS=tmp_pass - # Ensure launchd plist is bundled, but place it inside Resources so that - # the bundle keeps a valid structure (nothing but `Contents` at the root). - mkdir -p "$BUNDLE_DIR/Contents/Resources" - cp "$DEPLOY_DATA_DIR/$PLIST_NAME" "$BUNDLE_DIR/Contents/Resources/$PLIST_NAME" + security create-keychain -p $TEMP_PASS $KEYCHAIN || true + security default-keychain -s $KEYCHAIN + security unlock-keychain -p $TEMP_PASS $KEYCHAIN - # Show available signing identities (useful for debugging) - security find-identity -p codesigning || true + security default-keychain + security list-keychains + + security import $WWDRCA -k $KEYCHAIN -T /usr/bin/codesign || true + security import $CERTIFICATE_P12 -k $KEYCHAIN -P $MAC_CERT_PW -T /usr/bin/codesign || true + + security set-key-partition-list -S apple-tool:,apple: -k $TEMP_PASS $KEYCHAIN + security find-identity -p codesigning echo "Signing App bundle..." - /usr/bin/codesign --deep --force --verbose --timestamp -o runtime --keychain "$KEYCHAIN_PATH" --sign "$MAC_SIGNER_ID" "$BUNDLE_DIR" - /usr/bin/codesign --verify -vvvv "$BUNDLE_DIR" || true - spctl -a -vvvv "$BUNDLE_DIR" || true + /usr/bin/codesign --deep --force --verbose --timestamp -o runtime --sign "$MAC_SIGNER_ID" $BUNDLE_DIR + /usr/bin/codesign --verify -vvvv $BUNDLE_DIR || true + spctl -a -vvvv $BUNDLE_DIR || true + if [ "${NOTARIZE_APP+x}" ]; then + echo "Notarizing App bundle..." + /usr/bin/ditto -c -k --keepParent $BUNDLE_DIR $PROJECT_DIR/Bundle_to_notarize.zip + xcrun notarytool submit $PROJECT_DIR/Bundle_to_notarize.zip --apple-id $APPLE_DEV_EMAIL --team-id $MAC_TEAM_ID --password $APPLE_DEV_PASSWORD + rm $PROJECT_DIR/Bundle_to_notarize.zip + sleep 300 + xcrun stapler staple $BUNDLE_DIR + xcrun stapler validate $BUNDLE_DIR + spctl -a -vvvv $BUNDLE_DIR || true + fi fi echo "Packaging installer..." -PKG_DIR=$BUILD_DIR/pkg -# Remove any stale packaging data from previous runs -rm -rf "$PKG_DIR" -PKG_ROOT=$PKG_DIR/root -SCRIPTS_DIR=$PKG_DIR/scripts -RESOURCES_DIR=$PKG_DIR/resources -INSTALL_PKG=$PKG_DIR/${APP_NAME}_install.pkg -UNINSTALL_PKG=$PKG_DIR/${APP_NAME}_uninstall.pkg -FINAL_PKG=$PKG_DIR/${APP_NAME}.pkg -UNINSTALL_SCRIPTS_DIR=$PKG_DIR/uninstall_scripts +mkdir -p $INSTALLER_DATA_DIR +cp -av $PROJECT_DIR/deploy/installer $BUILD_DIR +cp -av $DEPLOY_DATA_DIR/post_install.sh $INSTALLER_DATA_DIR/post_install.sh +cp -av $DEPLOY_DATA_DIR/post_uninstall.sh $INSTALLER_DATA_DIR/post_uninstall.sh +cp -av $DEPLOY_DATA_DIR/$PLIST_NAME $INSTALLER_DATA_DIR/$PLIST_NAME -mkdir -p "$PKG_ROOT/Applications" "$SCRIPTS_DIR" "$RESOURCES_DIR" "$UNINSTALL_SCRIPTS_DIR" +chmod a+x $INSTALLER_DATA_DIR/post_install.sh $INSTALLER_DATA_DIR/post_uninstall.sh -cp -R "$BUNDLE_DIR" "$PKG_ROOT/Applications" -# launchd plist is already inside the bundle; no need to add it again after signing -/usr/bin/codesign --deep --force --verbose --timestamp -o runtime --keychain "$KEYCHAIN_PATH" --sign "$MAC_SIGNER_ID" "$PKG_ROOT/Applications/$APP_FILENAME" -/usr/bin/codesign --verify --deep --strict --verbose=4 "$PKG_ROOT/Applications/$APP_FILENAME" || true -cp "$DEPLOY_DATA_DIR/post_install.sh" "$SCRIPTS_DIR/post_install.sh" -cp "$DEPLOY_DATA_DIR/post_uninstall.sh" "$UNINSTALL_SCRIPTS_DIR/postinstall" -mkdir -p "$RESOURCES_DIR/scripts" -cp "$DEPLOY_DATA_DIR/check_install.sh" "$RESOURCES_DIR/scripts/check_install.sh" -cp "$DEPLOY_DATA_DIR/check_uninstall.sh" "$RESOURCES_DIR/scripts/check_uninstall.sh" +cd $BUNDLE_DIR +tar czf $INSTALLER_DATA_DIR/$APP_NAME.tar.gz ./ -cat > "$SCRIPTS_DIR/postinstall" <<'EOS' -#!/bin/bash -SCRIPT_DIR="$(dirname "$0")" -bash "$SCRIPT_DIR/post_install.sh" -exit 0 -EOS +echo "Building installer..." +$QIF_BIN_DIR/binarycreator --offline-only -v -c $BUILD_DIR/installer/config/macos.xml -p $BUILD_DIR/installer/packages -f $INSTALLER_BUNDLE_DIR -chmod +x "$SCRIPTS_DIR"/* -chmod +x "$UNINSTALL_SCRIPTS_DIR"/* -chmod +x "$RESOURCES_DIR/scripts"/* -cp "$PROJECT_DIR/LICENSE" "$RESOURCES_DIR/LICENSE" +if [ "${MAC_CERT_PW+x}" ]; then + echo "Signing installer bundle..." + security unlock-keychain -p $TEMP_PASS $KEYCHAIN + /usr/bin/codesign --deep --force --verbose --timestamp -o runtime --sign "$MAC_SIGNER_ID" $INSTALLER_BUNDLE_DIR + /usr/bin/codesign --verify -vvvv $INSTALLER_BUNDLE_DIR || true -APP_VERSION=$(grep -m1 -E 'project\(' "$PROJECT_DIR/CMakeLists.txt" | sed -E 's/.*VERSION ([0-9.]+).*/\1/') -echo "Building component package $INSTALL_PKG ..." - -# Disable bundle relocation so the app always ends up in /Applications even if -# another copy is lying around somewhere. We do this by letting pkgbuild -# analyse the contents, flipping the BundleIsRelocatable flag to false for every -# bundle it discovers and then feeding that plist back to pkgbuild. - -COMPONENT_PLIST="$PKG_DIR/component.plist" -# Create the component description plist first -pkgbuild --analyze --root "$PKG_ROOT" "$COMPONENT_PLIST" - -# Turn all `BundleIsRelocatable` keys to false (PlistBuddy is available on all -# macOS systems). We first convert to xml1 to ensure predictable formatting. - -# Turn relocation off for every bundle entry in the plist. PlistBuddy cannot -# address keys that contain slashes without quoting, so we iterate through the -# top-level keys it prints. -plutil -convert xml1 "$COMPONENT_PLIST" -for bundle_key in $(/usr/libexec/PlistBuddy -c "Print" "$COMPONENT_PLIST" | awk '/^[ \t]*[A-Za-z0-9].*\.app/ {print $1}'); do - /usr/libexec/PlistBuddy -c "Set :'${bundle_key}':BundleIsRelocatable false" "$COMPONENT_PLIST" || true -done - -# Now build the real payload package with the edited plist so that the final -# PackageInfo contains relocatable="false". -pkgbuild --root "$PKG_ROOT" \ - --identifier "$APP_DOMAIN" \ - --version "$APP_VERSION" \ - --install-location "/" \ - --scripts "$SCRIPTS_DIR" \ - --component-plist "$COMPONENT_PLIST" \ - --sign "$MAC_INSTALLER_SIGNER_ID" \ - "$INSTALL_PKG" - -# Build uninstaller component package -UNINSTALL_COMPONENT_PKG=$PKG_DIR/${APP_NAME}_uninstall_component.pkg -echo "Building uninstaller component package $UNINSTALL_COMPONENT_PKG ..." -pkgbuild --nopayload \ - --identifier "$APP_DOMAIN.uninstall" \ - --version "$APP_VERSION" \ - --scripts "$UNINSTALL_SCRIPTS_DIR" \ - --sign "$MAC_INSTALLER_SIGNER_ID" \ - "$UNINSTALL_COMPONENT_PKG" - -# Wrap uninstaller component in a distribution package for clearer UI -echo "Building uninstaller distribution package $UNINSTALL_PKG ..." -UNINSTALL_RESOURCES=$PKG_DIR/uninstall_resources -rm -rf "$UNINSTALL_RESOURCES" -mkdir -p "$UNINSTALL_RESOURCES" -cp "$DEPLOY_DATA_DIR/uninstall_welcome.html" "$UNINSTALL_RESOURCES" -cp "$DEPLOY_DATA_DIR/uninstall_conclusion.html" "$UNINSTALL_RESOURCES" -productbuild \ - --distribution "$DEPLOY_DATA_DIR/distribution_uninstall.xml" \ - --package-path "$PKG_DIR" \ - --resources "$UNINSTALL_RESOURCES" \ - --sign "$MAC_INSTALLER_SIGNER_ID" \ - "$UNINSTALL_PKG" - -cp "$PROJECT_DIR/deploy/data/macos/distribution.xml" "$PKG_DIR/distribution.xml" - -echo "Creating final installer $FINAL_PKG ..." -productbuild --distribution "$PKG_DIR/distribution.xml" \ - --package-path "$PKG_DIR" \ - --resources "$RESOURCES_DIR" \ - --sign "$MAC_INSTALLER_SIGNER_ID" \ - "$FINAL_PKG" - -if [ "${MAC_INSTALL_CERT_PW+x}" ] && [ "${NOTARIZE_APP+x}" ]; then - echo "Notarizing installer package..." - xcrun notarytool submit "$FINAL_PKG" \ - --apple-id "$APPLE_DEV_EMAIL" \ - --team-id "$MAC_TEAM_ID" \ - --password "$APPLE_DEV_PASSWORD" \ - --wait - - echo "Stapling ticket..." - xcrun stapler staple "$FINAL_PKG" - xcrun stapler validate "$FINAL_PKG" + if [ "${NOTARIZE_APP+x}" ]; then + echo "Notarizing installer bundle..." + /usr/bin/ditto -c -k --keepParent $INSTALLER_BUNDLE_DIR $PROJECT_DIR/Installer_bundle_to_notarize.zip + xcrun notarytool submit $PROJECT_DIR/Installer_bundle_to_notarize.zip --apple-id $APPLE_DEV_EMAIL --team-id $MAC_TEAM_ID --password $APPLE_DEV_PASSWORD + rm $PROJECT_DIR/Installer_bundle_to_notarize.zip + sleep 300 + xcrun stapler staple $INSTALLER_BUNDLE_DIR + xcrun stapler validate $INSTALLER_BUNDLE_DIR + spctl -a -vvvv $INSTALLER_BUNDLE_DIR || true + fi fi -if [ "${MAC_INSTALL_CERT_PW+x}" ]; then - /usr/bin/codesign --verify -vvvv "$FINAL_PKG" || true - spctl -a -vvvv "$FINAL_PKG" || true +echo "Building DMG installer..." +# Allow Terminal to make changes in Privacy & Security > App Management +hdiutil create -size 256mb -volname AmneziaVPN -srcfolder $BUILD_DIR/installer/$APP_NAME.app -ov -format UDZO $DMG_FILENAME + +if [ "${MAC_CERT_PW+x}" ]; then + echo "Signing DMG installer..." + security unlock-keychain -p $TEMP_PASS $KEYCHAIN + /usr/bin/codesign --deep --force --verbose --timestamp -o runtime --sign "$MAC_SIGNER_ID" $DMG_FILENAME + /usr/bin/codesign --verify -vvvv $DMG_FILENAME || true + + if [ "${NOTARIZE_APP+x}" ]; then + echo "Notarizing DMG installer..." + xcrun notarytool submit $DMG_FILENAME --apple-id $APPLE_DEV_EMAIL --team-id $MAC_TEAM_ID --password $APPLE_DEV_PASSWORD + sleep 300 + xcrun stapler staple $DMG_FILENAME + xcrun stapler validate $DMG_FILENAME + fi fi -# Sign app bundle -/usr/bin/codesign --deep --force --verbose --timestamp -o runtime --keychain "$KEYCHAIN_PATH" --sign "$MAC_SIGNER_ID" "$BUNDLE_DIR" -spctl -a -vvvv "$BUNDLE_DIR" || true +echo "Finished, artifact is $DMG_FILENAME" -# Restore login keychain as the only user keychain and delete the temporary keychain -KEYCHAIN="$HOME/Library/Keychains/login.keychain-db" -security list-keychains -d user -s "$KEYCHAIN" -security delete-keychain "$KEYCHAIN_PATH" - -echo "Finished, artifact is $FINAL_PKG" +# restore keychain +security default-keychain -s login.keychain diff --git a/deploy/build_macos_ne.sh b/deploy/build_macos_ne.sh new file mode 100755 index 00000000..fd3e0b74 --- /dev/null +++ b/deploy/build_macos_ne.sh @@ -0,0 +1,122 @@ +#!/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..." + +# Copy provisioning prifiles +mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles/" + +echo $MAC_APP_PROVISIONING_PROFILE | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision +echo $MAC_NE_PROVISIONING_PROFILE | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision + +shasum -a 256 ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision +shasum -a 256 ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision + +profile_uuid=`grep UUID -A1 -a ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision | grep -io "[-A-F0-9]\{36\}"` +echo $profile_uuid +profile_ne_uuid=`grep UUID -A1 -a ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision | grep -io "[-A-F0-9]\{36\}"` +echo $profile_ne_uuid + +mv ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/$profile_uuid.mobileprovision +mv ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/$profile_ne_uuid.mobileprovision + +# 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 -DDEPLOY=ON + +# Build and run tests here + +echo "____________________________________" +echo "............Deploying..............." +echo "____________________________________" +echo "Deploying MAC Network Extension App..." + +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 + + +# 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/data/macos/check_install.sh b/deploy/data/macos/check_install.sh deleted file mode 100755 index adf63550..00000000 --- a/deploy/data/macos/check_install.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -if [ -d "/Applications/AmneziaVPN.app" ] || pgrep -x "AmneziaVPN-service" >/dev/null; then - exit 1 -fi -exit 0 diff --git a/deploy/data/macos/check_uninstall.sh b/deploy/data/macos/check_uninstall.sh deleted file mode 100755 index e7a6f7e0..00000000 --- a/deploy/data/macos/check_uninstall.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -if [ -d "/Applications/AmneziaVPN.app" ] || pgrep -x "AmneziaVPN-service" >/dev/null; then - exit 0 -fi -exit 1 diff --git a/deploy/data/macos/distribution.xml b/deploy/data/macos/distribution.xml deleted file mode 100644 index c0a1dc68..00000000 --- a/deploy/data/macos/distribution.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - AmneziaVPN Installer - - - - - - - - - - - - AmneziaVPN_install.pkg - AmneziaVPN_uninstall_component.pkg - diff --git a/deploy/data/macos/distribution_uninstall.xml b/deploy/data/macos/distribution_uninstall.xml deleted file mode 100644 index cf8932b9..00000000 --- a/deploy/data/macos/distribution_uninstall.xml +++ /dev/null @@ -1,13 +0,0 @@ - - Uninstall AmneziaVPN - - - - - - - - - - AmneziaVPN_uninstall_component.pkg - diff --git a/deploy/data/macos/post_install.sh b/deploy/data/macos/post_install.sh index 053c8e13..acd3f93f 100755 --- a/deploy/data/macos/post_install.sh +++ b/deploy/data/macos/post_install.sh @@ -7,42 +7,29 @@ LOG_FOLDER=/var/log/$APP_NAME LOG_FILE="$LOG_FOLDER/post-install.log" APP_PATH=/Applications/$APP_NAME.app -# Handle new installations unpacked into localized folder -if [ -d "/Applications/${APP_NAME}.localized" ]; then - echo "`date` Detected ${APP_NAME}.localized, migrating to standard path" >> $LOG_FILE - sudo rm -rf "$APP_PATH" - sudo mv "/Applications/${APP_NAME}.localized/${APP_NAME}.app" "$APP_PATH" - sudo rm -rf "/Applications/${APP_NAME}.localized" -fi - if launchctl list "$APP_NAME-service" &> /dev/null; then - launchctl unload "$LAUNCH_DAEMONS_PLIST_NAME" - rm -f "$LAUNCH_DAEMONS_PLIST_NAME" + launchctl unload $LAUNCH_DAEMONS_PLIST_NAME + rm -f $LAUNCH_DAEMONS_PLIST_NAME fi -sudo chmod -R a-w "$APP_PATH/" -sudo chown -R root "$APP_PATH/" -sudo chgrp -R wheel "$APP_PATH/" +tar xzf $APP_PATH/$APP_NAME.tar.gz -C $APP_PATH +rm -f $APP_PATH/$APP_NAME.tar.gz +sudo chmod -R a-w $APP_PATH/ +sudo chown -R root $APP_PATH/ +sudo chgrp -R wheel $APP_PATH/ rm -rf $LOG_FOLDER mkdir -p $LOG_FOLDER echo "`date` Script started" > $LOG_FILE -echo "Requesting ${APP_NAME} to quit gracefully" >> "$LOG_FILE" -osascript -e 'tell application "AmneziaVPN" to quit' +killall -9 $APP_NAME-service 2>> $LOG_FILE -PLIST_SOURCE="$APP_PATH/Contents/Resources/$PLIST_NAME" -if [ -f "$PLIST_SOURCE" ]; then - mv -f "$PLIST_SOURCE" "$LAUNCH_DAEMONS_PLIST_NAME" 2>> $LOG_FILE -else - echo "`date` ERROR: service plist not found at $PLIST_SOURCE" >> $LOG_FILE -fi - -chown root:wheel "$LAUNCH_DAEMONS_PLIST_NAME" -launchctl load "$LAUNCH_DAEMONS_PLIST_NAME" -echo "`date` Launching ${APP_NAME} application" >> $LOG_FILE -open -a "$APP_PATH" 2>> $LOG_FILE || true +mv -f $APP_PATH/$PLIST_NAME $LAUNCH_DAEMONS_PLIST_NAME 2>> $LOG_FILE +chown root:wheel $LAUNCH_DAEMONS_PLIST_NAME +launchctl load $LAUNCH_DAEMONS_PLIST_NAME echo "`date` Service status: $?" >> $LOG_FILE echo "`date` Script finished" >> $LOG_FILE + +#rm -- "$0" diff --git a/deploy/data/macos/post_uninstall.sh b/deploy/data/macos/post_uninstall.sh index d6c5cdbd..de7846db 100755 --- a/deploy/data/macos/post_uninstall.sh +++ b/deploy/data/macos/post_uninstall.sh @@ -9,19 +9,6 @@ SYSTEM_APP_SUPPORT="/Library/Application Support/$APP_NAME" LOG_FOLDER="/var/log/$APP_NAME" CACHES_FOLDER="$HOME/Library/Caches/$APP_NAME" -# Attempt to quit the GUI application if it's currently running -if pgrep -x "$APP_NAME" > /dev/null; then - echo "Quitting $APP_NAME..." - osascript -e 'tell application "'"$APP_NAME"'" to quit' || true - # Wait up to 10 seconds for the app to terminate gracefully - for i in {1..10}; do - if ! pgrep -x "$APP_NAME" > /dev/null; then - break - fi - sleep 1 - done -fi - # Stop the running service if it exists if pgrep -x "${APP_NAME}-service" > /dev/null; then sudo killall -9 "${APP_NAME}-service" @@ -45,40 +32,3 @@ sudo rm -rf "$LOG_FOLDER" # Remove any caches left behind rm -rf "$CACHES_FOLDER" - -# Remove PF data directory created by firewall helper, if present -sudo rm -rf "/Library/Application Support/${APP_NAME}/pf" - -# ---------------- PF firewall cleanup ---------------------- -# Rules are loaded under the anchor "amn" (see macosfirewall.cpp) -# Flush only that anchor to avoid destroying user/system rules. - -PF_ANCHOR="amn" - -### Flush all PF rules, NATs, and tables under our anchor and sub-anchors ### -anchors=$(sudo pfctl -s Anchors 2>/dev/null | awk '/^'"${PF_ANCHOR}"'/ {sub(/\*$/, "", $1); print $1}') -for anc in $anchors; do - echo "Flushing PF anchor $anc" - sudo pfctl -a "$anc" -F all 2>/dev/null || true - # flush tables under this anchor - tables=$(sudo pfctl -s Tables 2>/dev/null | awk '/^'"$anc"'/ {print}') - for tbl in $tables; do - echo "Killing PF table $tbl" - sudo pfctl -t "$tbl" -T kill 2>/dev/null || true - done -done - -### Reload default PF config to restore system rules ### -if [ -f /etc/pf.conf ]; then - echo "Restoring system PF config" - sudo pfctl -f /etc/pf.conf 2>/dev/null || true -fi - -### Disable PF if no rules remain ### -if sudo pfctl -s info 2>/dev/null | grep -q '^Status: Enabled' && \ - ! sudo pfctl -sr 2>/dev/null | grep -q .; then - echo "Disabling PF" - sudo pfctl -d 2>/dev/null || true -fi - -# ----------------------------------------------------------- diff --git a/deploy/data/macos/uninstall_conclusion.html b/deploy/data/macos/uninstall_conclusion.html deleted file mode 100644 index f5b8bb63..00000000 --- a/deploy/data/macos/uninstall_conclusion.html +++ /dev/null @@ -1,7 +0,0 @@ - -Uninstall Complete - -

AmneziaVPN has been uninstalled

-

Thank you for using AmneziaVPN. The application and its components have been removed.

- - \ No newline at end of file diff --git a/deploy/data/macos/uninstall_welcome.html b/deploy/data/macos/uninstall_welcome.html deleted file mode 100644 index 9f3d97cb..00000000 --- a/deploy/data/macos/uninstall_welcome.html +++ /dev/null @@ -1,7 +0,0 @@ - -Uninstall AmneziaVPN - -

Uninstall AmneziaVPN

-

This process will remove AmneziaVPN from your system. Click Continue to proceed.

- - \ No newline at end of file diff --git a/deploy/deploy_s3.sh b/deploy/deploy_s3.sh index a139a5a5..c109a286 100755 --- a/deploy/deploy_s3.sh +++ b/deploy/deploy_s3.sh @@ -28,10 +28,10 @@ wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSIO wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_armeabi-v7a.apk wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_x86.apk wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_x86_64.apk -wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_linux_x64.tar.zip +wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_linux.tar.zip wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_macos.dmg wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_macos_old.dmg -wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_windows_x64.exe +wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_x64.exe cd ../ diff --git a/deploy/installer/config.cmake b/deploy/installer/config.cmake index 3c33a33c..13f09986 100644 --- a/deploy/installer/config.cmake +++ b/deploy/installer/config.cmake @@ -4,6 +4,11 @@ if(WIN32) ${CMAKE_CURRENT_LIST_DIR}/config/windows.xml.in ${CMAKE_BINARY_DIR}/installer/config/windows.xml ) +elseif(APPLE AND NOT IOS) + configure_file( + ${CMAKE_CURRENT_LIST_DIR}/config/macos.xml.in + ${CMAKE_BINARY_DIR}/installer/config/macos.xml + ) elseif(LINUX) set(ApplicationsDir "@ApplicationsDir@") configure_file( diff --git a/deploy/installer/config/AmneziaVPN.desktop.in b/deploy/installer/config/AmneziaVPN.desktop.in index 03ab570c..2a53074e 100755 --- a/deploy/installer/config/AmneziaVPN.desktop.in +++ b/deploy/installer/config/AmneziaVPN.desktop.in @@ -2,7 +2,7 @@ [Desktop Entry] Type=Application Name=AmneziaVPN -Version=1.0 +Version=@CMAKE_PROJECT_VERSION@ Comment=Client of your self-hosted VPN Exec=AmneziaVPN Icon=/usr/share/pixmaps/AmneziaVPN.png diff --git a/deploy/installer/config/macos.xml.in b/deploy/installer/config/macos.xml.in new file mode 100644 index 00000000..3888d08d --- /dev/null +++ b/deploy/installer/config/macos.xml.in @@ -0,0 +1,27 @@ + + + AmneziaVPN + @CMAKE_PROJECT_VERSION@ + AmneziaVPN + AmneziaVPN + AmneziaVPN + /Applications/AmneziaVPN.app + 600 + 380 + Mac + true + true + false + controlscript.js + false + true + false + true + + + https://amneziavpn.org/updates/macos + true + AmneziaVPN - repository for macOS + + + 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() diff --git a/service/server/killswitch.cpp b/service/server/killswitch.cpp index d0cba03a..c44bd6a2 100644 --- a/service/server/killswitch.cpp +++ b/service/server/killswitch.cpp @@ -192,14 +192,7 @@ bool KillSwitch::addAllowedRange(const QStringList &ranges) { bool KillSwitch::enablePeerTraffic(const QJsonObject &configStr) { #ifdef Q_OS_WIN InterfaceConfig config; - - config.m_primaryDnsServer = configStr.value(amnezia::config_key::dns1).toString(); - - // We don't use secondary DNS if primary DNS is AmneziaDNS - if (!config.m_primaryDnsServer.contains(amnezia::protocols::dns::amneziaDnsIp)) { - config.m_secondaryDnsServer = configStr.value(amnezia::config_key::dns2).toString(); - } - + config.m_dnsServer = configStr.value(amnezia::config_key::dns1).toString(); config.m_serverPublicKey = "openvpn"; config.m_serverIpv4Gateway = configStr.value("vpnGateway").toString(); config.m_serverIpv4AddrIn = configStr.value("vpnServer").toString(); @@ -262,9 +255,6 @@ bool KillSwitch::enablePeerTraffic(const QJsonObject &configStr) { bool KillSwitch::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIndex) { #ifdef Q_OS_WIN - if (configStr.value("splitTunnelType").toInt() != 0) { - WindowsFirewall::create(this)->allowAllTraffic(); - } return WindowsFirewall::create(this)->enableInterface(vpnAdapterIndex); #endif @@ -314,14 +304,8 @@ bool KillSwitch::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIn LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("300.allowLAN"), true); LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("310.blockDNS"), true); QStringList dnsServers; - dnsServers.append(configStr.value(amnezia::config_key::dns1).toString()); - - // We don't use secondary DNS if primary DNS is AmneziaDNS - if (!configStr.value(amnezia::config_key::dns1).toString().contains(amnezia::protocols::dns::amneziaDnsIp)) { - dnsServers.append(configStr.value(amnezia::config_key::dns2).toString()); - } - + dnsServers.append(configStr.value(amnezia::config_key::dns2).toString()); dnsServers.append("127.0.0.1"); dnsServers.append("127.0.0.53"); @@ -358,11 +342,7 @@ bool KillSwitch::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIn QStringList dnsServers; dnsServers.append(configStr.value(amnezia::config_key::dns1).toString()); - - // We don't use secondary DNS if primary DNS is AmneziaDNS - if (!configStr.value(amnezia::config_key::dns1).toString().contains(amnezia::protocols::dns::amneziaDnsIp)) { - dnsServers.append(configStr.value(amnezia::config_key::dns2).toString()); - } + dnsServers.append(configStr.value(amnezia::config_key::dns2).toString()); for (auto dns : configStr.value(amnezia::config_key::allowedDnsServers).toArray()) { if (!dns.isString()) {