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

Use list_catalog.json file in iOS #8729

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ extension BrowserViewController: WKNavigationDelegate {

@MainActor
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences) async -> (WKNavigationActionPolicy, WKWebpagePreferences) {

guard var requestURL = navigationAction.request.url else {
return (.cancel, preferences)
}
Expand Down Expand Up @@ -255,6 +254,9 @@ extension BrowserViewController: WKNavigationDelegate {
return (.cancel, preferences)
}

let signpostID = ContentBlockerManager.signpost.makeSignpostID()
let state = ContentBlockerManager.signpost.beginInterval("decidePolicyFor", id: signpostID)

// before loading any ad-block scripts
// await the preparation of the ad-block services
await LaunchHelper.shared.prepareAdBlockServices(
Expand All @@ -279,6 +281,7 @@ extension BrowserViewController: WKNavigationDelegate {
ContentBlockerManager.log.debug("Redirected user to `\(url.absoluteString, privacy: .private)`")
}

ContentBlockerManager.signpost.endInterval("decidePolicyFor", state, "Redirected navigation")
return (.cancel, preferences)
} else {
tab?.isInternalRedirect = false
Expand Down Expand Up @@ -321,6 +324,7 @@ extension BrowserViewController: WKNavigationDelegate {
var modifiedRequest = URLRequest(url: requestURL)
modifiedRequest.setValue("1", forHTTPHeaderField: "X-Brave-Ads-Enabled")
tab?.loadRequest(modifiedRequest)
ContentBlockerManager.signpost.endInterval("decidePolicyFor", state, "Redirected to search")
return (.cancel, preferences)
}

Expand Down Expand Up @@ -373,6 +377,7 @@ extension BrowserViewController: WKNavigationDelegate {
if let url = components?.url {
let request = PrivilegedRequest(url: url) as URLRequest
tab?.loadRequest(request)
ContentBlockerManager.signpost.endInterval("decidePolicyFor", state, "Blocked navigation")
return (.cancel, preferences)
}
}
Expand Down Expand Up @@ -437,6 +442,7 @@ extension BrowserViewController: WKNavigationDelegate {
self.shouldDownloadNavigationResponse = true
}

ContentBlockerManager.signpost.endInterval("decidePolicyFor", state)
return (.allow, preferences)
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/Brave/Frontend/Browser/Helpers/LaunchHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public actor LaunchHelper {
// Otherwise prepare the services and await the task
let task = Task {
let signpostID = Self.signpost.makeSignpostID()
ContentBlockerManager.log.debug("Loading blocking launch data")
let state = Self.signpost.beginInterval("blockingLaunchTask", id: signpostID)
// We only want to compile the necessary content blockers during launch
// We will compile other ones after launch
Expand All @@ -50,6 +51,7 @@ public actor LaunchHelper {
async let adblockResourceCache: Void = AdblockResourceDownloader.shared.loadCachedAndBundledDataIfNeeded(allowedModes: launchBlockModes)
_ = await (filterListCache, adblockResourceCache)
Self.signpost.emitEvent("loadedCachedData", id: signpostID, "Loaded cached data")
ContentBlockerManager.log.debug("Loaded blocking launch data")

// This one is non-blocking
performPostLoadTasks(adBlockService: adBlockService, loadedBlockModes: launchBlockModes)
Expand Down Expand Up @@ -128,7 +130,7 @@ private extension FilterListStorage {
var validBlocklistTypes: Set<ContentBlockerManager.BlocklistType> {
if filterLists.isEmpty {
// If we don't have filter lists yet loaded, use the settings
return Set(allFilterListSettings.compactMap { setting in
return Set(allFilterListSettings.compactMap { setting -> ContentBlockerManager.BlocklistType? in
guard let componentId = setting.componentId else { return nil }
return .filterList(
componentId: componentId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ extension UserScriptType: CustomDebugStringConvertible {
case .nacl:
return "nacl"
case .gpc(let isEnabled):
return "gpc(\(isEnabled)"
return "gpc(\(isEnabled))"
case .siteStateListener:
return "siteStateListener"
case .selectorsPoller:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,22 @@ struct FilterListsView: View {

@ViewBuilder private var filterListView: some View {
ForEach($filterListStorage.filterLists) { $filterList in
Toggle(isOn: $filterList.isEnabled) {
VStack(alignment: .leading) {
Text(filterList.entry.title)
.foregroundColor(Color(.bravePrimary))
Text(filterList.entry.desc)
.font(.caption)
.foregroundColor(Color(.secondaryBraveLabel))
if !filterList.isHidden {
Toggle(isOn: $filterList.isEnabled) {
VStack(alignment: .leading) {
Text(filterList.entry.title)
.foregroundColor(Color(.bravePrimary))
Text(filterList.entry.desc)
.font(.caption)
.foregroundColor(Color(.secondaryBraveLabel))
}
}
}
.onChange(of: filterList.isEnabled) { isEnabled in
if isEnabled {
expectedEnabledSources.insert(filterList.engineSource)
} else {
expectedEnabledSources.remove(filterList.engineSource)
.onChange(of: filterList.isEnabled) { isEnabled in
if isEnabled {
expectedEnabledSources.insert(filterList.engineSource)
} else {
expectedEnabledSources.remove(filterList.engineSource)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ actor ContentBlockerManager {
/// Should be used only as a cleanup once during launch to get rid of unecessary/old data.
/// This is mostly for custom filter lists a user may have added.
public func cleaupInvalidRuleLists(validTypes: Set<BlocklistType>) async {
let signpostID = Self.signpost.makeSignpostID()
let state = Self.signpost.beginInterval("cleaupInvalidRuleLists", id: signpostID)
let availableIdentifiers = await ruleStore.availableIdentifiers() ?? []

await availableIdentifiers.asyncConcurrentForEach { identifier in
Expand All @@ -170,6 +172,8 @@ actor ContentBlockerManager {
assertionFailure()
}
}

Self.signpost.endInterval("cleaupInvalidRuleLists", state)
}

/// Compile the rule list found in the given local URL using the specified modes
Expand Down
10 changes: 10 additions & 0 deletions Sources/Brave/WebFilters/CustomFilterListStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,13 @@ import Data
}
}
}

extension CustomFilterListStorage {
/// Gives us source representations of all the enabled custom filter lists
@MainActor var enabledSources: [CachedAdBlockEngine.Source] {
return filterListsURLs.compactMap { filterList -> CachedAdBlockEngine.Source? in
guard filterList.setting.isEnabled else { return nil }
return filterList.setting.engineSource
}
}
}
37 changes: 12 additions & 25 deletions Sources/Brave/WebFilters/FilterList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,44 @@
import BraveCore

struct FilterList: Identifiable {
/// This is the uuid of the default filter list. This is a special filter list which we use slim list content blockers for
public static let defaultFilterListUUID = "default"
/// The component ID of the "Fanboy's Mobile Notifications List"
/// This is a special filter list that is enabled by default
public static let mobileAnnoyancesComponentID = "bfpgedeaaibpoidldhjcknekahbikncb"
/// The component id of the cookie consent notices filter list.
/// This is a special filter list that has more accessible UI to control it
public static let cookieConsentNoticesComponentID = "cdbbhgbmjhfnhnmgeddbliobbofkgdhe"
/// A list of safe filter lists that can be automatically enabled if the user has the matching localization.
/// - Note: These are regional fiter lists that are well maintained. For now we hardcode these values
/// but it would be better if our component updater told us which ones are safe in the future.
public static let maintainedRegionalComponentIDs = [
"llgjaaddopeckcifdceaaadmemagkepi" // Japanese filter lists
]
/// This is a list of disabled filter lists. These lists are disabled because they are incompatible with iOS (for the time being)
public static let disabledComponentIDs = [
// The Anti-porn list has 500251 rules and is strictly all content blocking driven content
// The limit for the rule store is 150000 rules. We have no way to handle this at the current moment
"lbnibkdpkdjnookgfeogjdanfenekmpe"
]

/// All the component ids that should be set to on by default.
public static var defaultOnComponentIds: Set<String> {
return [mobileAnnoyancesComponentID]
}

/// This is a list of component to UUID for some filter lists that have special toggles
/// (which are availble before filter lists are downloaded)
/// To save these values before filter lists are downloaded we need to also have the UUID
public static var componentToUUID: [String: String] {
return [
mobileAnnoyancesComponentID: "2F3DCE16-A19A-493C-A88F-2E110FBD37D6",
cookieConsentNoticesComponentID: "AC023D22-AE88-4060-A978-4FEEEC4221693"
]
}

var id: String { return entry.uuid }
let order: Int
let entry: AdblockFilterListCatalogEntry
var isEnabled: Bool = false

var isHidden: Bool {
return entry.hidden

Check failure on line 31 in Sources/Brave/WebFilters/FilterList.swift

View workflow job for this annotation

GitHub Actions / Run tests

value of type 'AdblockFilterListCatalogEntry' has no member 'hidden'

Check failure on line 31 in Sources/Brave/WebFilters/FilterList.swift

View workflow job for this annotation

GitHub Actions / Run tests

value of type 'AdblockFilterListCatalogEntry' has no member 'hidden'
}

/// Tells us if this filter list is regional (i.e. if it contains language restrictions)
var isRegional: Bool {
return !entry.languages.isEmpty
}

/// Lets us know if this filter list is always aggressive.
/// Aggressive filter lists are those that are non regional.
var isAlwaysAggressive: Bool { !isRegional }
/// This value comes from `list_catalog.json` in brave core
var isAlwaysAggressive: Bool {
return entry.firstPartyProtections

Check failure on line 42 in Sources/Brave/WebFilters/FilterList.swift

View workflow job for this annotation

GitHub Actions / Run tests

value of type 'AdblockFilterListCatalogEntry' has no member 'firstPartyProtections'

Check failure on line 42 in Sources/Brave/WebFilters/FilterList.swift

View workflow job for this annotation

GitHub Actions / Run tests

value of type 'AdblockFilterListCatalogEntry' has no member 'firstPartyProtections'
}

init(from entry: AdblockFilterListCatalogEntry, order: Int, isEnabled: Bool) {
init(from entry: AdblockFilterListCatalogEntry, order: Int, isEnabled: Bool?) {
self.entry = entry
self.order = order
self.isEnabled = isEnabled
self.isEnabled = isEnabled ?? entry.defaultEnabled

Check failure on line 48 in Sources/Brave/WebFilters/FilterList.swift

View workflow job for this annotation

GitHub Actions / Run tests

value of type 'AdblockFilterListCatalogEntry' has no member 'defaultEnabled'
}
}
30 changes: 4 additions & 26 deletions Sources/Brave/WebFilters/FilterListCustomURLDownloader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,29 +58,9 @@ actor FilterListCustomURLDownloader: ObservableObject {
self.startedService = true
await CustomFilterListStorage.shared.loadCachedFilterLists()

do {
try await CustomFilterListStorage.shared.filterListsURLs.asyncConcurrentForEach { customURL in
let resource = await customURL.setting.resource

do {
if let cachedResult = try resource.cachedResult() {
await self.handle(downloadResult: cachedResult, for: customURL)
}
} catch {
let uuid = await customURL.setting.uuid
ContentBlockerManager.log.error(
"Failed to cached data for custom filter list `\(uuid)`: \(error)"
)
}

// Always fetch this resource so it's ready if the user enables it.
await self.startFetching(filterListCustomURL: customURL)

// Sleep for 1ms. This drastically reduces memory usage without much impact to usability
try await Task.sleep(nanoseconds: 1000000)
}
} catch {
// Ignore cancellation errors
await CustomFilterListStorage.shared.filterListsURLs.asyncForEach { customURL in
// Always fetch this resource so it's ready if the user enables it.
await self.startFetching(filterListCustomURL: customURL)
}
}

Expand All @@ -105,9 +85,7 @@ actor FilterListCustomURLDownloader: ObservableObject {
filterListInfo: filterListInfo, isAlwaysAggressive: true
)

guard await AdBlockStats.shared.isEagerlyLoaded(source: source) else {
// Don't compile unless eager
await AdBlockStats.shared.updateIfNeeded(resourcesInfo: resourcesInfo)
guard await AdBlockStats.shared.isEnabled(source: source) else {
await AdBlockStats.shared.updateIfNeeded(filterListInfo: filterListInfo, isAlwaysAggressive: true)

// To free some space, remove any rule lists that are not needed
Expand Down
Loading
Loading