Compare commits

..

14 Commits

Author SHA1 Message Date
Pokamest Nikak
aab275cacd Fix for linux sleep reconnect 2026-08-21 14:17:55 +01:00
NickVs2015
b66e3def09 fix: resolve deadlock filewrite and remove qml ApplicationActive event 2026-08-18 09:49:33 +03:00
NickVs2015
39a652df5b fix: QRingBuffer corruption under concurrent logging 2026-08-18 09:49:27 +03:00
NickVs2015
542ae60d27 fix: add log systemWoke received 2026-08-18 09:44:09 +03:00
NickVs2015
87d90ee92f fix: recover from stuck busy-indicator/disabled-controls on real OS wakeup (Windows/Linux) 2026-08-18 09:44:04 +03:00
NickVs2015
d906df6927 fix: prevent double WireGuard stop and fix NM sleep/wake 2026-08-18 09:43:53 +03:00
NickVs2015
9a472c6793 fix: bad rule xargs, cgroup v2 mkdir, amnvpnrt rt_tables, restart flush 2026-08-06 19:33:37 +03:00
NickVs2015
9bf974a2f4 fix: amnvpnrt flush error 2026-08-06 16:42:19 +03:00
NickVs2015
46100fd311 fix: make Linux DNS retry setup 2026-08-06 15:16:29 +03:00
NickVs2015
34b62f8fd6 fix: replace m_linkDefaultRoutes map with single m_gatewayIfindex
fix: solve infinite reconnect NM down
2026-08-06 14:46:01 +03:00
NickVs2015
b8e9ec8570 fix: killswitch compatible 2026-08-06 14:01:24 +03:00
NickVs2015
c35988d79f fix: NM down/up reconnection problem 2026-08-06 14:01:24 +03:00
NickVs2015
410538c6b2 fix: dns rewrites and flush 2026-08-06 14:01:24 +03:00
NickVs2015
cc71330c27 fix: make dbus async 2026-08-06 14:01:24 +03:00
155 changed files with 21144 additions and 47788 deletions

View File

@@ -745,37 +745,11 @@ jobs:
needs: Bake-Prebuilts-Android
if: ${{ always() }}
strategy:
fail-fast: false
matrix:
include:
- label: 'android9-10'
qt_version: '6.10.1'
min_sdk: 28
max_sdk: 29
version_code_offset: 0
build_aab: true
- label: 'android11+'
qt_version: '6.10.3'
min_sdk: 30
max_sdk: ''
version_code_offset: 1
build_aab: true
- label: 'android9-10-qt610-3'
qt_version: '6.10.3'
min_sdk: 28
max_sdk: 29
version_code_offset: 0
build_aab: false
env:
ANDROID_PLATFORM: android-${{ matrix.min_sdk }}
ANDROID_PLATFORM: android-28
NDK_VERSION: 27.0.11718014
QT_VERSION: ${{ matrix.qt_version }}
QT_VERSION: 6.10.3
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
APP_ANDROID_MIN_SDK: ${{ matrix.min_sdk }}
APP_ANDROID_MAX_SDK: ${{ matrix.max_sdk }}
APP_ANDROID_VERSION_CODE_OFFSET: ${{ matrix.version_code_offset }}
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
FALLBACK_S3_ENDPOINT: ${{ secrets.FALLBACK_S3_ENDPOINT }}
@@ -883,82 +857,62 @@ jobs:
QT_ANDROID_KEYSTORE_PATH: ${{ github.workspace }}/android.keystore
QT_ANDROID_KEYSTORE_ALIAS: ${{ secrets.ANDROID_RELEASE_KEYSTORE_KEY_ALIAS }}
QT_ANDROID_KEYSTORE_STORE_PASS: ${{ secrets.ANDROID_RELEASE_KEYSTORE_KEY_PASS }}
LABEL: ${{ matrix.label }}
BUILD_AAB: ${{ matrix.build_aab }}
shell: bash
run: |
OUT=deploy/artifacts
rm -rf $OUT && mkdir -p $OUT
if [[ "$BUILD_AAB" == "true" ]]; then
deploy/build.sh -t android --sign --aab
else
deploy/build.sh -t android --sign
fi
deploy/build.sh -t android --sign --aab
VERSION=$(grep CMAKE_PROJECT_VERSION:STATIC deploy/build/CMakeCache.txt | cut -d= -f2)
mv deploy/build/client/android-build/AmneziaVPN.apk \
$OUT/AmneziaVPN_${VERSION}_${LABEL}_universal.apk
if [[ "$BUILD_AAB" == "true" ]]; then
mv deploy/build/client/android-build/build/outputs/bundle/release/android-build-release.aab \
$OUT/AmneziaVPN_${VERSION}_${LABEL}.aab
fi
(cd deploy/build/client/android-build && mv AmneziaVPN.apk AmneziaVPN_${VERSION}_android9+_universal.apk)
(cd deploy/build/client/android-build/build/outputs/bundle/release && mv android-build-release.aab AmneziaVPN_${VERSION}.aab)
for abi in arm64-v8a armeabi-v7a x86 x86_64; do
deploy/build.sh -t android --sign --abi ${abi} --build ./deploy/build/${abi}
mv deploy/build/${abi}/client/android-build/AmneziaVPN.apk \
$OUT/AmneziaVPN_${VERSION}_${LABEL}_${abi}.apk
(cd deploy/build/${abi}/client/android-build && mv AmneziaVPN.apk AmneziaVPN_${VERSION}_android9+_${abi}.apk)
done
ls -l $OUT
- name: 'Upload universal APK'
uses: actions/upload-artifact@v7
with:
path: deploy/artifacts/*_universal.apk
path: deploy/build/client/android-build/*.apk
archive: false
retention-days: 7
- name: 'Upload AAB'
uses: actions/upload-artifact@v7
with:
path: deploy/build/client/android-build/build/outputs/bundle/release/*.aab
archive: false
retention-days: 7
- name: 'Upload arm64-v8a APK'
uses: actions/upload-artifact@v7
with:
path: deploy/artifacts/*_arm64-v8a.apk
path: deploy/build/arm64-v8a/client/android-build/*.apk
archive: false
retention-days: 7
- name: 'Upload armeabi-v7a APK'
uses: actions/upload-artifact@v7
with:
path: deploy/artifacts/*_armeabi-v7a.apk
path: deploy/build/armeabi-v7a/client/android-build/*.apk
archive: false
retention-days: 7
- name: 'Upload x86 APK'
uses: actions/upload-artifact@v7
with:
path: deploy/artifacts/*_x86.apk
path: deploy/build/x86/client/android-build/*.apk
archive: false
retention-days: 7
- name: 'Upload x86_64 APK'
uses: actions/upload-artifact@v7
with:
path: deploy/artifacts/*_x86_64.apk
path: deploy/build/x86_64/client/android-build/*.apk
archive: false
retention-days: 7
- name: 'Upload AAB'
if: ${{ matrix.build_aab }}
uses: actions/upload-artifact@v7
with:
path: deploy/artifacts/*.aab
archive: false
retention-days: 7
# ------------------------------------------------------
Extra:
runs-on: ubuntu-latest
steps:

View File

@@ -4,9 +4,7 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(PROJECT AmneziaVPN)
if(NOT AMNEZIAVPN_VERSION)
set(AMNEZIAVPN_VERSION 5.0.1.5 CACHE STRING "Client app version")
endif()
set(AMNEZIAVPN_VERSION 5.0.1.0)
set(QT_CREATOR_SKIP_PACKAGE_MANAGER_SETUP ON CACHE BOOL "" FORCE)
set(CMAKE_PROJECT_TOP_LEVEL_INCLUDES
@@ -30,12 +28,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})
# bump by 2 on every release, because we're releasing two versions on the play store
set(APP_ANDROID_VERSION_CODE 2152)
if(DEFINED APP_ANDROID_VERSION_CODE_OFFSET)
math(EXPR APP_ANDROID_VERSION_CODE "${APP_ANDROID_VERSION_CODE} + ${APP_ANDROID_VERSION_CODE_OFFSET}")
endif()
set(APP_ANDROID_VERSION_CODE 2141)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
@@ -61,14 +54,14 @@ if(APPLE AND NOT IOS)
endif()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/deploy/data/pf-templates/amn.400.allowPIA.conf.in"
"${CMAKE_SOURCE_DIR}/deploy/data/pf-templates/amn.400.allowPIA.conf.in"
"${CMAKE_CURRENT_BINARY_DIR}/amn.400.allowPIA.conf"
@ONLY
)
file(COPY_FILE
"${CMAKE_CURRENT_BINARY_DIR}/amn.400.allowPIA.conf"
"${CMAKE_CURRENT_SOURCE_DIR}/deploy/data/macos/pf/amn.400.allowPIA.conf"
"${CMAKE_SOURCE_DIR}/deploy/data/macos/pf/amn.400.allowPIA.conf"
ONLY_IF_DIFFERENT
)
endif()

View File

@@ -1,8 +1,6 @@
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/clientBrandingDefaults.cmake)
set(PROJECT ${CLIENT_TARGET_NAME})
set(PROJECT AmneziaVPN)
project(${PROJECT})
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
@@ -59,9 +57,6 @@ qt_add_executable(${PROJECT} MANUAL_FINALIZATION)
target_include_directories(${PROJECT} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
)
target_compile_definitions(${PROJECT} PRIVATE
CLIENT_KEYCHAIN_NAME_STR=\"${CLIENT_KEYCHAIN_NAME}\"
)
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep)
@@ -72,34 +67,24 @@ qt6_add_resources(QRC ${QRC}
${CMAKE_CURRENT_LIST_DIR}/images/images.qrc
${CMAKE_CURRENT_LIST_DIR}/images/flagKit.qrc
${CMAKE_CURRENT_LIST_DIR}/client_scripts/clientScripts.qrc
${CLIENT_QML_QRC_FILE}
${CMAKE_CURRENT_LIST_DIR}/ui/qml/qml.qrc
${CMAKE_CURRENT_LIST_DIR}/server_scripts/serverScripts.qrc
${CLIENT_EXTRA_QRC}
)
# -- i18n begin
if(CLIENT_TS_FILES)
set(AMNEZIAVPN_TS_FILES ${CLIENT_TS_FILES})
else()
set(AMNEZIAVPN_TS_FILES
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_ru_RU.ts
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_zh_CN.ts
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_fa_IR.ts
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_ar_EG.ts
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_my_MM.ts
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_uk_UA.ts
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_ur_PK.ts
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_hi_IN.ts
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_es_ES.ts
${CMAKE_CURRENT_LIST_DIR}/translations/${CLIENT_TS_PREFIX}_ko_KR.ts
)
endif()
file(GLOB_RECURSE AMNEZIAVPN_QML_FILES ${CMAKE_CURRENT_LIST_DIR}/ui/qml/*.qml)
set(AMNEZIAVPN_TS_FILES
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru_RU.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_zh_CN.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_fa_IR.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ar_EG.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_my_MM.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_uk_UA.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ur_PK.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_hi_IN.ts
)
qt6_add_translations(${PROJECT}
TS_FILES ${AMNEZIAVPN_TS_FILES}
SOURCES ${AMNEZIAVPN_QML_FILES}
RESOURCE_PREFIX "/translations"
)
# -- i18n end
@@ -116,18 +101,13 @@ endif()
include(${CMAKE_CURRENT_LIST_DIR}/cmake/3rdparty.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/sources.cmake)
set(_client_include_dirs
include_directories(
${CMAKE_CURRENT_LIST_DIR}/../ipc
${CMAKE_CURRENT_LIST_DIR}/../common/logger
${CMAKE_CURRENT_LIST_DIR}/../common/crypto
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
if(CLIENT_BRANDING_INCLUDE_DIR)
list(APPEND _client_include_dirs ${CLIENT_BRANDING_INCLUDE_DIR})
endif()
list(APPEND _client_include_dirs ${CMAKE_CURRENT_LIST_DIR})
include_directories(${_client_include_dirs})
if(MACOS_NE)
message("MACOS_NE is ON")
@@ -143,26 +123,6 @@ include_directories(mozilla/shared)
include_directories(mozilla/models)
configure_file(${CMAKE_CURRENT_LIST_DIR}/../version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/core/utils)
configure_file(
${CMAKE_CURRENT_LIST_DIR}/core/utils/appUiConfig.h.in
${CMAKE_CURRENT_BINARY_DIR}/core/utils/appUiConfig.h
@ONLY
)
configure_file(
${CMAKE_CURRENT_LIST_DIR}/core/utils/swiftBridgeConfig.h.in
${CMAKE_CURRENT_BINARY_DIR}/core/utils/swiftBridgeConfig.h
@ONLY
)
# Swift can't consume a `-DGROUP_ID="value"` compile define (Swift -D flags are
# presence-only), unlike the Objective-C++ sources that read GROUP_ID directly.
# Generate a Swift constant instead so Log.swift can use the branded app group.
set(CLIENT_GROUP_IDENTIFIER_SWIFT_FILE ${CMAKE_CURRENT_BINARY_DIR}/platforms/ios/GroupIdentifier.swift)
configure_file(
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/GroupIdentifier.swift.in
${CLIENT_GROUP_IDENTIFIER_SWIFT_FILE}
@ONLY
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(${PROJECT} PRIVATE "MZ_DEBUG")
@@ -190,6 +150,18 @@ if(APPLE)
cmake_policy(SET CMP0099 NEW)
cmake_policy(SET CMP0114 NEW)
if(NOT BUILD_OSX_APP_IDENTIFIER)
set(BUILD_OSX_APP_IDENTIFIER org.amnezia.AmneziaVPN CACHE STRING "OSX Application identifier")
endif()
if(NOT BUILD_IOS_APP_IDENTIFIER)
set(BUILD_IOS_APP_IDENTIFIER org.amnezia.AmneziaVPN CACHE STRING "iOS Application identifier")
endif()
if(NOT BUILD_IOS_GROUP_IDENTIFIER)
set(BUILD_IOS_GROUP_IDENTIFIER group.org.amnezia.AmneziaVPN CACHE STRING "iOS Group identifier")
endif()
if(NOT BUILD_VPN_DEVELOPMENT_TEAM)
set(BUILD_VPN_DEVELOPMENT_TEAM X7UJ388FXK CACHE STRING "Amnezia VPN Development Team")
endif()
set(CMAKE_XCODE_GENERATE_SCHEME FALSE)
set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${BUILD_VPN_DEVELOPMENT_TEAM})

View File

@@ -24,7 +24,6 @@
#include "ui/models/installedAppsModel.h"
#include "ui/utils/mtProxyPublicHostInput.h"
#include "version.h"
#include "core/utils/appUiConfig.h"
#include "platforms/ios/QRCodeReaderBase.h"
#ifdef Q_OS_IOS
@@ -103,7 +102,7 @@ void AmneziaApplication::init()
{
m_engine = new QQmlApplicationEngine;
const QUrl url(QStringLiteral(APP_QML_ENTRYPOINT));
const QUrl url(QStringLiteral("qrc:/ui/qml/main2.qml"));
QObject::connect(
m_engine, &QQmlApplicationEngine::objectCreated, this,
[this, url](QObject *obj, const QUrl &objUrl) {
@@ -156,7 +155,7 @@ void AmneziaApplication::init()
m_marketplaceUpdateController.reset(new MarketplaceUpdateController());
m_marketplaceUpdateController->start();
m_engine->addImportPath(QStringLiteral(APP_QML_IMPORT_PATH));
m_engine->addImportPath("qrc:/ui/qml/Modules/");
if (m_parser.isSet(m_optImport)) {
const QString data = m_parser.value(m_optImport);
@@ -245,7 +244,7 @@ void AmneziaApplication::loadFonts()
{
QQuickStyle::setStyle("Basic");
QFontDatabase::addApplicationFont(QStringLiteral(APP_UI_FONT_RESOURCE));
QFontDatabase::addApplicationFont(":/fonts/pt-root-ui_vf.ttf");
}
bool AmneziaApplication::parseCommands()
@@ -272,7 +271,7 @@ bool AmneziaApplication::parseCommands()
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
void AmneziaApplication::startLocalServer() {
const QString serverName(APP_INSTANCE_NAME);
const QString serverName("AmneziaVPNInstance");
QLocalServer::removeServer(serverName);
QLocalServer *server = new QLocalServer(this);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -148,10 +148,6 @@ open class Wireguard : Protocol() {
?.let { setKeepaliveTimeout(it) }
configData.optStringOrNull("MaxHandshakeAttempts")?.trim()?.takeIf { it.isNotEmpty() }
?.let { setMaxHandshakeAttempts(it) }
configData.optStringOrNull("RandomTrailers")?.trim()?.takeIf { it.isNotEmpty() }
?.let { setRandomTrailers(it) }
configData.optStringOrNull("DisableCookies")?.trim()?.takeIf { it.isNotEmpty() }
?.let { setDisableCookies(it) }
}
private fun start(

View File

@@ -38,8 +38,6 @@ open class WireguardConfig protected constructor(
val rejectAfterTime: String?,
val keepaliveTimeout: String?,
val maxHandshakeAttempts: String?,
val randomTrailers: String?,
val disableCookies: String?,
) : ProtocolConfig(protocolConfigBuilder) {
protected constructor(builder: Builder) : this(
@@ -73,8 +71,6 @@ open class WireguardConfig protected constructor(
builder.rejectAfterTime,
builder.keepaliveTimeout,
builder.maxHandshakeAttempts,
builder.randomTrailers,
builder.disableCookies,
)
fun toWgUserspaceString(): String = with(StringBuilder()) {
@@ -112,8 +108,6 @@ open class WireguardConfig protected constructor(
rejectAfterTime?.takeIf { it.isNotEmpty() }?.let { appendLine("reject_after_time=$it") }
keepaliveTimeout?.takeIf { it.isNotEmpty() }?.let { appendLine("keepalive_timeout=$it") }
maxHandshakeAttempts?.takeIf { it.isNotEmpty() }?.let { appendLine("max_handshake_attempts=$it") }
randomTrailers?.takeIf { it.isNotEmpty() }?.let { appendLine("random_trailers=${it.toUapiBool()}") }
disableCookies?.takeIf { it.isNotEmpty() }?.let { appendLine("disable_cookies=${it.toUapiBool()}") }
}
private fun validateProtocolExtensionParameters() {
@@ -183,8 +177,6 @@ open class WireguardConfig protected constructor(
internal var rejectAfterTime: String? = null
internal var keepaliveTimeout: String? = null
internal var maxHandshakeAttempts: String? = null
internal var randomTrailers: String? = null
internal var disableCookies: String? = null
fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint }
@@ -221,8 +213,6 @@ open class WireguardConfig protected constructor(
fun setRejectAfterTime(rejectAfterTime: String) = apply { this.rejectAfterTime = rejectAfterTime }
fun setKeepaliveTimeout(keepaliveTimeout: String) = apply { this.keepaliveTimeout = keepaliveTimeout }
fun setMaxHandshakeAttempts(maxHandshakeAttempts: String) = apply { this.maxHandshakeAttempts = maxHandshakeAttempts }
fun setRandomTrailers(randomTrailers: String) = apply { this.randomTrailers = randomTrailers }
fun setDisableCookies(disableCookies: String) = apply { this.disableCookies = disableCookies }
override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) }
}
@@ -234,9 +224,3 @@ open class WireguardConfig protected constructor(
@OptIn(ExperimentalStdlibApi::class)
internal fun String.base64ToHex(): String = Base64.decode(this, Base64.DEFAULT).toHexString()
/** Converts awg-quick on/off (and 0/1/true/false) to UAPI 1/0 for amneziawg-go ParseBool. */
internal fun String.toUapiBool(): String = when (trim().lowercase()) {
"on", "1", "true", "t", "yes" -> "1"
else -> "0"
}

View File

@@ -1,8 +1,6 @@
message("Client android ${CMAKE_ANDROID_ARCH_ABI} build")
if(NOT DEFINED APP_ANDROID_MIN_SDK)
set(APP_ANDROID_MIN_SDK 28)
endif()
set(APP_ANDROID_MIN_SDK 28)
set(ANDROID_PLATFORM "android-${APP_ANDROID_MIN_SDK}" CACHE STRING
"The minimum API level supported by the application or library" FORCE)
@@ -15,6 +13,7 @@ set_target_properties(${PROJECT} PROPERTIES
QT_ANDROID_MIN_SDK_VERSION ${APP_ANDROID_MIN_SDK}
QT_ANDROID_TARGET_SDK_VERSION 36
QT_ANDROID_SDK_BUILD_TOOLS_REVISION 36.0.0
QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android
)
set(QT_ANDROID_MULTI_ABI_FORWARD_VARS "QT_NO_GLOBAL_APK_TARGET_PART_OF_ALL;CMAKE_BUILD_TYPE")
@@ -54,27 +53,3 @@ file(COPY ${AMNEZIA_LIBXRAY_PATH} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/androi
find_package(openvpn-pt-android REQUIRED)
set(LIBS ${LIBS} amnezia::openvpn-pt-android)
set_property(TARGET ${PROJECT} APPEND PROPERTY QT_ANDROID_EXTRA_LIBS ${OPENVPN_PT_ANDROID_LIBCK_OVPN_PLUGIN_PATH})
set(APP_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android)
if(APP_ANDROID_MAX_SDK)
set(APP_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/android-package-source)
file(REMOVE_RECURSE ${APP_ANDROID_PACKAGE_SOURCE_DIR})
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/android/ DESTINATION ${APP_ANDROID_PACKAGE_SOURCE_DIR})
set(manifest_path ${APP_ANDROID_PACKAGE_SOURCE_DIR}/AndroidManifest.xml)
set(manifest_anchor "android:installLocation=\"auto\">")
file(READ ${manifest_path} manifest_contents)
string(REPLACE
"${manifest_anchor}"
"${manifest_anchor}\n\n <uses-sdk android:maxSdkVersion=\"${APP_ANDROID_MAX_SDK}\" />"
patched_contents "${manifest_contents}")
if(patched_contents STREQUAL manifest_contents)
message(FATAL_ERROR
"Failed to set maxSdkVersion=${APP_ANDROID_MAX_SDK}: anchor '${manifest_anchor}' "
"not found in ${CMAKE_CURRENT_SOURCE_DIR}/android/AndroidManifest.xml")
endif()
file(WRITE ${manifest_path} "${patched_contents}")
endif()
set_property(TARGET ${PROJECT} PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${APP_ANDROID_PACKAGE_SOURCE_DIR})

