diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 3a29487fdc49..7ed76968d52b 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -112,7 +112,6 @@ 585A02EB2A4B285800C6CAFF /* UDPConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585A02EA2A4B285800C6CAFF /* UDPConnection.swift */; }; 585A02ED2A4B28F300C6CAFF /* TCPConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585A02EC2A4B28F300C6CAFF /* TCPConnection.swift */; }; 585B1FF02AB09F97008AD470 /* VPNConnectionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9F360332AAB626300F53531 /* VPNConnectionProtocol.swift */; }; - 585B1FF22AB0BC69008AD470 /* State+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585B1FF12AB0BC69008AD470 /* State+Extensions.swift */; }; 585B4B8726D9098900555C4C /* TunnelStatusNotificationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A94AE326CFD945001CB97C /* TunnelStatusNotificationProvider.swift */; }; 585CA70F25F8C44600B47C62 /* UIMetrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585CA70E25F8C44600B47C62 /* UIMetrics.swift */; }; 585E820327F3285E00939F0E /* SendStoreReceiptOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585E820227F3285E00939F0E /* SendStoreReceiptOperation.swift */; }; @@ -384,7 +383,6 @@ 58F3C0A4249CB069003E76BE /* HeaderBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F3C0A3249CB069003E76BE /* HeaderBarView.swift */; }; 58F3F36A2AA08E3C00D3B0A4 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F3F3692AA08E3C00D3B0A4 /* PacketTunnelProvider.swift */; }; 58F7753D2AB8473200425B47 /* BlockedStateErrorMapperStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F7753C2AB8473200425B47 /* BlockedStateErrorMapperStub.swift */; }; - 58F775432AB9E3EF00425B47 /* AppMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F775422AB9E3EF00425B47 /* AppMessageHandler.swift */; }; 58F8AC0E25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F8AC0D25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift */; }; 58FB865526E8BF3100F188BC /* StorePaymentManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FB865426E8BF3100F188BC /* StorePaymentManagerError.swift */; }; 58FB865A26EA214400F188BC /* RelayCacheTrackerObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FB865926EA214400F188BC /* RelayCacheTrackerObserver.swift */; }; @@ -431,6 +429,10 @@ 7A3353912AAA014400F0A71C /* SimulatorVPNConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3353902AAA014400F0A71C /* SimulatorVPNConnection.swift */; }; 7A3353932AAA089000F0A71C /* SimulatorTunnelInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3353922AAA089000F0A71C /* SimulatorTunnelInfo.swift */; }; 7A3353972AAA0F8600F0A71C /* OperationBlockObserverSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3353962AAA0F8600F0A71C /* OperationBlockObserverSupport.swift */; }; + 7A3FD1B52AD4465A0042BEA6 /* AppMessageHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3FD1B42AD4465A0042BEA6 /* AppMessageHandlerTests.swift */; }; + 7A3FD1B62AD542110042BEA6 /* ServerRelaysResponse+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C342C42ACC42130045F00E /* ServerRelaysResponse+Stubs.swift */; }; + 7A3FD1B72AD54ABD0042BEA6 /* AnyTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BDEB982A98F4ED00F578F2 /* AnyTransport.swift */; }; + 7A3FD1B82AD54AE60042BEA6 /* TimeServerProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BDEB9A2A98F58600F578F2 /* TimeServerProxy.swift */; }; 7A42DEC92A05164100B209BE /* SettingsInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A42DEC82A05164100B209BE /* SettingsInputCell.swift */; }; 7A42DECD2A09064C00B209BE /* SelectableSettingsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A42DECC2A09064C00B209BE /* SelectableSettingsCell.swift */; }; 7A6B4F592AB8412E00123853 /* TunnelMonitorTimings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6B4F582AB8412E00123853 /* TunnelMonitorTimings.swift */; }; @@ -470,8 +472,13 @@ 7ABCA5B42A9349F20044A708 /* Routing.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7A88DCCE2A8FABBE00D2FF0E /* Routing.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 7ABCA5B72A9353C60044A708 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58CAF9F72983D36800BE19F7 /* Coordinator.swift */; }; 7ABE318D2A1CDD4500DF4963 /* UIFont+Weight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ABE318C2A1CDD4500DF4963 /* UIFont+Weight.swift */; }; + 7AD0AA1C2AD6A63F00119E10 /* PacketTunnelActorStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AD0AA1B2AD6A63F00119E10 /* PacketTunnelActorStub.swift */; }; + 7AD0AA1D2AD6A86700119E10 /* PacketTunnelActorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AD0AA192AD69B6E00119E10 /* PacketTunnelActorProtocol.swift */; }; + 7AD0AA1F2AD6C8B900119E10 /* URLRequestProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AD0AA1E2AD6C8B900119E10 /* URLRequestProxyProtocol.swift */; }; + 7AD0AA212AD6CB0000119E10 /* URLRequestProxyStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AD0AA202AD6CB0000119E10 /* URLRequestProxyStub.swift */; }; 7AE044BB2A935726003915D8 /* Routing.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A88DCD02A8FABBE00D2FF0E /* Routing.h */; settings = {ATTRIBUTES = (Public, ); }; }; 7AE47E522A17972A000418DA /* AlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE47E512A17972A000418DA /* AlertViewController.swift */; }; + 7AEF7F1A2AD00F52006FE45D /* AppMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEF7F192AD00F52006FE45D /* AppMessageHandler.swift */; }; 7AF6E5F02A95051E00F2679D /* RouterBlockDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF6E5EF2A95051E00F2679D /* RouterBlockDelegate.swift */; }; 7AF9BE992A4E0FE900DBFEDB /* MarkdownStylingOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF9BE982A4E0FE900DBFEDB /* MarkdownStylingOptions.swift */; }; A900E9B82ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A900E9B72ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift */; }; @@ -1245,7 +1252,6 @@ 585A02E82A4B283000C6CAFF /* TCPUnsafeListener.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TCPUnsafeListener.swift; sourceTree = ""; }; 585A02EA2A4B285800C6CAFF /* UDPConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UDPConnection.swift; sourceTree = ""; }; 585A02EC2A4B28F300C6CAFF /* TCPConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TCPConnection.swift; sourceTree = ""; }; - 585B1FF12AB0BC69008AD470 /* State+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "State+Extensions.swift"; sourceTree = ""; }; 585CA70E25F8C44600B47C62 /* UIMetrics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIMetrics.swift; sourceTree = ""; }; 585DA87626B024A600B8C587 /* CachedRelays.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedRelays.swift; sourceTree = ""; }; 585DA89226B0323E00B8C587 /* TunnelProviderMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelProviderMessage.swift; sourceTree = ""; }; @@ -1444,8 +1450,8 @@ 58E7BA182A975DF70068EC3A /* RESTTransportProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RESTTransportProvider.swift; sourceTree = ""; }; 58E973DD24850EB600096F90 /* AsyncOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncOperation.swift; sourceTree = ""; }; 58E9C3832A4EF15300CFDEAC /* WireGuardAdapter+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WireGuardAdapter+Async.swift"; sourceTree = ""; }; - 58EC06792A8D208D00BEB973 /* TunnelDeviceInfoStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelDeviceInfoStub.swift; sourceTree = ""; }; 58E9C3852A4EF1CB00CFDEAC /* PacketTunnelActor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelActor.swift; sourceTree = ""; }; + 58EC06792A8D208D00BEB973 /* TunnelDeviceInfoStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelDeviceInfoStub.swift; sourceTree = ""; }; 58EC067B2A8D2A0B00BEB973 /* NetworkCounters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkCounters.swift; sourceTree = ""; }; 58ECD29123F178FD004298B6 /* Screenshots.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Screenshots.xcconfig; sourceTree = ""; }; 58ED3A132A7C199C0085CE65 /* StartOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartOptions.swift; sourceTree = ""; }; @@ -1464,7 +1470,6 @@ 58F3F3652AA086A400D3B0A4 /* AutoCancellingTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCancellingTask.swift; sourceTree = ""; }; 58F3F3692AA08E3C00D3B0A4 /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = ""; }; 58F7753C2AB8473200425B47 /* BlockedStateErrorMapperStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedStateErrorMapperStub.swift; sourceTree = ""; }; - 58F775422AB9E3EF00425B47 /* AppMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMessageHandler.swift; sourceTree = ""; }; 58F7D26427EB50A300E4D821 /* ResultOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultOperation.swift; sourceTree = ""; }; 58F8AC0D25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemReportReviewViewController.swift; sourceTree = ""; }; 58FB865426E8BF3100F188BC /* StorePaymentManagerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorePaymentManagerError.swift; sourceTree = ""; }; @@ -1499,6 +1504,7 @@ 7A3353902AAA014400F0A71C /* SimulatorVPNConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimulatorVPNConnection.swift; sourceTree = ""; }; 7A3353922AAA089000F0A71C /* SimulatorTunnelInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimulatorTunnelInfo.swift; sourceTree = ""; }; 7A3353962AAA0F8600F0A71C /* OperationBlockObserverSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationBlockObserverSupport.swift; sourceTree = ""; }; + 7A3FD1B42AD4465A0042BEA6 /* AppMessageHandlerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppMessageHandlerTests.swift; sourceTree = ""; }; 7A42DEC82A05164100B209BE /* SettingsInputCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsInputCell.swift; sourceTree = ""; }; 7A42DECC2A09064C00B209BE /* SelectableSettingsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectableSettingsCell.swift; sourceTree = ""; }; 7A6B4F582AB8412E00123853 /* TunnelMonitorTimings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelMonitorTimings.swift; sourceTree = ""; }; @@ -1531,7 +1537,12 @@ 7A9CCCB12A96302800DD6A34 /* ApplicationCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationCoordinator.swift; sourceTree = ""; }; 7A9CCCB22A96302800DD6A34 /* TunnelCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelCoordinator.swift; sourceTree = ""; }; 7ABE318C2A1CDD4500DF4963 /* UIFont+Weight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Weight.swift"; sourceTree = ""; }; + 7AD0AA192AD69B6E00119E10 /* PacketTunnelActorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelActorProtocol.swift; sourceTree = ""; }; + 7AD0AA1B2AD6A63F00119E10 /* PacketTunnelActorStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelActorStub.swift; sourceTree = ""; }; + 7AD0AA1E2AD6C8B900119E10 /* URLRequestProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLRequestProxyProtocol.swift; sourceTree = ""; }; + 7AD0AA202AD6CB0000119E10 /* URLRequestProxyStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLRequestProxyStub.swift; sourceTree = ""; }; 7AE47E512A17972A000418DA /* AlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertViewController.swift; sourceTree = ""; }; + 7AEF7F192AD00F52006FE45D /* AppMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppMessageHandler.swift; sourceTree = ""; }; 7AF6E5EF2A95051E00F2679D /* RouterBlockDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterBlockDelegate.swift; sourceTree = ""; }; 7AF9BE982A4E0FE900DBFEDB /* MarkdownStylingOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkdownStylingOptions.swift; sourceTree = ""; }; A900E9B72ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountsProxy+Stubs.swift"; sourceTree = ""; }; @@ -2304,6 +2315,7 @@ 583832202AC3174700EA2071 /* PacketTunnelActor+NetworkReachability.swift */, 586C14592AC4735F00245C01 /* PacketTunnelActor+Public.swift */, 583832262AC3193600EA2071 /* PacketTunnelActor+SleepCycle.swift */, + 7AD0AA192AD69B6E00119E10 /* PacketTunnelActorProtocol.swift */, 58E7A0312AA0715100C57861 /* Protocols */, 58ED3A132A7C199C0085CE65 /* StartOptions.swift */, 5824030C2A811B0000163DE8 /* State.swift */, @@ -2536,8 +2548,9 @@ 58C7A4432A863F490060C66F /* PacketTunnelCoreTests */ = { isa = PBXGroup; children = ( - 586C14572AC463BB00245C01 /* CommandChannelTests.swift */, 58EC067D2A8D2B0700BEB973 /* Mocks */, + 7A3FD1B42AD4465A0042BEA6 /* AppMessageHandlerTests.swift */, + 586C14572AC463BB00245C01 /* CommandChannelTests.swift */, 58FE25D32AA729B5003D1918 /* PacketTunnelActorTests.swift */, 58C7A46F2A8649ED0060C66F /* PingerTests.swift */, 5838321C2AC1C54600EA2071 /* TaskSleepTests.swift */, @@ -2549,6 +2562,7 @@ 58C9B8C52ABB23B400040B46 /* IPC */ = { isa = PBXGroup; children = ( + 7AEF7F192AD00F52006FE45D /* AppMessageHandler.swift */, 587C575226D2615F005EF767 /* PacketTunnelOptions.swift */, 5898D2B62902A9EA00EB5EBA /* PacketTunnelRelay.swift */, 585DA89826B0329200B8C587 /* PacketTunnelStatus.swift */, @@ -2565,6 +2579,7 @@ 063687AF28EB083800BE7161 /* ProxyURLRequest.swift */, 5898D2AD290185D200EB5EBA /* ProxyURLResponse.swift */, 58D229B6298D1D5200BB5A2D /* URLRequestProxy.swift */, + 7AD0AA1E2AD6C8B900119E10 /* URLRequestProxyProtocol.swift */, ); path = URLRequestProxy; sourceTree = ""; @@ -2800,6 +2815,8 @@ 58FE25F12AA77674003D1918 /* SettingsReaderStub.swift */, 58F7753C2AB8473200425B47 /* BlockedStateErrorMapperStub.swift */, 5838321A2AC1B18400EA2071 /* PacketTunnelActor+Mocks.swift */, + 7AD0AA1B2AD6A63F00119E10 /* PacketTunnelActorStub.swift */, + 7AD0AA202AD6CB0000119E10 /* URLRequestProxyStub.swift */, ); path = Mocks; sourceTree = ""; @@ -2829,8 +2846,6 @@ isa = PBXGroup; children = ( 58F3F3692AA08E3C00D3B0A4 /* PacketTunnelProvider.swift */, - 58F775422AB9E3EF00425B47 /* AppMessageHandler.swift */, - 585B1FF12AB0BC69008AD470 /* State+Extensions.swift */, 580D6B912AB360BE00B2D6E0 /* DeviceCheck+BlockedStateReason.swift */, 5864AF7C2A9F4DC9008BC928 /* SettingsReader.swift */, 580D6B8D2AB33BBF00B2D6E0 /* BlockedStateErrorMapper.swift */, @@ -4133,11 +4148,14 @@ 58FE25D72AA72A8F003D1918 /* State.swift in Sources */, 58C7AF132ABD8480007EDD7A /* PacketTunnelStatus.swift in Sources */, 58C7A4592A863FB90060C66F /* WgStats.swift in Sources */, + 7AD0AA1F2AD6C8B900119E10 /* URLRequestProxyProtocol.swift in Sources */, 7A6B4F592AB8412E00123853 /* TunnelMonitorTimings.swift in Sources */, 58FE25DB2AA72A8F003D1918 /* StartOptions.swift in Sources */, 583832212AC3174700EA2071 /* PacketTunnelActor+NetworkReachability.swift in Sources */, 58FE25D82AA72A8F003D1918 /* ConfigurationBuilder.swift in Sources */, + 7AEF7F1A2AD00F52006FE45D /* AppMessageHandler.swift in Sources */, 580D6B8A2AB31AB400B2D6E0 /* NetworkPath+NetworkReachability.swift in Sources */, + 7AD0AA1D2AD6A86700119E10 /* PacketTunnelActorProtocol.swift in Sources */, 5826B6CB2ABD83E200B1CA13 /* PacketTunnelOptions.swift in Sources */, 586E8DB82AAF4AC4007BF3DA /* Task+Duration.swift in Sources */, 5838322B2AC3EF9600EA2071 /* CommandChannel.swift in Sources */, @@ -4156,20 +4174,26 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 7AD0AA1C2AD6A63F00119E10 /* PacketTunnelActorStub.swift in Sources */, 58EC067A2A8D208D00BEB973 /* TunnelDeviceInfoStub.swift in Sources */, 586C14582AC463BB00245C01 /* CommandChannelTests.swift in Sources */, 58EC067C2A8D2A0B00BEB973 /* NetworkCounters.swift in Sources */, 58FE25EC2AA77639003D1918 /* TunnelMonitorStub.swift in Sources */, + 7A3FD1B82AD54AE60042BEA6 /* TimeServerProxy.swift in Sources */, 58FE25EE2AA7764E003D1918 /* TunnelAdapterDummy.swift in Sources */, 581F23AD2A8CF92100788AB6 /* DefaultPathObserverFake.swift in Sources */, 5838321B2AC1B18400EA2071 /* PacketTunnelActor+Mocks.swift in Sources */, 5838321D2AC1C54600EA2071 /* TaskSleepTests.swift in Sources */, 58092E542A8B832E00C3CC72 /* TunnelMonitorTests.swift in Sources */, + 7AD0AA212AD6CB0000119E10 /* URLRequestProxyStub.swift in Sources */, 58FE25F02AA77664003D1918 /* RelaySelectorStub.swift in Sources */, 581F23AF2A8CF94D00788AB6 /* PingerMock.swift in Sources */, + 7A3FD1B62AD542110042BEA6 /* ServerRelaysResponse+Stubs.swift in Sources */, + 7A3FD1B72AD54ABD0042BEA6 /* AnyTransport.swift in Sources */, 58FE25F22AA77674003D1918 /* SettingsReaderStub.swift in Sources */, 58F7753D2AB8473200425B47 /* BlockedStateErrorMapperStub.swift in Sources */, 58FE25D42AA729B5003D1918 /* PacketTunnelActorTests.swift in Sources */, + 7A3FD1B52AD4465A0042BEA6 /* AppMessageHandlerTests.swift in Sources */, 58C7A4702A8649ED0060C66F /* PingerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4412,7 +4436,6 @@ 581DA2762A1E2FD10046ED47 /* WgKeyRotation.swift in Sources */, 580810E52A30E13A00B74552 /* DeviceStateAccessorProtocol.swift in Sources */, 580810E82A30E15500B74552 /* DeviceCheckRemoteServiceProtocol.swift in Sources */, - 585B1FF22AB0BC69008AD470 /* State+Extensions.swift in Sources */, 58C9B8CE2ABB252E00040B46 /* DeviceCheck.swift in Sources */, 58915D682A25FA080066445B /* DeviceCheckRemoteService.swift in Sources */, 58E9C3842A4EF15300CFDEAC /* WireGuardAdapter+Async.swift in Sources */, @@ -4432,7 +4455,6 @@ 58CE38C728992C8700A6D6E5 /* WireGuardAdapterError+Localization.swift in Sources */, 58E511E828DDDF2400B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */, 582403822A827E1500163DE8 /* RelaySelectorWrapper.swift in Sources */, - 58F775432AB9E3EF00425B47 /* AppMessageHandler.swift in Sources */, 58FDF2D92A0BA11A00C2B061 /* DeviceCheckOperation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift b/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift index a39f1f517d10..8a8748ed6064 100644 --- a/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift +++ b/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift @@ -27,12 +27,9 @@ enum SetAccountAction { var taskName: String { switch self { - case .new: - return "Set new account" - case .existing: - return "Set existing account" - case .unset: - return "Unset account" + case .new: "Set new account" + case .existing: "Set existing account" + case .unset: "Unset account" } } } diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift index 9b36bba5c5ac..7594e1559f36 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift @@ -289,7 +289,7 @@ final class TunnelManager: StorePaymentObserver { finish(result.error) } } catch { - if let error = error as? NoRelaysSatisfyingConstraintsError { + if error is NoRelaysSatisfyingConstraintsError { _ = self.setTunnelStatus { tunnelStatus in tunnelStatus.state = .error(.noRelaysSatisfyingConstraints) } diff --git a/ios/MullvadVPNTests/ServerRelaysResponse+Stubs.swift b/ios/MullvadVPNTests/ServerRelaysResponse+Stubs.swift index bf6615a05205..8bca08f4f8eb 100644 --- a/ios/MullvadVPNTests/ServerRelaysResponse+Stubs.swift +++ b/ios/MullvadVPNTests/ServerRelaysResponse+Stubs.swift @@ -8,6 +8,7 @@ import Foundation @testable import MullvadREST +import WireGuardKitTypes enum ServerRelaysResponseStubs { static let portRanges: [[UInt16]] = [[4000, 4001], [5000, 5001]] @@ -77,7 +78,7 @@ enum ServerRelaysResponseStubs { weight: 500, ipv4AddrIn: .loopback, ipv6AddrIn: .loopback, - publicKey: Data(), + publicKey: PrivateKey().publicKey.rawValue, includeInCountry: true ), REST.ServerRelay( @@ -89,7 +90,7 @@ enum ServerRelaysResponseStubs { weight: 1000, ipv4AddrIn: .loopback, ipv6AddrIn: .loopback, - publicKey: Data(), + publicKey: PrivateKey().publicKey.rawValue, includeInCountry: true ), REST.ServerRelay( @@ -101,7 +102,7 @@ enum ServerRelaysResponseStubs { weight: 50, ipv4AddrIn: .loopback, ipv6AddrIn: .loopback, - publicKey: Data(), + publicKey: PrivateKey().publicKey.rawValue, includeInCountry: true ), REST.ServerRelay( @@ -113,7 +114,7 @@ enum ServerRelaysResponseStubs { weight: 100, ipv4AddrIn: .loopback, ipv6AddrIn: .loopback, - publicKey: Data(), + publicKey: PrivateKey().publicKey.rawValue, includeInCountry: true ), REST.ServerRelay( @@ -125,7 +126,7 @@ enum ServerRelaysResponseStubs { weight: 100, ipv4AddrIn: .loopback, ipv6AddrIn: .loopback, - publicKey: Data(), + publicKey: PrivateKey().publicKey.rawValue, includeInCountry: true ), REST.ServerRelay( @@ -137,7 +138,7 @@ enum ServerRelaysResponseStubs { weight: 100, ipv4AddrIn: .loopback, ipv6AddrIn: .loopback, - publicKey: Data(), + publicKey: PrivateKey().publicKey.rawValue, includeInCountry: true ), ] diff --git a/ios/PacketTunnel/PacketTunnelProvider/BlockedStateErrorMapper.swift b/ios/PacketTunnel/PacketTunnelProvider/BlockedStateErrorMapper.swift index f7d22d16db2f..72b91f842f69 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/BlockedStateErrorMapper.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/BlockedStateErrorMapper.swift @@ -57,6 +57,10 @@ public struct BlockedStateErrorMapper: BlockedStateErrorMapperProtocol { // packet tunnel provider. return .tunnelAdapter + case is PublicKeyError: + // Returned when there is an endpoint but its public key is invalid. + return .invalidPublicKey + default: // Everything else in case we introduce new errors and forget to handle them. return .unknown diff --git a/ios/PacketTunnel/PacketTunnelProvider/State+Extensions.swift b/ios/PacketTunnel/PacketTunnelProvider/State+Extensions.swift deleted file mode 100644 index 99862e152199..000000000000 --- a/ios/PacketTunnel/PacketTunnelProvider/State+Extensions.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// State+Extensions.swift -// PacketTunnel -// -// Created by pronebird on 12/09/2023. -// Copyright © 2023 Mullvad VPN AB. All rights reserved. -// - -import Foundation -import MullvadTypes -import PacketTunnelCore - -extension State { - var packetTunnelStatus: PacketTunnelStatus { - var status = PacketTunnelStatus() - - switch self { - case let .connecting(connState), - let .connected(connState), - let .reconnecting(connState), - let .disconnecting(connState): - switch connState.networkReachability { - case .reachable: - status.isNetworkReachable = true - case .unreachable: - status.isNetworkReachable = false - case .undetermined: - // TODO: fix me - status.isNetworkReachable = true - } - - status.numberOfFailedAttempts = connState.connectionAttemptCount - status.tunnelRelay = connState.selectedRelay.packetTunnelRelay - - case .disconnected, .initial: - break - - case let .error(blockedState): - status.blockedStateReason = blockedState.reason - } - - return status - } - - var relayConstraints: RelayConstraints? { - switch self { - case let .connecting(connState), let .connected(connState), let .reconnecting(connState): - return connState.relayConstraints - - case let .error(blockedState): - return blockedState.relayConstraints - - case .initial, .disconnecting, .disconnected: - return nil - } - } -} diff --git a/ios/PacketTunnelCore/Actor/ConfigurationBuilder.swift b/ios/PacketTunnelCore/Actor/ConfigurationBuilder.swift index c4a731aa7829..6ba03db89b3e 100644 --- a/ios/PacketTunnelCore/Actor/ConfigurationBuilder.swift +++ b/ios/PacketTunnelCore/Actor/ConfigurationBuilder.swift @@ -13,6 +13,15 @@ import struct WireGuardKitTypes.IPAddressRange import class WireGuardKitTypes.PrivateKey import class WireGuardKitTypes.PublicKey +/// Error returned when there is an endpoint but its public key is invalid. +public struct PublicKeyError: LocalizedError { + let endpoint: MullvadEndpoint + + public var errorDescription: String? { + "Public key is invalid, endpoint: \(endpoint)" + } +} + /// Struct building tunnel adapter configuration. struct ConfigurationBuilder { var privateKey: PrivateKey @@ -20,22 +29,28 @@ struct ConfigurationBuilder { var dns: SelectedDNSServers? var endpoint: MullvadEndpoint? - func makeConfiguration() -> TunnelAdapterConfiguration { + func makeConfiguration() throws -> TunnelAdapterConfiguration { return TunnelAdapterConfiguration( privateKey: privateKey, interfaceAddresses: interfaceAddresses, dns: dnsServers, - peer: peer + peer: try peer ) } private var peer: TunnelPeer? { - guard let endpoint else { return nil } + get throws { + guard let endpoint else { return nil } - return TunnelPeer( - endpoint: .ipv4(endpoint.ipv4Relay), - publicKey: PublicKey(rawValue: endpoint.publicKey)! - ) + guard let publicKey = PublicKey(rawValue: endpoint.publicKey) else { + throw PublicKeyError(endpoint: endpoint) + } + + return TunnelPeer( + endpoint: .ipv4(endpoint.ipv4Relay), + publicKey: publicKey + ) + } } private var dnsServers: [IPAddress] { diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor+KeyPolicy.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor+KeyPolicy.swift index 0cf8351523c2..5ab13353e915 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor+KeyPolicy.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor+KeyPolicy.swift @@ -159,7 +159,7 @@ extension PacketTunnelActor { /** Internal helper that transitions key policy from `.usePrior` to `.useCurrent`. - - Parameter keyPolicy: a reference to key policy hend either in connection state or blocked state struct. + - Parameter keyPolicy: a reference to key policy held either in connection state or blocked state struct. - Returns: `true` when the policy was modified, otherwise `false`. */ private func setCurrentKeyPolicy(_ keyPolicy: inout KeyPolicy) -> Bool { diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift index 45f805eafd8b..b5b2c6f1c0e7 100644 --- a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift @@ -355,3 +355,5 @@ extension PacketTunnelActor { } } } + +extension PacketTunnelActor: PacketTunnelActorProtocol {} diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActorProtocol.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActorProtocol.swift new file mode 100644 index 000000000000..d5acf6bae390 --- /dev/null +++ b/ios/PacketTunnelCore/Actor/PacketTunnelActorProtocol.swift @@ -0,0 +1,16 @@ +// +// PacketTunnelActorProtocol.swift +// PacketTunnelCoreTests +// +// Created by Jon Petersson on 2023-10-11. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +public protocol PacketTunnelActorProtocol { + var state: State { get async } + + func reconnect(to nextRelay: NextRelay) + func notifyKeyRotation(date: Date?) +} diff --git a/ios/PacketTunnelCore/Actor/State+Extensions.swift b/ios/PacketTunnelCore/Actor/State+Extensions.swift index cfaed6cf0787..223fe2374475 100644 --- a/ios/PacketTunnelCore/Actor/State+Extensions.swift +++ b/ios/PacketTunnelCore/Actor/State+Extensions.swift @@ -7,6 +7,7 @@ // import Foundation +import MullvadTypes import class WireGuardKitTypes.PrivateKey extension State { @@ -36,6 +37,50 @@ extension State { } } + var packetTunnelStatus: PacketTunnelStatus { + var status = PacketTunnelStatus() + + switch self { + case let .connecting(connState), + let .connected(connState), + let .reconnecting(connState), + let .disconnecting(connState): + switch connState.networkReachability { + case .reachable: + status.isNetworkReachable = true + case .unreachable: + status.isNetworkReachable = false + case .undetermined: + // TODO: fix me + status.isNetworkReachable = true + } + + status.numberOfFailedAttempts = connState.connectionAttemptCount + status.tunnelRelay = connState.selectedRelay.packetTunnelRelay + + case .disconnected, .initial: + break + + case let .error(blockedState): + status.blockedStateReason = blockedState.reason + } + + return status + } + + public var relayConstraints: RelayConstraints? { + switch self { + case let .connecting(connState), let .connected(connState), let .reconnecting(connState): + return connState.relayConstraints + + case let .error(blockedState): + return blockedState.relayConstraints + + case .initial, .disconnecting, .disconnected: + return nil + } + } + // MARK: - Logging func logFormat() -> String { @@ -105,7 +150,7 @@ extension BlockedStateReason { return true case .noRelaysSatisfyingConstraints, .readSettings, .invalidAccount, .deviceRevoked, .tunnelAdapter, .unknown, - .deviceLoggedOut, .outdatedSchema: + .deviceLoggedOut, .outdatedSchema, .invalidPublicKey: return false } } diff --git a/ios/PacketTunnelCore/Actor/State.swift b/ios/PacketTunnelCore/Actor/State.swift index 836e742594ac..4449372762d6 100644 --- a/ios/PacketTunnelCore/Actor/State.swift +++ b/ios/PacketTunnelCore/Actor/State.swift @@ -110,7 +110,7 @@ public struct ConnectionState { /// This is primarily used by packet tunnel for updating constraints in tunnel provider. public var relayConstraints: RelayConstraints - /// Last WG key read from setings. + /// Last WG key read from settings. /// Can be `nil` if moved to `keyPolicy`. public var currentKey: PrivateKey? @@ -192,6 +192,9 @@ public enum BlockedStateReason: String, Codable, Equatable { /// Tunnel adapter error. case tunnelAdapter + /// Invalid public key. + case invalidPublicKey + /// Unidentified reason. case unknown } diff --git a/ios/PacketTunnel/PacketTunnelProvider/AppMessageHandler.swift b/ios/PacketTunnelCore/IPC/AppMessageHandler.swift similarity index 87% rename from ios/PacketTunnel/PacketTunnelProvider/AppMessageHandler.swift rename to ios/PacketTunnelCore/IPC/AppMessageHandler.swift index 952fcb4bdeb7..360b3bacb566 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/AppMessageHandler.swift +++ b/ios/PacketTunnelCore/IPC/AppMessageHandler.swift @@ -8,17 +8,16 @@ import Foundation import MullvadLogging -import PacketTunnelCore /** Actor handling packet tunnel IPC (app) messages and patching them through to the right facility. */ -struct AppMessageHandler { +public struct AppMessageHandler { private let logger = Logger(label: "AppMessageHandler") - private let packetTunnelActor: PacketTunnelActor - private let urlRequestProxy: URLRequestProxy + private let packetTunnelActor: PacketTunnelActorProtocol + private let urlRequestProxy: URLRequestProxyProtocol - init(packetTunnelActor: PacketTunnelActor, urlRequestProxy: URLRequestProxy) { + public init(packetTunnelActor: PacketTunnelActorProtocol, urlRequestProxy: URLRequestProxyProtocol) { self.packetTunnelActor = packetTunnelActor self.urlRequestProxy = urlRequestProxy } @@ -34,7 +33,7 @@ struct AppMessageHandler { the acknowledgment from IPC before starting next operation, hence it's critical to return as soon as possible. (See `TunnelManager.reconnectTunnel()`, `SendTunnelProviderMessageOperation`) */ - func handleAppMessage(_ messageData: Data) async -> Data? { + public func handleAppMessage(_ messageData: Data) async -> Data? { guard let message = decodeMessage(messageData) else { return nil } logger.debug("Received app message: \(message)") @@ -51,7 +50,7 @@ struct AppMessageHandler { return await encodeReply(packetTunnelActor.state.packetTunnelStatus) case .privateKeyRotation: - packetTunnelActor.notifyKeyRotation(date: nil) + packetTunnelActor.notifyKeyRotation(date: Date()) return nil case let .reconnectTunnel(selectorResult): diff --git a/ios/PacketTunnelCore/URLRequestProxy/URLRequestProxy.swift b/ios/PacketTunnelCore/URLRequestProxy/URLRequestProxy.swift index e6f6b38e1549..967a17e94028 100644 --- a/ios/PacketTunnelCore/URLRequestProxy/URLRequestProxy.swift +++ b/ios/PacketTunnelCore/URLRequestProxy/URLRequestProxy.swift @@ -87,3 +87,5 @@ extension URLRequestProxy { } } } + +extension URLRequestProxy: URLRequestProxyProtocol {} diff --git a/ios/PacketTunnelCore/URLRequestProxy/URLRequestProxyProtocol.swift b/ios/PacketTunnelCore/URLRequestProxy/URLRequestProxyProtocol.swift new file mode 100644 index 000000000000..da52b447ba8e --- /dev/null +++ b/ios/PacketTunnelCore/URLRequestProxy/URLRequestProxyProtocol.swift @@ -0,0 +1,15 @@ +// +// URLRequestProxyProtocol.swift +// PacketTunnelCore +// +// Created by Jon Petersson on 2023-10-11. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +public protocol URLRequestProxyProtocol { + func sendRequest(_ proxyRequest: ProxyURLRequest, completionHandler: @escaping @Sendable (ProxyURLResponse) -> Void) + func sendRequest(_ proxyRequest: ProxyURLRequest) async -> ProxyURLResponse + func cancelRequest(identifier: UUID) +} diff --git a/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift b/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift new file mode 100644 index 000000000000..59550a183010 --- /dev/null +++ b/ios/PacketTunnelCoreTests/AppMessageHandlerTests.swift @@ -0,0 +1,108 @@ +// +// AppMessageHandlerTests.swift +// PacketTunnelCoreTests +// +// Created by Jon Petersson on 2023-09-28. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +import Combine +@testable import MullvadREST +import MullvadTypes +import PacketTunnelCore +import RelaySelector +import XCTest + +final class AppMessageHandlerTests: XCTestCase { + func testHandleAppMessageForSendURLRequest() async throws { + let sendRequestExpectation = expectation(description: "Expect sending request") + + let actor = PacketTunnelActorStub() + let urlRequestProxy = URLRequestProxyStub(sendRequestExpectation: sendRequestExpectation) + let appMessageHandler = createAppMessageHandler(urlRequestProxy: urlRequestProxy) + + let url = URL(string: "localhost")! + let urlRequest = ProxyURLRequest( + id: UUID(), + urlRequest: URLRequest(url: url) + )! + + _ = try? await appMessageHandler.handleAppMessage( + TunnelProviderMessage.sendURLRequest(urlRequest).encode() + ) + + await fulfillment(of: [sendRequestExpectation], timeout: 1) + } + + func testHandleAppMessageForCancelURLRequest() async throws { + let cancelRequestExpectation = expectation(description: "Expect cancelling request") + + let actor = PacketTunnelActorStub() + let urlRequestProxy = URLRequestProxyStub(cancelRequestExpectation: cancelRequestExpectation) + let appMessageHandler = createAppMessageHandler(urlRequestProxy: urlRequestProxy) + + _ = try? await appMessageHandler.handleAppMessage( + TunnelProviderMessage.cancelURLRequest(UUID()).encode() + ) + + await fulfillment(of: [cancelRequestExpectation], timeout: 1) + } + + func testHandleAppMessageForTunnelStatus() async throws { + let stateExpectation = expectation(description: "Expect getting state") + + let actor = PacketTunnelActorStub(stateExpectation: stateExpectation) + let appMessageHandler = createAppMessageHandler(actor: actor) + + _ = try? await appMessageHandler.handleAppMessage( + TunnelProviderMessage.getTunnelStatus.encode() + ) + + await fulfillment(of: [stateExpectation], timeout: 1) + } + + func testHandleAppMessageForKeyRotation() async throws { + let keyRotationExpectation = expectation(description: "Expect key rotation") + + let actor = PacketTunnelActorStub(keyRotationExpectation: keyRotationExpectation) + let appMessageHandler = createAppMessageHandler(actor: actor) + + _ = try? await appMessageHandler.handleAppMessage( + TunnelProviderMessage.privateKeyRotation.encode() + ) + + await fulfillment(of: [keyRotationExpectation], timeout: 1) + } + + func testHandleAppMessageForReconnectTunnel() async throws { + let reconnectExpectation = expectation(description: "Expect reconnecting state") + + let actor = PacketTunnelActorStub(reconnectExpectation: reconnectExpectation) + let appMessageHandler = createAppMessageHandler(actor: actor) + + let relayConstraints = RelayConstraints(location: .only(.hostname("se", "sto", "se6-wireguard"))) + let selectorResult = try? RelaySelector.evaluate( + relays: ServerRelaysResponseStubs.sampleRelays, + constraints: relayConstraints, + numberOfFailedAttempts: 0 + ) + + _ = try? await appMessageHandler.handleAppMessage( + TunnelProviderMessage.reconnectTunnel(selectorResult).encode() + ) + + await fulfillment(of: [reconnectExpectation], timeout: 1) + } +} + +extension AppMessageHandlerTests { + func createAppMessageHandler( + actor: PacketTunnelActorProtocol = PacketTunnelActorStub(), + urlRequestProxy: URLRequestProxyProtocol = URLRequestProxyStub() + ) -> AppMessageHandler { + return AppMessageHandler( + packetTunnelActor: actor, + urlRequestProxy: urlRequestProxy + ) + } +} diff --git a/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActor+Mocks.swift b/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActor+Mocks.swift index 418f691f46e3..3e01bec31c4d 100644 --- a/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActor+Mocks.swift +++ b/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActor+Mocks.swift @@ -13,7 +13,7 @@ extension PacketTunnelActorTimings { static var timingsForTests: PacketTunnelActorTimings { return PacketTunnelActorTimings( bootRecoveryPeriodicity: .milliseconds(10), - wgKeyPropagationDelay: .milliseconds(10) + wgKeyPropagationDelay: .zero ) } } diff --git a/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActorStub.swift b/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActorStub.swift new file mode 100644 index 000000000000..80c22971df6a --- /dev/null +++ b/ios/PacketTunnelCoreTests/Mocks/PacketTunnelActorStub.swift @@ -0,0 +1,33 @@ +// +// PacketTunnelActorStub.swift +// PacketTunnelCoreTests +// +// Created by Jon Petersson on 2023-10-11. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import PacketTunnelCore +import XCTest + +struct PacketTunnelActorStub: PacketTunnelActorProtocol { + let innerState: State = .disconnected + var stateExpectation: XCTestExpectation? + var reconnectExpectation: XCTestExpectation? + var keyRotationExpectation: XCTestExpectation? + + var state: State { + get async { + stateExpectation?.fulfill() + return innerState + } + } + + func reconnect(to nextRelay: NextRelay) { + reconnectExpectation?.fulfill() + } + + func notifyKeyRotation(date: Date?) { + keyRotationExpectation?.fulfill() + } +} diff --git a/ios/PacketTunnelCoreTests/Mocks/URLRequestProxyStub.swift b/ios/PacketTunnelCoreTests/Mocks/URLRequestProxyStub.swift new file mode 100644 index 000000000000..a8f21538dbe9 --- /dev/null +++ b/ios/PacketTunnelCoreTests/Mocks/URLRequestProxyStub.swift @@ -0,0 +1,32 @@ +// +// URLRequestProxyStub.swift +// PacketTunnelCoreTests +// +// Created by Jon Petersson on 2023-10-11. +// Copyright © 2023 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import PacketTunnelCore +import XCTest + +struct URLRequestProxyStub: URLRequestProxyProtocol { + var sendRequestExpectation: XCTestExpectation? + var cancelRequestExpectation: XCTestExpectation? + + func sendRequest( + _ proxyRequest: PacketTunnelCore.ProxyURLRequest, + completionHandler: @escaping @Sendable (PacketTunnelCore.ProxyURLResponse) -> Void + ) { + sendRequestExpectation?.fulfill() + } + + func sendRequest(_ proxyRequest: PacketTunnelCore.ProxyURLRequest) async -> PacketTunnelCore.ProxyURLResponse { + sendRequestExpectation?.fulfill() + return ProxyURLResponse(data: nil, response: nil, error: nil) + } + + func cancelRequest(identifier: UUID) { + cancelRequestExpectation?.fulfill() + } +}