]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blobdiff - src/widgets/PrivacyWebEngineView.cpp
Partial filter list implementation.
[PrivacyBrowserPC.git] / src / widgets / PrivacyWebEngineView.cpp
index ba56d31d76c6827f9b3e1e60927c756f9ed4e896..15ee508b74eeaac03ad3d3e7c4e4c894b516edb6 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2022-2024 Soren Stoutner <soren@stoutner.com>.
  *
- * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/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
 
 // Application headers.
 #include "PrivacyWebEngineView.h"
+#include "Settings.h"
+#include "ui_HttpAuthenticationDialog.h"
 #include "databases/CookiesDatabase.h"
+#include "databases/DomainsDatabase.h"
+#include "dialogs/HttpAuthenticationDialog.h"
+#include "helpers/FilterListHelper.h"
+#include "interceptors/UrlRequestInterceptor.h"
 #include "windows/BrowserWindow.h"
 
+// Qt toolkit headers.
+#include <QContextMenuEvent>
+#include <QMenu>
+
 // Construct the class.
-PrivacyWebEngineView::PrivacyWebEngineView() : QWebEngineView(nullptr) {}
+PrivacyWebEngineView::PrivacyWebEngineView(QWidget *parentWidgetPointer) : QWebEngineView(parentWidgetPointer)
+{
+    // Create an off-the-record profile (the default when no profile name is specified).
+    webEngineProfilePointer = new QWebEngineProfile(QLatin1String(""));
+
+    // Create a WebEngine page.
+    QWebEnginePage *webEnginePagePointer = new QWebEnginePage(webEngineProfilePointer);
+
+    // Set the WebEngine page.
+    setPage(webEnginePagePointer);
+
+    // Get handles for the various aspects of the WebEngine.
+    webEngineSettingsPointer = webEnginePagePointer->settings();
+
+    // Instantiate the URL request interceptor.
+    UrlRequestInterceptor *urlRequestInterceptorPointer = new UrlRequestInterceptor(this);
+
+    // Set the URL request interceptor.
+    webEngineProfilePointer->setUrlRequestInterceptor(urlRequestInterceptorPointer);
+
+    // Connect the URL request interceptor signals.
+    connect(urlRequestInterceptorPointer, SIGNAL(applyDomainSettings(const QString&)), this, SLOT(applyDomainSettingsWithoutReloading(const QString&)));
+    connect(urlRequestInterceptorPointer, SIGNAL(newMainFrameResource()), this, SLOT(clearRequestsList()));
+    connect(urlRequestInterceptorPointer, SIGNAL(displayHttpPingDialog(const QString&)), this, SLOT(displayHttpPingDialog(const QString&)));
+    connect(urlRequestInterceptorPointer, SIGNAL(requestProcessed(RequestStruct*)), this, SLOT(storeRequest(RequestStruct*)));
+
+    // Handle HTTP authentication requests.
+    connect(webEnginePagePointer, SIGNAL(authenticationRequired(const QUrl&, QAuthenticator*)), this, SLOT(handleAuthenticationRequest(const QUrl&, QAuthenticator*)));
+}
 
 void PrivacyWebEngineView::addCookieToList(const QNetworkCookie &cookie) const
 {
@@ -37,30 +75,265 @@ void PrivacyWebEngineView::addCookieToList(const QNetworkCookie &cookie) const
         CookiesDatabase::updateCookie(cookie);
 
     // Update the cookies action.
-    emit updateCookiesAction(cookieListPointer->size());
+    emit numberOfCookiesChanged(cookieListPointer->size());
 }
 
