Merge pull request #45 from amnezia-vpn/ios-wireguard

Ios wireguard
This commit is contained in:
pokamest 2021-12-04 16:27:46 +03:00 committed by GitHub
commit 4c2941acf0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
182 changed files with 10563 additions and 309 deletions

25
.gitignore vendored
View file

@ -24,6 +24,30 @@ ui_*.h
Makefile* Makefile*
*build-* *build-*
# Qt-es
client/Debug-iphoneos/
client/.xcode/
client/.qmake.cache
client/.qmake.stash
client/*.pro.user
client/*.pro.user.*
client/*.qbs.user
client/*.qbs.user.*
client/*.moc
client/moc_*.cpp
client/qrc_*.cpp
client/ui_*.h
client/ui_*.cpp
client/Makefile*
client/*build-*
client/AmneziaVPN.xcodeproj
client/Debug-iphonesimulator/
client/amneziavpn_plugin_import.cpp
client/amneziavpn_qml_plugin_import.cpp
client/qmlcache_loader.cpp
client/rep_ipc_interface_replica.h
client/resources_qmlcache.qrc
# QtCreator # QtCreator
*.autosave *.autosave
@ -37,6 +61,7 @@ CMakeLists.txt.user*
# MACOS files # MACOS files
.DS_Store .DS_Store
client/.DS_Store
._.DS_Store ._.DS_Store
._* ._*
*.dmg *.dmg

3
.gitmodules vendored
View file

@ -4,3 +4,6 @@
[submodule "client/3rd/wireguard-tools"] [submodule "client/3rd/wireguard-tools"]
path = client/3rd/wireguard-tools path = client/3rd/wireguard-tools
url = https://github.com/WireGuard/wireguard-tools/ url = https://github.com/WireGuard/wireguard-tools/
[submodule "client/3rd/wireguard-apple"]
path = client/3rd/wireguard-apple
url = https://github.com/WireGuard/wireguard-apple

View file

@ -1,4 +1,4 @@
/* /*
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
* *
* Licensed under the OpenSSL license (the "License"). You may not use * Licensed under the OpenSSL license (the "License"). You may not use

View file

@ -58,9 +58,15 @@ ios: {
} }
} }
CONFIG(iphonesimulator, iphoneos|iphonesimulator) { CONFIG(iphonesimulator, iphoneos|iphonesimulator) {
INCLUDEPATH += $$PWD/ios/simulator INCLUDEPATH += $$PWD/ios/iphone
HEADERS += $$PWD/ios/simulator/botan_all.h HEADERS += $$PWD/ios/iphone/botan_all.h
SOURCES += $$PWD/ios/simulator/botan_all.cpp SOURCES += $$PWD/ios/iphone/botan_all.cpp
} }
# CONFIG(iphonesimulator, iphoneos|iphonesimulator) {
# INCLUDEPATH += $$PWD/ios/simulator
# HEADERS += $$PWD/ios/simulator/botan_all.h
# SOURCES += $$PWD/ios/simulator/botan_all.cpp
# }
} }

@ -0,0 +1 @@
Subproject commit 23618f994f17d8ad8f2f65d79b4a1e8a0830b334

247
client/AmneziaVPN-Swift.h Normal file
View file

@ -0,0 +1,247 @@
#ifndef AmneziaVPN_Swift_h
#define AmneziaVPN_Swift_h
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
#if !defined(__has_include)
# define __has_include(x) 0
#endif
#if !defined(__has_attribute)
# define __has_attribute(x) 0
#endif
#if !defined(__has_feature)
# define __has_feature(x) 0
#endif
#if !defined(__has_warning)
# define __has_warning(x) 0
#endif
#if __has_include(<swift/objc-prologue.h>)
# include <swift/objc-prologue.h>
#endif
#pragma clang diagnostic ignored "-Wauto-import"
#include <Foundation/Foundation.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#if !defined(SWIFT_TYPEDEFS)
# define SWIFT_TYPEDEFS 1
# if __has_include(<uchar.h>)
# include <uchar.h>
# elif !defined(__cplusplus)
typedef uint_least16_t char16_t;
typedef uint_least32_t char32_t;
# endif
typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
#endif
#if !defined(SWIFT_PASTE)
# define SWIFT_PASTE_HELPER(x, y) x##y
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
#endif
#if !defined(SWIFT_METATYPE)
# define SWIFT_METATYPE(X) Class
#endif
#if !defined(SWIFT_CLASS_PROPERTY)
# if __has_feature(objc_class_property)
# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
# else
# define SWIFT_CLASS_PROPERTY(...)
# endif
#endif
#if __has_attribute(objc_runtime_name)
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
#else
# define SWIFT_RUNTIME_NAME(X)
#endif
#if __has_attribute(swift_name)
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
#else
# define SWIFT_COMPILE_NAME(X)
#endif
#if __has_attribute(objc_method_family)
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
#else
# define SWIFT_METHOD_FAMILY(X)
#endif
#if __has_attribute(noescape)
# define SWIFT_NOESCAPE __attribute__((noescape))
#else
# define SWIFT_NOESCAPE
#endif
#if __has_attribute(ns_consumed)
# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed))
#else
# define SWIFT_RELEASES_ARGUMENT
#endif
#if __has_attribute(warn_unused_result)
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
# define SWIFT_WARN_UNUSED_RESULT
#endif
#if __has_attribute(noreturn)
# define SWIFT_NORETURN __attribute__((noreturn))
#else
# define SWIFT_NORETURN
#endif
#if !defined(SWIFT_CLASS_EXTRA)
# define SWIFT_CLASS_EXTRA
#endif
#if !defined(SWIFT_PROTOCOL_EXTRA)
# define SWIFT_PROTOCOL_EXTRA
#endif
#if !defined(SWIFT_ENUM_EXTRA)
# define SWIFT_ENUM_EXTRA
#endif
#if !defined(SWIFT_CLASS)
# if __has_attribute(objc_subclassing_restricted)
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# else
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# endif
#endif
#if !defined(SWIFT_RESILIENT_CLASS)
# if __has_attribute(objc_class_stub)
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub))
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME)
# else
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME)
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME)
# endif
#endif
#if !defined(SWIFT_PROTOCOL)
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
#endif
#if !defined(SWIFT_EXTENSION)
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
#endif
#if !defined(OBJC_DESIGNATED_INITIALIZER)
# if __has_attribute(objc_designated_initializer)
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
# else
# define OBJC_DESIGNATED_INITIALIZER
# endif
#endif
#if !defined(SWIFT_ENUM_ATTR)
# if defined(__has_attribute) && __has_attribute(enum_extensibility)
# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility)))
# else
# define SWIFT_ENUM_ATTR(_extensibility)
# endif
#endif
#if !defined(SWIFT_ENUM)
# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
# if __has_feature(generalized_swift_name)
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
# else
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility)
# endif
#endif
#if !defined(SWIFT_UNAVAILABLE)
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
#endif
#if !defined(SWIFT_UNAVAILABLE_MSG)
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
#endif
#if !defined(SWIFT_AVAILABILITY)
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
#endif
#if !defined(SWIFT_WEAK_IMPORT)
# define SWIFT_WEAK_IMPORT __attribute__((weak_import))
#endif
#if !defined(SWIFT_DEPRECATED)
# define SWIFT_DEPRECATED __attribute__((deprecated))
#endif
#if !defined(SWIFT_DEPRECATED_MSG)
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
#endif
#if __has_feature(attribute_diagnose_if_objc)
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
#else
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
#endif
#if !defined(IBSegueAction)
# define IBSegueAction
#endif
#if __has_feature(modules)
#if __has_warning("-Watimport-in-framework-header")
#pragma clang diagnostic ignored "-Watimport-in-framework-header"
#endif
@import Foundation;
@import ObjectiveC;
#endif
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
#if __has_warning("-Wpragma-clang-attribute")
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
#endif
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wnullability"
#if __has_attribute(external_source_symbol)
# pragma push_macro("any")
# undef any
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="AmneziaVPN",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
# pragma pop_macro("any")
#endif
@class NSString;
@class NSData;
enum ConnectionState : NSInteger;
@class NSDate;
@class NSNumber;
@class VPNIPAddressRange;
SWIFT_CLASS("_TtC10AmneziaVPN18IOSVpnProtocolImpl")
@interface IOSVpnProtocolImpl : NSObject
- (nonnull instancetype)initWithBundleID:(NSString * _Nonnull)bundleID privateKey:(NSData * _Nonnull)privateKey deviceIpv4Address:(NSString * _Nonnull)deviceIpv4Address deviceIpv6Address:(NSString * _Nonnull)deviceIpv6Address closure:(void (^ _Nonnull)(enum ConnectionState, NSDate * _Nullable))closure callback:(void (^ _Nonnull)(BOOL))callback OBJC_DESIGNATED_INITIALIZER;
- (void)connectWithDnsServer:(NSString * _Nonnull)dnsServer serverIpv6Gateway:(NSString * _Nonnull)serverIpv6Gateway serverPublicKey:(NSString * _Nonnull)serverPublicKey presharedKey:(NSString * _Nonnull)presharedKey serverIpv4AddrIn:(NSString * _Nonnull)serverIpv4AddrIn serverPort:(NSInteger)serverPort allowedIPAddressRanges:(NSArray<VPNIPAddressRange *> * _Nonnull)allowedIPAddressRanges ipv6Enabled:(Boolean)enabled reason:(NSInteger)reason failureCallback:(void (^ _Nonnull)(void))failureCallback;
- (void)disconnect;
- (void)checkStatusWithCallback:(void (^ _Nonnull)(NSString * _Nonnull, NSString * _Nonnull, NSString * _Nonnull))callback;
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
+ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable");
@end
typedef SWIFT_ENUM(NSInteger, ConnectionState, closed) {
ConnectionStateError = 0,
ConnectionStateConnected = 1,
ConnectionStateDisconnected = 2,
};
SWIFT_CLASS("_TtC10AmneziaVPN17VPNIPAddressRange")
@interface VPNIPAddressRange : NSObject
- (nonnull instancetype)initWithAddress:(NSString * _Nonnull)address networkPrefixLength:(uint8_t)networkPrefixLength isIpv6:(BOOL)isIpv6 OBJC_DESIGNATED_INITIALIZER;
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
+ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable");
@end
#if __has_attribute(external_source_symbol)
# pragma clang attribute pop
#endif
#pragma clang diagnostic pop
#endif /* AmneziaVPN_Swift_h */

39
client/Info.plist Normal file
View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${QMAKE_SHORT_VERSION}</string>
<key>CFBundleSignature</key>
<string>${QMAKE_PKGINFO_TYPEINFO}</string>
<key>CFBundleVersion</key>
<string>${QMAKE_FULL_VERSION}</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>${IPHONEOS_DEPLOYMENT_TARGET}</string>
<key>NOTE</key>
<string>This file was generated by Qt/QMake.</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,29 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "wireguard-go-version.h"
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include <stdbool.h>
#include <stdint.h>
#define WG_KEY_LEN (32)
#define WG_KEY_LEN_BASE64 (45)
#define WG_KEY_LEN_HEX (65)
void key_to_base64(char base64[WG_KEY_LEN_BASE64],
const uint8_t key[WG_KEY_LEN]);
bool key_from_base64(uint8_t key[WG_KEY_LEN], const char* base64);
void key_to_hex(char hex[WG_KEY_LEN_HEX], const uint8_t key[WG_KEY_LEN]);
bool key_from_hex(uint8_t key[WG_KEY_LEN], const char* hex);
bool key_eq(const uint8_t key1[WG_KEY_LEN], const uint8_t key2[WG_KEY_LEN]);
void write_msg_to_log(const char* tag, const char* msg);
#import "TargetConditionals.h"
#if TARGET_OS_OSX
# include <libproc.h>
#endif

View file

