Falkon Develop
Cross-platform Qt-based web browser
sitesettingsmanager.cpp
Go to the documentation of this file.
1/* ============================================================
2 * Falkon - Qt web browser
3 * Copyright (C) 2022 Juraj Oravec <jurajoravec@mailo.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * ============================================================ */
18
19#include "sitesettingsmanager.h"
20
21#include "mainapplication.h"
22#include "settings.h"
23#include "sqldatabase.h"
24
25#include <QUrl>
26#include <QtWebEngineCoreVersion>
27
28
29const QList<QWebEngineSettings::WebAttribute> supportedAttribute = {
30 QWebEngineSettings::AutoLoadImages
31 ,QWebEngineSettings::JavascriptEnabled
32 ,QWebEngineSettings::JavascriptCanOpenWindows
33 ,QWebEngineSettings::JavascriptCanAccessClipboard
34 ,QWebEngineSettings::JavascriptCanPaste
35 ,QWebEngineSettings::AllowWindowActivationFromJavaScript
36 ,QWebEngineSettings::LocalStorageEnabled
37 ,QWebEngineSettings::FullScreenSupportEnabled
38 ,QWebEngineSettings::AllowRunningInsecureContent
39 ,QWebEngineSettings::PlaybackRequiresUserGesture
40#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 6, 0)
41 ,QWebEngineSettings::ReadingFromCanvasEnabled
42#endif
43#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 7, 0)
44 ,QWebEngineSettings::ForceDarkMode
45#endif
46};
47const QList<QWebEnginePage::Feature> supportedFeatures = {
48 QWebEnginePage::Notifications
49 ,QWebEnginePage::Geolocation
50 ,QWebEnginePage::MediaAudioCapture
51 ,QWebEnginePage::MediaVideoCapture
52 ,QWebEnginePage::MediaAudioVideoCapture
53 ,QWebEnginePage::MouseLock
54 ,QWebEnginePage::DesktopVideoCapture
55 ,QWebEnginePage::DesktopAudioVideoCapture
56};
57
58
60: QObject(parent)
61, m_defaultCookies(Deny)
62{
63 prepareSqls();
65}
66
68
70{
71 Settings settings;
72
73 settings.beginGroup(QSL("Site-Settings"));
74 /* HTML5 Feature */
75 for (const auto &feature : std::as_const(supportedFeatures)) {
76 defaultFeatures[feature] = intToPermission(settings.value(featureToSqlColumn(feature), Ask).toInt());
77 }
78 settings.endGroup();
79
80 settings.beginGroup(QSL("Cookie-Settings"));
81 m_defaultCookies = settings.value(QSL("allowCookies"), true).toBool() ? Allow : Deny;
82 settings.endGroup();
83}
84
86{
87 Settings settings;
88 settings.beginGroup(QSL("Site-Settings"));
89 for (auto it = defaultFeatures.begin(); it != defaultFeatures.end(); ++it) {
90 settings.setValue(featureToSqlColumn(it.key()), it.value());
91 }
92 settings.endGroup();
93}
94
95QHash<QWebEngineSettings::WebAttribute, bool> SiteSettingsManager::getWebAttributes(const QUrl& url)
96{
97 QHash<QWebEngineSettings::WebAttribute, bool> attributes;
98 QString host = url.host();
99
100 if (host.isEmpty()) {
101 for (int i = 0; i < supportedAttribute.size(); ++i) {
102 QWebEngineSettings::WebAttribute attribute = supportedAttribute[i];
103 attributes[attribute] = mApp->webSettings()->testAttribute(attribute);
104 }
105
106 return attributes;
107 }
108
109 QSqlQuery query(SqlDatabase::instance()->database());
110 query.prepare(attributesSql);
111 query.addBindValue(host);
112 query.exec();
113
114 if (query.next()) {
115 for (int i = 0; i < query.record().count(); ++i) {
116 SiteSettingsManager::Permission perm = intToPermission(query.value(i).toInt());
117 QWebEngineSettings::WebAttribute attribute = supportedAttribute[i];
118
119 if (perm == Allow) {
120 attributes[attribute] = true;
121 }
122 else if (perm == Deny) {
123 attributes[attribute] = false;
124 }
125 else {
126 attributes[attribute] = mApp->webSettings()->testAttribute(attribute);
127 }
128 }
129 }
130
131 return attributes;
132}
133
134void SiteSettingsManager::setOption(const QString& column, const QUrl& url, const int value)
135{
136 QString host = url.host();
137
138 if (column.isEmpty() || host.isEmpty()) {
139 return;
140 }
141
142 auto job = new SqlQueryJob(QSL("UPDATE %2 SET %1=? WHERE server=?").arg(column, sqlTable()), this);
143 job->addBindValue(value);
144 job->addBindValue(host);
145 connect(job, &SqlQueryJob::finished, this, [=]() {
146 if (job->numRowsAffected() == 0) {
147 auto job = new SqlQueryJob(QSL("INSERT INTO %2 (server, %1) VALUES (?,?)").arg(column, sqlTable()), this);
148 job->addBindValue(host);
149 job->addBindValue(value);
150 job->start();
151 }
152 });
153 job->start();
154}
155
156void SiteSettingsManager::setOption(const PageOptions option, const QUrl& url, const int value)
157{
158 setOption(optionToSqlColumn(option), url, value);
159}
160
161void SiteSettingsManager::setOption(const QWebEnginePage::Feature& feature, const QUrl& url, const SiteSettingsManager::Permission value)
162{
163 setOption(featureToSqlColumn(feature), url, value);
164}
165
166void SiteSettingsManager::setOption(const QWebEngineSettings::WebAttribute& attribute, const QUrl& url, const SiteSettingsManager::Permission value)
167{
168 setOption(webAttributeToSqlColumn(attribute), url, value);
169}
170
172{
173 if (column.isEmpty()) {
174 return Deny;
175 }
176 if (host.isEmpty()) {
177 return Default;
178 }
179
180 QSqlQuery query(SqlDatabase::instance()->database());
181 query.prepare(QSL("SELECT %1 FROM %2 WHERE server=?").arg(column, sqlTable()));
182 query.addBindValue(host);
183 query.exec();
184
185 if (query.next()) {
186 int allow_option = query.value(column).toInt();
187
188 return intToPermission(allow_option);
189 }
190
191 return Default;
192}
193
195{
196 return getPermission(optionToSqlColumn(option), host);
197}
198
199SiteSettingsManager::Permission SiteSettingsManager::getPermission(const QWebEnginePage::Feature feature, const QString& host)
200{
201 return getPermission(featureToSqlColumn(feature), host);
202}
203
204SiteSettingsManager::Permission SiteSettingsManager::getPermission(const QWebEngineSettings::WebAttribute attribute, const QString& host)
205{
206 return getPermission(webAttributeToSqlColumn(attribute), host);
207}
208
210{
211 return getPermission(column, url.host());
212}
213
215{
216 return getPermission(optionToSqlColumn(option), url.host());
217}
218
219SiteSettingsManager::Permission SiteSettingsManager::getPermission(const QWebEnginePage::Feature feature, const QUrl& url)
220{
221 return getPermission(featureToSqlColumn(feature), url.host());
222}
223
224SiteSettingsManager::Permission SiteSettingsManager::getPermission(const QWebEngineSettings::WebAttribute attribute, const QUrl& url)
225{
226 return getPermission(webAttributeToSqlColumn(attribute), url.host());
227}
228
230{
231 switch (option) {
232 case poAllowCookies:
233 return m_defaultCookies;
234 // so far not implemented
235 case poZoomLevel:
236 default:
237 qWarning() << "Unknown option:" << option;
238 return Deny;
239 }
240}
241
243{
244 if (!supportedFeatures.contains(feature)) {
245 qWarning() << "Unknown feature:" << feature;
246 return Deny;
247 }
248
249 return defaultFeatures[feature];
250}
251
252SiteSettingsManager::Permission SiteSettingsManager::getDefaultPermission(const QWebEngineSettings::WebAttribute attribute) const
253{
254 if (!supportedAttribute.contains(attribute)) {
255 qWarning() << "Unknown attribute:" << attribute;
256 return Deny;
257 }
258
259 if (mApp->webSettings()->testAttribute(attribute)) {
260 return Allow;
261 }
262 else {
263 return Deny;
264 }
265}
266
268{
269 switch (permission) {
270 case Allow:
271 return Allow;
272 case Deny:
273 return Deny;
274 case Ask:
275 return Ask;
276 default:
277 return Default;
278 }
279}
280
282{
283 switch (option) {
284 case poZoomLevel:
285 return tr("Zoom level");
286 case poAllowCookies:
287 return tr("Cookies");
288 default:
289 qWarning() << "Unknown option:" << option;
290 return tr("Unknown");;
291 }
292}
293
294QString SiteSettingsManager::getOptionName(const QWebEnginePage::Feature feature) const
295{
296 switch (feature) {
297 case QWebEnginePage::Notifications:
298 return tr("Notifications");
299 case QWebEnginePage::Geolocation:
300 return tr("Geolocation");
301 case QWebEnginePage::MediaAudioCapture:
302 return tr("Microphone");
303 case QWebEnginePage::MediaVideoCapture:
304 return tr("Camera");
305 case QWebEnginePage::MediaAudioVideoCapture:
306 return tr("Microphone and Camera");
307 case QWebEnginePage::MouseLock:
308 return tr("Hide mouse pointer");
309 case QWebEnginePage::DesktopVideoCapture:
310 return tr("Screen capture");
311 case QWebEnginePage::DesktopAudioVideoCapture:
312 return tr("Screen capture with audio");
313 default:
314 qWarning() << "Unknown feature:" << feature;
315 return tr("Unknown");
316 }
317}
318
319QString SiteSettingsManager::getOptionName(const QWebEngineSettings::WebAttribute attribute) const
320{
321 switch (attribute) {
322 case QWebEngineSettings::AutoLoadImages:
323 return tr("Autoload images");
324
325 case QWebEngineSettings::JavascriptEnabled:
326 return tr("Enable JavaScript");
327 case QWebEngineSettings::JavascriptCanOpenWindows:
328 return tr("JavaScript: Open popup windows");
329 case QWebEngineSettings::JavascriptCanAccessClipboard:
330 return tr("JavaScript: Access clipboard");
331 case QWebEngineSettings::JavascriptCanPaste:
332 return tr("JavaScript: Paste from clipboard");
333 case QWebEngineSettings::AllowWindowActivationFromJavaScript:
334 return tr("JavaScript: Activate windows");
335
336 case QWebEngineSettings::LocalStorageEnabled:
337 return tr("Local storage");
338 case QWebEngineSettings::FullScreenSupportEnabled:
339 return tr("FullScreen support");
340 case QWebEngineSettings::AllowRunningInsecureContent:
341 return tr("Run insecure content");
342 case QWebEngineSettings::PlaybackRequiresUserGesture:
343 return tr("Automatic playing of videos");
344#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 6, 0)
345 case QWebEngineSettings::ReadingFromCanvasEnabled:
346 return tr("Allow reading from canvas");
347#endif
348#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 7, 0)
349 case QWebEngineSettings::ForceDarkMode:
350 return tr("Force dark mode");
351#endif
352
353 default:
354 qWarning() << "Unknown attribute:" << attribute;
355 return tr("Unknown");
356 }
357}
358
360{
361 switch (permission) {
362 case Allow:
363 return tr("Allow");
364 case Ask:
365 return tr("Ask");
366 case Deny:
367 return tr("Deny");
368 case Default:
369 return tr("Default");
370 default:
371 qWarning() << "Uknown permission:" << permission;
372 return tr("Unknown");
373 }
374}
375
377{
378 switch (option) {
379 case poAllowCookies:
380 return QSL("allow_cookies");
381 case poZoomLevel:
382 return QSL("zoom_level");
383 default:
384 qWarning() << "Unknown option:" << option;
385 return QLatin1String("");
386 }
387}
388
389QString SiteSettingsManager::featureToSqlColumn(const QWebEnginePage::Feature feature) const
390{
391 switch (feature) {
392 case QWebEnginePage::Notifications:
393 return QSL("f_notifications");
394 case QWebEnginePage::Geolocation:
395 return QSL("f_geolocation");
396 case QWebEnginePage::MediaAudioCapture:
397 return QSL("f_media_audio_capture");
398 case QWebEnginePage::MediaVideoCapture:
399 return QSL("f_media_video_capture");
400 case QWebEnginePage::MediaAudioVideoCapture:
401 return QSL("f_media_audio_video_capture");
402 case QWebEnginePage::MouseLock:
403 return QSL("f_mouse_lock");
404 case QWebEnginePage::DesktopVideoCapture:
405 return QSL("f_desktop_video_capture");
406 case QWebEnginePage::DesktopAudioVideoCapture:
407 return QSL("f_desktop_audio_video_capture");
408 default:
409 qWarning() << "Unknown feature:" << feature;
410 return QSL("f_notifications");
411 }
412}
413
414QString SiteSettingsManager::webAttributeToSqlColumn(const QWebEngineSettings::WebAttribute attribute) const
415{
416 switch (attribute) {
417 case QWebEngineSettings::AutoLoadImages:
418 return QSL("wa_autoload_images");
419
420 case QWebEngineSettings::JavascriptEnabled:
421 return QSL("wa_js_enabled");
422 case QWebEngineSettings::JavascriptCanOpenWindows:
423 return QSL("wa_js_open_windows");
424 case QWebEngineSettings::JavascriptCanAccessClipboard:
425 return QSL("wa_js_access_clipboard");
426 case QWebEngineSettings::JavascriptCanPaste:
427 return QSL("wa_js_can_paste");
428 case QWebEngineSettings::AllowWindowActivationFromJavaScript:
429 return QSL("wa_js_window_activation");
430
431 case QWebEngineSettings::LocalStorageEnabled:
432 return QSL("wa_local_storage");
433 case QWebEngineSettings::FullScreenSupportEnabled:
434 return QSL("wa_fullscreen_support");
435 case QWebEngineSettings::AllowRunningInsecureContent:
436 return QSL("wa_run_insecure_content");
437 case QWebEngineSettings::PlaybackRequiresUserGesture:
438 return QSL("wa_playback_needs_gesture");
439#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 6, 0)
440 case QWebEngineSettings::ReadingFromCanvasEnabled:
441 return QSL("wa_reading_from_canvas");
442#endif
443#if QTWEBENGINECORE_VERSION >= QT_VERSION_CHECK(6, 7, 0)
444 case QWebEngineSettings::ForceDarkMode:
445 return QSL("wa_force_dark_mode");
446#endif
447
448 default:
449 qWarning() << "Unknown attribute:" << attribute;
450 return QSL("wa_js_enabled");
451 }
452}
453
454QList<QWebEngineSettings::WebAttribute> SiteSettingsManager::getSupportedAttribute() const
455{
456 return supportedAttribute;
457}
458
459QList<QWebEnginePage::Feature> SiteSettingsManager::getSupportedFeatures() const
460{
461 return supportedFeatures;
462}
463
465{
466 SiteSettings siteSettings;
467 siteSettings.server = url.host();
468
469 if (url.isEmpty()) {
470 return siteSettings;
471 }
472
473 int index = 0;
474
475 QSqlQuery query(SqlDatabase::instance()->database());
476 query.prepare(everythingSql.arg(sqlTable()));
477 query.addBindValue(url.host());
478 query.exec();
479
480 if (query.next()) {
481 Permission perm;
482 for (int i = 0; i < supportedAttribute.size(); ++i, ++index) {
483 perm = intToPermission(query.value(index).toInt());
484 siteSettings.attributes[supportedAttribute[i]] = perm;
485 }
486 for (int i = 0; i < supportedFeatures.size(); ++i, ++index) {
487 perm = intToPermission(query.value(index).toInt());
488 siteSettings.features[supportedFeatures[i]] = perm;
489 }
490 siteSettings.AllowCookies = intToPermission(query.value(index++).toInt());
491 siteSettings.ZoomLevel = query.value(index++).toInt();
492 }
493
494 return siteSettings;
495}
496
498{
499 if (siteSettings.server.isEmpty()) {
500 return;
501 }
502
503 auto job = new SqlQueryJob(everythingUpdateSql.arg(sqlTable()), this);
504
505 for (int i = 0; i < supportedAttribute.size(); ++i) {
506 job->addBindValue(siteSettings.attributes[supportedAttribute[i]]);
507 }
508 for (int i = 0; i < supportedFeatures.size(); ++i) {
509 job->addBindValue(siteSettings.features[supportedFeatures[i]]);
510 }
511 job->addBindValue(siteSettings.AllowCookies);
512 job->addBindValue(siteSettings.ZoomLevel);
513 job->addBindValue(siteSettings.server);
514
515 connect(job, &SqlQueryJob::finished, this, [=]() {
516 if (job->numRowsAffected() == 0) {
517 auto job = new SqlQueryJob(everythingInsertSql.arg(sqlTable()), this);
518
519 for (int i = 0; i < supportedAttribute.size(); ++i) {
520 job->addBindValue(siteSettings.attributes[supportedAttribute[i]]);
521 }
522 for (int i = 0; i < supportedFeatures.size(); ++i) {
523 job->addBindValue(siteSettings.features[supportedFeatures[i]]);
524 }
525 job->addBindValue(siteSettings.AllowCookies);
526 job->addBindValue(siteSettings.ZoomLevel);
527 job->addBindValue(siteSettings.server);
528
529 job->start();
530 }
531 });
532 job->start();
533}
534
536{
537 return QSL("site_settings");
538}
539
540void SiteSettingsManager::prepareSqls() {
541 /* Select SQL for QtWE Attributes */
542 attributesSql = QSL("SELECT ");
543
544 for (int i = 0; i < supportedAttribute.size(); ++i) {
545 if (i > 0) {
546 attributesSql.append(QSL(", "));
547 }
548 attributesSql.append(webAttributeToSqlColumn(supportedAttribute[i]));
549 }
550
551 attributesSql.append(QSL(" FROM %1 WHERE server=?").arg(sqlTable()));
552
553
554 /* Select SQL for SiteSettings */
555 everythingSql = QSL("SELECT ");
556
557 for (int i = 0; i < supportedAttribute.size(); ++i) {
558 if (i > 0) {
559 everythingSql.append(QSL(", "));
560 }
561 everythingSql.append(webAttributeToSqlColumn(supportedAttribute[i]));
562 }
563
564 for (int i = 0; i < supportedFeatures.size(); ++i) {
565 everythingSql.append(QSL(", "));
566 everythingSql.append(featureToSqlColumn(supportedFeatures[i]));
567 }
568
569 everythingSql.append(QSL(", "));
570 everythingSql.append(optionToSqlColumn(poAllowCookies));
571
572 everythingSql.append(QSL(", "));
573 everythingSql.append(optionToSqlColumn(poZoomLevel));
574
575 everythingSql.append(QSL(" FROM %1 WHERE server=?"));
576
577
578 /* Insert SQL for SiteSettings */
579 everythingInsertSql = QSL("INSERT INTO %1 (");
580 for (int i = 0; i < supportedAttribute.size(); ++i) {
581 everythingInsertSql.append(webAttributeToSqlColumn(supportedAttribute[i]));
582 everythingInsertSql.append(QSL(", "));
583 }
584 for (int i = 0; i < supportedFeatures.size(); ++i) {
585 everythingInsertSql.append(featureToSqlColumn(supportedFeatures[i]));
586 everythingInsertSql.append(QSL(", "));
587 }
588
589 everythingInsertSql.append(optionToSqlColumn(poAllowCookies));
590 everythingInsertSql.append(QSL(", "));
591
592 everythingInsertSql.append(optionToSqlColumn(poZoomLevel));
593
594 everythingInsertSql.append(QSL(", server"));
595
596 everythingInsertSql.append(QSL(") Values ("));
597 /* Index = sum(server, numberOfAttributes, numberOfFeatures, cookies, zoom) */
598 int index = 1 + supportedAttribute.size() + supportedFeatures.size() + 2;
599 for (int i = 0; i < index; ++i) {
600 if (i > 0) {
601 everythingInsertSql.append(QSL(", "));
602 }
603 everythingInsertSql.append(QSL("?"));
604 }
605 everythingInsertSql.append(QSL(")"));
606
607
608 /* Update SQL for SiteSettings */
609 everythingUpdateSql = QSL("UPDATE %1 SET ");
610 for (int i = 0; i < supportedAttribute.size(); ++i) {
611 everythingUpdateSql.append(webAttributeToSqlColumn(supportedAttribute[i]));
612 everythingUpdateSql.append(QSL("=?, "));
613 }
614 for (int i = 0; i < supportedFeatures.size(); ++i) {
615 everythingUpdateSql.append(featureToSqlColumn(supportedFeatures[i]));
616 everythingUpdateSql.append(QSL("=?, "));
617 }
618
619 everythingUpdateSql.append(optionToSqlColumn(poAllowCookies));
620 everythingUpdateSql.append(QSL("=?, "));
621
622 everythingUpdateSql.append(optionToSqlColumn(poZoomLevel));
623 everythingUpdateSql.append(QSL("=? "));
624
625 everythingUpdateSql.append(QSL(" WHERE server=?"));
626}
void beginGroup(const QString &prefix)
Definition: settings.cpp:79
void endGroup()
Definition: settings.cpp:84
QVariant value(const QString &key, const QVariant &defaultValue=QVariant())
Definition: settings.cpp:74
void setValue(const QString &key, const QVariant &defaultValue=QVariant())
Definition: settings.cpp:69
Permission getPermission(const QString &column, const QString &host)
QString getPermissionName(const Permission permission) const
QString featureToSqlColumn(const QWebEnginePage::Feature feature) const
QList< QWebEnginePage::Feature > getSupportedFeatures() const
SiteSettingsManager(QObject *parent=nullptr)
QString webAttributeToSqlColumn(const QWebEngineSettings::WebAttribute attribute) const
Permission getDefaultPermission(const PageOptions option)
Permission intToPermission(const int permission) const
QHash< QWebEngineSettings::WebAttribute, bool > getWebAttributes(const QUrl &url)
void setOption(const QString &column, const QUrl &url, const int value)
QString getOptionName(const SiteSettingsManager::PageOptions option) const
QString optionToSqlColumn(const PageOptions option) const
QList< QWebEngineSettings::WebAttribute > getSupportedAttribute() const
void setSiteSettings(SiteSettings &siteSettings)
SiteSettings getSiteSettings(QUrl &url)
static SqlDatabase * instance()
void finished(SqlQueryJob *job)
#define mApp
int value(const QColor &c)
Definition: colors.cpp:238
i
Definition: i18n.py:23
#define QSL(x)
Definition: qzcommon.h:40
const QList< QWebEngineSettings::WebAttribute > supportedAttribute
const QList< QWebEnginePage::Feature > supportedFeatures
QMap< QWebEnginePage::Feature, Permission > features
QMap< QWebEngineSettings::WebAttribute, Permission > attributes