-QWebEngineView* PrivacyWebEngineView::createWindow(QWebEnginePage::WebWindowType webWindowType) {
-    qDebug().noquote().nospace() << "Web window type:  " << webWindowType;
+void PrivacyWebEngineView::applyDomainSettingsWithoutReloading(const QString &hostname)
+{
+    // Apply the domain settings  `false` does not reload the website.
+    applyDomainSettings(hostname, false);
+}
+
+void PrivacyWebEngineView::applyDomainSettings(const QString &hostname, const bool reloadWebsite)
+{
+    // Get the record for the hostname.
+    QSqlQuery domainQuery = DomainsDatabase::getDomainQuery(hostname);
+
+    // Check if the hostname has domain settings.
+    if (domainQuery.isValid())  // The hostname has domain settings.
+    {
+        // Store the domain settings name.
+        domainSettingsName = domainQuery.value(DomainsDatabase::DOMAIN_NAME).toString();
+
+        // Set the JavaScript status.
+        switch (domainQuery.value(DomainsDatabase::JAVASCRIPT).toInt())
+        {
+            // Set the default JavaScript status.
+            case (DomainsDatabase::SYSTEM_DEFAULT):
+            {
+                webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
+
+                break;
+            }
+
+            // Enable JavaScript.
+            case (DomainsDatabase::ENABLED):
+            {
+                webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
+
+                break;
+            }
+
+            // Disable JavaScript.
+            case (DomainsDatabase::DISABLED):
+            {
+                webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
+
+                break;
+            }
+        }
+
+        // Set the local storage status.
+        switch (domainQuery.value(DomainsDatabase::LOCAL_STORAGE).toInt())
+        {
+            // Set the default local storage status.
+            case (DomainsDatabase::SYSTEM_DEFAULT):
+            {
+                localStorageEnabled = Settings::localStorageEnabled();
+
+                break;
+            }
+
+            // Enable local storage.
+            case (DomainsDatabase::ENABLED):
+            {
+                localStorageEnabled = true;
+
+                break;
+            }
+
+            // Disable local storage.
+            case (DomainsDatabase::DISABLED):
+            {
+                localStorageEnabled = false;
+
+                break;
+            }
+        }
+
+        // Set the DOM storage status.
+        switch (domainQuery.value(DomainsDatabase::DOM_STORAGE).toInt())
+        {
+            // Set the default DOM storage status.  QWebEngineSettings confusingly calls this local storage.
+            case (DomainsDatabase::SYSTEM_DEFAULT):
+            {
+                webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
+
+                break;
+            }
+
+            // Enable DOM storage.  QWebEngineSettings confusingly calls this local storage.
+            case (DomainsDatabase::ENABLED):
+            {
+                webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
+
+                break;
+            }
+
+            // Disable DOM storage.  QWebEngineSettings confusingly calls this local storage.
+            case (DomainsDatabase::DISABLED):
+            {
+                webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, false);
+
+                break;
+            }
+        }
+
+        // Set the user agent.
+        webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getResultingDomainSettingsUserAgent(domainQuery.value(DomainsDatabase::USER_AGENT).toString()));
+
+        // Check if a custom zoom factor is set.
+        if (domainQuery.value(DomainsDatabase::ZOOM_FACTOR).toInt())
+        {
+            // Store the current zoom factor.
+            defaultZoomFactor = domainQuery.value(DomainsDatabase::CUSTOM_ZOOM_FACTOR).toDouble();
+        }
+        else
+        {
+            // Store the current zoom factor.
+            defaultZoomFactor = Settings::zoomFactor();
+        }
+    }
+    else  // The hostname does not have domain settings.
+    {
+        // Reset the domain settings name.
+        domainSettingsName = QLatin1String("");
+
+        // Set the JavaScript status.
+        webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
+
+        // Set the local storage status.
+        localStorageEnabled = Settings::localStorageEnabled();
+
+        // Set DOM storage.  In QWebEngineSettings it is called Local Storage.
+        webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
+
+        // Set the user agent.
+        webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgentFromDatabaseName(Settings::userAgent()));
 