View File

@@ -1,3 +0,0 @@
if(NOT CLIENT_ANDROID_PACKAGE)
set(CLIENT_ANDROID_PACKAGE "org.amnezia.vpn" CACHE STRING "Android package name for Play Store version lookup")
endif()

View File

@@ -1,22 +0,0 @@
if(NOT CLIENT_SWIFT_MODULE_NAME)
set(CLIENT_SWIFT_MODULE_NAME "${CLIENT_APPLICATION_NAME}" CACHE STRING "Swift module name for Objective-C interop header")
endif()
if(NOT CLIENT_SWIFT_OBJC_HEADER_NAME)
set(CLIENT_SWIFT_OBJC_HEADER_NAME "${CLIENT_SWIFT_MODULE_NAME}-Swift.h" CACHE STRING "Generated Swift Objective-C header name")
endif()
if(NOT CLIENT_NETWORK_EXTENSION_NAME)
set(CLIENT_NETWORK_EXTENSION_NAME "${CLIENT_APPLICATION_NAME}NetworkExtension" CACHE STRING "Display name for Apple network extension targets")
endif()
if(NOT BUILD_OSX_APP_IDENTIFIER)
set(BUILD_OSX_APP_IDENTIFIER org.amnezia.AmneziaVPN CACHE STRING "OSX Application identifier")
endif()
if(NOT BUILD_IOS_APP_IDENTIFIER)
set(BUILD_IOS_APP_IDENTIFIER org.amnezia.AmneziaVPN CACHE STRING "iOS Application identifier")
endif()
if(NOT BUILD_IOS_GROUP_IDENTIFIER)
set(BUILD_IOS_GROUP_IDENTIFIER group.org.amnezia.AmneziaVPN CACHE STRING "iOS Group identifier")
endif()
if(NOT BUILD_VPN_DEVELOPMENT_TEAM)
set(BUILD_VPN_DEVELOPMENT_TEAM X7UJ388FXK CACHE STRING "Amnezia VPN Development Team")
endif()

View File

@@ -1,60 +0,0 @@
if(NOT CLIENT_TARGET_NAME)
set(CLIENT_TARGET_NAME "AmneziaVPN" CACHE STRING "Client executable target name")
endif()
if(NOT CLIENT_APPLICATION_NAME)
set(CLIENT_APPLICATION_NAME "AmneziaVPN" CACHE STRING "Application display and executable name")
endif()
if(NOT CLIENT_SERVICE_NAME)
set(CLIENT_SERVICE_NAME "AmneziaVPN-service" CACHE STRING "Service executable name")
endif()
if(NOT CLIENT_ORGANIZATION_NAME)
set(CLIENT_ORGANIZATION_NAME "AmneziaVPN.ORG" CACHE STRING "QSettings organization name")
endif()
if(NOT CLIENT_APP_INSTANCE_NAME)
set(CLIENT_APP_INSTANCE_NAME "AmneziaVPNInstance" CACHE STRING "Single-instance local server name")
endif()
if(NOT CLIENT_KEYCHAIN_NAME)
set(CLIENT_KEYCHAIN_NAME "${CLIENT_APPLICATION_NAME}-Keychain" CACHE STRING "QtKeychain service name used for encrypted settings keys")
endif()
# -- QML entry points and UI resources
if(NOT CLIENT_QML_ENTRYPOINT)
set(CLIENT_QML_ENTRYPOINT "qrc:/ui/qml/main2.qml" CACHE STRING "Main QML entrypoint URL")
endif()
if(NOT CLIENT_QML_IMPORT_PATH)
set(CLIENT_QML_IMPORT_PATH "qrc:/ui/qml/Modules/" CACHE STRING "Additional QQmlEngine import path")
endif()
if(NOT CLIENT_QML_PAGES_PREFIX)
set(CLIENT_QML_PAGES_PREFIX "qrc:/ui/qml/Pages2/" CACHE STRING "PageController QML pages prefix")
endif()
if(NOT CLIENT_UI_FONT_RESOURCE)
set(CLIENT_UI_FONT_RESOURCE ":/fonts/pt-root-ui_vf.ttf" CACHE STRING "UI font resource path")
endif()
if(NOT CLIENT_QML_QRC_FILE)
set(CLIENT_QML_QRC_FILE "${_CLIENT_SRC_DIR}/ui/qml/qml.qrc" CACHE FILEPATH "QML resources manifest")
endif()
if(NOT CLIENT_EXTRA_QRC)
set(CLIENT_EXTRA_QRC "" CACHE STRING "Optional semicolon-separated extra QRC files")
endif()
# -- translations
if(NOT CLIENT_TS_PREFIX)
set(CLIENT_TS_PREFIX "amneziavpn" CACHE STRING "Translation filename prefix")
endif()
if(NOT CLIENT_TS_FILES)
set(CLIENT_TS_FILES "" CACHE STRING "Optional semicolon-separated absolute TS file paths")
endif()
# -- brand-provided headers
if(NOT CLIENT_BRANDING_INCLUDE_DIR)
set(CLIENT_BRANDING_INCLUDE_DIR "" CACHE PATH "Optional include root for non-generated branding headers (e.g. pageEnum.h)")
endif()
if(CLIENT_BRANDING_INCLUDE_DIR AND EXISTS "${CLIENT_BRANDING_INCLUDE_DIR}/ui/utils/pageEnum.h")
set(CLIENT_PAGE_ENUM_HEADER "${CLIENT_BRANDING_INCLUDE_DIR}/ui/utils/pageEnum.h")
else()
set(CLIENT_PAGE_ENUM_HEADER "${_CLIENT_SRC_DIR}/ui/utils/pageEnum.h")
endif()
if(NOT CLIENT_NOTIFICATION_IDENTIFIER)
set(CLIENT_NOTIFICATION_IDENTIFIER "${CLIENT_TS_PREFIX}" CACHE STRING "Local notification request identifier")
endif()

View File

@@ -1,45 +0,0 @@
if(NOT CLIENT_IOS_NE_TARGET_NAME)
set(CLIENT_IOS_NE_TARGET_NAME "networkextension" CACHE STRING "iOS network extension build target name")
endif()
if(NOT CLIENT_IOS_NE_ENTITLEMENTS_FILE)
set(CLIENT_IOS_NE_ENTITLEMENTS_FILE "AmneziaVPNNetworkExtension.entitlements" CACHE STRING "iOS network extension entitlements filename")
endif()
if(NOT CLIENT_IOS_LAUNCHSCREEN_FILE)
set(CLIENT_IOS_LAUNCHSCREEN_FILE "AmneziaVPNLaunchScreen.storyboard" CACHE STRING "iOS launch screen storyboard filename")
endif()
get_filename_component(CLIENT_IOS_LAUNCHSCREEN_NAME "${CLIENT_IOS_LAUNCHSCREEN_FILE}" NAME_WE)
if(NOT CLIENT_IOS_APP_ENTITLEMENTS_PATH)
set(CLIENT_IOS_APP_ENTITLEMENTS_PATH "${_CLIENT_SRC_DIR}/ios/app/main.entitlements" CACHE FILEPATH "iOS app entitlements file path")
endif()
if(NOT CLIENT_IOS_NE_ENTITLEMENTS_PATH)
set(CLIENT_IOS_NE_ENTITLEMENTS_PATH "${_CLIENT_SRC_DIR}/ios/networkextension/${CLIENT_IOS_NE_ENTITLEMENTS_FILE}" CACHE FILEPATH "iOS network extension entitlements file path")
endif()
if(NOT CLIENT_IOS_LAUNCHSCREEN_PATH)
set(CLIENT_IOS_LAUNCHSCREEN_PATH "${_CLIENT_SRC_DIR}/ios/app/${CLIENT_IOS_LAUNCHSCREEN_FILE}" CACHE FILEPATH "iOS launch screen storyboard path")
endif()
if(NOT CLIENT_IOS_MEDIA_ASSETS_PATH)
set(CLIENT_IOS_MEDIA_ASSETS_PATH "${_CLIENT_SRC_DIR}/ios/app/Media.xcassets" CACHE FILEPATH "iOS app Media.xcassets path")
endif()
if(NOT CLIENT_IOS_BUNDLE_ID)
set(CLIENT_IOS_BUNDLE_ID "org.amnezia.AmneziaVPN" CACHE STRING "iOS bundle id for App Store version lookup")
endif()
if(NOT CLIENT_IOS_STORE_URL_FALLBACK)
set(CLIENT_IOS_STORE_URL_FALLBACK "itms-apps://itunes.apple.com/app/id1600529900" CACHE STRING "Fallback App Store URL when lookup omits trackViewUrl")
endif()
# -- signing
if(NOT CLIENT_IOS_PROVISIONING_PROFILE_SPECIFIER)
set(CLIENT_IOS_PROVISIONING_PROFILE_SPECIFIER "distr ios.org.amnezia.AmneziaVPN" CACHE STRING "iOS app provisioning profile specifier for release")
endif()
if(NOT CLIENT_IOS_PROVISIONING_PROFILE_SPECIFIER_DEBUG)
set(CLIENT_IOS_PROVISIONING_PROFILE_SPECIFIER_DEBUG "dev ios.org.amnezia.AmneziaVPN" CACHE STRING "iOS app provisioning profile specifier for debug")
endif()
if(NOT CLIENT_IOS_NE_PROVISIONING_PROFILE_SPECIFIER)
set(CLIENT_IOS_NE_PROVISIONING_PROFILE_SPECIFIER "distr ios.org.amnezia.AmneziaVPN" CACHE STRING "iOS network extension provisioning profile specifier for release")
endif()
if(NOT CLIENT_IOS_NE_PROVISIONING_PROFILE_SPECIFIER_DEBUG)
set(CLIENT_IOS_NE_PROVISIONING_PROFILE_SPECIFIER_DEBUG "dev ios.org.amnezia.AmneziaVPN" CACHE STRING "iOS network extension provisioning profile specifier for debug")
endif()

View File

@@ -1,37 +0,0 @@
if(NOT CLIENT_MACOS_NE_TARGET_NAME)
set(CLIENT_MACOS_NE_TARGET_NAME "${CLIENT_NETWORK_EXTENSION_NAME}" CACHE STRING "macOS network extension build target name")
endif()
if(NOT CLIENT_MACOS_NE_ENTITLEMENTS_FILE)
set(CLIENT_MACOS_NE_ENTITLEMENTS_FILE "AmneziaVPNNetworkExtension.entitlements" CACHE STRING "macOS network extension entitlements filename")
endif()
if(NOT CLIENT_MACOS_APP_ENTITLEMENTS_PATH)
set(CLIENT_MACOS_APP_ENTITLEMENTS_PATH "${_CLIENT_SRC_DIR}/macos/app/app.entitlements" CACHE FILEPATH "macOS app entitlements file path")
endif()
if(NOT CLIENT_MACOS_NE_ENTITLEMENTS_PATH)
set(CLIENT_MACOS_NE_ENTITLEMENTS_PATH "${_CLIENT_SRC_DIR}/macos/networkextension/${CLIENT_MACOS_NE_ENTITLEMENTS_FILE}" CACHE FILEPATH "macOS network extension entitlements file path")
endif()
if(NOT CLIENT_MACOS_MEDIA_ASSETS_PATH)
set(CLIENT_MACOS_MEDIA_ASSETS_PATH "${_CLIENT_SRC_DIR}/macos/app/Images.xcassets" CACHE FILEPATH "macOS app Images.xcassets path")
endif()
if(NOT CLIENT_MACOS_APP_ICNS_PATH)
set(CLIENT_MACOS_APP_ICNS_PATH "${_CLIENT_SRC_DIR}/images/app.icns" CACHE FILEPATH "macOS app icon (.icns) used by non-App Store builds")
endif()
if(NOT CLIENT_MACOS_EXTRA_PLIST_ENTRIES)
set(CLIENT_MACOS_EXTRA_PLIST_ENTRIES "" CACHE STRING "Extra macOS Info.plist entries appended verbatim (e.g. appearance pinning)")
endif()
# -- signing
if(NOT CLIENT_MACOS_PROVISIONING_PROFILE_SPECIFIER)
set(CLIENT_MACOS_PROVISIONING_PROFILE_SPECIFIER "distr macos.org.amnezia.AmneziaVPN" CACHE STRING "macOS app provisioning profile specifier for release")
endif()
if(NOT CLIENT_MACOS_PROVISIONING_PROFILE_SPECIFIER_DEBUG)
set(CLIENT_MACOS_PROVISIONING_PROFILE_SPECIFIER_DEBUG "dev macos.org.amnezia.AmneziaVPN" CACHE STRING "macOS app provisioning profile specifier for debug")
endif()
if(NOT CLIENT_MACOS_NE_PROVISIONING_PROFILE_SPECIFIER)
set(CLIENT_MACOS_NE_PROVISIONING_PROFILE_SPECIFIER "distr macos.org.amnezia.amneziaVPN.NE" CACHE STRING "macOS network extension provisioning profile specifier for release")
endif()
if(NOT CLIENT_MACOS_NE_PROVISIONING_PROFILE_SPECIFIER_DEBUG)
set(CLIENT_MACOS_NE_PROVISIONING_PROFILE_SPECIFIER_DEBUG "dev macos.org.amnezia.amneziaVPN.NE" CACHE STRING "macOS network extension provisioning profile specifier for debug")
endif()

View File

@@ -1,9 +0,0 @@
get_filename_component(_CLIENT_SRC_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
include(${CMAKE_CURRENT_LIST_DIR}/branding/common.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/branding/apple.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/branding/ios.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/branding/macos.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/branding/android.cmake)
unset(_CLIENT_SRC_DIR)

View File

@@ -24,17 +24,6 @@ set(IOS_TARGET_COMPILED_TYPES
EXECUTABLE
)
## Simulator architecture: honor CMAKE_OSX_ARCHITECTURES when set, otherwise
## match the host — arm64 Macs run arm64 simulators (Xcode 26 has no Rosetta
## simulator destinations), Intel Macs need x86_64.
if(CMAKE_OSX_ARCHITECTURES)
string(REPLACE ";" " " IOS_SIMULATOR_ARCHS "${CMAKE_OSX_ARCHITECTURES}")
elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
set(IOS_SIMULATOR_ARCHS "arm64")
else()
set(IOS_SIMULATOR_ARCHS "x86_64")
endif()
## Inspect all the targets, and add extra properties if necessary.
while(IOS_TARGETS)
list(POP_FRONT IOS_TARGETS TARGET_NAME)
@@ -49,6 +38,6 @@ while(IOS_TARGETS)
message("Patching architectures for ${TARGET_NAME}")
set_target_properties(${TARGET_NAME} PROPERTIES
XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64"
XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "${IOS_SIMULATOR_ARCHS}"
XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64"
)
endwhile()

View File

@@ -64,25 +64,25 @@ target_include_directories(${PROJECT} PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
set_target_properties(${PROJECT} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/ios/app/Info.plist.in
MACOSX_BUNDLE_ICON_FILE "AppIcon"
MACOSX_BUNDLE_INFO_STRING "${CLIENT_APPLICATION_NAME}"
MACOSX_BUNDLE_BUNDLE_NAME "${CLIENT_APPLICATION_NAME}"
MACOSX_BUNDLE_INFO_STRING "AmneziaVPN"
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPN"
MACOSX_BUNDLE_GUI_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}"
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 "${CLIENT_IOS_APP_ENTITLEMENTS_PATH}"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/ios/app/main.entitlements"
XCODE_ATTRIBUTE_MARKETING_VERSION "${APPLE_PROJECT_VERSION}"
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
XCODE_ATTRIBUTE_PRODUCT_NAME "${CLIENT_APPLICATION_NAME}"
XCODE_ATTRIBUTE_BUNDLE_INFO_STRING "${CLIENT_APPLICATION_NAME}"
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPN"
XCODE_ATTRIBUTE_BUNDLE_INFO_STRING "AmneziaVPN"
XCODE_GENERATE_SCHEME TRUE
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon"
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY ON
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks"
XCODE_EMBED_APP_EXTENSIONS ${CLIENT_IOS_NE_TARGET_NAME}
XCODE_EMBED_APP_EXTENSIONS networkextension
)
if(DEPLOY)
@@ -90,8 +90,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 "${CLIENT_IOS_PROVISIONING_PROFILE_SPECIFIER}"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "${CLIENT_IOS_PROVISIONING_PROFILE_SPECIFIER_DEBUG}"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr ios.org.amnezia.AmneziaVPN"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev ios.org.amnezia.AmneziaVPN"
)
else()
set_target_properties(${PROJECT} PROPERTIES
@@ -103,11 +103,11 @@ 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 "${CLIENT_SWIFT_OBJC_HEADER_NAME}"
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 "${BUILD_VPN_DEVELOPMENT_TEAM}"
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK"
)
target_include_directories(${PROJECT} PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_compile_options(${PROJECT} PRIVATE
@@ -122,7 +122,6 @@ 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_GROUP_IDENTIFIER_SWIFT_FILE}
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
${CLIENT_ROOT_DIR}/platforms/ios/ScreenProtection.swift
${CLIENT_ROOT_DIR}/platforms/ios/VPNCController.swift
@@ -130,20 +129,20 @@ target_sources(${PROJECT} PRIVATE
)
set_source_files_properties(
${CLIENT_IOS_MEDIA_ASSETS_PATH}
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/Media.xcassets
PROPERTIES MACOSX_PACKAGE_LOCATION Resources
)
target_sources(${PROJECT} PRIVATE
${CLIENT_IOS_LAUNCHSCREEN_PATH}
${CLIENT_IOS_MEDIA_ASSETS_PATH}
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/AmneziaVPNLaunchScreen.storyboard
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/Media.xcassets
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
)
set_property(TARGET ${PROJECT} APPEND PROPERTY RESOURCE
${CLIENT_IOS_LAUNCHSCREEN_PATH}
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/AmneziaVPNLaunchScreen.storyboard
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
)
add_subdirectory(ios/networkextension)
add_dependencies(${PROJECT} ${CLIENT_IOS_NE_TARGET_NAME})
add_dependencies(${PROJECT} networkextension)

View File

@@ -34,8 +34,8 @@ set(SOURCES ${SOURCES}
set(ICON_FILE ${CLIENT_MACOS_APP_ICNS_PATH})
get_filename_component(MACOSX_BUNDLE_ICON_FILE "${CLIENT_MACOS_APP_ICNS_PATH}" NAME)
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})

View File

