X-Git-Url: https://gitweb.stoutner.com/?a=blobdiff_plain;f=src%2Fhelpers%2FFilterListHelper.cpp;fp=src%2Fhelpers%2FFilterListHelper.cpp;h=e49af5b20e5f2d7a09a4fa0e517f2b888d31c65a;hb=a44e607fb5398c80c5de2629017865ae749e8fbf;hp=0000000000000000000000000000000000000000;hpb=c5706a6ff3fbc42418e60b79fbe3f5c19396f7d2;p=PrivacyBrowserPC.git diff --git a/src/helpers/FilterListHelper.cpp b/src/helpers/FilterListHelper.cpp new file mode 100644 index 0000000..e49af5b --- /dev/null +++ b/src/helpers/FilterListHelper.cpp @@ -0,0 +1,281 @@ +/* + * Copyright 2024 Soren Stoutner . + * + * This file is part of Privacy Browser PC . + * + * Privacy Browser PC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Privacy Browser PC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Privacy Browser PC. If not, see . + */ + +// Application headers. +#include "FilterListHelper.h" + +// Qt toolkit headers. +#include +#include +#include + +// KDE Framework headers. +#include + +// Construct the class. +FilterListHelper::FilterListHelper() +{ + // Populate the translated disposition strings. Translated entries cannot be public static const. + DEFAULT_STRING = i18nc("Default disposition", "Default - Allowed"); + ALLOWED_STRING = i18nc("Allowed disposition", "Allowed"); + BLOCKED_STRING = i18nc("Blocked disposition", "Blocked"); + + // Populate the translated navigation type strings. Translated entries cannot be public static const. + NAVIGATION_TYPE_LINK = i18nc("Navigation type link", "Link"); + NAVIGATION_TYPE_TYPED = i18nc("Navigation type typed", "Typed"); + NAVIGATION_TYPE_FORM_SUBMITTED = i18nc("Navigation type form submitted", "Form Submitted"); + NAVIGATION_TYPE_BACK_FORWARD = i18nc("Navigation type back/forward", "Back/Forward"); + NAVIGATION_TYPE_RELOAD = i18nc("Navigation type reload", "Reload"); + NAVIGATION_TYPE_REDIRECT = i18nc("Navigation type redirect", "Redirect"); + NAVIGATION_TYPE_OTHER = i18nc("Navigation type other", "Other"); + + // Populate the translated resource type strings. Translated entries cannot be public static const. + RESOURCE_TYPE_MAIN_FRAME = i18nc("Resource type main frame", "Main Frame"); + RESOURCE_TYPE_SUB_FRAME = i18nc("Resource type sub frame", "Sub Frame"); + RESOURCE_TYPE_STYLESHEET = i18nc("Resource type stylesheet", "Stylesheet"); + RESOURCE_TYPE_SCRIPT = i18nc("Resource type script", "Script"); + RESOURCE_TYPE_IMAGE = i18nc("Resource type image", "Image"); + RESOURCE_TYPE_FONT_RESOURCE = i18nc("Resource type font", "Font"); + RESOURCE_TYPE_SUB_RESOURCE = i18nc("Resource type sub resource", "Sub Resource"); + RESOURCE_TYPE_OBJECT = i18nc("Resource type object", "Object"); + RESOURCE_TYPE_MEDIA = i18nc("Resource type media", "Media"); + RESOURCE_TYPE_WORKER = i18nc("Resource type worker", "Worker"); + RESOURCE_TYPE_SHARED_WORKER = i18nc("Resource type shared worker", "Shared Worker"); + RESOURCE_TYPE_PREFETCH = i18nc("Resource type prefetch", "Prefetch"); + RESOURCE_TYPE_FAVICON = i18nc("Resource type favicon", "Favicon"); + RESOURCE_TYPE_XHR = i18nc("Resource type XML HTTP request", "XML HTTP Request"); + RESOURCE_TYPE_PING = i18nc("Resource type HTTP ping", "HTTP Ping"); + RESOURCE_TYPE_SERVICE_WORKER = i18nc("Resource type service worker", "Service Worker"); + RESOURCE_TYPE_CSP_REPORT = i18nc("Resource type content security policy report", "Content Security Policy Report"); + RESOURCE_TYPE_PLUGIN_RESOURCE = i18nc("Resource type plugin request", "Plugin Request"); + RESOURCE_TYPE_NAVIGATION_PRELOAD_MAIN_FRAME = i18nc("Resource type preload main frame", "Preload Main Frame"); + RESOURCE_TYPE_NAVIGATION_PRELOAD_SUB_FRAME = i18nc("Resource type preload sub frame", "Preload Sub Frame"); + RESOURCE_TYPE_UNKNOWN = i18nc("Resource type unknown", "Unknown"); + + // Populate the translated sublist strings. Translated entries cannot be public static const. + MAIN_BLOCKLIST_STRING = i18nc("Main blocklist sublist", "Main Block List"); + + // Populate the filter lists. + ultraListStructPointer = populateFilterList(QLatin1String(":/filterlists/ultralist.txt")); + ultraPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/ultraprivacy.txt")); + easyListStructPointer = populateFilterList(QLatin1String(":/filterlists/easylist.txt")); + easyPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/easyprivacy.txt")); + fanboyAnnoyanceStructPointer = populateFilterList(QLatin1String(":/filterlists/fanboy-annoyance.txt")); +} + +bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer) const +{ + // Initiate a status tracker. If the tracker changes to false, all process of the request will be stopped. + bool status = true; + + // Check UltraList. + status = checkIndividualList(urlRequestInfo, requestStructPointer, ultraListStructPointer); + + // check UltraPrivacy if the status is still true. + if (status) { + status = checkIndividualList(urlRequestInfo, requestStructPointer, ultraPrivacyStructPointer); + } + + // Return the status. + return status; +} + +bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, FilterListStruct *filterListStruct) const +{ + // Get the request URL. + QUrl url = urlRequestInfo.requestUrl(); + + // Get the request URL string. + QString urlString = url.toString(); + + // Check the main block list. + for (auto filterListEntry = filterListStruct->mainBlockList.begin(); filterListEntry != filterListStruct->mainBlockList.end(); ++filterListEntry) { + // Get the entry struct. + EntryStruct *entryStructPointer = *filterListEntry; + + // Check if the URL string contains the applied entry + if (urlString.contains(entryStructPointer->appliedEntry)) { + // Block the request. + urlRequestInfo.block(true); + + // Populate the request struct. + populateRequestStruct(requestStructPointer, BLOCKED, filterListStruct->title, MAIN_BLOCKLIST, entryStructPointer->appliedEntry, entryStructPointer->originalEntry); + + // Log the block. + //qDebug().noquote().nospace() << "Blocked request: " << urlString << ", Filter list entry: " << entryStructPointer->appliedEntry; + + // Returning `false` stops all processing of the request. + return false; + } + } + + // Return `true` to continue processing the URL request. + return true; +} + +QString FilterListHelper::getDispositionString(int dispositionInt) const +{ + // Return the translated disposition string. + switch (dispositionInt) + { + case ALLOWED: return ALLOWED_STRING; + case BLOCKED: return BLOCKED_STRING; + default: return DEFAULT_STRING; + } +} + +QString FilterListHelper::getNavigationTypeString(int navigationTypeInt) const +{ + // Return the translated navigation type string. + switch (navigationTypeInt) + { + case QWebEngineUrlRequestInfo::NavigationTypeLink: return NAVIGATION_TYPE_LINK; + case QWebEngineUrlRequestInfo::NavigationTypeTyped: return NAVIGATION_TYPE_TYPED; + case QWebEngineUrlRequestInfo::NavigationTypeFormSubmitted: return NAVIGATION_TYPE_FORM_SUBMITTED; + case QWebEngineUrlRequestInfo::NavigationTypeBackForward: return NAVIGATION_TYPE_BACK_FORWARD; + case QWebEngineUrlRequestInfo::NavigationTypeReload: return NAVIGATION_TYPE_RELOAD; + case QWebEngineUrlRequestInfo::NavigationTypeRedirect: return NAVIGATION_TYPE_REDIRECT; + default: return NAVIGATION_TYPE_OTHER; + } +} + +QString FilterListHelper::getResourceTypeString(int resourceTypeInt) const +{ + // Return the translated resource type string. + switch (resourceTypeInt) + { + case QWebEngineUrlRequestInfo::ResourceTypeMainFrame: return RESOURCE_TYPE_MAIN_FRAME; + case QWebEngineUrlRequestInfo::ResourceTypeSubFrame: return RESOURCE_TYPE_SUB_FRAME; + case QWebEngineUrlRequestInfo::ResourceTypeStylesheet: return RESOURCE_TYPE_STYLESHEET; + case QWebEngineUrlRequestInfo::ResourceTypeScript: return RESOURCE_TYPE_SCRIPT; + case QWebEngineUrlRequestInfo::ResourceTypeImage: return RESOURCE_TYPE_IMAGE; + case QWebEngineUrlRequestInfo::ResourceTypeFontResource: return RESOURCE_TYPE_FONT_RESOURCE; + case QWebEngineUrlRequestInfo::ResourceTypeSubResource: return RESOURCE_TYPE_SUB_RESOURCE; + case QWebEngineUrlRequestInfo::ResourceTypeObject: return RESOURCE_TYPE_OBJECT; + case QWebEngineUrlRequestInfo::ResourceTypeMedia: return RESOURCE_TYPE_MEDIA; + case QWebEngineUrlRequestInfo::ResourceTypeWorker: return RESOURCE_TYPE_WORKER; + case QWebEngineUrlRequestInfo::ResourceTypeSharedWorker: return RESOURCE_TYPE_SHARED_WORKER; + case QWebEngineUrlRequestInfo::ResourceTypePrefetch: return RESOURCE_TYPE_PREFETCH; + case QWebEngineUrlRequestInfo::ResourceTypeFavicon: return RESOURCE_TYPE_FAVICON; + case QWebEngineUrlRequestInfo::ResourceTypeXhr: return RESOURCE_TYPE_XHR; + case QWebEngineUrlRequestInfo::ResourceTypePing: return RESOURCE_TYPE_PING; + case QWebEngineUrlRequestInfo::ResourceTypeServiceWorker: return RESOURCE_TYPE_SERVICE_WORKER; + case QWebEngineUrlRequestInfo::ResourceTypeCspReport: return RESOURCE_TYPE_CSP_REPORT; + case QWebEngineUrlRequestInfo::ResourceTypePluginResource: return RESOURCE_TYPE_PLUGIN_RESOURCE; + case QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame: return RESOURCE_TYPE_NAVIGATION_PRELOAD_MAIN_FRAME; + case QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame: return RESOURCE_TYPE_NAVIGATION_PRELOAD_SUB_FRAME; + default: return RESOURCE_TYPE_UNKNOWN; + } +} + +QString FilterListHelper::getSublistName(int sublistInt) const +{ + // Return the name of the requested sublist. + switch (sublistInt) + { + case MAIN_BLOCKLIST: return MAIN_BLOCKLIST_STRING; + default: return QString(); // The default return should never be reached. + } +} + +FilterListStruct* FilterListHelper::populateFilterList(const QString &filterListFileName) const +{ + // Get the filter list file. + QFile filterListFile(filterListFileName); + + // Open the filter list file. + filterListFile.open(QIODevice::ReadOnly); + + // Create a filter list text stream. + QTextStream filterListTextStream(&filterListFile); + + // Create a filter list struct. + FilterListStruct *filterListStructPointer = new FilterListStruct; + + // Populate the filter list file name. + filterListStructPointer->filePath = filterListFileName; + + // Create a filter list string. + QString filterListString; + + // Process each line of the filter list. + while (filterListTextStream.readLineInto(&filterListString)) { + // Create an entry struct. + EntryStruct *entryStructPointer = new EntryStruct; + + // Store the original entry. + entryStructPointer->originalEntry = filterListString; + + // Process the entry. + if (filterListString.startsWith(QLatin1Char('['))) { // The line starts with `[`, which is the file format. + // Do nothing. + + // Log the dropping of the line. + //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName; + } else if (filterListString.startsWith(QLatin1Char('!'))) { // The line starts with `!`, which are comments. + if (filterListString.startsWith(QLatin1String("! Title: "))) // The line contains the title. + { + // Add the title to the filter list struct. + filterListStructPointer->title = filterListString.remove(0, 9); + + // Log the addition of the filter list title. + //qDebug().noquote().nospace() << "Filter list title: " << filterListString << " added from " << filterListFileName; + } + else if (filterListString.startsWith(QLatin1String("! Version: "))) // The line contains the version. + { + // Add the version to the filter list struct. + filterListStructPointer->version = filterListString.remove(0, 11); + + // Log the addition of the filter list version. + //qDebug().noquote().nospace() << "Filter list version: " << filterListString << " added from " << filterListFileName; + } + + // Else do nothing. + + // Log the dropping of the line. + //qDebug().noquote().nospace() << originalFilterListString << " NOT added from " << filterListFileName; + } else { // Process the entry. + // Add the applied entry to the struct. + entryStructPointer->appliedEntry = filterListString; + + // Add the filter list entry struct to the main block list. + filterListStructPointer->mainBlockList.push_front(entryStructPointer); + + // Log the addition to the filter list. + //qDebug().noquote().nospace() << originalFilterListString << " added from " << filterListFileName; + } + } + + // Close the filter list file. + filterListFile.close(); + + // Return the filter list pair. + return filterListStructPointer; +} + +void FilterListHelper::populateRequestStruct(RequestStruct *requestStructPointer, const int disposition, const QString &filterListTitle, const int sublistInt, const QString &appliedEntry, + const QString &originalEntry) const +{ + // Populate the request struct. + requestStructPointer->dispositionInt = disposition; + requestStructPointer->filterListTitle = filterListTitle; + requestStructPointer->sublistInt = sublistInt; + requestStructPointer->entryStruct.appliedEntry = appliedEntry; + requestStructPointer->entryStruct.originalEntry = originalEntry; +}