diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 68632bf6e3..cc17b146e8 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13538,7 +13538,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 109.0.2; + version = 110.0.0; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index dbe440a602..eacf6dee47 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "da5f8ae73e7ad7fc47931f82f5ac6c4fafa6ac94", - "version" : "109.0.2" + "revision" : "d56b90bd229288f681f0a3a6a325ef25e3ce5f3c", + "version" : "110.0.0" } }, { diff --git a/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift b/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift index 86765ea05e..2a15c5f818 100644 --- a/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift +++ b/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift @@ -274,6 +274,15 @@ extension PrivacyDashboardViewController { let configuration = ContentBlocking.shared.privacyConfigurationManager.privacyConfig let protectionsState = configuration.isFeature(.contentBlocking, enabledForDomain: currentTab.content.url?.host) + var errors: [Error]? + var statusCodes: [Int]? + if let error = tabViewModel?.tab.lastWebError { + errors = [error] + } + if let httpStatusCode = tabViewModel?.tab.lastHttpStatusCode { + statusCodes = [httpStatusCode] + } + let websiteBreakage = WebsiteBreakage(siteUrl: currentURL, category: category.lowercased(), description: description, @@ -288,8 +297,8 @@ extension PrivacyDashboardViewController { urlParametersRemoved: urlParametersRemoved, protectionsState: protectionsState, reportFlow: source, - error: nil, - httpStatusCode: nil) + errors: errors, + httpStatusCodes: statusCodes) return websiteBreakage } } diff --git a/DuckDuckGo/Tab/Model/Tab.swift b/DuckDuckGo/Tab/Model/Tab.swift index b174ace747..6c7605161c 100644 --- a/DuckDuckGo/Tab/Model/Tab.swift +++ b/DuckDuckGo/Tab/Model/Tab.swift @@ -702,6 +702,9 @@ protocol NewWindowPolicyDecisionMaker { } let permissions: PermissionModel + @Published private(set) var lastWebError: Error? + @Published private(set) var lastHttpStatusCode: Int? + @Published private(set) var isLoading: Bool = false @Published private(set) var loadingProgress: Double = 0.0 @@ -1281,6 +1284,7 @@ extension Tab/*: NavigationResponder*/ { // to be moved to Tab+Navigation.swift @MainActor func willStart(_ navigation: Navigation) { if error != nil { error = nil } + if lastWebError != nil { lastWebError = nil } delegate?.tabWillStartNavigation(self, isUserInitiated: navigation.navigationAction.isUserInitiated) } @@ -1290,6 +1294,8 @@ extension Tab/*: NavigationResponder*/ { // to be moved to Tab+Navigation.swift internalUserDecider?.markUserAsInternalIfNeeded(forUrl: webView.url, response: navigationResponse.response as? HTTPURLResponse) + lastHttpStatusCode = navigationResponse.httpStatusCode + return .next } @@ -1300,6 +1306,7 @@ extension Tab/*: NavigationResponder*/ { // to be moved to Tab+Navigation.swift userInteractionDialog = nil // Unnecessary assignment triggers publishing + if lastWebError != nil { lastWebError = nil } if error != nil, navigation.navigationAction.navigationType != .alternateHtmlLoad { // error page navigation error = nil @@ -1339,6 +1346,11 @@ extension Tab/*: NavigationResponder*/ { // to be moved to Tab+Navigation.swift } } + @MainActor + func didFailProvisionalLoad(with request: URLRequest, in frame: WKFrameInfo, with error: Error) { + lastWebError = error + } + @MainActor func webContentProcessDidTerminate(with reason: WKProcessTerminationReason?) { let error = WKError(.webContentProcessTerminated, userInfo: [ diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index e8853bdc23..eb8aa9d0c8 100644 --- a/LocalPackages/DataBrokerProtection/Package.swift +++ b/LocalPackages/DataBrokerProtection/Package.swift @@ -29,7 +29,7 @@ let package = Package( targets: ["DataBrokerProtection"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "109.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "110.0.0"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper") diff --git a/LocalPackages/LoginItems/Package.swift b/LocalPackages/LoginItems/Package.swift index b7b7bb72d9..298688d204 100644 --- a/LocalPackages/LoginItems/Package.swift +++ b/LocalPackages/LoginItems/Package.swift @@ -13,7 +13,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "109.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "110.0.0"), ], targets: [ .target( diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index f1e2140732..5d017910e3 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -31,7 +31,7 @@ let package = Package( .library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "109.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "110.0.0"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems") diff --git a/LocalPackages/PixelKit/Package.swift b/LocalPackages/PixelKit/Package.swift index 0cc6651ae2..dfb0e4deed 100644 --- a/LocalPackages/PixelKit/Package.swift +++ b/LocalPackages/PixelKit/Package.swift @@ -20,7 +20,7 @@ let package = Package( ) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "109.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "110.0.0"), ], targets: [ .target( diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index b7af9e0bbb..ac79aa79e0 100644 --- a/LocalPackages/SubscriptionUI/Package.swift +++ b/LocalPackages/SubscriptionUI/Package.swift @@ -12,7 +12,7 @@ let package = Package( targets: ["SubscriptionUI"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "109.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "110.0.0"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/LocalPackages/SwiftUIExtensions/Package.swift b/LocalPackages/SwiftUIExtensions/Package.swift index 249d2a6cbb..0eb22b5831 100644 --- a/LocalPackages/SwiftUIExtensions/Package.swift +++ b/LocalPackages/SwiftUIExtensions/Package.swift @@ -11,7 +11,7 @@ let package = Package( .library(name: "PreferencesViews", targets: ["PreferencesViews"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "109.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "110.0.0"), ], targets: [ .target( diff --git a/LocalPackages/SyncUI/Package.swift b/LocalPackages/SyncUI/Package.swift index 8928521a9e..da7db34f24 100644 --- a/LocalPackages/SyncUI/Package.swift +++ b/LocalPackages/SyncUI/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(path: "../SwiftUIExtensions"), - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "109.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "110.0.0"), ], targets: [ .target( diff --git a/LocalPackages/SystemExtensionManager/Package.swift b/LocalPackages/SystemExtensionManager/Package.swift index 0ae14903d5..717e820512 100644 --- a/LocalPackages/SystemExtensionManager/Package.swift +++ b/LocalPackages/SystemExtensionManager/Package.swift @@ -16,7 +16,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "109.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "110.0.0"), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/LocalPackages/XPCHelper/Package.swift b/LocalPackages/XPCHelper/Package.swift index 323f247b91..ef2510badf 100644 --- a/LocalPackages/XPCHelper/Package.swift +++ b/LocalPackages/XPCHelper/Package.swift @@ -30,7 +30,7 @@ let package = Package( .library(name: "XPCHelper", targets: ["XPCHelper"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "109.0.2"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "110.0.0"), ], targets: [ .target( diff --git a/Submodules/privacy-reference-tests b/Submodules/privacy-reference-tests index 438faf5160..40ce86837d 160000 --- a/Submodules/privacy-reference-tests +++ b/Submodules/privacy-reference-tests @@ -1 +1 @@ -Subproject commit 438faf5160f7db0fd2f2952945a809a33a9cdbac +Subproject commit 40ce86837def0adbf558f00ed0531ab4df5839a8 diff --git a/UnitTests/PrivacyReferenceTests/BrokenSiteReportingReferenceTests.swift b/UnitTests/PrivacyReferenceTests/BrokenSiteReportingReferenceTests.swift index 826682a1aa..73e7cba06c 100644 --- a/UnitTests/PrivacyReferenceTests/BrokenSiteReportingReferenceTests.swift +++ b/UnitTests/PrivacyReferenceTests/BrokenSiteReportingReferenceTests.swift @@ -27,6 +27,22 @@ import PrivacyDashboard final class BrokenSiteReportingReferenceTests: XCTestCase { private let testHelper = PrivacyReferenceTestHelper() + struct MockError: LocalizedError { + let description: String + + init(_ description: String) { + self.description = description + } + + var errorDescription: String? { + description + } + + var localizedDescription: String? { + description + } + } + private enum Resource { static let tests = "privacy-reference-tests/broken-site-reporting/tests.json" } @@ -53,9 +69,14 @@ final class BrokenSiteReportingReferenceTests: XCTestCase { os_log("Testing [%s]", type: .info, test.name) + var errors: [Error]? + if let errs = test.errorDescriptions { + errors = errs.map { MockError($0) } + } + let breakage = WebsiteBreakage(siteUrl: test.siteURL, - category: "test", - description: "description", + category: test.category, + description: test.providedDescription, osVersion: test.os ?? "", manufacturer: "Apple", upgradedHttps: test.wasUpgraded, @@ -67,8 +88,8 @@ final class BrokenSiteReportingReferenceTests: XCTestCase { urlParametersRemoved: false, protectionsState: test.protectionsEnabled, reportFlow: .appMenu, - error: nil, - httpStatusCode: nil) + errors: errors, + httpStatusCodes: test.httpErrorCodes ?? []) let request = makeURLRequest(with: breakage.requestParameters) @@ -94,7 +115,23 @@ final class BrokenSiteReportingReferenceTests: XCTestCase { let match = regex.matches(in: absoluteURL, range: NSRange(location: 0, length: absoluteURL.count)) - XCTAssertEqual(match.count, 1, "Param [\(param.name)] with value [\(param.value)] not found in [\(absoluteURL)]") + if param.name == "errorDescriptions" { + // `localizedDescription` adds class information to the error. The value is not standardized across platforms + // so we'll just check the result is an array of strings + guard let params = URLComponents(string: absoluteURL)?.queryItems else { + XCTFail("Unable to parse query parameters from \(absoluteURL)") + return + } + var errorsFound = false + for queryItem in params { + if queryItem.name != param.name { continue } + errorsFound = true + XCTAssert((queryItem.value?.split(separator: ",").count ?? 0) > 1, "Error descriptions should return an array of strings. Parsed: \(queryItem.value ?? "")") + } + XCTAssert(errorsFound, "Param [\(param.name)] with value [\(param.value)] not found in [\(absoluteURL)]") + } else { + XCTAssertEqual(match.count, 1, "Param [\(param.name)] with value [\(param.value)] not found in [\(absoluteURL)]") + } } } } @@ -121,6 +158,7 @@ private struct Test: Codable { let siteURL: URL let wasUpgraded: Bool let category: String + let providedDescription: String? let blockedTrackers, surrogates: [String] let atb, blocklistVersion: String let expectReportURLPrefix: String @@ -129,6 +167,8 @@ private struct Test: Codable { let manufacturer, model, os: String? let gpcEnabled: Bool? let protectionsEnabled: Bool + let errorDescriptions: [String]? + let httpErrorCodes: [Int]? } // MARK: - ExpectReportURLParam diff --git a/UnitTests/WebsiteBreakageReport/WebsiteBreakageReportTests.swift b/UnitTests/WebsiteBreakageReport/WebsiteBreakageReportTests.swift index 33132f8c3b..c0c006e124 100644 --- a/UnitTests/WebsiteBreakageReport/WebsiteBreakageReportTests.swift +++ b/UnitTests/WebsiteBreakageReport/WebsiteBreakageReportTests.swift @@ -44,8 +44,8 @@ class WebsiteBreakageReportTests: XCTestCase { urlParametersRemoved: false, protectionsState: true, reportFlow: .appMenu, - error: nil, - httpStatusCode: nil + errors: nil, + httpStatusCodes: nil ) let urlRequest = makeURLRequest(with: breakage.requestParameters) @@ -87,8 +87,8 @@ class WebsiteBreakageReportTests: XCTestCase { urlParametersRemoved: false, protectionsState: true, reportFlow: .appMenu, - error: nil, - httpStatusCode: nil + errors: nil, + httpStatusCodes: nil ) let urlRequest = makeURLRequest(with: breakage.requestParameters)