@@ -60,25 +60,25 @@ 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 "${CLIENT_APPLICATION_NAME}"
MACOSX_BUNDLE_BUNDLE_NAME "${CLIENT_APPLICATION_NAME}"
MACOSX_BUNDLE_INFO_STRING "AmneziaVPN"
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPN"
MACOSX_BUNDLE_GUI_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}"
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 "${CLIENT_MACOS_APP_ENTITLEMENTS_PATH}"
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 "${CLIENT_APPLICATION_NAME}"
XCODE_ATTRIBUTE_BUNDLE_INFO_STRING "${CLIENT_APPLICATION_NAME}"
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPN"
XCODE_ATTRIBUTE_BUNDLE_INFO_STRING "AmneziaVPN"
XCODE_GENERATE_SCHEME TRUE
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon"
XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY "NO"
XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY "YES"
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks"
XCODE_EMBED_APP_EXTENSIONS ${CLIENT_MACOS_NE_TARGET_NAME}
XCODE_EMBED_APP_EXTENSIONS AmneziaVPNNetworkExtension
)
if(DEPLOY)
@@ -86,8 +86,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 "${CLIENT_MACOS_PROVISIONING_PROFILE_SPECIFIER}"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "${CLIENT_MACOS_PROVISIONING_PROFILE_SPECIFIER_DEBUG}"
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
@@ -99,11 +99,11 @@ 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 "${CLIENT_SWIFT_OBJC_HEADER_NAME}"
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 "${BUILD_VPN_DEVELOPMENT_TEAM}"
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK"
)
target_include_directories(${PROJECT} PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_compile_options(${PROJECT} PRIVATE
@@ -117,7 +117,6 @@ 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_GROUP_IDENTIFIER_SWIFT_FILE}
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
${CLIENT_ROOT_DIR}/platforms/ios/ScreenProtection.swift
${CLIENT_ROOT_DIR}/platforms/ios/VPNCController.swift
@@ -125,12 +124,12 @@ target_sources(${PROJECT} PRIVATE
)
set_source_files_properties(
${CLIENT_MACOS_MEDIA_ASSETS_PATH}
${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Images.xcassets
PROPERTIES MACOSX_PACKAGE_LOCATION Resources
)
target_sources(${PROJECT} PRIVATE
${CLIENT_MACOS_MEDIA_ASSETS_PATH}
${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Images.xcassets
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
)
@@ -139,7 +138,7 @@ set_property(TARGET ${PROJECT} APPEND PROPERTY RESOURCE
)
add_subdirectory(macos/networkextension)
add_dependencies(${PROJECT} ${CLIENT_MACOS_NE_TARGET_NAME})
add_dependencies(${PROJECT} AmneziaVPNNetworkExtension)
get_target_property(QtCore_location Qt6::Core LOCATION)
message("QtCore_location")
@@ -148,5 +147,5 @@ message(${QtCore_location})
get_filename_component(QT_BIN_DIR_DETECTED "${QtCore_location}/../../../../../bin" ABSOLUTE)
add_custom_command(TARGET ${PROJECT} POST_BUILD
COMMAND ${QT_BIN_DIR_DETECTED}/macdeployqt $<TARGET_BUNDLE_DIR:${PROJECT}> -appstore-compliant -qmldir=${CMAKE_CURRENT_SOURCE_DIR} -no-codesign
COMMAND ${QT_BIN_DIR_DETECTED}/macdeployqt $<TARGET_BUNDLE_DIR:AmneziaVPN> -appstore-compliant -qmldir=${CMAKE_CURRENT_SOURCE_DIR} -no-codesign
)

View File

@@ -51,7 +51,6 @@ set(HEADERS ${HEADERS}
${CLIENT_ROOT_DIR}/core/repositories/secureAppSettingsRepository.h
${CLIENT_ROOT_DIR}/core/protocols/qmlRegisterProtocols.h
${CLIENT_ROOT_DIR}/ui/utils/pages.h
${CLIENT_PAGE_ENUM_HEADER}
${CLIENT_ROOT_DIR}/ui/utils/qAutoStart.h
${CLIENT_ROOT_DIR}/ui/utils/mtProxyPublicHostInput.h
${CLIENT_ROOT_DIR}/core/protocols/vpnProtocol.h
@@ -65,9 +64,7 @@ set(HEADERS ${HEADERS}
${CLIENT_ROOT_DIR}/../common/crypto/cryptoUtils.h
${CLIENT_ROOT_DIR}/ui/utils/qmlUtils.h
${CLIENT_ROOT_DIR}/core/utils/api/apiUtils.h
${CLIENT_ROOT_DIR}/core/utils/api/gatewayPayloadBuilder.h
${CLIENT_ROOT_DIR}/core/utils/osSignalHandler.h
${CLIENT_ROOT_DIR}/core/utils/swiftBridge.h
${CLIENT_ROOT_DIR}/core/utils/utilities.h
${CLIENT_ROOT_DIR}/core/utils/managementServer.h
${CLIENT_ROOT_DIR}/core/utils/constants.h
@@ -150,7 +147,6 @@ set(SOURCES ${SOURCES}
${CLIENT_ROOT_DIR}/../common/crypto/cryptoUtils.cpp
${CLIENT_ROOT_DIR}/ui/utils/qmlUtils.cpp
${CLIENT_ROOT_DIR}/core/utils/api/apiUtils.cpp
${CLIENT_ROOT_DIR}/core/utils/api/gatewayPayloadBuilder.cpp
${CLIENT_ROOT_DIR}/core/utils/serverConfigUtils.cpp
${CLIENT_ROOT_DIR}/core/utils/osSignalHandler.cpp
${CLIENT_ROOT_DIR}/core/utils/utilities.cpp

View File

@@ -106,8 +106,6 @@ ProtocolConfig AwgConfigurator::createConfig(const ServerCredentials &credential
newClientConfig.rejectAfterTime = configMap.value(configKey::rejectAfterTime);
newClientConfig.keepaliveTimeout = configMap.value(configKey::keepaliveTimeout);
newClientConfig.maxHandshakeAttempts = configMap.value(configKey::maxHandshakeAttempts);
newClientConfig.randomTrailers = configMap.value(configKey::randomTrailers);
newClientConfig.disableCookies = configMap.value(configKey::disableCookies);
protocolConfig.setClientConfig(newClientConfig);

View File

@@ -228,6 +228,8 @@ ProtocolConfig WireguardConfigurator::createConfig(const ServerCredentials &cred
}
}
const bool isAwg3 = awgServerConfig && awgServerConfig->protocolVersion == protocols::awg::awgV3;
amnezia::ScriptVars vars = amnezia::genBaseVars(credentials, container, dnsSettings.primaryDns, dnsSettings.secondaryDns);
vars.append(amnezia::genProtocolVarsForContainer(container, containerConfig));
QString scriptData = amnezia::scriptData(m_configTemplate, container);
@@ -273,9 +275,8 @@ ProtocolConfig WireguardConfigurator::createConfig(const ServerCredentials &cred
clientConfig.presharedKey = connData.pskKey;
clientConfig.clientId = connData.clientPubKey;
clientConfig.allowedIps = QStringList { "0.0.0.0/0", "::/0" };
const bool useKeepAliveRange = awgServerConfig && awgServerConfig->hasAwg3Params();
clientConfig.persistentKeepAlive = useKeepAliveRange ? protocols::awg::defaultPersistentKeepAlive
: protocols::wireguard::defaultPersistentKeepAlive;
clientConfig.persistentKeepAlive = isAwg3 ? protocols::awg::defaultPersistentKeepAlive
: protocols::wireguard::defaultPersistentKeepAlive;
clientConfig.mtu = mtu;
clientConfig.isObfuscationEnabled = false;

View File

@@ -211,6 +211,33 @@ ErrorCode XrayConfigurator::readRealityKeyFiles(const DockerContainer container,
return readKeyFile(QString::fromLatin1(amnezia::protocols::xray::shortidPath), outShortId);
}
QJsonObject XrayConfigurator::mergeStreamSettingsForServerInbound(const XrayServerConfig &srv,
const QJsonObject &existingStreamSettings) const
{
QJsonObject streamSettings = buildStreamSettings(srv, QString());
if (effectiveSecurity(srv) != QLatin1String("reality")) {
return streamSettings;
}
const QJsonObject newRs = streamSettings[amnezia::protocols::xray::realitySettings].toObject();
QJsonObject oldRs = existingStreamSettings[amnezia::protocols::xray::realitySettings].toObject();
QJsonObject merged = oldRs.isEmpty() ? newRs : oldRs;
const QString siteEff = srv.site.isEmpty() ? QString::fromLatin1(amnezia::protocols::xray::defaultSite) : srv.site;
const QString sniEff = srv.sni.isEmpty() ? siteEff : srv.sni;
if (newRs.contains(amnezia::protocols::xray::fingerprint)) {
merged[amnezia::protocols::xray::fingerprint] = newRs[amnezia::protocols::xray::fingerprint];
}
merged[amnezia::protocols::xray::serverNames] = QJsonArray { sniEff };
if (!merged.contains(QStringLiteral("dest"))) {
merged[QStringLiteral("dest")] = siteEff + QStringLiteral(":443");
}
streamSettings[amnezia::protocols::xray::realitySettings] = merged;
return streamSettings;
}
ErrorCode XrayConfigurator::applyServerSettingsToRemote(const ServerCredentials &credentials, DockerContainer container,
ContainerConfig &containerConfig, const DnsSettings &dnsSettings,
@@ -281,6 +308,13 @@ ErrorCode XrayConfigurator::applyServerSettingsToRemote(const ServerCredentials
return ErrorCode::XrayServerConfigInvalid;
}
const QJsonObject existingStream = inbound[amnezia::protocols::xray::streamSettings].toObject();
inbound[amnezia::protocols::xray::streamSettings] = mergeStreamSettingsForServerInbound(srv, existingStream);
if (!srv.port.isEmpty()) {
inbound[amnezia::protocols::xray::port] = srv.port.toInt();
}
QJsonObject settings = inbound[amnezia::protocols::xray::settings].toObject();
if (!settings.contains(amnezia::protocols::xray::clients)) {
settings[amnezia::protocols::xray::clients] = QJsonArray {};

View File

@@ -60,6 +60,9 @@ private:
QString &outPublicKey,
QString &outShortId) const;
QJsonObject mergeStreamSettingsForServerInbound(const amnezia::XrayServerConfig &srv,
const QJsonObject &existingStreamSettings) const;
QJsonObject buildStreamSettings(const amnezia::XrayServerConfig &srv,
const QString &clientId) const;
};

View File

@@ -2,8 +2,6 @@
#include "core/controllers/gatewayController.h"
#include "core/repositories/secureServersRepository.h"
#include "core/utils/api/apiUtils.h"
#include "core/utils/api/gatewayPayloadBuilder.h"
#include "core/utils/constants/apiKeys.h"
#include "core/utils/constants/apiConstants.h"
#include <QtConcurrent/QtConcurrent>
@@ -83,12 +81,15 @@ QFuture<QPair<ErrorCode, QJsonArray>> NewsController::fetchNews()
m_appSettingsRepository->isStrictKillSwitchEnabled(),
m_appSettingsRepository);
// both country codes and service types are arrays here, one entry per gateway stack the user has
const QJsonObject payload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::locale, apiUtils::getAppLanguageCode(m_appSettingsRepository))
.addField(apiDefs::key::userCountryCode, services.value(apiDefs::key::userCountryCode))
.addField(apiDefs::key::serviceType, services.value(apiDefs::key::serviceType))
.build();
QJsonObject payload;
payload.insert("locale", m_appSettingsRepository->getAppLanguage().name().split("_").first());
if (services.contains(apiDefs::key::userCountryCode)) {
payload.insert(apiDefs::key::userCountryCode, services.value(apiDefs::key::userCountryCode));
}
if (services.contains(apiDefs::key::serviceType)) {
payload.insert(apiDefs::key::serviceType, services.value(apiDefs::key::serviceType));
}
auto future = gatewayController->postAsync(QString("%1v1/news"), payload);
return future.then([gatewayController](QPair<ErrorCode, QByteArray> result) -> QPair<ErrorCode, QJsonArray> {

View File

@@ -1,6 +1,7 @@
#include "servicesCatalogController.h"
#include <QJsonDocument>
#include <QSysInfo>
#include <QJsonArray>
#include <QEventLoop>
#include <QDebug>
@@ -10,7 +11,6 @@
#include <limits>
#include "core/controllers/gatewayController.h"
#include "core/utils/api/gatewayPayloadBuilder.h"
#include "core/utils/serverConfigUtils.h"
#include "core/utils/constants/apiKeys.h"
#include "core/utils/constants/apiConstants.h"
@@ -212,7 +212,11 @@ ServicesCatalogController::ServicesCatalogController(SecureAppSettingsRepository
ErrorCode ServicesCatalogController::fillAvailableServices(QJsonObject &servicesData)
{
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository).build();
QJsonObject apiPayload;
apiPayload[apiDefs::key::osVersion] = QSysInfo::productType();
apiPayload[apiDefs::key::appVersion] = QString(APP_VERSION);
apiPayload[apiDefs::key::cliName] = QString(APPLICATION_NAME);
apiPayload[apiDefs::key::appLanguage] = m_appSettingsRepository->getAppLanguage().name().split("_").first();
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/services"), apiPayload, responseBody);

View File

@@ -8,6 +8,7 @@
#include <QJsonObject>
#include <QPromise>
#include <QSet>
#include <QSysInfo>
#include <QUuid>
#include <QVariantMap>
@@ -20,7 +21,6 @@
#include "core/utils/constants/apiKeys.h"
#include "core/utils/constants/apiConstants.h"
#include "core/utils/api/apiUtils.h"
#include "core/utils/api/gatewayPayloadBuilder.h"
#include "core/controllers/gatewayController.h"
#include "core/utils/protocolEnum.h"
#include "core/protocols/protocolUtils.h"
@@ -32,7 +32,7 @@
#if defined(Q_OS_IOS) || defined(MACOS_NE)
#include "platforms/ios/ios_controller.h"
#include "core/utils/swiftBridge.h"
#include <AmneziaVPN-Swift.h>
#endif
using namespace amnezia;
@@ -97,6 +97,39 @@ SubscriptionController::SubscriptionController(SecureServersRepository* serversR
{
}
QJsonObject SubscriptionController::GatewayRequestData::toJsonObject() const
{
QJsonObject obj;
if (!osVersion.isEmpty()) {
obj[apiDefs::key::osVersion] = osVersion;
}
if (!appVersion.isEmpty()) {
obj[apiDefs::key::appVersion] = appVersion;
}
if (!appLanguage.isEmpty()) {
obj[apiDefs::key::appLanguage] = appLanguage;
}
if (!installationUuid.isEmpty()) {
obj[apiDefs::key::uuid] = installationUuid;
}
if (!userCountryCode.isEmpty()) {
obj[apiDefs::key::userCountryCode] = userCountryCode;
}
if (!serverCountryCode.isEmpty()) {
obj[apiDefs::key::serverCountryCode] = serverCountryCode;
}
if (!serviceType.isEmpty()) {
obj[apiDefs::key::serviceType] = serviceType;
}
if (!serviceProtocol.isEmpty()) {
obj[apiDefs::key::serviceProtocol] = serviceProtocol;
}
if (!authData.isEmpty()) {
obj[apiDefs::key::authData] = authData;
}
return obj;
}
SubscriptionController::ProtocolData SubscriptionController::generateProtocolData(const QString &protocol)
{
ProtocolData protocolData;
@@ -111,15 +144,13 @@ SubscriptionController::ProtocolData SubscriptionController::generateProtocolDat
return protocolData;
}
QString SubscriptionController::publicKeyForProtocol(const QString &protocol, const ProtocolData &protocolData)
void SubscriptionController::appendProtocolDataToApiPayload(const QString &protocol, const ProtocolData &protocolData, QJsonObject &apiPayload)
{
if (protocol == configKey::awg) {
return protocolData.wireGuardClientPubKey;
apiPayload[apiDefs::key::publicKey] = protocolData.wireGuardClientPubKey;
} else if (protocol == configKey::vless) {
apiPayload[apiDefs::key::publicKey] = protocolData.xrayUuid;
}
if (protocol == configKey::vless) {
return protocolData.xrayUuid;
}
return {};
}
ErrorCode SubscriptionController::extractServerConfigJsonFromResponse(const QByteArray &apiResponseBody, const QString &protocol,
@@ -209,12 +240,18 @@ ErrorCode SubscriptionController::importServiceFromGateway(const QString &userCo
const QString &serviceProtocol, const ProtocolData &protocolData,
CaptchaInfo &captchaInfo)
{
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, userCountryCode)
.addField(apiDefs::key::serviceType, serviceType)
.addField(apiDefs::key::serviceProtocol, serviceProtocol)
.addField(apiDefs::key::publicKey, publicKeyForProtocol(serviceProtocol, protocolData))
.build();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
userCountryCode,
"",
serviceType,
serviceProtocol,
QJsonObject() };
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload);
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody);
@@ -254,15 +291,20 @@ ErrorCode SubscriptionController::importTrialFromGateway(const QString &userCoun
return ErrorCode::ApiConfigEmptyError;
}
ProtocolData protocolData = generateProtocolData(serviceProtocol);
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
userCountryCode,
"",
serviceType,
serviceProtocol,
QJsonObject() };
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, userCountryCode)
.addField(apiDefs::key::serviceType, serviceType)
.addField(apiDefs::key::serviceProtocol, serviceProtocol)
.addField(apiDefs::key::publicKey, publicKeyForProtocol(serviceProtocol, protocolData))
.addField(apiDefs::key::email, trimmedEmail)
.build();
ProtocolData protocolData = generateProtocolData(serviceProtocol);
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload);
apiPayload.insert(apiDefs::key::email, trimmedEmail);
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/trial"), apiPayload, responseBody);
@@ -303,13 +345,19 @@ ErrorCode SubscriptionController::importServiceFromAppStore(const QString &userC
const QString &transactionId, bool isTestPurchase,
int *duplicateServerIndex)
{
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, userCountryCode)
.addField(apiDefs::key::serviceType, serviceType)
.addField(apiDefs::key::serviceProtocol, serviceProtocol)
.addField(apiDefs::key::publicKey, publicKeyForProtocol(serviceProtocol, protocolData))
.addField(apiDefs::key::transactionId, transactionId)
.build();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
userCountryCode,
"",
serviceType,
serviceProtocol,
QJsonObject() };
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload);
apiPayload[apiDefs::key::transactionId] = transactionId;
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/subscriptions"), apiPayload, responseBody, isTestPurchase);
@@ -364,6 +412,8 @@ ErrorCode SubscriptionController::importServiceFromAppStore(const QString &userC
ApiV2ServerConfig apiV2ServerConfig = ApiV2ServerConfig::fromJson(configObject);
ApiV2ServerConfig* apiV2 = &apiV2ServerConfig;
apiV2->apiConfig.vpnKey = normalizedKey;
apiV2->apiConfig.isTestPurchase = isTestPurchase;
apiV2->apiConfig.isInAppPurchase = true;
apiV2->apiConfig.subscriptionExpiredByServer = false;
apiV2->crc = crc;
@@ -401,15 +451,23 @@ ErrorCode SubscriptionController::updateServiceFromGateway(const QString &server
ProtocolData protocolData = generateProtocolData(serviceProtocol);
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, apiV2->apiConfig.userCountryCode)
.addField(apiDefs::key::serverCountryCode, newCountryCode)
.addField(apiDefs::key::serviceType, apiV2->serviceType())
.addField(apiDefs::key::serviceProtocol, serviceProtocol)
.addField(apiDefs::key::publicKey, publicKeyForProtocol(serviceProtocol, protocolData))
.addField(apiDefs::key::authData, apiV2->authData.toJson())
.addField(apiDefs::key::isConnectEvent, isConnectEvent ? QJsonValue(true) : QJsonValue())
.build();
QJsonObject authDataJson = apiV2->authData.toJson();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
apiV2->apiConfig.userCountryCode,
newCountryCode,
apiV2->serviceType(),
serviceProtocol,
authDataJson };
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload);
if (isConnectEvent) {
apiPayload[apiDefs::key::isConnectEvent] = true;
}
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody, isTestPurchase);
@@ -455,6 +513,8 @@ ErrorCode SubscriptionController::applyUpdatedServiceConfig(const QString &serve
ApiV2ServerConfig* newApiV2 = &newApiV2Config;
newApiV2->apiConfig.vpnKey = apiV2->apiConfig.vpnKey;
newApiV2->apiConfig.isTestPurchase = apiV2->apiConfig.isTestPurchase;
newApiV2->apiConfig.isInAppPurchase = apiV2->apiConfig.isInAppPurchase;
newApiV2->apiConfig.subscriptionExpiredByServer = false;
newApiV2->authData = apiV2->authData;
@@ -483,17 +543,26 @@ ErrorCode SubscriptionController::resolveUpdateServiceCaptcha(const QString &ser
const bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
QString serviceProtocol = apiV2->serviceProtocol();
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, apiV2->apiConfig.userCountryCode)
.addField(apiDefs::key::serverCountryCode, newCountryCode)
.addField(apiDefs::key::serviceType, apiV2->serviceType())
.addField(apiDefs::key::serviceProtocol, serviceProtocol)
.addField(apiDefs::key::publicKey, publicKeyForProtocol(serviceProtocol, protocolData))
.addField(apiDefs::key::authData, apiV2->authData.toJson())
.addField(apiDefs::key::captchaId, captchaId)
.addField(apiDefs::key::captchaSolution, normalizeCaptchaSolution(captchaSolution))
.addField(apiDefs::key::isConnectEvent, isConnectEvent ? QJsonValue(true) : QJsonValue())
.build();
QJsonObject authDataJson = apiV2->authData.toJson();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
apiV2->apiConfig.userCountryCode,
newCountryCode,
apiV2->serviceType(),
serviceProtocol,
authDataJson };
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload);
if (isConnectEvent) {
apiPayload[apiDefs::key::isConnectEvent] = true;
}
apiPayload["captcha_id"] = captchaId;
apiPayload["captcha_solution"] = normalizeCaptchaSolution(captchaSolution);
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody, isTestPurchase);
@@ -526,12 +595,18 @@ ErrorCode SubscriptionController::deactivateDevice(const QString &serverId)
return ErrorCode::NoError;
}
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, apiV2->apiConfig.userCountryCode)
.addField(apiDefs::key::serverCountryCode, apiV2->apiConfig.serverCountryCode)
.addField(apiDefs::key::serviceType, apiV2->serviceType())
.addField(apiDefs::key::authData, apiV2->authData.toJson())
.build();
QJsonObject authDataJson = apiV2->authData.toJson();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
apiV2->apiConfig.userCountryCode,
apiV2->apiConfig.serverCountryCode,
apiV2->serviceType(),
"",
authDataJson };
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
const bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
QByteArray responseBody;
@@ -557,13 +632,18 @@ ErrorCode SubscriptionController::deactivateExternalDevice(const QString &server
return ErrorCode::NoError;
}
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::installationUuid, uuid)
.addField(apiDefs::key::userCountryCode, apiV2->apiConfig.userCountryCode)
.addField(apiDefs::key::serverCountryCode, serverCountryCode)
.addField(apiDefs::key::serviceType, apiV2->serviceType())
.addField(apiDefs::key::authData, apiV2->authData.toJson())
.build();
QJsonObject authDataJson = apiV2->authData.toJson();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
uuid,
apiV2->apiConfig.userCountryCode,
serverCountryCode,
apiV2->serviceType(),
"",
authDataJson };
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
const bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
QByteArray responseBody;
@@ -591,14 +671,19 @@ ErrorCode SubscriptionController::exportNativeConfig(const QString &serverId, co
QString protocol = configKey::awg;
ProtocolData protocolData = generateProtocolData(protocol);
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, apiV2->apiConfig.userCountryCode)
.addField(apiDefs::key::serverCountryCode, serverCountryCode)
.addField(apiDefs::key::serviceType, apiV2->serviceType())
.addField(apiDefs::key::serviceProtocol, protocol)
.addField(apiDefs::key::publicKey, publicKeyForProtocol(protocol, protocolData))
.addField(apiDefs::key::authData, apiV2->authData.toJson())
.build();
QJsonObject authDataJson = apiV2->authData.toJson();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
apiV2->apiConfig.userCountryCode,
serverCountryCode,
apiV2->serviceType(),
protocol,
authDataJson };
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
appendProtocolDataToApiPayload(protocol, protocolData, apiPayload);
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/native_config"), apiPayload, responseBody, isTestPurchase);
@@ -621,13 +706,18 @@ ErrorCode SubscriptionController::revokeNativeConfig(const QString &serverId, co
const bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
QString protocol = configKey::awg;
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, apiV2->apiConfig.userCountryCode)
.addField(apiDefs::key::serverCountryCode, serverCountryCode)
.addField(apiDefs::key::serviceType, apiV2->serviceType())
.addField(apiDefs::key::serviceProtocol, protocol)
.addField(apiDefs::key::authData, apiV2->authData.toJson())
.build();
QJsonObject authDataJson = apiV2->authData.toJson();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
apiV2->apiConfig.userCountryCode,
serverCountryCode,
apiV2->serviceType(),
protocol,
authDataJson };
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/revoke_native_config"), apiPayload, responseBody, isTestPurchase);
@@ -692,7 +782,7 @@ void SubscriptionController::removeApiConfig(const QString &serverId)
.arg(hostName)
.arg("");
SWIFT_BRIDGE_NAMESPACE::removeVPNC(vpncName.toStdString());
AmneziaVPN::removeVPNC(vpncName.toStdString());
#endif
apiV2->dns1.clear();
@@ -934,13 +1024,20 @@ ErrorCode SubscriptionController::getAccountInfo(const QString &serverId, QJsonO
}
bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, apiV2->apiConfig.userCountryCode)
.addField(apiDefs::key::serviceType, apiV2->serviceType())
.addField(apiDefs::key::authData, apiV2->authData.toJson())
.addField(apiDefs::key::cliVersion, QString(APP_VERSION))
.addField(apiDefs::key::subscriptionStatus, getSubscriptionStatusForRenewal(apiV2->apiConfig))
.build();
QJsonObject authDataJson = apiV2->authData.toJson();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
apiV2->apiConfig.userCountryCode,
"",
apiV2->serviceType(),
"",
authDataJson };
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
apiPayload[apiDefs::key::subscriptionStatus] = getSubscriptionStatusForRenewal(apiV2->apiConfig);
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/account_info"), apiPayload, responseBody, isTestPurchase);
@@ -948,8 +1045,7 @@ ErrorCode SubscriptionController::getAccountInfo(const QString &serverId, QJsonO
return errorCode;
}
accountInfo = QJsonDocument::fromJson(responseBody).object();
accountInfo = QJsonDocument::fromJson(responseBody).object();
return ErrorCode::NoError;
}
@@ -966,13 +1062,20 @@ QFuture<QPair<ErrorCode, QString>> SubscriptionController::getRenewalLink(const
}
bool isTestPurchase = apiV2->apiConfig.isTestPurchase;
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, apiV2->apiConfig.userCountryCode)
.addField(apiDefs::key::serviceType, apiV2->serviceType())
.addField(apiDefs::key::authData, apiV2->authData.toJson())
.addField(apiDefs::key::cliVersion, QString(APP_VERSION))
.addField(apiDefs::key::subscriptionStatus, getSubscriptionStatusForRenewal(apiV2->apiConfig))
.build();
QJsonObject authDataJson = apiV2->authData.toJson();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
apiV2->apiConfig.userCountryCode,
"",
apiV2->serviceType(),
"",
authDataJson };
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
apiPayload[apiDefs::key::subscriptionStatus] = getSubscriptionStatusForRenewal(apiV2->apiConfig);
auto gatewayController = QSharedPointer<GatewayController>::create(m_appSettingsRepository->getGatewayEndpoint(isTestPurchase),
m_appSettingsRepository->isDevGatewayEnv(isTestPurchase),
@@ -1008,14 +1111,21 @@ ErrorCode SubscriptionController::resolveImportServiceCaptcha(const QString &use
const QString &captchaSolution,
CaptchaInfo *retryCaptchaOut)
{
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::userCountryCode, userCountryCode)
.addField(apiDefs::key::serviceType, serviceType)
.addField(apiDefs::key::serviceProtocol, serviceProtocol)
.addField(apiDefs::key::publicKey, publicKeyForProtocol(serviceProtocol, protocolData))
.addField(apiDefs::key::captchaId, captchaId)
.addField(apiDefs::key::captchaSolution, normalizeCaptchaSolution(captchaSolution))
.build();
GatewayRequestData gatewayRequestData{QSysInfo::productType(),
QString(APP_VERSION),
m_appSettingsRepository->getAppLanguage().name().split("_").first(),
m_appSettingsRepository->getInstallationUuid(true),
userCountryCode,
"",
serviceType,
serviceProtocol,
QJsonObject()};
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload);
apiPayload["captcha_id"] = captchaId;
apiPayload["captcha_solution"] = normalizeCaptchaSolution(captchaSolution);
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody);

