mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-23 02:00:20 +07:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| deb9511b62 | |||
| 4188640c1d | |||
| 4ec20e9f37 | |||
| ac61dd1498 | |||
| 2923fdaaf0 | |||
| ff63cd24e5 | |||
| bfa5fe4eb7 |
@@ -238,14 +238,13 @@ jobs:
|
|||||||
IOS_APP_PROVISIONING_PROFILE: ${{ secrets.IOS_APP_PROVISIONING_PROFILE }}
|
IOS_APP_PROVISIONING_PROFILE: ${{ secrets.IOS_APP_PROVISIONING_PROFILE }}
|
||||||
IOS_NE_PROVISIONING_PROFILE: ${{ secrets.IOS_NE_PROVISIONING_PROFILE }}
|
IOS_NE_PROVISIONING_PROFILE: ${{ secrets.IOS_NE_PROVISIONING_PROFILE }}
|
||||||
|
|
||||||
# - name: 'Upload appstore .ipa and dSYMs to artifacts'
|
- name: 'Upload unsigned .ipa to artifacts'
|
||||||
# uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
# with:
|
with:
|
||||||
# name: app-store ipa & dsyms
|
name: AmneziaVPN-unsigned-ipa
|
||||||
# path: |
|
path: |
|
||||||
# ${{ github.workspace }}/AmneziaVPN-iOS.ipa
|
${{ github.workspace }}/build-ios/AmneziaVPN_unsigned.ipa
|
||||||
# ${{ github.workspace }}/*.app.dSYM.zip
|
retention-days: 7
|
||||||
# retention-days: 7
|
|
||||||
|
|
||||||
# ------------------------------------------------------
|
# ------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
# push:
|
# push:
|
||||||
# tags:
|
# tags:
|
||||||
# - **
|
# - "**"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
|
|||||||
@@ -169,8 +169,20 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
|
|||||||
networkSettings?.ipv6Settings?.includedRoutes = ipv6IncludedRoutes
|
networkSettings?.ipv6Settings?.includedRoutes = ipv6IncludedRoutes
|
||||||
networkSettings?.ipv4Settings?.excludedRoutes = ipv4ExcludedRoutes
|
networkSettings?.ipv4Settings?.excludedRoutes = ipv4ExcludedRoutes
|
||||||
}
|
}
|
||||||
|
if splitTunnelType == 0 || splitTunnelType == nil {
|
||||||
|
// Full tunnel: send all traffic via VPN
|
||||||
|
if let ipv4Settings = networkSettings?.ipv4Settings {
|
||||||
|
ipv4Settings.includedRoutes = [NEIPv4Route.default()]
|
||||||
|
NSLog("[Route] Added default IPv4 route (0.0.0.0/0)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let ipv6Settings = networkSettings?.ipv6Settings {
|
||||||
|
let ipv6DefaultRoute = NEIPv6Route(destinationAddress: "::", networkPrefixLength: 0)
|
||||||
|
ipv6Settings.includedRoutes = [ipv6DefaultRoute]
|
||||||
|
NSLog("[Route] Added default IPv6 route (::/0)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Set the network settings for the current tunneling session.
|
// Set the network settings for the current tunneling session.
|
||||||
setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler)
|
setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ const char* MessageKey::isOnDemand = "is-on-demand";
|
|||||||
const char* MessageKey::SplitTunnelType = "SplitTunnelType";
|
const char* MessageKey::SplitTunnelType = "SplitTunnelType";
|
||||||
const char* MessageKey::SplitTunnelSites = "SplitTunnelSites";
|
const char* MessageKey::SplitTunnelSites = "SplitTunnelSites";
|
||||||
|
|
||||||
#if !MACOS_NE
|
|
||||||
static UIViewController* getViewController() {
|
static UIViewController* getViewController() {
|
||||||
UIApplication *application = [UIApplication sharedApplication];
|
UIApplication *application = [UIApplication sharedApplication];
|
||||||
|
|
||||||
@@ -71,7 +70,6 @@ static UIViewController* getViewController() {
|
|||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
Vpn::ConnectionState iosStatusToState(NEVPNStatus status) {
|
Vpn::ConnectionState iosStatusToState(NEVPNStatus status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@@ -162,6 +160,39 @@ bool IosController::connectVpn(amnezia::Proto proto, const QJsonObject& configur
|
|||||||
m_rawConfig = configuration;
|
m_rawConfig = configuration;
|
||||||
m_serverAddress = configuration.value(config_key::hostName).toString().toNSString();
|
m_serverAddress = configuration.value(config_key::hostName).toString().toNSString();
|
||||||
|
|
||||||
|
if (proto == amnezia::Proto::OpenVpn) {
|
||||||
|
QJsonObject ovpn = configuration["openvpn_config_data"].toObject();
|
||||||
|
QString ovpnConfig = ovpn["config"].toString();
|
||||||
|
QStringList unsupportedDirectives = {
|
||||||
|
"resolv-retry",
|
||||||
|
"persist-key",
|
||||||
|
"persist-tun",
|
||||||
|
"block-ipv6",
|
||||||
|
"redirect-gateway"
|
||||||
|
};
|
||||||
|
|
||||||
|
QStringList lines = ovpnConfig.split('\n');
|
||||||
|
QStringList filteredLines;
|
||||||
|
for (const QString &line : lines) {
|
||||||
|
QString trimmedLine = line.trimmed();
|
||||||
|
|
||||||
|
bool shouldIgnore = false;
|
||||||
|
for (const QString &bad : unsupportedDirectives) {
|
||||||
|
if (trimmedLine.startsWith(bad)) {
|
||||||
|
shouldIgnore = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldIgnore) {
|
||||||
|
filteredLines.append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ovpnConfig = filteredLines.join("\n");
|
||||||
|
ovpn["config"] = ovpnConfig;
|
||||||
|
m_rawConfig["openvpn_config_data"] = ovpn;
|
||||||
|
}
|
||||||
|
|
||||||
QString tunnelName;
|
QString tunnelName;
|
||||||
if (configuration.value(config_key::description).toString().isEmpty()) {
|
if (configuration.value(config_key::description).toString().isEmpty()) {
|
||||||
tunnelName = QString("%1 %2")
|
tunnelName = QString("%1 %2")
|
||||||
@@ -285,21 +316,6 @@ void IosController::checkStatus()
|
|||||||
sendVpnExtensionMessage(message, [&](NSDictionary* response){
|
sendVpnExtensionMessage(message, [&](NSDictionary* response){
|
||||||
uint64_t txBytes = [response[@"tx_bytes"] intValue];
|
uint64_t txBytes = [response[@"tx_bytes"] intValue];
|
||||||
uint64_t rxBytes = [response[@"rx_bytes"] intValue];
|
uint64_t rxBytes = [response[@"rx_bytes"] intValue];
|
||||||
|
|
||||||
uint64_t last_handshake_time_sec = 0;
|
|
||||||
#if !MACOS_NE
|
|
||||||
if (response[@"last_handshake_time_sec"] && ![response[@"last_handshake_time_sec"] isKindOfClass:[NSNull class]]) {
|
|
||||||
last_handshake_time_sec = [response[@"last_handshake_time_sec"] intValue];
|
|
||||||
} else {
|
|
||||||
qDebug() << "Key last_handshake_time_sec is missing or null";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last_handshake_time_sec < 0) {
|
|
||||||
disconnectVpn();
|
|
||||||
qDebug() << "Invalid handshake time, disconnecting VPN.";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
emit bytesChanged(rxBytes - m_rxBytes, txBytes - m_txBytes);
|
emit bytesChanged(rxBytes - m_rxBytes, txBytes - m_txBytes);
|
||||||
m_rxBytes = rxBytes;
|
m_rxBytes = rxBytes;
|
||||||
m_txBytes = txBytes;
|
m_txBytes = txBytes;
|
||||||
@@ -558,8 +574,6 @@ bool IosController::setupWireGuard()
|
|||||||
|
|
||||||
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
||||||
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
||||||
wgConfig.insert(config_key::cookieReplyPacketJunkSize, config[config_key::cookieReplyPacketJunkSize]);
|
|
||||||
wgConfig.insert(config_key::transportPacketJunkSize, config[config_key::transportPacketJunkSize]);
|
|
||||||
|
|
||||||
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
||||||
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
||||||
@@ -658,23 +672,11 @@ bool IosController::setupAwg()
|
|||||||
|
|
||||||
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
||||||
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
||||||
wgConfig.insert(config_key::cookieReplyPacketJunkSize, config[config_key::cookieReplyPacketJunkSize]);
|
|
||||||
wgConfig.insert(config_key::transportPacketJunkSize, config[config_key::transportPacketJunkSize]);
|
|
||||||
|
|
||||||
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
||||||
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
||||||
wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]);
|
wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]);
|
||||||
|
|
||||||
wgConfig.insert(config_key::specialJunk1, config[config_key::specialJunk1]);
|
|
||||||
wgConfig.insert(config_key::specialJunk2, config[config_key::specialJunk2]);
|
|
||||||
wgConfig.insert(config_key::specialJunk3, config[config_key::specialJunk3]);
|
|
||||||
wgConfig.insert(config_key::specialJunk4, config[config_key::specialJunk4]);
|
|
||||||
wgConfig.insert(config_key::specialJunk5, config[config_key::specialJunk5]);
|
|
||||||
wgConfig.insert(config_key::controlledJunk1, config[config_key::controlledJunk1]);
|
|
||||||
wgConfig.insert(config_key::controlledJunk2, config[config_key::controlledJunk2]);
|
|
||||||
wgConfig.insert(config_key::controlledJunk3, config[config_key::controlledJunk3]);
|
|
||||||
wgConfig.insert(config_key::specialHandshakeTimeout, config[config_key::specialHandshakeTimeout]);
|
|
||||||
|
|
||||||
QJsonDocument wgConfigDoc(wgConfig);
|
QJsonDocument wgConfigDoc(wgConfig);
|
||||||
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
|
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
|
||||||
|
|
||||||
@@ -854,14 +856,14 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
|||||||
NSURL *logFileUrl = [[NSURL alloc] initFileURLWithPath:filesToSend[i].toNSString()];
|
NSURL *logFileUrl = [[NSURL alloc] initFileURLWithPath:filesToSend[i].toNSString()];
|
||||||
[sharingItems addObject:logFileUrl];
|
[sharingItems addObject:logFileUrl];
|
||||||
}
|
}
|
||||||
#if !MACOS_NE
|
|
||||||
UIViewController *qtController = getViewController();
|
UIViewController *qtController = getViewController();
|
||||||
if (!qtController) return;
|
if (!qtController) return;
|
||||||
|
|
||||||
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
||||||
#endif
|
|
||||||
__block bool isAccepted = false;
|
__block bool isAccepted = false;
|
||||||
#if !MACOS_NE
|
|
||||||
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
|
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
|
||||||
isAccepted = completed;
|
isAccepted = completed;
|
||||||
emit finished();
|
emit finished();
|
||||||
@@ -874,7 +876,6 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
|||||||
popController.sourceRect = CGRectMake(100, 100, 100, 100);
|
popController.sourceRect = CGRectMake(100, 100, 100, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||||
wait.exec();
|
wait.exec();
|
||||||
@@ -883,7 +884,6 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString IosController::openFile() {
|
QString IosController::openFile() {
|
||||||
#if !MACOS_NE
|
|
||||||
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen];
|
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen];
|
||||||
|
|
||||||
DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init];
|
DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init];
|
||||||
@@ -894,9 +894,8 @@ QString IosController::openFile() {
|
|||||||
|
|
||||||
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
||||||
|
|
||||||
#endif
|
|
||||||
__block QString filePath;
|
__block QString filePath;
|
||||||
#if !MACOS_NE
|
|
||||||
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
||||||
if (path) {
|
if (path) {
|
||||||
filePath = QString::fromUtf8(path.UTF8String);
|
filePath = QString::fromUtf8(path.UTF8String);
|
||||||
@@ -905,7 +904,7 @@ QString IosController::openFile() {
|
|||||||
}
|
}
|
||||||
emit finished();
|
emit finished();
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||||
wait.exec();
|
wait.exec();
|
||||||
|
|||||||
+17
-60
@@ -34,66 +34,23 @@ clang -v
|
|||||||
# Generate XCodeProj
|
# Generate XCodeProj
|
||||||
$QT_BIN_DIR/qt-cmake . -B $BUILD_DIR -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR -DDEPLOY=ON
|
$QT_BIN_DIR/qt-cmake . -B $BUILD_DIR -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR -DDEPLOY=ON
|
||||||
|
|
||||||
KEYCHAIN=amnezia.build.ios.keychain
|
|
||||||
KEYCHAIN_FILE=$HOME/Library/Keychains/${KEYCHAIN}-db
|
|
||||||
|
|
||||||
# Setup keychain
|
cd $BUILD_DIR
|
||||||
if [ "${IOS_SIGNING_CERT_BASE64+x}" ]; then
|
xcodebuild archive \
|
||||||
echo "Import certificate"
|
-project AmneziaVPN.xcodeproj \
|
||||||
|
|
||||||
TRUST_CERT_CER=$BUILD_DIR/trust-cert.cer
|
|
||||||
SIGNING_CERT_P12=$BUILD_DIR/signing-cert.p12
|
|
||||||
|
|
||||||
echo $IOS_TRUST_CERT_BASE64 | base64 --decode > $TRUST_CERT_CER
|
|
||||||
echo $IOS_SIGNING_CERT_BASE64 | base64 --decode > $SIGNING_CERT_P12
|
|
||||||
|
|
||||||
shasum -a 256 $TRUST_CERT_CER
|
|
||||||
shasum -a 256 $SIGNING_CERT_P12
|
|
||||||
|
|
||||||
KEYCHAIN_PASS=$IOS_SIGNING_CERT_PASSWORD
|
|
||||||
|
|
||||||
security create-keychain -p $KEYCHAIN_PASS $KEYCHAIN || true
|
|
||||||
security default-keychain -s $KEYCHAIN
|
|
||||||
security unlock-keychain -p $KEYCHAIN_PASS $KEYCHAIN
|
|
||||||
|
|
||||||
security default-keychain
|
|
||||||
security list-keychains
|
|
||||||
|
|
||||||
security import $TRUST_CERT_CER -k $KEYCHAIN -P "" -T /usr/bin/codesign
|
|
||||||
security import $SIGNING_CERT_P12 -k $KEYCHAIN -P $IOS_SIGNING_CERT_PASSWORD -T /usr/bin/codesign
|
|
||||||
|
|
||||||
security set-key-partition-list -S "apple-tool:,apple:,codesign:" -s -k $KEYCHAIN_PASS $KEYCHAIN
|
|
||||||
security find-identity -p codesigning
|
|
||||||
security set-keychain-settings $KEYCHAIN_FILE
|
|
||||||
security set-keychain-settings -t 3600 $KEYCHAIN_FILE
|
|
||||||
security unlock-keychain -p $KEYCHAIN_PASS $KEYCHAIN_FILE
|
|
||||||
|
|
||||||
# Copy provisioning prifiles
|
|
||||||
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles/"
|
|
||||||
|
|
||||||
echo $IOS_APP_PROVISIONING_PROFILE | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision
|
|
||||||
echo $IOS_NE_PROVISIONING_PROFILE | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision
|
|
||||||
|
|
||||||
shasum -a 256 ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision
|
|
||||||
shasum -a 256 ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision
|
|
||||||
|
|
||||||
profile_uuid=`grep UUID -A1 -a ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision | grep -io "[-A-F0-9]\{36\}"`
|
|
||||||
profile_ne_uuid=`grep UUID -A1 -a ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision | grep -io "[-A-F0-9]\{36\}"`
|
|
||||||
|
|
||||||
mv ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/$profile_uuid.mobileprovision
|
|
||||||
mv ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/$profile_ne_uuid.mobileprovision
|
|
||||||
else
|
|
||||||
echo "Failed to import certificate, aborting..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Build project
|
|
||||||
xcodebuild \
|
|
||||||
"OTHER_CODE_SIGN_FLAGS=--keychain '$KEYCHAIN_FILE'" \
|
|
||||||
-configuration Release \
|
|
||||||
-scheme AmneziaVPN \
|
-scheme AmneziaVPN \
|
||||||
-destination "generic/platform=iOS,name=Any iOS'" \
|
-configuration Release \
|
||||||
-project $BUILD_DIR/AmneziaVPN.xcodeproj
|
-archivePath ./build/AmneziaVPN.xcarchive \
|
||||||
|
CODE_SIGNING_ALLOWED=NO \
|
||||||
|
CODE_SIGN_IDENTITY="" \
|
||||||
|
CODE_SIGNING_REQUIRED=NO
|
||||||
|
|
||||||
# restore keychain
|
mkdir -p Payload
|
||||||
security default-keychain -s login.keychain
|
|
||||||
|
cp -R ./build/AmneziaVPN.xcarchive/Products/Applications/AmneziaVPN.app Payload/
|
||||||
|
|
||||||
|
zip -r AmneziaVPN_unsigned.ipa Payload
|
||||||
|
|
||||||
|
rm -rf Payload
|
||||||
|
|
||||||
|
echo " Build setup completed successfully."
|
||||||
|
|||||||
Reference in New Issue
Block a user