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

BSK support for FB CTL update #760

Merged
merged 25 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1859341
BSK support for FB CTL update
ladamski Apr 4, 2024
7da4543
revert var
ladamski Apr 5, 2024
8c20736
fix surrogate tests
ladamski Apr 6, 2024
293641a
TEMP: update TRK dep
ladamski Apr 7, 2024
9ab5d7d
update feature name to clickToLoad
ladamski Apr 15, 2024
99b4f8f
surrogates.js cleanup
ladamski Apr 15, 2024
717db16
handle blockCtlFB in TrackerResolver
ladamski Apr 19, 2024
9ec8813
update TrackerRadarKit to production release
ladamski May 17, 2024
1a4a2b8
Merge branch 'main' into la/clicktoload-redux
jaceklyp May 21, 2024
134d01b
review nits and related TRK branch change
ladamski May 22, 2024
025590b
updated TRK ref, tests
ladamski May 31, 2024
b5e59d9
Add crude reference tests for CTL
bwaresiak May 31, 2024
2a0741b
Fix brainfart
bwaresiak May 31, 2024
e43dd01
move ClickToLoadRulesSplitter to BSK
ladamski May 31, 2024
d663f37
update tests after moving ClickToLoadRulesSplitter to BSK
ladamski Jun 3, 2024
06a3547
Cleanup clickToLoadRulesSpliter return logic
ladamski Jun 3, 2024
9b39a45
lint
ladamski Jun 3, 2024
a7e4d7e
fix and extend ClickToLoadBlockingTests
ladamski Jun 4, 2024
debc53e
Update SurrogatesUserScriptTests.swift
ladamski Jun 5, 2024
69b7cc4
update splitter and surrogate tests per test branch
ladamski Jun 7, 2024
d31f925
lint
ladamski Jun 7, 2024
9377692
Update SurrogatesUserScriptTests.swift
ladamski Jun 8, 2024
337ad8c
move surrogate test fulfill to JS callback
ladamski Jun 11, 2024
fdafd4b
revert to prior fallback TDS handling
ladamski Jun 12, 2024
864223b
remove force unwrap for fallback TDS
ladamski Jun 13, 2024
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
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/TrackerRadarKit",
"state" : {
"revision" : "6c84fd19139414fc0edbf9673ade06e532a564f0",
"version" : "2.0.0"
"revision" : "2a79006fccde6483f47f9d508b11f153f24da30d",
"version" : "2.1.0"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/duckduckgo/duckduckgo-autofill.git", exact: "11.0.1"),
.package(url: "https://github.com/duckduckgo/GRDB.swift.git", exact: "2.3.0"),
.package(url: "https://github.com/duckduckgo/TrackerRadarKit", exact: "2.0.0"),
.package(url: "https://github.com/duckduckgo/TrackerRadarKit", exact: "2.1.0"),
.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/privacy-dashboard", exact: "3.5.0"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,7 @@ public class ContentBlockerRulesManager: CompiledRuleListsSource {
}
}