View File

@@ -27,6 +27,21 @@ public:
QString xrayUuid;
};
struct GatewayRequestData
{
QString osVersion;
QString appVersion;
QString appLanguage;
QString installationUuid;
QString userCountryCode;
QString serverCountryCode;
QString serviceType;
QString serviceProtocol;
QJsonObject authData;
QJsonObject toJsonObject() const;
};
struct CaptchaInfo {
QString captchaId;
QString captchaImageBase64;
@@ -38,8 +53,7 @@ public:
SecureAppSettingsRepository* appSettingsRepository);
ProtocolData generateProtocolData(const QString &protocol);
static QString publicKeyForProtocol(const QString &protocol, const ProtocolData &protocolData);
void appendProtocolDataToApiPayload(const QString &protocol, const ProtocolData &protocolData, QJsonObject &apiPayload);
ErrorCode importServiceFromGateway(const QString &userCountryCode, const QString &serviceType,
const QString &serviceProtocol, const ProtocolData &protocolData,

View File

@@ -29,6 +29,7 @@ ConnectionController::ConnectionController(SecureServersRepository* serversRepos
m_vpnConnection(vpnConnection)
{
connect(m_vpnConnection, &VpnConnection::connectionStateChanged, this, &ConnectionController::connectionStateChanged);
connect(m_vpnConnection, &VpnConnection::systemWoke, this, &ConnectionController::systemWoke);
connect(this, &ConnectionController::openConnectionRequested, m_vpnConnection, &VpnConnection::connectToVpn, Qt::QueuedConnection);
connect(this, &ConnectionController::closeConnectionRequested, m_vpnConnection, &VpnConnection::disconnectFromVpn, Qt::QueuedConnection);
connect(this, &ConnectionController::killSwitchModeChangedRequested, m_vpnConnection, &VpnConnection::onKillSwitchModeChanged, Qt::QueuedConnection);

View File

@@ -65,6 +65,7 @@ public:
signals:
void connectionStateChanged(Vpn::ConnectionState state);
void systemWoke();
void openConnectionRequested(const QString &serverId, DockerContainer container, const QJsonObject &vpnConfiguration);
void closeConnectionRequested();
void killSwitchModeChangedRequested(bool enabled);

View File

@@ -10,7 +10,6 @@
#include "core/controllers/coreSignalHandlers.h"
#include "logger.h"
#include "secureQSettings.h"
#include "core/utils/appUiConfig.h"
#if defined(Q_OS_ANDROID)
#include "core/utils/installedAppsImageProvider.h"
@@ -19,7 +18,7 @@
#if defined(Q_OS_IOS)
#include "platforms/ios/ios_controller.h"
#include "core/utils/swiftBridge.h"
#include <AmneziaVPN-Swift.h>
#endif
CoreController::CoreController(const QSharedPointer<VpnConnection> &vpnConnection, SecureQSettings* settings,
@@ -259,7 +258,7 @@ void CoreController::initAppleController()
{
#ifdef Q_OS_IOS
IosController::Instance()->initialize();
QTimer::singleShot(0, this, [this]() { SWIFT_BRIDGE_NAMESPACE::toggleScreenshots(m_appSettingsRepository->isScreenshotsEnabled()); });
QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_appSettingsRepository->isScreenshotsEnabled()); });
#endif
}
@@ -299,15 +298,15 @@ void CoreController::updateTranslator(const QLocale &locale)
}
QStringList availableTranslations;
QDirIterator it(":/translations", QStringList(APP_TS_PREFIX "_*.qm"), QDir::Files);
QDirIterator it(":/translations", QStringList("amneziavpn_*.qm"), QDir::Files);
while (it.hasNext()) {
availableTranslations << it.next();
}
// This code allow to load translation for the language only, without country code
const QString lang = locale.name().split("_").first();
const QString translationFilePrefix = QString(":/translations/" APP_TS_PREFIX "_") + lang;
QString strFileName = QString(":/translations/" APP_TS_PREFIX "_%1.qm").arg(locale.name());
const QString translationFilePrefix = QString(":/translations/amneziavpn_") + lang;
QString strFileName = QString(":/translations/amneziavpn_%1.qm").arg(locale.name());
for (const QString &translation : availableTranslations) {
if (translation.contains(translationFilePrefix)) {
strFileName = translation;
@@ -318,7 +317,7 @@ void CoreController::updateTranslator(const QLocale &locale)
if (m_translator->load(strFileName)) {
QCoreApplication::installTranslator(m_translator);
} else {
if (m_translator->load(QString(":/translations/" APP_TS_PREFIX "_en.qm"))) {
if (m_translator->load(QString(":/translations/amneziavpn_en.qm"))) {
QCoreApplication::installTranslator(m_translator);
}
}

View File

@@ -48,7 +48,7 @@
#ifdef Q_OS_IOS
#include "platforms/ios/ios_controller.h"
#include "core/utils/swiftBridge.h"
#include <AmneziaVPN-Swift.h>
#endif
CoreSignalHandlers::CoreSignalHandlers(CoreController* coreController, QObject* parent)
@@ -413,7 +413,7 @@ void CoreSignalHandlers::initIosImportHandler()
void CoreSignalHandlers::initIosSettingsHandler()
{
#ifdef Q_OS_IOS
connect(m_coreController->m_appSettingsRepository, &SecureAppSettingsRepository::screenshotsEnabledChanged, [](bool enabled) { SWIFT_BRIDGE_NAMESPACE::toggleScreenshots(enabled); });
connect(m_coreController->m_appSettingsRepository, &SecureAppSettingsRepository::screenshotsEnabledChanged, [](bool enabled) { AmneziaVPN::toggleScreenshots(enabled); });
#endif
}

View File

@@ -154,13 +154,8 @@ QString IpSplitTunnelingController::normalizeHostname(const QString &hostname) c
normalized.replace("https://", "");
normalized.replace("http://", "");
normalized.replace("ftp://", "");
if (NetworkUtilities::ipAddressWithSubnetRegExp().exactMatch(normalized)) {
return normalized;
}
const QStringList parts = normalized.split("/", Qt::SkipEmptyParts);
return parts.isEmpty() ? QString() : parts.first();
normalized = normalized.split("/", Qt::SkipEmptyParts).first();
return normalized;
}
bool IpSplitTunnelingController::validateHostname(const QString &hostname) const

View File

@@ -14,7 +14,6 @@
#include "core/models/selfhosted/selfHostedAdminServerConfig.h"
#include "core/models/containerConfig.h"
#include "core/models/protocolConfig.h"
#include "version.h"
using namespace amnezia;
@@ -221,10 +220,7 @@ ExportController::ExportResult ExportController::generateWireGuardConfig(const Q
result.config.append(line + "\n");
}
const QString qr = qrCodeUtils::generatePlainQrCodeImage(result.config.toUtf8());
if (!qr.isEmpty()) {
result.qrCodes << qr;
}
result.qrCodes << generateSingleQrCode(result.config.toUtf8());
return result;
}
@@ -255,10 +251,7 @@ ExportController::ExportResult ExportController::generateAwgConfig(const QString
result.config.append(line + "\n");
}
const QString qr = qrCodeUtils::generatePlainQrCodeImage(result.config.toUtf8());
if (!qr.isEmpty()) {
result.qrCodes << qr;
}
result.qrCodes << generateSingleQrCode(result.config.toUtf8());
return result;
}
@@ -344,7 +337,7 @@ ExportController::ExportResult ExportController::generateXrayConfig(const QStrin
// VlessServerObject doesn't have alpn field, so we embed in serverName if needed
}
result.nativeConfigString = amnezia::serialization::vless::Serialize(vlessServer, APPLICATION_NAME);
result.nativeConfigString = amnezia::serialization::vless::Serialize(vlessServer, "AmneziaVPN");
return result;
}
@@ -376,3 +369,9 @@ QList<QString> ExportController::generateQrCodesFromConfig(const QByteArray &dat
{
return qrCodeUtils::generateQrCodeImageSeries(data);
}
QString ExportController::generateSingleQrCode(const QByteArray &data)
{
auto qr = qrCodeUtils::generateQrCode(data);
return qrCodeUtils::svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
}

View File

@@ -69,6 +69,7 @@ private:
QString generateVpnUrl(const QByteArray &compressedConfig);
QList<QString> generateQrCodesFromConfig(const QByteArray &data);
QString generateSingleQrCode(const QByteArray &data);
SecureServersRepository* m_serversRepository;
SecureAppSettingsRepository* m_appSettingsRepository;

View File

@@ -511,10 +511,9 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data, Config
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
continue;
} else {
const qsizetype separatorIndex = trimmedLine.indexOf('=');
if (separatorIndex > 0) {
configMap[trimmedLine.left(separatorIndex).trimmed()] =
trimmedLine.mid(separatorIndex + 1).trimmed();
QStringList parts = trimmedLine.split(" = ");
if (parts.count() == 2) {
configMap[parts.at(0).trimmed()] = parts.at(1).trimmed();
}
}
}
@@ -567,9 +566,8 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data, Config
lastConfig[configKey::persistentKeepAlive] = configMap.value(protocols::wireguard::PersistentKeepalive);
}
const QStringList allowedIps = configMap.value(protocols::wireguard::AllowedIPs).split(
QRegularExpression("\\s*,\\s*"), Qt::SkipEmptyParts);
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(allowedIps);
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(
configMap.value(protocols::wireguard::AllowedIPs).split(", "));
lastConfig[configKey::allowedIps] = allowedIpsJsonArray;
@@ -637,24 +635,11 @@ QJsonObject ImportController::extractXrayConfig(const QString &data, ConfigTypes
{
QJsonParseError parserErr;
QJsonDocument jsonConf = QJsonDocument::fromJson(data.toLocal8Bit(), &parserErr);
if (parserErr.error != QJsonParseError::NoError || !jsonConf.isObject()) {
qDebug() << "Xray config JSON parse failed:" << parserErr.errorString();
return QJsonObject();
}
const QJsonObject parsedConfig = jsonConf.object();
if (!parsedConfig.value(protocols::xray::inbounds).isArray()
|| !parsedConfig.value(protocols::xray::outbounds).isArray()) {
qDebug() << "Xray config is missing inbounds or outbounds";
return QJsonObject();
}
const QString serializedConfig = QString::fromUtf8(jsonConf.toJson());
QJsonObject xrayVpnConfig;
xrayVpnConfig[configKey::config] = serializedConfig;
xrayVpnConfig[configKey::config] = jsonConf.toJson().constData();
QJsonObject lastConfig;
lastConfig[configKey::lastConfig] = serializedConfig;
lastConfig[configKey::lastConfig] = jsonConf.toJson().constData();
lastConfig[configKey::isThirdPartyConfig] = true;
QJsonObject containers;

View File

@@ -201,6 +201,9 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
SshSession sshSession;
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
if (container == DockerContainer::Xray || container == DockerContainer::SSXray) {
reinstallRequired = true;
}
qDebug() << "InstallController::updateServerConfig for container" << container << "reinstall required is" << reinstallRequired;
ErrorCode errorCode = ErrorCode::NoError;
@@ -213,7 +216,7 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
awgConfig->serverConfig.protocolVersion = protocols::awg::awgV3;
}
}
} else if (container != DockerContainer::Xray && container != DockerContainer::SSXray) {
} else {
errorCode = configureContainerWorker(credentials, container, newConfig, sshSession);
if (errorCode == ErrorCode::NoError) {
errorCode = startupContainerWorker(credentials, container, newConfig, sshSession);

View File

@@ -8,7 +8,7 @@
#include "core/models/serverDescription.h"
#if defined(Q_OS_IOS) || defined(MACOS_NE)
#include "core/utils/swiftBridge.h"
#include <AmneziaVPN-Swift.h>
#endif

View File

@@ -351,6 +351,16 @@ void SettingsController::setAppLanguage(const QLocale &locale)
m_appSettingsRepository->setAppLanguage(locale);
}
bool SettingsController::isPremV1MigrationReminderActive() const
{
return m_appSettingsRepository->isPremV1MigrationReminderActive();
}
void SettingsController::disablePremV1MigrationReminder()
{
m_appSettingsRepository->disablePremV1MigrationReminder();
}
QString SettingsController::nextAvailableServerName() const
{
return m_serversRepository->nextAvailableServerName();

View File

@@ -69,6 +69,9 @@ public:
void enableDevMode();
bool isPremV1MigrationReminderActive() const;
void disablePremV1MigrationReminder();
QString nextAvailableServerName() const;
bool isDevModeEnabled() const;

View File

@@ -5,13 +5,13 @@
#include <QUrl>
#include <QJsonDocument>
#include <QJsonObject>
#include <QSysInfo>
#include <QTimer>
#include "amneziaApplication.h"
#include "logger.h"
#include "version.h"
#include "core/controllers/gatewayController.h"
#include "core/utils/api/gatewayPayloadBuilder.h"
#include "core/utils/constants/apiKeys.h"
#include "core/utils/selfhosted/scriptsRegistry.h"
@@ -98,9 +98,10 @@ void UpdateController::fetchGatewayUrl()
m_appSettingsRepository->isStrictKillSwitchEnabled(),
m_appSettingsRepository);
QJsonObject apiPayload = GatewayPayloadBuilder(m_appSettingsRepository)
.addField(apiDefs::key::cliVersion, QString(APP_VERSION))
.build();
QJsonObject apiPayload;
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
apiPayload[apiDefs::key::osVersion] = QSysInfo::productType();
apiPayload[apiDefs::key::installationUuid] = m_appSettingsRepository->getInstallationUuid(true);
// Workaround: wait before contacting gateway to avoid rate limit triggered by other requests (news etc.)
QTimer::singleShot(1000, this, [this, gatewayController, apiPayload]() {

View File

@@ -78,8 +78,6 @@ void AwgInstaller::generateAwgParameters(AwgServerConfig &serverConfig)
serverConfig.rejectAfterTime = protocols::awg::defaultRejectAfterTime;
serverConfig.keepaliveTimeout = protocols::awg::defaultKeepaliveTimeout;
serverConfig.maxHandshakeAttempts = protocols::awg::defaultMaxHandshakeAttempts;
serverConfig.randomTrailers = protocols::awg::defaultRandomTrailers;
serverConfig.disableCookies = protocols::awg::defaultDisableCookies;
}
ErrorCode AwgInstaller::extractConfigFromContainer(DockerContainer container, const ServerCredentials &credentials,
@@ -146,8 +144,6 @@ ErrorCode AwgInstaller::extractConfigFromContainer(DockerContainer container, co
awgConfig->serverConfig.rejectAfterTime = serverConfigMap.value(configKey::rejectAfterTime);
awgConfig->serverConfig.keepaliveTimeout = serverConfigMap.value(configKey::keepaliveTimeout);
awgConfig->serverConfig.maxHandshakeAttempts = serverConfigMap.value(configKey::maxHandshakeAttempts);
awgConfig->serverConfig.randomTrailers = serverConfigMap.value(configKey::randomTrailers);
awgConfig->serverConfig.disableCookies = serverConfigMap.value(configKey::disableCookies);
awgConfig->serverConfig.protocolVersion = awgConfig->serverProtocolVersion();
}

View File

@@ -20,7 +20,7 @@ namespace amnezia
namespace
{
template <typename T>
bool hasAwg3Markers(const T &config)
QString awgVersionOf(const T &config)
{
auto hasValue = [](const QString &value) { return !value.trimmed().isEmpty(); };
@@ -29,19 +29,6 @@ namespace
config.rejectAfterTime, config.keepaliveTimeout,
config.maxHandshakeAttempts };
if (std::any_of(awg3Params.begin(), awg3Params.end(), hasValue)) {
return true;
}
return AwgProtocolConfig::isToggleEnabled(config.randomTrailers)
|| AwgProtocolConfig::isToggleEnabled(config.disableCookies);
}
template <typename T>
QString awgVersionOf(const T &config)
{
auto hasValue = [](const QString &value) { return !value.trimmed().isEmpty(); };
if (hasAwg3Markers(config)) {
return protocols::awg::awgV3;
}
@@ -147,12 +134,6 @@ QJsonObject AwgServerConfig::toJson() const
if (!maxHandshakeAttempts.isEmpty()) {
obj[configKey::maxHandshakeAttempts] = maxHandshakeAttempts;
}
if (!randomTrailers.isEmpty()) {
obj[configKey::randomTrailers] = randomTrailers;
}
if (!disableCookies.isEmpty()) {
obj[configKey::disableCookies] = disableCookies;
}
if (isThirdPartyConfig) {
obj[configKey::isThirdPartyConfig] = isThirdPartyConfig;
@@ -197,8 +178,6 @@ AwgServerConfig AwgServerConfig::fromJson(const QJsonObject& json)
config.rejectAfterTime = json.value(configKey::rejectAfterTime).toString();
config.keepaliveTimeout = json.value(configKey::keepaliveTimeout).toString();
config.maxHandshakeAttempts = json.value(configKey::maxHandshakeAttempts).toString();
config.randomTrailers = json.value(configKey::randomTrailers).toString();
config.disableCookies = json.value(configKey::disableCookies).toString();
config.isThirdPartyConfig = json.value(configKey::isThirdPartyConfig).toBool(false);
@@ -323,12 +302,6 @@ QJsonObject AwgClientConfig::toJson() const
if (!maxHandshakeAttempts.isEmpty()) {
obj[configKey::maxHandshakeAttempts] = maxHandshakeAttempts;
}
if (!randomTrailers.isEmpty()) {
obj[configKey::randomTrailers] = randomTrailers;
}
if (!disableCookies.isEmpty()) {
obj[configKey::disableCookies] = disableCookies;
}
return obj;
}
@@ -380,8 +353,6 @@ AwgClientConfig AwgClientConfig::fromJson(const QJsonObject& json)
config.rejectAfterTime = json.value(configKey::rejectAfterTime).toString();
config.keepaliveTimeout = json.value(configKey::keepaliveTimeout).toString();
config.maxHandshakeAttempts = json.value(configKey::maxHandshakeAttempts).toString();
config.randomTrailers = json.value(configKey::randomTrailers).toString();
config.disableCookies = json.value(configKey::disableCookies).toString();
return config;
}
@@ -424,16 +395,9 @@ QString AwgProtocolConfig::clientProtocolVersion() const
return clientConfig.has_value() ? awgVersionOf(clientConfig.value()) : QString();
}
bool AwgProtocolConfig::isToggleEnabled(const QString &value)
{
const QString trimmedValue = value.trimmed();
return !trimmedValue.isEmpty()
&& trimmedValue.compare(QLatin1String(protocols::awg::awgBoolOff), Qt::CaseInsensitive) != 0;
}
QString AwgProtocolConfig::protocolVersionString(const QString &version)
{
if (version == protocols::awg::awgV3) return QObject::tr(" (version 3.1)");
if (version == protocols::awg::awgV3) return QObject::tr(" (version 3)");
if (version == protocols::awg::awgV2) return QObject::tr(" (version 2)");
if (version == protocols::awg::awgV1_5) return QObject::tr(" (version 1.5)");
return "";
@@ -473,19 +437,13 @@ bool AwgServerConfig::hasEqualServerSettings(const AwgServerConfig& other) const
contentPaddingAddition != other.contentPaddingAddition ||
rekeyAfterTime != other.rekeyAfterTime || rekeyTimeout != other.rekeyTimeout ||
rejectAfterTime != other.rejectAfterTime || keepaliveTimeout != other.keepaliveTimeout ||
maxHandshakeAttempts != other.maxHandshakeAttempts ||
randomTrailers != other.randomTrailers || disableCookies != other.disableCookies) {
maxHandshakeAttempts != other.maxHandshakeAttempts) {
return false;
}
return true;
}
bool AwgServerConfig::hasAwg3Params() const
{
return hasAwg3Markers(*this);
}
bool AwgProtocolConfig::isHeadersEqual(const QString &h1, const QString &h2, const QString &h3, const QString &h4)
{
QSet<QString> uniqueHeaders;

View File

@@ -46,15 +46,12 @@ struct AwgServerConfig {
QString rejectAfterTime;
QString keepaliveTimeout;
QString maxHandshakeAttempts;
QString randomTrailers;
QString disableCookies;
bool isThirdPartyConfig = false;
QJsonObject toJson() const;
static AwgServerConfig fromJson(const QJsonObject& json);
bool hasEqualServerSettings(const AwgServerConfig& other) const;
bool hasAwg3Params() const;
};
struct AwgClientConfig {
@@ -93,8 +90,6 @@ struct AwgClientConfig {
QString rejectAfterTime;
QString keepaliveTimeout;
QString maxHandshakeAttempts;
QString randomTrailers;
QString disableCookies;
QJsonObject toJson() const;
static AwgClientConfig fromJson(const QJsonObject& json);
};
@@ -109,7 +104,6 @@ struct AwgProtocolConfig {
QString serverProtocolVersion() const;
QString clientProtocolVersion() const;
static QString protocolVersionString(const QString &version);
static bool isToggleEnabled(const QString &value);
bool hasClientConfig() const;
void setClientConfig(const AwgClientConfig& config);

View File

@@ -19,7 +19,6 @@ VpnProtocol::VpnProtocol(const QJsonObject &configuration, QObject *parent)
m_connectionState(Vpn::ConnectionState::Unknown),
m_rawConfig(configuration),
m_timeoutTimer(new QTimer(this)),
m_lastError(ErrorCode::NoError),
m_receivedBytes(0),
m_sentBytes(0)
{
@@ -36,6 +35,11 @@ void VpnProtocol::setLastError(ErrorCode lastError)
qCritical().noquote() << "VpnProtocol error, code" << m_lastError << errorString(m_lastError);
}
void VpnProtocol::recordLastError(ErrorCode lastError)
{
m_lastError = lastError;
}
ErrorCode VpnProtocol::lastError() const
{
return m_lastError;

View File

@@ -89,6 +89,10 @@ protected:
void startTimeoutTimer();
void stopTimeoutTimer();
// Remembers the error for lastError() without forcing the Error connection
// state, unlike setLastError().
void recordLastError(ErrorCode lastError);
Vpn::ConnectionState m_connectionState;
QString m_routeGateway;
@@ -99,7 +103,7 @@ protected:
private:
QTimer* m_timeoutTimer;
ErrorCode m_lastError;
ErrorCode m_lastError = ErrorCode::NoError;
quint64 m_receivedBytes;
quint64 m_sentBytes;
};

View File

@@ -1,4 +1,5 @@
#include <QCoreApplication>
#include <QDebug>
#include <QFileInfo>
#include <QProcess>
#include <QTcpSocket>
@@ -50,19 +51,39 @@ WireguardProtocol::~WireguardProtocol()
void WireguardProtocol::stop()
{
if (m_stopped) {
return;
}
m_stopped = true;
stopMzImpl();
return;
}
ErrorCode WireguardProtocol::startMzImpl()
{
QString protocolName = m_rawConfig.value("protocol").toString();
QJsonObject vpnConfigData = m_rawConfig.value(protocolName + "_config_data").toObject();
vpnConfigData[configKey::hostName] = NetworkUtilities::getIPAddress(vpnConfigData.value(configKey::hostName).toString());
m_rawConfig.insert(protocolName + "_config_data", vpnConfigData);
m_rawConfig[configKey::hostName] = NetworkUtilities::getIPAddress(m_rawConfig[configKey::hostName].toString());
const QString protocolName = m_rawConfig.value("protocol").toString();
const QString configDataKey = protocolName + "_config_data";
QJsonObject vpnConfigData = m_rawConfig.value(configDataKey).toObject();
m_impl->activate(m_rawConfig);
const QString endpointHost = vpnConfigData.value(configKey::hostName).toString();
const QString endpointIp = NetworkUtilities::getIPAddress(endpointHost);
if (endpointIp.isEmpty()) {
qWarning() << "WireguardProtocol: unable to resolve the endpoint host, aborting this attempt";
recordLastError(ErrorCode::EndpointResolutionError);
return ErrorCode::EndpointResolutionError;
}
// Activate a resolved copy: m_rawConfig must keep the original hostname so
// a later attempt (e.g. reconnect after wakeup) re-resolves it from scratch
// instead of reusing a stale — or empty — address.
QJsonObject rawConfig = m_rawConfig;
vpnConfigData[configKey::hostName] = endpointIp;
rawConfig.insert(configDataKey, vpnConfigData);
if (rawConfig.value(configKey::hostName).toString() == endpointHost) {
rawConfig[configKey::hostName] = endpointIp;
}
m_impl->activate(rawConfig);
return ErrorCode::NoError;
}
@@ -75,5 +96,6 @@ ErrorCode WireguardProtocol::stopMzImpl()
ErrorCode WireguardProtocol::start()
{
m_stopped = false;
return startMzImpl();
}

View File

@@ -28,6 +28,7 @@ public:
private:
QScopedPointer<ControllerImpl> m_impl;
bool m_stopped = false;
};
#endif // WIREGUARDPROTOCOL_H

View File

@@ -442,6 +442,16 @@ void SecureAppSettingsRepository::disableHomeAdLabel()
setValue("Conf/homeAdLabelVisible", false);
}
bool SecureAppSettingsRepository::isPremV1MigrationReminderActive() const
{
return value("Conf/premV1MigrationReminderActive", true).toBool();
}
void SecureAppSettingsRepository::disablePremV1MigrationReminder()
{
setValue("Conf/premV1MigrationReminderActive", false);
}
QByteArray SecureAppSettingsRepository::backupAppConfig() const
{
return m_settings->backupAppConfig();

View File

@@ -90,6 +90,8 @@ public:
bool isHomeAdLabelVisible() const;
void disableHomeAdLabel();
bool isPremV1MigrationReminderActive() const;
void disablePremV1MigrationReminder();
QByteArray backupAppConfig() const;
bool restoreAppConfig(const QByteArray &cfg);
void clearSettings();

View File

@@ -1,6 +1,5 @@
#include "apiUtils.h"
#include "core/repositories/secureAppSettingsRepository.h"
#include "core/utils/serverConfigUtils.h"
#include "core/utils/constants/configKeys.h"
#include <QDateTime>
@@ -49,30 +48,6 @@ namespace
}
}
QString apiUtils::getAppLanguageCode(const SecureAppSettingsRepository *appSettingsRepository)
{
if (appSettingsRepository == nullptr) {
return {};
}
return appSettingsRepository->getAppLanguage().name().split("_").first();
}
QString apiUtils::getDistributionChannel()
{
#if defined(Q_OS_ANDROID)
return {};
#elif defined(Q_OS_IOS) || defined(MACOS_NE)
return QStringLiteral("appstore");
#else
return QStringLiteral("github");
#endif
}
QString apiUtils::getCountryFlagCode(const QString &serverCountryCode)
{
return serverCountryCode.section('-', 0, 0).toUpper();
}
bool apiUtils::isSubscriptionExpired(const QString &subscriptionEndDate)
{
if (subscriptionEndDate.isEmpty()) {
@@ -192,6 +167,44 @@ bool apiUtils::isPremiumServer(const QJsonObject &serverConfigObject)
return premiumTypes.contains(serverConfigUtils::configTypeFromJson(serverConfigObject));
}
QString apiUtils::getPremiumV1VpnKey(const QJsonObject &serverConfigObject)
{
if (serverConfigUtils::configTypeFromJson(serverConfigObject) != serverConfigUtils::ConfigType::AmneziaPremiumV1) {
return {};
}
QList<QPair<QString, QVariant>> orderedFields;
orderedFields.append(qMakePair(configKey::name, serverConfigObject[configKey::name].toString()));
orderedFields.append(qMakePair(configKey::description, serverConfigObject[configKey::description].toString()));
orderedFields.append(qMakePair(configKey::configVersion, serverConfigObject[configKey::configVersion].toDouble()));
orderedFields.append(qMakePair(apiDefs::key::protocol, serverConfigObject[apiDefs::key::protocol].toString()));
orderedFields.append(qMakePair(apiDefs::key::apiEndpoint, serverConfigObject[apiDefs::key::apiEndpoint].toString()));
orderedFields.append(qMakePair(apiDefs::key::apiKey, serverConfigObject[apiDefs::key::apiKey].toString()));
QString vpnKeyStr = "{";
for (int i = 0; i < orderedFields.size(); ++i) {
const auto &pair = orderedFields[i];
if (pair.second.typeId() == QMetaType::Type::QString) {
vpnKeyStr += "\"" + pair.first + "\": \"" + pair.second.toString() + "\"";
} else if (pair.second.typeId() == QMetaType::Type::Double || pair.second.typeId() == QMetaType::Type::Int) {
vpnKeyStr += "\"" + pair.first + "\": " + QString::number(pair.second.toDouble(), 'f', 1);
}
if (i < orderedFields.size() - 1) {
vpnKeyStr += ", ";
}
}
vpnKeyStr += "}";
QByteArray vpnKeyCompressed = escapeUnicode(vpnKeyStr).toUtf8();
vpnKeyCompressed = qCompress(vpnKeyCompressed, 6);
vpnKeyCompressed = vpnKeyCompressed.mid(4);
QByteArray signedData = AMNEZIA_CONFIG_SIGNATURE + vpnKeyCompressed;
return QString("vpn://%1").arg(QString(signedData.toBase64(QByteArray::Base64UrlEncoding)));
}
QString apiUtils::getPremiumV2VpnKey(const QJsonObject &serverConfigObject)
{
auto configType = serverConfigUtils::configTypeFromJson(serverConfigObject);

View File

@@ -11,18 +11,8 @@
#include "core/utils/routeModes.h"
#include "core/utils/commonStructs.h"
class SecureAppSettingsRepository;
namespace apiUtils
{
QString getAppLanguageCode(const SecureAppSettingsRepository *appSettingsRepository);
QString getDistributionChannel();
// The gateway may report a country code with a region suffix, e.g. "us-west", while flag
// resources are named after the ISO 3166-1 alpha-2 code alone. Returns the part before the dash
// in upper case.
QString getCountryFlagCode(const QString &serverCountryCode);
bool isSubscriptionExpired(const QString &subscriptionEndDate);
bool isSubscriptionExpiringSoon(const QString &subscriptionEndDate, int withinDays = 30);
@@ -33,6 +23,7 @@ namespace apiUtils
const QNetworkReply::NetworkError &replyError, const int httpStatusCode,
const QByteArray &responseBody);
QString getPremiumV1VpnKey(const QJsonObject &serverConfigObject);
QString getPremiumV2VpnKey(const QJsonObject &serverConfigObject);
}

View File

@@ -1,62 +0,0 @@
#include "gatewayPayloadBuilder.h"
#include <QJsonArray>
#include <QSysInfo>
#include "core/repositories/secureAppSettingsRepository.h"
#include "core/utils/api/apiUtils.h"
#include "core/utils/constants/apiKeys.h"
#include "version.h"
namespace
{
bool isEmptyValue(const QJsonValue &value)
{
switch (value.type()) {
case QJsonValue::Null:
case QJsonValue::Undefined:
return true;
case QJsonValue::String:
return value.toString().isEmpty();
case QJsonValue::Object:
return value.toObject().isEmpty();
case QJsonValue::Array:
return value.toArray().isEmpty();
default:
return false;
}
}
}
GatewayPayloadBuilder::GatewayPayloadBuilder(const SecureAppSettingsRepository *appSettingsRepository)
{
m_payload[apiDefs::key::osVersion] = QSysInfo::productType();
m_payload[apiDefs::key::appVersion] = QString(APP_VERSION);
m_payload[apiDefs::key::cliName] = QString(APPLICATION_NAME);
const QString distributionChannel = apiUtils::getDistributionChannel();
if (!distributionChannel.isEmpty()) {
m_payload[apiDefs::key::distribution] = distributionChannel;
}
if (appSettingsRepository == nullptr) {
qWarning() << "SecureAppSettingsRepository is null, skip app language and installation uuid";
return;
}
m_payload[apiDefs::key::appLanguage] = apiUtils::getAppLanguageCode(appSettingsRepository);
m_payload[apiDefs::key::installationUuid] = appSettingsRepository->getInstallationUuid(true);
}
GatewayPayloadBuilder &GatewayPayloadBuilder::addField(QLatin1String key, const QJsonValue &value)
{
if (!isEmptyValue(value)) {
m_payload[key] = value;
}
return *this;
}
QJsonObject GatewayPayloadBuilder::build() const
{
return m_payload;
}

View File

@@ -1,22 +0,0 @@
#ifndef GATEWAYPAYLOADBUILDER_H
#define GATEWAYPAYLOADBUILDER_H
#include <QJsonObject>
#include <QJsonValue>
#include <QLatin1String>
class SecureAppSettingsRepository;
class GatewayPayloadBuilder
{
public:
explicit GatewayPayloadBuilder(const SecureAppSettingsRepository *appSettingsRepository);
GatewayPayloadBuilder &addField(QLatin1String key, const QJsonValue &value);
QJsonObject build() const;
private:
QJsonObject m_payload;
};
#endif // GATEWAYPAYLOADBUILDER_H

View File

@@ -1,15 +0,0 @@
#ifndef APP_UI_CONFIG_H
#define APP_UI_CONFIG_H
#define APP_INSTANCE_NAME "@CLIENT_APP_INSTANCE_NAME@"
#define APP_QML_ENTRYPOINT "@CLIENT_QML_ENTRYPOINT@"
#define APP_QML_IMPORT_PATH "@CLIENT_QML_IMPORT_PATH@"
#define APP_QML_PAGES_PREFIX "@CLIENT_QML_PAGES_PREFIX@"
#define APP_UI_FONT_RESOURCE "@CLIENT_UI_FONT_RESOURCE@"
#define APP_TS_PREFIX "@CLIENT_TS_PREFIX@"
#define APP_NOTIFICATION_IDENTIFIER "@CLIENT_NOTIFICATION_IDENTIFIER@"
#define APP_IOS_BUNDLE_ID "@CLIENT_IOS_BUNDLE_ID@"
#define APP_IOS_STORE_URL_FALLBACK "@CLIENT_IOS_STORE_URL_FALLBACK@"
#define APP_ANDROID_PACKAGE "@CLIENT_ANDROID_PACKAGE@"
#endif

View File

@@ -23,7 +23,6 @@ namespace apiDefs
constexpr QLatin1String installationUuid("installation_uuid");
constexpr QLatin1String uuid("installation_uuid");
constexpr QLatin1String osVersion("os_version");
constexpr QLatin1String distribution("distribution");
constexpr QLatin1String userCountryCode("user_country_code");
constexpr QLatin1String serverCountryCode("server_country_code");
constexpr QLatin1String serverCountryName("server_country_name");
@@ -41,10 +40,6 @@ namespace apiDefs
constexpr QLatin1String lastDownloaded("last_downloaded");
constexpr QLatin1String sourceType("source_type");
constexpr QLatin1String appLanguage("app_language");
constexpr QLatin1String locale("locale");
constexpr QLatin1String captchaId("captcha_id");
constexpr QLatin1String captchaSolution("captcha_solution");
constexpr QLatin1String activeDeviceCount("active_device_count");
constexpr QLatin1String maxDeviceCount("max_device_count");
@@ -67,6 +62,7 @@ namespace apiDefs
constexpr QLatin1String id("id");
constexpr QLatin1String orderId("order_id");
constexpr QLatin1String migrationCode("migration_code");
constexpr QLatin1String transactionId("transaction_id");
constexpr QLatin1String isTestPurchase("is_test_purchase");
constexpr QLatin1String isInAppPurchase("is_in_app_purchase");

View File

@@ -100,8 +100,6 @@ namespace amnezia
constexpr QLatin1String rejectAfterTime("RejectAfterTime");
constexpr QLatin1String keepaliveTimeout("KeepaliveTimeout");
constexpr QLatin1String maxHandshakeAttempts("MaxHandshakeAttempts");
constexpr QLatin1String randomTrailers("RandomTrailers");
constexpr QLatin1String disableCookies("DisableCookies");
inline QStringList awgProtocolKeys()
{
@@ -127,9 +125,7 @@ namespace amnezia
rekeyTimeout,
rejectAfterTime,
keepaliveTimeout,
maxHandshakeAttempts,
randomTrailers,
disableCookies };
maxHandshakeAttempts };
}
constexpr QLatin1String openvpn("openvpn");

