From a8569329e2ab4cfbec434dfd4c04ab0678eab1e1 Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Tue, 14 Nov 2023 15:03:31 +0000 Subject: [PATCH 01/12] Privacy dashboard controller now can open Report Broken site directly --- .../PrivacyDashboardController.swift | 93 ++++++++++++------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/Sources/PrivacyDashboard/PrivacyDashboardController.swift b/Sources/PrivacyDashboard/PrivacyDashboardController.swift index 085302444..5fe2ab8eb 100644 --- a/Sources/PrivacyDashboard/PrivacyDashboardController.swift +++ b/Sources/PrivacyDashboard/PrivacyDashboardController.swift @@ -26,44 +26,60 @@ public enum PrivacyDashboardOpenSettingsTarget: String { case cookiePopupManagement = "cpm" } -public protocol PrivacyDashboardControllerDelegate: AnyObject { - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, - didChangeProtectionSwitch protectionState: ProtectionState) - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestOpenUrlInNewTab url: URL) - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, - didRequestOpenSettings target: PrivacyDashboardOpenSettingsTarget) + +public protocol PrivacyDashboardNavigationDelegate: AnyObject { #if os(iOS) func privacyDashboardControllerDidTapClose(_ privacyDashboardController: PrivacyDashboardController) - func privacyDashboardControllerDidRequestShowReportBrokenSite(_ privacyDashboardController: PrivacyDashboardController) #endif - + #if os(macOS) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetHeight height: Int) - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, - didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, - didSetPermission permissionName: String, - to state: PermissionAuthorizationState) - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, - setPermission permissionName: String, - paused: Bool) #endif +} + +public protocol PrivacyDashboardReportBrokenSiteDelegate: AnyObject { + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, reportBrokenSiteDidChangeProtectionSwitch protectionState: ProtectionState) } -@MainActor -public final class PrivacyDashboardController: NSObject { + + +public protocol PrivacyDashboardControllerDelegate: AnyObject { - public weak var delegate: PrivacyDashboardControllerDelegate? + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didChangeProtectionSwitch protectionState: ProtectionState) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestOpenUrlInNewTab url: URL) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestOpenSettings target: PrivacyDashboardOpenSettingsTarget) + func privacyDashboardControllerDidRequestShowReportBrokenSite(_ privacyDashboardController: PrivacyDashboardController) + +#if os(macOS) + //??? + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetPermission permissionName: String, to state: PermissionAuthorizationState) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, setPermission permissionName: String, paused: Bool) +#endif + +} + + + + + + +/// <#Description#> +@MainActor public final class PrivacyDashboardController: NSObject { + + //Delegates + public weak var privacyDashboardDelegate: PrivacyDashboardControllerDelegate? + public weak var privacyDashboardNavigationDelegate: PrivacyDashboardNavigationDelegate? + public weak var privacyDashboardReportBrokenSiteDelegate: PrivacyDashboardReportBrokenSiteDelegate? @Published public var theme: PrivacyDashboardTheme? public var preferredLocale: String? @Published public var allowedPermissions: [AllowedPermission] = [] - public private(set) weak var privacyInfo: PrivacyInfo? - private weak var webView: WKWebView? + private weak var webView: WKWebView? private let privacyDashboardScript = PrivacyDashboardUserScript() private var cancellables = Set() @@ -71,13 +87,12 @@ public final class PrivacyDashboardController: NSObject { self.privacyInfo = privacyInfo } - public func setup(for webView: WKWebView) { + public func setup(for webView: WKWebView, reportBrokenSiteOnly: Bool) { self.webView = webView - webView.navigationDelegate = self setupPrivacyDashboardUserScript() - loadPrivacyDashboardHTML() + loadPrivacyDashboardHTML(reportBrokenSiteOnly: reportBrokenSiteOnly) } public func updatePrivacyInfo(_ privacyInfo: PrivacyInfo?) { @@ -118,8 +133,13 @@ public final class PrivacyDashboardController: NSObject { } } - private func loadPrivacyDashboardHTML() { - guard let url = Bundle.privacyDashboardURL else { return } + private func loadPrivacyDashboardHTML(reportBrokenSiteOnly: Bool) { + guard var url = Bundle.privacyDashboardURL else { return } + + if reportBrokenSiteOnly { + url = url.appendingParameter(name: "screen", value: ProtectionState.EventOriginScreen.breakageForm.rawValue) + } + webView?.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent().deletingLastPathComponent()) } } @@ -237,26 +257,33 @@ extension PrivacyDashboardController: PrivacyDashboardUserScriptDelegate { func userScript(_ userScript: PrivacyDashboardUserScript, didRequestOpenSettings target: String) { let settingsTarget = PrivacyDashboardOpenSettingsTarget(rawValue: target) ?? .general - delegate?.privacyDashboardController(self, didRequestOpenSettings: settingsTarget) + privacyDashboardDelegate?.privacyDashboardController(self, didRequestOpenSettings: settingsTarget) } func userScript(_ userScript: PrivacyDashboardUserScript, didChangeProtectionState protectionState: ProtectionState) { - delegate?.privacyDashboardController(self, didChangeProtectionSwitch: protectionState) + + switch protectionState.eventOrigin.screen { + case .primaryScreen: + privacyDashboardDelegate?.privacyDashboardController(self, didChangeProtectionSwitch: protectionState) + case .breakageForm: + privacyDashboardReportBrokenSiteDelegate?.privacyDashboardController(self, reportBrokenSiteDidChangeProtectionSwitch: protectionState) + } + } func userScript(_ userScript: PrivacyDashboardUserScript, didRequestOpenUrlInNewTab url: URL) { - delegate?.privacyDashboardController(self, didRequestOpenUrlInNewTab: url) + privacyDashboardDelegate?.privacyDashboardController(self, didRequestOpenUrlInNewTab: url) } func userScriptDidRequestClosing(_ userScript: PrivacyDashboardUserScript) { #if os(iOS) - delegate?.privacyDashboardControllerDidTapClose(self) + privacyDashboardNavigationDelegate?.privacyDashboardControllerDidTapClose(self) #endif } func userScriptDidRequestShowReportBrokenSite(_ userScript: PrivacyDashboardUserScript) { #if os(iOS) - delegate?.privacyDashboardControllerDidRequestShowReportBrokenSite(self) + privacyDashboardDelegate?.privacyDashboardControllerDidRequestShowReportBrokenSite(self) #endif } @@ -267,9 +294,7 @@ extension PrivacyDashboardController: PrivacyDashboardUserScriptDelegate { } func userScript(_ userScript: PrivacyDashboardUserScript, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) { -#if os(macOS) - delegate?.privacyDashboardController(self, didRequestSubmitBrokenSiteReportWithCategory: category, description: description) -#endif + privacyDashboardReportBrokenSiteDelegate?.privacyDashboardController(self, didRequestSubmitBrokenSiteReportWithCategory: category, description: description) } func userScript(_ userScript: PrivacyDashboardUserScript, didSetPermission permission: String, to state: PermissionAuthorizationState) { From 2eff43745b873907e0c7fb38e196d0a6ae2990ea Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Wed, 15 Nov 2023 17:50:39 +0000 Subject: [PATCH 02/12] PrivacyDashboardController, didSetHeight is now for iOS and Mac --- .../PrivacyDashboardController.swift | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/Sources/PrivacyDashboard/PrivacyDashboardController.swift b/Sources/PrivacyDashboard/PrivacyDashboardController.swift index 5fe2ab8eb..0da1b7a65 100644 --- a/Sources/PrivacyDashboard/PrivacyDashboardController.swift +++ b/Sources/PrivacyDashboard/PrivacyDashboardController.swift @@ -26,16 +26,12 @@ public enum PrivacyDashboardOpenSettingsTarget: String { case cookiePopupManagement = "cpm" } - - public protocol PrivacyDashboardNavigationDelegate: AnyObject { #if os(iOS) func privacyDashboardControllerDidTapClose(_ privacyDashboardController: PrivacyDashboardController) #endif -#if os(macOS) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetHeight height: Int) -#endif } public protocol PrivacyDashboardReportBrokenSiteDelegate: AnyObject { @@ -44,8 +40,6 @@ public protocol PrivacyDashboardReportBrokenSiteDelegate: AnyObject { func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, reportBrokenSiteDidChangeProtectionSwitch protectionState: ProtectionState) } - - public protocol PrivacyDashboardControllerDelegate: AnyObject { func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didChangeProtectionSwitch protectionState: ProtectionState) @@ -54,18 +48,13 @@ public protocol PrivacyDashboardControllerDelegate: AnyObject { func privacyDashboardControllerDidRequestShowReportBrokenSite(_ privacyDashboardController: PrivacyDashboardController) #if os(macOS) - //??? func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetPermission permissionName: String, to state: PermissionAuthorizationState) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, setPermission permissionName: String, paused: Bool) #endif } - - - - - +// TODO: describe everything /// <#Description#> @MainActor public final class PrivacyDashboardController: NSObject { @@ -288,9 +277,7 @@ extension PrivacyDashboardController: PrivacyDashboardUserScriptDelegate { } func userScript(_ userScript: PrivacyDashboardUserScript, setHeight height: Int) { -#if os(macOS) - delegate?.privacyDashboardController(self, didSetHeight: height) -#endif + privacyDashboardNavigationDelegate?.privacyDashboardController(self, didSetHeight: height) } func userScript(_ userScript: PrivacyDashboardUserScript, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) { @@ -299,13 +286,13 @@ extension PrivacyDashboardController: PrivacyDashboardUserScriptDelegate { func userScript(_ userScript: PrivacyDashboardUserScript, didSetPermission permission: String, to state: PermissionAuthorizationState) { #if os(macOS) - delegate?.privacyDashboardController(self, didSetPermission: permission, to: state) + privacyDashboardDelegate?.privacyDashboardController(self, didSetPermission: permission, to: state) #endif } func userScript(_ userScript: PrivacyDashboardUserScript, setPermission permission: String, paused: Bool) { #if os(macOS) - delegate?.privacyDashboardController(self, setPermission: permission, paused: paused) + privacyDashboardDelegate?.privacyDashboardController(self, setPermission: permission, paused: paused) #endif } } From 1cec675acdbc85028f5ea36e7ed161b37e71eeee Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Thu, 16 Nov 2023 10:09:15 +0000 Subject: [PATCH 03/12] Comments added --- .../PrivacyDashboardController.swift | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Sources/PrivacyDashboard/PrivacyDashboardController.swift b/Sources/PrivacyDashboard/PrivacyDashboardController.swift index 0da1b7a65..d254d0e0c 100644 --- a/Sources/PrivacyDashboard/PrivacyDashboardController.swift +++ b/Sources/PrivacyDashboard/PrivacyDashboardController.swift @@ -26,6 +26,7 @@ public enum PrivacyDashboardOpenSettingsTarget: String { case cookiePopupManagement = "cpm" } +/// Navigation delegate for the pages provided by the PrivacyDashboardController public protocol PrivacyDashboardNavigationDelegate: AnyObject { #if os(iOS) func privacyDashboardControllerDidTapClose(_ privacyDashboardController: PrivacyDashboardController) @@ -34,12 +35,14 @@ public protocol PrivacyDashboardNavigationDelegate: AnyObject { func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetHeight height: Int) } +/// `Report broken site` web page delegate public protocol PrivacyDashboardReportBrokenSiteDelegate: AnyObject { func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, reportBrokenSiteDidChangeProtectionSwitch protectionState: ProtectionState) } +/// `Privacy Dasboard` oweb page delegate public protocol PrivacyDashboardControllerDelegate: AnyObject { func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didChangeProtectionSwitch protectionState: ProtectionState) @@ -51,11 +54,12 @@ public protocol PrivacyDashboardControllerDelegate: AnyObject { func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetPermission permissionName: String, to state: PermissionAuthorizationState) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, setPermission permissionName: String, paused: Bool) #endif - } -// TODO: describe everything -/// <#Description#> +/// This controller provides two type of user experiences +/// 1- `Privacy Dashboard` with teh possibility to navigate to the `Report broken site` page +/// 2- Direct access to the `Report broken site` page +/// Which flow is used is decided at `setup(...)` time, where if `reportBrokenSiteOnly` is true then the `Report broken site` page is opened directly. @MainActor public final class PrivacyDashboardController: NSObject { //Delegates @@ -76,6 +80,10 @@ public protocol PrivacyDashboardControllerDelegate: AnyObject { self.privacyInfo = privacyInfo } + /// Configure the webview for showing `Privacy Dasboard` or `Report broken site` + /// - Parameters: + /// - webView: The webview to use + /// - reportBrokenSiteOnly: true = `Report broken site`, false = `Privacy Dasboard` public func setup(for webView: WKWebView, reportBrokenSiteOnly: Bool) { self.webView = webView webView.navigationDelegate = self From 473d5ffdfcc919bc4a8f0fd072fedbaab0ca847f Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Thu, 16 Nov 2023 11:19:45 +0000 Subject: [PATCH 04/12] fixed typos in comments --- Sources/PrivacyDashboard/PrivacyDashboardController.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/PrivacyDashboard/PrivacyDashboardController.swift b/Sources/PrivacyDashboard/PrivacyDashboardController.swift index d254d0e0c..15b2b2fb1 100644 --- a/Sources/PrivacyDashboard/PrivacyDashboardController.swift +++ b/Sources/PrivacyDashboard/PrivacyDashboardController.swift @@ -42,7 +42,7 @@ public protocol PrivacyDashboardReportBrokenSiteDelegate: AnyObject { func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, reportBrokenSiteDidChangeProtectionSwitch protectionState: ProtectionState) } -/// `Privacy Dasboard` oweb page delegate +/// `Privacy Dasboard` web page delegate public protocol PrivacyDashboardControllerDelegate: AnyObject { func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didChangeProtectionSwitch protectionState: ProtectionState) @@ -57,12 +57,12 @@ public protocol PrivacyDashboardControllerDelegate: AnyObject { } /// This controller provides two type of user experiences -/// 1- `Privacy Dashboard` with teh possibility to navigate to the `Report broken site` page +/// 1- `Privacy Dashboard` with the possibility to navigate to the `Report broken site` page /// 2- Direct access to the `Report broken site` page /// Which flow is used is decided at `setup(...)` time, where if `reportBrokenSiteOnly` is true then the `Report broken site` page is opened directly. @MainActor public final class PrivacyDashboardController: NSObject { - //Delegates + // Delegates public weak var privacyDashboardDelegate: PrivacyDashboardControllerDelegate? public weak var privacyDashboardNavigationDelegate: PrivacyDashboardNavigationDelegate? public weak var privacyDashboardReportBrokenSiteDelegate: PrivacyDashboardReportBrokenSiteDelegate? From 209e701e6cdfb894a1523bb594769e66ba3bb321 Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Thu, 16 Nov 2023 11:54:19 +0000 Subject: [PATCH 05/12] swiftlint fixes --- .../Model/AllowedPermission.swift | 2 +- .../Model/ProtectionStatus.swift | 2 +- .../PrivacyDashboard/Model/TrackerInfo.swift | 18 ++-- .../PrivacyDashboardController.swift | 84 +++++++++---------- Sources/PrivacyDashboard/PrivacyInfo.swift | 12 +-- .../PrivacyDashboardUserScript.swift | 24 +++--- 6 files changed, 71 insertions(+), 71 deletions(-) diff --git a/Sources/PrivacyDashboard/Model/AllowedPermission.swift b/Sources/PrivacyDashboard/Model/AllowedPermission.swift index 1d73c60e3..c4d36e9ea 100644 --- a/Sources/PrivacyDashboard/Model/AllowedPermission.swift +++ b/Sources/PrivacyDashboard/Model/AllowedPermission.swift @@ -26,7 +26,7 @@ public struct AllowedPermission: Codable { var used: Bool var paused: Bool var options: [[String: String]] - + public init(key: String, icon: String, title: String, diff --git a/Sources/PrivacyDashboard/Model/ProtectionStatus.swift b/Sources/PrivacyDashboard/Model/ProtectionStatus.swift index 22020c81b..bc2de57f7 100644 --- a/Sources/PrivacyDashboard/Model/ProtectionStatus.swift +++ b/Sources/PrivacyDashboard/Model/ProtectionStatus.swift @@ -25,7 +25,7 @@ public struct ProtectionStatus: Encodable { let enabledFeatures: [String] let allowlisted: Bool let denylisted: Bool - + public init(unprotectedTemporary: Bool, enabledFeatures: [String], allowlisted: Bool, denylisted: Bool) { self.unprotectedTemporary = unprotectedTemporary self.enabledFeatures = enabledFeatures diff --git a/Sources/PrivacyDashboard/Model/TrackerInfo.swift b/Sources/PrivacyDashboard/Model/TrackerInfo.swift index 9782b349a..5494c40da 100644 --- a/Sources/PrivacyDashboard/Model/TrackerInfo.swift +++ b/Sources/PrivacyDashboard/Model/TrackerInfo.swift @@ -21,7 +21,7 @@ import TrackerRadarKit import ContentBlocking public struct TrackerInfo: Encodable { - + enum CodingKeys: String, CodingKey { case requests case installedSurrogates @@ -32,14 +32,14 @@ public struct TrackerInfo: Encodable { public private(set) var installedSurrogates = Set() public init() { } - + // MARK: - Collecting detected elements - + public mutating func addDetectedTracker(_ tracker: DetectedRequest, onPageWithURL url: URL) { guard tracker.pageUrl == url.absoluteString else { return } trackers.insert(tracker) } - + public mutating func add(detectedThirdPartyRequest request: DetectedRequest) { thirdPartyRequests.insert(request) } @@ -50,20 +50,20 @@ public struct TrackerInfo: Encodable { } // MARK: - Helper accessors - + public var trackersBlocked: [DetectedRequest] { trackers.filter { $0.state == .blocked } } - + public var trackersDetected: [DetectedRequest] { trackers.filter { $0.state != .blocked } } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - + let allRequests = [] + trackers + thirdPartyRequests - + try container.encode(allRequests, forKey: .requests) try container.encode(installedSurrogates, forKey: .installedSurrogates) } diff --git a/Sources/PrivacyDashboard/PrivacyDashboardController.swift b/Sources/PrivacyDashboard/PrivacyDashboardController.swift index 15b2b2fb1..a6f10c0e2 100644 --- a/Sources/PrivacyDashboard/PrivacyDashboardController.swift +++ b/Sources/PrivacyDashboard/PrivacyDashboardController.swift @@ -31,20 +31,20 @@ public protocol PrivacyDashboardNavigationDelegate: AnyObject { #if os(iOS) func privacyDashboardControllerDidTapClose(_ privacyDashboardController: PrivacyDashboardController) #endif - + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetHeight height: Int) } /// `Report broken site` web page delegate public protocol PrivacyDashboardReportBrokenSiteDelegate: AnyObject { - + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, reportBrokenSiteDidChangeProtectionSwitch protectionState: ProtectionState) } /// `Privacy Dasboard` web page delegate public protocol PrivacyDashboardControllerDelegate: AnyObject { - + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didChangeProtectionSwitch protectionState: ProtectionState) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestOpenUrlInNewTab url: URL) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestOpenSettings target: PrivacyDashboardOpenSettingsTarget) @@ -61,17 +61,17 @@ public protocol PrivacyDashboardControllerDelegate: AnyObject { /// 2- Direct access to the `Report broken site` page /// Which flow is used is decided at `setup(...)` time, where if `reportBrokenSiteOnly` is true then the `Report broken site` page is opened directly. @MainActor public final class PrivacyDashboardController: NSObject { - + // Delegates public weak var privacyDashboardDelegate: PrivacyDashboardControllerDelegate? public weak var privacyDashboardNavigationDelegate: PrivacyDashboardNavigationDelegate? public weak var privacyDashboardReportBrokenSiteDelegate: PrivacyDashboardReportBrokenSiteDelegate? - + @Published public var theme: PrivacyDashboardTheme? public var preferredLocale: String? @Published public var allowedPermissions: [AllowedPermission] = [] public private(set) weak var privacyInfo: PrivacyInfo? - + private weak var webView: WKWebView? private let privacyDashboardScript = PrivacyDashboardUserScript() private var cancellables = Set() @@ -79,7 +79,7 @@ public protocol PrivacyDashboardControllerDelegate: AnyObject { public init(privacyInfo: PrivacyInfo?) { self.privacyInfo = privacyInfo } - + /// Configure the webview for showing `Privacy Dasboard` or `Report broken site` /// - Parameters: /// - webView: The webview to use @@ -87,56 +87,56 @@ public protocol PrivacyDashboardControllerDelegate: AnyObject { public func setup(for webView: WKWebView, reportBrokenSiteOnly: Bool) { self.webView = webView webView.navigationDelegate = self - + setupPrivacyDashboardUserScript() loadPrivacyDashboardHTML(reportBrokenSiteOnly: reportBrokenSiteOnly) } - + public func updatePrivacyInfo(_ privacyInfo: PrivacyInfo?) { cancellables.removeAll() self.privacyInfo = privacyInfo - + subscribeToDataModelChanges() sendProtectionStatus() } - + public func cleanUp() { cancellables.removeAll() - + privacyDashboardScript.messageNames.forEach { messageName in webView?.configuration.userContentController.removeScriptMessageHandler(forName: messageName) } } - + public func didStartRulesCompilation() { guard let webView = self.webView else { return } privacyDashboardScript.setIsPendingUpdates(true, webView: webView) } - + public func didFinishRulesCompilation() { guard let webView = self.webView else { return } privacyDashboardScript.setIsPendingUpdates(false, webView: webView) } - + private func setupPrivacyDashboardUserScript() { guard let webView = self.webView else { return } - + privacyDashboardScript.delegate = self - + webView.configuration.userContentController.addUserScript(privacyDashboardScript.makeWKUserScriptSync()) - + privacyDashboardScript.messageNames.forEach { messageName in webView.configuration.userContentController.add(privacyDashboardScript, name: messageName) } } - + private func loadPrivacyDashboardHTML(reportBrokenSiteOnly: Bool) { guard var url = Bundle.privacyDashboardURL else { return } - + if reportBrokenSiteOnly { url = url.appendingParameter(name: "screen", value: ProtectionState.EventOriginScreen.breakageForm.rawValue) } - + webView?.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent().deletingLastPathComponent()) } } @@ -145,15 +145,15 @@ extension PrivacyDashboardController: WKNavigationDelegate { public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { subscribeToDataModelChanges() - + sendProtectionStatus() sendParentEntity() sendCurrentLocale() } - + private func subscribeToDataModelChanges() { cancellables.removeAll() - + subscribeToTheme() subscribeToTrackerInfo() subscribeToConnectionUpgradedTo() @@ -161,7 +161,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { subscribeToConsentManaged() subscribeToAllowedPermissions() } - + private func subscribeToTheme() { $theme .removeDuplicates() @@ -183,7 +183,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func subscribeToConnectionUpgradedTo() { privacyInfo?.$connectionUpgradedTo .receive(on: DispatchQueue.main) @@ -194,7 +194,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func subscribeToServerTrust() { privacyInfo?.$serverTrust .receive(on: DispatchQueue.global(qos: .userInitiated)) @@ -208,7 +208,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func subscribeToConsentManaged() { privacyInfo?.$cookieConsentManaged .receive(on: DispatchQueue.main) @@ -218,7 +218,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func subscribeToAllowedPermissions() { $allowedPermissions .receive(on: DispatchQueue.main) @@ -228,23 +228,23 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func sendProtectionStatus() { guard let webView = self.webView, let protectionStatus = privacyInfo?.protectionStatus else { return } - + privacyDashboardScript.setProtectionStatus(protectionStatus, webView: webView) } - + private func sendParentEntity() { guard let webView = self.webView else { return } privacyDashboardScript.setParentEntity(privacyInfo?.parentEntity, webView: webView) } - + private func sendCurrentLocale() { guard let webView = self.webView else { return } - + let locale = preferredLocale ?? "en" privacyDashboardScript.setLocale(locale, webView: webView) } @@ -258,16 +258,16 @@ extension PrivacyDashboardController: PrivacyDashboardUserScriptDelegate { } func userScript(_ userScript: PrivacyDashboardUserScript, didChangeProtectionState protectionState: ProtectionState) { - + switch protectionState.eventOrigin.screen { case .primaryScreen: privacyDashboardDelegate?.privacyDashboardController(self, didChangeProtectionSwitch: protectionState) case .breakageForm: privacyDashboardReportBrokenSiteDelegate?.privacyDashboardController(self, reportBrokenSiteDidChangeProtectionSwitch: protectionState) } - + } - + func userScript(_ userScript: PrivacyDashboardUserScript, didRequestOpenUrlInNewTab url: URL) { privacyDashboardDelegate?.privacyDashboardController(self, didRequestOpenUrlInNewTab: url) } @@ -277,27 +277,27 @@ extension PrivacyDashboardController: PrivacyDashboardUserScriptDelegate { privacyDashboardNavigationDelegate?.privacyDashboardControllerDidTapClose(self) #endif } - + func userScriptDidRequestShowReportBrokenSite(_ userScript: PrivacyDashboardUserScript) { #if os(iOS) privacyDashboardDelegate?.privacyDashboardControllerDidRequestShowReportBrokenSite(self) #endif } - + func userScript(_ userScript: PrivacyDashboardUserScript, setHeight height: Int) { privacyDashboardNavigationDelegate?.privacyDashboardController(self, didSetHeight: height) } - + func userScript(_ userScript: PrivacyDashboardUserScript, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) { privacyDashboardReportBrokenSiteDelegate?.privacyDashboardController(self, didRequestSubmitBrokenSiteReportWithCategory: category, description: description) } - + func userScript(_ userScript: PrivacyDashboardUserScript, didSetPermission permission: String, to state: PermissionAuthorizationState) { #if os(macOS) privacyDashboardDelegate?.privacyDashboardController(self, didSetPermission: permission, to: state) #endif } - + func userScript(_ userScript: PrivacyDashboardUserScript, setPermission permission: String, paused: Bool) { #if os(macOS) privacyDashboardDelegate?.privacyDashboardController(self, setPermission: permission, paused: paused) diff --git a/Sources/PrivacyDashboard/PrivacyInfo.swift b/Sources/PrivacyDashboard/PrivacyInfo.swift index 41d937793..a4ca9265f 100644 --- a/Sources/PrivacyDashboard/PrivacyInfo.swift +++ b/Sources/PrivacyDashboard/PrivacyInfo.swift @@ -21,16 +21,16 @@ import TrackerRadarKit import Common public final class PrivacyInfo { - + public private(set) var url: URL private(set) var parentEntity: Entity? - + @Published public var trackerInfo: TrackerInfo @Published private(set) var protectionStatus: ProtectionStatus @Published public var serverTrust: SecTrust? @Published public var connectionUpgradedTo: URL? @Published public var cookieConsentManaged: CookieConsentInfo? - + public init(url: URL, parentEntity: Entity?, protectionStatus: ProtectionStatus) { self.url = url self.parentEntity = parentEntity @@ -38,15 +38,15 @@ public final class PrivacyInfo { trackerInfo = TrackerInfo() } - + public var https: Bool { return url.isHttps } - + public var domain: String? { return url.host } - + public func isFor(_ url: URL?) -> Bool { return self.url.host == url?.host } diff --git a/Sources/PrivacyDashboard/UserScript/PrivacyDashboardUserScript.swift b/Sources/PrivacyDashboard/UserScript/PrivacyDashboardUserScript.swift index 77b9c5c5e..5c57ef390 100644 --- a/Sources/PrivacyDashboard/UserScript/PrivacyDashboardUserScript.swift +++ b/Sources/PrivacyDashboard/UserScript/PrivacyDashboardUserScript.swift @@ -102,7 +102,7 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { handleOpenSettings(message: message) } } - + // MARK: - JS message handlers private func handleSetProtection(message: WKScriptMessage) { @@ -114,7 +114,7 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { delegate?.userScript(self, didChangeProtectionState: protectionState) } - + private func handleSetSize(message: WKScriptMessage) { guard let dict = message.body as? [String: Any], let height = dict["height"] as? Int else { @@ -128,11 +128,11 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { private func handleClose() { delegate?.userScriptDidRequestClosing(self) } - + private func handleShowReportBrokenSite() { delegate?.userScriptDidRequestShowReportBrokenSite(self) } - + private func handleSubmitBrokenSiteReport(message: WKScriptMessage) { guard let dict = message.body as? [String: Any], let category = dict["category"] as? String, @@ -143,7 +143,7 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { delegate?.userScript(self, didRequestSubmitBrokenSiteReportWithCategory: category, description: description) } - + private func handleOpenUrlInNewTab(message: WKScriptMessage) { guard let dict = message.body as? [String: Any], let urlString = dict["url"] as? String, @@ -192,7 +192,7 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { } // MARK: - Calls to script's JS API - + func setTrackerInfo(_ tabUrl: URL, trackerInfo: TrackerInfo, webView: WKWebView) { guard let trackerBlockingDataJson = try? JSONEncoder().encode(trackerInfo).utf8String() else { assertionFailure("Can't encode trackerInfoViewModel into JSON") @@ -212,7 +212,7 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { assertionFailure("Can't encode mockProtectionStatus into JSON") return } - + evaluate(js: "window.onChangeProtectionStatus(\(protectionStatusJson))", in: webView) } @@ -254,19 +254,19 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { func setIsPendingUpdates(_ isPendingUpdates: Bool, webView: WKWebView) { evaluate(js: "window.onIsPendingUpdates(\(isPendingUpdates))", in: webView) } - + func setLocale(_ currentLocale: String, webView: WKWebView) { struct LocaleSetting: Encodable { var locale: String } - + guard let localeSettingJson = try? JSONEncoder().encode(LocaleSetting(locale: currentLocale)).utf8String() else { assertionFailure("Can't encode consentInfo into JSON") return } evaluate(js: "window.onChangeLocale(\(localeSettingJson))", in: webView) } - + func setConsentManaged(_ consentManaged: CookieConsentInfo?, webView: WKWebView) { guard let consentDataJson = try? JSONEncoder().encode(consentManaged).utf8String() else { assertionFailure("Can't encode consentInfo into JSON") @@ -274,13 +274,13 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { } evaluate(js: "window.onChangeConsentManaged(\(consentDataJson))", in: webView) } - + func setPermissions(allowedPermissions: [AllowedPermission], webView: WKWebView) { guard let allowedPermissionsJson = try? JSONEncoder().encode(allowedPermissions).utf8String() else { assertionFailure("PrivacyDashboardUserScript: could not serialize permissions object") return } - + self.evaluate(js: "window.onChangeAllowedPermissions(\(allowedPermissionsJson))", in: webView) } From f0991ba42ed8d8850cbd47e2a9339a18450b041e Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Thu, 16 Nov 2023 12:36:29 +0000 Subject: [PATCH 06/12] privacy-dashboard now pointing to feature branch --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index c2279e3bb..97108e3d8 100644 --- a/Package.swift +++ b/Package.swift @@ -38,7 +38,7 @@ let package = Package( .package(url: "https://github.com/duckduckgo/sync_crypto", exact: "0.2.0"), .package(url: "https://github.com/gumob/PunycodeSwift.git", exact: "2.1.0"), .package(url: "https://github.com/duckduckgo/content-scope-scripts", exact: "4.40.0"), - .package(url: "https://github.com/duckduckgo/privacy-dashboard", exact: "2.0.0"), + .package(url: "https://github.com/duckduckgo/privacy-dashboard", .branch("shane/ios-form") ), .package(url: "https://github.com/httpswift/swifter.git", exact: "1.5.0"), .package(url: "https://github.com/duckduckgo/bloom_cpp.git", exact: "3.0.0"), .package(url: "https://github.com/duckduckgo/wireguard-apple", exact: "1.1.1") From 279f27bb1f8d9b706c15e10cf516db3c08ef5eb6 Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Thu, 16 Nov 2023 15:03:16 +0000 Subject: [PATCH 07/12] swiftlint fixes --- .../PrivacyDashboardController.swift | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Sources/PrivacyDashboard/PrivacyDashboardController.swift b/Sources/PrivacyDashboard/PrivacyDashboardController.swift index a6f10c0e2..1e2209dcd 100644 --- a/Sources/PrivacyDashboard/PrivacyDashboardController.swift +++ b/Sources/PrivacyDashboard/PrivacyDashboardController.swift @@ -38,21 +38,28 @@ public protocol PrivacyDashboardNavigationDelegate: AnyObject { /// `Report broken site` web page delegate public protocol PrivacyDashboardReportBrokenSiteDelegate: AnyObject { - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, reportBrokenSiteDidChangeProtectionSwitch protectionState: ProtectionState) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, + didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, + reportBrokenSiteDidChangeProtectionSwitch protectionState: ProtectionState) } /// `Privacy Dasboard` web page delegate public protocol PrivacyDashboardControllerDelegate: AnyObject { - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didChangeProtectionSwitch protectionState: ProtectionState) - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestOpenUrlInNewTab url: URL) - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestOpenSettings target: PrivacyDashboardOpenSettingsTarget) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, + didChangeProtectionSwitch protectionState: ProtectionState) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, + didRequestOpenUrlInNewTab url: URL) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, + didRequestOpenSettings target: PrivacyDashboardOpenSettingsTarget) func privacyDashboardControllerDidRequestShowReportBrokenSite(_ privacyDashboardController: PrivacyDashboardController) #if os(macOS) - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetPermission permissionName: String, to state: PermissionAuthorizationState) - func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, setPermission permissionName: String, paused: Bool) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, + didSetPermission permissionName: String, to state: PermissionAuthorizationState) + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, + setPermission permissionName: String, paused: Bool) #endif } @@ -289,7 +296,8 @@ extension PrivacyDashboardController: PrivacyDashboardUserScriptDelegate { } func userScript(_ userScript: PrivacyDashboardUserScript, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) { - privacyDashboardReportBrokenSiteDelegate?.privacyDashboardController(self, didRequestSubmitBrokenSiteReportWithCategory: category, description: description) + privacyDashboardReportBrokenSiteDelegate?.privacyDashboardController(self, didRequestSubmitBrokenSiteReportWithCategory: category, + description: description) } func userScript(_ userScript: PrivacyDashboardUserScript, didSetPermission permission: String, to state: PermissionAuthorizationState) { From 3beb9e40d9062b330a56b5af77f944a9aa6c39e3 Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Fri, 17 Nov 2023 14:57:03 +0000 Subject: [PATCH 08/12] privacy-dashboard dependency updated to 3.1.0 --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 97108e3d8..511e45f6a 100644 --- a/Package.swift +++ b/Package.swift @@ -38,7 +38,7 @@ let package = Package( .package(url: "https://github.com/duckduckgo/sync_crypto", exact: "0.2.0"), .package(url: "https://github.com/gumob/PunycodeSwift.git", exact: "2.1.0"), .package(url: "https://github.com/duckduckgo/content-scope-scripts", exact: "4.40.0"), - .package(url: "https://github.com/duckduckgo/privacy-dashboard", .branch("shane/ios-form") ), + .package(url: "https://github.com/duckduckgo/privacy-dashboard", exact: "3.1.0" ), .package(url: "https://github.com/httpswift/swifter.git", exact: "1.5.0"), .package(url: "https://github.com/duckduckgo/bloom_cpp.git", exact: "3.0.0"), .package(url: "https://github.com/duckduckgo/wireguard-apple", exact: "1.1.1") From ab4154a909cdd702620c4b5420b1ca185588ba0c Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Mon, 20 Nov 2023 14:18:18 +0000 Subject: [PATCH 09/12] white spaces reverted --- .../Model/AllowedPermission.swift | 2 +- .../PrivacyDashboard/Model/TrackerInfo.swift | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Sources/PrivacyDashboard/Model/AllowedPermission.swift b/Sources/PrivacyDashboard/Model/AllowedPermission.swift index c4d36e9ea..1d73c60e3 100644 --- a/Sources/PrivacyDashboard/Model/AllowedPermission.swift +++ b/Sources/PrivacyDashboard/Model/AllowedPermission.swift @@ -26,7 +26,7 @@ public struct AllowedPermission: Codable { var used: Bool var paused: Bool var options: [[String: String]] - + public init(key: String, icon: String, title: String, diff --git a/Sources/PrivacyDashboard/Model/TrackerInfo.swift b/Sources/PrivacyDashboard/Model/TrackerInfo.swift index 5494c40da..8b5b051b7 100644 --- a/Sources/PrivacyDashboard/Model/TrackerInfo.swift +++ b/Sources/PrivacyDashboard/Model/TrackerInfo.swift @@ -21,51 +21,51 @@ import TrackerRadarKit import ContentBlocking public struct TrackerInfo: Encodable { - + enum CodingKeys: String, CodingKey { case requests case installedSurrogates } - + public private (set) var trackers = Set() private(set) var thirdPartyRequests = Set() public private(set) var installedSurrogates = Set() - + public init() { } - + // MARK: - Collecting detected elements - + public mutating func addDetectedTracker(_ tracker: DetectedRequest, onPageWithURL url: URL) { guard tracker.pageUrl == url.absoluteString else { return } trackers.insert(tracker) } - + public mutating func add(detectedThirdPartyRequest request: DetectedRequest) { thirdPartyRequests.insert(request) } - + public mutating func addInstalledSurrogateHost(_ host: String, for tracker: DetectedRequest, onPageWithURL url: URL) { guard tracker.pageUrl == url.absoluteString else { return } installedSurrogates.insert(host) } - + // MARK: - Helper accessors - + public var trackersBlocked: [DetectedRequest] { trackers.filter { $0.state == .blocked } } - + public var trackersDetected: [DetectedRequest] { trackers.filter { $0.state != .blocked } } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - + let allRequests = [] + trackers + thirdPartyRequests - + try container.encode(allRequests, forKey: .requests) try container.encode(installedSurrogates, forKey: .installedSurrogates) } - + } From beb710e6ce2b1a887d85b65fbbd66f26b05e31cc Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Mon, 20 Nov 2023 14:40:05 +0000 Subject: [PATCH 10/12] white spaces fix --- .../Model/CookieConsentInfo.swift | 2 +- .../Model/ProtectionStatus.swift | 4 +- .../PrivacyDashboardController.swift | 98 +++++++++---------- Sources/PrivacyDashboard/PrivacyInfo.swift | 14 +-- 4 files changed, 59 insertions(+), 59 deletions(-) diff --git a/Sources/PrivacyDashboard/Model/CookieConsentInfo.swift b/Sources/PrivacyDashboard/Model/CookieConsentInfo.swift index c86872932..475d24931 100644 --- a/Sources/PrivacyDashboard/Model/CookieConsentInfo.swift +++ b/Sources/PrivacyDashboard/Model/CookieConsentInfo.swift @@ -24,7 +24,7 @@ public struct CookieConsentInfo: Encodable { let optoutFailed: Bool? let selftestFailed: Bool? let configurable = true - + public init(consentManaged: Bool, cosmetic: Bool?, optoutFailed: Bool?, selftestFailed: Bool?) { self.consentManaged = consentManaged self.cosmetic = cosmetic diff --git a/Sources/PrivacyDashboard/Model/ProtectionStatus.swift b/Sources/PrivacyDashboard/Model/ProtectionStatus.swift index bc2de57f7..2fc310faa 100644 --- a/Sources/PrivacyDashboard/Model/ProtectionStatus.swift +++ b/Sources/PrivacyDashboard/Model/ProtectionStatus.swift @@ -20,12 +20,12 @@ import Foundation public struct ProtectionStatus: Encodable { - + let unprotectedTemporary: Bool let enabledFeatures: [String] let allowlisted: Bool let denylisted: Bool - + public init(unprotectedTemporary: Bool, enabledFeatures: [String], allowlisted: Bool, denylisted: Bool) { self.unprotectedTemporary = unprotectedTemporary self.enabledFeatures = enabledFeatures diff --git a/Sources/PrivacyDashboard/PrivacyDashboardController.swift b/Sources/PrivacyDashboard/PrivacyDashboardController.swift index 1e2209dcd..b3df002c8 100644 --- a/Sources/PrivacyDashboard/PrivacyDashboardController.swift +++ b/Sources/PrivacyDashboard/PrivacyDashboardController.swift @@ -31,13 +31,13 @@ public protocol PrivacyDashboardNavigationDelegate: AnyObject { #if os(iOS) func privacyDashboardControllerDidTapClose(_ privacyDashboardController: PrivacyDashboardController) #endif - + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetHeight height: Int) } /// `Report broken site` web page delegate public protocol PrivacyDashboardReportBrokenSiteDelegate: AnyObject { - + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, @@ -46,7 +46,7 @@ public protocol PrivacyDashboardReportBrokenSiteDelegate: AnyObject { /// `Privacy Dasboard` web page delegate public protocol PrivacyDashboardControllerDelegate: AnyObject { - + func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didChangeProtectionSwitch protectionState: ProtectionState) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, @@ -54,7 +54,7 @@ public protocol PrivacyDashboardControllerDelegate: AnyObject { func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didRequestOpenSettings target: PrivacyDashboardOpenSettingsTarget) func privacyDashboardControllerDidRequestShowReportBrokenSite(_ privacyDashboardController: PrivacyDashboardController) - + #if os(macOS) func privacyDashboardController(_ privacyDashboardController: PrivacyDashboardController, didSetPermission permissionName: String, to state: PermissionAuthorizationState) @@ -68,25 +68,25 @@ public protocol PrivacyDashboardControllerDelegate: AnyObject { /// 2- Direct access to the `Report broken site` page /// Which flow is used is decided at `setup(...)` time, where if `reportBrokenSiteOnly` is true then the `Report broken site` page is opened directly. @MainActor public final class PrivacyDashboardController: NSObject { - + // Delegates public weak var privacyDashboardDelegate: PrivacyDashboardControllerDelegate? public weak var privacyDashboardNavigationDelegate: PrivacyDashboardNavigationDelegate? public weak var privacyDashboardReportBrokenSiteDelegate: PrivacyDashboardReportBrokenSiteDelegate? - + @Published public var theme: PrivacyDashboardTheme? public var preferredLocale: String? @Published public var allowedPermissions: [AllowedPermission] = [] public private(set) weak var privacyInfo: PrivacyInfo? - + private weak var webView: WKWebView? private let privacyDashboardScript = PrivacyDashboardUserScript() private var cancellables = Set() - + public init(privacyInfo: PrivacyInfo?) { self.privacyInfo = privacyInfo } - + /// Configure the webview for showing `Privacy Dasboard` or `Report broken site` /// - Parameters: /// - webView: The webview to use @@ -94,73 +94,73 @@ public protocol PrivacyDashboardControllerDelegate: AnyObject { public func setup(for webView: WKWebView, reportBrokenSiteOnly: Bool) { self.webView = webView webView.navigationDelegate = self - + setupPrivacyDashboardUserScript() loadPrivacyDashboardHTML(reportBrokenSiteOnly: reportBrokenSiteOnly) } - + public func updatePrivacyInfo(_ privacyInfo: PrivacyInfo?) { cancellables.removeAll() self.privacyInfo = privacyInfo - + subscribeToDataModelChanges() sendProtectionStatus() } - + public func cleanUp() { cancellables.removeAll() - + privacyDashboardScript.messageNames.forEach { messageName in webView?.configuration.userContentController.removeScriptMessageHandler(forName: messageName) } } - + public func didStartRulesCompilation() { guard let webView = self.webView else { return } privacyDashboardScript.setIsPendingUpdates(true, webView: webView) } - + public func didFinishRulesCompilation() { guard let webView = self.webView else { return } privacyDashboardScript.setIsPendingUpdates(false, webView: webView) } - + private func setupPrivacyDashboardUserScript() { guard let webView = self.webView else { return } - + privacyDashboardScript.delegate = self - + webView.configuration.userContentController.addUserScript(privacyDashboardScript.makeWKUserScriptSync()) - + privacyDashboardScript.messageNames.forEach { messageName in webView.configuration.userContentController.add(privacyDashboardScript, name: messageName) } } - + private func loadPrivacyDashboardHTML(reportBrokenSiteOnly: Bool) { guard var url = Bundle.privacyDashboardURL else { return } - + if reportBrokenSiteOnly { url = url.appendingParameter(name: "screen", value: ProtectionState.EventOriginScreen.breakageForm.rawValue) } - + webView?.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent().deletingLastPathComponent()) } } extension PrivacyDashboardController: WKNavigationDelegate { - + public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { subscribeToDataModelChanges() - + sendProtectionStatus() sendParentEntity() sendCurrentLocale() } - + private func subscribeToDataModelChanges() { cancellables.removeAll() - + subscribeToTheme() subscribeToTrackerInfo() subscribeToConnectionUpgradedTo() @@ -168,7 +168,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { subscribeToConsentManaged() subscribeToAllowedPermissions() } - + private func subscribeToTheme() { $theme .removeDuplicates() @@ -179,7 +179,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func subscribeToTrackerInfo() { privacyInfo?.$trackerInfo .receive(on: DispatchQueue.main) @@ -190,7 +190,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func subscribeToConnectionUpgradedTo() { privacyInfo?.$connectionUpgradedTo .receive(on: DispatchQueue.main) @@ -201,7 +201,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func subscribeToServerTrust() { privacyInfo?.$serverTrust .receive(on: DispatchQueue.global(qos: .userInitiated)) @@ -215,7 +215,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func subscribeToConsentManaged() { privacyInfo?.$cookieConsentManaged .receive(on: DispatchQueue.main) @@ -225,7 +225,7 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func subscribeToAllowedPermissions() { $allowedPermissions .receive(on: DispatchQueue.main) @@ -235,77 +235,77 @@ extension PrivacyDashboardController: WKNavigationDelegate { }) .store(in: &cancellables) } - + private func sendProtectionStatus() { guard let webView = self.webView, let protectionStatus = privacyInfo?.protectionStatus else { return } - + privacyDashboardScript.setProtectionStatus(protectionStatus, webView: webView) } - + private func sendParentEntity() { guard let webView = self.webView else { return } privacyDashboardScript.setParentEntity(privacyInfo?.parentEntity, webView: webView) } - + private func sendCurrentLocale() { guard let webView = self.webView else { return } - + let locale = preferredLocale ?? "en" privacyDashboardScript.setLocale(locale, webView: webView) } } extension PrivacyDashboardController: PrivacyDashboardUserScriptDelegate { - + func userScript(_ userScript: PrivacyDashboardUserScript, didRequestOpenSettings target: String) { let settingsTarget = PrivacyDashboardOpenSettingsTarget(rawValue: target) ?? .general privacyDashboardDelegate?.privacyDashboardController(self, didRequestOpenSettings: settingsTarget) } - + func userScript(_ userScript: PrivacyDashboardUserScript, didChangeProtectionState protectionState: ProtectionState) { - + switch protectionState.eventOrigin.screen { case .primaryScreen: privacyDashboardDelegate?.privacyDashboardController(self, didChangeProtectionSwitch: protectionState) case .breakageForm: privacyDashboardReportBrokenSiteDelegate?.privacyDashboardController(self, reportBrokenSiteDidChangeProtectionSwitch: protectionState) } - + } - + func userScript(_ userScript: PrivacyDashboardUserScript, didRequestOpenUrlInNewTab url: URL) { privacyDashboardDelegate?.privacyDashboardController(self, didRequestOpenUrlInNewTab: url) } - + func userScriptDidRequestClosing(_ userScript: PrivacyDashboardUserScript) { #if os(iOS) privacyDashboardNavigationDelegate?.privacyDashboardControllerDidTapClose(self) #endif } - + func userScriptDidRequestShowReportBrokenSite(_ userScript: PrivacyDashboardUserScript) { #if os(iOS) privacyDashboardDelegate?.privacyDashboardControllerDidRequestShowReportBrokenSite(self) #endif } - + func userScript(_ userScript: PrivacyDashboardUserScript, setHeight height: Int) { privacyDashboardNavigationDelegate?.privacyDashboardController(self, didSetHeight: height) } - + func userScript(_ userScript: PrivacyDashboardUserScript, didRequestSubmitBrokenSiteReportWithCategory category: String, description: String) { privacyDashboardReportBrokenSiteDelegate?.privacyDashboardController(self, didRequestSubmitBrokenSiteReportWithCategory: category, description: description) } - + func userScript(_ userScript: PrivacyDashboardUserScript, didSetPermission permission: String, to state: PermissionAuthorizationState) { #if os(macOS) privacyDashboardDelegate?.privacyDashboardController(self, didSetPermission: permission, to: state) #endif } - + func userScript(_ userScript: PrivacyDashboardUserScript, setPermission permission: String, paused: Bool) { #if os(macOS) privacyDashboardDelegate?.privacyDashboardController(self, setPermission: permission, paused: paused) diff --git a/Sources/PrivacyDashboard/PrivacyInfo.swift b/Sources/PrivacyDashboard/PrivacyInfo.swift index a4ca9265f..fd488e382 100644 --- a/Sources/PrivacyDashboard/PrivacyInfo.swift +++ b/Sources/PrivacyDashboard/PrivacyInfo.swift @@ -21,32 +21,32 @@ import TrackerRadarKit import Common public final class PrivacyInfo { - + public private(set) var url: URL private(set) var parentEntity: Entity? - + @Published public var trackerInfo: TrackerInfo @Published private(set) var protectionStatus: ProtectionStatus @Published public var serverTrust: SecTrust? @Published public var connectionUpgradedTo: URL? @Published public var cookieConsentManaged: CookieConsentInfo? - + public init(url: URL, parentEntity: Entity?, protectionStatus: ProtectionStatus) { self.url = url self.parentEntity = parentEntity self.protectionStatus = protectionStatus - + trackerInfo = TrackerInfo() } - + public var https: Bool { return url.isHttps } - + public var domain: String? { return url.host } - + public func isFor(_ url: URL?) -> Bool { return self.url.host == url?.host } From 59125174e049f1ab8e995dbd26378eb2a78eaa38 Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Mon, 20 Nov 2023 14:43:49 +0000 Subject: [PATCH 11/12] indentation fix --- .../PrivacyDashboardUserScript.swift | 100 +++++++++--------- .../ViewModel/ServerTrustViewModel.swift | 52 ++++----- 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/Sources/PrivacyDashboard/UserScript/PrivacyDashboardUserScript.swift b/Sources/PrivacyDashboard/UserScript/PrivacyDashboardUserScript.swift index 5c57ef390..1df481f4d 100644 --- a/Sources/PrivacyDashboard/UserScript/PrivacyDashboardUserScript.swift +++ b/Sources/PrivacyDashboard/UserScript/PrivacyDashboardUserScript.swift @@ -42,11 +42,11 @@ public enum PrivacyDashboardTheme: String, Encodable { public struct ProtectionState: Decodable { public let isProtected: Bool public let eventOrigin: EventOrigin - + public struct EventOrigin: Decodable { public let screen: EventOriginScreen } - + public enum EventOriginScreen: String, Decodable { case primaryScreen case breakageForm @@ -54,7 +54,7 @@ public struct ProtectionState: Decodable { } final class PrivacyDashboardUserScript: NSObject, StaticUserScript { - + enum MessageNames: String, CaseIterable { case privacyDashboardSetProtection case privacyDashboardSetSize @@ -66,21 +66,21 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { case privacyDashboardSetPermission case privacyDashboardSetPermissionPaused } - + static var injectionTime: WKUserScriptInjectionTime { .atDocumentStart } static var forMainFrameOnly: Bool { false } static var source: String = "" static var script: WKUserScript = PrivacyDashboardUserScript.makeWKUserScript() var messageNames: [String] { MessageNames.allCases.map(\.rawValue) } - + weak var delegate: PrivacyDashboardUserScriptDelegate? - + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard let messageType = MessageNames(rawValue: message.name) else { assertionFailure("PrivacyDashboardUserScript: unexpected message name \(message.name)") return } - + switch messageType { case .privacyDashboardSetProtection: handleSetProtection(message: message) @@ -102,37 +102,37 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { handleOpenSettings(message: message) } } - + // MARK: - JS message handlers - + private func handleSetProtection(message: WKScriptMessage) { - + guard let protectionState: ProtectionState = DecodableHelper.decode(from: message.messageBody) else { assertionFailure("privacyDashboardSetProtection: expected ProtectionState") return } - + delegate?.userScript(self, didChangeProtectionState: protectionState) } - + private func handleSetSize(message: WKScriptMessage) { guard let dict = message.body as? [String: Any], let height = dict["height"] as? Int else { assertionFailure("privacyDashboardSetHeight: expected height to be an Int") return } - + delegate?.userScript(self, setHeight: height) } - + private func handleClose() { delegate?.userScriptDidRequestClosing(self) } - + private func handleShowReportBrokenSite() { delegate?.userScriptDidRequestShowReportBrokenSite(self) } - + private func handleSubmitBrokenSiteReport(message: WKScriptMessage) { guard let dict = message.body as? [String: Any], let category = dict["category"] as? String, @@ -140,10 +140,10 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { assertionFailure("privacyDashboardSetHeight: expected { category: String, description: String }") return } - + delegate?.userScript(self, didRequestSubmitBrokenSiteReportWithCategory: category, description: description) } - + private func handleOpenUrlInNewTab(message: WKScriptMessage) { guard let dict = message.body as? [String: Any], let urlString = dict["url"] as? String, @@ -152,10 +152,10 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { assertionFailure("handleOpenUrlInNewTab: expected { url: '...' } ") return } - + delegate?.userScript(self, didRequestOpenUrlInNewTab: url) } - + private func handleOpenSettings(message: WKScriptMessage) { guard let dict = message.body as? [String: Any], let target = dict["target"] as? String @@ -163,10 +163,10 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { assertionFailure("handleOpenSettings: expected { target: '...' } ") return } - + delegate?.userScript(self, didRequestOpenSettings: target) } - + private func handleSetPermission(message: WKScriptMessage) { guard let dict = message.body as? [String: Any], let permission = dict["permission"] as? String, @@ -175,10 +175,10 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { assertionFailure("privacyDashboardSetPermission: expected { permission: PermissionType, value: PermissionAuthorizationState }") return } - + delegate?.userScript(self, didSetPermission: permission, to: state) } - + private func handleSetPermissionPaused(message: WKScriptMessage) { guard let dict = message.body as? [String: Any], let permission = dict["permission"] as? String, @@ -187,86 +187,86 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { assertionFailure("handleSetPermissionPaused: expected { permission: PermissionType, paused: Bool }") return } - + delegate?.userScript(self, setPermission: permission, paused: paused) } - + // MARK: - Calls to script's JS API - + func setTrackerInfo(_ tabUrl: URL, trackerInfo: TrackerInfo, webView: WKWebView) { guard let trackerBlockingDataJson = try? JSONEncoder().encode(trackerInfo).utf8String() else { assertionFailure("Can't encode trackerInfoViewModel into JSON") return } - + guard let safeTabUrl = try? JSONEncoder().encode(tabUrl).utf8String() else { assertionFailure("Can't encode tabUrl into JSON") return } - + evaluate(js: "window.onChangeRequestData(\(safeTabUrl), \(trackerBlockingDataJson))", in: webView) } - + func setProtectionStatus(_ protectionStatus: ProtectionStatus, webView: WKWebView) { guard let protectionStatusJson = try? JSONEncoder().encode(protectionStatus).utf8String() else { assertionFailure("Can't encode mockProtectionStatus into JSON") return } - + evaluate(js: "window.onChangeProtectionStatus(\(protectionStatusJson))", in: webView) } - + func setUpgradedHttps(_ upgradedHttps: Bool, webView: WKWebView) { evaluate(js: "window.onChangeUpgradedHttps(\(upgradedHttps))", in: webView) } - + func setParentEntity(_ parentEntity: Entity?, webView: WKWebView) { if parentEntity == nil { return } - + guard let parentEntityJson = try? JSONEncoder().encode(parentEntity).utf8String() else { assertionFailure("Can't encode parentEntity into JSON") return } - + evaluate(js: "window.onChangeParentEntity(\(parentEntityJson))", in: webView) } - + func setTheme(_ theme: PrivacyDashboardTheme?, webView: WKWebView) { if theme == nil { return } - + guard let themeJson = try? JSONEncoder().encode(theme).utf8String() else { assertionFailure("Can't encode themeName into JSON") return } - + evaluate(js: "window.onChangeTheme(\(themeJson))", in: webView) } - + func setServerTrust(_ serverTrustViewModel: ServerTrustViewModel, webView: WKWebView) { guard let certificateDataJson = try? JSONEncoder().encode(serverTrustViewModel).utf8String() else { assertionFailure("Can't encode serverTrustViewModel into JSON") return } - + evaluate(js: "window.onChangeCertificateData(\(certificateDataJson))", in: webView) } - + func setIsPendingUpdates(_ isPendingUpdates: Bool, webView: WKWebView) { evaluate(js: "window.onIsPendingUpdates(\(isPendingUpdates))", in: webView) } - + func setLocale(_ currentLocale: String, webView: WKWebView) { struct LocaleSetting: Encodable { var locale: String } - + guard let localeSettingJson = try? JSONEncoder().encode(LocaleSetting(locale: currentLocale)).utf8String() else { assertionFailure("Can't encode consentInfo into JSON") return } evaluate(js: "window.onChangeLocale(\(localeSettingJson))", in: webView) } - + func setConsentManaged(_ consentManaged: CookieConsentInfo?, webView: WKWebView) { guard let consentDataJson = try? JSONEncoder().encode(consentManaged).utf8String() else { assertionFailure("Can't encode consentInfo into JSON") @@ -274,26 +274,26 @@ final class PrivacyDashboardUserScript: NSObject, StaticUserScript { } evaluate(js: "window.onChangeConsentManaged(\(consentDataJson))", in: webView) } - + func setPermissions(allowedPermissions: [AllowedPermission], webView: WKWebView) { guard let allowedPermissionsJson = try? JSONEncoder().encode(allowedPermissions).utf8String() else { assertionFailure("PrivacyDashboardUserScript: could not serialize permissions object") return } - + self.evaluate(js: "window.onChangeAllowedPermissions(\(allowedPermissionsJson))", in: webView) } - + private func evaluate(js: String, in webView: WKWebView) { webView.evaluateJavaScript(js) } - + } extension Data { - + func utf8String() -> String? { return String(data: self, encoding: .utf8) } - + } diff --git a/Sources/PrivacyDashboard/ViewModel/ServerTrustViewModel.swift b/Sources/PrivacyDashboard/ViewModel/ServerTrustViewModel.swift index eb94d1db3..0862cb89d 100644 --- a/Sources/PrivacyDashboard/ViewModel/ServerTrustViewModel.swift +++ b/Sources/PrivacyDashboard/ViewModel/ServerTrustViewModel.swift @@ -19,28 +19,28 @@ import Foundation public struct ServerTrustViewModel: Encodable { - + struct SecCertificateViewModel: Encodable { - + let summary: String? let commonName: String? let emails: [String]? let publicKey: SecKeyViewModel? - + public init(secCertificate: SecCertificate) { summary = SecCertificateCopySubjectSummary(secCertificate) as String? ?? "" - + var commonName: CFString? SecCertificateCopyCommonName(secCertificate, &commonName) self.commonName = commonName as String? ?? "" - + var emails: CFArray? if errSecSuccess == SecCertificateCopyEmailAddresses(secCertificate, &emails) { self.emails = emails as? [String] } else { self.emails = nil } - + var secTrust: SecTrust? if errSecSuccess == SecTrustCreateWithCertificates(secCertificate, SecPolicyCreateBasicX509(), &secTrust), let certTrust = secTrust { if #available(iOS 14.0, macOS 11.0, *) { @@ -53,11 +53,11 @@ public struct ServerTrustViewModel: Encodable { publicKey = nil } } - + } - + struct SecKeyViewModel: Encodable { - + static func typeToString(_ type: String) -> String? { switch type as CFString { case kSecAttrKeyTypeRSA: return "RSA" @@ -66,14 +66,14 @@ public struct ServerTrustViewModel: Encodable { default: return nil } } - + let keyId: Data? let externalRepresentation: Data? - + let bitSize: Int? let blockSize: Int? let effectiveSize: Int? - + let canDecrypt: Bool let canDerive: Bool let canEncrypt: Bool @@ -81,20 +81,20 @@ public struct ServerTrustViewModel: Encodable { let canUnwrap: Bool let canVerify: Bool let canWrap: Bool - + let isPermanent: Bool? let type: String? - + init?(secKey: SecKey?) { guard let secKey = secKey else { return nil } - + blockSize = SecKeyGetBlockSize(secKey) externalRepresentation = SecKeyCopyExternalRepresentation(secKey, nil) as Data? - + let attrs: NSDictionary? = SecKeyCopyAttributes(secKey) - + bitSize = attrs?[kSecAttrKeySizeInBits] as? Int effectiveSize = attrs?[kSecAttrEffectiveKeySize] as? Int canDecrypt = attrs?[kSecAttrCanDecrypt] as? Bool ?? false @@ -106,36 +106,36 @@ public struct ServerTrustViewModel: Encodable { canWrap = attrs?[kSecAttrCanWrap] as? Bool ?? false isPermanent = attrs?[kSecAttrIsPermanent] as? Bool ?? false keyId = attrs?[kSecAttrApplicationLabel] as? Data - + if let type = attrs?[kSecAttrType] as? String { self.type = Self.typeToString(type) } else { self.type = nil } - + } - + } - + let secCertificateViewModels: [SecCertificateViewModel] - + public init?(serverTrust: SecTrust?) { guard let serverTrust = serverTrust else { return nil } - + let secTrust = serverTrust let count = SecTrustGetCertificateCount(secTrust) guard count != 0 else { return nil } - + var secCertificateViewModels = [SecCertificateViewModel]() for i in 0 ..< count { guard let certificate = SecTrustGetCertificateAtIndex(secTrust, i) else { return nil } let certificateViewModel = SecCertificateViewModel(secCertificate: certificate) secCertificateViewModels.append(certificateViewModel) } - + self.secCertificateViewModels = secCertificateViewModels } - + } From 3820c6b6387b163e69d1ed55a9893b4c3aa6a32d Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Wed, 6 Dec 2023 09:54:05 +0000 Subject: [PATCH 12/12] API enabled in macos --- Package.resolved | 4 ++-- Sources/PrivacyDashboard/PrivacyDashboardController.swift | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Package.resolved b/Package.resolved index 450099eed..98582486d 100644 --- a/Package.resolved +++ b/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/privacy-dashboard", "state" : { - "revision" : "daa9708223b4b4318fb6448ca44801dfabcddc6f", - "version" : "3.0.0" + "revision" : "59dedf0f4ff1e9147de0806a54c6043861eb0870", + "version" : "3.1.0" } }, { diff --git a/Sources/PrivacyDashboard/PrivacyDashboardController.swift b/Sources/PrivacyDashboard/PrivacyDashboardController.swift index b3df002c8..9c715d5ef 100644 --- a/Sources/PrivacyDashboard/PrivacyDashboardController.swift +++ b/Sources/PrivacyDashboard/PrivacyDashboardController.swift @@ -286,9 +286,7 @@ extension PrivacyDashboardController: PrivacyDashboardUserScriptDelegate { } func userScriptDidRequestShowReportBrokenSite(_ userScript: PrivacyDashboardUserScript) { -#if os(iOS) privacyDashboardDelegate?.privacyDashboardControllerDidRequestShowReportBrokenSite(self) -#endif } func userScript(_ userScript: PrivacyDashboardUserScript, setHeight height: Int) {