Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trigger the Cookie Hidden animation early for filterlist rules #3584

Merged
merged 7 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 51 additions & 19 deletions DuckDuckGo/Autoconsent/AutoconsentUserScript.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ final class AutoconsentUserScript: NSObject, WKScriptMessageHandlerWithReply, Us
let consentStatus = CookieConsentInfo(
consentManaged: consentManaged, cosmetic: cosmetic, optoutFailed: optoutFailed, selftestFailed: selftestFailed
)
Logger.autoconsent.debug("Refreshing dashboard state: \(String(describing: consentStatus))")
Logger.autoconsent.info("Refreshing dashboard state: \(String(describing: consentStatus))")
muodov marked this conversation as resolved.
Show resolved Hide resolved
self.delegate?.autoconsentUserScript(consentStatus: consentStatus)
}

Expand Down Expand Up @@ -171,13 +171,12 @@ extension AutoconsentUserScript {
case MessageName.eval:
handleEval(message: message, replyHandler: replyHandler)
case MessageName.popupFound:
Logger.autoconsent.debug("Autoconsent popup found")
replyHandler([ "type": "ok" ], nil) // this is just to prevent a Promise rejection
handlePopupFound(message: message, replyHandler: replyHandler)
case MessageName.optOutResult:
handleOptOutResult(message: message, replyHandler: replyHandler)
case MessageName.optInResult:
// this is not supported in browser
Logger.autoconsent.debug("ignoring optInResult: \(String(describing: message.body))")
Logger.autoconsent.info("ignoring optInResult: \(String(describing: message.body))")
replyHandler(nil, "opt-in is not supported")
case MessageName.cmpDetected:
// no need to do anything here
Expand All @@ -187,7 +186,7 @@ extension AutoconsentUserScript {
case MessageName.autoconsentDone:
handleAutoconsentDone(message: message, replyHandler: replyHandler)
case MessageName.autoconsentError:
Logger.autoconsent.debug("Autoconsent error: \(String(describing: message.body))")
Logger.autoconsent.error("Autoconsent error: \(String(describing: message.body))")
replyHandler([ "type": "ok" ], nil) // this is just to prevent a Promise rejection
}
}
Expand All @@ -205,7 +204,7 @@ extension AutoconsentUserScript {

guard url.navigationalScheme?.isHypertextScheme == true else {
// ignore special schemes
Logger.autoconsent.debug("Ignoring special URL scheme: \(messageData.url)")
Logger.autoconsent.info("Ignoring special URL scheme: \(messageData.url)")
replyHandler([ "type": "ok" ], nil) // this is just to prevent a Promise rejection
return
}
Expand Down Expand Up @@ -291,13 +290,44 @@ extension AutoconsentUserScript {
}
}

@MainActor
func handlePopupFound(message: WKScriptMessage, replyHandler: @escaping (Any?, String?) -> Void) {
guard let messageData: PopupFoundMessage = decodeMessageBody(from: message.body) else {
replyHandler(nil, "cannot decode message")
return
}
Logger.autoconsent.info("Cookie popup found: \(String(describing: messageData))")
guard let url = URL(string: messageData.url),
let host = url.host else {
replyHandler(nil, "cannot decode message")
return
}
muodov marked this conversation as resolved.
Show resolved Hide resolved

if messageData.cmp == "filterList" {
muodov marked this conversation as resolved.
Show resolved Hide resolved
refreshDashboardState(consentManaged: true, cosmetic: true, optoutFailed: false, selftestFailed: nil)
// trigger animation, but do not cache it because it can still be overridden
if !management.sitesNotifiedCache.contains(host) {
Logger.autoconsent.info("Starting animation for cosmetic filters")
// post popover notification on main thread
DispatchQueue.main.async {
muodov marked this conversation as resolved.
Show resolved Hide resolved
NotificationCenter.default.post(name: Self.newSitePopupHiddenNotification, object: self, userInfo: [
"topUrl": self.topUrl ?? url,
"isCosmetic": true
])
}
}
}

replyHandler([ "type": "ok" ], nil) // this is just to prevent a Promise rejection
}