@ -70,6 +70,10 @@ HEADERS += \
utils.h \ utils.h \
vpnconnection.h \ vpnconnection.h \
protocols/vpnprotocol.h \ protocols/vpnprotocol.h \
logger.h \
loghandler.h \
loglevel.h \
constants.h
SOURCES += \ SOURCES += \
configurators/cloak_configurator.cpp \ configurators/cloak_configurator.cpp \
@ -120,6 +124,9 @@ SOURCES += \
utils.cpp \ utils.cpp \
vpnconnection.cpp \ vpnconnection.cpp \
protocols/vpnprotocol.cpp \ protocols/vpnprotocol.cpp \
logger.cpp \
loghandler.cpp
RESOURCES += \ RESOURCES += \
resources.qrc resources.qrc
@ -128,6 +135,8 @@ TRANSLATIONS = \
translations/amneziavpn_ru.ts translations/amneziavpn_ru.ts
win32 { win32 {
DEFINES += MVPN_WINDOWS
OTHER_FILES += platform_win/vpnclient.rc OTHER_FILES += platform_win/vpnclient.rc
RC_FILE = platform_win/vpnclient.rc RC_FILE = platform_win/vpnclient.rc
@ -163,6 +172,8 @@ win32 {
} }
macx { macx {
DEFINES += MVPN_MACOS
ICON = $$PWD/images/app.icns ICON = $$PWD/images/app.icns
HEADERS += ui/macos_util.h HEADERS += ui/macos_util.h
@ -175,6 +186,8 @@ macx {
} }
linux:!android { linux:!android {
DEFINES += MVPN_LINUX
LIBS += /usr/lib/x86_64-linux-gnu/libcrypto.a LIBS += /usr/lib/x86_64-linux-gnu/libcrypto.a
LIBS += /usr/lib/x86_64-linux-gnu/libssl.a LIBS += /usr/lib/x86_64-linux-gnu/libssl.a
} }
@ -200,6 +213,7 @@ win32|macx|linux:!android {
android { android {
QT += androidextras QT += androidextras
DEFINES += MVPN_ANDROID
INCLUDEPATH += platforms/android INCLUDEPATH += platforms/android
@ -251,46 +265,90 @@ android {
ios { ios {
message("Client ios build") message("Client ios build")
CONFIG += static CONFIG += static
CONFIG += file_copies
# For the authentication
LIBS += -framework AuthenticationServices
# For notifications
LIBS += -framework UIKit
LIBS += -framework Foundation
LIBS += -framework StoreKit
LIBS += -framework UserNotifications
DEFINES += MVPN_IOS
HEADERS += \
protocols/ios_vpnprotocol.h \
platforms/ios/iosnotificationhandler.h \
platforms/ios/json.h \
platforms/ios/bigint.h \
platforms/ios/bigintipv6addr.h \
platforms/ios/ipaddress.h \
platforms/ios/ipaddressrange.h
SOURCES += \
protocols/ios_vpnprotocol.mm \
platforms/ios/iosnotificationhandler.mm \
platforms/ios/json.cpp \
platforms/ios/iosglue.mm \
platforms/ios/ipaddress.cpp \
platforms/ios/ipaddressrange.cpp
Q_ENABLE_BITCODE.value = NO Q_ENABLE_BITCODE.value = NO
Q_ENABLE_BITCODE.name = ENABLE_BITCODE Q_ENABLE_BITCODE.name = ENABLE_BITCODE
QMAKE_MAC_XCODE_SETTINGS += Q_ENABLE_BITCODE QMAKE_MAC_XCODE_SETTINGS += Q_ENABLE_BITCODE
CONFIG(iphoneos, iphoneos|iphonesimulator) { # CONFIG(iphoneos, iphoneos|iphonesimulator) {
message("Building for iPhone OS") iphoneos {
QMAKE_TARGET_BUNDLE_PREFIX = org.amnezia message("Building for iPhone OS")
QMAKE_BUNDLE = AmneziaVPN QMAKE_TARGET_BUNDLE_PREFIX = org.amnezia
QMAKE_IOS_DEPLOYMENT_TARGET = 12.0 QMAKE_BUNDLE = AmneziaVPN
QMAKE_APPLE_TARGETED_DEVICE_FAMILY = 1 QMAKE_IOS_DEPLOYMENT_TARGET = 12.0
QMAKE_DEVELOPMENT_TEAM = X7UJ388FXK QMAKE_APPLE_TARGETED_DEVICE_FAMILY = 1
QMAKE_PROVISIONING_PROFILE = f2fefb59-14aa-4aa9-ac14-1d5531b06dcc QMAKE_DEVELOPMENT_TEAM = X7UJ388FXK
QMAKE_XCODE_CODE_SIGN_IDENTITY = "Apple Distribution" QMAKE_PROVISIONING_PROFILE = f2fefb59-14aa-4aa9-ac14-1d5531b06dcc
QMAKE_XCODE_CODE_SIGN_IDENTITY = "Apple Distribution"
QMAKE_INFO_PLIST= $$PWD/ios/app/Info.plist
XCODEBUILD_FLAGS += -allowProvisioningUpdates XCODEBUILD_FLAGS += -allowProvisioningUpdates
DEFINES += iphoneos DEFINES += iphoneos
contains(QT_ARCH, arm64) { contains(QT_ARCH, arm64) {
message("Building for iOS/ARM v8 64-bit architecture") message("Building for iOS/ARM v8 64-bit architecture")
ARCH_TAG = "ios_armv8_64" ARCH_TAG = "ios_armv8_64"
LIBS += $$PWD/3rd/OpenSSL/lib/ios/iphone/libcrypto.a LIBS += $$PWD/3rd/OpenSSL/lib/ios/iphone/libcrypto.a
LIBS += $$PWD/3rd/OpenSSL/lib/ios/iphone/libssl.a LIBS += $$PWD/3rd/OpenSSL/lib/ios/iphone/libssl.a
} else { } else {
message("Building for iOS/ARM v7 (32-bit) architecture") message("Building for iOS/ARM v7 (32-bit) architecture")
ARCH_TAG = "ios_armv7" ARCH_TAG = "ios_armv7"
}
} }
}
# }
CONFIG(iphonesimulator, iphoneos|iphonesimulator) {
message("Building for iPhone Simulator")
ARCH_TAG = "ios_x86_64"
DEFINES += iphonesimulator # CONFIG(iphonesimulator, iphoneos|iphonesimulator) {
# iphonesimulator {
# message("Building for iPhone Simulator")
# ARCH_TAG = "ios_x86_64"
#
# DEFINES += iphonesimulator
#
# LIBS += $$PWD/3rd/OpenSSL/lib/ios/simulator/libcrypto.a
# LIBS += $$PWD/3rd/OpenSSL/lib/ios/simulator/libssl.a
# }
# }
LIBS += $$PWD/3rd/OpenSSL/lib/ios/simulator/libcrypto.a NETWORKEXTENSION=1
LIBS += $$PWD/3rd/OpenSSL/lib/ios/simulator/libssl.a # ! build_pass: system(ruby $$PWD/scripts/xcode_patcher.rb "$$PWD" "$$OUT_PWD/AmneziaVPN.xcodeproj" "2.0" "2.0.0" "ios" "$$NETWORKEXTENSION"|| echo "Failed to merge xcode with wireguard")
}
#ruby %{sourceDir}/client/ios/xcode_patcher.rb "%{buildDir}/AmneziaVPN.xcodeproj" "2.0" "2.0.0" "ios" "1"
#cd client/ && /Users/md/Qt/5.15.2/ios/bin/qmake -o Makefile /Users/md/amnezia/desktop-client/client/client.pro -spec macx-ios-clang CONFIG+=iphonesimulator CONFIG+=simulator CONFIG+=qml_debug -after
# %{sourceDir}/client/ios/xcode_patcher.rb %{buildDir}/client/AmneziaVPN.xcodeproj 2.0 2.0.0 ios 1
} }

View file

@ -18,22 +18,22 @@ Settings &VpnConfigurator::m_settings()
} }
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, Protocol proto, ErrorCode *errorCode) DockerContainer container, const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode)
{ {
switch (proto) { switch (proto) {
case Protocol::OpenVpn: case Proto::OpenVpn:
return OpenVpnConfigurator::genOpenVpnConfig(credentials, container, containerConfig, errorCode); return OpenVpnConfigurator::genOpenVpnConfig(credentials, container, containerConfig, errorCode);
case Protocol::ShadowSocks: case Proto::ShadowSocks:
return ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, errorCode); return ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, errorCode);
case Protocol::Cloak: case Proto::Cloak:
return CloakConfigurator::genCloakConfig(credentials, container, containerConfig, errorCode); return CloakConfigurator::genCloakConfig(credentials, container, containerConfig, errorCode);
case Protocol::WireGuard: case Proto::WireGuard:
return WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, errorCode); return WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, errorCode);
case Protocol::Ikev2: case Proto::Ikev2:
return Ikev2Configurator::genIkev2Config(credentials, container, containerConfig, errorCode); return Ikev2Configurator::genIkev2Config(credentials, container, containerConfig, errorCode);
default: default:
@ -41,23 +41,23 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia
} }
} }
QString VpnConfigurator::processConfigWithLocalSettings(DockerContainer container, Protocol proto, QString config) QString VpnConfigurator::processConfigWithLocalSettings(DockerContainer container, Proto proto, QString config)
{ {
config.replace("$PRIMARY_DNS", m_settings().primaryDns()); config.replace("$PRIMARY_DNS", m_settings().primaryDns());
config.replace("$SECONDARY_DNS", m_settings().secondaryDns()); config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
if (proto == Protocol::OpenVpn) { if (proto == Proto::OpenVpn) {
return OpenVpnConfigurator::processConfigWithLocalSettings(config); return OpenVpnConfigurator::processConfigWithLocalSettings(config);
} }
return config; return config;
} }
QString VpnConfigurator::processConfigWithExportSettings(DockerContainer container, Protocol proto, QString config) QString VpnConfigurator::processConfigWithExportSettings(DockerContainer container, Proto proto, QString config)
{ {
config.replace("$PRIMARY_DNS", m_settings().primaryDns()); config.replace("$PRIMARY_DNS", m_settings().primaryDns());
config.replace("$SECONDARY_DNS", m_settings().secondaryDns()); config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
if (proto == Protocol::OpenVpn) { if (proto == Proto::OpenVpn) {
return OpenVpnConfigurator::processConfigWithExportSettings(config); return OpenVpnConfigurator::processConfigWithExportSettings(config);
} }
return config; return config;
@ -66,7 +66,7 @@ QString VpnConfigurator::processConfigWithExportSettings(DockerContainer contain
void VpnConfigurator::updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig, void VpnConfigurator::updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig,
const QString &stdOut) const QString &stdOut)
{ {
Protocol mainProto = ContainerProps::defaultProtocol(container); Proto mainProto = ContainerProps::defaultProtocol(container);
if (container == DockerContainer::TorWebSite) { if (container == DockerContainer::TorWebSite) {
QJsonObject protocol = containerConfig.value(ProtocolProps::protoToString(mainProto)).toObject(); QJsonObject protocol = containerConfig.value(ProtocolProps::protoToString(mainProto)).toObject();

View file

@ -13,10 +13,10 @@ class VpnConfigurator
public: public:
static QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container, static QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, Protocol proto, ErrorCode *errorCode = nullptr); const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
static QString processConfigWithLocalSettings(DockerContainer container, Protocol proto, QString config); static QString processConfigWithLocalSettings(DockerContainer container, Proto proto, QString config);
static QString processConfigWithExportSettings(DockerContainer container, Protocol proto, QString config); static QString processConfigWithExportSettings(DockerContainer container, Proto proto, QString config);
// workaround for containers which is not support normal configaration // workaround for containers which is not support normal configaration
static void updateContainerConfigAfterInstallation(DockerContainer container, static void updateContainerConfigAfterInstallation(DockerContainer container,

127
client/constants.h Normal file
View file

@ -0,0 +1,127 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef CONSTANTS_H
#define CONSTANTS_H
#include <stdint.h>
namespace Constants {
// Returns true if we are in a production environment.
bool inProduction();
void setStaging();
// Number of msecs for the captive-portal block alert.
constexpr uint32_t CAPTIVE_PORTAL_ALERT_MSEC = 4000;
// Number of msecs for the unsecured network alert.
constexpr uint32_t UNSECURED_NETWORK_ALERT_MSEC = 4000;
// Number of recent connections to retain.
constexpr int RECENT_CONNECTIONS_MAX_COUNT = 5;
#if defined(UNIT_TEST)
# define CONSTEXPR(type, functionName, releaseValue, debugValue, \
testingValue) \
inline type functionName() { return testingValue; }
#else
# define CONSTEXPR(type, functionName, releaseValue, debugValue, \
testingValue) \
inline type functionName() { \
return inProduction() ? releaseValue : debugValue; \
}
#endif
// Let's refresh the IP address any 10 minutes (in milliseconds).
CONSTEXPR(uint32_t, ipAddressTimerMsec, 600000, 10000, 0)
// Let's check the connection status any second.
CONSTEXPR(uint32_t, checkStatusTimerMsec, 1000, 1000, 0)
// Number of points for the charts.
CONSTEXPR(int, chartsMaxPoints, 30, 30, 30);
// Any 6 hours, a new check
CONSTEXPR(uint32_t, releaseMonitorMsec, 21600000, 4000, 0)
// in milliseconds, how often we should fetch the server list and the account.
CONSTEXPR(uint32_t, scheduleAccountAndServersTimerMsec, 3600000, 4000, 0)
// how often we check the captive portal when the VPN is on.
CONSTEXPR(uint32_t, captivePortalRequestTimeoutMsec, 10000, 4000, 0)
// How fast the animated icon should move
CONSTEXPR(uint32_t, statusIconAnimationMsec, 200, 200, 0)
// How often glean pings are sent
CONSTEXPR(uint32_t, gleanTimeoutMsec, 1200000, 1000, 0)
// How often we check the surveys to be executed (no network requests are done
// for this check)
CONSTEXPR(uint32_t, surveyTimerMsec, 300000, 4000, 0)
#undef CONSTEXPR
#define PRODBETAEXPR(type, functionName, prod, beta) \
inline type functionName() { return inProduction() ? prod : beta; }
constexpr const char* API_PRODUCTION_URL = "https://vpn.mozilla.org";
constexpr const char* API_STAGING_URL =
"https://stage-vpn.guardian.nonprod.cloudops.mozgcp.net";
constexpr const char* LOGO_URL = ":/ui/resources/logo-dock.png";
PRODBETAEXPR(const char*, fxaUrl, "https://api.accounts.firefox.com",
"https://api-accounts.stage.mozaws.net")
PRODBETAEXPR(
const char*, balrogUrl,
"https://aus5.mozilla.org/json/1/FirefoxVPN/%1/%2/release/update.json",
"https://stage.balrog.nonprod.cloudops.mozgcp.net/json/1/FirefoxVPN/%1/%2/"
"release-cdntest/update.json");
PRODBETAEXPR(
const char*, balrogRootCertFingerprint,
"97e8ba9cf12fb3de53cc42a4e6577ed64df493c247b414fea036818d3823560e",
"3c01446abe9036cea9a09acaa3a520ac628f20a7ae32ce861cb2efb70fa0c745");
#undef PRODBETAEXPR
constexpr const char* PLATFORM_NAME =
#if defined(MVPN_IOS)
"ios"
#elif defined(MVPN_MACOS)
"macos"
#elif defined(MVPN_LINUX)
"linux"
#elif defined(MVPN_ANDROID)
"android"
#elif defined(MVPN_WINDOWS)
"windows"
#elif defined(UNIT_TEST) || defined(MVPN_DUMMY)
"dummy"
#else
# error "Unsupported platform"
#endif
;
constexpr const char* PLACEHOLDER_USER_DNS = "127.0.0.1";
#if defined(MVPN_ADJUST)
// These are the two auto-generated token from the Adjust dashboard for the
// "Subscription Completed" event. We have two since in the Adjust dashboard we
// have defined two apps for iOS and Android with a event token each.
constexpr const char* ADJUST_SUBSCRIPTION_COMPLETED =
# if defined(MVPN_IOS)
"jl72xm"
# elif defined(MVPN_ANDROID)
"o1mn9m"
# else
""
# endif
;
#endif
}; // namespace Constants
#endif // CONSTANTS_H

View file

@ -27,29 +27,29 @@ QString ContainerProps::containerToString(amnezia::DockerContainer c){
return "amnezia-" + containerKey.toLower(); return "amnezia-" + containerKey.toLower();
} }
QVector<amnezia::Protocol> ContainerProps::protocolsForContainer(amnezia::DockerContainer container) QVector<amnezia::Proto> ContainerProps::protocolsForContainer(amnezia::DockerContainer container)
{ {
switch (container) { switch (container) {
case DockerContainer::None: case DockerContainer::None:
return { }; return { };
case DockerContainer::OpenVpn: case DockerContainer::OpenVpn:
return { Protocol::OpenVpn }; return { Proto::OpenVpn };
case DockerContainer::ShadowSocks: case DockerContainer::ShadowSocks:
return { Protocol::OpenVpn, Protocol::ShadowSocks }; return { Proto::OpenVpn, Proto::ShadowSocks };
case DockerContainer::Cloak: case DockerContainer::Cloak:
return { Protocol::OpenVpn, Protocol::ShadowSocks, Protocol::Cloak }; return { Proto::OpenVpn, Proto::ShadowSocks, Proto::Cloak };
case DockerContainer::Ipsec: case DockerContainer::Ipsec:
return { Protocol::Ikev2 /*, Protocol::L2tp */}; return { Proto::Ikev2 /*, Protocol::L2tp */};
case DockerContainer::Dns: case DockerContainer::Dns:
return { }; return { };
case DockerContainer::Sftp: case DockerContainer::Sftp:
return { Protocol::Sftp}; return { Proto::Sftp};
default: default:
return { defaultProtocol(container) }; return { defaultProtocol(container) };
@ -118,21 +118,21 @@ amnezia::ServiceType ContainerProps::containerService(DockerContainer c)
} }
} }
Protocol ContainerProps::defaultProtocol(DockerContainer c) Proto ContainerProps::defaultProtocol(DockerContainer c)
{ {
switch (c) { switch (c) {
case DockerContainer::None : return Protocol::Any; case DockerContainer::None : return Proto::Any;
case DockerContainer::OpenVpn : return Protocol::OpenVpn; case DockerContainer::OpenVpn : return Proto::OpenVpn;
case DockerContainer::Cloak : return Protocol::Cloak; case DockerContainer::Cloak : return Proto::Cloak;
case DockerContainer::ShadowSocks : return Protocol::ShadowSocks; case DockerContainer::ShadowSocks : return Proto::ShadowSocks;
case DockerContainer::WireGuard : return Protocol::WireGuard; case DockerContainer::WireGuard : return Proto::WireGuard;
case DockerContainer::Ipsec : return Protocol::Ikev2; case DockerContainer::Ipsec : return Proto::Ikev2;
case DockerContainer::TorWebSite : return Protocol::TorWebSite; case DockerContainer::TorWebSite : return Proto::TorWebSite;
case DockerContainer::Dns : return Protocol::Dns; case DockerContainer::Dns : return Proto::Dns;
//case DockerContainer::FileShare : return Protocol::FileShare; //case DockerContainer::FileShare : return Protocol::FileShare;
case DockerContainer::Sftp : return Protocol::Sftp; case DockerContainer::Sftp : return Proto::Sftp;
default: return Protocol::Any; default: return Proto::Any;
} }
} }
@ -140,7 +140,6 @@ bool ContainerProps::isWorkingOnPlatform(DockerContainer c)
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
return true; return true;
#elif defined (Q_OS_MAC)
#elif defined (Q_OS_IOS) #elif defined (Q_OS_IOS)
switch (c) { switch (c) {
@ -148,6 +147,9 @@ bool ContainerProps::isWorkingOnPlatform(DockerContainer c)
case DockerContainer::OpenVpn: return true; case DockerContainer::OpenVpn: return true;
default: return false; default: return false;
} }
#elif defined (Q_OS_MAC)
return false;
#elif defined (Q_OS_ANDROID) #elif defined (Q_OS_ANDROID)
switch (c) { switch (c) {
case DockerContainer::WireGuard: return true; case DockerContainer::WireGuard: return true;
@ -156,6 +158,7 @@ bool ContainerProps::isWorkingOnPlatform(DockerContainer c)
} }
#elif defined (Q_OS_LINUX) #elif defined (Q_OS_LINUX)
return false;
#else #else
return false; return false;

View file

@ -46,13 +46,13 @@ public:
Q_INVOKABLE static QMap<DockerContainer, QString> containerDescriptions(); Q_INVOKABLE static QMap<DockerContainer, QString> containerDescriptions();
// these protocols will be displayed in container settings // these protocols will be displayed in container settings
Q_INVOKABLE static QVector<Protocol> protocolsForContainer(DockerContainer container); Q_INVOKABLE static QVector<Proto> protocolsForContainer(DockerContainer container);
Q_INVOKABLE static ServiceType containerService(DockerContainer c); Q_INVOKABLE static ServiceType containerService(DockerContainer c);
// binding between Docker container and main protocol of given container // binding between Docker container and main protocol of given container
// it may be changed fot future containers :) // it may be changed fot future containers :)
Q_INVOKABLE static Protocol defaultProtocol(DockerContainer c); Q_INVOKABLE static Proto defaultProtocol(DockerContainer c);
Q_INVOKABLE static bool isWorkingOnPlatform(DockerContainer c); Q_INVOKABLE static bool isWorkingOnPlatform(DockerContainer c);
}; };

View file

@ -1,5 +1,6 @@
#include "privileged_process.h" #include "privileged_process.h"
#ifndef Q_OS_IOS
PrivilegedProcess::PrivilegedProcess() : PrivilegedProcess::PrivilegedProcess() :
IpcProcessInterfaceReplica() IpcProcessInterfaceReplica()
{ {
@ -25,3 +26,4 @@ void PrivilegedProcess::waitForFinished(int msecs)
loop->exec(); loop->exec();
} }
#endif // Q_OS_IOS

View file

@ -20,11 +20,11 @@ public:
}; };
#endif // PRIVILEGED_PROCESS_H
#else // defined Q_OS_IOS #else // defined Q_OS_IOS
class IpcProcessInterfaceReplica {}; class IpcProcessInterfaceReplica {};
class PrivilegedProcess {}; class PrivilegedProcess {};
#endif #endif // Q_OS_IOS
#endif // PRIVILEGED_PROCESS_H

