]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/helpers/FilterListHelper.cpp
Partial filter list implementation.
[PrivacyBrowserPC.git] / src / helpers / FilterListHelper.cpp
1 /*
2  * Copyright 2024 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 // Application headers.
21 #include "FilterListHelper.h"
22
23 // Qt toolkit headers.
24 #include <QDebug>
25 #include <QFile>
26 #include <QTextStream>
27
28 // KDE Framework headers.
29 #include <KLocalizedString>
30
31 // Construct the class.
32 FilterListHelper::FilterListHelper()
33 {
34     // Populate the translated disposition strings.  Translated entries cannot be public static const.
35     DEFAULT_STRING = i18nc("Default disposition", "Default - Allowed");
36     ALLOWED_STRING = i18nc("Allowed disposition", "Allowed");
37     BLOCKED_STRING = i18nc("Blocked disposition", "Blocked");
38
39     // Populate the translated navigation type strings.  Translated entries cannot be public static const.
40     NAVIGATION_TYPE_LINK = i18nc("Navigation type link", "Link");
41     NAVIGATION_TYPE_TYPED = i18nc("Navigation type typed", "Typed");
42     NAVIGATION_TYPE_FORM_SUBMITTED = i18nc("Navigation type form submitted", "Form Submitted");
43     NAVIGATION_TYPE_BACK_FORWARD = i18nc("Navigation type back/forward", "Back/Forward");
44     NAVIGATION_TYPE_RELOAD = i18nc("Navigation type reload", "Reload");
45     NAVIGATION_TYPE_REDIRECT = i18nc("Navigation type redirect", "Redirect");
46     NAVIGATION_TYPE_OTHER = i18nc("Navigation type other", "Other");
47
48     // Populate the translated resource type strings.  Translated entries cannot be public static const.
49     RESOURCE_TYPE_MAIN_FRAME = i18nc("Resource type main frame", "Main Frame");
50     RESOURCE_TYPE_SUB_FRAME = i18nc("Resource type sub frame", "Sub Frame");
51     RESOURCE_TYPE_STYLESHEET = i18nc("Resource type stylesheet", "Stylesheet");
52     RESOURCE_TYPE_SCRIPT = i18nc("Resource type script", "Script");
53     RESOURCE_TYPE_IMAGE = i18nc("Resource type image", "Image");
54     RESOURCE_TYPE_FONT_RESOURCE = i18nc("Resource type font", "Font");
55     RESOURCE_TYPE_SUB_RESOURCE = i18nc("Resource type sub resource", "Sub Resource");
56     RESOURCE_TYPE_OBJECT = i18nc("Resource type object", "Object");
57     RESOURCE_TYPE_MEDIA = i18nc("Resource type media", "Media");
58     RESOURCE_TYPE_WORKER = i18nc("Resource type worker", "Worker");
59     RESOURCE_TYPE_SHARED_WORKER = i18nc("Resource type shared worker", "Shared Worker");
60     RESOURCE_TYPE_PREFETCH = i18nc("Resource type prefetch", "Prefetch");
61     RESOURCE_TYPE_FAVICON = i18nc("Resource type favicon", "Favicon");
62     RESOURCE_TYPE_XHR = i18nc("Resource type XML HTTP request", "XML HTTP Request");
63     RESOURCE_TYPE_PING = i18nc("Resource type HTTP ping", "HTTP Ping");
64     RESOURCE_TYPE_SERVICE_WORKER = i18nc("Resource type service worker", "Service Worker");
65     RESOURCE_TYPE_CSP_REPORT = i18nc("Resource type content security policy report", "Content Security Policy Report");
66     RESOURCE_TYPE_PLUGIN_RESOURCE = i18nc("Resource type plugin request", "Plugin Request");
67     RESOURCE_TYPE_NAVIGATION_PRELOAD_MAIN_FRAME = i18nc("Resource type preload main frame", "Preload Main Frame");
68     RESOURCE_TYPE_NAVIGATION_PRELOAD_SUB_FRAME = i18nc("Resource type preload sub frame", "Preload Sub Frame");
69     RESOURCE_TYPE_UNKNOWN = i18nc("Resource type unknown", "Unknown");
70
71     // Populate the translated sublist strings.  Translated entries cannot be public static const.
72     MAIN_BLOCKLIST_STRING = i18nc("Main blocklist sublist", "Main Block List");
73
74     // Populate the filter lists.
75     ultraListStructPointer = populateFilterList(QLatin1String(":/filterlists/ultralist.txt"));
76     ultraPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/ultraprivacy.txt"));
77     easyListStructPointer = populateFilterList(QLatin1String(":/filterlists/easylist.txt"));
78     easyPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/easyprivacy.txt"));
79     fanboyAnnoyanceStructPointer = populateFilterList(QLatin1String(":/filterlists/fanboy-annoyance.txt"));
80 }
81
82 bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer) const
83 {
84     // Initiate a status tracker.  If the tracker changes to false, all process of the request will be stopped.
85     bool status = true;
86
87     // Check UltraList.
88     status = checkIndividualList(urlRequestInfo, requestStructPointer, ultraListStructPointer);
89
90     // check UltraPrivacy if the status is still true.
91     if (status) {
92         status = checkIndividualList(urlRequestInfo, requestStructPointer, ultraPrivacyStructPointer);
93     }
94
95     // Return the status.
96     return status;
97 }
98
99 bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, FilterListStruct *filterListStruct) const
100 {
101     // Get the request URL.
102     QUrl url = urlRequestInfo.requestUrl();
103
104     // Get the request URL string.
105     QString urlString = url.toString();
106
107     // Check the main block list.
108     for (auto filterListEntry = filterListStruct->mainBlockList.begin(); filterListEntry != filterListStruct->mainBlockList.end(); ++filterListEntry) {
109         // Get the entry struct.
110         EntryStruct *entryStructPointer = *filterListEntry;
111
112         // Check if the URL string contains the applied entry
113         if (urlString.contains(entryStructPointer->appliedEntry)) {
114             // Block the request.
115             urlRequestInfo.block(true);
116
117             // Populate the request struct.
118             populateRequestStruct(requestStructPointer, BLOCKED, filterListStruct->title, MAIN_BLOCKLIST, entryStructPointer->appliedEntry, entryStructPointer->originalEntry);
119
120             // Log the block.
121             //qDebug().noquote().nospace() << "Blocked request:  " << urlString << ",  Filter list entry:  " << entryStructPointer->appliedEntry;
122
123             // Returning `false` stops all processing of the request.
124             return false;
125         }
126     }
127
128     // Return `true` to continue processing the URL request.
129     return true;
130 }
131
132 QString FilterListHelper::getDispositionString(int dispositionInt) const
133 {
134     // Return the translated disposition string.
135     switch (dispositionInt)
136     {
137         case ALLOWED: return ALLOWED_STRING;
138         case BLOCKED: return BLOCKED_STRING;
139         default: return DEFAULT_STRING;
140     }
141 }
142
143 QString FilterListHelper::getNavigationTypeString(int navigationTypeInt) const
144 {
145     // Return the translated navigation type string.
146     switch (navigationTypeInt)
147     {
148         case QWebEngineUrlRequestInfo::NavigationTypeLink: return NAVIGATION_TYPE_LINK;
149         case QWebEngineUrlRequestInfo::NavigationTypeTyped: return NAVIGATION_TYPE_TYPED;
150         case QWebEngineUrlRequestInfo::NavigationTypeFormSubmitted: return NAVIGATION_TYPE_FORM_SUBMITTED;
151         case QWebEngineUrlRequestInfo::NavigationTypeBackForward: return NAVIGATION_TYPE_BACK_FORWARD;
152         case QWebEngineUrlRequestInfo::NavigationTypeReload: return NAVIGATION_TYPE_RELOAD;
153         case QWebEngineUrlRequestInfo::NavigationTypeRedirect: return NAVIGATION_TYPE_REDIRECT;
154         default: return NAVIGATION_TYPE_OTHER;
155     }
156 }
157
158 QString FilterListHelper::getResourceTypeString(int resourceTypeInt) const
159 {
160     // Return the translated resource type string.
161     switch (resourceTypeInt)
162     {
163         case QWebEngineUrlRequestInfo::ResourceTypeMainFrame: return RESOURCE_TYPE_MAIN_FRAME;
164         case QWebEngineUrlRequestInfo::ResourceTypeSubFrame: return RESOURCE_TYPE_SUB_FRAME;
165         case QWebEngineUrlRequestInfo::ResourceTypeStylesheet: return RESOURCE_TYPE_STYLESHEET;
166         case QWebEngineUrlRequestInfo::ResourceTypeScript: return RESOURCE_TYPE_SCRIPT;
167         case QWebEngineUrlRequestInfo::ResourceTypeImage: return RESOURCE_TYPE_IMAGE;
168         case QWebEngineUrlRequestInfo::ResourceTypeFontResource: return RESOURCE_TYPE_FONT_RESOURCE;
169         case QWebEngineUrlRequestInfo::ResourceTypeSubResource: return RESOURCE_TYPE_SUB_RESOURCE;
170         case QWebEngineUrlRequestInfo::ResourceTypeObject: return RESOURCE_TYPE_OBJECT;
171         case QWebEngineUrlRequestInfo::ResourceTypeMedia: return RESOURCE_TYPE_MEDIA;
172         case QWebEngineUrlRequestInfo::ResourceTypeWorker: return RESOURCE_TYPE_WORKER;
173         case QWebEngineUrlRequestInfo::ResourceTypeSharedWorker: return RESOURCE_TYPE_SHARED_WORKER;
174         case QWebEngineUrlRequestInfo::ResourceTypePrefetch: return RESOURCE_TYPE_PREFETCH;
175         case QWebEngineUrlRequestInfo::ResourceTypeFavicon: return RESOURCE_TYPE_FAVICON;
176         case QWebEngineUrlRequestInfo::ResourceTypeXhr: return RESOURCE_TYPE_XHR;
177         case QWebEngineUrlRequestInfo::ResourceTypePing: return RESOURCE_TYPE_PING;
178         case QWebEngineUrlRequestInfo::ResourceTypeServiceWorker: return RESOURCE_TYPE_SERVICE_WORKER;
179         case QWebEngineUrlRequestInfo::ResourceTypeCspReport: return RESOURCE_TYPE_CSP_REPORT;
180         case QWebEngineUrlRequestInfo::ResourceTypePluginResource: return RESOURCE_TYPE_PLUGIN_RESOURCE;
181         case QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame: return RESOURCE_TYPE_NAVIGATION_PRELOAD_MAIN_FRAME;
182         case QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame: return RESOURCE_TYPE_NAVIGATION_PRELOAD_SUB_FRAME;
183         default: return RESOURCE_TYPE_UNKNOWN;
184     }
185 }
186
187 QString FilterListHelper::getSublistName(int sublistInt) const
188 {
189     // Return the name of the requested sublist.
190     switch (sublistInt)
191     {
192         case MAIN_BLOCKLIST: return MAIN_BLOCKLIST_STRING;
193         default: return QString();  // The default return should never be reached.
194     }
195 }
196
197 FilterListStruct* FilterListHelper::populateFilterList(const QString &filterListFileName) const
198 {
199     // Get the filter list file.
200     QFile filterListFile(filterListFileName);
201
202     // Open the filter list file.
203     filterListFile.open(QIODevice::ReadOnly);
204
205     // Create a filter list text stream.
206     QTextStream filterListTextStream(&filterListFile);
207
208     // Create a filter list struct.
209     FilterListStruct *filterListStructPointer = new FilterListStruct;
210
211     // Populate the filter list file name.
212     filterListStructPointer->filePath = filterListFileName;
213
214     // Create a filter list string.
215     QString filterListString;
216
217     // Process each line of the filter list.
218     while (filterListTextStream.readLineInto(&filterListString)) {
219         // Create an entry struct.
220         EntryStruct *entryStructPointer = new EntryStruct;
221
222         // Store the original entry.
223         entryStructPointer->originalEntry = filterListString;
224
225         // Process the entry.
226         if (filterListString.startsWith(QLatin1Char('['))) {  // The line starts with `[`, which is the file format.
227             // Do nothing.
228
229             // Log the dropping of the line.
230             //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName;
231         } else if (filterListString.startsWith(QLatin1Char('!'))) {  // The line starts with `!`, which are comments.
232             if (filterListString.startsWith(QLatin1String("! Title: ")))  // The line contains the title.
233             {
234                 // Add the title to the filter list struct.
235                 filterListStructPointer->title = filterListString.remove(0, 9);
236
237                 // Log the addition of the filter list title.
238                 //qDebug().noquote().nospace() << "Filter list title:  " << filterListString << " added from " << filterListFileName;
239             }
240             else if (filterListString.startsWith(QLatin1String("! Version: ")))  // The line contains the version.
241             {
242                 // Add the version to the filter list struct.
243                 filterListStructPointer->version = filterListString.remove(0, 11);
244
245                 // Log the addition of the filter list version.
246                 //qDebug().noquote().nospace() << "Filter list version:  " << filterListString << " added from " << filterListFileName;
247             }
248
249             // Else do nothing.
250
251             // Log the dropping of the line.
252             //qDebug().noquote().nospace() << originalFilterListString << " NOT added from " << filterListFileName;
253         } else {  // Process the entry.
254             // Add the applied entry to the struct.
255             entryStructPointer->appliedEntry = filterListString;
256
257             // Add the filter list entry struct to the main block list.
258             filterListStructPointer->mainBlockList.push_front(entryStructPointer);
259
260             // Log the addition to the filter list.
261             //qDebug().noquote().nospace() << originalFilterListString << " added from " << filterListFileName;
262         }
263     }
264
265     // Close the filter list file.
266     filterListFile.close();
267
268     // Return the filter list pair.
269     return filterListStructPointer;
270 }
271
272 void FilterListHelper::populateRequestStruct(RequestStruct *requestStructPointer, const int disposition, const QString &filterListTitle, const int sublistInt, const QString &appliedEntry,
273                                              const QString &originalEntry) const
274 {
275     // Populate the request struct.
276     requestStructPointer->dispositionInt = disposition;
277     requestStructPointer->filterListTitle = filterListTitle;
278     requestStructPointer->sublistInt = sublistInt;
279     requestStructPointer->entryStruct.appliedEntry = appliedEntry;
280     requestStructPointer->entryStruct.originalEntry = originalEntry;
281 }