View File

@@ -204,7 +204,7 @@ namespace amnezia
constexpr char awgV1_5[] = "1.5";
constexpr char awgV2[] = "2";
constexpr char awgV3[] = "3.1";
constexpr char awgV3[] = "3";
constexpr char defaultContentPaddingAddition[] = "10-100";
constexpr char defaultRekeyAfterTime[] = "100-120";
@@ -213,10 +213,6 @@ namespace amnezia
constexpr char defaultKeepaliveTimeout[] = "5-15";
constexpr char defaultMaxHandshakeAttempts[] = "15-20";
constexpr char defaultPersistentKeepAlive[] = "25-35";
constexpr char defaultRandomTrailers[] = "on";
constexpr char defaultDisableCookies[] = "on";
constexpr char awgBoolOn[] = "on";
constexpr char awgBoolOff[] = "off";
}

View File

@@ -112,7 +112,8 @@ QMap<DockerContainer, QString> ContainerUtils::containerDescriptions()
QObject::tr("Replace the current DNS server with your own. This will increase your privacy level.") },
{ DockerContainer::Sftp,
QObject::tr("Create a file vault on your server to securely store and transfer files.") },
{ DockerContainer::Socks5Proxy, ("") },
{ DockerContainer::Socks5Proxy,
QObject::tr("") },
{ DockerContainer::MtProxy,
QObject::tr("Telegram MTProto proxy server") },
{ DockerContainer::Telemt,

View File

@@ -68,6 +68,7 @@ namespace amnezia
OpenVpnUnknownError = 701,
OpenVpnTapAdapterError = 702,
AddressPoolError = 703,
EndpointResolutionError = 704,
// 3rd party utils errors
OpenSslFailed = 800,
@@ -97,6 +98,7 @@ namespace amnezia
ApiServicesMissingError = 1107,
ApiConfigLimitError = 1108,
ApiNotFoundError = 1109,
ApiMigrationError = 1110,
ApiUpdateRequestError = 1111,
ApiSubscriptionExpiredError = 1112,
ApiPurchaseError = 1113,

View File

@@ -66,6 +66,7 @@ QString errorString(ErrorCode code) {
case (ErrorCode::OpenVpnAdaptersInUseError): errorMessage = QObject::tr("Can't connect: another VPN connection is active"); break;
case (ErrorCode::OpenVpnTapAdapterError): errorMessage = QObject::tr("Can't setup OpenVPN TAP network adapter"); break;
case (ErrorCode::AddressPoolError): errorMessage = QObject::tr("VPN pool error: no available addresses"); break;
case (ErrorCode::EndpointResolutionError): errorMessage = QObject::tr("Failed to resolve the VPN server address"); break;
case (ErrorCode::ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break;
case (ErrorCode::ImportBackupFileUseRestoreInstead): errorMessage = QObject::tr("Backup files cannot be imported here. Use 'Restore from backup' instead."); break;
@@ -89,6 +90,7 @@ QString errorString(ErrorCode code) {
case (ErrorCode::ApiServicesMissingError): errorMessage = QObject::tr("Missing list of available services"); break;
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;
case (ErrorCode::ApiSubscriptionExpiredError): errorMessage = QObject::tr("Your Amnezia Premium subscription has expired.\n Please check your email for renewal instructions.\n If you haven't received an email, please contact our support."); break;
case (ErrorCode::ApiPurchaseError): errorMessage = QObject::tr("Unable to process purchase"); break;

View File

@@ -53,8 +53,7 @@ QRegularExpression NetworkUtilities::ipAddressRegExp()
QRegExp NetworkUtilities::ipAddressWithSubnetRegExp()
{
return QRegExp("(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}"
"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])"
"(\\/(?:[0-9]|[1-2][0-9]|3[0-2])){0,1}");
"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(\\/[0-9]{1,2}){0,1}");
}
QRegExp NetworkUtilities::ipNetwork24RegExp()
@@ -79,16 +78,12 @@ QString NetworkUtilities::netMaskFromIpWithSubnet(const QString ip)
if (!ip.contains("/"))
return "255.255.255.255";
const QStringList parts = ip.split("/");
if (parts.size() < 2)
return "255.255.255.255";
bool ok;
int prefix = parts.at(1).toInt(&ok);
if (!ok || prefix < 0 || prefix > 32)
int prefix = ip.split("/").at(1).toInt(&ok);
if (!ok)
return "255.255.255.255";
const quint32 mask = prefix == 0 ? 0 : 0xFFFFFFFFu << (32 - prefix);
unsigned long mask = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF;
return QString("%1.%2.%3.%4").arg(mask >> 24).arg((mask >> 16) & 0xFF).arg((mask >> 8) & 0xFF).arg(mask & 0xFF);
}

View File

@@ -1,8 +1,5 @@
#include "qrCodeUtils.h"
#include <cmath>
#include <QDataStream>
#include <QIODevice>
#include <QList>
@@ -19,7 +16,7 @@ QList<QString> qrCodeUtils::generateQrCodeImageSeries(const QByteArray &data)
QByteArray ba = chunk.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(ba.constData(), qrcodegen::QrCode::Ecc::LOW);
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(ba, qrcodegen::QrCode::Ecc::LOW);
QString svg = QString::fromStdString(toSvgString(qr, 1));
chunks.append(svgToBase64(svg));
}
@@ -29,13 +26,9 @@ QList<QString> qrCodeUtils::generateQrCodeImageSeries(const QByteArray &data)
QString qrCodeUtils::generatePlainQrCodeImage(const QByteArray &data)
{
try {
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(data.constData(), qrcodegen::QrCode::Ecc::LOW);
QString svg = QString::fromStdString(toSvgString(qr, 1));
return svgToBase64(svg);
} catch (const qrcodegen::data_too_long &) {
return {};
}
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(data, qrcodegen::QrCode::Ecc::LOW);
QString svg = QString::fromStdString(toSvgString(qr, 1));
return svgToBase64(svg);
}
QString qrCodeUtils::svgToBase64(const QString &image)
@@ -45,5 +38,5 @@ QString qrCodeUtils::svgToBase64(const QString &image)
qrcodegen::QrCode qrCodeUtils::generateQrCode(const QByteArray &data)
{
return qrcodegen::QrCode::encodeText(data.constData(), qrcodegen::QrCode::Ecc::LOW);
return qrcodegen::QrCode::encodeText(data, qrcodegen::QrCode::Ecc::LOW);
}

View File

@@ -1,8 +1,6 @@
#ifndef QRCODEUTILS_H
#define QRCODEUTILS_H
#include <QByteArray>
#include <QList>
#include <QString>
#include "qrcodegen.hpp"

View File

@@ -255,8 +255,9 @@ amnezia::ScriptVars amnezia::genAwgVars(const ContainerConfig &containerConfig)
vars.append({ { "$SPECIAL_JUNK_4", config.specialJunk4 } });
vars.append({ { "$SPECIAL_JUNK_5", config.specialJunk5 } });
vars.append({ { "$PERSISTENT_KEEPALIVE", config.hasAwg3Params() ? QString(protocols::awg::defaultPersistentKeepAlive)
: QString(protocols::wireguard::defaultPersistentKeepAlive) } });
const bool isAwg3 = config.protocolVersion == protocols::awg::awgV3;
vars.append({ { "$PERSISTENT_KEEPALIVE", isAwg3 ? QString(protocols::awg::defaultPersistentKeepAlive)
: QString(protocols::wireguard::defaultPersistentKeepAlive) } });
vars.append({ { "$HEADER_PROTECTION_KEY", config.headerProtectionKey } });
vars.append({ { "$CONTENT_PADDING_ADDITION", config.contentPaddingAddition } });
@@ -265,10 +266,6 @@ amnezia::ScriptVars amnezia::genAwgVars(const ContainerConfig &containerConfig)
vars.append({ { "$REJECT_AFTER_TIME", config.rejectAfterTime } });
vars.append({ { "$KEEPALIVE_TIMEOUT", config.keepaliveTimeout } });
vars.append({ { "$MAX_HANDSHAKE_ATTEMPTS", config.maxHandshakeAttempts } });
vars.append({ { "$RANDOM_TRAILERS", AwgProtocolConfig::isToggleEnabled(config.randomTrailers)
? config.randomTrailers : QString() } });
vars.append({ { "$DISABLE_COOKIES", AwgProtocolConfig::isToggleEnabled(config.disableCookies)
? config.disableCookies : QString() } });
}
return vars;