View file

@ -454,7 +454,7 @@ ErrorCode ServerController::updateContainer(const ServerCredentials &credentials
QJsonObject ServerController::createContainerInitialConfig(DockerContainer container, int port, TransportProto tp) QJsonObject ServerController::createContainerInitialConfig(DockerContainer container, int port, TransportProto tp)
{ {
Protocol mainProto = ContainerProps::defaultProtocol(container); Proto mainProto = ContainerProps::defaultProtocol(container);
QJsonObject config { QJsonObject config {
{ config_key::container, ContainerProps::containerToString(container) } { config_key::container, ContainerProps::containerToString(container) }
@ -621,11 +621,11 @@ ErrorCode ServerController::startupContainerWorker(const ServerCredentials &cred
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config) ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
{ {
const QJsonObject &openvpnConfig = config.value(ProtocolProps::protoToString(Protocol::OpenVpn)).toObject(); const QJsonObject &openvpnConfig = config.value(ProtocolProps::protoToString(Proto::OpenVpn)).toObject();
const QJsonObject &cloakConfig = config.value(ProtocolProps::protoToString(Protocol::Cloak)).toObject(); const QJsonObject &cloakConfig = config.value(ProtocolProps::protoToString(Proto::Cloak)).toObject();
const QJsonObject &ssConfig = config.value(ProtocolProps::protoToString(Protocol::ShadowSocks)).toObject(); const QJsonObject &ssConfig = config.value(ProtocolProps::protoToString(Proto::ShadowSocks)).toObject();
const QJsonObject &wireguarConfig = config.value(ProtocolProps::protoToString(Protocol::WireGuard)).toObject(); const QJsonObject &wireguarConfig = config.value(ProtocolProps::protoToString(Proto::WireGuard)).toObject();
const QJsonObject &sftpConfig = config.value(ProtocolProps::protoToString(Protocol::Sftp)).toObject(); const QJsonObject &sftpConfig = config.value(ProtocolProps::protoToString(Proto::Sftp)).toObject();
// //
Vars vars; Vars vars;
@ -694,7 +694,7 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
// Sftp vars // Sftp vars
vars.append({{"$SFTP_PORT", sftpConfig.value(config_key::port).toString(QString::number(ProtocolProps::defaultPort(Protocol::Sftp))) }}); vars.append({{"$SFTP_PORT", sftpConfig.value(config_key::port).toString(QString::number(ProtocolProps::defaultPort(Proto::Sftp))) }});
vars.append({{"$SFTP_USER", sftpConfig.value(config_key::userName).toString() }}); vars.append({{"$SFTP_USER", sftpConfig.value(config_key::userName).toString() }});
vars.append({{"$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() }}); vars.append({{"$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() }});

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="ipad12_9rounded" orientation="portrait" layout="fullscreen" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="gZ9-gc-3t5">
<rect key="frame" x="0.0" y="0.0" width="1024" height="1366"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launch.png" translatesAutoresizingMaskIntoConstraints="NO" id="q5g-aV-39U">
<rect key="frame" x="467" y="638" width="90" height="90"/>
<constraints>
<constraint firstAttribute="width" constant="90" id="VFp-nz-h8O"/>
<constraint firstAttribute="height" constant="90" id="ZUg-Ud-mgE"/>
</constraints>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="Whf-X3-AA4"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="q5g-aV-39U" firstAttribute="centerX" secondItem="gZ9-gc-3t5" secondAttribute="centerX" id="Ayw-bo-LVF"/>
<constraint firstItem="q5g-aV-39U" firstAttribute="centerY" secondItem="gZ9-gc-3t5" secondAttribute="centerY" id="YHd-Kc-J0u"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="launch.png" width="1024" height="1024"/>
</resources>
</document>

View file

@ -0,0 +1,116 @@
{
"images" : [
{
"filename" : "icon-ios-20@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "icon-ios-20@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"filename" : "icon-ios-29@2x-1.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "icon-ios-29@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"filename" : "icon-ios-40@2x-1.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "icon-ios-40@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"filename" : "icon-ios-60@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "icon-ios-60@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"filename" : "icon-ios-20@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"filename" : "icon-ios-20@2x-1.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "icon-ios-29@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "icon-ios-29@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "icon-ios-40@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"filename" : "icon-ios-40@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "icon-ios-76@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"filename" : "icon-ios-76@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"filename" : "icon-ios-83.5@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"filename" : "icon-ios-1024@1x.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

49
client/ios/app/Info.plist Normal file
View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>AmneziaVPN</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIcons</key>
<dict/>
<key>CFBundleIcons~ipad</key>
<dict/>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${APP_DISPLAY_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<false/>
<key>UILaunchStoryboardName</key>
<string>AmneziaVPNLaunchScreen</string>
<key>UIRequiresFullScreen</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array/>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
</dict>
</plist>

BIN
client/ios/app/launch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
<string>group.ru.kotit.AmneziaVPN.udev</string>
</array>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)group.ru.kotit.AmneziaVPN.udev</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
<string>group.ru.kotit.AmneziaVPN.udev</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)group.ru.kotit.AmneziaVPN.udev</string>
</array>
</dict>
</plist>

13
client/ios/xcode.xconfig Normal file
View file

@ -0,0 +1,13 @@
DEVELOPMENT_TEAM = <X7UJ388FXK>
# MacOS configuration
GROUP_ID_MACOS = <>
APP_ID_MACOS = <>
NETEXT_ID_MACOS = <>
LOGIN_ID_MACOS = <>
NATIVEMESSAGING_ID_MACOS = <>
# IOS configuration
GROUP_ID_IOS = group.org.mozilla.ios.Guardian
APP_ID_IOS = org.mozilla.ios.FirefoxVPN
NETEXT_ID_IOS = org.mozilla.ios.FirefoxVPN.network-extension

598
client/ios/xcode_patcher.rb Normal file
View file

@ -0,0 +1,598 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
require 'xcodeproj'
class XCodeprojPatcher
attr :project
attr :p_root
attr :target_main
attr :target_extension
# @@project_root
# def self.project_root
# @@project_root
# end
def run(project_root, file, shortVersion, fullVersion, platform, networkExtension, webExtension, configHash, adjust_sdk_token)
@p_root = project_root
open_project file
open_target_main
die 'IOS requires networkExtension mode' if not networkExtension and platform == 'ios'
group = @project.main_group.new_group('Configuration')
@configFile = group.new_file('ios/xcode.xconfig')
setup_target_main shortVersion, fullVersion, platform, networkExtension, configHash, adjust_sdk_token
if platform == 'macos'
setup_target_loginitem shortVersion, fullVersion, configHash
setup_target_nativemessaging shortVersion, fullVersion, configHash if webExtension
end
if networkExtension
setup_target_extension shortVersion, fullVersion, platform, configHash
setup_target_gobridge
else
setup_target_wireguardgo
setup_target_wireguardtools
end
setup_target_balrog if platform == 'macos'
@project.save
end
def open_project(file)
@project = Xcodeproj::Project.open(file)
puts 'Failed to open the project file: ' + file if @project.nil?
die 'Failed to open the project file: ' + file if @project.nil?
end
def open_target_main
@target_main = @project.targets.find { |target| target.to_s == 'AmneziaVPN' }
return @target_main if not @target_main.nil?
puts 'Unable to open AmneziaVPN target'
die 'Unable to open AmneziaVPN target'
end
def setup_target_main(shortVersion, fullVersion, platform, networkExtension, configHash, adjust_sdk_token)
@target_main.build_configurations.each do |config|
config.base_configuration_reference = @configFile
config.build_settings['LD_RUNPATH_SEARCH_PATHS'] ||= '"$(inherited) @executable_path/../Frameworks"'
config.build_settings['SWIFT_VERSION'] ||= '5.0'
config.build_settings['CLANG_ENABLE_MODULES'] ||= 'YES'
config.build_settings['SWIFT_OBJC_BRIDGING_HEADER'] ||= p_root + "/" + 'macos/app/WireGuard-Bridging-Header.h'
config.build_settings['FRAMEWORK_SEARCH_PATHS'] ||= [
"$(inherited)",
"$(PROJECT_DIR)/3rd"
]
# Versions and names
config.build_settings['MARKETING_VERSION'] ||= shortVersion
config.build_settings['CURRENT_PROJECT_VERSION'] ||= fullVersion
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = configHash['APP_ID_MACOS'] if platform == 'macos'
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = configHash['APP_ID_IOS'] if platform == 'ios'
config.build_settings['PRODUCT_NAME'] = 'Mozilla VPN'
# other config
config.build_settings['INFOPLIST_FILE'] ||= p_root + "/" + platform + '/app/Info.plist'
if platform == 'ios'
config.build_settings['CODE_SIGN_ENTITLEMENTS'] ||= p_root + "/" + 'ios/app/main.entitlements'
if adjust_sdk_token != ""
config.build_settings['ADJUST_SDK_TOKEN'] = adjust_sdk_token
end
elsif networkExtension
config.build_settings['CODE_SIGN_ENTITLEMENTS'] ||= p_root + "/" + 'macos/app/app.entitlements'
else
config.build_settings['CODE_SIGN_ENTITLEMENTS'] ||= p_root + "/" + 'macos/app/daemon.entitlements'
end
config.build_settings['CODE_SIGN_IDENTITY'] ||= 'Apple Development'
config.build_settings['ENABLE_BITCODE'] ||= 'NO' if platform == 'ios'
config.build_settings['SDKROOT'] = 'iphoneos' if platform == 'ios'
config.build_settings['SWIFT_PRECOMPILE_BRIDGING_HEADER'] = 'NO' if platform == 'ios'
groupId = "";
if (platform == 'macos')
groupId = configHash['DEVELOPMENT_TEAM'] + "." + configHash['GROUP_ID_MACOS']
config.build_settings['APP_ID_MACOS'] ||= configHash['APP_ID_MACOS']
else
groupId = configHash['GROUP_ID_IOS']
config.build_settings['GROUP_ID_IOS'] ||= configHash['GROUP_ID_IOS']
end
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'GROUP_ID=\"' + groupId + '\"',
"VPN_NE_BUNDLEID=\\\"" + (platform == 'macos' ? configHash['NETEXT_ID_MACOS'] : configHash['NETEXT_ID_IOS']) + "\\\"",
]
if config.name == 'Release'
config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] ||= '-Onone'
end
end
if networkExtension
# WireGuard group
group = @project.main_group.new_group('WireGuard')
[
'macos/gobridge/wireguard-go-version.h',
'3rd/wireguard-apple/Sources/Shared/Keychain.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/IPAddressRange.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/InterfaceConfiguration.swift',
'3rd/wireguard-apple/Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/TunnelConfiguration.swift',
'3rd/wireguard-apple/Sources/Shared/Model/TunnelConfiguration+WgQuickConfig.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/Endpoint.swift',
'3rd/wireguard-apple/Sources/Shared/Model/String+ArrayConversion.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/PeerConfiguration.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/DNSServer.swift',
'3rd/wireguard-apple/Sources/WireGuardApp/LocalizationHelper.swift',
'3rd/wireguard-apple/Sources/Shared/FileManager+Extension.swift',
'3rd/wireguard-apple/Sources/WireGuardKitC/x25519.c',
'3rd/wireguard-apple/Sources/WireGuardKit/PrivateKey.swift',
].each { |filename|
file = group.new_file(p_root + "/" + filename)
@target_main.add_file_references([file])
}
# @target_main + swift integration
group = @project.main_group.new_group('SwiftIntegration')
[
'platforms/ios/ioscontroller.swift',
'platforms/ios/ioslogger.swift',
].each { |filename|
file = group.new_file(p_root + "/" + filename)
@target_main.add_file_references([file])
}
end
if (platform == 'ios' && adjust_sdk_token != "")
frameworks_group = @project.groups.find { |group| group.display_name == 'Frameworks' }
frameworks_build_phase = @target_main.build_phases.find { |build_phase| build_phase.to_s == 'FrameworksBuildPhase' }
embed_frameworks_build_phase = @target_main.build_phases.find { |build_phase| build_phase.to_s == 'Embed Frameworks' }
framework_ref = frameworks_group.new_file('3rd/AdjustSdk.framework')
frameworks_build_phase.add_file_reference(framework_ref)
framework_file = embed_frameworks_build_phase.add_file_reference(framework_ref)
framework_file.settings = { "ATTRIBUTES" => ['RemoveHeadersOnCopy', 'CodeSignOnCopy'] }
framework_ref = frameworks_group.new_file('AdServices.framework')
frameworks_build_phase.add_file_reference(framework_ref)
framework_ref = frameworks_group.new_file('iAd.framework')
frameworks_build_phase.add_file_reference(framework_ref)
end
end
def setup_target_extension(shortVersion, fullVersion, platform, configHash)
@target_extension = @project.new_target(:app_extension, 'WireGuardNetworkExtension', platform == 'macos' ? :osx : :ios)
@target_extension.build_configurations.each do |config|
config.base_configuration_reference = @configFile
config.build_settings['LD_RUNPATH_SEARCH_PATHS'] ||= '"$(inherited) @executable_path/../Frameworks"'
config.build_settings['SWIFT_VERSION'] ||= '5.0'
config.build_settings['CLANG_ENABLE_MODULES'] ||= 'YES'
config.build_settings['SWIFT_OBJC_BRIDGING_HEADER'] ||= p_root + "/" + 'macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h'
config.build_settings['SWIFT_PRECOMPILE_BRIDGING_HEADER'] = 'NO'
# Versions and names
config.build_settings['MARKETING_VERSION'] ||= shortVersion
config.build_settings['CURRENT_PROJECT_VERSION'] ||= fullVersion
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] ||= configHash['NETEXT_ID_MACOS'] if platform == 'macos'
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] ||= configHash['NETEXT_ID_IOS'] if platform == 'ios'
config.build_settings['PRODUCT_NAME'] = 'WireGuardNetworkExtension'
# other configs
config.build_settings['INFOPLIST_FILE'] ||= p_root + "/" + 'macos/networkextension/Info.plist'
config.build_settings['CODE_SIGN_ENTITLEMENTS'] ||= p_root + "/" + platform + '/networkextension/AmneziaVPNNetworkExtension.entitlements'
config.build_settings['CODE_SIGN_IDENTITY'] = 'Apple Development'
if platform == 'ios'
config.build_settings['ENABLE_BITCODE'] ||= 'NO'
config.build_settings['SDKROOT'] = 'iphoneos'
config.build_settings['OTHER_LDFLAGS'] ||= [
"-stdlib=libc++",
"-Wl,-rpath,@executable_path/Frameworks",
"-framework",
"AssetsLibrary",
"-framework",
"MobileCoreServices",
"-lm",
"-framework",
"UIKit",
"-lz",
"-framework",
"OpenGLES",
]
end
groupId = "";
if (platform == 'macos')
groupId = configHash['DEVELOPMENT_TEAM'] + "." + configHash['GROUP_ID_MACOS']
else
groupId = configHash['GROUP_ID_IOS']
end
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
# This is needed to compile the iosglue without Qt.
'NETWORK_EXTENSION=1',
'GROUP_ID=\"' + groupId + '\"',
]
if config.name == 'Release'
config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] ||= '-Onone'
end
end
group = @project.main_group.new_group('WireGuardExtension')
[
'3rd/wireguard-apple/Sources/WireGuardKit/WireGuardAdapter.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/DNSResolver.swift',
'3rd/wireguard-apple/Sources/WireGuardNetworkExtension/ErrorNotifier.swift',
'3rd/wireguard-apple/Sources/Shared/Keychain.swift',
'3rd/wireguard-apple/Sources/Shared/Model/TunnelConfiguration+WgQuickConfig.swift',
'3rd/wireguard-apple/Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift',
'3rd/wireguard-apple/Sources/Shared/Model/String+ArrayConversion.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/TunnelConfiguration.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/IPAddressRange.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/Endpoint.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/DNSServer.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/InterfaceConfiguration.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/PeerConfiguration.swift',
'3rd/wireguard-apple/Sources/Shared/FileManager+Extension.swift',
'3rd/wireguard-apple/Sources/WireGuardKitC/x25519.c',
'3rd/wireguard-apple/Sources/WireGuardKit/Array+ConcurrentMap.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/IPAddress+AddrInfo.swift',
'3rd/wireguard-apple/Sources/WireGuardKit/PrivateKey.swift',
].each { |filename|
file = group.new_file(p_root + "/" + filename)
@target_extension.add_file_references([file])
}
# @target_extension + swift integration
group = @project.main_group.new_group('SwiftIntegration')
[
'platforms/ios/iostunnel.swift',
'platforms/ios/iosglue.mm',
'platforms/ios/ioslogger.swift',
].each { |filename|
file = group.new_file(p_root + "/" + filename)
@target_extension.add_file_references([file])
}
frameworks_group = @project.groups.find { |group| group.display_name == 'Frameworks' }
frameworks_build_phase = @target_extension.build_phases.find { |build_phase| build_phase.to_s == 'FrameworksBuildPhase' }
frameworks_build_phase.clear
framework_ref = frameworks_group.new_file('libwg-go.a')
frameworks_build_phase.add_file_reference(framework_ref)
framework_ref = frameworks_group.new_file('NetworkExtension.framework')
frameworks_build_phase.add_file_reference(framework_ref)
# This fails: @target_main.add_dependency @target_extension
container_proxy = @project.new(Xcodeproj::Project::PBXContainerItemProxy)
container_proxy.container_portal = @project.root_object.uuid
container_proxy.proxy_type = Xcodeproj::Constants::PROXY_TYPES[:native_target]
container_proxy.remote_global_id_string = @target_extension.uuid
container_proxy.remote_info = @target_extension.name
dependency = @project.new(Xcodeproj::Project::PBXTargetDependency)
dependency.name = @target_extension.name
dependency.target = @target_main
dependency.target_proxy = container_proxy
@target_main.dependencies << dependency
copy_appex = @target_main.new_copy_files_build_phase
copy_appex.name = 'Copy Network-Extension plugin'
copy_appex.symbol_dst_subfolder_spec = :plug_ins
appex_file = copy_appex.add_file_reference @target_extension.product_reference
appex_file.settings = { "ATTRIBUTES" => ['RemoveHeadersOnCopy'] }
end
def setup_target_gobridge
target_gobridge = legacy_target = @project.new(Xcodeproj::Project::PBXLegacyTarget)
target_gobridge.build_working_directory = p_root + "/" + 'macos/gobridge'
target_gobridge.build_tool_path = 'make'
target_gobridge.pass_build_settings_in_environment = '1'
target_gobridge.build_arguments_string = '$(ACTION)'
target_gobridge.name = 'WireGuardGoBridge'
target_gobridge.product_name = 'WireGuardGoBridge'
@project.targets << target_gobridge
@target_extension.add_dependency target_gobridge
end
def setup_target_balrog
target_balrog = legacy_target = @project.new(Xcodeproj::Project::PBXLegacyTarget)
target_balrog.build_working_directory = p_root + "/" + 'balrog'
target_balrog.build_tool_path = 'make'
target_balrog.pass_build_settings_in_environment = '1'
target_balrog.build_arguments_string = '$(ACTION)'
target_balrog.name = 'WireGuardBalrog'
target_balrog.product_name = 'WireGuardBalrog'
@project.targets << target_balrog
frameworks_group = @project.groups.find { |group| group.display_name == 'Frameworks' }
frameworks_build_phase = @target_main.build_phases.find { |build_phase| build_phase.to_s == 'FrameworksBuildPhase' }
framework_ref = frameworks_group.new_file('balrog/balrog.a')
frameworks_build_phase.add_file_reference(framework_ref)
# This fails: @target_main.add_dependency target_balrog
container_proxy = @project.new(Xcodeproj::Project::PBXContainerItemProxy)
container_proxy.container_portal = @project.root_object.uuid
container_proxy.proxy_type = Xcodeproj::Constants::PROXY_TYPES[:native_target]
container_proxy.remote_global_id_string = target_balrog.uuid
container_proxy.remote_info = target_balrog.name
dependency = @project.new(Xcodeproj::Project::PBXTargetDependency)
dependency.name = target_balrog.name
dependency.target = @target_main
dependency.target_proxy = container_proxy
@target_main.dependencies << dependency
end
def setup_target_wireguardtools
target_wireguardtools = legacy_target = @project.new(Xcodeproj::Project::PBXLegacyTarget)
target_wireguardtools.build_working_directory = p_root + "/" + '3rd/wireguard-tools/src'
target_wireguardtools.build_tool_path = 'make'
target_wireguardtools.pass_build_settings_in_environment = '1'
target_wireguardtools.build_arguments_string = '$(ACTION)'
target_wireguardtools.name = 'WireGuardTools'
target_wireguardtools.product_name = 'WireGuardTools'
@project.targets << target_wireguardtools
# This fails: @target_main.add_dependency target_wireguardtools
container_proxy = @project.new(Xcodeproj::Project::PBXContainerItemProxy)
container_proxy.container_portal = @project.root_object.uuid
container_proxy.proxy_type = Xcodeproj::Constants::PROXY_TYPES[:native_target]
container_proxy.remote_global_id_string = target_wireguardtools.uuid
container_proxy.remote_info = target_wireguardtools.name
dependency = @project.new(Xcodeproj::Project::PBXTargetDependency)
dependency.name = target_wireguardtools.name
dependency.target = @target_main
dependency.target_proxy = container_proxy
@target_main.dependencies << dependency
copy_wireguardTools = @target_main.new_copy_files_build_phase
copy_wireguardTools.name = 'Copy wireguard-tools'
copy_wireguardTools.symbol_dst_subfolder_spec = :wrapper
copy_wireguardTools.dst_path = 'Contents/Resources/utils'
group = @project.main_group.new_group('WireGuardTools')
file = group.new_file '3rd/wireguard-tools/src/wg'
wireguardTools_file = copy_wireguardTools.add_file_reference file
wireguardTools_file.settings = { "ATTRIBUTES" => ['RemoveHeadersOnCopy'] }
end
def setup_target_wireguardgo
target_wireguardgo = legacy_target = @project.new(Xcodeproj::Project::PBXLegacyTarget)
target_wireguardgo.build_working_directory = p_root + "/" + '3rd/wireguard-go'
target_wireguardgo.build_tool_path = 'make'
target_wireguardgo.pass_build_settings_in_environment = '1'
target_wireguardgo.build_arguments_string = '$(ACTION)'
target_wireguardgo.name = 'WireGuardGo'
target_wireguardgo.product_name = 'WireGuardGo'
@project.targets << target_wireguardgo
# This fails: @target_main.add_dependency target_wireguardgo
container_proxy = @project.new(Xcodeproj::Project::PBXContainerItemProxy)
container_proxy.container_portal = @project.root_object.uuid
container_proxy.proxy_type = Xcodeproj::Constants::PROXY_TYPES[:native_target]
container_proxy.remote_global_id_string = target_wireguardgo.uuid
container_proxy.remote_info = target_wireguardgo.name
dependency = @project.new(Xcodeproj::Project::PBXTargetDependency)
dependency.name = target_wireguardgo.name
dependency.target = @target_main
dependency.target_proxy = container_proxy
@target_main.dependencies << dependency
copy_wireguardGo = @target_main.new_copy_files_build_phase
copy_wireguardGo.name = 'Copy wireguard-go'
copy_wireguardGo.symbol_dst_subfolder_spec = :wrapper
copy_wireguardGo.dst_path = 'Contents/Resources/utils'
group = @project.main_group.new_group('WireGuardGo')
file = group.new_file '3rd/wireguard-go/wireguard-go'
wireguardGo_file = copy_wireguardGo.add_file_reference file
wireguardGo_file.settings = { "ATTRIBUTES" => ['RemoveHeadersOnCopy'] }
end
def setup_target_loginitem(shortVersion, fullVersion, configHash)
return
@target_loginitem = @project.new_target(:application, 'AmneziaVPNLoginItem', :osx)
@target_loginitem.build_configurations.each do |config|
config.base_configuration_reference = @configFile
config.build_settings['LD_RUNPATH_SEARCH_PATHS'] ||= '"$(inherited) @executable_path/../Frameworks"'
# Versions and names
config.build_settings['MARKETING_VERSION'] ||= shortVersion
config.build_settings['CURRENT_PROJECT_VERSION'] ||= fullVersion
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] ||= configHash['LOGIN_ID_MACOS']
config.build_settings['PRODUCT_NAME'] = 'AmneziaVPNLoginItem'
# other configs
config.build_settings['INFOPLIST_FILE'] ||= 'macos/loginitem/Info.plist'
config.build_settings['CODE_SIGN_ENTITLEMENTS'] ||= p_root + "/" + 'macos/loginitem/AmneziaVPNLoginItem.entitlements'
config.build_settings['CODE_SIGN_IDENTITY'] = 'Apple Development'
config.build_settings['SKIP_INSTALL'] = 'YES'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'APP_ID=\"' + configHash['APP_ID_MACOS'] + '\"',
]
if config.name == 'Release'
config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] ||= '-Onone'
end
end
group = @project.main_group.new_group('LoginItem')
[
'macos/loginitem/main.m',
].each { |filename|
file = group.new_file(filename)
@target_loginitem.add_file_references([file])
}
# This fails: @target_main.add_dependency @target_loginitem
container_proxy = @project.new(Xcodeproj::Project::PBXContainerItemProxy)
container_proxy.container_portal = @project.root_object.uuid
container_proxy.proxy_type = Xcodeproj::Constants::PROXY_TYPES[:native_target]
container_proxy.remote_global_id_string = @target_loginitem.uuid
container_proxy.remote_info = @target_loginitem.name
dependency = @project.new(Xcodeproj::Project::PBXTargetDependency)
dependency.name = @target_loginitem.name
dependency.target = @target_main
dependency.target_proxy = container_proxy
@target_main.dependencies << dependency
copy_app = @target_main.new_copy_files_build_phase
copy_app.name = 'Copy LoginItem'
copy_app.symbol_dst_subfolder_spec = :wrapper
copy_app.dst_path = 'Contents/Library/LoginItems'
app_file = copy_app.add_file_reference @target_loginitem.product_reference
app_file.settings = { "ATTRIBUTES" => ['RemoveHeadersOnCopy'] }
end
def setup_target_nativemessaging(shortVersion, fullVersion, configHash)
@target_nativemessaging = @project.new_target(:application, 'AmneziaVPNNativeMessaging', :osx)
@target_nativemessaging.build_configurations.each do |config|
config.base_configuration_reference = @configFile
config.build_settings['LD_RUNPATH_SEARCH_PATHS'] ||= '"$(inherited) @executable_path/../Frameworks"'
# Versions and names
config.build_settings['MARKETING_VERSION'] ||= shortVersion
config.build_settings['CURRENT_PROJECT_VERSION'] ||= fullVersion
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] ||= configHash['NATIVEMESSAGING_ID_MACOS']
config.build_settings['PRODUCT_NAME'] = 'AmneziaVPNNativeMessaging'
# other configs
config.build_settings['INFOPLIST_FILE'] ||= p_root + "/" + 'macos/nativeMessaging/Info.plist'
config.build_settings['CODE_SIGN_ENTITLEMENTS'] ||= p_root + "/" + 'macos/nativeMessaging/AmneziaVPNNativeMessaging.entitlements'
config.build_settings['CODE_SIGN_IDENTITY'] = 'Apple Development'
config.build_settings['SKIP_INSTALL'] = 'YES'
end
group = @project.main_group.new_group('NativeMessaging')
[
'extension/app/constants.h',
'extension/app/handler.cpp',
'extension/app/handler.h',
'extension/app/json.hpp',
'extension/app/logger.cpp',
'extension/app/logger.h',
'extension/app/main.cpp',
'extension/app/vpnconnection.cpp',
'extension/app/vpnconnection.h',
].each { |filename|
file = group.new_file(p_root + "/" + filename)
@target_nativemessaging.add_file_references([file])
}
# This fails: @target_main.add_dependency @target_nativemessaging
container_proxy = @project.new(Xcodeproj::Project::PBXContainerItemProxy)
container_proxy.container_portal = @project.root_object.uuid
container_proxy.proxy_type = Xcodeproj::Constants::PROXY_TYPES[:native_target]
container_proxy.remote_global_id_string = @target_nativemessaging.uuid
container_proxy.remote_info = @target_nativemessaging.name
dependency = @project.new(Xcodeproj::Project::PBXTargetDependency)
dependency.name = @target_nativemessaging.name
dependency.target = @target_main
dependency.target_proxy = container_proxy
@target_main.dependencies << dependency
copy_app = @target_main.new_copy_files_build_phase
copy_app.name = 'Copy LoginItem'
copy_app.symbol_dst_subfolder_spec = :wrapper
copy_app.dst_path = 'Contents/Library/NativeMessaging'
app_file = copy_app.add_file_reference @target_nativemessaging.product_reference
app_file.settings = { "ATTRIBUTES" => ['RemoveHeadersOnCopy'] }
copy_nativeMessagingManifest = @target_main.new_copy_files_build_phase
copy_nativeMessagingManifest.name = 'Copy native messaging manifest'
copy_nativeMessagingManifest.symbol_dst_subfolder_spec = :wrapper
copy_nativeMessagingManifest.dst_path = 'Contents/Resources/utils'
group = @project.main_group.new_group('WireGuardHelper')
file = group.new_file 'extension/app/manifests/macos/mozillavpn.json'
nativeMessagingManifest_file = copy_nativeMessagingManifest.add_file_reference file
nativeMessagingManifest_file.settings = { "ATTRIBUTES" => ['RemoveHeadersOnCopy'] }
end
def die(msg)
print $msg
exit 1
end
end
if ARGV.length < 4 || (ARGV[4] != "ios" && ARGV[4] != "macos")
puts "Usage: <script> project_file shortVersion fullVersion ios/macos"
exit 1
end
if !File.exist?("ios/xcode.xconfig")
puts "xcode.xconfig file is required! See the template file."
exit 1
end
config = Hash.new
configFile = File.read("ios/xcode.xconfig").split("\n")
configFile.each { |line|
next if line[0] == "#"
if line.include? "="
keys = line.split("=")
config[keys[0].strip] = keys[1].strip
end
}
platform = "macos"
platform = "ios" if ARGV[4] == "ios"
networkExtension = true
webExtension = false
adjustToken = ""
r = XCodeprojPatcher.new
r.run ARGV[0], ARGV[1], ARGV[2], ARGV[3], platform, networkExtension, webExtension, config, adjustToken
exit 0