static func extractSurrogates(from tds: TrackerData) -> TrackerData {

public static func extractSurrogates(from tds: TrackerData) -> TrackerData {
let trackers = tds.trackers.filter { pair in
return pair.value.rules?.first(where: { rule in
rule.surrogate != nil
Expand All @@ -345,7 +344,6 @@ public class ContentBlockerRulesManager: CompiledRuleListsSource {
}

private func compilationCompleted() {

var changes = [String: ContentBlockerRulesIdentifier.Difference]()

lock.lock()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import Common
public protocol SurrogatesUserScriptDelegate: NSObjectProtocol {

func surrogatesUserScriptShouldProcessTrackers(_ script: SurrogatesUserScript) -> Bool
func surrogatesUserScriptShouldProcessCTLTrackers(_ script: SurrogatesUserScript) -> Bool
func surrogatesUserScript(_ script: SurrogatesUserScript,
detectedTracker tracker: DetectedRequest,
withSurrogate host: String)
Expand Down Expand Up @@ -83,7 +84,7 @@ public class DefaultSurrogatesUserScriptConfig: SurrogatesUserScriptConfig {
}
}

open class SurrogatesUserScript: NSObject, UserScript {
open class SurrogatesUserScript: NSObject, UserScript, WKScriptMessageHandlerWithReply {
struct TrackerDetectedKey {
static let protectionId = "protectionId"
static let blocked = "blocked"
Expand Down Expand Up @@ -111,25 +112,47 @@ open class SurrogatesUserScript: NSObject, UserScript {

public var requiresRunInPageContentWorld: Bool = true

public var messageNames: [String] = [ "trackerDetectedMessage" ]
public var messageNames: [String] = [
"trackerDetectedMessage",
"isCTLEnabled"
]

public weak var delegate: SurrogatesUserScriptDelegate?

public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
public func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage,
replyHandler: @escaping (Any?, String?) -> Void) {

guard let delegate = delegate else { return }
guard delegate.surrogatesUserScriptShouldProcessTrackers(self) else { return }

guard let dict = message.body as? [String: Any] else { return }
guard let blocked = dict[TrackerDetectedKey.blocked] as? Bool else { return }
guard let urlString = dict[TrackerDetectedKey.url] as? String else { return }
guard let pageUrlStr = dict[TrackerDetectedKey.pageUrl] as? String else { return }
if message.name == "isCTLEnabled" {
let ctlEnabled = delegate.surrogatesUserScriptShouldProcessCTLTrackers(self)
replyHandler(ctlEnabled, nil)
return
} else if message.name == "trackerDetectedMessage" {
guard delegate.surrogatesUserScriptShouldProcessTrackers(self) else { return }

guard let dict = message.body as? [String: Any] else { return }
guard let blocked = dict[TrackerDetectedKey.blocked] as? Bool else { return }
guard let urlString = dict[TrackerDetectedKey.url] as? String else { return }
guard let pageUrlStr = dict[TrackerDetectedKey.pageUrl] as? String else { return }

let tracker = trackerFromUrl(urlString.trimmingWhitespace(), pageUrlString: pageUrlStr, blocked)
let tracker = trackerFromUrl(urlString.trimmingWhitespace(), pageUrlString: pageUrlStr, blocked)

if let isSurrogate = dict[TrackerDetectedKey.isSurrogate] as? Bool, isSurrogate, let host = URL(string: urlString)?.host {
delegate.surrogatesUserScript(self, detectedTracker: tracker, withSurrogate: host)
if let isSurrogate = dict[TrackerDetectedKey.isSurrogate] as? Bool, isSurrogate, let host = URL(string: urlString)?.host {
delegate.surrogatesUserScript(self, detectedTracker: tracker, withSurrogate: host)
}
replyHandler(nil, nil)
return
}

replyHandler(nil, "Unknown message")
}

public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
assertionFailure("Should never be here!")
}

private func trackerFromUrl(_ urlString: String, pageUrlString: String, _ blocked: Bool) -> DetectedRequest {
let currentTrackerData = configuration.trackerData
let knownTracker = currentTrackerData?.findTracker(forUrl: urlString)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ fileprivate extension KnownTracker.Rule {
private extension KnownTracker.ActionType {

func toTrackerResolverRuleAction() -> TrackerResolver.RuleAction {
self == .block ? .blockRequest : .allowRequest
self == .block || self == .blockCtlFB ? .blockRequest : .allowRequest
ladamski marked this conversation as resolved.
Show resolved Hide resolved
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
//

(function () {

let ctlSurrogates = ['fb-sdk.js']

const duckduckgoDebugMessaging = (function () {
let log = () => {}
let signpostEvent = () => {}
Expand All @@ -42,6 +45,15 @@
}
}())

async function isCTLEnabled () {
try {
const response = await webkit.messageHandlers.isCTLEnabled.postMessage('') // message body required but ignored
return response
} catch (error) {
// webkit might not be defined
}
}

function surrogateInjected (data) {
try {
webkit.messageHandlers.trackerDetectedMessage.postMessage(data)
Expand Down Expand Up @@ -472,9 +484,8 @@
}

// public
function shouldBlock (trackerUrl, type, element) {
async function shouldBlock (trackerUrl, type, element) {
const startTime = performance.now()

if (!blockingEnabled) {
return false
}
Expand All @@ -498,63 +509,71 @@

const isSurrogate = !!(result.matchedRule && result.matchedRule.surrogate)

// Tracker blocking is dealt with by content rules
// Only handle surrogates here
if (blocked && isSurrogate && !isTrackerAllowlisted(topLevelUrl, trackerUrl)) {
// Remove error handlers on the original element
if (element && element.onerror) {
element.onerror = () => {}
}
try {
loadSurrogate(result.matchedRule.surrogate)
// Trigger a load event on the original element
if (element && element.onload) {
element.onload(new Event('load'))
// set flag for CTL enable check if request is blocked and matches a CTL surrogate
const isCTLSurrogate = blocked && isSurrogate && ctlSurrogates.includes(result.matchedRule.surrogate)

// if a CTL surrogate, check if CTL is enabled first otherwise continue immediately
const promise = isCTLSurrogate ? isCTLEnabled() : Promise.resolve(true)

return promise.then ((surrogateEnabled) => {
// Tracker blocking is dealt with by content rules
// Only handle surrogates here
if (blocked && isSurrogate && !isTrackerAllowlisted(topLevelUrl, trackerUrl) && surrogateEnabled) {
// Remove error handlers on the original element
if (element && element.onerror) {
element.onerror = () => {}
}
} catch (e) {
duckduckgoDebugMessaging.log(`error loading surrogate: ${e.toString()}`)
}
const pageUrl = window.location.href
surrogateInjected({
url: trackerUrl,
blocked: blocked,
reason: result.reason,
isSurrogate: isSurrogate,
pageUrl: pageUrl
})
try {
loadSurrogate(result.matchedRule.surrogate)
// Trigger a load event on the original element
if (element && element.onload) {
element.onload(new Event('load'))
}
} catch (e) {
duckduckgoDebugMessaging.log(`error loading surrogate: ${e.toString()}`)
}
const pageUrl = window.location.href
surrogateInjected({
url: trackerUrl,
blocked: blocked,
reason: result.reason,
isSurrogate: isSurrogate,
pageUrl: pageUrl
})

duckduckgoDebugMessaging.signpostEvent({
event: 'Surrogate Injected',
url: trackerUrl,
time: performance.now() - startTime
})
duckduckgoDebugMessaging.signpostEvent({
event: 'Surrogate Injected',
url: trackerUrl,
time: performance.now() - startTime
})

return true
}
return true
}

return false
return false
})
}

const observer = new MutationObserver((records) => {
const observer = new MutationObserver(async (records) => {
for (const record of records) {
record.addedNodes.forEach((node) => {
record.addedNodes.forEach(async (node) => {
if (node instanceof HTMLScriptElement) {
if (shouldBlock(node.src, 'script', node)) {
if (await shouldBlock(node.src, 'script', node)) {
duckduckgoDebugMessaging.log('blocking load')
}
}
})
if (record.target instanceof HTMLScriptElement) {
if (shouldBlock(record.target.src, 'script', record.target)) {
if (await shouldBlock(record.target.src, 'script', record.target)) {
duckduckgoDebugMessaging.log('blocking load')
}
}
}
})
const rootElement = document.body || document.documentElement
observer.observe(rootElement, {
childList: true,
subtree: true,
childList: true,
subtree: true,
attributeFilter: ['src']
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public enum PrivacyFeature: String {
case gpc
case httpsUpgrade = "https"
case autoconsent
case clickToPlay
case clickToLoad
case autofill
case ampLinks
case trackingParameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ final class SurrogatesReferenceTests: XCTestCase {
userScript.delegate = self.userScriptDelegateMock

for messageName in userScript.messageNames {
configuration.userContentController.add(userScript, name: messageName)
configuration.userContentController.addScriptMessageHandler(userScript, contentWorld: .page, name: messageName)
}

configuration.userContentController.addUserScript(WKUserScript(source: userScript.source,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ class SurrogatesUserScriptsTests: XCTestCase {
userScript.delegate = self.userScriptDelegateMock

for messageName in userScript.messageNames {
configuration.userContentController.add(userScript, name: messageName)
configuration.userContentController.addScriptMessageHandler(userScript, contentWorld: .page, name: messageName)
}

configuration.userContentController.addUserScript(WKUserScript(source: userScript.source,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ final class MockRulesUserScriptDelegate: NSObject, ContentBlockerRulesUserScript
final class MockSurrogatesUserScriptDelegate: NSObject, SurrogatesUserScriptDelegate {

var shouldProcessTrackers = true
var shouldProcessCTLTrackers = true

var onSurrogateDetected: ((DetectedRequest, String) -> Void)?
var detectedSurrogates = Set<DetectedRequest>()
Expand All @@ -85,6 +86,10 @@ final class MockSurrogatesUserScriptDelegate: NSObject, SurrogatesUserScriptDele
return shouldProcessTrackers
}

func surrogatesUserScriptShouldProcessCTLTrackers(_ script: SurrogatesUserScript) -> Bool {
return shouldProcessCTLTrackers
ladamski marked this conversation as resolved.
Show resolved Hide resolved
}

func surrogatesUserScript(_ script: SurrogatesUserScript,
detectedTracker tracker: DetectedRequest,
withSurrogate host: String) {
Expand Down
Loading