X-Git-Url: https://gitweb.stoutner.com/?a=blobdiff_plain;f=src%2Fhelpers%2FFilterListHelper.cpp;fp=src%2Fhelpers%2FFilterListHelper.cpp;h=e4ce25f529d3a2cbce839fa7fcac435b6eaaa055;hb=be625d0fcb1f4e8184ed62a28d23629f8c246d8e;hp=f84112b58531ad17f1262eb68dd5e7dff5161403;hpb=f8f8d907d0caa128abf73696f812f8e92db812b7;p=PrivacyBrowserPC.git diff --git a/src/helpers/FilterListHelper.cpp b/src/helpers/FilterListHelper.cpp index f84112b..e4ce25f 100644 --- a/src/helpers/FilterListHelper.cpp +++ b/src/helpers/FilterListHelper.cpp @@ -21,14 +21,15 @@ #include "FilterListHelper.h" #include "structs/OverrideStruct.h" +// KDE Framework headers. +#include + // Qt toolkit headers. #include #include +#include #include -// KDE Framework headers. -#include - // Construct the class. FilterListHelper::FilterListHelper() { @@ -78,18 +79,19 @@ FilterListHelper::FilterListHelper() MAIN_ALLOWLIST_STRING = i18nc("Main allowlist sublist", "Main Allow List"); MAIN_BLOCKLIST_STRING = i18nc("Main blocklist sublist", "Main Block List"); INITIAL_DOMAIN_BLOCKLIST_STRING = i18nc("Initial domain blocklist string", "Initial Domain Block List"); + REGULAR_EXPRESSION_BLOCKLIST_STRING = i18nc("Regular expression blocklist string", "Regular Expression Block List"); // Populate the filter lists. - ultraListStructPointer = populateFilterList(QLatin1String(":/filterlists/ultralist.txt")); ultraPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/ultraprivacy.txt")); - easyListStructPointer = populateFilterList(QLatin1String(":/filterlists/easylist.txt")); + ultraListStructPointer = populateFilterList(QLatin1String(":/filterlists/ultralist.txt")); easyPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/easyprivacy.txt")); + easyListStructPointer = populateFilterList(QLatin1String(":/filterlists/easylist.txt")); fanboyAnnoyanceStructPointer = populateFilterList(QLatin1String(":/filterlists/fanboy-annoyance.txt")); } bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer) const { - // Initiate a continue checking tracker. If the tracker changes to false, all process of the request will be stopped. + // Initiate a continue checking tracker. If the tracker changes to false, all processing of the request will be stopped. bool continueChecking = true; // Create a URL struct. @@ -101,10 +103,10 @@ bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo // Get the hosts. QString firstPartyHost = firstPartyUrl.host(); - QString requestHost = requestUrl.host(); + urlStruct.fqdn = requestUrl.host(); // Determine if this is a third-party request. - urlStruct.isThirdPartyRequest = (firstPartyHost != requestHost); + urlStruct.isThirdPartyRequest = (firstPartyHost != urlStruct.fqdn); // Get the request URL string. urlStruct.urlString = requestUrl.toString(); @@ -119,8 +121,9 @@ bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo urlStruct.urlStringWithSeparators.replace(QLatin1Char('='), QLatin1Char('^')); urlStruct.urlStringWithSeparators.replace(QLatin1Char('&'), QLatin1Char('^')); - // Add a `^` to the end of the string. - urlStruct.urlStringWithSeparators.append(QLatin1Char('^')); + // Add a `^` to the end of the string it it doesn't already contain one. + if (!urlStruct.urlStringWithSeparators.endsWith(QLatin1Char('^'))) + urlStruct.urlStringWithSeparators.append(QLatin1Char('^')); // Create truncated URL strings and initially populate it with the original URL strings. urlStruct.truncatedUrlString = urlStruct.urlString; @@ -134,20 +137,21 @@ bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo urlStruct.truncatedUrlStringWithSeparators.remove(0, fqdnIndex); // Check UltraList. - continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraListStructPointer); + continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraPrivacyStructPointer); // Check UltraPrivacy. if (continueChecking) - continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraPrivacyStructPointer); - - // Check EasyList. - if (continueChecking) - continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyListStructPointer); + continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraListStructPointer); // Check EasyPrivacy. if (continueChecking) continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyPrivacyStructPointer); + // Check EasyList. + if (continueChecking) + continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyListStructPointer); + + // Check Fanboy's Annoyance list. if (continueChecking) continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, fanboyAnnoyanceStructPointer); @@ -155,35 +159,22 @@ bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo return continueChecking; } -bool FilterListHelper::blockRequest(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, - EntryStruct *entryStructPointer) const -{ - // Block the request. - urlRequestInfo.block(true); - - // Populate the request struct. - populateRequestStruct(requestStructPointer, BLOCKED, filterListTitle, sublistInt, entryStructPointer); - - // Log the block. - //qDebug().noquote().nospace() << "Blocked request: " << urlRequestInfo.firstPartyUrl() << ", Filter list entry: " << entryStructPointer->appliedEntry; - - // Returning `false` stops all processing of the request. - return false; -} - bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, FilterListStruct *filterListStructPointer) const { + // Initiate a continue checking tracker. If the tracker changes to false, all process of the request will be stopped. + bool continueChecking = true; + // Check the main allow list. - for (auto filterListEntry = filterListStructPointer->mainAllowList.begin(); filterListEntry != filterListStructPointer->mainAllowList.end(); ++filterListEntry) + for (auto filterListEntry = filterListStructPointer->mainAllowListPointer->begin(); filterListEntry != filterListStructPointer->mainAllowListPointer->end(); ++filterListEntry) { // Get the entry struct. EntryStruct *entryStructPointer = *filterListEntry; // TODO. Temporarily ignore empty applied entries. - if (!entryStructPointer->appliedEntry.isEmpty()) + if (!entryStructPointer->appliedEntryList[0].isEmpty()) { - // Check if the URL string contains the applied entry. - if (urlStruct.urlString.contains(entryStructPointer->appliedEntry) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntry)) + // Check if the URL string contains the applied entry. TODO. + if (urlStruct.urlString.contains(entryStructPointer->appliedEntryList[0]) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntryList[0])) { // Allow the request. urlRequestInfo.block(false); @@ -200,47 +191,384 @@ bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestI } } + // Get the main block list end. + auto mainBlockListEnd = filterListStructPointer->mainBlockListPointer->end(); + // Check the main block list. - for (auto filterListEntry = filterListStructPointer->mainBlockList.begin(); filterListEntry != filterListStructPointer->mainBlockList.end(); ++filterListEntry) + for (auto mainBlockListEntry = filterListStructPointer->mainBlockListPointer->begin(); mainBlockListEntry != mainBlockListEnd; ++mainBlockListEntry) { + // Exit the loop if continue checking is false. + if (!continueChecking) + break; + // Get the entry struct. - EntryStruct *entryStructPointer = *filterListEntry; + EntryStruct *entryStructPointer = *mainBlockListEntry; - // TODO. Temporarily ignore empty applied entries. - if (!entryStructPointer->appliedEntry.isEmpty()) + // Check the applied entries. + continueChecking = checkAppliedEntry(urlRequestInfo, urlStruct, requestStructPointer, filterListStructPointer->title, MAIN_BLOCKLIST, entryStructPointer, urlStruct.urlString, + urlStruct.urlStringWithSeparators); + } + + // Get the initial domain block list end. + auto initialDomainBlockListEnd = filterListStructPointer->initialDomainBlockListPointer->end(); + + // Check the initial domain block list. + for (auto initialDomainBlockListEntry = filterListStructPointer->initialDomainBlockListPointer->begin(); initialDomainBlockListEntry != initialDomainBlockListEnd; + ++initialDomainBlockListEntry) + { + // Exit the loop if continue checking is false. + if (!continueChecking) + break; + + // Get the entry struct. + EntryStruct *entryStructPointer = *initialDomainBlockListEntry; + + // Check the applied entries. + continueChecking = checkAppliedEntry(urlRequestInfo, urlStruct, requestStructPointer, filterListStructPointer->title, INITIAL_DOMAIN_BLOCKLIST, entryStructPointer, + urlStruct.truncatedUrlString, urlStruct.truncatedUrlStringWithSeparators); + } + + // Get the regular expression block list end. + auto regularExpressionBlockListEnd = filterListStructPointer->regularExpressionBlockListPointer->end(); + + // Check the regular expression block list. + for (auto regularExpressionBlockListEntry = filterListStructPointer->regularExpressionBlockListPointer->begin(); regularExpressionBlockListEntry != regularExpressionBlockListEnd; + ++regularExpressionBlockListEntry) + { + // Exit the loop if continue checking is false. + if (!continueChecking) + break; + + // Get the entry struct. + EntryStruct *entryStructPointer = *regularExpressionBlockListEntry; + + // Check the applied entries. + continueChecking = checkRegularExpression(urlRequestInfo, urlStruct, requestStructPointer, filterListStructPointer->title, REGULAR_EXPRESSION_BLOCKLIST, entryStructPointer); + } + + // Return the continue checking status. + return continueChecking; +} + +bool FilterListHelper::checkAppliedEntry(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle, + const int sublistInt, EntryStruct *entryStructPointer, QString &urlString, QString &urlStringWithSeparators) const +{ + // Check the entries according to the number. + if (entryStructPointer->singleAppliedEntry) + { + // Process initial and final matches. + if (entryStructPointer->initialMatch && entryStructPointer->finalMatch) // This is both an initial and final match. + { + // Check the URL against the applied entry. + if ((urlString == entryStructPointer->appliedEntryList[0]) || (urlStringWithSeparators == entryStructPointer->appliedEntryList[0])) + { + // Check the domain status. + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + } + else if (entryStructPointer->initialMatch) // This is an initial match. + { + // Check the URL against the applied entry. + if (urlString.startsWith(entryStructPointer->appliedEntryList[0]) || urlStringWithSeparators.startsWith(entryStructPointer->appliedEntryList[0])) + { + // Check the domain status. + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + } + else if (entryStructPointer->finalMatch) // This is a final match. + { + // Check the URL against the applied entry. + if (urlString.endsWith(entryStructPointer->appliedEntryList[0]) || urlStringWithSeparators.endsWith(entryStructPointer->appliedEntryList[0])) + { + // Check the domain status. + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + } + else // There is no initial or final matching. { // Check if the URL string contains the applied entry. - if (urlStruct.urlString.contains(entryStructPointer->appliedEntry) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntry)) + if (urlString.contains(entryStructPointer->appliedEntryList[0]) || urlStringWithSeparators.contains(entryStructPointer->appliedEntryList[0])) { - // Check the third-party status. - bool continueChecking = checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListStructPointer->title, MAIN_BLOCKLIST, entryStructPointer); + // Check the domain status. + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + } + } + else // There are multiple entries. + { + // Create a URL matches flag. + bool urlMatches = true; + + // Process initial and final matches. + if (entryStructPointer->initialMatch && entryStructPointer->finalMatch) // This is both an initial and final match. + { + // Check the first entry. + if (urlString.startsWith(entryStructPointer->appliedEntryList[0]) || + urlStringWithSeparators.startsWith(entryStructPointer->appliedEntryList[0])) // The URL string starts with the first applied entry. + { + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = entryStructPointer->appliedEntryList[0].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The URL string does not end with the last applied entry. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + + // Check the other entries if the URL still matches. + if (urlMatches) + { + // Calculate the penultimate entry. + int penultimateEntryNumber = (entryStructPointer->sizeOfAppliedEntryList - 1); + int ultimateEntryIndex = penultimateEntryNumber; + + // Check all the middle entries. + for (int i = 1; i < penultimateEntryNumber; ++i) + { + // Get the index of the applied entry, which will be `-1` if it doesn't exist. + int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]); + int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]); + + // Get the larger of the two indexes. + int index = std::max(stringIndex, stringWithSeparatorsIndex); + + // Check if the entry was found. + if (index >= 0) // The entry is contained in the URL string. + { + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The entry is not contained in the URL string. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + } + + // Check the final entry if the URL still matches. + if (urlMatches) + { + if (urlString.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex]) || + urlStringWithSeparators.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex])) // The URL string ends with the last applied entry. + { + // There is no need to modify the URL string copies as no further checks will be performed. + } + else // The URL string does not end with the last applied entry. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + } + } + } + else if (entryStructPointer->initialMatch) // This is an initial match. + { + // Check the first entry. + if (urlString.startsWith(entryStructPointer->appliedEntryList[0]) || + urlStringWithSeparators.startsWith(entryStructPointer->appliedEntryList[0])) // The URL string starts with the first applied entry. + { + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = entryStructPointer->appliedEntryList[0].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The URL string does not end with the last applied entry. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + + // Check the other entries if the URL still matches. + if (urlMatches) + { + for (int i = 1; i < entryStructPointer->sizeOfAppliedEntryList; ++i) + { + // Get the index of the applied entry, which will be `-1` if it doesn't exist. + int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]); + int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]); + + // Get the larger of the two indexes. + int index = std::max(stringIndex, stringWithSeparatorsIndex); + + // Check if the entry was found. + if (index >= 0) // The entry is contained in the URL string. + { + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The entry is not contained in the URL string. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + } + } + } + else if (entryStructPointer->finalMatch) // This is a final match. + { + // Calculate the penultimate entry. + int penultimateEntryNumber = (entryStructPointer->sizeOfAppliedEntryList - 1); + int ultimateEntryIndex = penultimateEntryNumber; + + // Check all the entries except the last one. + for (int i = 0; i < penultimateEntryNumber; ++i) + { + // Get the index of the applied entry, which will be `-1` if it doesn't exist. + int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]); + int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]); + + // Get the larger of the two indexes. + int index = std::max(stringIndex, stringWithSeparatorsIndex); + + // Check if the entry was found. + if (index >= 0) // The entry is contained in the URL string. + { + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The entry is not contained in the URL string. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + } - // Stop processing the filter lists if continue checking is `false`. Returning false halts all processing at upper levels. - if (continueChecking == false) - return false; + // Check the final entry if the URL still matches. + if (urlMatches) + { + if (urlString.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex]) || + urlStringWithSeparators.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex])) // The URL string ends with the last applied entry. + { + // There is no need to modify the URL string copies as no further checks will be performed. + } + else // The URL string does not end with the last applied entry. + { + // Mark the URL matches flag as false. + urlMatches = false; + } } } + else // There is no initial or final matching. + { + for (int i = 0; i < entryStructPointer->sizeOfAppliedEntryList; ++i) + { + // Get the index of the applied entry, which will be `-1` if it doesn't exist. + int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]); + int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]); + + // Get the larger of the two indexes. + int index = std::max(stringIndex, stringWithSeparatorsIndex); + + // Check if the entry was found. + if (index >= 0) // The entry is contained in the URL string. + { + + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The entry is not contained in the URL string. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + } + } + + // Check the domain status if the URL matches. + if (urlMatches) + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); } - // Check the initial domain block list. - for (auto filterListEntry = filterListStructPointer->initialDomainBlockList.begin(); filterListEntry != filterListStructPointer->initialDomainBlockList.end(); ++filterListEntry) + // If the applied entry doesn't match, return `true` to continue processing the URL request. + return true; +} + +bool FilterListHelper::checkRegularExpression(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle, + const int sublistInt, EntryStruct *entryStructPointer) const +{ + // Create an applied entry regular expression. + QRegularExpression appliedEntryRegularExpression(entryStructPointer->appliedEntryList[0]); + + // Check if the regular expression matches the applied entry. + if (urlStruct.urlString.contains(appliedEntryRegularExpression)) { - // Get the entry struct. - EntryStruct *entryStructPointer = *filterListEntry; + // Check the domain status. + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } - // Check if the truncated URL string begins with the applied entry. - if (urlStruct.truncatedUrlString.startsWith(entryStructPointer->appliedEntry) || urlStruct.truncatedUrlStringWithSeparators.startsWith(entryStructPointer->appliedEntry)) + // If the regular expression doesn't match, return `true` to continue processing the URL request. + return true; +} + +bool FilterListHelper::checkDomain(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, + EntryStruct *entryStructPointer) const +{ + // Check domain status. + if (entryStructPointer->domain == FilterOptionEnum::Disposition::Null) // Ignore domain status. + { + // Check the third-party status. + return checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListTitle, sublistInt, entryStructPointer); + } + else if (entryStructPointer->domain == FilterOptionEnum::Disposition::Apply) // Block requests from listed domains. + { + // Check each domain. + foreach (QString blockedDomain, entryStructPointer->domainList) { - // Check the third-party status. - bool continueChecking = checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListStructPointer->title, INITIAL_DOMAIN_BLOCKLIST, entryStructPointer); + // Check if the request came from a blocked domain. + if (urlStruct.fqdn.endsWith(blockedDomain)) + { + // Check the third-party status. + return checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListTitle, sublistInt, entryStructPointer); + } + } + } + else if (entryStructPointer->domain == FilterOptionEnum::Disposition::Override) // Block domains that are not overridden. + { + // Create a block domain flag. + bool blockDomain = true; - // Stop processing the filter lists if continue checking is `false`. Returning false halts all processing at upper levels. - if (continueChecking == false) - return false; + // Check each overridden domain. + foreach (QString overriddenDomain, entryStructPointer->domainList) + { + // Check if the request came from an overridden domain. + if (urlStruct.fqdn.endsWith(overriddenDomain)) + { + // Don't block the domain. + blockDomain = false; + } + } + + // Continue checking if the domain is blocked. + if (blockDomain) + { + // Check the third-party status. + return checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListTitle, sublistInt, entryStructPointer); } } - // Return `true` to continue processing the URL request. + // There is a domain specified that doesn't match this request. Return `true` to continue processing the URL request. return true; } @@ -250,13 +578,13 @@ bool FilterListHelper::checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, // Check third-party status. if (entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Null) // Ignore third-party status. { - // Check if filter options are applied. - if (entryStructPointer->hasFilterOptions) // Filter options are applied. + // Check if request options are applied. + if (entryStructPointer->hasRequestOptions) // Request options are applied. { - // Process the filter options. - return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + // Check the request options. + return checkRequestOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); } - else // Filter options are not applied. + else // Request options are not applied. { // Block the request. return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); @@ -264,13 +592,13 @@ bool FilterListHelper::checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, } else if ((entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Apply) && isThirdPartyRequest) // Block third-party request. { - // Check if filter options are applied. - if (entryStructPointer->hasFilterOptions) // Filter options are applied. + // Check if request options are applied. + if (entryStructPointer->hasRequestOptions) // Request options are applied. { - // Process the filter options. - return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + // Check the request options. + return checkRequestOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); } - else // Filter options are not applied. + else // Request options are not applied. { // Block the request. return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); @@ -278,23 +606,133 @@ bool FilterListHelper::checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, } else if ((entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Override) && !isThirdPartyRequest) // Block first-party requests. { - // Check if filter options are applied. - if (entryStructPointer->hasFilterOptions) // Filter options are applied. + // Check if request options are applied. + if (entryStructPointer->hasRequestOptions) // Request options are applied. { - // Process the filter options. - return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + // Check the request options. + return checkRequestOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); } - else // Filter options are not applied. + else // Request options are not applied. { // Block the request. return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); } } - // Returning `true` continues to process the filter lists. Returning `false` halts all processing of the filter lists. + // The third-party option specified doesn't match this request. Return `true` to continue processing the URL request. + return true; +} + +bool FilterListHelper::checkRequestOptions(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, + EntryStruct *entryStructPointer) const +{ + // Block font requests. + if ((entryStructPointer->font == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFontResource)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block image requests. + if ((entryStructPointer->image == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeImage)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block main frame requests. + if ((entryStructPointer->mainFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMainFrame) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame))) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block media requests. + if ((entryStructPointer->media == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMedia)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block object requests. + if ((entryStructPointer->object == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeObject)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block other requests. + if ((entryStructPointer->other == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubResource) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeWorker) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSharedWorker) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePrefetch) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFavicon) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeServiceWorker) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeCspReport) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePluginResource) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeUnknown))) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block ping requests + if ((entryStructPointer->ping == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePing)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block script requests. + if ((entryStructPointer->script == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeScript)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block style sheet requests. + if ((entryStructPointer->styleSheet == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeStylesheet)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block sub resource requests. + if ((entryStructPointer->subFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubFrame) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame))) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block XML HTTP requests. + if ((entryStructPointer->xmlHttpRequest == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeXhr)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // The request options specified don't match this request. Return `true` to continue processing the URL request. return true; } +bool FilterListHelper::blockRequest(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, + EntryStruct *entryStructPointer) const +{ + // Block the request. + urlRequestInfo.block(true); + + // Populate the request struct. + populateRequestStruct(requestStructPointer, BLOCKED, filterListTitle, sublistInt, entryStructPointer); + + // Log the block. + //qDebug().noquote().nospace() << "Blocked request: " << urlRequestInfo.firstPartyUrl() << ", Filter list entry: " << entryStructPointer->appliedEntry; + + // Returning `false` stops all processing of the request. + return false; +} + QString FilterListHelper::getDispositionString(int dispositionInt) const { // Return the translated disposition string. @@ -306,17 +744,6 @@ QString FilterListHelper::getDispositionString(int dispositionInt) const } } -QString FilterListHelper::getFilterOptionDispositionString(const FilterOptionEnum::Disposition filterOptionDisposition) const -{ - // Return the translated filter option disposition string. - switch (filterOptionDisposition) - { - case FilterOptionEnum::Disposition::Apply: return FILTER_OPTION_APPLY; - case FilterOptionEnum::Disposition::Override: return FILTER_OPTION_OVERRIDE; - default: return FILTER_OPTION_NULL; - } -} - QString FilterListHelper::getNavigationTypeString(int navigationTypeInt) const { // Return the translated navigation type string. @@ -332,6 +759,17 @@ QString FilterListHelper::getNavigationTypeString(int navigationTypeInt) const } } +QString FilterListHelper::getRequestOptionDispositionString(const FilterOptionEnum::Disposition filterOptionDisposition) const +{ + // Return the translated filter option disposition string. + switch (filterOptionDisposition) + { + case FilterOptionEnum::Disposition::Apply: return FILTER_OPTION_APPLY; + case FilterOptionEnum::Disposition::Override: return FILTER_OPTION_OVERRIDE; + default: return FILTER_OPTION_NULL; + } +} + QString FilterListHelper::getResourceTypeString(int resourceTypeInt) const { // Return the translated resource type string. @@ -369,6 +807,7 @@ QString FilterListHelper::getSublistName(int sublistInt) const case MAIN_ALLOWLIST: return MAIN_ALLOWLIST_STRING; case MAIN_BLOCKLIST: return MAIN_BLOCKLIST_STRING; case INITIAL_DOMAIN_BLOCKLIST: return INITIAL_DOMAIN_BLOCKLIST_STRING; + case REGULAR_EXPRESSION_BLOCKLIST: return REGULAR_EXPRESSION_BLOCKLIST_STRING; default: return QString(); // The default return should never be reached. } } @@ -452,342 +891,362 @@ FilterListStruct* FilterListHelper::populateFilterList(const QString &filterList } else // Process the filter options. { - // Split any filter options from the end of the string. - QStringList splitEntryStringList = filterListString.split(QLatin1Char('$')); - - // Store the entry without the filter options as the filter list string. - filterListString = splitEntryStringList[0]; - - // Create a popup only filter option tracker. - bool popupOnlyFilterOption = false; + // Get the index of the last dollar sign. + int indexOfLastDollarSign = filterListString.lastIndexOf(QLatin1Char('$')); // Process the filter options if they exist. - if (splitEntryStringList.size() > 1) + if (indexOfLastDollarSign > -1) { - // Store the filter options. - entryStructPointer->filterOptions = splitEntryStringList[1]; + // Get the filter options. + entryStructPointer->originalFilterOptions = filterListString.section(QLatin1Char('$'), -1); + + // Store the entry without the filter options as the filter list string. + filterListString.truncate(indexOfLastDollarSign); // Split the filter options. - QStringList filterOptionsList = splitEntryStringList[1].split(QLatin1Char(',')); + QStringList originalFilterOptionsList = entryStructPointer->originalFilterOptions.split(QLatin1Char(',')); - // Check if the entry has a single popup filter option as Qt WebEngine doesn't know how to process them. - if ((filterOptionsList.size() == 1) && (filterOptionsList[0] == QLatin1String("popup"))) // This entry has a single popup filter option. + // Create an applied filter options list. + QStringList appliedFilterOptionsList; + + // Populate the applied filter options list. + foreach (QString filterOption, originalFilterOptionsList) { - // Set the popup only filter option flag. - popupOnlyFilterOption = true; + // Only add filter options that are handled by Privacy Browser. + if (!(filterOption.startsWith(QLatin1String("csp=")) || + filterOption.startsWith(QLatin1String("method=")) || + filterOption.startsWith(QLatin1String("redirect=")) || + filterOption.startsWith(QLatin1String("rewrite=")))) + appliedFilterOptionsList.append(filterOption); } - else // This entry has filter options besides popup. - { - // Initialize an override struct. - OverrideStruct overrideStruct; - // Populate the filter options entries. - foreach (QString filterOption, filterOptionsList) - { - // Populate the third-party options. - if (filterOption == QLatin1String("third-party")) entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("~third-party")) entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Override; - - // Populate the filter options. - if (filterOption == QLatin1String("document")) - { - // Populate the main frame option. - entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply; - - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } - - if (filterOption == QLatin1String("font")) - { - // Populate the font option. - entryStructPointer->font = FilterOptionEnum::Disposition::Apply; - - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } - - if (filterOption == QLatin1String("image")) - { - // Populate the image option. - entryStructPointer->image = FilterOptionEnum::Disposition::Apply; + // Store the applied filter options list. + entryStructPointer->appliedFilterOptionsList = appliedFilterOptionsList; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Initialize an override struct. + OverrideStruct overrideStruct; - if (filterOption == QLatin1String("media")) - { - // Populate the media option. - entryStructPointer->media = FilterOptionEnum::Disposition::Apply; + // Populate the filter options entries. + foreach (QString filterOption, appliedFilterOptionsList) + { + // Parse the filter options. + if (filterOption.startsWith(QLatin1String("domain="))) // Domain. + { + // Remove `domain=` from the filter option. + filterOption.remove(0, 7); - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Store the domain list. + entryStructPointer->domainList = filterOption.split(QLatin1Char('|')); - if (filterOption == QLatin1String("object")) + // Set the disposition. + if (entryStructPointer->domainList[0].startsWith(QLatin1Char('~'))) // Override domains. { - // Populate the object option. - entryStructPointer->object = FilterOptionEnum::Disposition::Apply; + // Populate the domain filter disposition. + entryStructPointer->domain = FilterOptionEnum::Disposition::Override; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; + // Remove the initial `~` from each domain. + entryStructPointer->domainList.replaceInStrings(QLatin1String("~"), QLatin1String("")); } - - if (filterOption == QLatin1String("other")) + else // Standard domains. { - // Populate the other option. - entryStructPointer->other = FilterOptionEnum::Disposition::Apply; - - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; + // Populate the domain filter disposition. + entryStructPointer->domain = FilterOptionEnum::Disposition::Apply; } + } + else if (filterOption == QLatin1String("third-party")) // Third-party. + { + // Populate the third-party filter disposition. + entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Apply; + } + else if (filterOption == QLatin1String("~third-party")) // Third-party override. + { + // Populate the third-party filter disposition. + entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Override; + } + else if ((filterOption == QLatin1String("document")) || (filterOption == QLatin1String("popup"))) // Document (and popup). + { + // Populate the main frame disposition. + entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("ping")) - { - // Populate the ping option. - entryStructPointer->ping = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("font")) // Font. + { + // Populate the font disposition. + entryStructPointer->font = FilterOptionEnum::Disposition::Apply; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("image")) // Image. + { + // Populate the image disposition. + entryStructPointer->image = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("script")) - { - // Populate the script option. - entryStructPointer->script = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("media")) // Media. + { + // Populate the media disposition. + entryStructPointer->media = FilterOptionEnum::Disposition::Apply; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("object")) // Object. + { + // Populate the object disposition. + entryStructPointer->object = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("stylesheet")) - { - // Populate the script option. - entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if ((filterOption == QLatin1String("other")) || (filterOption == QLatin1String("webrtc")) || (filterOption == QLatin1String("websocket"))) // Other. + { // `websocket` will get its own section in Qt6. + // Populate the other disposition. + entryStructPointer->other = FilterOptionEnum::Disposition::Apply; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("ping")) // Ping. + { + // Populate the ping disposition. + entryStructPointer->ping = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("subdocument")) - { - // Populate the sub resource option. - entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("script")) // Script. + { + // Populate the script disposition. + entryStructPointer->script = FilterOptionEnum::Disposition::Apply; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("stylesheet")) // Style sheet. + { + // Populate the script disposition. + entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("xmlhttprequest")) - { - //Populate the XML HTTP request option. - entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("subdocument")) // Sub document. + { + // Populate the sub resource disposition. + entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("xmlhttprequest")) // XML HTTP request. + { + //Populate the XML HTTP request disposition. + entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("~document")) // Document override. + { // Populate the override struct. - if (filterOption == QLatin1String("~document")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.mainFrame = true; - } - - if (filterOption == QLatin1String("~font")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.font = true; - } - - if (filterOption == QLatin1String("~image")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.image = true; - } - - if (filterOption == QLatin1String("~media")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.media = true; - } - - if (filterOption == QLatin1String("~object")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.object = true; - } - - if (filterOption == QLatin1String("~other")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.other = true; - } - - if (filterOption == QLatin1String("~ping")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.ping = true; - } - - if (filterOption == QLatin1String("~script")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.script = true; - } - - if (filterOption == QLatin1String("~stylesheet")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.styleSheet = true; - } - - if (filterOption == QLatin1String("~subdocument")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.subFrame = true; - } - - if (filterOption == QLatin1String("~xmlhttprequest")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.xmlHttpRequest = true; - } + overrideStruct.hasOverride = true; + overrideStruct.mainFrame = true; } - - // Apply the overrides. - if (overrideStruct.hasOverride) + else if (filterOption == QLatin1String("~font")) // Font override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.font = true; + } + else if (filterOption == QLatin1String("~image")) // Image override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.image = true; + } + else if (filterOption == QLatin1String("~media")) // Media override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.media = true; + } + else if (filterOption == QLatin1String("~object")) // Object override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.object = true; + } + else if ((filterOption == QLatin1String("~other")) || (filterOption == QLatin1String("~webrtc")) || (filterOption == QLatin1String("~websocket"))) // Other override. + { // `websocket` will get its own section in Qt6. + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.other = true; + } + else if (filterOption == QLatin1String("~ping")) // Ping override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.ping = true; + } + else if (filterOption == QLatin1String("~script")) // Script override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.script = true; + } + else if (filterOption == QLatin1String("~stylesheet")) // Style sheet override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.styleSheet = true; + } + else if (filterOption == QLatin1String("~subdocument")) // Sub document override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.subFrame = true; + } + else if (filterOption == QLatin1String("~xmlhttprequest")) // XML HTTP request override. { - // Font. - if (overrideStruct.font) - entryStructPointer->font = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->font = FilterOptionEnum::Disposition::Apply; - - // Image. - if (overrideStruct.image) - entryStructPointer->image = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->image = FilterOptionEnum::Disposition::Apply; - - // Main Frame (document). - if (overrideStruct.mainFrame) - entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply; - - // Media. - if (overrideStruct.media) - entryStructPointer->media = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->media = FilterOptionEnum::Disposition::Apply; - - // Object. - if (overrideStruct.object) - entryStructPointer->object = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->object = FilterOptionEnum::Disposition::Apply; - - // Other. - if (overrideStruct.other) - entryStructPointer->other = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->other = FilterOptionEnum::Disposition::Apply; - - // Ping. - if (overrideStruct.ping) - entryStructPointer->ping = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->ping = FilterOptionEnum::Disposition::Apply; - - // Script. - if (overrideStruct.script) - entryStructPointer->script = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->script = FilterOptionEnum::Disposition::Apply; - - // Style Sheet. - if (overrideStruct.styleSheet) - entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply; - - // Sub Resource. - if (overrideStruct.subFrame) - entryStructPointer->subFrame = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply; - - // XML HTTP Request. - if (overrideStruct.xmlHttpRequest) - entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply; + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.xmlHttpRequest = true; } } - } - // Drop entries that only have a single popup filter option as Qt WebEngine doesn't know how to process them. - if (popupOnlyFilterOption) // This entry has a single popup filter option. + // Apply the overrides. + if (overrideStruct.hasOverride) + { + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + + // Font. + if (overrideStruct.font) + entryStructPointer->font = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->font = FilterOptionEnum::Disposition::Apply; + + // Image. + if (overrideStruct.image) + entryStructPointer->image = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->image = FilterOptionEnum::Disposition::Apply; + + // Main Frame (document). + if (overrideStruct.mainFrame) + entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply; + + // Media. + if (overrideStruct.media) + entryStructPointer->media = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->media = FilterOptionEnum::Disposition::Apply; + + // Object. + if (overrideStruct.object) + entryStructPointer->object = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->object = FilterOptionEnum::Disposition::Apply; + + // Other. + if (overrideStruct.other) + entryStructPointer->other = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->other = FilterOptionEnum::Disposition::Apply; + + // Ping. + if (overrideStruct.ping) + entryStructPointer->ping = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->ping = FilterOptionEnum::Disposition::Apply; + + // Script. + if (overrideStruct.script) + entryStructPointer->script = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->script = FilterOptionEnum::Disposition::Apply; + + // Style Sheet. + if (overrideStruct.styleSheet) + entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply; + + // Sub Resource. + if (overrideStruct.subFrame) + entryStructPointer->subFrame = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply; + + // XML HTTP Request. + if (overrideStruct.xmlHttpRequest) + entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply; + } + } // Finish processing filter options. + + + if (filterListString.isEmpty() && !entryStructPointer->hasRequestOptions) // There are no applied entries and no request options. { - // Do nothing. + // Ignore these entries as they will block all requests generally or for a specified domain. Typically these are left over after removing `csp=` filter options. - // Log the dropping of the line. - //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " NOT added from " << filterListFileName << " (single popup filter option)."; + // Log the dropping of the entry. + //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " NOT added from " << filterListFileName << "."; } else if (filterListString.startsWith(QLatin1String("@@"))) // Process an allow list entry. { // Remove the initial `@@`. filterListString.remove(0, 2); - // Remove any initial and trailing asterisks. - removeInitialAndTrailingAsterisks(filterListString); + // Prepare the filter list string. TODO. Initial allow lists must be processed first. + prepareFilterListString(filterListString, entryStructPointer); - // Add the applied entry to the struct. - entryStructPointer->appliedEntry = filterListString; - - // Add the filter list entry struct to the main allow list. - filterListStructPointer->mainAllowList.push_front(entryStructPointer); + // Add the entry struct to the main allow list. + filterListStructPointer->mainAllowListPointer->push_front(entryStructPointer); // Log the addition to the filter list. //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Main Allow List from " << filterListFileName << "."; } - else if (filterListString.startsWith(QLatin1String("||"))) // Process an initial domain allow list entry. + else if (filterListString.startsWith(QLatin1String("||"))) // Process an initial domain block list entry. { // Remove the initial `||`. filterListString.remove(0, 2); - // Add the applied entry to the struct. - entryStructPointer->appliedEntry = filterListString; + // Set the initial match flag. + entryStructPointer->initialMatch = true; + + // Prepare the filter list string. + prepareFilterListString(filterListString, entryStructPointer); - // Add the filter list entry struct to the initial domain block list. - filterListStructPointer->initialDomainBlockList.push_front(entryStructPointer); + // Add the entry struct to the initial domain block list. + filterListStructPointer->initialDomainBlockListPointer->push_front(entryStructPointer); // Log the addition to the filter list. //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Initial Domain Block List from " << filterListFileName << "."; } - else // Process a block list entry. + else if (filterListString.contains(QLatin1String("\\"))) // Process a regular expression block list entry. { - // Remove any initial and trailing asterisks. - removeInitialAndTrailingAsterisks(filterListString); + // Add the regular expression to the applied entry list. + entryStructPointer->appliedEntryList.append(filterListString); - // Add the applied entry to the struct. - entryStructPointer->appliedEntry = filterListString; + // Add the entry struct to the regular expression block list. + filterListStructPointer->regularExpressionBlockListPointer->push_front(entryStructPointer); + } + else // Process a main block list entry. + { + // Prepare the filter list string. + prepareFilterListString(filterListString, entryStructPointer); - // Add the filter list entry struct to the main block list. - filterListStructPointer->mainBlockList.push_front(entryStructPointer); + // Add the entry struct to the main block list. + filterListStructPointer->mainBlockListPointer->push_front(entryStructPointer); // Log the addition to the filter list. //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Main Block List from " << filterListFileName << "."; @@ -808,111 +1267,46 @@ void FilterListHelper::populateRequestStruct(RequestStruct *requestStructPointer requestStructPointer->dispositionInt = disposition; requestStructPointer->filterListTitle = filterListTitle; requestStructPointer->sublistInt = sublistInt; - requestStructPointer->entryStruct.appliedEntry = entryStructPointer->appliedEntry; + requestStructPointer->entryStruct.appliedEntryList = entryStructPointer->appliedEntryList; requestStructPointer->entryStruct.originalEntry = entryStructPointer->originalEntry; } -bool FilterListHelper::processFilterOptions(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, - EntryStruct *entryStructPointer) const +void FilterListHelper::prepareFilterListString(QString &filterListString, EntryStruct *entryStructPointer) const { - // Block font requests. - if ((entryStructPointer->font == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFontResource)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } - - // Block image requests. - if ((entryStructPointer->image == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeImage)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } - - // Block main frame requests. - if ((entryStructPointer->mainFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMainFrame) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame))) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } - - // Block media requests. - if ((entryStructPointer->media == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMedia)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } - - // Block object requests. - if ((entryStructPointer->object == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeObject)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } - - // Block other requests. - if ((entryStructPointer->other == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubResource) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeWorker) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSharedWorker) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePrefetch) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFavicon) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeServiceWorker) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeCspReport) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePluginResource) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeUnknown))) + // Check if this is an initial match. + if (filterListString.startsWith(QLatin1Char('|'))) { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } + // Strip the initial `|`. + filterListString.remove(0, 1); - // Block ping requests - if ((entryStructPointer->ping == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePing)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + // Set the initial match flag. + entryStructPointer->initialMatch = true; } - // Block script requests. - if ((entryStructPointer->script == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeScript)) + // Check if this is a final match. + if (filterListString.endsWith(QLatin1Char('|'))) { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } + // Strip the final `|`. + filterListString.chop(1); - // Block style sheet requests. - if ((entryStructPointer->styleSheet == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeStylesheet)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + // Set the final match flag. + entryStructPointer->finalMatch = true; } - // Block sub resource requests. - if ((entryStructPointer->subFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubFrame) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame))) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } + // Remove the initial asterisk if it exists. + if (filterListString.startsWith(QLatin1Char('*'))) + filterListString.remove(0, 1); - // Block XML HTTP requests. - if ((entryStructPointer->xmlHttpRequest == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeXhr)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } + // Remove the final asterisk if it exists. + if (filterListString.endsWith(QLatin1Char('*'))) + filterListString.chop(1); - // Returning true continues processing the filter list. - return true; -} + // Split the filter list string and set it as the applied entry list. + entryStructPointer->appliedEntryList = filterListString.split(QLatin1Char('*')); -void FilterListHelper::removeInitialAndTrailingAsterisks(QString &filterListEntry) const -{ - // Remove the initial asterisk if it exists. - if (filterListEntry.startsWith(QLatin1Char('*'))) - filterListEntry.remove(0, 1); + // Store the size of the applied entry list. + entryStructPointer->sizeOfAppliedEntryList = entryStructPointer->appliedEntryList.size(); - // Remove the final asterisk if it exists. - if (filterListEntry.endsWith(QLatin1Char('*'))) - filterListEntry.chop(1); + // Determine if this is a single applied entry (including an empty entry). + entryStructPointer->singleAppliedEntry = (entryStructPointer->sizeOfAppliedEntryList == 1); }