59
client/logger.cpp Normal file
View file

@ -0,0 +1,59 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "logger.h"
#include "loghandler.h"
Logger::Logger(const QString& module, const QString& className)
: Logger(QStringList({module}), className) {}
Logger::Logger(const QStringList& modules, const QString& className)
: m_modules(modules), m_className(className) {}
Logger::Log Logger::error() { return Log(this, LogLevel::Error); }
Logger::Log Logger::warning() { return Log(this, LogLevel::Warning); }
Logger::Log Logger::info() { return Log(this, LogLevel::Info); }
Logger::Log Logger::debug() { return Log(this, LogLevel::Debug); }
Logger::Log::Log(Logger* logger, LogLevel logLevel)
: m_logger(logger), m_logLevel(logLevel), m_data(new Data()) {}
Logger::Log::~Log() {
LogHandler::messageHandler(m_logLevel, m_logger->modules(),
m_logger->className(), m_data->m_buffer.trimmed());
delete m_data;
}
#define CREATE_LOG_OP_REF(x) \
Logger::Log& Logger::Log::operator<<(x t) { \
m_data->m_ts << t << ' '; \
return *this; \
}
CREATE_LOG_OP_REF(uint64_t);
CREATE_LOG_OP_REF(const char*);
CREATE_LOG_OP_REF(const QString&);
CREATE_LOG_OP_REF(const QByteArray&);
CREATE_LOG_OP_REF(void*);
#undef CREATE_LOG_OP_REF
Logger::Log& Logger::Log::operator<<(const QStringList& t) {
m_data->m_ts << '[' << t.join(",") << ']' << ' ';
return *this;
}
Logger::Log& Logger::Log::operator<<(QTextStreamFunction t) {
m_data->m_ts << t;
return *this;
}
// static
QString Logger::sensitive(const QString& input) {
#ifdef QT_DEBUG
return input;
#else
return QString(input.length(), 'X');
#endif
}

88
client/logger.h Normal file
View file

@ -0,0 +1,88 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LOGGER_H
#define LOGGER_H
#include "loglevel.h"
#include <QString>
#include <QTextStream>
constexpr const char* LOG_CAPTIVEPORTAL = "captiveportal";
constexpr const char* LOG_CONTROLLER = "controller";
constexpr const char* LOG_IAP = "iap";
constexpr const char* LOG_INSPECTOR = "inspector";
constexpr const char* LOG_MAIN = "main";
constexpr const char* LOG_MODEL = "model";
constexpr const char* LOG_NETWORKING = "networking";
constexpr const char* LOG_SERVER = "server";
#if defined(MVPN_LINUX) || defined(MVPN_ANDROID)
constexpr const char* LOG_LINUX = "linux";
#endif
#ifdef MVPN_WINDOWS
constexpr const char* LOG_WINDOWS = "windows";
#endif
#if __APPLE__ || defined(MVPN_WASM)
constexpr const char* LOG_MACOS = "macos";
constexpr const char* LOG_IOS = "ios";
#endif
#if defined(MVPN_ANDROID) || defined(UNIT_TEST)
constexpr const char* LOG_ANDROID = "android";
#endif
class Logger {
public:
Logger(const QString& module, const QString& className);
Logger(const QStringList& modules, const QString& className);
const QStringList& modules() const { return m_modules; }
const QString& className() const { return m_className; }
class Log {
public:
Log(Logger* logger, LogLevel level);
~Log();
Log& operator<<(uint64_t t);
Log& operator<<(const char* t);
Log& operator<<(const QString& t);
Log& operator<<(const QStringList& t);
Log& operator<<(const QByteArray& t);
Log& operator<<(QTextStreamFunction t);
Log& operator<<(void* t);
private:
Logger* m_logger;
LogLevel m_logLevel;
struct Data {
Data() : m_ts(&m_buffer, QIODevice::WriteOnly) {}
QString m_buffer;
QTextStream m_ts;
};
Data* m_data;
};
Log error();
Log warning();
Log info();
Log debug();
// Use this to log sensitive data such as IP address, session tokens, and so
// on.
QString sensitive(const QString& input);
private:
QStringList m_modules;
QString m_className;
};
#endif // LOGGER_H

346
client/loghandler.cpp Normal file
View file

