mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 22:43:24 +00:00
Compare commits
7 Commits
4.8.11.3
...
fixbug/ios
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
deb9511b62 | ||
|
|
4188640c1d | ||
|
|
4ec20e9f37 | ||
|
|
ac61dd1498 | ||
|
|
2923fdaaf0 | ||
|
|
ff63cd24e5 | ||
|
|
bfa5fe4eb7 |
15
.github/workflows/deploy.yml
vendored
15
.github/workflows/deploy.yml
vendored
@@ -238,14 +238,13 @@ jobs:
|
||||
IOS_APP_PROVISIONING_PROFILE: ${{ secrets.IOS_APP_PROVISIONING_PROFILE }}
|
||||
IOS_NE_PROVISIONING_PROFILE: ${{ secrets.IOS_NE_PROVISIONING_PROFILE }}
|
||||
|
||||
# - name: 'Upload appstore .ipa and dSYMs to artifacts'
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: app-store ipa & dsyms
|
||||
# path: |
|
||||
# ${{ github.workspace }}/AmneziaVPN-iOS.ipa
|
||||
# ${{ github.workspace }}/*.app.dSYM.zip
|
||||
# retention-days: 7
|
||||
- name: 'Upload unsigned .ipa to artifacts'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN-unsigned-ipa
|
||||
path: |
|
||||
${{ github.workspace }}/build-ios/AmneziaVPN_unsigned.ipa
|
||||
retention-days: 7
|
||||
|
||||
# ------------------------------------------------------
|
||||
|
||||
|
||||
2
.github/workflows/tag-deploy.yml
vendored
2
.github/workflows/tag-deploy.yml
vendored
@@ -4,7 +4,7 @@ on:
|
||||
workflow_dispatch:
|
||||
# push:
|
||||
# tags:
|
||||
# - **
|
||||
# - "**"
|
||||
|
||||
jobs:
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ extension PacketTunnelProvider {
|
||||
startHandler = completionHandler
|
||||
ovpnAdapter?.connect(using: packetFlow)
|
||||
}
|
||||
|
||||
|
||||
func handleOpenVPNStatusMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
|
||||
guard let completionHandler = completionHandler else { return }
|
||||
let bytesin = ovpnAdapter?.transportStatistics.bytesIn
|
||||
@@ -169,8 +169,20 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
|
||||
networkSettings?.ipv6Settings?.includedRoutes = ipv6IncludedRoutes
|
||||
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.
|
||||
setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ const char* MessageKey::isOnDemand = "is-on-demand";
|
||||
const char* MessageKey::SplitTunnelType = "SplitTunnelType";
|
||||
const char* MessageKey::SplitTunnelSites = "SplitTunnelSites";
|
||||
|
||||
#if !MACOS_NE
|
||||
static UIViewController* getViewController() {
|
||||
UIApplication *application = [UIApplication sharedApplication];
|
||||
|
||||
@@ -71,7 +70,6 @@ static UIViewController* getViewController() {
|
||||
|
||||
return nil;
|
||||
}
|
||||
#endif
|
||||
|
||||
Vpn::ConnectionState iosStatusToState(NEVPNStatus status) {
|
||||
switch (status) {
|
||||
@@ -162,6 +160,39 @@ bool IosController::connectVpn(amnezia::Proto proto, const QJsonObject& configur
|
||||
m_rawConfig = configuration;
|
||||
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;
|
||||
if (configuration.value(config_key::description).toString().isEmpty()) {
|
||||
tunnelName = QString("%1 %2")
|
||||
@@ -285,21 +316,6 @@ void IosController::checkStatus()
|
||||
sendVpnExtensionMessage(message, [&](NSDictionary* response){
|
||||
uint64_t txBytes = [response[@"tx_bytes"] intValue];
|
||||
uint64_t rxBytes = [response[@"rx_bytes"] intValue];
|
||||
|
||||
uint64_t last_handshake_time_sec = 0;
|
||||
#if !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);
|
||||
m_rxBytes = rxBytes;
|
||||
m_txBytes = txBytes;
|
||||
@@ -558,8 +574,6 @@ bool IosController::setupWireGuard()
|
||||
|
||||
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
||||
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
||||
wgConfig.insert(config_key::cookieReplyPacketJunkSize, config[config_key::cookieReplyPacketJunkSize]);
|
||||
wgConfig.insert(config_key::transportPacketJunkSize, config[config_key::transportPacketJunkSize]);
|
||||
|
||||
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
||||
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
||||
@@ -658,23 +672,11 @@ bool IosController::setupAwg()
|
||||
|
||||
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
||||
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
||||
wgConfig.insert(config_key::cookieReplyPacketJunkSize, config[config_key::cookieReplyPacketJunkSize]);
|
||||
wgConfig.insert(config_key::transportPacketJunkSize, config[config_key::transportPacketJunkSize]);
|
||||
|
||||
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
||||
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
||||
wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]);
|
||||
|
||||
wgConfig.insert(config_key::specialJunk1, config[config_key::specialJunk1]);
|
||||
wgConfig.insert(config_key::specialJunk2, config[config_key::specialJunk2]);
|
||||
wgConfig.insert(config_key::specialJunk3, config[config_key::specialJunk3]);
|
||||
wgConfig.insert(config_key::specialJunk4, config[config_key::specialJunk4]);
|
||||
wgConfig.insert(config_key::specialJunk5, config[config_key::specialJunk5]);
|
||||
wgConfig.insert(config_key::controlledJunk1, config[config_key::controlledJunk1]);
|
||||
wgConfig.insert(config_key::controlledJunk2, config[config_key::controlledJunk2]);
|
||||
wgConfig.insert(config_key::controlledJunk3, config[config_key::controlledJunk3]);
|
||||
wgConfig.insert(config_key::specialHandshakeTimeout, config[config_key::specialHandshakeTimeout]);
|
||||
|
||||
QJsonDocument wgConfigDoc(wgConfig);
|
||||
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
|
||||
|
||||
@@ -854,14 +856,14 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
||||
NSURL *logFileUrl = [[NSURL alloc] initFileURLWithPath:filesToSend[i].toNSString()];
|
||||
[sharingItems addObject:logFileUrl];
|
||||
}
|
||||
#if !MACOS_NE
|
||||
|
||||
UIViewController *qtController = getViewController();
|
||||
if (!qtController) return;
|
||||
|
||||
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
||||
#endif
|
||||
|
||||
__block bool isAccepted = false;
|
||||
#if !MACOS_NE
|
||||
|
||||
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
|
||||
isAccepted = completed;
|
||||
emit finished();
|
||||
@@ -873,17 +875,15 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
||||
popController.sourceView = qtController.view;
|
||||
popController.sourceRect = CGRectMake(100, 100, 100, 100);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
QEventLoop wait;
|
||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||
wait.exec();
|
||||
|
||||
|
||||
return isAccepted;
|
||||
}
|
||||
|
||||
QString IosController::openFile() {
|
||||
#if !MACOS_NE
|
||||
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen];
|
||||
|
||||
DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init];
|
||||
@@ -893,10 +893,9 @@ QString IosController::openFile() {
|
||||
if (!qtController) return;
|
||||
|
||||
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
||||
|
||||
#endif
|
||||
|
||||
__block QString filePath;
|
||||
#if !MACOS_NE
|
||||
|
||||
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
||||
if (path) {
|
||||
filePath = QString::fromUtf8(path.UTF8String);
|
||||
@@ -905,11 +904,11 @@ QString IosController::openFile() {
|
||||
}
|
||||
emit finished();
|
||||
};
|
||||
#endif
|
||||
|
||||
QEventLoop wait;
|
||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||
wait.exec();
|
||||
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,66 +34,23 @@ clang -v
|
||||
# Generate XCodeProj
|
||||
$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
|
||||
if [ "${IOS_SIGNING_CERT_BASE64+x}" ]; then
|
||||
echo "Import certificate"
|
||||
cd $BUILD_DIR
|
||||
xcodebuild archive \
|
||||
-project AmneziaVPN.xcodeproj \
|
||||
-scheme AmneziaVPN \
|
||||
-configuration Release \
|
||||
-archivePath ./build/AmneziaVPN.xcarchive \
|
||||
CODE_SIGNING_ALLOWED=NO \
|
||||
CODE_SIGN_IDENTITY="" \
|
||||
CODE_SIGNING_REQUIRED=NO
|
||||
|
||||
TRUST_CERT_CER=$BUILD_DIR/trust-cert.cer
|
||||
SIGNING_CERT_P12=$BUILD_DIR/signing-cert.p12
|
||||
mkdir -p Payload
|
||||
|
||||
echo $IOS_TRUST_CERT_BASE64 | base64 --decode > $TRUST_CERT_CER
|
||||
echo $IOS_SIGNING_CERT_BASE64 | base64 --decode > $SIGNING_CERT_P12
|
||||
cp -R ./build/AmneziaVPN.xcarchive/Products/Applications/AmneziaVPN.app Payload/
|
||||
|
||||
shasum -a 256 $TRUST_CERT_CER
|
||||
shasum -a 256 $SIGNING_CERT_P12
|
||||
zip -r AmneziaVPN_unsigned.ipa Payload
|
||||
|
||||
KEYCHAIN_PASS=$IOS_SIGNING_CERT_PASSWORD
|
||||
rm -rf Payload
|
||||
|
||||
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 \
|
||||
-destination "generic/platform=iOS,name=Any iOS'" \
|
||||
-project $BUILD_DIR/AmneziaVPN.xcodeproj
|
||||
|
||||
# restore keychain
|
||||
security default-keychain -s login.keychain
|
||||
echo " Build setup completed successfully."
|
||||
|
||||
Reference in New Issue
Block a user