diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index c0cf06df29..e005658d55 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13770,7 +13770,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 120.0.0; + version = 121.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 5787b3eda5..8749a59390 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "cea7c43e5ab1d7484ab29abeda429350ed8a7dc1", - "version" : "120.0.0" + "revision" : "4555c3dbf265f1dca0304c69e7013b9d46a758b3", + "version" : "121.0.0" } }, { @@ -95,8 +95,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/privacy-dashboard", "state" : { - "revision" : "c67d268bf234760f49034a0fe7a6137a1b216b05", - "version" : "3.2.0" + "revision" : "43a6e1c1864846679a254e60c91332c3fbd922ee", + "version" : "3.3.0" } }, { diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index db71e63d65..7d4b4b7711 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -332,6 +332,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel #if DBP DataBrokerProtectionAppEvents().applicationDidBecomeActive() #endif + AppPrivacyFeatures.shared.contentBlocking.privacyConfigurationManager.toggleProtectionsCounter.sendEventsIfNeeded() } func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { diff --git a/DuckDuckGo/ContentBlocker/ContentBlocking.swift b/DuckDuckGo/ContentBlocker/ContentBlocking.swift index 637834c2b3..dee72a7514 100644 --- a/DuckDuckGo/ContentBlocker/ContentBlocking.swift +++ b/DuckDuckGo/ContentBlocker/ContentBlocking.swift @@ -64,6 +64,7 @@ final class AppContentBlocking { embeddedDataProvider: AppPrivacyConfigurationDataProvider(), localProtection: LocalUnprotectedDomains.shared, errorReporting: Self.debugEvents, + toggleProtectionsCounterEventReporting: toggleProtectionsEvents, internalUserDecider: internalUserDecider) trackerDataManager = TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerDataSet), @@ -96,6 +97,15 @@ final class AppContentBlocking { log: .attribution) } + private let toggleProtectionsEvents = EventMapping { event, _, parameters, _ in + let domainEvent: Pixel.Event + switch event { + case .toggleProtectionsCounterDaily: + domainEvent = .toggleProtectionsDailyCount + } + Pixel.fire(domainEvent, withAdditionalParameters: parameters ?? [:]) + } + private static let debugEvents = EventMapping { event, error, parameters, onComplete in guard NSApp.runType.requiresEnvironment else { return } diff --git a/DuckDuckGo/ContentBlocker/Mocks/MockPrivacyConfiguration.swift b/DuckDuckGo/ContentBlocker/Mocks/MockPrivacyConfiguration.swift index 1078823ed8..60dc35a8e1 100644 --- a/DuckDuckGo/ContentBlocker/Mocks/MockPrivacyConfiguration.swift +++ b/DuckDuckGo/ContentBlocker/Mocks/MockPrivacyConfiguration.swift @@ -18,6 +18,7 @@ import BrowserServicesKit import Combine +import Common #if DEBUG @@ -95,6 +96,8 @@ final class MockPrivacyConfigurationManager: NSObject, PrivacyConfigurationManag var updatesPublisher: AnyPublisher = Just(()).eraseToAnyPublisher() var privacyConfig: PrivacyConfiguration = MockPrivacyConfiguration() var internalUserDecider: InternalUserDecider = DefaultInternalUserDecider() + var toggleProtectionsCounter: ToggleProtectionsCounter = ToggleProtectionsCounter(eventReporting: EventMapping { _, _, _, _ in + }) } #endif diff --git a/DuckDuckGo/Menus/MainMenuActions.swift b/DuckDuckGo/Menus/MainMenuActions.swift index 80bb0ee02a..2f4c286472 100644 --- a/DuckDuckGo/Menus/MainMenuActions.swift +++ b/DuckDuckGo/Menus/MainMenuActions.swift @@ -122,7 +122,7 @@ extension AppDelegate { @objc func openReportBrokenSite(_ sender: Any?) { let storyboard = NSStoryboard(name: "PrivacyDashboard", bundle: nil) let privacyDashboardViewController = storyboard.instantiateController(identifier: "PrivacyDashboardViewController") { coder in - PrivacyDashboardViewController(coder: coder, initMode: .reportBrokenSite) + PrivacyDashboardViewController(coder: coder, privacyInfo: nil, dashboardMode: .report) } privacyDashboardViewController.sizeDelegate = self diff --git a/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift b/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift index f6ea4e16b9..d30d1700d7 100644 --- a/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift +++ b/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift @@ -36,49 +36,65 @@ final class PrivacyDashboardViewController: NSViewController { static let initialContentWidth: CGFloat = 360.0 } - /// Type of web page displayed - enum Mode { - case privacyDashboard - case reportBrokenSite - } - private var webView: WKWebView! - private let initMode: Mode - - var source: WebsiteBreakage.Source { - initMode == .reportBrokenSite ? .appMenu : .dashboard - } + private let privacyDashboardController: PrivacyDashboardController + private var privacyDashboardDidTriggerDismiss: Bool = false - private let privacyDashboardController = PrivacyDashboardController(privacyInfo: nil) public let rulesUpdateObserver = ContentBlockingRulesUpdateObserver() - private let websiteBreakageReporter: WebsiteBreakageReporter = { - WebsiteBreakageReporter(pixelHandler: { parameters in + private let brokenSiteReporter: BrokenSiteReporter = { + BrokenSiteReporter(pixelHandler: { parameters in Pixel.fire( .brokenSiteReport, withAdditionalParameters: parameters, - allowedQueryReservedCharacters: WebsiteBreakage.allowedQueryReservedCharacters + allowedQueryReservedCharacters: BrokenSiteReport.allowedQueryReservedCharacters ) }, keyValueStoring: UserDefaults.standard) }() + private let toggleProtectionsOffReporter: BrokenSiteReporter = { + BrokenSiteReporter(pixelHandler: { parameters in + Pixel.fire( + .protectionToggledOffBreakageReport, + withAdditionalParameters: parameters, + allowedQueryReservedCharacters: BrokenSiteReport.allowedQueryReservedCharacters) + }, keyValueStoring: UserDefaults.standard) + }() + + private let toggleReportEvents = EventMapping { event, _, parameters, _ in + let domainEvent: Pixel.Event + switch event { + case .toggleReportDismiss: domainEvent = .toggleReportDismiss + case .toggleReportDoNotSend: domainEvent = .toggleReportDoNotSend + } + Pixel.fire(domainEvent, withAdditionalParameters: parameters) + } + private let permissionHandler = PrivacyDashboardPermissionHandler() private var preferredMaxHeight: CGFloat = Constants.initialContentHeight func setPreferredMaxHeight(_ height: CGFloat) { guard height > Constants.initialContentHeight else { return } - preferredMaxHeight = height } var sizeDelegate: PrivacyDashboardViewControllerSizeDelegate? private weak var tabViewModel: TabViewModel? - required init?(coder: NSCoder, initMode: Mode) { - self.initMode = initMode + required init?(coder: NSCoder, + privacyInfo: PrivacyInfo?, + dashboardMode: PrivacyDashboardMode, + privacyConfigurationManager: PrivacyConfigurationManaging = ContentBlocking.shared.privacyConfigurationManager) { + self.privacyDashboardController = PrivacyDashboardController(privacyInfo: privacyInfo, + dashboardMode: dashboardMode, + privacyConfigurationManager: privacyConfigurationManager, + eventMapping: toggleReportEvents) super.init(coder: coder) } required init?(coder: NSCoder) { - self.initMode = .privacyDashboard + self.privacyDashboardController = PrivacyDashboardController(privacyInfo: nil, + dashboardMode: .dashboard, + privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager, + eventMapping: toggleReportEvents) super.init(coder: coder) } @@ -94,16 +110,23 @@ final class PrivacyDashboardViewController: NSViewController { } public override func viewDidLoad() { - super.viewDidLoad() initWebView() - privacyDashboardController.setup(for: webView, reportBrokenSiteOnly: initMode == .reportBrokenSite ? true : false) + privacyDashboardController.setup(for: webView) privacyDashboardController.privacyDashboardNavigationDelegate = self privacyDashboardController.privacyDashboardDelegate = self privacyDashboardController.privacyDashboardReportBrokenSiteDelegate = self + privacyDashboardController.privacyDashboardToggleReportDelegate = self privacyDashboardController.preferredLocale = Bundle.main.preferredLocalizations.first } + override func viewWillDisappear() { + super.viewWillDisappear() + if !privacyDashboardDidTriggerDismiss { + privacyDashboardController.handleViewWillDisappear() + } + } + private func initWebView() { let configuration = WKWebViewConfiguration() #if DEBUG @@ -146,9 +169,7 @@ final class PrivacyDashboardViewController: NSViewController { } private func privacyDashboardProtectionSwitchChangeHandler(state: ProtectionState) { - - dismiss() - + privacyDashboardDidTriggerDismiss = true guard let domain = privacyDashboardController.privacyInfo?.url.host else { return } @@ -175,7 +196,9 @@ extension PrivacyDashboardViewController: PrivacyDashboardControllerDelegate { // Not used in macOS: Pixel.fire(.privacyDashboardReportBrokenSite) } - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didChangeProtectionSwitch protectionState: ProtectionState) { + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, + didChangeProtectionSwitch protectionState: ProtectionState, + didSendReport: Bool) { privacyDashboardProtectionSwitchChangeHandler(state: protectionState) } @@ -206,7 +229,6 @@ extension PrivacyDashboardViewController: PrivacyDashboardControllerDelegate { func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetPermission permissionName: String, to state: PermissionAuthorizationState) { guard let domain = self.privacyDashboardController.privacyInfo?.url.host else { return } - permissionHandler.setPermissionAuthorization(authorizationState: state, domain: domain, permissionName: permissionName) } @@ -235,11 +257,12 @@ extension PrivacyDashboardViewController: PrivacyDashboardReportBrokenSiteDelega func privacyDashboardController(_ privacyDashboardController: PrivacyDashboard.PrivacyDashboardController, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) { + let source: BrokenSiteReport.Source = privacyDashboardController.initDashboardMode == .report ? .appMenu : .dashboard do { - let websiteBreakage = try makeWebsiteBreakage(category: category, description: description) - try websiteBreakageReporter.report(breakage: websiteBreakage) + let report = try makeBrokenSiteReport(category: category, description: description, source: source) + try brokenSiteReporter.report(report, reportMode: .regular) } catch { - os_log("Failed to generate or send the website breakage report: \(error.localizedDescription)", type: .error) + os_log("Failed to generate or send the broken site report: \(error.localizedDescription)", type: .error) } } @@ -250,20 +273,44 @@ extension PrivacyDashboardViewController: PrivacyDashboardReportBrokenSiteDelega } } +// MARK: - PrivacyDashboardToggleReportDelegate + +extension PrivacyDashboardViewController: PrivacyDashboardToggleReportDelegate { + + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, + didRequestSubmitToggleReportWithSource source: BrokenSiteReport.Source, + didOpenReportInfo: Bool, + toggleReportCounter: Int?) { + do { + let report = try makeBrokenSiteReport(source: source, + didOpenReportInfo: didOpenReportInfo, + toggleReportCounter: toggleReportCounter) + try toggleProtectionsOffReporter.report(report, reportMode: .toggle) + } catch { + os_log("Failed to generate or send the broken site report: %@", type: .error, error.localizedDescription) + } + } + +} + // MARK: - Breakage extension PrivacyDashboardViewController { - enum WebsiteBreakageError: Error { + enum BrokenSiteReportError: Error { case failedToFetchTheCurrentURL } - private func makeWebsiteBreakage(category: String, description: String) throws -> WebsiteBreakage { + private func makeBrokenSiteReport(category: String = "", + description: String = "", + source: BrokenSiteReport.Source, + didOpenReportInfo: Bool = false, + toggleReportCounter: Int? = nil) throws -> BrokenSiteReport { // ⚠️ To limit privacy risk, site URL is trimmed to not include query and fragment guard let currentTab = tabViewModel?.tab, let currentURL = currentTab.content.url?.trimmingQueryItemsAndFragment() else { - throw WebsiteBreakageError.failedToFetchTheCurrentURL + throw BrokenSiteReportError.failedToFetchTheCurrentURL } let blockedTrackerDomains = currentTab.privacyInfo?.trackerInfo.trackersBlocked.compactMap { $0.domain } ?? [] let installedSurrogates = currentTab.privacyInfo?.trackerInfo.installedSurrogates.map {$0} ?? [] @@ -283,22 +330,24 @@ extension PrivacyDashboardViewController { statusCodes = [httpStatusCode] } - let websiteBreakage = WebsiteBreakage(siteUrl: currentURL, - category: category.lowercased(), - description: description, - osVersion: "\(ProcessInfo.processInfo.operatingSystemVersion)", - manufacturer: "Apple", - upgradedHttps: currentTab.privacyInfo?.connectionUpgradedTo != nil, - tdsETag: ContentBlocking.shared.contentBlockingManager.currentRules.first?.etag, - blockedTrackerDomains: blockedTrackerDomains, - installedSurrogates: installedSurrogates, - isGPCEnabled: PrivacySecurityPreferences.shared.gpcEnabled, - ampURL: ampURL, - urlParametersRemoved: urlParametersRemoved, - protectionsState: protectionsState, - reportFlow: source, - errors: errors, - httpStatusCodes: statusCodes) + let websiteBreakage = BrokenSiteReport(siteUrl: currentURL, + category: category.lowercased(), + description: description, + osVersion: "\(ProcessInfo.processInfo.operatingSystemVersion)", + manufacturer: "Apple", + upgradedHttps: currentTab.privacyInfo?.connectionUpgradedTo != nil, + tdsETag: ContentBlocking.shared.contentBlockingManager.currentRules.first?.etag, + blockedTrackerDomains: blockedTrackerDomains, + installedSurrogates: installedSurrogates, + isGPCEnabled: PrivacySecurityPreferences.shared.gpcEnabled, + ampURL: ampURL, + urlParametersRemoved: urlParametersRemoved, + protectionsState: protectionsState, + reportFlow: source, + errors: errors, + httpStatusCodes: statusCodes, + didOpenReportInfo: didOpenReportInfo, + toggleReportCounter: toggleReportCounter) return websiteBreakage } } diff --git a/DuckDuckGo/Statistics/PixelEvent.swift b/DuckDuckGo/Statistics/PixelEvent.swift index d8cb04dbae..6e6db6ffeb 100644 --- a/DuckDuckGo/Statistics/PixelEvent.swift +++ b/DuckDuckGo/Statistics/PixelEvent.swift @@ -219,6 +219,11 @@ extension Pixel { case dailyPixel(Event, isFirst: Bool) + case protectionToggledOffBreakageReport + case toggleProtectionsDailyCount + case toggleReportDoNotSend + case toggleReportDismiss + enum Debug { /// This is a convenience pixel that allows us to fire `PixelKitEvents` using our /// regular `Pixel.fire()` calls. This is a convenience intermediate step to help ensure @@ -595,6 +600,10 @@ extension Pixel.Event { return "m_mac_netp_ev_geoswitching_set_custom" case .networkProtectionGeoswitchingNoLocations: return "m_mac_netp_ev_geoswitching_no_locations" + case .protectionToggledOffBreakageReport: return "m_mac_protection-toggled-off-breakage-report" + case .toggleProtectionsDailyCount: return "m_mac_toggle-protections-daily-count" + case .toggleReportDoNotSend: return "m_mac_toggle-report-do-not-send" + case .toggleReportDismiss: return "m_mac_toggle-report-dismiss" } } } diff --git a/DuckDuckGo/Statistics/PixelParameters.swift b/DuckDuckGo/Statistics/PixelParameters.swift index 692f6e9234..56203884e6 100644 --- a/DuckDuckGo/Statistics/PixelParameters.swift +++ b/DuckDuckGo/Statistics/PixelParameters.swift @@ -165,7 +165,11 @@ extension Pixel.Event { .dataBrokerDisableAndDeleteDaily, .dataBrokerEnableLoginItemDaily, .dataBrokerDisableLoginItemDaily, - .dataBrokerResetLoginItemDaily: + .dataBrokerResetLoginItemDaily, + .protectionToggledOffBreakageReport, + .toggleProtectionsDailyCount, + .toggleReportDoNotSend, + .toggleReportDismiss: return nil } } diff --git a/DuckDuckGoDBPBackgroundAgent/DBPMocks.swift b/DuckDuckGoDBPBackgroundAgent/DBPMocks.swift index b184a883df..5e4e36ef2f 100644 --- a/DuckDuckGoDBPBackgroundAgent/DBPMocks.swift +++ b/DuckDuckGoDBPBackgroundAgent/DBPMocks.swift @@ -19,6 +19,7 @@ import Foundation import BrowserServicesKit import Combine +import Common /* This mock is a hack for now @@ -56,23 +57,30 @@ final class PrivacyConfigurationManagingMock: PrivacyConfigurationManaging { guard let privacyConfigurationData = try? PrivacyConfigurationData(data: data) else { fatalError("Could not retrieve privacy configuration data") } - let privacyConfig = privacyConfiguration(withData: privacyConfigurationData, internalUserDecider: internalUserDecider) + let privacyConfig = privacyConfiguration(withData: privacyConfigurationData, + internalUserDecider: internalUserDecider, + toggleProtectionsCounter: toggleProtectionsCounter) return privacyConfig } var internalUserDecider: InternalUserDecider = DefaultInternalUserDecider(store: InternalUserDeciderStoreMock()) + var toggleProtectionsCounter: ToggleProtectionsCounter = ToggleProtectionsCounter(eventReporting: EventMapping { _, _, _, _ in + }) func reload(etag: String?, data: Data?) -> PrivacyConfigurationManager.ReloadResult { .downloaded } } -func privacyConfiguration(withData data: PrivacyConfigurationData, internalUserDecider: InternalUserDecider) -> PrivacyConfiguration { +func privacyConfiguration(withData data: PrivacyConfigurationData, + internalUserDecider: InternalUserDecider, + toggleProtectionsCounter: ToggleProtectionsCounter) -> PrivacyConfiguration { let domain = MockDomainsProtectionStore() return AppPrivacyConfiguration(data: data, identifier: UUID().uuidString, localProtection: domain, - internalUserDecider: internalUserDecider) + internalUserDecider: internalUserDecider, + toggleProtectionsCounter: toggleProtectionsCounter) } final class MockDomainsProtectionStore: DomainsProtectionStore { diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index af9dd89079..87c5b62cc9 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: "120.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "121.0.0"), .package(path: "../PixelKit"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/CCF/DataBrokerProtectionUtils.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/CCF/DataBrokerProtectionUtils.swift index d65b1653b2..8c2d9a03bc 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/CCF/DataBrokerProtectionUtils.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/CCF/DataBrokerProtectionUtils.swift @@ -164,6 +164,7 @@ private class PrivacyConfigurationDataBrokerProtectionConfigOverride: PrivacyCon var updatesPublisher: AnyPublisher<(), Never> var privacyConfig: PrivacyConfiguration var internalUserDecider: InternalUserDecider + var toggleProtectionsCounter: ToggleProtectionsCounter var currentConfig: Data { return updateConfigWithBrokerProtection() @@ -178,6 +179,7 @@ private class PrivacyConfigurationDataBrokerProtectionConfigOverride: PrivacyCon updatesPublisher = manager.updatesPublisher privacyConfig = manager.privacyConfig internalUserDecider = manager.internalUserDecider + toggleProtectionsCounter = manager.toggleProtectionsCounter } private func updateConfigWithBrokerProtection() -> Data { diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/DebugUI/DataBrokerRunCustomJSONViewModel.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/DebugUI/DataBrokerRunCustomJSONViewModel.swift index 523770aed0..50208b2899 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/DebugUI/DataBrokerRunCustomJSONViewModel.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/DebugUI/DataBrokerRunCustomJSONViewModel.swift @@ -275,23 +275,31 @@ private final class PrivacyConfigurationManagingMock: PrivacyConfigurationManagi guard let privacyConfigurationData = try? PrivacyConfigurationData(data: data) else { fatalError("Could not retrieve privacy configuration data") } - let privacyConfig = privacyConfiguration(withData: privacyConfigurationData, internalUserDecider: internalUserDecider) + let privacyConfig = privacyConfiguration(withData: privacyConfigurationData, + internalUserDecider: internalUserDecider, + toggleProtectionsCounter: toggleProtectionsCounter) return privacyConfig } var internalUserDecider: InternalUserDecider = DefaultInternalUserDecider(store: InternalUserDeciderStoreMock()) + var toggleProtectionsCounter: ToggleProtectionsCounter = ToggleProtectionsCounter(eventReporting: EventMapping { _, _, _, _ in + }) + func reload(etag: String?, data: Data?) -> PrivacyConfigurationManager.ReloadResult { .downloaded } } -func privacyConfiguration(withData data: PrivacyConfigurationData, internalUserDecider: InternalUserDecider) -> PrivacyConfiguration { +func privacyConfiguration(withData data: PrivacyConfigurationData, + internalUserDecider: InternalUserDecider, + toggleProtectionsCounter: ToggleProtectionsCounter) -> PrivacyConfiguration { let domain = MockDomainsProtectionStore() return AppPrivacyConfiguration(data: data, identifier: UUID().uuidString, localProtection: domain, - internalUserDecider: internalUserDecider) + internalUserDecider: internalUserDecider, + toggleProtectionsCounter: toggleProtectionsCounter) } final class MockDomainsProtectionStore: DomainsProtectionStore { diff --git a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift index 6cecf5a81d..71aa241a45 100644 --- a/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift +++ b/LocalPackages/DataBrokerProtection/Tests/DataBrokerProtectionTests/Mocks.swift @@ -67,6 +67,8 @@ final class InternalUserDeciderStoreMock: InternalUserStoring { } final class PrivacyConfigurationManagingMock: PrivacyConfigurationManaging { + var toggleProtectionsCounter: ToggleProtectionsCounter = ToggleProtectionsCounter(eventReporting: nil) + var currentConfig: Data = Data() var updatesPublisher: AnyPublisher = .init(Just(())) diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index bd45f1e253..36497d486c 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: "120.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "121.0.0"), .package(path: "../XPCHelper"), .package(path: "../SwiftUIExtensions"), .package(path: "../LoginItems"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 6239fb6917..a450104d34 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: "120.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "121.0.0"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/UnitTests/ContentBlocker/AppPrivacyConfigurationTests.swift b/UnitTests/ContentBlocker/AppPrivacyConfigurationTests.swift index 279979e840..0226be7ecc 100644 --- a/UnitTests/ContentBlocker/AppPrivacyConfigurationTests.swift +++ b/UnitTests/ContentBlocker/AppPrivacyConfigurationTests.swift @@ -54,7 +54,8 @@ class AppPrivacyConfigurationTests: XCTestCase { let config = AppPrivacyConfiguration(data: configData, identifier: "", localProtection: MockDomainsProtectionStore(), - internalUserDecider: DefaultInternalUserDecider(store: InternalUserDeciderStoreMock())) + internalUserDecider: DefaultInternalUserDecider(store: InternalUserDeciderStoreMock()), + toggleProtectionsCounter: ToggleProtectionsCounter(eventReporting: nil)) XCTAssert(config.isEnabled(featureKey: .contentBlocking)) diff --git a/UnitTests/PrivacyReferenceTests/BrokenSiteReportingReferenceTests.swift b/UnitTests/PrivacyReferenceTests/BrokenSiteReportingReferenceTests.swift index 73e7cba06c..7adfb26758 100644 --- a/UnitTests/PrivacyReferenceTests/BrokenSiteReportingReferenceTests.swift +++ b/UnitTests/PrivacyReferenceTests/BrokenSiteReportingReferenceTests.swift @@ -53,7 +53,7 @@ final class BrokenSiteReportingReferenceTests: XCTestCase { params["test"] = "1" let configuration = APIRequest.Configuration(url: URL.pixelUrl(forPixelNamed: Pixel.Event.brokenSiteReport.name), queryParameters: params, - allowedQueryReservedCharacters: WebsiteBreakage.allowedQueryReservedCharacters) + allowedQueryReservedCharacters: BrokenSiteReport.allowedQueryReservedCharacters) return configuration.request } @@ -74,22 +74,24 @@ final class BrokenSiteReportingReferenceTests: XCTestCase { errors = errs.map { MockError($0) } } - let breakage = WebsiteBreakage(siteUrl: test.siteURL, - category: test.category, - description: test.providedDescription, - osVersion: test.os ?? "", - manufacturer: "Apple", - upgradedHttps: test.wasUpgraded, - tdsETag: test.blocklistVersion, - blockedTrackerDomains: test.blockedTrackers, - installedSurrogates: test.surrogates, - isGPCEnabled: test.gpcEnabled ?? false, - ampURL: "", - urlParametersRemoved: false, - protectionsState: test.protectionsEnabled, - reportFlow: .appMenu, - errors: errors, - httpStatusCodes: test.httpErrorCodes ?? []) + let breakage = BrokenSiteReport(siteUrl: test.siteURL, + category: test.category, + description: test.providedDescription, + osVersion: test.os ?? "", + manufacturer: "Apple", + upgradedHttps: test.wasUpgraded, + tdsETag: test.blocklistVersion, + blockedTrackerDomains: test.blockedTrackers, + installedSurrogates: test.surrogates, + isGPCEnabled: test.gpcEnabled ?? false, + ampURL: "", + urlParametersRemoved: false, + protectionsState: test.protectionsEnabled, + reportFlow: .appMenu, + errors: errors, + httpStatusCodes: test.httpErrorCodes ?? [], + didOpenReportInfo: false, + toggleReportCounter: nil) let request = makeURLRequest(with: breakage.requestParameters) diff --git a/UnitTests/PrivacyReferenceTests/PrivacyReferenceTestHelper.swift b/UnitTests/PrivacyReferenceTests/PrivacyReferenceTestHelper.swift index 65480c0240..cdef96e4d0 100644 --- a/UnitTests/PrivacyReferenceTests/PrivacyReferenceTestHelper.swift +++ b/UnitTests/PrivacyReferenceTests/PrivacyReferenceTestHelper.swift @@ -56,6 +56,7 @@ struct PrivacyReferenceTestHelper { return AppPrivacyConfiguration(data: data, identifier: UUID().uuidString, localProtection: domain, - internalUserDecider: DefaultInternalUserDecider(store: InternalUserDeciderStoreMock())) + internalUserDecider: DefaultInternalUserDecider(store: InternalUserDeciderStoreMock()), + toggleProtectionsCounter: ToggleProtectionsCounter(eventReporting: nil)) } } diff --git a/UnitTests/WebsiteBreakageReport/WebsiteBreakageReportTests.swift b/UnitTests/WebsiteBreakageReport/WebsiteBreakageReportTests.swift index 2493402b40..341e6c9c69 100644 --- a/UnitTests/WebsiteBreakageReport/WebsiteBreakageReportTests.swift +++ b/UnitTests/WebsiteBreakageReport/WebsiteBreakageReportTests.swift @@ -26,7 +26,7 @@ import XCTest class WebsiteBreakageReportTests: XCTestCase { func testCommonSetOfFields() throws { - let breakage = WebsiteBreakage( + let breakage = BrokenSiteReport( siteUrl: #URL("https://example.test/"), category: "contentIsMissing", description: nil, @@ -47,7 +47,9 @@ class WebsiteBreakageReportTests: XCTestCase { protectionsState: true, reportFlow: .appMenu, errors: nil, - httpStatusCodes: nil + httpStatusCodes: nil, + didOpenReportInfo: false, + toggleReportCounter: nil ) let urlRequest = makeURLRequest(with: breakage.requestParameters) @@ -69,7 +71,7 @@ class WebsiteBreakageReportTests: XCTestCase { } func testThatNativeAppSpecificFieldsAreReported() throws { - let breakage = WebsiteBreakage( + let breakage = BrokenSiteReport( siteUrl: #URL("http://unsafe.example.test/path/to/thing.html"), category: "videoOrImagesDidntLoad", description: nil, @@ -90,7 +92,9 @@ class WebsiteBreakageReportTests: XCTestCase { protectionsState: true, reportFlow: .appMenu, errors: nil, - httpStatusCodes: nil + httpStatusCodes: nil, + didOpenReportInfo: false, + toggleReportCounter: nil ) let urlRequest = makeURLRequest(with: breakage.requestParameters) @@ -120,7 +124,7 @@ class WebsiteBreakageReportTests: XCTestCase { params["test"] = "1" let configuration = APIRequest.Configuration(url: URL.pixelUrl(forPixelNamed: Pixel.Event.brokenSiteReport.name), queryParameters: params, - allowedQueryReservedCharacters: WebsiteBreakage.allowedQueryReservedCharacters) + allowedQueryReservedCharacters: BrokenSiteReport.allowedQueryReservedCharacters) return configuration.request } }