+        // Store the zoom factor.
+        defaultZoomFactor = Settings::zoomFactor();
+    }
+
+    // Set the current zoom factor.
+    setZoomFactor(defaultZoomFactor);
+
+    // Reload the website if requested.
+    if (reloadWebsite)
+        reload();
+
+    // Reset the HTTP authentication dialog counter.
+    httpAuthenticationDialogsDisplayed = 0;
+
+    // Update the UI.
+    emit updateUi(this);
+}
+
+void PrivacyWebEngineView::clearRequestsList()
+{
+    // Reset the number of blocked requests.
+    blockedRequests = 0;
+
+    // Clear the requests list.
+    requestsListPointer->clear();
+
+    // Update the blocked requests action.
+    emit(requestBlocked(blockedRequests));
+}
+
+void PrivacyWebEngineView::contextMenuEvent(QContextMenuEvent *contextMenuEvent) {
+    // Get a handle for the
+    QWebEnginePage *webEnginePagePointer = page();
+
+    // Get a handle for the menu.
+    QMenu *contextMenu = webEnginePagePointer->createStandardContextMenu();
+
+    // Get the list of context menu actions.
+    const QList<QAction *> contextMenuActionsList = contextMenu->actions();
+
+    // Add the open link in new background tab action if the context menu already contains the open link in new window action.
+    if (contextMenuActionsList.contains(webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewWindow)))
+    {
+        // Move the open in new tab action to the top of the list.
+        contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewTab));
+
+        // Add the open link in background tab action below the open in new tab action.
+        contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewBackgroundTab));
+
+        // Move the open in new window action below the open in background tab action.
+        contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewWindow));
+
+        // Add a separator below the open in new window action.
+        contextMenu->insertSeparator(webEnginePagePointer->action(QWebEnginePage::Back));
+    }
+
+    // Display the menu using the location in the context menu event.
+    contextMenu->popup(contextMenuEvent->globalPos());
+}
+
+QWebEngineView* PrivacyWebEngineView::createWindow(QWebEnginePage::WebWindowType webWindowType) {
     // Get a handle for the browser window.
     BrowserWindow *browserWindowPointer = qobject_cast<BrowserWindow*>(window());
 
-    // Create the requsted window type.
-    switch (webWindowType) {
-        case QWebEnginePage::WebBrowserTab: {
-            // Create the new tab and return the privacy WebEngine view pointer.  `true` removes the focus from the blank URL line edit.
+    // Create the requested window type.
+    switch (webWindowType)
+    {
+        case QWebEnginePage::WebBrowserTab:
+        {
+            // Create the new tab and return the privacy WebEngine view pointer.  `true` removes the focus from the blank URL line edit.  `true` adds the new tab adjacent to the current tab.
             // The new privacy WebEngine view pointer is returned so it can be populated with the link from the context menu.
-            return browserWindowPointer->tabWidgetPointer->addTab(true);
+            return browserWindowPointer->tabWidgetPointer->addTab(true, true);
         }
 
-        default: {
-            // Return an null pointer.
+        case QWebEnginePage::WebBrowserWindow:
+        {
+            // Create a new browser window.
+            BrowserWindow *newBrowserWindowPointer = new BrowserWindow();
+
+            // Show the new browser window.
+            newBrowserWindowPointer->show();
+
+            // The new privacy WebEngine view pointer is returned so it can be populated with the link from the context menu.
+            return newBrowserWindowPointer->tabWidgetPointer->loadBlankInitialWebsite();
+        }
+
+        case QWebEnginePage::WebBrowserBackgroundTab:
+        {
+            // Create the new tab and return the privacy WebEngine view pointer.  `false` does not clear the URL line edit.  `true` adds the new tab adjacent to the current tab.
+            // `true` creates a background tab.
+            // The new privacy WebEngine view pointer is returned so it can be populated with the link from the context menu.
+            return browserWindowPointer->tabWidgetPointer->addTab(false, true, true);
+        }
+
+        default:
+        {
+            // Return a null pointer for opening a web dialog.
             return nullptr;
         }
     }
 }
 
+void PrivacyWebEngineView::displayHttpPingDialog(const QString &httpPingUrl) const
+{
+    // Display the HTTP Ping blocked dialog.
+    emit displayHttpPingBlockedDialog(httpPingUrl);
+}
+
+void PrivacyWebEngineView::handleAuthenticationRequest(const QUrl &requestUrl, QAuthenticator *authenticatorPointer)
+{
+    // Only display the HTTP authentication dialog if it hasn't already been displayed three times for this URL.
+    if (httpAuthenticationDialogsDisplayed < 3) {
+        // Increment the HTTP authentication dialog display counter.
+        ++httpAuthenticationDialogsDisplayed;
+
+        // Instantiate an HTTP authentication dialog.
+        HttpAuthenticationDialog *httpAuthenticationDialogPointer = new HttpAuthenticationDialog(parentWidget(), requestUrl, authenticatorPointer);
+
+        // Display the dialog.  This must be `exec()` instead of `show()` so that the website doesn't proceed before populating the authentication pointer.
+        httpAuthenticationDialogPointer->exec();
+    }
+}
+
 void PrivacyWebEngineView::removeCookieFromList(const QNetworkCookie &cookie) const
 {
     //qDebug() << "Remove cookie:  " << cookie.toRawForm();
@@ -69,5 +342,21 @@ void PrivacyWebEngineView::removeCookieFromList(const QNetworkCookie &cookie) co
     cookieListPointer->remove(cookie);
 
     // Update the cookies action.
-    emit updateCookiesAction(cookieListPointer->size());
+    emit numberOfCookiesChanged(cookieListPointer->size());
+}
+
+void PrivacyWebEngineView::storeRequest(RequestStruct *requestStructPointer)
+{
+    // Store the request struct in the list.
+    requestsListPointer->append(requestStructPointer);
+
+    // Track blocked requests.
+    if (requestStructPointer->dispositionInt == FilterListHelper::BLOCKED)
+    {
+        // Update the blocked requests counter.
+        ++blockedRequests;
+
+        // Update the blocked requests action.
+        emit(requestBlocked(blockedRequests));
+    }
 }