@ -0,0 +1,346 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "loghandler.h"
#include "constants.h"
#include "logger.h"
#include <QDate>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QMessageLogContext>
#include <QMutexLocker>
#include <QProcessEnvironment>
#include <QStandardPaths>
#include <QString>
#include <QTextStream>
#ifdef MVPN_ANDROID
# include <android/log.h>
#endif
constexpr qint64 LOG_MAX_FILE_SIZE = 204800;
constexpr const char* LOG_FILENAME = "mozillavpn.txt";
namespace {
QMutex s_mutex;
QString s_location =
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
LogHandler* s_instance = nullptr;
LogLevel qtTypeToLogLevel(QtMsgType type) {
switch (type) {
case QtDebugMsg:
return Debug;
case QtInfoMsg:
return Info;
case QtWarningMsg:
return Warning;
case QtCriticalMsg:
[[fallthrough]];
case QtFatalMsg:
return Error;
default:
return Debug;
}
}
} // namespace
// static
LogHandler* LogHandler::instance() {
QMutexLocker lock(&s_mutex);
return maybeCreate(lock);
}
// static
void LogHandler::messageQTHandler(QtMsgType type,
const QMessageLogContext& context,
const QString& message) {
QMutexLocker lock(&s_mutex);
maybeCreate(lock)->addLog(Log(qtTypeToLogLevel(type), context.file,
context.function, context.line, message),
lock);
}
// static
void LogHandler::messageHandler(LogLevel logLevel, const QStringList& modules,
const QString& className,
const QString& message) {
QMutexLocker lock(&s_mutex);
maybeCreate(lock)->addLog(Log(logLevel, modules, className, message), lock);
}
// static
LogHandler* LogHandler::maybeCreate(const QMutexLocker& proofOfLock) {
if (!s_instance) {
LogLevel minLogLevel = Debug; // TODO: in prod, we should log >= warning
QStringList modules;
QProcessEnvironment pe = QProcessEnvironment::systemEnvironment();
if (pe.contains("MOZVPN_LEVEL")) {
QString level = pe.value("MOZVPN_LEVEL");
if (level == "info")
minLogLevel = Info;
else if (level == "warning")
minLogLevel = Warning;
else if (level == "error")
minLogLevel = Error;
}
if (pe.contains("MOZVPN_LOG")) {
QStringList parts = pe.value("MOZVPN_LOG").split(",");
for (const QString& part : parts) {
modules.append(part.trimmed());
}
}
s_instance = new LogHandler(minLogLevel, modules, proofOfLock);
}
return s_instance;
}
// static
void LogHandler::prettyOutput(QTextStream& out, const LogHandler::Log& log) {
out << "[" << log.m_dateTime.toString("dd.MM.yyyy hh:mm:ss.zzz") << "] ";
switch (log.m_logLevel) {
case Debug:
out << "Debug: ";
break;
case Info:
out << "Info: ";
break;
case Warning:
out << "Warning: ";
break;
case Error:
out << "Error: ";
break;
default:
out << "?!?: ";
break;
}
if (log.m_fromQT) {
out << log.m_message;
if (!log.m_file.isEmpty() || !log.m_function.isEmpty()) {
out << " (";
if (!log.m_file.isEmpty()) {
int pos = log.m_file.lastIndexOf("/");
out << log.m_file.right(log.m_file.length() - pos - 1);
if (log.m_line >= 0) {
out << ":" << log.m_line;
}
if (!log.m_function.isEmpty()) {
out << ", ";
}
}
if (!log.m_function.isEmpty()) {
out << log.m_function;
}
out << ")";
}
} else {
out << "(" << log.m_modules.join("|") << " - " << log.m_className << ") "
<< log.m_message;
}
out << Qt::endl;
}
// static
void LogHandler::enableDebug() {
QMutexLocker lock(&s_mutex);
maybeCreate(lock)->m_showDebug = true;
}
LogHandler::LogHandler(LogLevel minLogLevel, const QStringList& modules,
const QMutexLocker& proofOfLock)
: m_minLogLevel(minLogLevel), m_modules(modules) {
Q_UNUSED(proofOfLock);
#if defined(QT_DEBUG) || defined(MVPN_WASM)
m_showDebug = true;
#endif
if (!s_location.isEmpty()) {
openLogFile(proofOfLock);
}
}
void LogHandler::addLog(const Log& log, const QMutexLocker& proofOfLock) {
if (!matchLogLevel(log, proofOfLock)) {
return;
}
if (!matchModule(log, proofOfLock)) {
return;
}
if (m_output) {
prettyOutput(*m_output, log);
}
if ((log.m_logLevel != LogLevel::Debug) || m_showDebug) {
QTextStream out(stderr);
prettyOutput(out, log);
}
QByteArray buffer;
{
QTextStream out(&buffer);
prettyOutput(out, log);
}
emit logEntryAdded(buffer);
#if defined(MVPN_ANDROID) && defined(QT_DEBUG)
const char* str = buffer.constData();
if (str) {
__android_log_write(ANDROID_LOG_DEBUG, "mozillavpn", str);
}
#endif
}
bool LogHandler::matchModule(const Log& log,
const QMutexLocker& proofOfLock) const {
Q_UNUSED(proofOfLock);
// Let's include QT logs always.
if (log.m_fromQT) {
return true;
}
// If no modules has been specified, let's include all.
if (m_modules.isEmpty()) {
return true;
}
for (const QString& module : log.m_modules) {
if (m_modules.contains(module)) {
return true;
}
}
return false;
}
bool LogHandler::matchLogLevel(const Log& log,
const QMutexLocker& proofOfLock) const {
Q_UNUSED(proofOfLock);
return log.m_logLevel >= m_minLogLevel;
}
// static
void LogHandler::writeLogs(QTextStream& out) {
QMutexLocker lock(&s_mutex);
if (!s_instance || !s_instance->m_logFile) {
return;
}
QString logFileName = s_instance->m_logFile->fileName();
s_instance->closeLogFile(lock);
{
QFile file(logFileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return;
}
out << file.readAll();
}
s_instance->openLogFile(lock);
}
// static
void LogHandler::cleanupLogs() {
QMutexLocker lock(&s_mutex);
cleanupLogFile(lock);
}
// static
void LogHandler::cleanupLogFile(const QMutexLocker& proofOfLock) {
if (!s_instance || !s_instance->m_logFile) {
return;
}
QString logFileName = s_instance->m_logFile->fileName();
s_instance->closeLogFile(proofOfLock);
{
QFile file(logFileName);
file.remove();
}
s_instance->openLogFile(proofOfLock);
}
// static
void LogHandler::setLocation(const QString& path) {
QMutexLocker lock(&s_mutex);
s_location = path;
if (s_instance && s_instance->m_logFile) {
cleanupLogFile(lock);
}
}
void LogHandler::openLogFile(const QMutexLocker& proofOfLock) {
Q_UNUSED(proofOfLock);
Q_ASSERT(!m_logFile);
Q_ASSERT(!m_output);
QDir appDataLocation(s_location);
if (!appDataLocation.exists()) {
QDir tmp(s_location);
tmp.cdUp();
if (!tmp.exists()) {
return;
}
if (!tmp.mkdir(appDataLocation.dirName())) {
return;
}
}
QString logFileName = appDataLocation.filePath(LOG_FILENAME);
m_logFile = new QFile(logFileName);
if (m_logFile->size() > LOG_MAX_FILE_SIZE) {
m_logFile->remove();
}
if (!m_logFile->open(QIODevice::WriteOnly | QIODevice::Append |
QIODevice::Text)) {
delete m_logFile;
m_logFile = nullptr;
return;
}
m_output = new QTextStream(m_logFile);
addLog(Log(Debug, QStringList{LOG_MAIN}, "LogHandler",
QString("Log file: %1").arg(logFileName)),
proofOfLock);
}
void LogHandler::closeLogFile(const QMutexLocker& proofOfLock) {
Q_UNUSED(proofOfLock);
if (m_logFile) {
delete m_output;
m_output = nullptr;
delete m_logFile;
m_logFile = nullptr;
}
}

102
client/loghandler.h Normal file
View file

@ -0,0 +1,102 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LOGHANDLER_H
#define LOGHANDLER_H
#include "loglevel.h"
#include <QDateTime>
#include <QObject>
#include <QVector>
class QFile;
class QMutexLocker;
class QTextStream;
class LogHandler final : public QObject {
Q_OBJECT
public:
struct Log {
Log() = default;
Log(LogLevel logLevel, const QStringList& modules, const QString& className,
const QString& message)
: m_logLevel(logLevel),
m_dateTime(QDateTime::currentDateTime()),
m_modules(modules),
m_className(className),
m_message(message),
m_fromQT(false) {}
Log(LogLevel logLevel, const QString& file, const QString& function,
uint32_t line, const QString& message)
: m_logLevel(logLevel),
m_dateTime(QDateTime::currentDateTime()),
m_file(file),
m_function(function),
m_message(message),
m_line(line),
m_fromQT(true) {}
LogLevel m_logLevel = LogLevel::Debug;
QDateTime m_dateTime;
QString m_file;
QString m_function;
QStringList m_modules;
QString m_className;
QString m_message;
int32_t m_line = -1;
bool m_fromQT = false;
};
static LogHandler* instance();
static void messageQTHandler(QtMsgType type,
const QMessageLogContext& context,
const QString& message);
static void messageHandler(LogLevel logLevel, const QStringList& modules,
const QString& className, const QString& message);
static void prettyOutput(QTextStream& out, const LogHandler::Log& log);
static void writeLogs(QTextStream& out);
static void cleanupLogs();
static void setLocation(const QString& path);
static void enableDebug();
signals:
void logEntryAdded(const QByteArray& log);
private:
LogHandler(LogLevel m_minLogLevel, const QStringList& modules,
const QMutexLocker& proofOfLock);
static LogHandler* maybeCreate(const QMutexLocker& proofOfLock);
void addLog(const Log& log, const QMutexLocker& proofOfLock);
bool matchLogLevel(const Log& log, const QMutexLocker& proofOfLock) const;
bool matchModule(const Log& log, const QMutexLocker& proofOfLock) const;
void openLogFile(const QMutexLocker& proofOfLock);
void closeLogFile(const QMutexLocker& proofOfLock);
static void cleanupLogFile(const QMutexLocker& proofOfLock);
const LogLevel m_minLogLevel;
const QStringList m_modules;
bool m_showDebug = false;
QFile* m_logFile = nullptr;
QTextStream* m_output = nullptr;
};
#endif // LOGHANDLER_H

15
client/loglevel.h Normal file
View file