View File

@@ -1,25 +0,0 @@
#ifndef SWIFTBRIDGE_H
#define SWIFTBRIDGE_H
#if defined(Q_OS_IOS) || defined(MACOS_NE)
#include "core/utils/swiftBridgeConfig.h"
#ifndef SWIFT_BRIDGE_OBJC_HEADER
#ifdef AMNEZIA_SWIFT_OBJC_HEADER
#define SWIFT_BRIDGE_OBJC_HEADER AMNEZIA_SWIFT_OBJC_HEADER
#else
#define SWIFT_BRIDGE_OBJC_HEADER "AmneziaVPN-Swift.h"
#endif
#endif
#ifndef SWIFT_BRIDGE_NAMESPACE
#ifdef AMNEZIA_SWIFT_NAMESPACE
#define SWIFT_BRIDGE_NAMESPACE AMNEZIA_SWIFT_NAMESPACE
#else
#define SWIFT_BRIDGE_NAMESPACE AmneziaVPN
#endif
#endif
#include SWIFT_BRIDGE_OBJC_HEADER
#endif
#endif

View File

@@ -1,7 +0,0 @@
#ifndef SWIFT_BRIDGE_CONFIG_H
#define SWIFT_BRIDGE_CONFIG_H
#define SWIFT_BRIDGE_OBJC_HEADER "@CLIENT_SWIFT_OBJC_HEADER_NAME@"
#define SWIFT_BRIDGE_NAMESPACE @CLIENT_SWIFT_MODULE_NAME@
#endif

View File

