Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Commit

Permalink
Fix #6841: Add custom filter list urls
Browse files Browse the repository at this point in the history
  • Loading branch information
cuba committed Mar 14, 2023
1 parent 2e7ebd6 commit 578575b
Show file tree
Hide file tree
Showing 31 changed files with 1,150 additions and 645 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ extension BrowserViewController: WKNavigationDelegate {
let domainForShields = Domain.getOrCreate(forUrl: mainDocumentURL, persistent: !isPrivateBrowsing)

// Load rule lists
let ruleLists = ContentBlockerManager.shared.ruleLists(for: domainForShields)
let ruleLists = await ContentBlockerManager.shared.ruleLists(for: domainForShields)
tab?.contentBlocker.set(ruleLists: ruleLists)

let isScriptsEnabled = !domainForShields.isShieldExpected(.NoScript, considerAllShieldsOption: true)
Expand Down
45 changes: 30 additions & 15 deletions Sources/Brave/Frontend/Browser/Helpers/LaunchHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,15 @@ public actor LaunchHelper {
#endif

// Load cached data
// This is done first because compileResources and loadCachedRuleLists need their results
async let loadBundledResources: Void = ContentBlockerManager.shared.loadBundledResources()
// This is done first because compileResources need their results
async let loadCaches: Void = ContentBlockerManager.shared.loadCaches()
async let filterListCache: Void = FilterListResourceDownloader.shared.loadCachedData()
async let adblockResourceCache: Void = AdblockResourceDownloader.shared.loadCachedData()
_ = await (loadBundledResources, filterListCache, adblockResourceCache)
async let filterListURLCache: Void = FilterListCustomURLDownloader.shared.loadCachedFilterLists()
_ = await (loadCaches, filterListCache, adblockResourceCache, filterListURLCache)

// Compile some engines and load cached rule lists
async let compiledResourcesCompile: Void = AdBlockEngineManager.shared.compileResources()
async let cachedRuleListLoad: Void = ContentBlockerManager.shared.loadCachedRuleLists()
_ = await (compiledResourcesCompile, cachedRuleListLoad)
// Compile some engines
await AdBlockEngineManager.shared.compileResources()

#if DEBUG
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
Expand All @@ -50,7 +49,7 @@ public actor LaunchHelper {

// This one is non-blocking
performPostLoadTasks(adBlockService: adBlockService)
markAdBlockReady()
areAdBlockServicesReady = true
}

// Await the task and wait for the results
Expand All @@ -59,18 +58,34 @@ public actor LaunchHelper {
self.loadTask = nil
}

private func markAdBlockReady() {
areAdBlockServicesReady = true
}

/// Perform tasks that don't need to block the initial load (things that can happen happily in the background after the first page loads
private func performPostLoadTasks(adBlockService: AdblockService) {
Task { @MainActor in
await ContentBlockerManager.shared.cleanupDeadRuleLists()
await ContentBlockerManager.shared.compilePendingResources()
FilterListResourceDownloader.shared.start(with: adBlockService)
await AdblockResourceDownloader.shared.startFetching()
ContentBlockerManager.shared.startTimer()
await AdBlockEngineManager.shared.startTimer()

/// Cleanup rule lists so we don't have dead rule lists
let validBlocklistTypes = getAllValidBlocklistTypes()
await ContentBlockerManager.shared.cleaupInvalidRuleLists(validTypes: validBlocklistTypes)
}
}

/// Get all possible types of blocklist types available in this app, this includes actual and potential types
/// This is used to delete old filter lists so that we clean up old stuff
@MainActor private func getAllValidBlocklistTypes() -> Set<ContentBlockerManager.BlocklistType> {
return FilterListResourceDownloader.shared.filterLists
// All filter lists blocklist types
.reduce(Set<ContentBlockerManager.BlocklistType>()) { partialResult, filterList in
return partialResult.union([.filterList(uuid: filterList.uuid)])
}
// All generic types
.union(
ContentBlockerManager.GenericBlocklistType.allCases.map { .generic($0) }
)
// All custom filter list urls
.union(
CustomFilterListStorage.shared.filterListsURLs.map { .customFilterList(uuid: $0.setting.uuid) }
)
}
}
11 changes: 4 additions & 7 deletions Sources/Brave/Frontend/Browser/LinkPreviewViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,11 @@ class LinkPreviewViewController: UIViewController {
return
}

let domain = Domain.getOrCreate(forUrl: url, persistent: !PrivateBrowsingManager.shared.isPrivateBrowsing)

Task(priority: .userInitiated) {
// Add rule lists for this page
Task { @MainActor in
let domain = Domain.getOrCreate(forUrl: url, persistent: !PrivateBrowsingManager.shared.isPrivateBrowsing)
let ruleLists = await ContentBlockerManager.shared.ruleLists(for: domain)

for ruleList in ruleLists {
webView.configuration.userContentController.add(ruleList)
}
ruleLists.forEach { webView.configuration.userContentController.add($0) }
}

webView.frame = view.bounds
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ class TopToolbarView: UIView, ToolbarProtocol {
if let currentURL = currentURL {
let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing
let domain = Domain.getOrCreate(forUrl: currentURL, persistent: !isPrivateBrowsing)
if domain.shield_allOff == 1 {
if domain.areAllShieldsOff {
shieldIcon = shieldsOffIcon
}
if currentURL.isLocal || currentURL.isLocalUtility {
Expand Down
35 changes: 35 additions & 0 deletions Sources/Brave/Frontend/Browser/UserScriptManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,16 @@ class UserScriptManager {
return
}

#if DEBUG
ContentBlockerManager.log.debug("Loaded \(userScripts.count + customScripts.count) scripts:")
userScripts.sorted(by: { $0.rawValue < $1.rawValue}).forEach { scriptType in
ContentBlockerManager.log.debug(" \(scriptType.debugDescription)")
}
customScripts.sorted(by: { $0.order < $1.order}).forEach { scriptType in
ContentBlockerManager.log.debug(" #\(scriptType.order) \(scriptType.debugDescription)")
}
#endif

loadScripts(into: tab, scripts: userScripts)

webView.configuration.userContentController.do { scriptController in
Expand Down Expand Up @@ -306,3 +316,28 @@ class UserScriptManager {
}
}
}

#if DEBUG
extension UserScriptType: CustomDebugStringConvertible {
var debugDescription: String {
switch self {
case .domainUserScript(let domainUserScript):
return "domainUserScript(\(domainUserScript.associatedDomains.joined(separator: ", ")))"
case .engineScript(let configuration):
return "engineScript(\(configuration.frameURL))"
case .farblingProtection(let etld):
return "farblingProtection(\(etld))"
case .nacl:
return "nacl"
case .siteStateListener:
return "siteStateListener"
}
}
}

extension UserScriptManager.ScriptType: CustomDebugStringConvertible {
var debugDescription: String {
return rawValue
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class AdblockDebugMenuTableViewController: TableViewController {
text: "Recompile Content Blockers",
selection: {
Task { @MainActor in
await ContentBlockerManager.shared.compilePendingResources()
await AdblockResourceDownloader.shared.loadCachedData()
self.showCompiledBlockListAlert()
}
}, cellClass: ButtonCell.self)
Expand Down Expand Up @@ -173,10 +173,14 @@ class AdblockDebugMenuTableViewController: TableViewController {
return Row(text: fileURL.lastPathComponent, detailText: detailText, cellClass: MultilineSubtitleCell.self)
}

var resources = FilterListResourceDownloader.shared.filterLists.flatMap { filterList -> [ResourceDownloader.Resource] in
return filterList.resources
var resources = FilterListResourceDownloader.shared.filterLists.map { filterList -> ResourceDownloader.Resource in
return filterList.makeResource(componentId: filterList.entry.componentId)
}

resources.append(contentsOf: CustomFilterListStorage.shared.filterListsURLs.map({ customURL in
return .customFilterListURL(uuid: customURL.setting.uuid, externalURL: customURL.setting.externalURL)
}))

resources.append(contentsOf: [
.debounceRules, .genericContentBlockingBehaviors, .genericFilterRules, .generalCosmeticFilters, .generalScriptletResources
])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class BraveShieldsAndPrivacySettingsController: TableViewController {
// Listen to changes on filter lists so we know we need to reload the section
FilterListResourceDownloader.shared.$filterLists
.sink { filterLists in
let filterList = filterLists.first(where: { $0.componentId == FilterList.cookieConsentNoticesComponentID })
let filterList = filterLists.first(where: { $0.entry.componentId == FilterList.cookieConsentNoticesComponentID })

Task { @MainActor in
let isEnabled = FilterListResourceDownloader.shared.isEnabled(for: FilterList.cookieConsentNoticesComponentID)
Expand Down
101 changes: 101 additions & 0 deletions Sources/Brave/Frontend/Settings/FilterListAddURLView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2023 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

import SwiftUI
import Strings
import DesignSystem
import BraveUI

struct FilterListAddURLView: View {
@ObservedObject private var customFilterListStorage = CustomFilterListStorage.shared
@SwiftUI.Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
@State private var newURLInput: String = ""

private var textField: some View {
TextField(Strings.filterListsEnterFilterListURL, text: $newURLInput)
.keyboardType(.URL)
.textContentType(.URL)
.autocapitalization(.none)
}

var body: some View {
NavigationView {
List {
Section(content: {
VStack {
textField
.submitLabel(SubmitLabel.done)
}.listRowBackground(Color(.secondaryBraveGroupedBackground))
}, header: {
Text(Strings.customFilterListURL)
.textCase(.uppercase)
}, footer: {
VStack(alignment: .leading, spacing: 8) {
Text(Strings.addCustomFilterListDescription)
Text(Strings.addCustomFilterListWarning).bold() + Text(Strings.addCustomFilterListWarning2)
}.padding(.top, 16)
})
}
.listBackgroundColor(Color(UIColor.braveGroupedBackground))
.navigationTitle(Strings.customFilterList)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItemGroup(placement: .primaryAction) {
Button(Strings.filterListsAdd) {
handleOnSubmit()
}.disabled(newURLInput.isEmpty)
}

ToolbarItemGroup(placement: .cancellationAction) {
Button(Strings.CancelString) {
presentationMode.wrappedValue.dismiss()
}
}
}
}
}

private func handleOnSubmit() {
guard !newURLInput.isEmpty else { return }
guard let url = URL(string: newURLInput) else {
// Show invalid URL error
return
}
guard url.scheme == "https" else {
// Show invalid scheme error
return
}
guard !customFilterListStorage.filterListsURLs.contains(where: { filterListURL in
return filterListURL.setting.externalURL == url
}) else {
// Don't allow duplicates
self.presentationMode.wrappedValue.dismiss()
return
}

Task {
let customURL = FilterListCustomURL(
externalURL: url, isEnabled: true,
inMemory: !customFilterListStorage.persistChanges
)

customFilterListStorage.filterListsURLs.append(customURL)

await FilterListCustomURLDownloader.shared.startFetching(
filterListCustomURL: customURL
)

self.presentationMode.wrappedValue.dismiss()
}
}
}

#if DEBUG
struct FilterListAddURLView_Previews: PreviewProvider {
static var previews: some View {
FilterListAddURLView()
}
}
#endif
Loading

0 comments on commit 578575b

Please sign in to comment.