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

Update Content Blocking to use BSK stack #354

Merged
merged 24 commits into from
Nov 30, 2021

Conversation

bwaresiak
Copy link
Collaborator

@bwaresiak bwaresiak commented Nov 28, 2021

Task/Issue URL:

Tech Design URL:
CC:

Description:

Move Content Blocking stack from iOS to BSK and introduce it to Mac OS browser.

This is sibling PR to the one from BSK: duckduckgo/BrowserServicesKit#35

Steps to test this PR:

All privacy related features should be carefully tested (see checklist below) and checked against privacy test pages.

Testing checklist:

  • Test with Release configuration

Privacy features:

  • Tracker Blocking.
  • Tracker Reporting (privacy dashboard).
  • Surrogates injection.
  • GPC toggling.
  • Unprotected sites and toggling protection.
  • Temporary list exceptions.
  • Tracker Allowlist exceptions (see https://app.asana.com/0/856498667320406/1201168402252793 for details).
  • TDS and PrivacyConfig updates.

Internal references:

Software Engineering Expectations
Technical Design Template
When ready for review, remember to post the PR in MM

userScriptsUpdatedCancellable = scriptsSource.sourceUpdatedPublisher.receive(on: RunLoop.main).sink { [weak self] _ in
guard let self = self, self.delegate != nil else { return }

self.userScripts = UserScripts(with: self.scriptsSource)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could check the diff of the rules here (e.g. for the presence of unprotected sites changes) and reload the tab here, instead of doing that from Dashboard (but it would require figuring out if current tab is the one for which change has been triggered, or if it matches the unprotected sites change).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1
Not sure if it helps, but active tab state can be easily determined with webview.superview != nil

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to know if that tab is relevant to the change - hard to do that now, probably should be tackled elsewhere.


self.reload(knownChanges: newRulesInfo.changes)
})
contentBlockingRulesUpdatedCancellable = cancellable
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've refactored the event flow, as Scripts depend on the state of the Content Blocking & Config layers, so source provider now listens to changes and sends sigal once sources are updated. Tabs listen for this and reinstantiate scripts.

@@ -26,7 +26,7 @@ struct PrivacySecurityPreferences {
@UserDefaultsWrapper(key: .gpcEnabled, defaultValue: true)
public var gpcEnabled: Bool {
didSet {
DefaultScriptSourceProvider.shared.reload()
DefaultScriptSourceProvider.shared.reload(knownChanges: nil)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just 2nd place where DefaultScriptSourceProvider.shared is used so we could make it regular instance instead of singleton if we were to refactor this code into some event-driven logic.


let majorTrackerThresholdPrevalence = 25.0
let parentEntity = ContentBlocking.trackerDataManager.trackerData.findEntity(forHost: host)
let isMajorTrackingNetwork = (parentEntity?.prevalence ?? 0.0) >= majorTrackerThresholdPrevalence
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This business logic has been moved from TrackerRadarManager.

self.sendPendingUpdates()

let activeTab = self.tabViewModel?.tab
activeTab?.reload()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some bugs related to fact that we allow user to change tabs after toggling protection status:

  1. Current Tab can be closed - then browser crashes.
  2. Current Tab can be changed - then reload() is called for wrong tab.

These issues should be handled in another task.


final class PrivacyDashboardViewController: NSViewController {

@IBOutlet var webView: WKWebView!
private let privacyDashboardScript = PrivacyDashboardUserScript()
private var cancellables = Set<AnyCancellable>()
@Published var pendingUpdates = Set<String>()
@Published var pendingUpdates = [String: String]()
Copy link
Collaborator Author

@bwaresiak bwaresiak Nov 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not possible to have multiple pending updates per current logic (toggle is disabled when processing change), but I preserved that capability in the code to not make too many changes here.

@bwaresiak bwaresiak changed the title [WIP] Update Content Blocking to use BSK stack Update Content Blocking to use BSK stack Nov 28, 2021
@bwaresiak bwaresiak force-pushed the bartek/update-content-blocking branch from dc211c0 to 9102a99 Compare November 28, 2021 21:18
@tomasstrba tomasstrba self-assigned this Nov 29, 2021
@tomasstrba tomasstrba self-requested a review November 29, 2021 08:27
Copy link
Contributor

@tomasstrba tomasstrba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bwaresiak, I promised this to be reviewed today, but I need few more minutes to review this tomorrow. Code architecture looks very good, I can see you cared. Don't expect any major changes after the second review tomorrow

@@ -429,29 +430,27 @@ extension URL {
}

// MARK: - GPC

static func gpcHeadersEnabled(config: PrivacyConfiguration) -> [String] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, these two methods are weird. They are static on URL, but the main point is to look into the instance of PrivacyConfiguration. I would define them there. Definitely not scope of this PR, I added a task into my tech debt list.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely good idea, I didn't want to touch "too much" to not add to the scope creep.

@@ -19,7 +19,7 @@
import WebKit
import BrowserServicesKit

final class ContentBlockerRulesUserScript: NSObject, UserScript {
final class OldContentBlockerRulesUserScript: NSObject, UserScript {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reference to this file is removed from Xcode but the file is still in ContentBlocker folder.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops :)

Copy link
Contributor

@tomasstrba tomasstrba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are tests that I used to verify the functionality:

  • Tracker blocking: https://privacy-test-pages.glitch.me/index.html
  • Surrogates: https://efficient-zest-side.glitch.me/
  • GPC: https://globalprivacycontrol.org/
  • Unprotected sites and toggling protection: switching the protection on/off in the privacy dashboard
  • Temporary list exceptions: Editing bundled macos-config.json and waiting until the downloaded version is applied
  • Tracker Allowlist exceptions: Run tests in BSK using "swift test" (Failed to load a local file when tests were running from Xcode)
  • TDS and PrivacyConfig updates: Combination of breakpoints, removal of the local configuration from ~/Library/Containers/com.duckduckgo.macos.browser.debug/Data/Library/Application Support/Configuration and looking whether tracker allowlist exceptions were applied

The only issue discovered is we are not passing information about temporary unprotected site to the user. It is not part of the scope of this PR

Bartek, this is an excelent work! 🎖️ 🏅 I'm very happy we have another pair of eyes looking at our codebase. Thanks for all suggestions, I took notes and will add follow up tasks into our macOS Development board.

LGTM! 💯

@tomasstrba tomasstrba assigned bwaresiak and unassigned tomasstrba Nov 30, 2021
@bwaresiak bwaresiak merged commit 1fcc9bb into develop Nov 30, 2021
@bwaresiak bwaresiak deleted the bartek/update-content-blocking branch November 30, 2021 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants