diff options
| -rw-r--r-- | ios/MullvadSettings/IPOverride.swift | 4 | ||||
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 4 | ||||
| -rw-r--r-- | ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideInteractor.swift | 2 | ||||
| -rw-r--r-- | ios/MullvadVPN/SceneDelegate.swift | 174 | ||||
| -rw-r--r-- | ios/MullvadVPN/Supporting Files/Info.plist | 21 | ||||
| -rw-r--r-- | ios/MullvadVPN/TunnelManager/TunnelManager.swift | 10 |
6 files changed, 208 insertions, 7 deletions
diff --git a/ios/MullvadSettings/IPOverride.swift b/ios/MullvadSettings/IPOverride.swift index ec59ebc384..f530a7c373 100644 --- a/ios/MullvadSettings/IPOverride.swift +++ b/ios/MullvadSettings/IPOverride.swift @@ -11,6 +11,10 @@ import Network public struct RelayOverrides: Codable, Sendable { public let overrides: [IPOverride] + public init(overrides: [IPOverride]) { + self.overrides = overrides + } + private enum CodingKeys: String, CodingKey { case overrides = "relay_overrides" } diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 26406d4230..d8c3254d97 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -1108,8 +1108,8 @@ F910A4312D4A1B41002FF3BB /* InAppPurchaseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F910A4302D4A1B3B002FF3BB /* InAppPurchaseCoordinator.swift */; }; F910A43A2D4A283D002FF3BB /* InAppPurchaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F910A4392D4A2839002FF3BB /* InAppPurchaseViewController.swift */; }; F910A8572D523812002FF3BB /* TunnelSettingsV7.swift in Sources */ = {isa = PBXBuildFile; fileRef = F910A8562D523812002FF3BB /* TunnelSettingsV7.swift */; }; - F924C65F2DAE4554001F4660 /* ServerRelayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F924C65E2DAE4554001F4660 /* ServerRelayTests.swift */; }; F924C4532D70692E001F4660 /* MullvadApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F924C4522D706929001F4660 /* MullvadApiTests.swift */; }; + F924C65F2DAE4554001F4660 /* ServerRelayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F924C65E2DAE4554001F4660 /* ServerRelayTests.swift */; }; F998EFF82D359C4600D88D01 /* SKProduct+Formatting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FD5BEF24238EB300112C88 /* SKProduct+Formatting.swift */; }; F998EFFA2D3656BA00D88D01 /* SKProduct+Sorting.swift in Sources */ = {isa = PBXBuildFile; fileRef = F998EFF92D3656B100D88D01 /* SKProduct+Sorting.swift */; }; /* End PBXBuildFile section */ @@ -2520,8 +2520,8 @@ F910A4302D4A1B3B002FF3BB /* InAppPurchaseCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppPurchaseCoordinator.swift; sourceTree = "<group>"; }; F910A4392D4A2839002FF3BB /* InAppPurchaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppPurchaseViewController.swift; sourceTree = "<group>"; }; F910A8562D523812002FF3BB /* TunnelSettingsV7.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsV7.swift; sourceTree = "<group>"; }; - F924C65E2DAE4554001F4660 /* ServerRelayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerRelayTests.swift; sourceTree = "<group>"; }; F924C4522D706929001F4660 /* MullvadApiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MullvadApiTests.swift; sourceTree = "<group>"; }; + F924C65E2DAE4554001F4660 /* ServerRelayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerRelayTests.swift; sourceTree = "<group>"; }; F998EFF92D3656B100D88D01 /* SKProduct+Sorting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SKProduct+Sorting.swift"; sourceTree = "<group>"; }; /* End PBXFileReference section */ diff --git a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideInteractor.swift b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideInteractor.swift index f4076787e3..bdf8399a96 100644 --- a/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideInteractor.swift +++ b/ios/MullvadVPN/Coordinators/Settings/IPOverride/IPOverrideInteractor.swift @@ -54,7 +54,7 @@ final class IPOverrideInteractor { resetToDefaultStatus() } - private func handleImport(of data: Data, context: IPOverrideStatus.Context) { + func handleImport(of data: Data, context: IPOverrideStatus.Context) { do { let overrides = try repository.parse(data: data) diff --git a/ios/MullvadVPN/SceneDelegate.swift b/ios/MullvadVPN/SceneDelegate.swift index feec718687..b5839e6af1 100644 --- a/ios/MullvadVPN/SceneDelegate.swift +++ b/ios/MullvadVPN/SceneDelegate.swift @@ -10,7 +10,9 @@ import MullvadLogging import MullvadREST import MullvadSettings import MullvadTypes +import Network import Operations +import Routing import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate, @preconcurrency SettingsMigrationUIHandler { @@ -180,6 +182,178 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, @preconcurrency Setting } } + // swiftlint:disable:next function_body_length + func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { + do { + let url = URLContexts.first!.url + + guard + let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true), + let albumPath = components.path, + let params = components.queryItems + else { + throw NSError(domain: "", code: 1, userInfo: nil) + } + + var currentSettings = tunnelManager.settings + + switch albumPath { + case "settings": + try params.forEach { param in + switch param.name { + case "daita": + currentSettings.daita.daitaState = param.value == "on" ? .on : .off + case "directOnly": + currentSettings.daita.directOnlyState = param.value == "on" ? .on : .off + case "multihop": + currentSettings.tunnelMultihopState = param.value == "on" ? .on : .off + case "quantumResistance": + currentSettings.tunnelQuantumResistance = param.value == "on" ? .on : .off + case "obfuscation": + var state: WireGuardObfuscationState = .automatic + var port: Int? + + let components = param.value!.split(separator: ",") + + try components.forEach { component in + let keyValue = component.split(separator: "=") + + switch keyValue.first! { + case "state": + switch keyValue.last! { + case "automatic": + state = .automatic + case "off": + state = .off + case "shadowsocks": + state = .shadowsocks + case "udpOverTcp": + state = .udpOverTcp + default: + throw NSError(domain: "", code: 2, userInfo: nil) + } + case "port": + port = Int(keyValue.last!) + default: + throw NSError(domain: "", code: 3, userInfo: nil) + } + } + + currentSettings.wireGuardObfuscation.state = state + + switch state { + case .shadowsocks: + let shadowSocksPort = port.flatMap { + WireGuardObfuscationShadowsocksPort.custom(UInt16($0)) + } ?? WireGuardObfuscationShadowsocksPort.automatic + + currentSettings.wireGuardObfuscation.shadowsocksPort = shadowSocksPort + case .udpOverTcp: + let udpTcpPort: WireGuardObfuscationUdpOverTcpPort = switch port { + case nil: + .automatic + case 80: + .port80 + case 5001: + .port5001 + default: + throw NSError(domain: "", code: 4, userInfo: nil) + } + + currentSettings.wireGuardObfuscation.udpOverTcpPort = udpTcpPort + default: + break + } + default: + throw NSError(domain: "", code: 5, userInfo: nil) + } + } + case "ipOverrides": + var overrides: [IPOverride] = [] + + try params.forEach { param in + var hostname = "" + var ipv4: IPv4Address? + var ipv6: IPv6Address? + + let hostComponents = param.value!.split(separator: ",") + + try hostComponents.forEach { component in + let keyValue = component.split(separator: "=") + + switch keyValue.first! { + case "hostname": + hostname = String(keyValue.last!) + case "ipv4_addr_in": + ipv4 = keyValue.last.flatMap { IPv4Address(String($0)) } + case "ipv6_addr_in": + ipv6 = keyValue.last.flatMap { IPv6Address(String($0)) } + default: + throw NSError(domain: "", code: 6, userInfo: nil) + } + } + + try overrides.append(IPOverride(hostname: hostname, ipv4Address: ipv4, ipv6Address: ipv6)) + } + + let interactor = IPOverrideInteractor(repository: IPOverrideRepository(), tunnelManager: tunnelManager) + try interactor.handleImport(of: JSONEncoder().encode(RelayOverrides(overrides: overrides)), context: .text) + default: + throw NSError(domain: "", code: 7, userInfo: nil) + } + + tunnelManager.updateSettings(currentSettings) + + let presentation = AlertPresentation( + id: "import-successful", + icon: .info, + title: NSLocalizedString( + "SHARE_IMPORT_SUCCESSFUL_TITLE", + tableName: "Settings", + value: "Success!", + comment: "" + ), + message: NSLocalizedString( + "SHARE_IMPORT_SUCCESSFUL_MESSAGE", + tableName: "Settings", + value: "The new settings were successfully applied.", + comment: "" + ), + buttons: [ + AlertAction(title: "Got it!", style: .default) + ] + ) + + let alert = AlertPresenter(context: appCoordinator) + alert.showAlert(presentation: presentation, animated: true) + } catch { + print(error) + + let presentation = AlertPresentation( + id: "import-unsuccessful", + icon: .warning, + title: NSLocalizedString( + "SHARE_IMPORT_SUCCESSFUL_TITLE", + tableName: "Settings", + value: "Failure!", + comment: "" + ), + message: NSLocalizedString( + "SHARE_IMPORT_SUCCESSFUL_MESSAGE", + tableName: "Settings", + value: "The new settings could not be applied.", + comment: "" + ), + buttons: [ + AlertAction(title: "Got it!", style: .default) + ] + ) + + let alert = AlertPresenter(context: appCoordinator) + alert.showAlert(presentation: presentation, animated: true) + } + } + func sceneDidDisconnect(_ scene: UIScene) {} func sceneDidBecomeActive(_ scene: UIScene) { diff --git a/ios/MullvadVPN/Supporting Files/Info.plist b/ios/MullvadVPN/Supporting Files/Info.plist index 14af71cdc7..b8ba272e94 100644 --- a/ios/MullvadVPN/Supporting Files/Info.plist +++ b/ios/MullvadVPN/Supporting Files/Info.plist @@ -2,10 +2,6 @@ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> - <key>HostName</key> - <string>$(HOST_NAME)</string> - <key>NSLocalNetworkUsageDescription</key> - <string>The app needs this to connect and test a new method.</string> <key>ApplicationSecurityGroupIdentifier</key> <string>$(SECURITY_GROUP_IDENTIFIER)</string> <key>BGTaskSchedulerPermittedIdentifiers</key> @@ -30,10 +26,25 @@ <string>APPL</string> <key>CFBundleShortVersionString</key> <string>$(MARKETING_VERSION)</string> + <key>CFBundleURLTypes</key> + <array> + <dict> + <key>CFBundleTypeRole</key> + <string>Viewer</string> + <key>CFBundleURLName</key> + <string>net.mullvad.MullvadVPN</string> + <key>CFBundleURLSchemes</key> + <array> + <string>mullvad</string> + </array> + </dict> + </array> <key>CFBundleVersion</key> <string>$(CURRENT_PROJECT_VERSION)</string> <key>HasTimeAccountNumber</key> <string>$(HAS_TIME_ACCOUNT_NUMBER)</string> + <key>HostName</key> + <string>$(HOST_NAME)</string> <key>ITSAppUsesNonExemptEncryption</key> <false/> <key>LSRequiresIPhoneOS</key> @@ -45,6 +56,8 @@ <key>NSAllowsArbitraryLoads</key> <true/> </dict> + <key>NSLocalNetworkUsageDescription</key> + <string>The app needs this to connect and test a new method.</string> <key>NSUserActivityTypes</key> <array> <string>StartVPNIntent</string> diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift index af1a41f124..50f132b52a 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift @@ -558,6 +558,16 @@ final class TunnelManager: StorePaymentObserver, @unchecked Sendable { ) } + func updateSettings(_ newSettings: LatestTunnelSettings, completionHandler: (@Sendable () -> Void)? = nil) { + scheduleSettingsUpdate( + taskName: "Update tunnel settings", + modificationBlock: { settings in + settings = newSettings + }, + completionHandler: completionHandler + ) + } + func refreshRelayCacheTracker() throws { try relayCacheTracker.refreshCachedRelays() } |