@ -0,0 +1,15 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LOGLEVEL_H
#define LOGLEVEL_H
enum LogLevel {
Debug,
Info,
Warning,
Error,
};
#endif // LOGLEVEL_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -0,0 +1,68 @@
{
"images" : [
{
"filename" : "16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "16@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "32@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"filename" : "128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"filename" : "128@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"filename" : "256.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "256@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "512@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>LSMultipleInstancesProhibited</key>
<true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,29 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "wireguard-go-version.h"
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include <stdbool.h>
#include <stdint.h>
#define WG_KEY_LEN (32)
#define WG_KEY_LEN_BASE64 (45)
#define WG_KEY_LEN_HEX (65)
void key_to_base64(char base64[WG_KEY_LEN_BASE64],
const uint8_t key[WG_KEY_LEN]);
bool key_from_base64(uint8_t key[WG_KEY_LEN], const char* base64);
void key_to_hex(char hex[WG_KEY_LEN_HEX], const uint8_t key[WG_KEY_LEN]);
bool key_from_hex(uint8_t key[WG_KEY_LEN], const char* hex);
bool key_eq(const uint8_t key1[WG_KEY_LEN], const uint8_t key2[WG_KEY_LEN]);
void write_msg_to_log(const char* tag, const char* msg);
#import "TargetConditionals.h"
#if TARGET_OS_OSX
# include <libproc.h>
#endif

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.application-identifier</key>
<string>$(DEVELOPMENT_TEAM).$(APP_ID_MACOS)</string>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(DEVELOPMENT_TEAM).*</string>
</array>
<key>com.apple.developer.team-identifier</key>
<string>$(DEVELOPMENT_TEAM)</string>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>$(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS)</string>
</array>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.application-identifier</key>
<string>$(DEVELOPMENT_TEAM).$(APP_ID_MACOS)</string>
<key>keychain-access-groups</key>
<array>
<string>$(DEVELOPMENT_TEAM).*</string>
</array>
<key>com.apple.developer.team-identifier</key>
<string>$(DEVELOPMENT_TEAM)</string>
<key>com.apple.security.application-groups</key>
<array>
<string>$(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS)</string>
</array>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

3
client/macos/gobridge/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.cache/
.tmp/
out/

View file

@ -0,0 +1,225 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2018-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main
// #include <stdlib.h>
// #include <sys/types.h>
// static void callLogger(void *func, void *ctx, int level, const char *msg)
// {
// ((void(*)(void *, int, const char *))func)(ctx, level, msg);
// }
import "C"
import (
"fmt"
"math"
"os"
"os/signal"
"runtime"
"runtime/debug"
"strings"
"time"
"unsafe"
"golang.org/x/sys/unix"
"golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
)
var loggerFunc unsafe.Pointer
var loggerCtx unsafe.Pointer
type CLogger int
func cstring(s string) *C.char {
b, err := unix.BytePtrFromString(s)
if err != nil {
b := [1]C.char{}
return &b[0]
}
return (*C.char)(unsafe.Pointer(b))
}
func (l CLogger) Printf(format string, args ...interface{}) {
if uintptr(loggerFunc) == 0 {
return
}
C.callLogger(loggerFunc, loggerCtx, C.int(l), cstring(fmt.Sprintf(format, args...)))
}
type tunnelHandle struct {
*device.Device
*device.Logger
}
var tunnelHandles = make(map[int32]tunnelHandle)
func init() {
signals := make(chan os.Signal)
signal.Notify(signals, unix.SIGUSR2)
go func() {
buf := make([]byte, os.Getpagesize())
for {
select {
case <-signals:
n := runtime.Stack(buf, true)
buf[n] = 0
if uintptr(loggerFunc) != 0 {
C.callLogger(loggerFunc, loggerCtx, 0, (*C.char)(unsafe.Pointer(&buf[0])))
}
}
}
}()
}
//export wgSetLogger
func wgSetLogger(context, loggerFn uintptr) {
loggerCtx = unsafe.Pointer(context)
loggerFunc = unsafe.Pointer(loggerFn)
}
//export wgTurnOn
func wgTurnOn(settings *C.char, tunFd int32) int32 {
logger := &device.Logger{
Verbosef: CLogger(0).Printf,
Errorf: CLogger(1).Printf,
}
dupTunFd, err := unix.Dup(int(tunFd))
if err != nil {
logger.Errorf("Unable to dup tun fd: %v", err)
return -1
}
err = unix.SetNonblock(dupTunFd, true)
if err != nil {
logger.Errorf("Unable to set tun fd as non blocking: %v", err)
unix.Close(dupTunFd)
return -1
}
tun, err := tun.CreateTUNFromFile(os.NewFile(uintptr(dupTunFd), "/dev/tun"), 0)
if err != nil {
logger.Errorf("Unable to create new tun device from fd: %v", err)
unix.Close(dupTunFd)
return -1
}
logger.Verbosef("Attaching to interface")
dev := device.NewDevice(tun, conn.NewStdNetBind(), logger)
err = dev.IpcSet(C.GoString(settings))
if err != nil {
logger.Errorf("Unable to set IPC settings: %v", err)
unix.Close(dupTunFd)
dev.Close()
return -1
}
dev.Up()
logger.Verbosef("Device started")
var i int32
for i = 0; i < math.MaxInt32; i++ {
if _, exists := tunnelHandles[i]; !exists {
break
}
}
if i == math.MaxInt32 {
unix.Close(dupTunFd)
dev.Close()
return -1
}
tunnelHandles[i] = tunnelHandle{dev, logger}
return i
}
//export wgTurnOff
func wgTurnOff(tunnelHandle int32) {
dev, ok := tunnelHandles[tunnelHandle]
if !ok {
return
}
delete(tunnelHandles, tunnelHandle)
dev.Close()
}
//export wgSetConfig
func wgSetConfig(tunnelHandle int32, settings *C.char) int64 {
dev, ok := tunnelHandles[tunnelHandle]
if !ok {
return 0
}
err := dev.IpcSet(C.GoString(settings))
if err != nil {
dev.Errorf("Unable to set IPC settings: %v", err)
if ipcErr, ok := err.(*device.IPCError); ok {
return ipcErr.ErrorCode()
}
return -1
}
return 0
}
//export wgGetConfig
func wgGetConfig(tunnelHandle int32) *C.char {
device, ok := tunnelHandles[tunnelHandle]
if !ok {
return nil
}
settings, err := device.IpcGet()
if err != nil {
return nil
}
return C.CString(settings)
}
//export wgBumpSockets
func wgBumpSockets(tunnelHandle int32) {
dev, ok := tunnelHandles[tunnelHandle]
if !ok {
return
}
go func() {
for i := 0; i < 10; i++ {
err := dev.BindUpdate()
if err == nil {
dev.SendKeepalivesToPeersWithCurrentKeypair()
return
}
dev.Errorf("Unable to update bind, try %d: %v", i+1, err)
time.Sleep(time.Second / 2)
}
dev.Errorf("Gave up trying to update bind; tunnel is likely dysfunctional")
}()
}
//export wgDisableSomeRoamingForBrokenMobileSemantics
func wgDisableSomeRoamingForBrokenMobileSemantics(tunnelHandle int32) {
dev, ok := tunnelHandles[tunnelHandle]
if !ok {
return
}
dev.DisableSomeRoamingForBrokenMobileSemantics()
}
//export wgVersion
func wgVersion() *C.char {
info, ok := debug.ReadBuildInfo()
if !ok {
return C.CString("unknown")
}
for _, dep := range info.Deps {
if dep.Path == "golang.zx2c4.com/wireguard" {
parts := strings.Split(dep.Version, "-")
if len(parts) == 3 && len(parts[2]) == 12 {
return C.CString(parts[2][:7])
}
return C.CString(dep.Version)
}
}
return C.CString("unknown")
}
func main() {}

View file

@ -0,0 +1 @@
// Empty

View file

@ -0,0 +1,8 @@
module golang.zx2c4.com/wireguard/apple
go 1.16
require (
golang.org/x/sys v0.0.0-20210308170721-88b6017d0656
golang.zx2c4.com/wireguard v0.0.0-20210307162820-f4695db51c39
)

View file

@ -0,0 +1,19 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305215415-5cdee2b1b5a0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210308170721-88b6017d0656 h1:FuBaiPCiXkq4v+JY5JEGPU/HwEZwpVyDbu/KBz9fU+4=
golang.org/x/sys v0.0.0-20210308170721-88b6017d0656/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.zx2c4.com/wireguard v0.0.0-20210307162820-f4695db51c39 h1:yv331J9aB1fuvxzneUKsRnWyhwK+aj495rADUXSP7Uk=
golang.zx2c4.com/wireguard v0.0.0-20210307162820-f4695db51c39/go.mod h1:ojGPy+9W6ZSM8anL+xC67fvh8zPQJwA6KpFOHyDWLX4=

View file

@ -0,0 +1,61 @@
From 516dc0c15ff1ab781e0677606b5be72919251b3e Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Wed, 9 Dec 2020 14:07:06 +0100
Subject: [PATCH] runtime: use libc_mach_continuous_time in nanotime on Darwin
This makes timers account for having expired while a computer was
asleep, which is quite common on mobile devices. Note that
continuous_time absolute_time, except that it takes into account
time spent in suspend.
Fixes #24595
Change-Id: Ia3282e8bd86f95ad2b76427063e60a005563f4eb
---
src/runtime/sys_darwin.go | 2 +-
src/runtime/sys_darwin_amd64.s | 2 +-
src/runtime/sys_darwin_arm64.s | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go
index 4a3f2fc453..4a69403b32 100644
--- a/src/runtime/sys_darwin.go
+++ b/src/runtime/sys_darwin.go
@@ -440,7 +440,7 @@ func setNonblock(fd int32) {
//go:cgo_import_dynamic libc_usleep usleep "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_mach_timebase_info mach_timebase_info "/usr/lib/libSystem.B.dylib"
-//go:cgo_import_dynamic libc_mach_absolute_time mach_absolute_time "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_mach_continuous_time mach_continuous_time "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_clock_gettime clock_gettime "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_sigaction sigaction "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_sigmask pthread_sigmask "/usr/lib/libSystem.B.dylib"
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index 630fb5df64..4499c88802 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -114,7 +114,7 @@ TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
MOVQ DI, BX
- CALL libc_mach_absolute_time(SB)
+ CALL libc_mach_continuous_time(SB)
MOVQ AX, 0(BX)
MOVL timebase<>+machTimebaseInfo_numer(SB), SI
MOVL timebase<>+machTimebaseInfo_denom(SB), DI // atomic read
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index 96d2ed1076..f046545395 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -143,7 +143,7 @@ GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$40
MOVD R0, R19
- BL libc_mach_absolute_time(SB)
+ BL libc_mach_continuous_time(SB)
MOVD R0, 0(R19)
MOVW timebase<>+machTimebaseInfo_numer(SB), R20
MOVD $timebase<>+machTimebaseInfo_denom(SB), R21
--
2.30.1

View file

@ -0,0 +1,5 @@
module WireGuardKitGo {
umbrella header "wireguard.h"
link "wg-go"
export *
}

View file

@ -0,0 +1 @@
#define WIREGUARD_GO_VERSION "0.0.0"

View file

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved.
*/
#ifndef WIREGUARD_H
#define WIREGUARD_H
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
typedef void (*logger_fn_t)(void* context, int level, const char* msg);
extern void wgSetLogger(void* context, logger_fn_t logger_fn);
extern int wgTurnOn(const char* settings, int32_t tun_fd);
extern void wgTurnOff(int handle);
extern int64_t wgSetConfig(int handle, const char* settings);
extern char* wgGetConfig(int handle);
extern void wgBumpSockets(int handle);
extern void wgDisableSomeRoamingForBrokenMobileSemantics(int handle);
extern const char* wgVersion();
#endif

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>LSBackgroundOnly</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.application-identifier</key>
<string>$(DEVELOPMENT_TEAM).$(NETEXT_ID_MACOS)</string>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(DEVELOPMENT_TEAM).*</string>
</array>
<key>com.apple.developer.team-identifier</key>
<string>$(DEVELOPMENT_TEAM)</string>
<key>com.apple.developer.system-extension.install</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>$(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS)</string>
</array>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>AmneziaVPNNetworkExtension</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.networkextension.packet-tunnel</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,25 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "macos/gobridge/wireguard.h"
#include "wireguard-go-version.h"
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include <stdbool.h>
#include <stdint.h>
#define WG_KEY_LEN (32)
#define WG_KEY_LEN_BASE64 (45)
#define WG_KEY_LEN_HEX (65)
void key_to_base64(char base64[WG_KEY_LEN_BASE64],
const uint8_t key[WG_KEY_LEN]);
bool key_from_base64(uint8_t key[WG_KEY_LEN], const char* base64);
void key_to_hex(char hex[WG_KEY_LEN_HEX], const uint8_t key[WG_KEY_LEN]);
bool key_from_hex(uint8_t key[WG_KEY_LEN], const char* hex);
bool key_eq(const uint8_t key1[WG_KEY_LEN], const uint8_t key2[WG_KEY_LEN]);
void write_msg_to_log(const char* tag, const char* msg);

View file

@ -116,15 +116,15 @@ int main(int argc, char *argv[])
app.setQuitOnLastWindowClosed(false); app.setQuitOnLastWindowClosed(false);
qRegisterMetaType<VpnProtocol::ConnectionState>("VpnProtocol::ConnectionState"); qRegisterMetaType<VpnProtocol::VpnConnectionState>("VpnProtocol::VpnConnectionState");
qRegisterMetaType<ServerCredentials>("ServerCredentials"); qRegisterMetaType<ServerCredentials>("ServerCredentials");
qRegisterMetaType<DockerContainer>("DockerContainer"); qRegisterMetaType<DockerContainer>("DockerContainer");
qRegisterMetaType<TransportProto>("TransportProto"); qRegisterMetaType<TransportProto>("TransportProto");
qRegisterMetaType<Protocol>("Protocol"); qRegisterMetaType<Proto>("Proto");
qRegisterMetaType<ServiceType>("ServiceType"); qRegisterMetaType<ServiceType>("ServiceType");
qRegisterMetaType<Page>("Page"); qRegisterMetaType<Page>("Page");
qRegisterMetaType<VpnProtocol::ConnectionState>("ConnectionState"); qRegisterMetaType<VpnProtocol::VpnConnectionState>("ConnectionState");
qRegisterMetaType<PageProtocolLogicBase *>("PageProtocolLogicBase *"); qRegisterMetaType<PageProtocolLogicBase *>("PageProtocolLogicBase *");
@ -160,7 +160,7 @@ int main(int argc, char *argv[])
engine->rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic()); engine->rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic());
engine->rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic()); engine->rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic());
engine->rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic()); engine->rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic());
engine->rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverVpnProtocolsLogic()); engine->rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverprotocolsLogic());
engine->rootContext()->setContextProperty("ShareConnectionLogic", uiLogic->shareConnectionLogic()); engine->rootContext()->setContextProperty("ShareConnectionLogic", uiLogic->shareConnectionLogic());
engine->rootContext()->setContextProperty("SitesLogic", uiLogic->sitesLogic()); engine->rootContext()->setContextProperty("SitesLogic", uiLogic->sitesLogic());
engine->rootContext()->setContextProperty("StartPageLogic", uiLogic->startPageLogic()); engine->rootContext()->setContextProperty("StartPageLogic", uiLogic->startPageLogic());

View file

@ -39,7 +39,7 @@ public:
void setVpnConfig(const QJsonObject &newVpnConfig); void setVpnConfig(const QJsonObject &newVpnConfig);
signals: signals:
void connectionStateChanged(VpnProtocol::ConnectionState state); void connectionStateChanged(VpnProtocol::VpnConnectionState state);
// This signal is emitted when the controller is initialized. Note that the // This signal is emitted when the controller is initialized. Note that the
// VPN tunnel can be already active. In this case, "connected" should be set // VPN tunnel can be already active. In this case, "connected" should be set

View file

@ -0,0 +1,29 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "wireguard-go-version.h"
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include <stdbool.h>
#include <stdint.h>
#define WG_KEY_LEN (32)
#define WG_KEY_LEN_BASE64 (45)
#define WG_KEY_LEN_HEX (65)
void key_to_base64(char base64[WG_KEY_LEN_BASE64],
const uint8_t key[WG_KEY_LEN]);
bool key_from_base64(uint8_t key[WG_KEY_LEN], const char* base64);
void key_to_hex(char hex[WG_KEY_LEN_HEX], const uint8_t key[WG_KEY_LEN]);
bool key_from_hex(uint8_t key[WG_KEY_LEN], const char* hex);
bool key_eq(const uint8_t key1[WG_KEY_LEN], const uint8_t key2[WG_KEY_LEN]);
void write_msg_to_log(const char* tag, const char* msg);
#import "TargetConditionals.h"
#if TARGET_OS_OSX
# include <libproc.h>
#endif

View file

@ -0,0 +1,127 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BIGINT_H
#define BIGINT_H
#include <QVector>
// This BigInt implementation is meant to be used for IPv6 addresses. It
// doesn't support dynamic resize: when the max size is reached, the value
// overflows. If you need to change the size, use `resize()`.
class BigInt final {
public:
explicit BigInt(uint8_t bytes) {
m_value.resize(bytes);
memset(m_value.data(), 0, bytes);
}
BigInt(const BigInt& other) { m_value = other.m_value; }
const uint8_t* value() const { return m_value.data(); }
uint8_t size() const { return m_value.size(); }
// Assign operator.
BigInt& operator=(const BigInt& other) {
m_value = other.m_value;
return *this;
}
// Comparison operators.
bool operator==(const BigInt& other) const {
return m_value == other.m_value;
}
bool operator!=(const BigInt& other) const { return !(*this == other); }
bool operator<(const BigInt& other) const { return cmp(other) < 0; }
bool operator>(const BigInt& other) const { return cmp(other) > 0; }
bool operator<=(const BigInt& other) const { return cmp(other) <= 0; }
bool operator>=(const BigInt& other) const { return cmp(other) >= 0; }
// math operators (only some of them are implemented)
BigInt& operator++() {
for (int i = size() - 1; i >= 0; --i) {
if (m_value[i] < UINT8_MAX) {
++m_value[i];
return *this;
}
m_value[i] = 0;
}
// overflow
memset(m_value.data(), 0, size());
return *this;
}
BigInt& operator+=(const BigInt& other) {
Q_ASSERT(other.size() == size());
uint8_t carry = 0;
for (int i = m_value.size() - 1; i >= 0; --i) {
uint16_t total = carry + m_value[i] + other.m_value[i];
m_value[i] = (uint8_t)(total & UINT8_MAX);
carry = (uint8_t)((total & 0xFF00) >> 8);
}
return *this;
}
// Shift operators
BigInt operator>>(int shift) {
BigInt x(size());
x = *this;
for (int i = 0; i < shift; i++) {
BigInt a(size());
a = x;
a.m_value[size() - 1] = x.m_value[size() - 1] >> 1;
for (int j = size() - 2; j >= 0; j--) {
a.m_value[j] = x.m_value[j] >> 1;
if ((x.m_value[j] & 1) != 0) {
a.m_value[j + 1] |= 128; // Set most significant bit or a uint8_t
}
}
x = a;
}
return x;
}
void setValueAt(uint8_t value, uint8_t pos) {
Q_ASSERT(pos < size());
m_value[pos] = value;
}
uint8_t valueAt(uint8_t pos) const {
Q_ASSERT(size() > pos);
return m_value[pos];
}
private:
int cmp(const BigInt& other) const {
Q_ASSERT(size() == other.size());
for (int i = 0; i < size(); i++) {
int diff = (m_value[i] - other.m_value[i]);
if (diff != 0) return diff;
}
return 0;
}
private:
QVector<uint8_t> m_value;
};
#endif // BIGINT_H

View file

@ -0,0 +1,86 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BIGINTIPV6ADDR_H
#define BIGINTIPV6ADDR_H
#include "bigint.h"
#include <QHostAddress>
class BigIntIPv6Addr final {
public:
BigIntIPv6Addr() : m_value(16) {}
explicit BigIntIPv6Addr(const Q_IPV6ADDR& a) : m_value(16) {
for (int i = 0; i < 16; ++i) m_value.setValueAt(a[i], i);
}
BigIntIPv6Addr(const BigIntIPv6Addr& other) : m_value(16) { *this = other; }
Q_IPV6ADDR value() const {
Q_IPV6ADDR addr;
for (int i = 0; i < 16; ++i) addr[i] = m_value.valueAt(i);
return addr;
}
// Assign operator.
BigIntIPv6Addr& operator=(const BigIntIPv6Addr& other) {
m_value = other.m_value;
return *this;
}
// Comparison operators.
bool operator==(const BigIntIPv6Addr& other) const {
return m_value == other.m_value;
}
bool operator!=(const BigIntIPv6Addr& other) const {
return m_value != other.m_value;
}
bool operator<(const BigIntIPv6Addr& other) const {
return m_value < other.m_value;
}
bool operator>(const BigIntIPv6Addr& other) const {
return m_value > other.m_value;
}
bool operator<=(const BigIntIPv6Addr& other) const {
return m_value <= other.m_value;
}
bool operator>=(const BigIntIPv6Addr& other) const {
return m_value >= other.m_value;
}
// math operators (only some of them are implemented)
BigIntIPv6Addr& operator++() {
++m_value;
return *this;
}
BigIntIPv6Addr& operator+=(const BigIntIPv6Addr& b) {
m_value += b.m_value;
return *this;
}
// Shift operators
BigIntIPv6Addr operator>>(int shift) {
BigIntIPv6Addr x;
x.m_value = m_value >> shift;
return x;
}
private:
BigInt m_value;
};
#endif // BIGINTIPV6ADDR_H