@MainActor
func handleOptOutResult(message: WKScriptMessage, replyHandler: @escaping (Any?, String?) -> Void) {
guard let messageData: OptOutResultMessage = decodeMessageBody(from: message.body) else {
replyHandler(nil, "cannot decode message")
return
}
Logger.autoconsent.debug("opt-out result: \(String(describing: messageData))")
Logger.autoconsent.info("opt-out result: \(String(describing: messageData))")

if !messageData.result {
refreshDashboardState(consentManaged: true, cosmetic: nil, optoutFailed: true, selftestFailed: nil)
Expand All @@ -317,7 +347,7 @@ extension AutoconsentUserScript {
replyHandler(nil, "cannot decode message")
return
}
Logger.autoconsent.debug("opt-out successful: \(String(describing: messageData))")
Logger.autoconsent.info("opt-out successful: \(String(describing: messageData))")

guard let url = URL(string: messageData.url),
let host = url.host else {
Expand All @@ -329,22 +359,24 @@ extension AutoconsentUserScript {

// trigger popup once per domain
if !management.sitesNotifiedCache.contains(host) {
Logger.autoconsent.debug("bragging that we closed a popup")
management.sitesNotifiedCache.insert(host)
// post popover notification on main thread
DispatchQueue.main.async {
NotificationCenter.default.post(name: Self.newSitePopupHiddenNotification, object: self, userInfo: [
"topUrl": self.topUrl ?? url,
"isCosmetic": messageData.isCosmetic
])
if messageData.cmp != "filterList" { // filterlist animation should have been triggered already (see handlePopupFound)
Logger.autoconsent.info("Starting animation for the handled cookie popup")
// post popover notification on main thread
DispatchQueue.main.async {
NotificationCenter.default.post(name: Self.newSitePopupHiddenNotification, object: self, userInfo: [
"topUrl": self.topUrl ?? url,
"isCosmetic": messageData.isCosmetic
])
}
}
}

replyHandler([ "type": "ok" ], nil) // this is just to prevent a Promise rejection

if let selfTestWebView = selfTestWebView,
let selfTestFrameInfo = selfTestFrameInfo {
Logger.autoconsent.debug("requesting self-test in: \(messageData.url)")
Logger.autoconsent.info("requesting self-test in: \(messageData.url)")
selfTestWebView.evaluateJavaScript(
"window.autoconsentMessageCallback({ type: 'selfTest' })",
in: selfTestFrameInfo,
Expand All @@ -354,12 +386,12 @@ extension AutoconsentUserScript {
case.failure(let error):
Logger.autoconsent.error("Error running self-test: \(error.localizedDescription, privacy: .public)")
case.success:
Logger.autoconsent.debug("self-test requested")
Logger.autoconsent.info("self-test requested")
}
}
)
} else {
Logger.autoconsent.debug("no self-test scheduled in this tab")
Logger.autoconsent.error("no self-test scheduled in this tab")
}
selfTestWebView = nil
selfTestFrameInfo = nil
Expand All @@ -372,7 +404,7 @@ extension AutoconsentUserScript {
return
}
// store self-test result
Logger.autoconsent.debug("self-test result: \(String(describing: messageData))")
Logger.autoconsent.info("self-test result: \(String(describing: messageData))")
refreshDashboardState(consentManaged: true, cosmetic: nil, optoutFailed: false, selftestFailed: messageData.result)
replyHandler([ "type": "ok" ], nil) // this is just to prevent a Promise rejection
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class AutoconsentMessageProtocolTests: XCTestCase {
let message = MockWKScriptMessage(name: "popupFound", body: [
"type": "popupFound",
"cmp": "some cmp",
"url": "some url"
"url": "https://example.com"
])
userScript.handleMessage(
replyHandler: {(msg: Any?, _: String?) in
Expand Down
Loading