diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-09-22 12:09:17 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-09-26 13:44:09 +0200 |
| commit | d52fbbdc6f8a3626d2a222543ac51fd07634179a (patch) | |
| tree | 0e654d17a7711ab98fe1c308927ad209637a4b8d | |
| parent | 2c003f12e01e92b338e6361d38a4f75a47e3e041 (diff) | |
| download | mullvadvpn-d52fbbdc6f8a3626d2a222543ac51fd07634179a.tar.xz mullvadvpn-d52fbbdc6f8a3626d2a222543ac51fd07634179a.zip | |
Replace ChainedError with WrappingError
37 files changed, 278 insertions, 223 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 1d105f09d8..35842fcd3a 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -34,8 +34,8 @@ 5815039E24D6ECE600C9C50E /* TextFileOutputStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5815039C24D6ECE600C9C50E /* TextFileOutputStream.swift */; }; 581503A024D6F01E00C9C50E /* LogRotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5815039324D6EB7200C9C50E /* LogRotation.swift */; }; 581503A124D6F01F00C9C50E /* LogRotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5815039324D6EB7200C9C50E /* LogRotation.swift */; }; - 581503A324D6F1EC00C9C50E /* ChainedError+Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581503A224D6F1EC00C9C50E /* ChainedError+Logger.swift */; }; - 581503A424D6F1EC00C9C50E /* ChainedError+Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581503A224D6F1EC00C9C50E /* ChainedError+Logger.swift */; }; + 581503A324D6F1EC00C9C50E /* Logger+Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581503A224D6F1EC00C9C50E /* Logger+Errors.swift */; }; + 581503A424D6F1EC00C9C50E /* Logger+Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581503A224D6F1EC00C9C50E /* Logger+Errors.swift */; }; 581503A624D6F4AE00C9C50E /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581503A524D6F4AE00C9C50E /* Logging.swift */; }; 581503A724D6F4AE00C9C50E /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581503A524D6F4AE00C9C50E /* Logging.swift */; }; 58161C9C28352F850028ECFD /* MigrateSettingsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58161C9B28352F850028ECFD /* MigrateSettingsOperation.swift */; }; @@ -64,8 +64,6 @@ 58293FB725138B88005D0BB5 /* CustomNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58293FB625138B88005D0BB5 /* CustomNavigationController.swift */; }; 582A8A3A28BCE19B00D0F9FB /* FixedWidthIntegerArithmeticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582A8A3928BCE19B00D0F9FB /* FixedWidthIntegerArithmeticsTests.swift */; }; 582A8A3B28BCE1AB00D0F9FB /* FixedWidthInteger+Arithmetics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58900D0228BBDCC70094E4F0 /* FixedWidthInteger+Arithmetics.swift */; }; - 582AD44027BE616E002A6BFC /* CodingErrors+ChainedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582AD43F27BE616E002A6BFC /* CodingErrors+ChainedError.swift */; }; - 582AD44127BE6178002A6BFC /* CodingErrors+ChainedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582AD43F27BE616E002A6BFC /* CodingErrors+ChainedError.swift */; }; 582AE3102440A6CA00E6733A /* AccountTokenInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582AE30F2440A6CA00E6733A /* AccountTokenInput.swift */; }; 582AE3122440CA0D00E6733A /* AccountTokenInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582AE3112440CA0D00E6733A /* AccountTokenInputTests.swift */; }; 582AE3132440CA2700E6733A /* AccountTokenInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582AE30F2440A6CA00E6733A /* AccountTokenInput.swift */; }; @@ -122,7 +120,6 @@ 58561C99239A5D1500BD6B5E /* IPEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58561C98239A5D1500BD6B5E /* IPEndpoint.swift */; }; 58561C9A239A5D1500BD6B5E /* IPEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58561C98239A5D1500BD6B5E /* IPEndpoint.swift */; }; 5856D13727450A8A00DFD627 /* UIImage+TintColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5856D13627450A8A00DFD627 /* UIImage+TintColor.swift */; }; - 5857F23024C843ED00CF6F47 /* ChainedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F840B12464491D0044E708 /* ChainedError.swift */; }; 5857F23424C8443700CF6F47 /* AsyncOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E973DD24850EB600096F90 /* AsyncOperation.swift */; }; 5857F23824C8446700CF6F47 /* AsyncBlockOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 580EE22324B3243100F9D8A1 /* AsyncBlockOperation.swift */; }; 5857F24324C8662600CF6F47 /* SelectLocationHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5857F24224C8662600CF6F47 /* SelectLocationHeaderView.swift */; }; @@ -274,6 +271,14 @@ 58E0A98827C8F46300FE6BDD /* Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E0A98727C8F46300FE6BDD /* Tunnel.swift */; }; 58E20771274672CA00DE5D77 /* LaunchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E20770274672CA00DE5D77 /* LaunchViewController.swift */; }; 58E25F812837BBBB002CFB2C /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E25F802837BBBB002CFB2C /* SceneDelegate.swift */; }; + 58E511E128DDB7F100B0BCDE /* WrappingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E511E028DDB7F100B0BCDE /* WrappingError.swift */; }; + 58E511E228DDB7FB00B0BCDE /* WrappingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E511E028DDB7F100B0BCDE /* WrappingError.swift */; }; + 58E511E428DDDE8900B0BCDE /* CustomErrorDescriptionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E511E328DDDE8900B0BCDE /* CustomErrorDescriptionProtocol.swift */; }; + 58E511E628DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E511E528DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift */; }; + 58E511E728DDDF1C00B0BCDE /* CustomErrorDescriptionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E511E328DDDE8900B0BCDE /* CustomErrorDescriptionProtocol.swift */; }; + 58E511E828DDDF2400B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E511E528DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift */; }; + 58E511EB28DDE18400B0BCDE /* Error+Chain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E511EA28DDE18400B0BCDE /* Error+Chain.swift */; }; + 58E511EC28DDE18400B0BCDE /* Error+Chain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E511EA28DDE18400B0BCDE /* Error+Chain.swift */; }; 58E6771F24ADFE7800AA26E7 /* SettingsNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E6771E24ADFE7800AA26E7 /* SettingsNavigationController.swift */; }; 58EE2E3A272FF814003BFF93 /* SettingsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58EE2E38272FF814003BFF93 /* SettingsDataSource.swift */; }; 58EE2E3B272FF814003BFF93 /* SettingsDataSourceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58EE2E39272FF814003BFF93 /* SettingsDataSourceDelegate.swift */; }; @@ -291,8 +296,6 @@ 58F3C0A724A50C02003E76BE /* relays.json in Resources */ = {isa = PBXBuildFile; fileRef = 58F3C0A524A50155003E76BE /* relays.json */; }; 58F7CA882692E34000FC59FD /* WireguardKeysContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F7CA872692E34000FC59FD /* WireguardKeysContentView.swift */; }; 58F7D26527EB50A300E4D821 /* ResultOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F7D26427EB50A300E4D821 /* ResultOperation.swift */; }; - 58F840B22464491D0044E708 /* ChainedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F840B12464491D0044E708 /* ChainedError.swift */; }; - 58F840B32464491D0044E708 /* ChainedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F840B12464491D0044E708 /* ChainedError.swift */; }; 58F8AC0E25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F8AC0D25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift */; }; 58F97A1B280EEBC00050C2FC /* RESTProxyFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F97A1A280EEBC00050C2FC /* RESTProxyFactory.swift */; }; 58F97A1E280FDE230050C2FC /* RESTRequestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F97A1D280FDE230050C2FC /* RESTRequestHandler.swift */; }; @@ -388,7 +391,7 @@ 5815039324D6EB7200C9C50E /* LogRotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogRotation.swift; sourceTree = "<group>"; }; 5815039624D6ECAE00C9C50E /* CustomFormatLogHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomFormatLogHandler.swift; sourceTree = "<group>"; }; 5815039C24D6ECE600C9C50E /* TextFileOutputStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFileOutputStream.swift; sourceTree = "<group>"; }; - 581503A224D6F1EC00C9C50E /* ChainedError+Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChainedError+Logger.swift"; sourceTree = "<group>"; }; + 581503A224D6F1EC00C9C50E /* Logger+Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+Errors.swift"; sourceTree = "<group>"; }; 581503A524D6F4AE00C9C50E /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; }; 58161C9B28352F850028ECFD /* MigrateSettingsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateSettingsOperation.swift; sourceTree = "<group>"; }; 5819C2132726CC8D00D6EC38 /* DataSourceSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourceSnapshotTests.swift; sourceTree = "<group>"; }; @@ -412,7 +415,6 @@ 58293FB2251241B3005D0BB5 /* CustomTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextView.swift; sourceTree = "<group>"; }; 58293FB625138B88005D0BB5 /* CustomNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavigationController.swift; sourceTree = "<group>"; }; 582A8A3928BCE19B00D0F9FB /* FixedWidthIntegerArithmeticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FixedWidthIntegerArithmeticsTests.swift; sourceTree = "<group>"; }; - 582AD43F27BE616E002A6BFC /* CodingErrors+ChainedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CodingErrors+ChainedError.swift"; sourceTree = "<group>"; }; 582AE30F2440A6CA00E6733A /* AccountTokenInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountTokenInput.swift; sourceTree = "<group>"; }; 582AE3112440CA0D00E6733A /* AccountTokenInputTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTokenInputTests.swift; sourceTree = "<group>"; }; 582BB1AE229566420055B6EF /* SettingsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsCell.swift; sourceTree = "<group>"; }; @@ -576,6 +578,10 @@ 58E0A98727C8F46300FE6BDD /* Tunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tunnel.swift; sourceTree = "<group>"; }; 58E20770274672CA00DE5D77 /* LaunchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchViewController.swift; sourceTree = "<group>"; }; 58E25F802837BBBB002CFB2C /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; }; + 58E511E028DDB7F100B0BCDE /* WrappingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappingError.swift; sourceTree = "<group>"; }; + 58E511E328DDDE8900B0BCDE /* CustomErrorDescriptionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomErrorDescriptionProtocol.swift; sourceTree = "<group>"; }; + 58E511E528DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CodingErrors+CustomErrorDescription.swift"; sourceTree = "<group>"; }; + 58E511EA28DDE18400B0BCDE /* Error+Chain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Error+Chain.swift"; sourceTree = "<group>"; }; 58E6771E24ADFE7800AA26E7 /* SettingsNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsNavigationController.swift; sourceTree = "<group>"; }; 58E973DD24850EB600096F90 /* AsyncOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncOperation.swift; sourceTree = "<group>"; }; 58ECD29123F178FD004298B6 /* Screenshots.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Screenshots.xcconfig; sourceTree = "<group>"; }; @@ -594,7 +600,6 @@ 58F3C0A524A50155003E76BE /* relays.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = relays.json; sourceTree = "<group>"; }; 58F7CA872692E34000FC59FD /* WireguardKeysContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireguardKeysContentView.swift; sourceTree = "<group>"; }; 58F7D26427EB50A300E4D821 /* ResultOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultOperation.swift; sourceTree = "<group>"; }; - 58F840B12464491D0044E708 /* ChainedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainedError.swift; sourceTree = "<group>"; }; 58F8AC0D25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemReportReviewViewController.swift; sourceTree = "<group>"; }; 58F97A1A280EEBC00050C2FC /* RESTProxyFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RESTProxyFactory.swift; sourceTree = "<group>"; }; 58F97A1D280FDE230050C2FC /* RESTRequestHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RESTRequestHandler.swift; sourceTree = "<group>"; }; @@ -713,7 +718,7 @@ 5815039F24D6ECF200C9C50E /* Logging */ = { isa = PBXGroup; children = ( - 581503A224D6F1EC00C9C50E /* ChainedError+Logger.swift */, + 581503A224D6F1EC00C9C50E /* Logger+Errors.swift */, 5815039624D6ECAE00C9C50E /* CustomFormatLogHandler.swift */, 58FB865D26EA284E00F188BC /* LogFormatting.swift */, 581503A524D6F4AE00C9C50E /* Logging.swift */, @@ -889,14 +894,14 @@ 58FEEB57260B662E00A621A8 /* AutomaticKeyboardResponder.swift */, 5891BF1B25E3E3EB006D6FB0 /* Bundle+ProductVersion.swift */, 58F1311227E09B00007AC5BC /* Cancellable.swift */, - 58F840B12464491D0044E708 /* ChainedError.swift */, 587EB669270EFACB00123C75 /* CharacterSet+IPAddress.swift */, - 582AD43F27BE616E002A6BFC /* CodingErrors+ChainedError.swift */, + 58E511E528DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift */, 58B43C1825F77DB60002C8C3 /* ConnectContentView.swift */, 58A1AA8B23F5584B009F7EA6 /* ConnectionPanelView.swift */, 58CCA00F224249A1004F3011 /* ConnectViewController.swift */, 5871FB95254ADE4E0051A0A4 /* ConsolidatedApplicationLog.swift */, 5896AE83246D5889005B36CB /* CustomDateComponentsFormatting.swift */, + 58E511E328DDDE8900B0BCDE /* CustomErrorDescriptionProtocol.swift */, 582BB1B0229569620055B6EF /* CustomNavigationBar.swift */, 58293FB625138B88005D0BB5 /* CustomNavigationController.swift */, 5868BD32261DCD2600E6027F /* CustomSplitViewController.swift */, @@ -913,6 +918,7 @@ 58B9EB142489139B00095626 /* DisplayChainedError.swift */, 580F8B8528197958002E0998 /* DNSSettings.swift */, 5892A45D265FABFF00890742 /* EmptyTableViewHeaderFooterView.swift */, + 58E511EA28DDE18400B0BCDE /* Error+Chain.swift */, 58FEEB45260A028D00A621A8 /* GeoJSON.swift */, 58B3F30E2742708B00A2DD38 /* HeaderBarButton.swift */, 58F3C0A3249CB069003E76BE /* HeaderBarView.swift */, @@ -975,13 +981,13 @@ 584D26C5270C8741004EA533 /* SettingsDNSTextCell.swift */, 580F8B88281A79A7002E0998 /* SettingsManager */, 58E6771E24ADFE7800AA26E7 /* SettingsNavigationController.swift */, - 75FD0C2428B117D30021E33E /* ShortcutsViewController.swift */, - 75FD0C2228B109860021E33E /* ShortcutsDataSourceDelegate.swift */, - 75FD0C2028B108570021E33E /* ShortcutsDataSource.swift */, - 753D6C0B28B4BF3E0052D9E1 /* ShortcutsManager.swift */, 584D26C1270C8542004EA533 /* SettingsStaticTextFooterView.swift */, 58ACF64A26553C3F00ACE4B7 /* SettingsSwitchCell.swift */, 58CCA01122424D11004F3011 /* SettingsViewController.swift */, + 75FD0C2028B108570021E33E /* ShortcutsDataSource.swift */, + 75FD0C2228B109860021E33E /* ShortcutsDataSourceDelegate.swift */, + 753D6C0B28B4BF3E0052D9E1 /* ShortcutsManager.swift */, + 75FD0C2428B117D30021E33E /* ShortcutsViewController.swift */, 58BA693023EADA6A009DC256 /* SimulatorTunnelProvider.swift */, 587A01FB23F1F0BE00B68763 /* SimulatorTunnelProviderHost.swift */, 58FD5BEF24238EB300112C88 /* SKProduct+Formatting.swift */, @@ -1003,6 +1009,7 @@ 5856D13627450A8A00DFD627 /* UIImage+TintColor.swift */, 585CA70E25F8C44600B47C62 /* UIMetrics.swift */, 58F7CA872692E34000FC59FD /* WireguardKeysContentView.swift */, + 58E511E028DDB7F100B0BCDE /* WrappingError.swift */, ); path = MullvadVPN; sourceTree = "<group>"; @@ -1326,7 +1333,6 @@ 58A8055E2716EA6700681642 /* AnyIPAddress.swift in Sources */, 58DF5B7D28521AAC00E92647 /* OutputOperation.swift in Sources */, 58DF5B79285217F300E92647 /* TransformOperation.swift in Sources */, - 5857F23024C843ED00CF6F47 /* ChainedError.swift in Sources */, 58A8BE81239FBE62006B74AC /* IPEndpoint.swift in Sources */, 58871D2325D535D2002297FA /* IPAddressRange+Codable.swift in Sources */, 580CBFB82848D503007878F0 /* OperationConditionTests.swift in Sources */, @@ -1341,6 +1347,7 @@ files = ( 58BFA5CC22A7CE1F00A6173D /* ApplicationConfiguration.swift in Sources */, 5891BF5125E66B1E006D6FB0 /* UIBarButtonItem+KeyboardNavigation.swift in Sources */, + 58E511E628DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */, 587B75412668FD7800DEF7E9 /* AccountExpiryNotificationProvider.swift in Sources */, 585DA89926B0329200B8C587 /* PacketTunnelStatus.swift in Sources */, 587988C728A2A01F00E3DF54 /* AccountDataThrottling.swift in Sources */, @@ -1358,7 +1365,6 @@ 58095C512760BBB500890776 /* AddressCacheTracker.swift in Sources */, 584D26C6270C8741004EA533 /* SettingsDNSTextCell.swift in Sources */, 585DA87D26B0254000B8C587 /* RelayCacheIO.swift in Sources */, - 582AD44027BE616E002A6BFC /* CodingErrors+ChainedError.swift in Sources */, 58F2E148276A307400A79513 /* MapConnectionStatusOperation.swift in Sources */, 58F7D26527EB50A300E4D821 /* ResultOperation.swift in Sources */, 58BA693123EADA6A009DC256 /* SimulatorTunnelProvider.swift in Sources */, @@ -1386,6 +1392,7 @@ E158B360285381C60002F069 /* StringFormatter.swift in Sources */, 582BB1B1229569620055B6EF /* CustomNavigationBar.swift in Sources */, 58B3F30F2742708B00A2DD38 /* HeaderBarButton.swift in Sources */, + 58E511E428DDDE8900B0BCDE /* CustomErrorDescriptionProtocol.swift in Sources */, 584789E026529D72000E45FB /* SSLPinningURLSessionDelegate.swift in Sources */, 58161C9C28352F850028ECFD /* MigrateSettingsOperation.swift in Sources */, E1187ABF289BE76F0024E748 /* RESTCreateApplePaymentResponse+Localization.swift in Sources */, @@ -1454,6 +1461,7 @@ 584B17AB27637DE40057F3B8 /* ReconnectTunnelOperation.swift in Sources */, 5820676426E771DB00655B05 /* TunnelManagerErrors.swift in Sources */, 585B4B8726D9098900555C4C /* TunnelStatusNotificationProvider.swift in Sources */, + 58E511E128DDB7F100B0BCDE /* WrappingError.swift in Sources */, 58FEAFB92750DA2F003C1625 /* AddressCache.swift in Sources */, 58B67B482602079E008EF58E /* RelaySelector.swift in Sources */, 58DF28A52417CB4B00E836B0 /* AppStorePaymentManager.swift in Sources */, @@ -1508,6 +1516,7 @@ 587B753F2668E5A700DEF7E9 /* NotificationContainerView.swift in Sources */, 58554F79280B037400013055 /* RESTAccessTokenManager.swift in Sources */, 75FD0C2328B109860021E33E /* ShortcutsDataSourceDelegate.swift in Sources */, + 58E511EB28DDE18400B0BCDE /* Error+Chain.swift in Sources */, 58421034282E4B1500F24E46 /* TunnelSettingsV2+REST.swift in Sources */, 58F2E144276A13F300A79513 /* StartTunnelOperation.swift in Sources */, 5868BD33261DCD2600E6027F /* CustomSplitViewController.swift in Sources */, @@ -1525,7 +1534,7 @@ 585DA87726B024A600B8C587 /* CachedRelays.swift in Sources */, 5896AE84246D5889005B36CB /* CustomDateComponentsFormatting.swift in Sources */, 587AD7C623421D7000E93A53 /* TunnelSettingsV1.swift in Sources */, - 581503A324D6F1EC00C9C50E /* ChainedError+Logger.swift in Sources */, + 581503A324D6F1EC00C9C50E /* Logger+Errors.swift in Sources */, 58E20771274672CA00DE5D77 /* LaunchViewController.swift in Sources */, 584D26C4270C855B004EA533 /* PreferencesDataSource.swift in Sources */, 58B5A899280AB0D7009FDE99 /* RESTAuthorization.swift in Sources */, @@ -1537,7 +1546,6 @@ 58C3A4B222456F1B00340BDB /* AccountInputGroupView.swift in Sources */, 58059DDE28468158002B1049 /* OutputOperation.swift in Sources */, 589D287B2846250500F9A7B3 /* AsyncOperationQueue.swift in Sources */, - 58F840B22464491D0044E708 /* ChainedError.swift in Sources */, 588BCF24280FE43D009ADCEC /* RESTDevicesProxy.swift in Sources */, 58ACF64B26553C3F00ACE4B7 /* SettingsSwitchCell.swift in Sources */, 587EB67027143B6500123C75 /* DataSourceSnapshot.swift in Sources */, @@ -1561,20 +1569,22 @@ 5806767C27048E9B00C858CB /* PacketTunnelProvider.swift in Sources */, 585DA89426B0323E00B8C587 /* TunnelProviderMessage.swift in Sources */, 587AD7C723421D8600E93A53 /* TunnelSettingsV1.swift in Sources */, + 58E511EC28DDE18400B0BCDE /* Error+Chain.swift in Sources */, 58AEEF662344A37400C9BBD5 /* KeychainError.swift in Sources */, 58CE38C828992C9200A6D6E5 /* TunnelMonitorDelegate.swift in Sources */, - 582AD44127BE6178002A6BFC /* CodingErrors+ChainedError.swift in Sources */, 5840250222B1124600E4CFEC /* IPAddress+Codable.swift in Sources */, 58FC040A27B3EE03001C21F0 /* TunnelMonitor.swift in Sources */, 5838318B27C40A3900000571 /* Pinger.swift in Sources */, 5820675C26E6576800655B05 /* RelayCache.swift in Sources */, 585DA89A26B0329200B8C587 /* PacketTunnelStatus.swift in Sources */, + 58E511E228DDB7FB00B0BCDE /* WrappingError.swift in Sources */, 585DA88526B0270700B8C587 /* ServerRelaysResponse.swift in Sources */, 581503A724D6F4AE00C9C50E /* Logging.swift in Sources */, 58E0729D28814AAE008902F8 /* PacketTunnelConfiguration.swift in Sources */, 58E0729F28814ACC008902F8 /* WireGuardLogLevel+Logging.swift in Sources */, 580F8B8428197884002E0998 /* TunnelSettingsV2.swift in Sources */, - 581503A424D6F1EC00C9C50E /* ChainedError+Logger.swift in Sources */, + 581503A424D6F1EC00C9C50E /* Logger+Errors.swift in Sources */, + 58E511E728DDDF1C00B0BCDE /* CustomErrorDescriptionProtocol.swift in Sources */, 5815039824D6ECAE00C9C50E /* CustomFormatLogHandler.swift in Sources */, 5840250522B11AB700E4CFEC /* MullvadEndpoint.swift in Sources */, 58906DE02445C7A5002F0673 /* NEProviderStopReason+Debug.swift in Sources */, @@ -1583,7 +1593,6 @@ 585DA87826B024A900B8C587 /* CachedRelays.swift in Sources */, 58E072A128814B0E008902F8 /* MullvadEndpoint+WgEndpoint.swift in Sources */, 584E96BD240FD4DA00D3334F /* Location.swift in Sources */, - 58F840B32464491D0044E708 /* ChainedError.swift in Sources */, 58D67A0A26D7AE3300557C3C /* OSLogHandler.swift in Sources */, 5820675626E6528A00655B05 /* RESTError.swift in Sources */, 58900D0328BBDCC70094E4F0 /* FixedWidthInteger+Arithmetics.swift in Sources */, @@ -1595,6 +1604,7 @@ 5877D70F282137E8002FCFC7 /* SettingsManager.swift in Sources */, 58CE38C728992C8700A6D6E5 /* WireGuardAdapterError+Localization.swift in Sources */, 5820675926E652BE00655B05 /* RESTCoding.swift in Sources */, + 58E511E828DDDF2400B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ios/MullvadVPN/AddressCache/AddressCacheStore.swift b/ios/MullvadVPN/AddressCache/AddressCacheStore.swift index 94ea5d5850..57e5a9bed8 100644 --- a/ios/MullvadVPN/AddressCache/AddressCacheStore.swift +++ b/ios/MullvadVPN/AddressCache/AddressCacheStore.swift @@ -121,7 +121,7 @@ extension AddressCache { try writeToDisk() } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to persist address cache after reading it from bundle." ) } @@ -170,7 +170,7 @@ extension AddressCache { try writeToDisk() } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to write address cache after selecting next endpoint." ) } @@ -209,7 +209,7 @@ extension AddressCache { try writeToDisk() } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to write address cache after setting new endpoints." ) } @@ -238,7 +238,7 @@ extension AddressCache { return readResult } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to read address cache from disk. Fallback to pre-bundled cache." ) @@ -253,7 +253,7 @@ extension AddressCache { return readResult } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to read address cache from bundle." ) diff --git a/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift b/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift index 69300772ac..00d118de75 100644 --- a/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift +++ b/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift @@ -143,7 +143,7 @@ extension AddressCache { case let .failure(error): logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to update address cache." ) diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift index 74670008a7..10d44fd99b 100644 --- a/ios/MullvadVPN/AppDelegate.swift +++ b/ios/MullvadVPN/AppDelegate.swift @@ -317,7 +317,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { try BGTaskScheduler.shared.submit(request) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Could not schedule app refresh task." ) } @@ -341,7 +341,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { try BGTaskScheduler.shared.submit(request) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Could not schedule private key rotation task." ) } @@ -363,7 +363,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { try BGTaskScheduler.shared.submit(request) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Could not schedule address cache update task." ) } diff --git a/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManagerError.swift b/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManagerError.swift index ad29ef3929..f88b6255d4 100644 --- a/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManagerError.swift +++ b/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManagerError.swift @@ -10,7 +10,7 @@ import Foundation extension AppStorePaymentManager { /// An error type emitted by `AppStorePaymentManager`. - enum Error: ChainedError { + enum Error: LocalizedError, WrappingError { /// Failure to find the account token associated with the transaction. case noAccountSet @@ -29,15 +29,30 @@ extension AppStorePaymentManager { var errorDescription: String? { switch self { case .noAccountSet: - return "Account is not set" + return "Account is not set." case .validateAccount: - return "Account validation error" + return "Account validation error." case .storePayment: - return "Store payment error" + return "Store payment error." case .readReceipt: - return "Read recept error" + return "Read recept error." case .sendReceipt: - return "Send receipt error" + return "Send receipt error." + } + } + + var underlyingError: Swift.Error? { + switch self { + case .noAccountSet: + return nil + case let .sendReceipt(error): + return error + case let .validateAccount(error): + return error + case let .readReceipt(error): + return error + case let .storePayment(error): + return error } } } diff --git a/ios/MullvadVPN/AppStorePaymentManager/SendAppStoreReceiptOperation.swift b/ios/MullvadVPN/AppStorePaymentManager/SendAppStoreReceiptOperation.swift index 32295d4350..b99c542c5a 100644 --- a/ios/MullvadVPN/AppStorePaymentManager/SendAppStoreReceiptOperation.swift +++ b/ios/MullvadVPN/AppStorePaymentManager/SendAppStoreReceiptOperation.swift @@ -60,7 +60,7 @@ class SendAppStoreReceiptOperation: ResultOperation< case let .failure(error): self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to fetch the AppStore receipt." ) self.finish(completion: .failure(.readReceipt(error))) @@ -87,7 +87,7 @@ class SendAppStoreReceiptOperation: ResultOperation< case let .failure(error): self.logger.error( - chainedError: error, + error: error, message: "Failed to send the AppStore receipt." ) self.finish(completion: .failure(.sendReceipt(error))) diff --git a/ios/MullvadVPN/ChainedError.swift b/ios/MullvadVPN/ChainedError.swift deleted file mode 100644 index 446ed99469..0000000000 --- a/ios/MullvadVPN/ChainedError.swift +++ /dev/null @@ -1,98 +0,0 @@ -// -// ErrorChain.swift -// MullvadVPN -// -// Created by pronebird on 07/05/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -/// A protocol describing errors that can be chained together. -protocol ChainedError: LocalizedError { - /// A source error when available. - var source: Error? { get } -} - -/// A protocol providing error a way to override error description when printing error chain. -protocol CustomChainedErrorDescriptionProtocol { - /// A custom error description that overrides `localizedDescription` when printing error chain. - var customErrorDescription: String? { get } -} - -extension ChainedError { - var source: Error? { - let reflection = Mirror(reflecting: self) - - if case .enum = reflection.displayStyle { - for child in reflection.children { - if let associatedError = child.value as? Error { - return associatedError - } - } - } - - return nil - } - - /// Create a string representation of the entire error chain. - /// An extra `message` is added at the start of the chain when given. - func displayChain(message: String? = nil) -> String { - var s: String - - let errorDescription = Self.getErrorDescription(self) - if let message = message { - s = "Error: \(message)\nCaused by: \(errorDescription)" - } else { - s = "Error: \(errorDescription)" - } - - for sourceError in makeChainIterator() { - s.append("\nCaused by: \(Self.getErrorDescription(sourceError))") - } - - return s - } - - private func makeChainIterator() -> AnyIterator<Error> { - var current: Error? = self - return AnyIterator { () -> Error? in - current = (current as? ChainedError)?.source - return current - } - } - - private static func getErrorDescription(_ error: Error) -> String { - let anError = error as? CustomChainedErrorDescriptionProtocol - - return anError?.customErrorDescription ?? error.localizedDescription - } -} - -extension CustomChainedErrorDescriptionProtocol { - var customErrorDescription: String? { - return nil - } -} - -/// A type-erasing container type for any `Error` that makes the wrapped error behave like -/// `ChainedError`. -final class AnyChainedError: ChainedError, CustomChainedErrorDescriptionProtocol { - private let wrappedError: Error - - init(_ error: Error) { - wrappedError = error - } - - var source: Error? { - return (wrappedError as? ChainedError)?.source - } - - var errorDescription: String? { - return wrappedError.localizedDescription - } - - var customErrorDescription: String? { - return (wrappedError as? CustomChainedErrorDescriptionProtocol)?.customErrorDescription - } -} diff --git a/ios/MullvadVPN/CodingErrors+ChainedError.swift b/ios/MullvadVPN/CodingErrors+CustomErrorDescription.swift index 1dfa73f923..25c65d8b82 100644 --- a/ios/MullvadVPN/CodingErrors+ChainedError.swift +++ b/ios/MullvadVPN/CodingErrors+CustomErrorDescription.swift @@ -1,5 +1,5 @@ // -// CodingErrors+ChainedError.swift +// CodingErrors+CustomErrorDescription.swift // MullvadVPN // // Created by pronebird on 17/02/2022. @@ -8,7 +8,7 @@ import Foundation -extension DecodingError: CustomChainedErrorDescriptionProtocol { +extension DecodingError: CustomErrorDescriptionProtocol { var customErrorDescription: String? { switch self { case let .typeMismatch(type, context): @@ -29,7 +29,7 @@ extension DecodingError: CustomChainedErrorDescriptionProtocol { } } -extension EncodingError: CustomChainedErrorDescriptionProtocol { +extension EncodingError: CustomErrorDescriptionProtocol { var customErrorDescription: String? { switch self { case let .invalidValue(_, context): diff --git a/ios/MullvadVPN/ConnectViewController.swift b/ios/MullvadVPN/ConnectViewController.swift index 49a7bdf1bf..e3da0fe159 100644 --- a/ios/MullvadVPN/ConnectViewController.swift +++ b/ios/MullvadVPN/ConnectViewController.swift @@ -536,7 +536,7 @@ class ConnectViewController: UIViewController, MKMapViewDelegate, RootContainmen contentView.mapView.addOverlays(overlays, level: .aboveLabels) } catch { - logger.error(chainedError: AnyChainedError(error), message: "Failed to load geojson.") + logger.error(error: error, message: "Failed to load geojson.") } } } diff --git a/ios/MullvadVPN/CustomErrorDescriptionProtocol.swift b/ios/MullvadVPN/CustomErrorDescriptionProtocol.swift new file mode 100644 index 0000000000..448d848686 --- /dev/null +++ b/ios/MullvadVPN/CustomErrorDescriptionProtocol.swift @@ -0,0 +1,15 @@ +// +// CustomErrorDescription.swift +// MullvadVPN +// +// Created by pronebird on 23/09/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +/// A protocol providing error a way to override error description when printing error chain. +protocol CustomErrorDescriptionProtocol { + /// A custom error description that overrides `localizedDescription` when printing error chain. + var customErrorDescription: String? { get } +} diff --git a/ios/MullvadVPN/DeviceManagementViewController.swift b/ios/MullvadVPN/DeviceManagementViewController.swift index 128e1c6ab4..383b7ca822 100644 --- a/ios/MullvadVPN/DeviceManagementViewController.swift +++ b/ios/MullvadVPN/DeviceManagementViewController.swift @@ -248,7 +248,7 @@ class DeviceManagementViewController: UIViewController, RootContainment { case let .failure(error): self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to delete device." ) completionHandler(error) diff --git a/ios/MullvadVPN/Error+Chain.swift b/ios/MullvadVPN/Error+Chain.swift new file mode 100644 index 0000000000..8ddd0df219 --- /dev/null +++ b/ios/MullvadVPN/Error+Chain.swift @@ -0,0 +1,44 @@ +// +// Error+Chain.swift +// MullvadVPN +// +// Created by pronebird on 23/09/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +extension Error { + /// Returns a flat list of errors by unrolling the underlying error chain. + var underlyingErrorChain: [Error] { + var errors: [Error] = [] + var currentError: Error? = self as Error + + while let underlyingError = currentError?.getUnderlyingError() { + currentError = underlyingError + errors.append(underlyingError) + } + + return errors + } + + func logFormatError() -> String { + let nsError = self as NSError + var message = "" + + let description = (self as? CustomErrorDescriptionProtocol)? + .customErrorDescription ?? localizedDescription + + message += "\(description) (domain = \(nsError.domain), code = \(nsError.code))" + + return message + } + + private func getUnderlyingError() -> Error? { + if let wrappingError = self as? WrappingError { + return wrappingError.underlyingError + } else { + return (self as NSError).userInfo[NSUnderlyingErrorKey] as? Error + } + } +} diff --git a/ios/MullvadVPN/Logging/LogRotation.swift b/ios/MullvadVPN/Logging/LogRotation.swift index ff7671ae80..4775315b77 100644 --- a/ios/MullvadVPN/Logging/LogRotation.swift +++ b/ios/MullvadVPN/Logging/LogRotation.swift @@ -9,7 +9,7 @@ import Foundation enum LogRotation { - enum Error: ChainedError { + enum Error: LocalizedError, WrappingError { case noSourceLogFile case moveSourceLogFile(Swift.Error) @@ -21,6 +21,15 @@ enum LogRotation { return "Failure to move the source log file to backup." } } + + var underlyingError: Swift.Error? { + switch self { + case .noSourceLogFile: + return nil + case let .moveSourceLogFile(error): + return error + } + } } static func rotateLog(logsDirectory: URL, logFileName: String) throws { diff --git a/ios/MullvadVPN/Logging/ChainedError+Logger.swift b/ios/MullvadVPN/Logging/Logger+Errors.swift index 0aede67701..0b2811a68e 100644 --- a/ios/MullvadVPN/Logging/ChainedError+Logger.swift +++ b/ios/MullvadVPN/Logging/Logger+Errors.swift @@ -1,5 +1,5 @@ // -// ChainedError+Logger.swift +// Logger+Errors.swift // MullvadVPN // // Created by pronebird on 02/08/2020. @@ -10,8 +10,8 @@ import Foundation import Logging extension Logger { - func error<T: ChainedError>( - chainedError: T, + func error<T: Error>( + error: T, message: @autoclosure () -> String? = nil, metadata: @autoclosure () -> Logger.Metadata? = nil, source: @autoclosure () -> String? = nil, @@ -19,11 +19,25 @@ extension Logger { function: String = #function, line: UInt = #line ) { + var lines = [String]() + var errors = [Error]() + + if let prefixMessage = message() { + lines.append(prefixMessage) + errors.append(error) + } else { + lines.append(error.logFormatError()) + } + + errors.append(contentsOf: error.underlyingErrorChain) + + for error in errors { + lines.append("Caused by: \(error.logFormatError())") + } + log( level: .error, - Message( - stringLiteral: chainedError.displayChain(message: message()) - ), + Message(stringLiteral: lines.joined(separator: "\n")), metadata: metadata(), source: source(), file: file, diff --git a/ios/MullvadVPN/Logging/Logging.swift b/ios/MullvadVPN/Logging/Logging.swift index a0c535853e..1e65249ec8 100644 --- a/ios/MullvadVPN/Logging/Logging.swift +++ b/ios/MullvadVPN/Logging/Logging.swift @@ -70,7 +70,7 @@ func initLoggingSystem(bundleIdentifier: String, metadata: Logger.Metadata? = ni if let logRotationError = logRotationError { Logger(label: "LogRotation").error( - chainedError: AnyChainedError(logRotationError), + error: logRotationError, message: "Failed to rotate log" ) } diff --git a/ios/MullvadVPN/LoginViewController.swift b/ios/MullvadVPN/LoginViewController.swift index 6e363a6b25..b0587e9543 100644 --- a/ios/MullvadVPN/LoginViewController.swift +++ b/ios/MullvadVPN/LoginViewController.swift @@ -236,7 +236,7 @@ class LoginViewController: UIViewController, RootContainment { contentView.accountInputGroup.setLastUsedAccount(accountNumber, animated: false) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to update last used account." ) } @@ -423,7 +423,7 @@ extension LoginViewController: AccountInputGroupViewDelegate { return true } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to remove last used account." ) return false diff --git a/ios/MullvadVPN/NotificationManager.swift b/ios/MullvadVPN/NotificationManager.swift index 63468e70a3..5838b41d5b 100644 --- a/ios/MullvadVPN/NotificationManager.swift +++ b/ios/MullvadVPN/NotificationManager.swift @@ -145,7 +145,7 @@ class NotificationManager: NotificationProviderDelegate { notificationCenter.add(newRequest) { error in if let error = error { self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to add notification request with identifier \(newRequest.identifier)." ) } @@ -174,7 +174,7 @@ class NotificationManager: NotificationProviderDelegate { .requestAuthorization(options: authorizationOptions) { granted, error in if let error = error { self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to obtain user notifications authorization" ) } diff --git a/ios/MullvadVPN/Notifications/TunnelStatusNotificationProvider.swift b/ios/MullvadVPN/Notifications/TunnelStatusNotificationProvider.swift index d19335972d..59642ccc0c 100644 --- a/ios/MullvadVPN/Notifications/TunnelStatusNotificationProvider.swift +++ b/ios/MullvadVPN/Notifications/TunnelStatusNotificationProvider.swift @@ -124,7 +124,7 @@ class TunnelStatusNotificationProvider: NotificationProvider, InAppNotificationP value: "Failed to start the tunnel: %@.", comment: "" ), - startError.underlyingError.localizedDescription + startError.underlyingError?.localizedDescription ?? "" ) } else if let stopError = error as? StopTunnelError { body = String( @@ -133,7 +133,7 @@ class TunnelStatusNotificationProvider: NotificationProvider, InAppNotificationP value: "Failed to stop the tunnel: %@.", comment: "" ), - stopError.underlyingError.localizedDescription + stopError.underlyingError?.localizedDescription ?? "" ) } else { body = error.localizedDescription diff --git a/ios/MullvadVPN/REST/RESTAccessTokenManager.swift b/ios/MullvadVPN/REST/RESTAccessTokenManager.swift index 7d46b16edd..79e5096fb5 100644 --- a/ios/MullvadVPN/REST/RESTAccessTokenManager.swift +++ b/ios/MullvadVPN/REST/RESTAccessTokenManager.swift @@ -49,7 +49,7 @@ extension REST { case let .failure(error): self.logger.error( - chainedError: error, + error: error, message: "Failed to fetch access token." ) diff --git a/ios/MullvadVPN/REST/RESTError.swift b/ios/MullvadVPN/REST/RESTError.swift index 25e51bd1b9..63a6167d39 100644 --- a/ios/MullvadVPN/REST/RESTError.swift +++ b/ios/MullvadVPN/REST/RESTError.swift @@ -10,7 +10,7 @@ import Foundation extension REST { /// An error type returned by REST API classes. - enum Error: ChainedError { + enum Error: LocalizedError, WrappingError { /// A failure to create URL request. case createURLRequest(Swift.Error) @@ -25,10 +25,10 @@ extension REST { var errorDescription: String? { switch self { - case .createURLRequest: - return "Failure to create URL request." - case .network: - return "Network error." + case let .createURLRequest(error): + return "Failure to create URL request: \(error.localizedDescription)." + case let .network(error): + return "Network error: \(error.localizedDescription)." case let .unhandledResponse(statusCode, serverResponse): var str = "Failure to handle server response: HTTP/\(statusCode)." @@ -41,8 +41,21 @@ extension REST { } return str - case .decodeResponse: - return "Failure to decode URL response data." + case let .decodeResponse(error): + return "Failure to decode URL response data: \(error.localizedDescription)." + } + } + + var underlyingError: Swift.Error? { + switch self { + case let .network(error): + return error + case let .createURLRequest(error): + return error + case let .decodeResponse(error): + return error + case .unhandledResponse: + return nil } } diff --git a/ios/MullvadVPN/REST/RESTNetworkOperation.swift b/ios/MullvadVPN/REST/RESTNetworkOperation.swift index 02b1f5bff2..f1ffe472da 100644 --- a/ios/MullvadVPN/REST/RESTNetworkOperation.swift +++ b/ios/MullvadVPN/REST/RESTNetworkOperation.swift @@ -125,7 +125,7 @@ extension REST { dispatchPrecondition(condition: .onQueue(dispatchQueue)) logger.error( - chainedError: error, + error: error, message: "Failed to request authorization." ) @@ -165,7 +165,7 @@ extension REST { dispatchPrecondition(condition: .onQueue(dispatchQueue)) logger.error( - chainedError: error, + error: error, message: "Failed to create URLRequest." ) @@ -188,7 +188,7 @@ extension REST { } logger.error( - chainedError: AnyChainedError(urlError), + error: urlError, message: "Failed to perform request to \(endpoint)." ) diff --git a/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift b/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift index ec56e2b5bb..9698322559 100644 --- a/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift +++ b/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift @@ -104,7 +104,7 @@ extension RelayCache { ) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to read the relay cache during initialization." ) @@ -241,7 +241,7 @@ extension RelayCache { if let error = mappedCompletion.error { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to update relays." ) } diff --git a/ios/MullvadVPN/SettingsManager/SettingsManager.swift b/ios/MullvadVPN/SettingsManager/SettingsManager.swift index 95af7b2a99..cd40ef67d1 100644 --- a/ios/MullvadVPN/SettingsManager/SettingsManager.swift +++ b/ios/MullvadVPN/SettingsManager/SettingsManager.swift @@ -224,7 +224,7 @@ extension SettingsManager { ) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to decode legacy settings." ) return nil @@ -248,7 +248,7 @@ extension SettingsManager { if error != .itemNotFound { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to list legacy settings." ) } @@ -280,7 +280,7 @@ extension SettingsManager { let error = KeychainError(code: status) logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to remove legacy settings entry \(index)." ) } diff --git a/ios/MullvadVPN/ShortcutsManager.swift b/ios/MullvadVPN/ShortcutsManager.swift index 4a6309429c..1baa525401 100644 --- a/ios/MullvadVPN/ShortcutsManager.swift +++ b/ios/MullvadVPN/ShortcutsManager.swift @@ -38,7 +38,7 @@ final class ShortcutsManager { guard let self = self else { return } if let error = error { self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to fetch voice shortcuts." ) return diff --git a/ios/MullvadVPN/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProviderHost.swift index 31d28ad84c..c30dda0e39 100644 --- a/ios/MullvadVPN/SimulatorTunnelProviderHost.swift +++ b/ios/MullvadVPN/SimulatorTunnelProviderHost.swift @@ -31,7 +31,7 @@ class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { selectorResult = try tunnelOptions.getSelectorResult() } catch { self.providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: """ Failed to decode relay selector result passed from the app. \ Will continue by picking new relay. @@ -45,7 +45,7 @@ class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { completionHandler(nil) } catch { self.providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to pick relay." ) completionHandler(error) @@ -72,7 +72,7 @@ class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { completionHandler?(response) } catch { self.providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to handle app message." ) diff --git a/ios/MullvadVPN/TunnelManager/LoadTunnelConfigurationOperation.swift b/ios/MullvadVPN/TunnelManager/LoadTunnelConfigurationOperation.swift index e98aaff5fd..70a3d95d25 100644 --- a/ios/MullvadVPN/TunnelManager/LoadTunnelConfigurationOperation.swift +++ b/ios/MullvadVPN/TunnelManager/LoadTunnelConfigurationOperation.swift @@ -51,7 +51,7 @@ class LoadTunnelConfigurationOperation: ResultOperation<Void, Error> { tunnel.removeFromPreferences { error in if let error = error { self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to remove VPN configuration." ) } @@ -78,14 +78,14 @@ class LoadTunnelConfigurationOperation: ResultOperation<Void, Error> { return .success(nil) } else if let error = error as? DecodingError { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Cannot decode settings. Will attempt to delete them from keychain." ) return Result { try SettingsManager.deleteSettings() } .mapError { error in logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to delete settings from keychain." ) @@ -109,14 +109,14 @@ class LoadTunnelConfigurationOperation: ResultOperation<Void, Error> { return .success(nil) } else if let error = error as? DecodingError { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Cannot decode device state. Will attempt to delete it from keychain." ) return Result { try SettingsManager.deleteDeviceState() } .mapError { error in logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to delete device state from keychain." ) diff --git a/ios/MullvadVPN/TunnelManager/MigrateSettingsOperation.swift b/ios/MullvadVPN/TunnelManager/MigrateSettingsOperation.swift index 17fc69cff1..adf3735f14 100644 --- a/ios/MullvadVPN/TunnelManager/MigrateSettingsOperation.swift +++ b/ios/MullvadVPN/TunnelManager/MigrateSettingsOperation.swift @@ -55,7 +55,7 @@ class MigrateSettingsOperation: AsyncOperation { try SettingsManager.setLastUsedAccount(storedAccountNumber) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to store last used account." ) } @@ -73,7 +73,7 @@ class MigrateSettingsOperation: AsyncOperation { return } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to read legacy settings from keychain." ) finishMigration() @@ -147,7 +147,7 @@ class MigrateSettingsOperation: AsyncOperation { self.accountData = accountData case let .failure(error): - logger.error(chainedError: error, message: "Failed to fetch accound data.") + logger.error(error: error, message: "Failed to fetch accound data.") case .cancelled: logger.debug("Account data request was cancelled.") @@ -163,7 +163,7 @@ class MigrateSettingsOperation: AsyncOperation { self.devices = devices case let .failure(error): - logger.error(chainedError: error, message: "Failed to fetch devices.") + logger.error(error: error, message: "Failed to fetch devices.") case .cancelled: logger.debug("Device request was cancelled.") @@ -235,7 +235,7 @@ class MigrateSettingsOperation: AsyncOperation { try SettingsManager.writeDeviceState(newDeviceState) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to write migrated settings." ) } diff --git a/ios/MullvadVPN/TunnelManager/RotateKeyOperation.swift b/ios/MullvadVPN/TunnelManager/RotateKeyOperation.swift index 5cdf10a872..0029373af7 100644 --- a/ios/MullvadVPN/TunnelManager/RotateKeyOperation.swift +++ b/ios/MullvadVPN/TunnelManager/RotateKeyOperation.swift @@ -107,7 +107,7 @@ class RotateKeyOperation: ResultOperation<Bool, Error> { case let .failure(error): logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to rotate device key." ) finish(completion: .failure(error)) diff --git a/ios/MullvadVPN/TunnelManager/SendTunnelProviderMessageOperation.swift b/ios/MullvadVPN/TunnelManager/SendTunnelProviderMessageOperation.swift index 2652433cee..9fb72e03d9 100644 --- a/ios/MullvadVPN/TunnelManager/SendTunnelProviderMessageOperation.swift +++ b/ios/MullvadVPN/TunnelManager/SendTunnelProviderMessageOperation.swift @@ -235,7 +235,7 @@ extension SendTunnelProviderMessageOperation where Output == Void { } } -enum SendTunnelProviderMessageError: ChainedError { +enum SendTunnelProviderMessageError: LocalizedError, WrappingError { /// Tunnel process is either down or about to go down. case tunnelDown(NEVPNStatus) @@ -251,8 +251,17 @@ enum SendTunnelProviderMessageError: ChainedError { return "Tunnel is either down or about to go down (status: \(status))." case .timeout: return "Send timeout." - case .system: - return "System error." + case let .system(error): + return "System error: \(error.localizedDescription)" + } + } + + var underlyingError: Error? { + switch self { + case let .system(error): + return error + case .timeout, .tunnelDown: + return nil } } } diff --git a/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift b/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift index 812869caaa..5ceb8cdfda 100644 --- a/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift +++ b/ios/MullvadVPN/TunnelManager/SetAccountOperation.swift @@ -204,7 +204,7 @@ class SetAccountOperation: ResultOperation<StoredAccountData?, Error> { let task = self.accountsProxy.createAccount(retryStrategy: .default) { completion in let mappedCompletion = completion.mapError { error -> Error in self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to create new account." ) return error @@ -243,7 +243,7 @@ class SetAccountOperation: ResultOperation<StoredAccountData?, Error> { ) { completion in let mappedCompletion = completion.mapError { error -> Error in self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to receive account data." ) return error @@ -286,7 +286,7 @@ class SetAccountOperation: ResultOperation<StoredAccountData?, Error> { let mappedCompletion = completion .mapError { error -> Error in self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to delete device." ) return error @@ -333,7 +333,7 @@ class SetAccountOperation: ResultOperation<StoredAccountData?, Error> { // Ignore error but log it. if let error = error { self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to remove VPN configuration." ) } @@ -362,7 +362,7 @@ class SetAccountOperation: ResultOperation<StoredAccountData?, Error> { try SettingsManager.setLastUsedAccount(storedAccountData.number) } catch { self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to store last used account number." ) } @@ -386,7 +386,7 @@ class SetAccountOperation: ResultOperation<StoredAccountData?, Error> { return (privateKey, device) } .mapError { error -> Error in - self.logger.error(chainedError: error, message: "Failed to create device.") + self.logger.error(error: error, message: "Failed to create device.") return error } diff --git a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift index f11164961e..f1eeee4a21 100644 --- a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift +++ b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift @@ -97,7 +97,7 @@ class StartTunnelOperation: ResultOperation<Void, Error> { try tunnelOptions.setSelectorResult(selectorResult) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to encode the selector result." ) } diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift index 1fa465b67b..b107491712 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift @@ -212,7 +212,7 @@ final class TunnelManager { if case let .failure(error) = completion { self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to load configuration." ) } @@ -261,7 +261,7 @@ final class TunnelManager { DispatchQueue.main.async { if let error = completion.error { self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to start the tunnel." ) @@ -293,7 +293,7 @@ final class TunnelManager { DispatchQueue.main.async { if let error = completion.error { self.logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to stop the tunnel." ) @@ -651,7 +651,7 @@ final class TunnelManager { try SettingsManager.writeSettings(settings) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to write settings." ) } @@ -679,7 +679,7 @@ final class TunnelManager { try SettingsManager.writeDeviceState(deviceState) } catch { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to write device state." ) } @@ -730,7 +730,7 @@ final class TunnelManager { if let error = completion.error { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to reconnect the tunnel." ) } diff --git a/ios/MullvadVPN/TunnelManager/TunnelManagerErrors.swift b/ios/MullvadVPN/TunnelManager/TunnelManagerErrors.swift index 8c25b173df..35b804a711 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManagerErrors.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManagerErrors.swift @@ -31,7 +31,9 @@ struct InvalidDeviceStateError: LocalizedError { } } -struct StartTunnelError: LocalizedError { +struct StartTunnelError: LocalizedError, WrappingError { + private let _underlyingError: Error + var errorDescription: String? { return NSLocalizedString( "START_TUNNEL_ERROR", @@ -41,13 +43,18 @@ struct StartTunnelError: LocalizedError { ) } - let underlyingError: Error + var underlyingError: Error? { + return _underlyingError + } + init(underlyingError: Error) { - self.underlyingError = underlyingError + _underlyingError = underlyingError } } -struct StopTunnelError: LocalizedError { +struct StopTunnelError: LocalizedError, WrappingError { + private let _underlyingError: Error + var errorDescription: String? { return NSLocalizedString( "STOP_TUNNEL_ERROR", @@ -57,8 +64,11 @@ struct StopTunnelError: LocalizedError { ) } - let underlyingError: Error + var underlyingError: Error? { + return _underlyingError + } + init(underlyingError: Error) { - self.underlyingError = underlyingError + _underlyingError = underlyingError } } diff --git a/ios/MullvadVPN/TunnelManager/UpdateAccountDataOperation.swift b/ios/MullvadVPN/TunnelManager/UpdateAccountDataOperation.swift index d0f62c68e4..b95d629ea5 100644 --- a/ios/MullvadVPN/TunnelManager/UpdateAccountDataOperation.swift +++ b/ios/MullvadVPN/TunnelManager/UpdateAccountDataOperation.swift @@ -52,7 +52,7 @@ class UpdateAccountDataOperation: ResultOperation<Void, Error> { ) { let mappedCompletion = completion.mapError { error -> Error in self.logger.error( - chainedError: error, + error: error, message: "Failed to fetch account expiry." ) return error diff --git a/ios/MullvadVPN/WrappingError.swift b/ios/MullvadVPN/WrappingError.swift new file mode 100644 index 0000000000..ff217d0dae --- /dev/null +++ b/ios/MullvadVPN/WrappingError.swift @@ -0,0 +1,14 @@ +// +// WrappingError.swift +// MullvadVPN +// +// Created by pronebird on 23/09/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +/// Protocol describing errors that may contain underlying errors. +protocol WrappingError: Error { + var underlyingError: Error? { get } +} diff --git a/ios/PacketTunnel/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider.swift index 3eefd5ec7a..0386279ac7 100644 --- a/ios/PacketTunnel/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider.swift @@ -112,7 +112,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { } catch { providerLogger.debug("Start the tunnel via app.") providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: """ Failed to decode relay selector result passed from the app. \ Will continue by picking new relay. @@ -128,7 +128,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { tunnelConfiguration = try makeConfiguration(initialRelay) } catch { providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to start the tunnel." ) @@ -148,7 +148,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { self.dispatchQueue.async { if let error = error { self.providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to start the tunnel." ) @@ -186,7 +186,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { self.dispatchQueue.async { if let error = error { self.providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to stop the tunnel gracefully." ) } else { @@ -204,7 +204,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { message = try TunnelProviderMessage(messageData: messageData) } catch { self.providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to decode the app message." ) @@ -231,7 +231,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { response = try TunnelProviderReply(self.packetTunnelStatus).encode() } catch { self.providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to encode tunnel status reply." ) } @@ -335,7 +335,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { tunnelConfiguration = try makeConfiguration(nextRelay) } catch { providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed produce new configuration." ) completionHandler?() @@ -358,7 +358,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { if let error = error { self.providerLogger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to update WireGuard configuration." ) diff --git a/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift b/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift index f132817fd0..f9082fa161 100644 --- a/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift +++ b/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift @@ -288,7 +288,7 @@ final class TunnelMonitor: PingerDelegate { func pinger(_ pinger: Pinger, didFailWithError error: Error) { logger.error( - chainedError: AnyChainedError(error), + error: error, message: "Failed to parse ICMP response." ) } @@ -436,7 +436,7 @@ final class TunnelMonitor: PingerDelegate { logger.debug("Send ping icmp_seq=\(sendResult.sequenceNumber).") } catch { - logger.error(chainedError: AnyChainedError(error), message: "Failed to send ping.") + logger.error(error: error, message: "Failed to send ping.") } } @@ -500,7 +500,7 @@ final class TunnelMonitor: PingerDelegate { try pinger.openSocket(bindTo: interfaceName) } catch { - logger.error(chainedError: AnyChainedError(error), message: "Failed to open socket.") + logger.error(error: error, message: "Failed to open socket.") return } |
