1 /**************************************************************************
2 * Otter Browser: Web browser controlled by the user, not vice-versa.
3 * Copyright (C) 2016 - 2019 Michal Dutkiewicz aka Emdek <michal@emdek.pl>
4 * Copyright (C) 2016 Jan Bajer aka bajasoft <jbajer@gmail.com>
5 *
6 * This program 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 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **************************************************************************/
20
21 #include "QtWebEngineUrlRequestInterceptor.h"
22 #include "QtWebEngineWebWidget.h"
23 #include "../../../../core/Console.h"
24 #include "../../../../core/ContentFiltersManager.h"
25 #include "../../../../core/SettingsManager.h"
26 #include "../../../../core/Utils.h"
27
28 #include <QtCore/QCoreApplication>
29
30 namespace Otter
31 {
32
33 #if QTWEBENGINECORE_VERSION >= 0x050D00
QtWebEngineUrlRequestInterceptor(QtWebEngineWebWidget * parent)34 QtWebEngineUrlRequestInterceptor::QtWebEngineUrlRequestInterceptor(QtWebEngineWebWidget *parent) : QWebEngineUrlRequestInterceptor(parent),
35 m_widget(parent),
36 m_doNotTrackPolicy(NetworkManagerFactory::SkipTrackPolicy),
37 m_areImagesEnabled(true),
38 m_canSendReferrer(true)
39 {
40 }
41
interceptRequest(QWebEngineUrlRequestInfo & request)42 void QtWebEngineUrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &request)
43 {
44 if (!m_areImagesEnabled && request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeImage)
45 {
46 request.block(true);
47
48 return;
49 }
50
51 if (!m_contentBlockingProfiles.isEmpty() && (m_unblockedHosts.isEmpty() || !m_unblockedHosts.contains(Utils::extractHost(request.firstPartyUrl()))))
52 {
53 NetworkManager::ResourceType resourceType(NetworkManager::OtherType);
54 bool storeBlockedUrl(true);
55
56 switch (request.resourceType())
57 {
58 case QWebEngineUrlRequestInfo::ResourceTypeMainFrame:
59 resourceType = NetworkManager::MainFrameType;
60
61 break;
62 case QWebEngineUrlRequestInfo::ResourceTypeSubFrame:
63 resourceType = NetworkManager::SubFrameType;
64
65 break;
66 case QWebEngineUrlRequestInfo::ResourceTypeStylesheet:
67 resourceType = NetworkManager::StyleSheetType;
68 storeBlockedUrl = false;
69
70 break;
71 case QWebEngineUrlRequestInfo::ResourceTypeScript:
72 resourceType = NetworkManager::ScriptType;
73 storeBlockedUrl = false;
74
75 break;
76 case QWebEngineUrlRequestInfo::ResourceTypeImage:
77 resourceType = NetworkManager::ImageType;
78
79 break;
80 case QWebEngineUrlRequestInfo::ResourceTypeObject:
81 case QWebEngineUrlRequestInfo::ResourceTypeMedia:
82 resourceType = NetworkManager::ObjectType;
83
84 break;
85 case QWebEngineUrlRequestInfo::ResourceTypePluginResource:
86 resourceType = NetworkManager::ObjectSubrequestType;
87 storeBlockedUrl = false;
88
89 break;
90 case QWebEngineUrlRequestInfo::ResourceTypeXhr:
91 resourceType = NetworkManager::XmlHttpRequestType;
92
93 break;
94 default:
95 break;
96 }
97
98 const ContentFiltersManager::CheckResult result(ContentFiltersManager::checkUrl(m_contentBlockingProfiles, request.firstPartyUrl(), request.requestUrl(), resourceType));
99
100 if (result.isBlocked)
101 {
102 const ContentFiltersProfile *profile(ContentFiltersManager::getProfile(result.profile));
103
104 Console::addMessage(QCoreApplication::translate("main", "Request blocked by rule from profile %1:\n%2").arg(profile ? profile->getTitle() : QCoreApplication::translate("main", "(Unknown)")).arg(result.rule), Console::NetworkCategory, Console::LogLevel, request.requestUrl().toString(), -1);
105
106 if (storeBlockedUrl && !m_blockedElements.contains(request.requestUrl().url()))
107 {
108 m_blockedElements.append(request.requestUrl().url());
109 }
110
111 NetworkManager::ResourceInformation resource;
112 resource.url = request.requestUrl();
113 resource.resourceType = resourceType;
114 resource.metaData[NetworkManager::ContentBlockingProfileMetaData] = result.profile;
115 resource.metaData[NetworkManager::ContentBlockingRuleMetaData] = result.rule;
116
117 m_blockedRequests.append(resource);
118
119 emit requestBlocked(resource);
120
121 request.block(true);
122
123 return;
124 }
125 }
126
127 if (m_doNotTrackPolicy != NetworkManagerFactory::SkipTrackPolicy)
128 {
129 request.setHttpHeader(QStringLiteral("DNT").toLatin1(), ((m_doNotTrackPolicy == NetworkManagerFactory::DoNotAllowToTrackPolicy) ? QStringLiteral("1") : QStringLiteral("0")).toLatin1());
130 }
131
132 if (!m_canSendReferrer)
133 {
134 request.setHttpHeader(QStringLiteral("Referer").toLatin1(), QByteArray());
135 }
136 }
137
updateOptions(const QUrl & url)138 void QtWebEngineUrlRequestInterceptor::updateOptions(const QUrl &url)
139 {
140 m_blockedRequests.clear();
141 m_blockedElements.clear();
142
143 if (getOption(SettingsManager::ContentBlocking_EnableContentBlockingOption, url).toBool())
144 {
145 m_contentBlockingProfiles = ContentFiltersManager::getProfileIdentifiers(getOption(SettingsManager::ContentBlocking_ProfilesOption, url).toStringList());
146 }
147 else
148 {
149 m_contentBlockingProfiles.clear();
150 }
151
152 m_unblockedHosts = getOption(SettingsManager::ContentBlocking_IgnoreHostsOption, url).toStringList();
153
154 const QString doNotTrackPolicyValue(getOption(SettingsManager::Network_DoNotTrackPolicyOption, url).toString());
155
156 if (doNotTrackPolicyValue == QLatin1String("allow"))
157 {
158 m_doNotTrackPolicy = NetworkManagerFactory::AllowToTrackPolicy;
159 }
160 else if (doNotTrackPolicyValue == QLatin1String("doNotAllow"))
161 {
162 m_doNotTrackPolicy = NetworkManagerFactory::DoNotAllowToTrackPolicy;
163 }
164 else
165 {
166 m_doNotTrackPolicy = NetworkManagerFactory::SkipTrackPolicy;
167 }
168
169 m_areImagesEnabled = (getOption(SettingsManager::Permissions_EnableImagesOption, url).toString() != QLatin1String("disabled"));
170 m_canSendReferrer = getOption(SettingsManager::Network_EnableReferrerOption, url).toBool();
171 }
172
getOption(int identifier,const QUrl & url) const173 QVariant QtWebEngineUrlRequestInterceptor::getOption(int identifier, const QUrl &url) const
174 {
175 return (m_widget ? m_widget->getOption(identifier, url) : SettingsManager::getOption(identifier, Utils::extractHost(url)));
176 }
177
getBlockedElements() const178 QStringList QtWebEngineUrlRequestInterceptor::getBlockedElements() const
179 {
180 return m_blockedElements;
181 }
182
getBlockedRequests() const183 QVector<NetworkManager::ResourceInformation> QtWebEngineUrlRequestInterceptor::getBlockedRequests() const
184 {
185 return m_blockedRequests;
186 }
187 #else
188 QtWebEngineUrlRequestInterceptor::QtWebEngineUrlRequestInterceptor(QObject *parent) : QWebEngineUrlRequestInterceptor(parent),
189 m_clearTimer(0),
190 m_areImagesEnabled(SettingsManager::getOption(SettingsManager::Permissions_EnableImagesOption).toString() != QLatin1String("disabled"))
191 {
192 m_clearTimer = startTimer(1800000);
193
194 connect(SettingsManager::getInstance(), &SettingsManager::optionChanged, this, &QtWebEngineUrlRequestInterceptor::handleOptionChanged);
195 connect(SettingsManager::getInstance(), &SettingsManager::hostOptionChanged, this, &QtWebEngineUrlRequestInterceptor::handleOptionChanged);
196 }
197
198 void QtWebEngineUrlRequestInterceptor::timerEvent(QTimerEvent *event)
199 {
200 if (event->timerId() == m_clearTimer)
201 {
202 clearContentBlockingInformation();
203 }
204 }
205
206 void QtWebEngineUrlRequestInterceptor::clearContentBlockingInformation()
207 {
208 m_blockedElements.clear();
209 m_contentBlockingProfiles.clear();
210 }
211
212 void QtWebEngineUrlRequestInterceptor::handleOptionChanged(int identifier)
213 {
214 switch (identifier)
215 {
216 case SettingsManager::ContentBlocking_ProfilesOption:
217 clearContentBlockingInformation();
218
219 break;
220 case SettingsManager::Permissions_EnableImagesOption:
221 m_areImagesEnabled = (SettingsManager::getOption(SettingsManager::Permissions_EnableImagesOption).toString() != QLatin1String("disabled"));
222
223 break;
224 default:
225 break;
226 }
227 }
228
229 QStringList QtWebEngineUrlRequestInterceptor::getBlockedElements(const QString &domain) const
230 {
231 return m_blockedElements.value(domain);
232 }
233
234 void QtWebEngineUrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &request)
235 {
236 if (!m_areImagesEnabled && request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeImage)
237 {
238 request.block(true);
239
240 return;
241 }
242
243 if (!m_contentBlockingProfiles.contains(request.firstPartyUrl().host()))
244 {
245 const QString host(Utils::extractHost(request.firstPartyUrl()));
246
247 if (SettingsManager::getOption(SettingsManager::ContentBlocking_EnableContentBlockingOption, host).toBool())
248 {
249 m_contentBlockingProfiles[host] = ContentFiltersManager::getProfileIdentifiers(SettingsManager::getOption(SettingsManager::ContentBlocking_ProfilesOption, host).toStringList());
250 }
251 else
252 {
253 m_contentBlockingProfiles[host] = {};
254 }
255 }
256
257 const QVector<int> contentBlockingProfiles(m_contentBlockingProfiles.value(request.firstPartyUrl().host()));
258
259 if (!contentBlockingProfiles.isEmpty())
260 {
261 NetworkManager::ResourceType resourceType(NetworkManager::OtherType);
262 bool storeBlockedUrl(true);
263
264 switch (request.resourceType())
265 {
266 case QWebEngineUrlRequestInfo::ResourceTypeMainFrame:
267 resourceType = NetworkManager::MainFrameType;
268
269 break;
270 case QWebEngineUrlRequestInfo::ResourceTypeSubFrame:
271 resourceType = NetworkManager::SubFrameType;
272
273 break;
274 case QWebEngineUrlRequestInfo::ResourceTypeStylesheet:
275 resourceType = NetworkManager::StyleSheetType;
276 storeBlockedUrl = false;
277
278 break;
279 case QWebEngineUrlRequestInfo::ResourceTypeScript:
280 resourceType = NetworkManager::ScriptType;
281 storeBlockedUrl = false;
282
283 break;
284 case QWebEngineUrlRequestInfo::ResourceTypeImage:
285 resourceType = NetworkManager::ImageType;
286
287 break;
288 case QWebEngineUrlRequestInfo::ResourceTypeObject:
289 case QWebEngineUrlRequestInfo::ResourceTypeMedia:
290 resourceType = NetworkManager::ObjectType;
291
292 break;
293 case QWebEngineUrlRequestInfo::ResourceTypePluginResource:
294 resourceType = NetworkManager::ObjectSubrequestType;
295 storeBlockedUrl = false;
296
297 break;
298 case QWebEngineUrlRequestInfo::ResourceTypeXhr:
299 resourceType = NetworkManager::XmlHttpRequestType;
300
301 break;
302 default:
303 break;
304 }
305
306 const ContentFiltersManager::CheckResult result(ContentFiltersManager::checkUrl(contentBlockingProfiles, request.firstPartyUrl(), request.requestUrl(), resourceType));
307
308 if (result.isBlocked)
309 {
310 const ContentFiltersProfile *profile(ContentFiltersManager::getProfile(result.profile));
311
312 Console::addMessage(QCoreApplication::translate("main", "Request blocked by rule from profile %1:\n%2").arg(profile ? profile->getTitle() : QCoreApplication::translate("main", "(Unknown)")).arg(result.rule), Console::NetworkCategory, Console::LogLevel, request.requestUrl().toString(), -1);
313
314 if (storeBlockedUrl && !m_blockedElements.value(request.firstPartyUrl().host()).contains(request.requestUrl().url()))
315 {
316 m_blockedElements[request.firstPartyUrl().host()].append(request.requestUrl().url());
317 }
318
319 request.block(true);
320
321 return;
322 }
323 }
324
325 const NetworkManagerFactory::DoNotTrackPolicy doNotTrackPolicy(NetworkManagerFactory::getDoNotTrackPolicy());
326
327 if (doNotTrackPolicy != NetworkManagerFactory::SkipTrackPolicy)
328 {
329 request.setHttpHeader(QStringLiteral("DNT").toLatin1(), ((doNotTrackPolicy == NetworkManagerFactory::DoNotAllowToTrackPolicy) ? QStringLiteral("1") : QStringLiteral("0")).toLatin1());
330 }
331
332 if (!SettingsManager::getOption(SettingsManager::Network_EnableReferrerOption).toBool())
333 {
334 request.setHttpHeader(QStringLiteral("Referer").toLatin1(), QByteArray());
335 }
336 }
337 #endif
338
339 }
340