View file

@ -0,0 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef IOSADJUSTHELPER_H
#define IOSADJUSTHELPER_H
#include <QString>
class IOSAdjustHelper final {
public:
static void initialize();
static void trackEvent(const QString& eventToken);
};
#endif // IOSADJUSTHELPER_H

View file

@ -0,0 +1,37 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "iosadjusthelper.h"
#include "logger.h"
#include "constants.h"
#import <AdjustSdk/Adjust.h>
namespace {
Logger logger(LOG_IOS, "IOSAdjustHelper");
} // namespace
void IOSAdjustHelper::initialize() {
NSString *adjustToken = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"ADJUST_SDK_TOKEN"];
if(adjustToken.length) {
NSString *environment = Constants::inProduction() ? ADJEnvironmentProduction : ADJEnvironmentSandbox;
ADJConfig *adjustConfig = [ADJConfig configWithAppToken:adjustToken
environment:environment];
[adjustConfig setLogLevel:ADJLogLevelDebug];
[Adjust appDidLaunch:adjustConfig];
}
}
void IOSAdjustHelper::trackEvent(const QString& eventToken) {
NSString *adjustToken = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"ADJUST_SDK_TOKEN"];
if(adjustToken.length) {
ADJEvent *event = [ADJEvent eventWithEventToken:eventToken.toNSString()];
[Adjust trackEvent:event];
}
}

View file

@ -0,0 +1,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef IOSAUTHENTICATIONLISTENER_H
#define IOSAUTHENTICATIONLISTENER_H
#include "authenticationlistener.h"
#include <QObject>
class IOSAuthenticationListener final : public AuthenticationListener {
Q_DISABLE_COPY_MOVE(IOSAuthenticationListener)
public:
IOSAuthenticationListener(QObject* parent);
~IOSAuthenticationListener();
void start(const QString& codeChallenge, const QString& codeChallengeMethod,
const QString& emailAddress) override;
};
#endif // IOSAUTHENTICATIONLISTENER_H

View file

@ -0,0 +1,139 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "iosauthenticationlistener.h"
#include "leakdetector.h"
#include "logger.h"
#include "mozillavpn.h"
#include "qmlengineholder.h"
#include <QApplication>
#include <QUrl>
#include <QUrlQuery>
#include <QtGui/qpa/qplatformnativeinterface.h>
#include <QtGui>
#include <QWindow>
#include <QQmlApplicationEngine>
#import <UIKit/UIKit.h>
#import <AuthenticationServices/ASWebAuthenticationSession.h>
namespace {
Logger logger({LOG_IOS, LOG_MAIN}, "IOSAuthenticationListener");
ASWebAuthenticationSession* session = nullptr;
} // namespace
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
@interface ContextProvider : NSObject <ASWebAuthenticationPresentationContextProviding> {
UIView* m_view;
}
@end
@implementation ContextProvider
- (id)initWithUIView:(UIView*)uiView {
self = [super init];
if (self) {
m_view = uiView;
}
return self;
}
# pragma mark - ASWebAuthenticationPresentationContextProviding
- (nonnull ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:
(nonnull ASWebAuthenticationSession*)session API_AVAILABLE(ios(13.0)) {
return m_view.window;
}
@end
#endif
IOSAuthenticationListener::IOSAuthenticationListener(QObject* parent)
: AuthenticationListener(parent) {
MVPN_COUNT_CTOR(IOSAuthenticationListener);
}
IOSAuthenticationListener::~IOSAuthenticationListener() {
MVPN_COUNT_DTOR(IOSAuthenticationListener);
}
void IOSAuthenticationListener::start(const QString& codeChallenge,
const QString& codeChallengeMethod,
const QString& emailAddress) {
logger.debug() << "IOSAuthenticationListener initialize";
QUrl url(createAuthenticationUrl(AmneziaVPN::AuthenticationInBrowser, codeChallenge,
codeChallengeMethod, emailAddress));
QUrlQuery query(url.query());
query.addQueryItem("platform", "ios");
url.setQuery(query);
#ifdef QT_DEBUG
logger.debug() << "Authentication URL:" << url.toString();
#endif
if (session) {
[session dealloc];
session = nullptr;
}
session = [[ASWebAuthenticationSession alloc]
initWithURL:url.toNSURL()
callbackURLScheme:@"mozilla-vpn"
completionHandler:^(NSURL* _Nullable callbackURL, NSError* _Nullable error) {
[session dealloc];
session = nullptr;
if (error) {
logger.error() << "Authentication failed:"
<< QString::fromNSString([error localizedDescription]);
logger.error() << "Code:" << [error code];
logger.error() << "Suggestion:"
<< QString::fromNSString([error localizedRecoverySuggestion]);
logger.error() << "Reason:" << QString::fromNSString([error localizedFailureReason]);
if ([error code] == ASWebAuthenticationSessionErrorCodeCanceledLogin) {
emit abortedByUser();
} else {
emit failed(ErrorHandler::RemoteServiceError);
}
return;
}
QUrl callbackUrl = QUrl::fromNSURL(callbackURL);
logger.debug() << "Authentication completed";
Q_ASSERT(callbackUrl.hasQuery());
QUrlQuery callbackUrlQuery(callbackUrl.query());
Q_ASSERT(callbackUrlQuery.hasQueryItem("code"));
QString code = callbackUrlQuery.queryItemValue("code");
emit completed(code);
}];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
QObject* rootObject = QmlEngineHolder::instance()->engine()->rootObjects().first();
QWindow* window = qobject_cast<QWindow*>(rootObject);
Q_ASSERT(window);
UIView* view = static_cast<UIView*>(
QGuiApplication::platformNativeInterface()->nativeResourceForWindow("uiview", window));
if (@available(iOS 13, *)) {
session.presentationContextProvider = [[ContextProvider alloc] initWithUIView:view];
}
#endif
if (![session start]) {
[session dealloc];
session = nullptr;
logger.error() << "Authentication failed: session doesn't start.";
emit failed(ErrorHandler::RemoteServiceError);
}
}

View file

@ -0,0 +1,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef IOSCONTROLLER_H
#define IOSCONTROLLER_H
#include "vpnprotocol.h"
#include <QObject>
class IOSVPNProtocol final : public VpnProtocol {
Q_DISABLE_COPY_MOVE(IOSVPNProtocol)
public:
IOSController();
~IOSController();
void initialize(const Device* device, const Keys* keys) override;
void activate(const QList<Server>& serverList, const Device* device,
const Keys* keys,
const QList<IPAddressRange>& allowedIPAddressRanges,
const QList<QString>& vpnDisabledApps,
const QHostAddress& dnsServer, Reason reason) override;
void deactivate(Reason reason) override;
void checkStatus() override;
void getBackendLogs(std::function<void(const QString&)>&& callback) override;
void cleanupBackendLogs() override;
private:
bool m_checkingStatus = false;
};
#endif // IOSCONTROLLER_H

View file

@ -0,0 +1,240 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ioscontroller.h"
#include "Mozilla_VPN-Swift.h"
#include "device.h"
#include "ipaddressrange.h"
#include "keys.h"
#include "leakdetector.h"
#include "logger.h"
#include "mozillavpn.h"
#include "server.h"
#include "settingsholder.h"
#include <QByteArray>
#include <QFile>
#include <QHostAddress>
namespace {
Logger logger({LOG_IOS, LOG_CONTROLLER}, "IOSController");
// Our Swift singleton.
IOSControllerImpl* impl = nullptr;
} // namespace
IOSController::IOSController() {
MVPN_COUNT_CTOR(IOSController);
logger.debug() << "created";
Q_ASSERT(!impl);
}
IOSController::~IOSController() {
MVPN_COUNT_DTOR(IOSController);
logger.debug() << "deallocated";
if (impl) {
[impl dealloc];
impl = nullptr;
}
}
void IOSController::initialize(const Device* device, const Keys* keys) {
Q_ASSERT(!impl);
Q_UNUSED(device);
logger.debug() << "Initializing Swift Controller";
static bool creating = false;
// No nested creation!
Q_ASSERT(creating == false);
creating = true;
QByteArray key = QByteArray::fromBase64(keys->privateKey().toLocal8Bit());
impl = [[IOSControllerImpl alloc] initWithBundleID:@VPN_NE_BUNDLEID
privateKey:key.toNSData()
deviceIpv4Address:device->ipv4Address().toNSString()
deviceIpv6Address:device->ipv6Address().toNSString()
closure:^(ConnectionState state, NSDate* date) {
logger.debug() << "Creation completed with connection state:" << state;
creating = false;
switch (state) {
case ConnectionStateError: {
[impl dealloc];
impl = nullptr;
emit initialized(false, false, QDateTime());
return;
}
case ConnectionStateConnected: {
Q_ASSERT(date);
QDateTime qtDate(QDateTime::fromNSDate(date));
emit initialized(true, true, qtDate);
return;
}
case ConnectionStateDisconnected:
// Just in case we are connecting, let's call disconnect.
[impl disconnect];
emit initialized(true, false, QDateTime());
return;
}
}
callback:^(BOOL a_connected) {
logger.debug() << "State changed: " << a_connected;
if (a_connected) {
emit connected();
return;
}
emit disconnected();
}];
}
void IOSController::activate(const QList<Server>& serverList, const Device* device,
const Keys* keys, const QList<IPAddressRange>& allowedIPAddressRanges,
const QList<QString>& vpnDisabledApps, const QHostAddress& dnsServer,
Reason reason) {
Q_UNUSED(device);
Q_UNUSED(keys);
Q_ASSERT(serverList.length() == 1);
const Server& server = serverList[0];
// This feature is not supported on macos/ios yet.
Q_ASSERT(vpnDisabledApps.isEmpty());
logger.debug() << "IOSController activating" << server.hostname();
if (!impl) {
logger.error() << "Controller not correctly initialized";
emit disconnected();
return;
}
NSMutableArray<VPNIPAddressRange*>* allowedIPAddressRangesNS =
[NSMutableArray<VPNIPAddressRange*> arrayWithCapacity:allowedIPAddressRanges.length()];
for (const IPAddressRange& i : allowedIPAddressRanges) {
VPNIPAddressRange* range =
[[VPNIPAddressRange alloc] initWithAddress:i.ipAddress().toNSString()
networkPrefixLength:i.range()
isIpv6:i.type() == IPAddressRange::IPv6];
[allowedIPAddressRangesNS addObject:[range autorelease]];
}
[impl connectWithDnsServer:dnsServer.toString().toNSString()
serverIpv6Gateway:server.ipv6Gateway().toNSString()
serverPublicKey:server.publicKey().toNSString()
serverIpv4AddrIn:server.ipv4AddrIn().toNSString()
serverPort:server.choosePort()
allowedIPAddressRanges:allowedIPAddressRangesNS
ipv6Enabled:SettingsHolder::instance()->ipv6Enabled()
reason:reason
failureCallback:^() {
logger.error() << "IOSSWiftController - connection failed";
emit disconnected();
}];
}
void IOSController::deactivate(Reason reason) {
logger.debug() << "IOSController deactivated";
if (reason != ReasonNone) {
logger.debug() << "We do not need to disable the VPN for switching or connection check.";
emit disconnected();
return;
}
if (!impl) {
logger.error() << "Controller not correctly initialized";
emit disconnected();
return;
}
[impl disconnect];
}
void IOSController::checkStatus() {
logger.debug() << "Checking status";
if (m_checkingStatus) {
logger.warning() << "We are still waiting for the previous status.";
return;
}
if (!impl) {
logger.error() << "Controller not correctly initialized";
return;
}
m_checkingStatus = true;
[impl checkStatusWithCallback:^(NSString* serverIpv4Gateway, NSString* deviceIpv4Address,
NSString* configString) {
QString config = QString::fromNSString(configString);
m_checkingStatus = false;
if (config.isEmpty()) {
return;
}
uint64_t txBytes = 0;
uint64_t rxBytes = 0;
QStringList lines = config.split("\n");
for (const QString& line : lines) {
if (line.startsWith("tx_bytes=")) {
txBytes = line.split("=")[1].toULongLong();
} else if (line.startsWith("rx_bytes=")) {
rxBytes = line.split("=")[1].toULongLong();
}
if (txBytes && rxBytes) {
break;
}
}
logger.debug() << "ServerIpv4Gateway:" << QString::fromNSString(serverIpv4Gateway)
<< "DeviceIpv4Address:" << QString::fromNSString(deviceIpv4Address)
<< "RxBytes:" << rxBytes << "TxBytes:" << txBytes;
emit statusUpdated(QString::fromNSString(serverIpv4Gateway),
QString::fromNSString(deviceIpv4Address), txBytes, rxBytes);
}];
}
void IOSController::getBackendLogs(std::function<void(const QString&)>&& a_callback) {
std::function<void(const QString&)> callback = std::move(a_callback);
QString groupId(GROUP_ID);
NSURL* groupPath = [[NSFileManager defaultManager]
containerURLForSecurityApplicationGroupIdentifier:groupId.toNSString()];
NSURL* path = [groupPath URLByAppendingPathComponent:@"networkextension.log"];
QFile file(QString::fromNSString([path path]));
if (!file.open(QIODevice::ReadOnly)) {
callback("Network extension log file missing or unreadable.");
return;
}
QByteArray content = file.readAll();
callback(content);
}
void IOSController::cleanupBackendLogs() {
QString groupId(GROUP_ID);
NSURL* groupPath = [[NSFileManager defaultManager]
containerURLForSecurityApplicationGroupIdentifier:groupId.toNSString()];
NSURL* path = [groupPath URLByAppendingPathComponent:@"networkextension.log"];
QFile file(QString::fromNSString([path path]));
file.remove();
}

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