@@ -464,12 +464,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
if (const auto maxHandshakeAttempts = obj.value("MaxHandshakeAttempts"); !maxHandshakeAttempts.isUndefined()) {
config.m_maxHandshakeAttempts = maxHandshakeAttempts.toString();
}
if (const auto randomTrailers = obj.value("RandomTrailers"); !randomTrailers.isUndefined()) {
config.m_randomTrailers = randomTrailers.toString();
}
if (const auto disableCookies = obj.value("DisableCookies"); !disableCookies.isUndefined()) {
config.m_disableCookies = disableCookies.toString();
}
return true;
}
@@ -643,7 +637,7 @@ void Daemon::checkHandshake() {
pendingHandshakes++;
}
}
// Check again if there were connections that haven't completed a handshake.
if (pendingHandshakes > 0) {
m_handshakeTimer.start(HANDSHAKE_POLL_MSEC);

View File

@@ -179,12 +179,6 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
if (!m_maxHandshakeAttempts.isEmpty()) {
out << "MaxHandshakeAttempts = " << m_maxHandshakeAttempts << "\n";
}
if (!m_randomTrailers.isEmpty()) {
out << "RandomTrailers = " << m_randomTrailers << "\n";
}
if (!m_disableCookies.isEmpty()) {
out << "DisableCookies = " << m_disableCookies << "\n";
}
// If any extra config was provided, append it now.
for (const QString& key : extra.keys()) {
@@ -212,13 +206,3 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
return content;
}
QString InterfaceConfig::awgBoolToUapi(const QString& value) {
const QString v = value.trimmed().toLower();
if (v == QLatin1String("on") || v == QLatin1String("1") ||
v == QLatin1String("true") || v == QLatin1String("t") ||
v == QLatin1String("yes")) {
return QStringLiteral("1");
}
return QStringLiteral("0");
}

View File

@@ -66,16 +66,10 @@ class InterfaceConfig {
QString m_rejectAfterTime;
QString m_keepaliveTimeout;
QString m_maxHandshakeAttempts;
QString m_randomTrailers;
QString m_disableCookies;
QJsonObject toJson() const;
QString toWgConf(
const QMap<QString, QString>& extra = QMap<QString, QString>()) const;
// Converts awg-quick on/off (and 0/1/true/false) to UAPI 1/0.
// amneziawg-go uses strconv.ParseBool and rejects "on"/"off".
static QString awgBoolToUapi(const QString& value);
};
#endif // INTERFACECONFIG_H

View File

@@ -31,7 +31,7 @@
<key>LSSupportsOpeningDocumentsInPlace</key>
<false/>
<key>UILaunchStoryboardName</key>
<string>${CLIENT_IOS_LAUNCHSCREEN_NAME}</string>
<string>AmneziaVPNLaunchScreen</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
@@ -70,11 +70,11 @@
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>com.wireguard.ios.app_group_id</key>
<string>${BUILD_IOS_GROUP_IDENTIFIER}</string>
<string>group.org.amnezia.AmneziaVPN</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>${CLIENT_APPLICATION_NAME} needs access to the camera for reading QR-codes.</string>
<string>Amnezia VPN needs access to the camera for reading QR-codes.</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
@@ -116,11 +116,11 @@
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>${CLIENT_APPLICATION_NAME} config</string>
<string>Amnezia VPN config</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>${BUILD_IOS_APP_IDENTIFIER}.amnezia-config</string>
<string>org.amnezia.AmneziaVPN.amnezia-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
@@ -143,7 +143,7 @@
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>${BUILD_IOS_APP_IDENTIFIER}.wireguard-config</string>
<string>org.amnezia.AmneziaVPN.wireguard-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
@@ -167,7 +167,7 @@
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>${BUILD_IOS_APP_IDENTIFIER}.openvpn-config</string>
<string>org.amnezia.AmneziaVPN.openvpn-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
@@ -186,11 +186,11 @@
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>${CLIENT_APPLICATION_NAME} backup file</string>
<string>AmneziaVPN backup file</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>${BUILD_IOS_APP_IDENTIFIER}.backup-config</string>
<string>org.amnezia.AmneziaVPN.backup-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
@@ -208,15 +208,15 @@
<array>
<dict>
<key>CFBundleTypeName</key>
<string>${CLIENT_APPLICATION_NAME} config</string>
<string>Amnezia VPN config</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>${BUILD_IOS_APP_IDENTIFIER}.amnezia-config</string>
<string>${BUILD_IOS_APP_IDENTIFIER}.wireguard-config</string>
<string>${BUILD_IOS_APP_IDENTIFIER}.openvpn-config</string>
<string>${BUILD_IOS_APP_IDENTIFIER}.backup-config</string>
<string>org.amnezia.AmneziaVPN.amnezia-config</string>
<string>org.amnezia.AmneziaVPN.wireguard-config</string>
<string>org.amnezia.AmneziaVPN.openvpn-config</string>
<string>org.amnezia.AmneziaVPN.backup-config</string>
</array>
</dict>
</array>

View File

@@ -2,24 +2,24 @@ enable_language(Swift)
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
add_executable(${CLIENT_IOS_NE_TARGET_NAME})
set_target_properties(${CLIENT_IOS_NE_TARGET_NAME} PROPERTIES
add_executable(networkextension)
set_target_properties(networkextension PROPERTIES
XCODE_PRODUCT_TYPE com.apple.product-type.app-extension
BUNDLE_EXTENSION appex
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
MACOSX_BUNDLE_INFO_STRING "${CLIENT_NETWORK_EXTENSION_NAME}"
MACOSX_BUNDLE_BUNDLE_NAME "${CLIENT_NETWORK_EXTENSION_NAME}"
MACOSX_BUNDLE_INFO_STRING "AmneziaVPNNetworkExtension"
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPNNetworkExtension"
MACOSX_BUNDLE_GUI_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}.network-extension"
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}.network-extension"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CLIENT_IOS_NE_ENTITLEMENTS_PATH}
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/AmneziaVPNNetworkExtension.entitlements
XCODE_ATTRIBUTE_MARKETING_VERSION "${APP_MAJOR_VERSION}"
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
XCODE_ATTRIBUTE_PRODUCT_NAME "${CLIENT_NETWORK_EXTENSION_NAME}"
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPNNetworkExtension"
XCODE_ATTRIBUTE_APPLICATION_EXTENSION_API_ONLY "YES"
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
@@ -30,20 +30,20 @@ set_target_properties(${CLIENT_IOS_NE_TARGET_NAME} PROPERTIES
)
if(DEPLOY)
set_target_properties(${CLIENT_IOS_NE_TARGET_NAME} PROPERTIES
set_target_properties(networkextension 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 "${CLIENT_IOS_NE_PROVISIONING_PROFILE_SPECIFIER}"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "${CLIENT_IOS_NE_PROVISIONING_PROFILE_SPECIFIER_DEBUG}"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr ios.org.amnezia.AmneziaVPN"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev ios.org.amnezia.AmneziaVPN"
)
else()
set_target_properties(${CLIENT_IOS_NE_TARGET_NAME} PROPERTIES
set_target_properties(networkextension PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic
)
endif()
set_target_properties(${CLIENT_IOS_NE_TARGET_NAME} PROPERTIES
set_target_properties(networkextension PROPERTIES
XCODE_ATTRIBUTE_SWIFT_VERSION "5.0"
XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES"
XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/WireGuardNetworkExtension-Bridging-Header.h"
@@ -51,8 +51,8 @@ set_target_properties(${CLIENT_IOS_NE_TARGET_NAME} PROPERTIES
XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO"
)
set_target_properties("${CLIENT_IOS_NE_TARGET_NAME}" PROPERTIES
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${BUILD_VPN_DEVELOPMENT_TEAM}"
set_target_properties("networkextension" PROPERTIES
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK"
)
find_library(FW_ASSETS_LIBRARY AssetsLibrary)
@@ -60,17 +60,17 @@ find_library(FW_MOBILE_CORE MobileCoreServices)
find_library(FW_UI_KIT UIKit)
find_library(FW_LIBRESOLV libresolv.9.tbd)
target_link_libraries(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE ${FW_ASSETS_LIBRARY})
target_link_libraries(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE ${FW_MOBILE_CORE})
target_link_libraries(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE ${FW_UI_KIT})
target_link_libraries(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE ${FW_LIBRESOLV})
target_link_libraries(networkextension PRIVATE ${FW_ASSETS_LIBRARY})
target_link_libraries(networkextension PRIVATE ${FW_MOBILE_CORE})
target_link_libraries(networkextension PRIVATE ${FW_UI_KIT})
target_link_libraries(networkextension PRIVATE ${FW_LIBRESOLV})
target_compile_options(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
target_compile_options(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE -DNETWORK_EXTENSION=1)
target_compile_options(networkextension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
target_compile_options(networkextension PRIVATE -DNETWORK_EXTENSION=1)
set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/amneziawg-apple/Sources)
target_sources(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE
target_sources(networkextension PRIVATE
${WG_APPLE_SOURCE_DIR}/WireGuardKit/WireGuardAdapter.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/PacketTunnelSettingsGenerator.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/DNSResolver.swift
@@ -93,7 +93,6 @@ target_sources(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE
${CLIENT_ROOT_DIR}/platforms/ios/HevSocksTunnel.swift
${CLIENT_ROOT_DIR}/platforms/ios/NELogController.swift
${CLIENT_ROOT_DIR}/platforms/ios/Log.swift
${CLIENT_GROUP_IDENTIFIER_SWIFT_FILE}
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+WireGuard.swift
@@ -104,16 +103,16 @@ target_sources(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE
${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm
)
target_sources(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE
target_sources(networkextension PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
)
set_property(TARGET ${CLIENT_IOS_NE_TARGET_NAME} APPEND PROPERTY RESOURCE
set_property(TARGET networkextension APPEND PROPERTY RESOURCE
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
)
target_include_directories(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE ${CLIENT_ROOT_DIR})
target_include_directories(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(networkextension PRIVATE ${CLIENT_ROOT_DIR})
target_include_directories(networkextension PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
find_package(openvpnadapter REQUIRED)
# FIXME(ygurov): https://github.com/conan-io/conan/issues/20034
@@ -121,10 +120,10 @@ set_property(TARGET amnezia::openvpnadapter APPEND PROPERTY IMPORTED_CONFIGURATI
set_property(TARGET amnezia::openvpnadapter APPEND PROPERTY IMPORTED_CONFIGURATIONS MINSIZEREL)
set_property(TARGET amnezia::openvpnadapter APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_property(TARGET amnezia::openvpnadapter APPEND PROPERTY IMPORTED_CONFIGURATIONS RELWITHDEBINFO)
target_link_libraries(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE amnezia::openvpnadapter)
target_link_libraries(networkextension PRIVATE amnezia::openvpnadapter)
find_package(awg-apple REQUIRED)
target_link_libraries(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE amnezia::awg-apple)
target_link_libraries(networkextension PRIVATE amnezia::awg-apple)
find_package(hev-socks5-tunnel REQUIRED)
# FIXME(ygurov): https://github.com/conan-io/conan/issues/20034
@@ -132,4 +131,4 @@ set_property(TARGET heiher::hev-socks5-tunnel APPEND PROPERTY IMPORTED_CONFIGURA
set_property(TARGET heiher::hev-socks5-tunnel APPEND PROPERTY IMPORTED_CONFIGURATIONS MINSIZEREL)
set_property(TARGET heiher::hev-socks5-tunnel APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_property(TARGET heiher::hev-socks5-tunnel APPEND PROPERTY IMPORTED_CONFIGURATIONS RELWITHDEBINFO)
target_link_libraries(${CLIENT_IOS_NE_TARGET_NAME} PRIVATE heiher::hev-socks5-tunnel)
target_link_libraries(networkextension PRIVATE heiher::hev-socks5-tunnel)

View File

@@ -38,9 +38,9 @@
</dict>
<key>com.wireguard.ios.app_group_id</key>
<string>${BUILD_IOS_GROUP_IDENTIFIER}</string>
<string>group.${BUILD_IOS_APP_IDENTIFIER}</string>
<key>com.wireguard.macos.app_group_id</key>
<string>${BUILD_VPN_DEVELOPMENT_TEAM}.${BUILD_IOS_GROUP_IDENTIFIER}</string>
<string>${BUILD_VPN_DEVELOPMENT_TEAM}.group.${BUILD_OSX_APP_IDENTIFIER}</string>
</dict>
</plist>

View File

@@ -34,9 +34,9 @@
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>com.wireguard.ios.app_group_id</key>
<string>${BUILD_IOS_GROUP_IDENTIFIER}</string>
<string>group.org.amnezia.AmneziaVPN</string>
<key>NSCameraUsageDescription</key>
<string>${CLIENT_APPLICATION_NAME} needs access to the camera for reading QR-codes.</string>
<string>Amnezia VPN needs access to the camera for reading QR-codes.</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
@@ -66,11 +66,11 @@
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>${CLIENT_APPLICATION_NAME} config</string>
<string>Amnezia VPN config</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>${BUILD_OSX_APP_IDENTIFIER}.amnezia-config</string>
<string>org.amnezia.AmneziaVPN.amnezia-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
@@ -93,7 +93,7 @@
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>${BUILD_OSX_APP_IDENTIFIER}.wireguard-config</string>
<string>org.amnezia.AmneziaVPN.wireguard-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
@@ -117,7 +117,7 @@
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>${BUILD_OSX_APP_IDENTIFIER}.openvpn-config</string>
<string>org.amnezia.AmneziaVPN.openvpn-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
@@ -136,11 +136,11 @@
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>${CLIENT_APPLICATION_NAME} backup file</string>
<string>AmneziaVPN backup file</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>${BUILD_OSX_APP_IDENTIFIER}.backup-config</string>
<string>org.amnezia.AmneziaVPN.backup-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
@@ -158,15 +158,15 @@
<array>
<dict>
<key>CFBundleTypeName</key>
<string>${CLIENT_APPLICATION_NAME} config</string>
<string>Amnezia VPN config</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>${BUILD_OSX_APP_IDENTIFIER}.amnezia-config</string>
<string>${BUILD_OSX_APP_IDENTIFIER}.wireguard-config</string>
<string>${BUILD_OSX_APP_IDENTIFIER}.openvpn-config</string>
<string>${BUILD_OSX_APP_IDENTIFIER}.backup-config</string>
<string>org.amnezia.AmneziaVPN.amnezia-config</string>
<string>org.amnezia.AmneziaVPN.wireguard-config</string>
<string>org.amnezia.AmneziaVPN.openvpn-config</string>
<string>org.amnezia.AmneziaVPN.backup-config</string>
</array>
</dict>
</array>
@@ -180,6 +180,5 @@
</dict>
</array>
${CLIENT_MACOS_EXTRA_PLIST_ENTRIES}
</dict>
</plist>

View File

@@ -1,27 +1,22 @@
enable_language(Swift)
message("Client message >> macos build >> ${CLIENT_MACOS_NE_TARGET_NAME}")
message("Client message >> macos build >> AmneziaVPNNetworkExtension")
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
add_executable(${CLIENT_MACOS_NE_TARGET_NAME})
add_executable(AmneziaVPNNetworkExtension)
message("executable_path is: @executable_path/../../Frameworks")
# The plist is consumed by Xcode directly, so branding variables have to be
# substituted by CMake beforehand
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/Info.plist)
set_target_properties(${CLIENT_MACOS_NE_TARGET_NAME} PROPERTIES
set_target_properties(AmneziaVPNNetworkExtension PROPERTIES
XCODE_PRODUCT_TYPE com.apple.product-type.app-extension
BUNDLE_EXTENSION appex
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}.network-extension"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CLIENT_MACOS_NE_ENTITLEMENTS_PATH}
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/AmneziaVPNNetworkExtension.entitlements
XCODE_ATTRIBUTE_MARKETING_VERSION "${APP_MAJOR_VERSION}"
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
XCODE_ATTRIBUTE_PRODUCT_NAME "${CLIENT_NETWORK_EXTENSION_NAME}"
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPNNetworkExtension"
XCODE_ATTRIBUTE_APPLICATION_EXTENSION_API_ONLY "YES"
XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_BINARY_DIR}/Info.plist
XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../../../../Frameworks @loader_path/../../../../Frameworks"
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
@@ -29,20 +24,20 @@ set_target_properties(${CLIENT_MACOS_NE_TARGET_NAME} PROPERTIES
if(DEPLOY)
message("DEPLOY is ON")
set_target_properties(${CLIENT_MACOS_NE_TARGET_NAME} PROPERTIES
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 "${CLIENT_MACOS_NE_PROVISIONING_PROFILE_SPECIFIER}"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "${CLIENT_MACOS_NE_PROVISIONING_PROFILE_SPECIFIER_DEBUG}"
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(${CLIENT_MACOS_NE_TARGET_NAME} PROPERTIES
set_target_properties(AmneziaVPNNetworkExtension PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic
)
endif()
set_target_properties(${CLIENT_MACOS_NE_TARGET_NAME} PROPERTIES
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"
@@ -50,8 +45,8 @@ set_target_properties(${CLIENT_MACOS_NE_TARGET_NAME} PROPERTIES
XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO"
)
set_target_properties("${CLIENT_MACOS_NE_TARGET_NAME}" PROPERTIES
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${BUILD_VPN_DEVELOPMENT_TEAM}"
set_target_properties("AmneziaVPNNetworkExtension" PROPERTIES
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK"
)
find_library(FW_ASSETS_LIBRARY AssetsLibrary)
@@ -63,17 +58,17 @@ find_library(FW_LIBRESOLV libresolv.9.tbd)
# Set the root directory
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
target_link_libraries(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE ${FW_LIBRESOLV})
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${FW_LIBRESOLV})
target_compile_options(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
target_compile_options(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE -DNETWORK_EXTENSION=1)
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(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE
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
@@ -96,7 +91,6 @@ target_sources(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE
${CLIENT_ROOT_DIR}/platforms/ios/HevSocksTunnel.swift
${CLIENT_ROOT_DIR}/platforms/ios/NELogController.swift
${CLIENT_ROOT_DIR}/platforms/ios/Log.swift
${CLIENT_GROUP_IDENTIFIER_SWIFT_FILE}
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+WireGuard.swift
@@ -107,16 +101,16 @@ target_sources(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE
${CLIENT_ROOT_DIR}/platforms/ios/XrayConfig.swift
)
target_sources(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE
target_sources(AmneziaVPNNetworkExtension PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
)
set_property(TARGET ${CLIENT_MACOS_NE_TARGET_NAME} APPEND PROPERTY RESOURCE
set_property(TARGET AmneziaVPNNetworkExtension APPEND PROPERTY RESOURCE
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
)
target_include_directories(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE ${CLIENT_ROOT_DIR})
target_include_directories(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR})
target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
find_package(openvpnadapter REQUIRED)
# FIXME(ygurov): https://github.com/conan-io/conan/issues/20034
@@ -124,10 +118,10 @@ set_property(TARGET amnezia::openvpnadapter APPEND PROPERTY IMPORTED_CONFIGURATI
set_property(TARGET amnezia::openvpnadapter APPEND PROPERTY IMPORTED_CONFIGURATIONS MINSIZEREL)
set_property(TARGET amnezia::openvpnadapter APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_property(TARGET amnezia::openvpnadapter APPEND PROPERTY IMPORTED_CONFIGURATIONS RELWITHDEBINFO)
target_link_libraries(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE amnezia::openvpnadapter)
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE amnezia::openvpnadapter)
find_package(awg-apple REQUIRED)
target_link_libraries(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE amnezia::awg-apple)
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE amnezia::awg-apple)
find_package(hev-socks5-tunnel REQUIRED)
# FIXME(ygurov): https://github.com/conan-io/conan/issues/20034
@@ -135,4 +129,4 @@ set_property(TARGET heiher::hev-socks5-tunnel APPEND PROPERTY IMPORTED_CONFIGURA
set_property(TARGET heiher::hev-socks5-tunnel APPEND PROPERTY IMPORTED_CONFIGURATIONS MINSIZEREL)
set_property(TARGET heiher::hev-socks5-tunnel APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_property(TARGET heiher::hev-socks5-tunnel APPEND PROPERTY IMPORTED_CONFIGURATIONS RELWITHDEBINFO)
target_link_libraries(${CLIENT_MACOS_NE_TARGET_NAME} PRIVATE heiher::hev-socks5-tunnel)
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE heiher::hev-socks5-tunnel)

View File

@@ -5,14 +5,14 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${CLIENT_NETWORK_EXTENSION_NAME}</string>
<string>AmneziaVPNNetworkExtension</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${CLIENT_NETWORK_EXTENSION_NAME}</string>
<string>AmneziaVPNNetworkExtension</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
@@ -27,7 +27,7 @@
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>CFBundleDisplayName</key>
<string>${CLIENT_NETWORK_EXTENSION_NAME}</string>
<string>AmneziaVPNNetworkExtension</string>
<key>NSExtension</key>
<dict>
@@ -38,9 +38,9 @@
</dict>
<key>com.wireguard.ios.app_group_id</key>
<string>${BUILD_IOS_GROUP_IDENTIFIER}</string>
<string>group.org.amnezia.AmneziaVPN</string>
<key>com.wireguard.macos.app_group_id</key>
<string>$(DEVELOPMENT_TEAM).${BUILD_IOS_GROUP_IDENTIFIER}</string>
<string>$(DEVELOPMENT_TEAM).group.org.amnezia.AmneziaVPN</string>
</dict>
</plist>

View File

@@ -6,7 +6,6 @@
#include "amneziaApplication.h"
#include "core/utils/osSignalHandler.h"
#include "core/utils/migrations.h"
#include "core/utils/appUiConfig.h"
#include "version.h"
@@ -27,9 +26,9 @@ void anchorOpenSSL() {
bool isAnotherInstanceRunning()
{
QLocalSocket socket;
socket.connectToServer(APP_INSTANCE_NAME);
socket.connectToServer("AmneziaVPNInstance");
if (socket.waitForConnected(500)) {
qWarning() << APPLICATION_NAME << "is already running";
qWarning() << "AmneziaVPN is already running";
return true;
}
return false;

View File

@@ -76,7 +76,16 @@ void LocalSocketController::errorOccurred(
}
qCritical() << "ControllerError";
disconnectInternal();
// The socket to the daemon is gone (daemon restart/crash or a failed
// connection attempt). Unlike a plain tunnel-down message we cannot talk to
// the daemon anymore, so remember that and let the next activate()/
// deactivate() re-establish the connection instead of writing into a dead
// socket forever.
m_daemonState = eDisconnected;
m_initializingRetry = 0;
m_initializingTimer.stop();
emit disconnected();
}
void LocalSocketController::disconnectInternal() {
@@ -122,7 +131,38 @@ void LocalSocketController::daemonConnected() {
checkStatus();
}
bool LocalSocketController::isSocketAlive() const {
// ConnectingState counts as alive: on a fresh protocol activate() runs
// right after initialize(), before the connection (and the status
// handshake) completes — writes are buffered by the socket, and the daemon
// processes them once the connection is established.
const QLocalSocket::LocalSocketState state = m_socket->state();
return state == QLocalSocket::ConnectedState ||
state == QLocalSocket::ConnectingState;
}
void LocalSocketController::reconnectToDaemon() {
if (m_daemonState == eInitializing) {
// A connection attempt is already in progress.
return;
}
if (isSocketAlive()) {
return;
}
logger.warning() << "Daemon socket is not connected; reconnecting";
m_initializingRetry = 0;
initializeInternal();
}
void LocalSocketController::activate(const QJsonObject &rawConfig) {
if (!isSocketAlive()) {
logger.error() << "Cannot activate, daemon connection is not ready";
reconnectToDaemon();
emit disconnected();
return;
}
QString protocolName = rawConfig.value("protocol").toString();
int splitTunnelType = rawConfig.value("splitTunnelType").toInt();
@@ -267,8 +307,9 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
void LocalSocketController::deactivate() {
logger.debug() << "Deactivating";
if (m_daemonState != eReady) {
if (m_daemonState != eReady || !isSocketAlive()) {
logger.debug() << "No disconnect, controller is not ready";
reconnectToDaemon();
emit disconnected();
return;
}
@@ -334,7 +375,12 @@ void LocalSocketController::readData() {
logger.debug() << "Reading";
Q_ASSERT(m_socket);
Q_ASSERT(m_daemonState == eInitializing || m_daemonState == eReady);
if (m_daemonState != eInitializing && m_daemonState != eReady) {
// Stray data delivered around a socket teardown — nothing to do with it.
m_socket->readAll();
m_buffer.clear();
return;
}
QByteArray input = m_socket->readAll();
m_buffer.append(input);

View File

@@ -39,6 +39,8 @@ class LocalSocketController final : public ControllerImpl {
private:
void initializeInternal();
void disconnectInternal();
void reconnectToDaemon();
bool isSocketAlive() const;
void daemonConnected();
void errorOccurred(QLocalSocket::LocalSocketError socketError);

View File

@@ -1,3 +0,0 @@
enum BuildConfig {
static let appGroupIdentifier = "@BUILD_IOS_GROUP_IDENTIFIER@"
}

View File

@@ -15,7 +15,7 @@ struct Log {
}
}
private static let appGroupID = BuildConfig.appGroupIdentifier
private static let appGroupID = "group.org.amnezia.AmneziaVPN"
static let appLogURL = {
let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupID)!

View File

@@ -92,7 +92,7 @@ extension PacketTunnelProvider {
}
}
} catch {
wg_log(.error, message: "Can't parse WG config: \(String(describing: error))")
wg_log(.error, message: "Can't parse WG config: \(error.localizedDescription)")
errorNotifier.notify(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
completionHandler(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
return

View File

@@ -4,8 +4,7 @@
#import "StoreKitController.h"
#import <StoreKit/StoreKit.h>
#include <QtCore/qglobal.h>
#import "core/utils/swiftBridge.h"
#import <AmneziaVPN-Swift.h>
#include <QtCore/QDebug>
#include <QtCore/QString>

View File

@@ -8,7 +8,6 @@ struct WGConfig: Decodable {
let specialJunk1, specialJunk2, specialJunk3, specialJunk4, specialJunk5: String?
let headerProtectionKey: String?
let contentPaddingAddition, rekeyAfterTime, rekeyTimeout, rejectAfterTime, keepaliveTimeout, maxHandshakeAttempts: String?
let randomTrailers, disableCookies: String?
let dns1: String
let dns2: String
let mtu: String
@@ -34,7 +33,6 @@ struct WGConfig: Decodable {
case rekeyAfterTime = "RekeyAfterTime", rekeyTimeout = "RekeyTimeout"
case rejectAfterTime = "RejectAfterTime", keepaliveTimeout = "KeepaliveTimeout"
case maxHandshakeAttempts = "MaxHandshakeAttempts"
case randomTrailers = "RandomTrailers", disableCookies = "DisableCookies"
case dns1
case dns2
case mtu
@@ -130,12 +128,6 @@ struct WGConfig: Decodable {
if let maxHandshakeAttempts = trimmed(maxHandshakeAttempts) {
settingsLines.append("MaxHandshakeAttempts = \(maxHandshakeAttempts)")
}
if let randomTrailers = trimmed(randomTrailers) {
settingsLines.append("RandomTrailers = \(randomTrailers)")
}
if let disableCookies = trimmed(disableCookies) {
settingsLines.append("DisableCookies = \(disableCookies)")
}
return settingsLines.joined(separator: "\n")
}

View File

@@ -4,8 +4,6 @@
#include "platforms/ios/iosnotificationhandler.h"
#include "core/utils/appUiConfig.h"
#import <UserNotifications/UserNotifications.h>
#import <Foundation/Foundation.h>
@@ -77,8 +75,7 @@ void IOSNotificationHandler::notify(NotificationHandler::Message type, const QSt
UNTimeIntervalNotificationTrigger* trigger =
[UNTimeIntervalNotificationTrigger triggerWithTimeInterval:timerSec repeats:NO];
UNNotificationRequest* request =
[UNNotificationRequest requestWithIdentifier:[NSString stringWithUTF8String:APP_NOTIFICATION_IDENTIFIER]
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"amneziavpn"
content:content
trigger:trigger];
@@ -160,8 +157,7 @@ void IOSNotificationHandler::notify(NotificationHandler::Message type, const QSt
UNTimeIntervalNotificationTrigger* trigger =
[UNTimeIntervalNotificationTrigger triggerWithTimeInterval:timerSec repeats:NO];
UNNotificationRequest* request =
[UNNotificationRequest requestWithIdentifier:[NSString stringWithUTF8String:APP_NOTIFICATION_IDENTIFIER]
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"amneziavpn"
content:content
trigger:trigger];

View File

@@ -7,10 +7,14 @@
#include <net/if.h>
#include <QDBusVariant>
#include <QNetworkInterface>
#include <QTimer>
#include <QtDBus/QtDBus>
#include "core/utils/networkUtilities.h"
#include "leakdetector.h"
#include "logger.h"
#include "router_linux.h"
constexpr const char* DBUS_RESOLVE_SERVICE = "org.freedesktop.resolve1";
constexpr const char* DBUS_RESOLVE_PATH = "/org/freedesktop/resolve1";
@@ -27,24 +31,56 @@ DnsUtilsLinux::DnsUtilsLinux(QObject* parent) : DnsUtils(parent) {
logger.debug() << "DnsUtilsLinux created.";
QDBusConnection conn = QDBusConnection::systemBus();
m_resolver = new QDBusInterface(DBUS_RESOLVE_SERVICE, DBUS_RESOLVE_PATH,
DBUS_RESOLVE_MANAGER, conn, this);
auto* watcher = new QDBusServiceWatcher(
DBUS_RESOLVE_SERVICE, conn,
QDBusServiceWatcher::WatchForRegistration |
QDBusServiceWatcher::WatchForUnregistration, this);
connect(watcher, &QDBusServiceWatcher::serviceRegistered,
this, &DnsUtilsLinux::onResolverRegistered);
connect(watcher, &QDBusServiceWatcher::serviceUnregistered,
this, &DnsUtilsLinux::onResolverUnregistered);
if (conn.interface()->isServiceRegistered(DBUS_RESOLVE_SERVICE)) {
onResolverRegistered();
}
}
void DnsUtilsLinux::onResolverRegistered() {
m_resolver.reset(new QDBusInterface(DBUS_RESOLVE_SERVICE, DBUS_RESOLVE_PATH,
DBUS_RESOLVE_MANAGER,
QDBusConnection::systemBus()));
logger.debug() << "systemd-resolved available, DNS resolver initialized";
if (!m_pendingIfname.isEmpty()) {
logger.debug() << "Re-applying DNS configuration for" << m_pendingIfname;
updateResolvers(m_pendingIfname, m_pendingResolvers);
}
}
void DnsUtilsLinux::onResolverUnregistered() {
logger.debug() << "systemd-resolved disappeared, dropping DNS resolver";
m_resolver.reset();
}
DnsUtilsLinux::~DnsUtilsLinux() {
MZ_COUNT_DTOR(DnsUtilsLinux);
for (auto iterator = m_linkDomains.constBegin();
iterator != m_linkDomains.constEnd(); ++iterator) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(iterator.key());
argumentList << QVariant::fromValue(iterator.value());
m_resolver->asyncCallWithArgumentList(QStringLiteral("SetLinkDomains"),
argumentList);
}
if (m_resolver) {
if (m_gatewayIfindex > 0)
setLinkDefaultRoute(m_gatewayIfindex, true);
if (m_ifindex > 0) {
m_resolver->asyncCall(QStringLiteral("RevertLink"), m_ifindex);
for (auto iterator = m_linkDomains.constBegin();
iterator != m_linkDomains.constEnd(); ++iterator) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(iterator.key());
argumentList << QVariant::fromValue(iterator.value());
m_resolver->asyncCallWithArgumentList(QStringLiteral("SetLinkDomains"),
argumentList);
}
if (m_ifindex > 0) {
m_resolver->asyncCall(QStringLiteral("RevertLink"), m_ifindex);
}
}
logger.debug() << "DnsUtilsLinux destroyed.";
@@ -52,19 +88,52 @@ DnsUtilsLinux::~DnsUtilsLinux() {
bool DnsUtilsLinux::updateResolvers(const QString& ifname,
const QList<QHostAddress>& resolvers) {
if (m_gatewayIfindex > 0) {
setLinkDefaultRoute(m_gatewayIfindex, true);
m_gatewayIfindex = 0;
}
const int previousIfindex = m_ifindex;
m_ifindex = if_nametoindex(qPrintable(ifname));
if (m_ifindex <= 0) {
logger.error() << "Unable to resolve ifindex for" << ifname;
return false;
}
m_pendingIfname = ifname;
m_pendingResolvers = resolvers;
if (!m_resolver) {
logger.debug() << "systemd-resolved not ready, queuing DNS configuration";
return true;
}
const int gwIdx = NetworkUtilities::getGatewayAndIface().second.index();
if (gwIdx > 0 && gwIdx != m_ifindex && gwIdx != m_gatewayIfindex) {
m_gatewayIfindex = gwIdx;
setLinkDefaultRoute(gwIdx, false);
}
setLinkDNS(m_ifindex, resolvers);
setLinkDefaultRoute(m_ifindex, true);
updateLinkDomains();
if (previousIfindex > 0 && previousIfindex != m_ifindex) {
m_resolver->callWithArgumentList(QDBus::Block, QStringLiteral("RevertLink"),
{QVariant::fromValue(previousIfindex)});
}
return true;
}
bool DnsUtilsLinux::restoreResolvers() {
m_pendingIfname.clear();
m_pendingResolvers.clear();
if (m_gatewayIfindex > 0) {
setLinkDefaultRoute(m_gatewayIfindex, true);
m_gatewayIfindex = 0;
}
for (auto iterator = m_linkDomains.constBegin();
iterator != m_linkDomains.constEnd(); ++iterator) {
setLinkDomains(iterator.key(), iterator.value());
@@ -72,7 +141,7 @@ bool DnsUtilsLinux::restoreResolvers() {
m_linkDomains.clear();
/* Revert the VPN interface's DNS configuration */
if (m_ifindex > 0) {
if (m_ifindex > 0 && m_resolver) {
QList<QVariant> argumentList = {QVariant::fromValue(m_ifindex)};
QDBusPendingReply<> reply = m_resolver->asyncCallWithArgumentList(
QStringLiteral("RevertLink"), argumentList);
@@ -90,13 +159,17 @@ bool DnsUtilsLinux::restoreResolvers() {
void DnsUtilsLinux::dnsCallCompleted(QDBusPendingCallWatcher* call) {
QDBusPendingReply<> reply = *call;
if (reply.isError()) {
logger.error() << "Error received from the DBus service";
logger.debug() << "DBus call failed (may be transient after systemd-resolved restart)";
logger.debug() << "Restarting resolved to clear its query backlog";
RouterLinux::Instance().flushDns();
scheduleRetry();
}
delete call;
}
void DnsUtilsLinux::setLinkDNS(int ifindex,
const QList<QHostAddress>& resolvers) {
if (!m_resolver) return;
QList<DnsResolver> resolverList;
char ifnamebuf[IF_NAMESIZE];
const char* ifname = if_indextoname(ifindex, ifnamebuf);
@@ -121,6 +194,7 @@ void DnsUtilsLinux::setLinkDNS(int ifindex,
void DnsUtilsLinux::setLinkDomains(int ifindex,
const QList<DnsLinkDomain>& domains) {
if (!m_resolver) return;
char ifnamebuf[IF_NAMESIZE];
const char* ifname = if_indextoname(ifindex, ifnamebuf);
if (ifname) {
@@ -144,6 +218,7 @@ void DnsUtilsLinux::setLinkDomains(int ifindex,
}
void DnsUtilsLinux::setLinkDefaultRoute(int ifindex, bool enable) {
if (!m_resolver) return;
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(ifindex);
argumentList << QVariant::fromValue(enable);
@@ -156,6 +231,7 @@ void DnsUtilsLinux::setLinkDefaultRoute(int ifindex, bool enable) {
}
void DnsUtilsLinux::updateLinkDomains() {
if (!m_resolver) return;
/* Get the list of search domains, and remove any others that might conspire
* to satisfy DNS resolution. Unfortunately, this is a pain because Qt doesn't
* seem to be able to demarshall complex property types.
@@ -174,11 +250,20 @@ void DnsUtilsLinux::updateLinkDomains() {
void DnsUtilsLinux::dnsDomainsReceived(QDBusPendingCallWatcher* call) {
QDBusPendingReply<QVariant> reply = *call;
call->deleteLater();
if (reply.isError()) {
logger.error() << "Error retrieving the DNS domains from the DBus service";
delete call;
// systemd-resolved may still be starting up after a restart — retry a few times
if (m_ifindex > 0 && m_domainRetries++ < 5) {
logger.debug() << "systemd-resolved not ready yet, retrying DNS setup ("
<< m_domainRetries << "/5)";
QTimer::singleShot(500, this, &DnsUtilsLinux::updateLinkDomains);
} else {
logger.warning() << "Failed to configure DNS after 5 retries";
m_domainRetries = 0;
}
return;
}
m_domainRetries = 0;
/* Update the state of the DNS domains */
m_linkDomains.clear();
@@ -204,9 +289,30 @@ void DnsUtilsLinux::dnsDomainsReceived(QDBusPendingCallWatcher* call) {
}
/* Add a root search domain for the new interface. */
QList<DnsLinkDomain> newlist = {root};
setLinkDomains(m_ifindex, newlist);
delete call;
if (m_ifindex > 0) {
setLinkDomains(m_ifindex, {root});
/* Disable DefaultRoute on the physical gateway so systemd-resolved
* routes all DNS through the VPN interface. */
const int gwIdx = NetworkUtilities::getGatewayAndIface().second.index();
if (gwIdx > 0 && gwIdx != m_ifindex && gwIdx != m_gatewayIfindex) {
m_gatewayIfindex = gwIdx;
setLinkDefaultRoute(gwIdx, false);
}
}
}
void DnsUtilsLinux::scheduleRetry() {
if (m_pendingIfname.isEmpty() || m_retryPending || m_domainRetries >= 5)
return;
m_retryPending = true;
++m_domainRetries;
logger.debug() << "Retrying full DNS setup (" << m_domainRetries << "/5)";
QTimer::singleShot(1000, this, [this]() {
m_retryPending = false;
if (!m_pendingIfname.isEmpty())
updateResolvers(m_pendingIfname, m_pendingResolvers);
});
}
static DnsMetatypeRegistrationProxy s_dnsMetatypeProxy;

View File

@@ -6,7 +6,12 @@
#define DNSUTILSLINUX_H
#include <QDBusInterface>
#include <QScopedPointer>
#include <QDBusPendingCallWatcher>
#include <QDBusServiceWatcher>
#include <QHostAddress>
#include <QList>
#include <QString>
#include "daemon/dnsutils.h"
#include "dbustypeslinux.h"
@@ -29,13 +34,22 @@ class DnsUtilsLinux final : public DnsUtils {
void updateLinkDomains();
private slots:
void onResolverRegistered();
void onResolverUnregistered();
void dnsCallCompleted(QDBusPendingCallWatcher*);
void dnsDomainsReceived(QDBusPendingCallWatcher*);
private:
void scheduleRetry();
int m_ifindex = 0;
int m_gatewayIfindex = 0;
int m_domainRetries = 0;
bool m_retryPending = false;
QMap<int, DnsLinkDomainList> m_linkDomains;
QDBusInterface* m_resolver = nullptr;
QScopedPointer<QDBusInterface> m_resolver;
QString m_pendingIfname;
QList<QHostAddress> m_pendingResolvers;
};
#endif // DNSUTILSLINUX_H

View File

@@ -189,6 +189,40 @@ void LinuxFirewall::uninstallAnchor(LinuxFirewall::IPVersion ip, const QString&
deleteChain(ip, actualChain, tableName);
}
QStringList LinuxFirewall::getDNSRules(const QStringList& servers)
{
QStringList result;
for (const QString& server : servers)
{
result << QStringLiteral("-o amn0+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server);
result << QStringLiteral("-o amn0+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server);
result << QStringLiteral("-o tun0+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server);
result << QStringLiteral("-o tun0+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server);
result << QStringLiteral("-o tun2+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server);
result << QStringLiteral("-o tun2+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server);
}
return result;
}
QStringList LinuxFirewall::getAllowRule(const QStringList& servers)
{
QStringList result;
for (const QString& server : servers)
{
result << QStringLiteral("-d %1 -j ACCEPT").arg(server);
}
return result;
}
QStringList LinuxFirewall::getBlockRule(const QStringList& servers)
{
QStringList result;
for (const QString& server : servers)
{
result << QStringLiteral("-d %1 -j REJECT").arg(server);
}
return result;
}
void LinuxFirewall::install()
@@ -258,8 +292,6 @@ void LinuxFirewall::install()
installAnchor(IPv4, QStringLiteral("110.allowNets"), {});
installAnchor(Both, QStringLiteral("400.allowPIA"), {});
installAnchor(Both, QStringLiteral("100.blockAll"), {
QStringLiteral("-j REJECT"),
});
@@ -423,33 +455,16 @@ void LinuxFirewall::updateDNSServers(const QStringList& servers)
static QStringList existingServers {};
existingServers = servers;
const QString chain = QStringLiteral("%1.320.allowDNS").arg(kAnchorName);
executeIptables(QStringLiteral("iptables"), {QStringLiteral("-F"), chain});
const QStringList ifaces = {
QStringLiteral("amn0+"), QStringLiteral("tun0+"), QStringLiteral("tun2+")
};
for (const QString& server : servers) {
for (const QString& iface : ifaces) {
executeIptables(QStringLiteral("iptables"),
{QStringLiteral("-A"), chain, QStringLiteral("-o"), iface,
QStringLiteral("-d"), server, QStringLiteral("-p"), QStringLiteral("udp"),
QStringLiteral("--dport"), QStringLiteral("53"), QStringLiteral("-j"), QStringLiteral("ACCEPT")});
executeIptables(QStringLiteral("iptables"),
{QStringLiteral("-A"), chain, QStringLiteral("-o"), iface,
QStringLiteral("-d"), server, QStringLiteral("-p"), QStringLiteral("tcp"),
QStringLiteral("--dport"), QStringLiteral("53"), QStringLiteral("-j"), QStringLiteral("ACCEPT")});
}
}
execute(QStringLiteral("iptables -F %1.320.allowDNS").arg(kAnchorName));
for (const QString& rule : getDNSRules(servers))
execute(QStringLiteral("iptables -A %1.320.allowDNS %2").arg(kAnchorName, rule));
}
void LinuxFirewall::updateAllowNets(const QStringList& servers)
{
const QString chain = QStringLiteral("%1.110.allowNets").arg(kAnchorName);
executeIptables(QStringLiteral("iptables"), {QStringLiteral("-F"), chain});
for (const QString& server : servers)
executeIptables(QStringLiteral("iptables"),
{QStringLiteral("-A"), chain, QStringLiteral("-d"), server,
QStringLiteral("-j"), QStringLiteral("ACCEPT")});
execute(QStringLiteral("iptables -F %1.110.allowNets").arg(kAnchorName));
for (const QString& rule : getAllowRule(servers))
execute(QStringLiteral("iptables -A %1.110.allowNets %2").arg(kAnchorName, rule));
}
void LinuxFirewall::updateBlockNets(const QStringList& servers)
@@ -457,12 +472,9 @@ void LinuxFirewall::updateBlockNets(const QStringList& servers)
static QStringList existingServers {};
existingServers = servers;
const QString chain = QStringLiteral("%1.120.blockNets").arg(kAnchorName);
executeIptables(QStringLiteral("iptables"), {QStringLiteral("-F"), chain});
for (const QString& server : servers)
executeIptables(QStringLiteral("iptables"),
{QStringLiteral("-A"), chain, QStringLiteral("-d"), server,
QStringLiteral("-j"), QStringLiteral("REJECT")});
execute(QStringLiteral("iptables -F %1.120.blockNets").arg(kAnchorName));
for (const QString& rule : getBlockRule(servers))
execute(QStringLiteral("iptables -A %1.120.blockNets %2").arg(kAnchorName, rule));
}
int waitForExitCode(QProcess& process)
@@ -490,25 +502,7 @@ int LinuxFirewall::execute(const QString &command, bool ignoreErrors)
logger.debug() << "(" << exitCode << ") $ " << command;
if (!out.isEmpty())
logger.info() << out;
if (!err.isEmpty())
logger.warning() << err;
return exitCode;
}
int LinuxFirewall::executeIptables(const QString &program, const QStringList &args, bool ignoreErrors)
{
QProcess p;
p.start(program, args, QProcess::ReadOnly);
p.closeWriteChannel();
int exitCode = waitForExitCode(p);
auto out = p.readAllStandardOutput().trimmed();
auto err = p.readAllStandardError().trimmed();
if ((exitCode != 0 || !err.isEmpty()) && !ignoreErrors)
logger.warning() << "(" << exitCode << ") $ " << program << args.join(QLatin1Char(' '));
if (!out.isEmpty())
logger.info() << out;
if (!err.isEmpty())
if (!err.isEmpty() && !ignoreErrors)
logger.warning() << err;
return exitCode;
}
@@ -520,14 +514,12 @@ void LinuxFirewall::setupTrafficSplitting()
logger.warning() << "net_cls cgroup v1 not available, traffic splitting disabled";
return;
}
execute(QStringLiteral(
"if ! grep -qE '^[0-9]+[[:space:]]+%1$' /etc/iproute2/rt_tables 2>/dev/null ; then "
"echo '200 %1' >> /etc/iproute2/rt_tables ; fi"
).arg(kRtableName));
auto cGroupDir = "/sys/fs/cgroup/net_cls/" BRAND_CODE "vpnexclusions/";
logger.info() << "Setting up cgroup in" << cGroupDir << "for traffic splitting";
logger.info() << "Should be setting up cgroup in" << cGroupDir << "for traffic splitting";
execute(QStringLiteral("if [ ! -d %1 ] ; then mkdir %1 ; sleep 0.1 ; echo %2 > %1/net_cls.classid ; fi").arg(cGroupDir).arg(kCGroupId));
// Set a rule with priority 100 (lower priority than local but higher than main/default, 0 is highest priority)
execute(QStringLiteral("if ! ip rule list | grep -q %1 ; then ip rule add from all fwmark %1 lookup %2 pri 100 ; fi").arg(kPacketTag, kRtableName));
@@ -536,7 +528,8 @@ void LinuxFirewall::setupTrafficSplitting()
void LinuxFirewall::teardownTrafficSplitting()
{
logger.info() << "Tearing down cgroup and routing rules";
execute(QStringLiteral("if ip rule list | grep -q %1; then ip rule del from all fwmark %1 lookup %2 2>/dev/null ; fi").arg(kPacketTag, kRtableName));
execute(QStringLiteral("ip route flush table %1 2>/dev/null || true").arg(kRtableName));
execute(QStringLiteral("if ip rule list | grep -q %1; then ip rule del from all fwmark %1 lookup %2 2> /dev/null ; fi").arg(kPacketTag, kRtableName));
execute(QStringLiteral("ip route flush table %1").arg(kRtableName), true);
execute(QStringLiteral("ip route flush cache"));
execute(QStringLiteral("sed -i '/%1/d' /etc/iproute2/rt_tables").arg(kRtableName));
}

View File

@@ -79,10 +79,12 @@ private:
static int unlinkChain(IPVersion ip, const QString& chain, const QString& parent, const QString& tableName = kFilterTable);
static void installAnchor(IPVersion ip, const QString& anchor, const QStringList& rules, const QString& tableName = kFilterTable, const FilterCallbackFunc& enableFunc = {}, const FilterCallbackFunc& disableFunc = {});
static void uninstallAnchor(IPVersion ip, const QString& anchor, const QString& tableName = kFilterTable);
static QStringList getDNSRules(const QStringList& servers);
static QStringList getAllowRule(const QStringList& servers);
static QStringList getBlockRule(const QStringList& servers);
static void setupTrafficSplitting();
static void teardownTrafficSplitting();
static int execute(const QString& command, bool ignoreErrors = false);
static int executeIptables(const QString& program, const QStringList& args, bool ignoreErrors = false);
private:
// Chain names
static QString kOutputChain, kRootChain, kPostRoutingChain, kPreRoutingChain;

View File

@@ -167,12 +167,6 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
if (!config.m_maxHandshakeAttempts.isEmpty()) {
out << "max_handshake_attempts=" << config.m_maxHandshakeAttempts << "\n";
}
if (!config.m_randomTrailers.isEmpty()) {
out << "random_trailers=" << InterfaceConfig::awgBoolToUapi(config.m_randomTrailers) << "\n";
}
if (!config.m_disableCookies.isEmpty()) {
out << "disable_cookies=" << InterfaceConfig::awgBoolToUapi(config.m_disableCookies) << "\n";
}
int err = uapiErrno(uapiCommand(message));
if (err != 0) {
@@ -269,7 +263,11 @@ bool WireguardUtilsLinux::updatePeer(const InterfaceConfig& config) {
// Exclude the server address, except for multihop exit servers.
if ((config.m_hopType != InterfaceConfig::MultiHopExit) &&
(m_rtmonitor != nullptr)) {
m_rtmonitor->addExclusionRoute(IPAddress(config.m_serverIpv4AddrIn));
if (!config.m_serverIpv4AddrIn.isEmpty() &&
!m_rtmonitor->addExclusionRoute(IPAddress(config.m_serverIpv4AddrIn))) {
logger.error() << "No gateway — cannot add server exclusion route";
return false;
}
m_rtmonitor->addExclusionRoute(IPAddress(config.m_serverIpv6AddrIn));
}

View File

@@ -37,7 +37,6 @@
enum NMState {
NM_STATE_UNKNOWN = 0,
NM_STATE_ASLEEP = 10,
NM_STATE_DISABLED = 10,
NM_STATE_DISCONNECTED = 20,
NM_STATE_DISCONNECTING = 30,
NM_STATE_CONNECTING = 40,
@@ -202,9 +201,18 @@ void LinuxNetworkWatcherWorker::NMStateChanged(quint32 state)
{
logger.debug() << "NMStateChanged " << state;
if (state == NM_STATE_ASLEEP || state == NM_STATE_DISABLED) {
// NM_STATE_ASLEEP means networking just went *down* (e.g. NM tearing
// interfaces down for suspend), not that the system woke up. Fire
// wakeup() on the transition back out of it, once NM starts doing
// anything again, rather than on entering it.
if (state == NM_STATE_ASLEEP) {
m_wasAsleep = true;
} else if (m_wasAsleep) {
m_wasAsleep = false;
emit wakeup();
} else if (state == NM_STATE_CONNECTED_GLOBAL) {
}
if (state == NM_STATE_CONNECTED_GLOBAL) {
emit networkChanged();
}
}

View File

@@ -39,6 +39,10 @@ class LinuxNetworkWatcherWorker final : public QObject {
// initialization. When a property of them changes, we check if the access
// point is active and unsecure.
QStringList m_devicePaths;
// Set on NM_STATE_ASLEEP, cleared when NetworkManager comes back. Guards
// wakeup() so it fires on the resume transition, not on going to sleep.
bool m_wasAsleep = false;
};
#endif // LINUXNETWORKWATCHERWORKER_H

View File

@@ -165,12 +165,6 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) {
if (!config.m_maxHandshakeAttempts.isEmpty()) {
out << "max_handshake_attempts=" << config.m_maxHandshakeAttempts << "\n";
}
if (!config.m_randomTrailers.isEmpty()) {
out << "random_trailers=" << InterfaceConfig::awgBoolToUapi(config.m_randomTrailers) << "\n";
}
if (!config.m_disableCookies.isEmpty()) {
out << "disable_cookies=" << InterfaceConfig::awgBoolToUapi(config.m_disableCookies) << "\n";
}
int err = uapiErrno(uapiCommand(message));
if (err != 0) {

View File

@@ -17,10 +17,7 @@ using namespace QKeychain;
namespace {
constexpr const char *settingsKeyTag = "settingsKeyTag";
constexpr const char *settingsIvTag = "settingsIvTag";
#ifndef CLIENT_KEYCHAIN_NAME_STR
#define CLIENT_KEYCHAIN_NAME_STR "AmneziaVPN-Keychain"
#endif
constexpr const char *keyChainName = CLIENT_KEYCHAIN_NAME_STR;
constexpr const char *keyChainName = "AmneziaVPN-Keychain";
}
SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent, bool enableEncryption)

View File

@@ -32,8 +32,6 @@ RekeyTimeout = $REKEY_TIMEOUT
RejectAfterTime = $REJECT_AFTER_TIME
KeepaliveTimeout = $KEEPALIVE_TIMEOUT
MaxHandshakeAttempts = $MAX_HANDSHAKE_ATTEMPTS
RandomTrailers = $RANDOM_TRAILERS
DisableCookies = $DISABLE_COOKIES
# I1 = $SPECIAL_JUNK_1
# I2 = $SPECIAL_JUNK_2
# I3 = $SPECIAL_JUNK_3

View File

@@ -25,8 +25,6 @@ RekeyTimeout = $REKEY_TIMEOUT
RejectAfterTime = $REJECT_AFTER_TIME
KeepaliveTimeout = $KEEPALIVE_TIMEOUT
MaxHandshakeAttempts = $MAX_HANDSHAKE_ATTEMPTS
RandomTrailers = $RANDOM_TRAILERS
DisableCookies = $DISABLE_COOKIES
[Peer]
PublicKey = $WIREGUARD_SERVER_PUBLIC_KEY

Some files were not shown because too many files have changed in this diff Show More