2 * Copyright 2024 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
6 * Privacy Browser PC is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser PC is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser PC. If not, see <http://www.gnu.org/licenses/>.
20 // Application headers.
21 #include "FilterListHelper.h"
22 #include "structs/OverrideStruct.h"
24 // Qt toolkit headers.
27 #include <QTextStream>
29 // KDE Framework headers.
30 #include <KLocalizedString>
32 // Construct the class.
33 FilterListHelper::FilterListHelper()
35 // Populate the translated disposition strings. Translated entries cannot be public static const.
36 DEFAULT_STRING = i18nc("Default disposition", "Default - Allowed");
37 ALLOWED_STRING = i18nc("Allowed disposition", "Allowed");
38 BLOCKED_STRING = i18nc("Blocked disposition", "Blocked");
40 // Populate the translated filter option disposition strings. Translated entries cannot be public static const.
41 FILTER_OPTION_NULL = QString();
42 FILTER_OPTION_APPLY = i18nc("Apply filter option", "Apply");
43 FILTER_OPTION_OVERRIDE = i18nc("Override filter option", "Override");
45 // Populate the translated navigation type strings. Translated entries cannot be public static const.
46 NAVIGATION_TYPE_LINK = i18nc("Navigation type link", "Link");
47 NAVIGATION_TYPE_TYPED = i18nc("Navigation type typed", "Typed");
48 NAVIGATION_TYPE_FORM_SUBMITTED = i18nc("Navigation type form submitted", "Form Submitted");
49 NAVIGATION_TYPE_BACK_FORWARD = i18nc("Navigation type back/forward", "Back/Forward");
50 NAVIGATION_TYPE_RELOAD = i18nc("Navigation type reload", "Reload");
51 NAVIGATION_TYPE_REDIRECT = i18nc("Navigation type redirect", "Redirect");
52 NAVIGATION_TYPE_OTHER = i18nc("Navigation type other", "Other");
54 // Populate the translated resource type strings. Translated entries cannot be public static const.
55 RESOURCE_TYPE_MAIN_FRAME = i18nc("Resource type main frame", "Main Frame");
56 RESOURCE_TYPE_SUB_FRAME = i18nc("Resource type sub frame", "Sub Frame");
57 RESOURCE_TYPE_STYLESHEET = i18nc("Resource type stylesheet", "Stylesheet");
58 RESOURCE_TYPE_SCRIPT = i18nc("Resource type script", "Script");
59 RESOURCE_TYPE_IMAGE = i18nc("Resource type image", "Image");
60 RESOURCE_TYPE_FONT_RESOURCE = i18nc("Resource type font", "Font");
61 RESOURCE_TYPE_SUB_RESOURCE = i18nc("Resource type sub resource", "Sub Resource");
62 RESOURCE_TYPE_OBJECT = i18nc("Resource type object", "Object");
63 RESOURCE_TYPE_MEDIA = i18nc("Resource type media", "Media");
64 RESOURCE_TYPE_WORKER = i18nc("Resource type worker", "Worker");
65 RESOURCE_TYPE_SHARED_WORKER = i18nc("Resource type shared worker", "Shared Worker");
66 RESOURCE_TYPE_PREFETCH = i18nc("Resource type prefetch", "Prefetch");
67 RESOURCE_TYPE_FAVICON = i18nc("Resource type favicon", "Favicon");
68 RESOURCE_TYPE_XHR = i18nc("Resource type XML HTTP request", "XML HTTP Request");
69 RESOURCE_TYPE_PING = i18nc("Resource type HTTP ping", "HTTP Ping");
70 RESOURCE_TYPE_SERVICE_WORKER = i18nc("Resource type service worker", "Service Worker");
71 RESOURCE_TYPE_CSP_REPORT = i18nc("Resource type content security policy report", "Content Security Policy Report");
72 RESOURCE_TYPE_PLUGIN_RESOURCE = i18nc("Resource type plugin request", "Plugin Request");
73 RESOURCE_TYPE_NAVIGATION_PRELOAD_MAIN_FRAME = i18nc("Resource type preload main frame", "Preload Main Frame");
74 RESOURCE_TYPE_NAVIGATION_PRELOAD_SUB_FRAME = i18nc("Resource type preload sub frame", "Preload Sub Frame");
75 RESOURCE_TYPE_UNKNOWN = i18nc("Resource type unknown", "Unknown");
77 // Populate the translated sublist strings. Translated entries cannot be public static const.
78 MAIN_ALLOWLIST_STRING = i18nc("Main allowlist sublist", "Main Allow List");
79 MAIN_BLOCKLIST_STRING = i18nc("Main blocklist sublist", "Main Block List");
80 INITIAL_DOMAIN_BLOCKLIST_STRING = i18nc("Initial domain blocklist string", "Initial Domain Block List");
82 // Populate the filter lists.
83 ultraListStructPointer = populateFilterList(QLatin1String(":/filterlists/ultralist.txt"));
84 ultraPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/ultraprivacy.txt"));
85 easyListStructPointer = populateFilterList(QLatin1String(":/filterlists/easylist.txt"));
86 easyPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/easyprivacy.txt"));
87 fanboyAnnoyanceStructPointer = populateFilterList(QLatin1String(":/filterlists/fanboy-annoyance.txt"));
90 bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer) const
92 // Initiate a continue checking tracker. If the tracker changes to false, all process of the request will be stopped.
93 bool continueChecking = true;
95 // Create a URL struct.
99 QUrl firstPartyUrl = urlRequestInfo.firstPartyUrl();
100 QUrl requestUrl = urlRequestInfo.requestUrl();
103 QString firstPartyHost = firstPartyUrl.host();
104 QString requestHost = requestUrl.host();
106 // Determine if this is a third-party request.
107 urlStruct.isThirdPartyRequest = (firstPartyHost != requestHost);
109 // Get the request URL string.
110 urlStruct.urlString = requestUrl.toString();
112 // Create a URL string with separators.
113 urlStruct.urlStringWithSeparators = urlStruct.urlString;
115 // Replace the separators characters with `^`.
116 urlStruct.urlStringWithSeparators.replace(QLatin1Char(':'), QLatin1Char('^'));
117 urlStruct.urlStringWithSeparators.replace(QLatin1Char('/'), QLatin1Char('^'));
118 urlStruct.urlStringWithSeparators.replace(QLatin1Char('?'), QLatin1Char('^'));
119 urlStruct.urlStringWithSeparators.replace(QLatin1Char('='), QLatin1Char('^'));
120 urlStruct.urlStringWithSeparators.replace(QLatin1Char('&'), QLatin1Char('^'));
122 // Add a `^` to the end of the string.
123 urlStruct.urlStringWithSeparators.append(QLatin1Char('^'));
125 // Create truncated URL strings and initially populate it with the original URL strings.
126 urlStruct.truncatedUrlString = urlStruct.urlString;
127 urlStruct.truncatedUrlStringWithSeparators = urlStruct.urlStringWithSeparators;
129 // Get the index of the beginning of the fully qualified domain name.
130 int fqdnIndex = urlStruct.truncatedUrlString.indexOf(QLatin1String("://")) + 3;
132 // Truncate the URL to the beginning of the fully qualified domain name.
133 urlStruct.truncatedUrlString.remove(0, fqdnIndex);
134 urlStruct.truncatedUrlStringWithSeparators.remove(0, fqdnIndex);
137 continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraListStructPointer);
139 // Check UltraPrivacy.
140 if (continueChecking)
141 continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraPrivacyStructPointer);
144 if (continueChecking)
145 continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyListStructPointer);
147 // Check EasyPrivacy.
148 if (continueChecking)
149 continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyPrivacyStructPointer);
151 if (continueChecking)
152 continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, fanboyAnnoyanceStructPointer);
154 // Return the continue checking status.
155 return continueChecking;
158 bool FilterListHelper::blockRequest(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt,
159 EntryStruct *entryStructPointer) const
161 // Block the request.
162 urlRequestInfo.block(true);
164 // Populate the request struct.
165 populateRequestStruct(requestStructPointer, BLOCKED, filterListTitle, sublistInt, entryStructPointer);
168 //qDebug().noquote().nospace() << "Blocked request: " << urlRequestInfo.firstPartyUrl() << ", Filter list entry: " << entryStructPointer->appliedEntry;
170 // Returning `false` stops all processing of the request.
174 bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, FilterListStruct *filterListStructPointer) const
176 // Check the main allow list.
177 for (auto filterListEntry = filterListStructPointer->mainAllowList.begin(); filterListEntry != filterListStructPointer->mainAllowList.end(); ++filterListEntry)
179 // Get the entry struct.
180 EntryStruct *entryStructPointer = *filterListEntry;
182 // TODO. Temporarily ignore empty applied entries.
183 if (!entryStructPointer->appliedEntry.isEmpty())
185 // Check if the URL string contains the applied entry.
186 if (urlStruct.urlString.contains(entryStructPointer->appliedEntry) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntry))
188 // Allow the request.
189 urlRequestInfo.block(false);
191 // Populate the request struct.
192 populateRequestStruct(requestStructPointer, ALLOWED, filterListStructPointer->title, MAIN_ALLOWLIST, entryStructPointer);
195 //qDebug().noquote().nospace() << "Allowed request: " << urlStruct.urlString << ", Filter list entry: " << entryStructPointer->appliedEntry;
197 // Returning `false` stops all processing of the request.
203 // Check the main block list.
204 for (auto filterListEntry = filterListStructPointer->mainBlockList.begin(); filterListEntry != filterListStructPointer->mainBlockList.end(); ++filterListEntry)
206 // Get the entry struct.
207 EntryStruct *entryStructPointer = *filterListEntry;
209 // TODO. Temporarily ignore empty applied entries.
210 if (!entryStructPointer->appliedEntry.isEmpty())
212 // Check if the URL string contains the applied entry.
213 if (urlStruct.urlString.contains(entryStructPointer->appliedEntry) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntry))
215 // Check the third-party status.
216 bool continueChecking = checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListStructPointer->title, MAIN_BLOCKLIST, entryStructPointer);
218 // Stop processing the filter lists if continue checking is `false`. Returning false halts all processing at upper levels.
219 if (continueChecking == false)
225 // Check the initial domain block list.
226 for (auto filterListEntry = filterListStructPointer->initialDomainBlockList.begin(); filterListEntry != filterListStructPointer->initialDomainBlockList.end(); ++filterListEntry)
228 // Get the entry struct.
229 EntryStruct *entryStructPointer = *filterListEntry;
231 // Check if the truncated URL string begins with the applied entry.
232 if (urlStruct.truncatedUrlString.startsWith(entryStructPointer->appliedEntry) || urlStruct.truncatedUrlStringWithSeparators.startsWith(entryStructPointer->appliedEntry))
234 // Check the third-party status.
235 bool continueChecking = checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListStructPointer->title, INITIAL_DOMAIN_BLOCKLIST, entryStructPointer);
237 // Stop processing the filter lists if continue checking is `false`. Returning false halts all processing at upper levels.
238 if (continueChecking == false)
243 // Return `true` to continue processing the URL request.
247 bool FilterListHelper::checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const bool isThirdPartyRequest, const QString &filterListTitle,
248 const int sublistInt, EntryStruct *entryStructPointer) const
250 // Check third-party status.
251 if (entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Null) // Ignore third-party status.
253 // Check if filter options are applied.
254 if (entryStructPointer->hasFilterOptions) // Filter options are applied.
256 // Process the filter options.
257 return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
259 else // Filter options are not applied.
261 // Block the request.
262 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
265 else if ((entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Apply) && isThirdPartyRequest) // Block third-party request.
267 // Check if filter options are applied.
268 if (entryStructPointer->hasFilterOptions) // Filter options are applied.
270 // Process the filter options.
271 return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
273 else // Filter options are not applied.
275 // Block the request.
276 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
279 else if ((entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Override) && !isThirdPartyRequest) // Block first-party requests.
281 // Check if filter options are applied.
282 if (entryStructPointer->hasFilterOptions) // Filter options are applied.
284 // Process the filter options.
285 return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
287 else // Filter options are not applied.
289 // Block the request.
290 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
294 // Returning `true` continues to process the filter lists. Returning `false` halts all processing of the filter lists.
298 QString FilterListHelper::getDispositionString(int dispositionInt) const
300 // Return the translated disposition string.
301 switch (dispositionInt)
303 case ALLOWED: return ALLOWED_STRING;
304 case BLOCKED: return BLOCKED_STRING;
305 default: return DEFAULT_STRING;
309 QString FilterListHelper::getFilterOptionDispositionString(const FilterOptionEnum::Disposition filterOptionDisposition) const
311 // Return the translated filter option disposition string.
312 switch (filterOptionDisposition)
314 case FilterOptionEnum::Disposition::Apply: return FILTER_OPTION_APPLY;
315 case FilterOptionEnum::Disposition::Override: return FILTER_OPTION_OVERRIDE;
316 default: return FILTER_OPTION_NULL;
320 QString FilterListHelper::getNavigationTypeString(int navigationTypeInt) const
322 // Return the translated navigation type string.
323 switch (navigationTypeInt)
325 case QWebEngineUrlRequestInfo::NavigationTypeLink: return NAVIGATION_TYPE_LINK;
326 case QWebEngineUrlRequestInfo::NavigationTypeTyped: return NAVIGATION_TYPE_TYPED;
327 case QWebEngineUrlRequestInfo::NavigationTypeFormSubmitted: return NAVIGATION_TYPE_FORM_SUBMITTED;
328 case QWebEngineUrlRequestInfo::NavigationTypeBackForward: return NAVIGATION_TYPE_BACK_FORWARD;
329 case QWebEngineUrlRequestInfo::NavigationTypeReload: return NAVIGATION_TYPE_RELOAD;
330 case QWebEngineUrlRequestInfo::NavigationTypeRedirect: return NAVIGATION_TYPE_REDIRECT;
331 default: return NAVIGATION_TYPE_OTHER;
335 QString FilterListHelper::getResourceTypeString(int resourceTypeInt) const
337 // Return the translated resource type string.
338 switch (resourceTypeInt)
340 case QWebEngineUrlRequestInfo::ResourceTypeMainFrame: return RESOURCE_TYPE_MAIN_FRAME;
341 case QWebEngineUrlRequestInfo::ResourceTypeSubFrame: return RESOURCE_TYPE_SUB_FRAME;
342 case QWebEngineUrlRequestInfo::ResourceTypeStylesheet: return RESOURCE_TYPE_STYLESHEET;
343 case QWebEngineUrlRequestInfo::ResourceTypeScript: return RESOURCE_TYPE_SCRIPT;
344 case QWebEngineUrlRequestInfo::ResourceTypeImage: return RESOURCE_TYPE_IMAGE;
345 case QWebEngineUrlRequestInfo::ResourceTypeFontResource: return RESOURCE_TYPE_FONT_RESOURCE;
346 case QWebEngineUrlRequestInfo::ResourceTypeSubResource: return RESOURCE_TYPE_SUB_RESOURCE;
347 case QWebEngineUrlRequestInfo::ResourceTypeObject: return RESOURCE_TYPE_OBJECT;
348 case QWebEngineUrlRequestInfo::ResourceTypeMedia: return RESOURCE_TYPE_MEDIA;
349 case QWebEngineUrlRequestInfo::ResourceTypeWorker: return RESOURCE_TYPE_WORKER;
350 case QWebEngineUrlRequestInfo::ResourceTypeSharedWorker: return RESOURCE_TYPE_SHARED_WORKER;
351 case QWebEngineUrlRequestInfo::ResourceTypePrefetch: return RESOURCE_TYPE_PREFETCH;
352 case QWebEngineUrlRequestInfo::ResourceTypeFavicon: return RESOURCE_TYPE_FAVICON;
353 case QWebEngineUrlRequestInfo::ResourceTypeXhr: return RESOURCE_TYPE_XHR;
354 case QWebEngineUrlRequestInfo::ResourceTypePing: return RESOURCE_TYPE_PING;
355 case QWebEngineUrlRequestInfo::ResourceTypeServiceWorker: return RESOURCE_TYPE_SERVICE_WORKER;
356 case QWebEngineUrlRequestInfo::ResourceTypeCspReport: return RESOURCE_TYPE_CSP_REPORT;
357 case QWebEngineUrlRequestInfo::ResourceTypePluginResource: return RESOURCE_TYPE_PLUGIN_RESOURCE;
358 case QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame: return RESOURCE_TYPE_NAVIGATION_PRELOAD_MAIN_FRAME;
359 case QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame: return RESOURCE_TYPE_NAVIGATION_PRELOAD_SUB_FRAME;
360 default: return RESOURCE_TYPE_UNKNOWN;
364 QString FilterListHelper::getSublistName(int sublistInt) const
366 // Return the name of the requested sublist.
369 case MAIN_ALLOWLIST: return MAIN_ALLOWLIST_STRING;
370 case MAIN_BLOCKLIST: return MAIN_BLOCKLIST_STRING;
371 case INITIAL_DOMAIN_BLOCKLIST: return INITIAL_DOMAIN_BLOCKLIST_STRING;
372 default: return QString(); // The default return should never be reached.
376 FilterListStruct* FilterListHelper::populateFilterList(const QString &filterListFileName) const
378 // Get the filter list file.
379 QFile filterListFile(filterListFileName);
381 // Open the filter list file.
382 filterListFile.open(QIODevice::ReadOnly);
384 // Create a filter list text stream.
385 QTextStream filterListTextStream(&filterListFile);
387 // Create a filter list struct.
388 FilterListStruct *filterListStructPointer = new FilterListStruct;
390 // Populate the filter list file name.
391 filterListStructPointer->filePath = filterListFileName;
393 // Create a filter list string.
394 QString filterListString;
396 // Process each line of the filter list.
397 while (filterListTextStream.readLineInto(&filterListString)) {
398 // Create an entry struct.
399 EntryStruct *entryStructPointer = new EntryStruct;
401 // Store the original entry.
402 entryStructPointer->originalEntry = filterListString;
404 // Process the entry.
405 if (filterListString.isEmpty()) // Ignore empty lines.
409 // Log the dropping of the line.
410 //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName << " (empty line).";
412 else if (filterListString.startsWith(QLatin1Char('['))) // The line starts with `[`, which is the file format.
416 // Log the dropping of the line.
417 //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName << " (file format).";
419 else if (filterListString.contains(QLatin1String("##")) ||
420 filterListString.contains(QLatin1String("#?#")) ||
421 filterListString.contains(QLatin1String("#@#")) ||
422 filterListString.contains(QLatin1String("#$#"))) // The line contains unimplemented content filtering.
426 // Log the dropping of the line.
427 //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName << " (content filtering).";
429 else if (filterListString.startsWith(QLatin1Char('!'))) // The line starts with `!`, which are comments.
431 if (filterListString.startsWith(QLatin1String("! Title: "))) // The line contains the title.
433 // Add the title to the filter list struct.
434 filterListStructPointer->title = filterListString.remove(0, 9);
436 // Log the addition of the filter list title.
437 //qDebug().noquote().nospace() << "Filter list title: " << filterListString << " added from " << filterListFileName;
439 else if (filterListString.startsWith(QLatin1String("! Version: "))) // The line contains the version.
441 // Add the version to the filter list struct.
442 filterListStructPointer->version = filterListString.remove(0, 11);
444 // Log the addition of the filter list version.
445 //qDebug().noquote().nospace() << "Filter list version: " << filterListString << " added from " << filterListFileName;
450 // Log the dropping of the line.
451 //qDebug().noquote().nospace() << originalFilterListString << " NOT added from " << filterListFileName;
453 else // Process the filter options.
455 // Split any filter options from the end of the string.
456 QStringList splitEntryStringList = filterListString.split(QLatin1Char('$'));
458 // Store the entry without the filter options as the filter list string.
459 filterListString = splitEntryStringList[0];
461 // Create a popup only filter option tracker.
462 bool popupOnlyFilterOption = false;
464 // Process the filter options if they exist.
465 if (splitEntryStringList.size() > 1)
467 // Store the filter options.
468 entryStructPointer->filterOptions = splitEntryStringList[1];
470 // Split the filter options.
471 QStringList filterOptionsList = splitEntryStringList[1].split(QLatin1Char(','));
473 // Check if the entry has a single popup filter option as Qt WebEngine doesn't know how to process them.
474 if ((filterOptionsList.size() == 1) && (filterOptionsList[0] == QLatin1String("popup"))) // This entry has a single popup filter option.
476 // Set the popup only filter option flag.
477 popupOnlyFilterOption = true;
479 else // This entry has filter options besides popup.
481 // Initialize an override struct.
482 OverrideStruct overrideStruct;
484 // Populate the filter options entries.
485 foreach (QString filterOption, filterOptionsList)
487 // Populate the third-party options.
488 if (filterOption == QLatin1String("third-party")) entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Apply;
489 if (filterOption == QLatin1String("~third-party")) entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Override;
491 // Populate the filter options.
492 if (filterOption == QLatin1String("document"))
494 // Populate the main frame option.
495 entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply;
497 // Set the filter options flag.
498 entryStructPointer->hasFilterOptions = true;
501 if (filterOption == QLatin1String("font"))
503 // Populate the font option.
504 entryStructPointer->font = FilterOptionEnum::Disposition::Apply;
506 // Set the filter options flag.
507 entryStructPointer->hasFilterOptions = true;
510 if (filterOption == QLatin1String("image"))
512 // Populate the image option.
513 entryStructPointer->image = FilterOptionEnum::Disposition::Apply;
515 // Set the filter options flag.
516 entryStructPointer->hasFilterOptions = true;
519 if (filterOption == QLatin1String("media"))
521 // Populate the media option.
522 entryStructPointer->media = FilterOptionEnum::Disposition::Apply;
524 // Set the filter options flag.
525 entryStructPointer->hasFilterOptions = true;
528 if (filterOption == QLatin1String("object"))
530 // Populate the object option.
531 entryStructPointer->object = FilterOptionEnum::Disposition::Apply;
533 // Set the filter options flag.
534 entryStructPointer->hasFilterOptions = true;
537 if (filterOption == QLatin1String("other"))
539 // Populate the other option.
540 entryStructPointer->other = FilterOptionEnum::Disposition::Apply;
542 // Set the filter options flag.
543 entryStructPointer->hasFilterOptions = true;
546 if (filterOption == QLatin1String("ping"))
548 // Populate the ping option.
549 entryStructPointer->ping = FilterOptionEnum::Disposition::Apply;
551 // Set the filter options flag.
552 entryStructPointer->hasFilterOptions = true;
555 if (filterOption == QLatin1String("script"))
557 // Populate the script option.
558 entryStructPointer->script = FilterOptionEnum::Disposition::Apply;
560 // Set the filter options flag.
561 entryStructPointer->hasFilterOptions = true;
564 if (filterOption == QLatin1String("stylesheet"))
566 // Populate the script option.
567 entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply;
569 // Set the filter options flag.
570 entryStructPointer->hasFilterOptions = true;
573 if (filterOption == QLatin1String("subdocument"))
575 // Populate the sub resource option.
576 entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply;
578 // Set the filter options flag.
579 entryStructPointer->hasFilterOptions = true;
582 if (filterOption == QLatin1String("xmlhttprequest"))
584 //Populate the XML HTTP request option.
585 entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply;
587 // Set the filter options flag.
588 entryStructPointer->hasFilterOptions = true;
591 // Populate the override struct.
592 if (filterOption == QLatin1String("~document"))
594 // Populate the override struct.
595 overrideStruct.hasOverride = true;
596 overrideStruct.mainFrame = true;
599 if (filterOption == QLatin1String("~font"))
601 // Populate the override struct.
602 overrideStruct.hasOverride = true;
603 overrideStruct.font = true;
606 if (filterOption == QLatin1String("~image"))
608 // Populate the override struct.
609 overrideStruct.hasOverride = true;
610 overrideStruct.image = true;
613 if (filterOption == QLatin1String("~media"))
615 // Populate the override struct.
616 overrideStruct.hasOverride = true;
617 overrideStruct.media = true;
620 if (filterOption == QLatin1String("~object"))
622 // Populate the override struct.
623 overrideStruct.hasOverride = true;
624 overrideStruct.object = true;
627 if (filterOption == QLatin1String("~other"))
629 // Populate the override struct.
630 overrideStruct.hasOverride = true;
631 overrideStruct.other = true;
634 if (filterOption == QLatin1String("~ping"))
636 // Populate the override struct.
637 overrideStruct.hasOverride = true;
638 overrideStruct.ping = true;
641 if (filterOption == QLatin1String("~script"))
643 // Populate the override struct.
644 overrideStruct.hasOverride = true;
645 overrideStruct.script = true;
648 if (filterOption == QLatin1String("~stylesheet"))
650 // Populate the override struct.
651 overrideStruct.hasOverride = true;
652 overrideStruct.styleSheet = true;
655 if (filterOption == QLatin1String("~subdocument"))
657 // Populate the override struct.
658 overrideStruct.hasOverride = true;
659 overrideStruct.subFrame = true;
662 if (filterOption == QLatin1String("~xmlhttprequest"))
664 // Populate the override struct.
665 overrideStruct.hasOverride = true;
666 overrideStruct.xmlHttpRequest = true;
670 // Apply the overrides.
671 if (overrideStruct.hasOverride)
674 if (overrideStruct.font)
675 entryStructPointer->font = FilterOptionEnum::Disposition::Override;
677 entryStructPointer->font = FilterOptionEnum::Disposition::Apply;
680 if (overrideStruct.image)
681 entryStructPointer->image = FilterOptionEnum::Disposition::Override;
683 entryStructPointer->image = FilterOptionEnum::Disposition::Apply;
685 // Main Frame (document).
686 if (overrideStruct.mainFrame)
687 entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Override;
689 entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply;
692 if (overrideStruct.media)
693 entryStructPointer->media = FilterOptionEnum::Disposition::Override;
695 entryStructPointer->media = FilterOptionEnum::Disposition::Apply;
698 if (overrideStruct.object)
699 entryStructPointer->object = FilterOptionEnum::Disposition::Override;
701 entryStructPointer->object = FilterOptionEnum::Disposition::Apply;
704 if (overrideStruct.other)
705 entryStructPointer->other = FilterOptionEnum::Disposition::Override;
707 entryStructPointer->other = FilterOptionEnum::Disposition::Apply;
710 if (overrideStruct.ping)
711 entryStructPointer->ping = FilterOptionEnum::Disposition::Override;
713 entryStructPointer->ping = FilterOptionEnum::Disposition::Apply;
716 if (overrideStruct.script)
717 entryStructPointer->script = FilterOptionEnum::Disposition::Override;
719 entryStructPointer->script = FilterOptionEnum::Disposition::Apply;
722 if (overrideStruct.styleSheet)
723 entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Override;
725 entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply;
728 if (overrideStruct.subFrame)
729 entryStructPointer->subFrame = FilterOptionEnum::Disposition::Override;
731 entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply;
734 if (overrideStruct.xmlHttpRequest)
735 entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Override;
737 entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply;
742 // Drop entries that only have a single popup filter option as Qt WebEngine doesn't know how to process them.
743 if (popupOnlyFilterOption) // This entry has a single popup filter option.
747 // Log the dropping of the line.
748 //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " NOT added from " << filterListFileName << " (single popup filter option).";
750 else if (filterListString.startsWith(QLatin1String("@@"))) // Process an allow list entry.
752 // Remove the initial `@@`.
753 filterListString.remove(0, 2);
755 // Remove any initial and trailing asterisks.
756 removeInitialAndTrailingAsterisks(filterListString);
758 // Add the applied entry to the struct.
759 entryStructPointer->appliedEntry = filterListString;
761 // Add the filter list entry struct to the main allow list.
762 filterListStructPointer->mainAllowList.push_front(entryStructPointer);
764 // Log the addition to the filter list.
765 //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Main Allow List from " << filterListFileName << ".";
767 else if (filterListString.startsWith(QLatin1String("||"))) // Process an initial domain allow list entry.
769 // Remove the initial `||`.
770 filterListString.remove(0, 2);
772 // Add the applied entry to the struct.
773 entryStructPointer->appliedEntry = filterListString;
775 // Add the filter list entry struct to the initial domain block list.
776 filterListStructPointer->initialDomainBlockList.push_front(entryStructPointer);
778 // Log the addition to the filter list.
779 //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Initial Domain Block List from " << filterListFileName << ".";
781 else // Process a block list entry.
783 // Remove any initial and trailing asterisks.
784 removeInitialAndTrailingAsterisks(filterListString);
786 // Add the applied entry to the struct.
787 entryStructPointer->appliedEntry = filterListString;
789 // Add the filter list entry struct to the main block list.
790 filterListStructPointer->mainBlockList.push_front(entryStructPointer);
792 // Log the addition to the filter list.
793 //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Main Block List from " << filterListFileName << ".";
798 // Close the filter list file.
799 filterListFile.close();
801 // Return the filter list pair.
802 return filterListStructPointer;
805 void FilterListHelper::populateRequestStruct(RequestStruct *requestStructPointer, const int disposition, const QString &filterListTitle, const int sublistInt, EntryStruct *entryStructPointer) const
807 // Populate the request struct.
808 requestStructPointer->dispositionInt = disposition;
809 requestStructPointer->filterListTitle = filterListTitle;
810 requestStructPointer->sublistInt = sublistInt;
811 requestStructPointer->entryStruct.appliedEntry = entryStructPointer->appliedEntry;
812 requestStructPointer->entryStruct.originalEntry = entryStructPointer->originalEntry;
815 bool FilterListHelper::processFilterOptions(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt,
816 EntryStruct *entryStructPointer) const
818 // Block font requests.
819 if ((entryStructPointer->font == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFontResource))
821 // Block the request.
822 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
825 // Block image requests.
826 if ((entryStructPointer->image == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeImage))
828 // Block the request.
829 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
832 // Block main frame requests.
833 if ((entryStructPointer->mainFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMainFrame) ||
834 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame)))
836 // Block the request.
837 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
840 // Block media requests.
841 if ((entryStructPointer->media == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMedia))
843 // Block the request.
844 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
847 // Block object requests.
848 if ((entryStructPointer->object == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeObject))
850 // Block the request.
851 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
854 // Block other requests.
855 if ((entryStructPointer->other == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubResource) ||
856 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeWorker) ||
857 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSharedWorker) ||
858 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePrefetch) ||
859 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFavicon) ||
860 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeServiceWorker) ||
861 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeCspReport) ||
862 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePluginResource) ||
863 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeUnknown)))
865 // Block the request.
866 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
869 // Block ping requests
870 if ((entryStructPointer->ping == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePing))
872 // Block the request.
873 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
876 // Block script requests.
877 if ((entryStructPointer->script == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeScript))
879 // Block the request.
880 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
883 // Block style sheet requests.
884 if ((entryStructPointer->styleSheet == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeStylesheet))
886 // Block the request.
887 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
890 // Block sub resource requests.
891 if ((entryStructPointer->subFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubFrame) ||
892 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame)))
894 // Block the request.
895 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
898 // Block XML HTTP requests.
899 if ((entryStructPointer->xmlHttpRequest == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeXhr))
901 // Block the request.
902 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
905 // Returning true continues processing the filter list.
909 void FilterListHelper::removeInitialAndTrailingAsterisks(QString &filterListEntry) const
911 // Remove the initial asterisk if it exists.
912 if (filterListEntry.startsWith(QLatin1Char('*')))
913 filterListEntry.remove(0, 1);
915 // Remove the final asterisk if it exists.
916 if (filterListEntry.endsWith(QLatin1Char('*')))
917 filterListEntry.chop(1);