diff options
-rw-r--r-- | smolbote.qbs | 13 | ||||
-rw-r--r-- | src/browser.cpp | 15 | ||||
-rw-r--r-- | src/browser.h | 8 | ||||
-rw-r--r-- | src/filter/filter.cpp | 212 | ||||
-rw-r--r-- | src/filter/filter.h | 91 | ||||
-rw-r--r-- | src/webengine/urlinterceptor.cpp | 49 | ||||
-rw-r--r-- | src/webengine/urlinterceptor.h | 18 |
7 files changed, 103 insertions, 303 deletions
diff --git a/smolbote.qbs b/smolbote.qbs index d18af60..a6044c3 100644 --- a/smolbote.qbs +++ b/smolbote.qbs @@ -116,14 +116,23 @@ Project { "src/widgets/webviewtabbar.h", ] } + + Group { + name: "Request Filter" + files: [ + "src/filter/filter.cpp", + "src/filter/filter.h", + "src/webengine/urlinterceptor.cpp", + "src/webengine/urlinterceptor.h", + ] + } + /* Group { name: "Request Filter" files: [ "src/filter/blockermanager.cpp", "src/filter/blockermanager.h", - "src/filter/filter.cpp", - "src/filter/filter.h", "src/filter/filtercollection.cpp", "src/filter/filtercollection.h", "src/filter/filtertree.cpp", diff --git a/src/browser.cpp b/src/browser.cpp index 354b179..82972dd 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -21,6 +21,7 @@ #include "browser.h" #include <bookmarks/bookmarkswidget.h> #include <downloads/downloadswidget.h> +#include "webengine/urlinterceptor.h" #include "mainwindow.h" #include <QtWebEngine> #include <QDir> @@ -39,8 +40,12 @@ Browser::Browser(int &argc, char *argv[]) : Browser::~Browser() { + // TODO: fix crash here // qDeleteAll(m_windows); // m_windows.clear(); + +// qDeleteAll(m_profiles); +// m_profiles.clear(); } void Browser::setConfiguration(std::shared_ptr<Configuration> &config) @@ -49,6 +54,8 @@ void Browser::setConfiguration(std::shared_ptr<Configuration> &config) m_bookmarksManager = std::make_shared<BookmarksWidget>(QString::fromStdString(m_config->value<std::string>("bookmarks.path").value())); m_downloadManager = std::make_shared<DownloadsWidget>(QString::fromStdString(m_config->value<std::string>("downloads.path").value())); + m_urlRequestInterceptor = std::make_shared<UrlRequestInterceptor>(QString::fromStdString(m_config->value<std::string>("browser.filterPath").value())); + } void Browser::loadProfiles() @@ -66,11 +73,15 @@ void Browser::loadProfiles() const QStringList profileList = profileDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); for(const QString &name : profileList) { - m_profiles.insert(name, new WebEngineProfile(name, profileDir.absoluteFilePath(name), this)); + WebEngineProfile *profile = new WebEngineProfile(name, profileDir.absoluteFilePath(name), this); + profile->setRequestInterceptor(m_urlRequestInterceptor.get()); + m_profiles.insert(name, profile); } // Also add the Off-the-record profile - m_profiles.insert("", new WebEngineProfile(this)); + WebEngineProfile *otr = new WebEngineProfile(this); + otr->setRequestInterceptor(m_urlRequestInterceptor.get()); + m_profiles.insert("", otr); // set default profile m_defaultProfile = m_profiles[QString::fromStdString(m_config->value<std::string>("browser.profile").value())]; diff --git a/src/browser.h b/src/browser.h index b3af5e6..a1557b4 100644 --- a/src/browser.h +++ b/src/browser.h @@ -23,10 +23,6 @@ #include "singleapplication.h" #include "webengine/webengineprofile.h" - -//#include "filter/blockermanager.h" -//#include "webengine/urlinterceptor.h" - #include <QVector> #include <memory> #include "settings/configuration.h" @@ -34,6 +30,7 @@ class MainWindow; class BookmarksWidget; class DownloadsWidget; +class UrlRequestInterceptor; class Browser : public SingleApplication { Q_OBJECT @@ -63,11 +60,10 @@ private: std::shared_ptr<Configuration> m_config; QVector<MainWindow *> m_windows; -// QVector<QPointer<MainWindow>> m_windows; QHash<QString, WebEngineProfile *> m_profiles; WebEngineProfile* m_defaultProfile; -// UrlRequestInterceptor *m_urlRequestInterceptor = nullptr; + std::shared_ptr<UrlRequestInterceptor> m_urlRequestInterceptor; std::shared_ptr<BookmarksWidget> m_bookmarksManager; std::shared_ptr<DownloadsWidget> m_downloadManager; // BlockerManager *m_blocklistManager = nullptr; diff --git a/src/filter/filter.cpp b/src/filter/filter.cpp index fcba05c..1d14f9d 100644 --- a/src/filter/filter.cpp +++ b/src/filter/filter.cpp @@ -19,220 +19,28 @@ ******************************************************************************/ #include "filter.h" +#include <QUrl> -Filter::Filter(const QString &domain, const QString &request, ResourceRules rules, bool shouldBlock, Filter *parentItem) +FilterRule::FilterRule(const QString &line) { - m_parentItem = parentItem; - - m_domainUrl.setPattern(domain); - m_requestUrl.setPattern(request); - m_rules = rules; - m_shouldBlock = shouldBlock; - - m_valid = false; -} - -Filter::~Filter() -{ - qDeleteAll(m_children); + parse(line); } -void Filter::enable() +FilterRule::~FilterRule() { - m_valid = true; -} - -Filter *Filter::parentItem() -{ - return m_parentItem; -} - -void Filter::appendChild(Filter *child) -{ - m_children.append(child); -} - -Filter *Filter::child(int row) -{ - return m_children.value(row); -} - -int Filter::childCount() const -{ - return m_children.count(); -} - -QString Filter::domain() const -{ - return m_domainUrl.pattern(); -} - -QString Filter::request() const -{ - return m_requestUrl.pattern(); -} - -bool Filter::isBlocking() -{ - return m_shouldBlock; -} - -QString Filter::allowedTypes() const -{ - return flags(m_rules.allowed); -} - -QString Filter::blockedTypes() const -{ - return flags(m_rules.blocked); -} - -int Filter::row() const -{ - if(m_parentItem) { - return m_parentItem->m_children.indexOf(const_cast<Filter*>(this)); - } - - return 0; } -bool Filter::hasDomainMatch(const QString &string) +bool FilterRule::shouldBlock(const QUrl &requestUrl) const { - return m_domainUrl.hasMatch(string); -} - -bool Filter::hasRuleMatch(const QString &string) -{ - return m_requestUrl.hasMatch(string); -} - -bool Filter::shouldBlock(const QWebEngineUrlRequestInfo &info) -{ - if(!m_valid) { + if(matcher.indexIn(requestUrl.toString()) == -1) { + // pattern not found in url return false; } - // Check options - switch (info.resourceType()) { - case QWebEngineUrlRequestInfo::ResourceTypeMainFrame: - return testFlag(MainFrame); - case QWebEngineUrlRequestInfo::ResourceTypeSubFrame: - return testFlag(SubFrame); - case QWebEngineUrlRequestInfo::ResourceTypeStylesheet: - return testFlag(Stylesheet); - case QWebEngineUrlRequestInfo::ResourceTypeScript: - return testFlag(Script); - case QWebEngineUrlRequestInfo::ResourceTypeImage: - return testFlag(Image); - case QWebEngineUrlRequestInfo::ResourceTypeFontResource: - return testFlag(Font); - case QWebEngineUrlRequestInfo::ResourceTypeSubResource: - return testFlag(SubResource); - case QWebEngineUrlRequestInfo::ResourceTypeObject: - return testFlag(Object); - case QWebEngineUrlRequestInfo::ResourceTypeMedia: - return testFlag(Media); - case QWebEngineUrlRequestInfo::ResourceTypeWorker: - return testFlag(Worker); - case QWebEngineUrlRequestInfo::ResourceTypeSharedWorker: - return testFlag(SharedWorker); - case QWebEngineUrlRequestInfo::ResourceTypePrefetch: - return testFlag(Prefetch); - case QWebEngineUrlRequestInfo::ResourceTypeFavicon: - return testFlag(Favicon); - case QWebEngineUrlRequestInfo::ResourceTypeXhr: - return testFlag(Xhr); - case QWebEngineUrlRequestInfo::ResourceTypePing: - return testFlag(Ping); - case QWebEngineUrlRequestInfo::ResourceTypeServiceWorker: - return testFlag(ServiceWorker); - case QWebEngineUrlRequestInfo::ResourceTypeCspReport: - return testFlag(CspReport); - case QWebEngineUrlRequestInfo::ResourceTypePluginResource: - return testFlag(PluginResource); - case QWebEngineUrlRequestInfo::ResourceTypeUnknown: - break; - } - - return m_shouldBlock; - + return true; } -bool Filter::isValid() +void FilterRule::parse(const QString &line) { - return m_valid; -} - -bool Filter::testFlag(ResourceType flag) -{ - if(m_rules.allowed.testFlag(flag)) { - return false; - } else if(m_rules.blocked.testFlag(flag)) { - return true; - } else { - return m_shouldBlock; - } -} - -QString Filter::flags(Resources f) const -{ - QStringList r; - if(f.testFlag(MainFrame)) { - r << QObject::tr("Main Frame"); - } - if(f.testFlag(SubFrame)) { - r << QObject::tr("Sub Frame"); - } - if(f.testFlag(Stylesheet)) { - r << QObject::tr("Stylesheet"); - } - if(f.testFlag(Script)) { - r << QObject::tr("Script"); - } - if(f.testFlag(Image)) { - r << QObject::tr("Image"); - } - if(f.testFlag(Font)) { - r << QObject::tr("Font"); - } - if(f.testFlag(SubResource)) { - r << QObject::tr("Sub Resource"); - } - if(f.testFlag(Object)) { - r << QObject::tr("Object"); - } - if(f.testFlag(Media)) { - r << QObject::tr("Media"); - } - if(f.testFlag(Worker)) { - r << QObject::tr("Worker"); - } - if(f.testFlag(SharedWorker)) { - r << QObject::tr("Shared Worker"); - } - if(f.testFlag(Prefetch)) { - r << QObject::tr("Prefetch"); - } - if(f.testFlag(Favicon)) { - r << QObject::tr("Favicon"); - } - if(f.testFlag(Xhr)) { - r << QObject::tr("Xhr"); - } - if(f.testFlag(Ping)) { - r << QObject::tr("Ping"); - } - if(f.testFlag(ServiceWorker)) { - r << QObject::tr("Service Worker"); - } - if(f.testFlag(CspReport)) { - r << QObject::tr("Csp Report"); - } - if(f.testFlag(PluginResource)) { - r << QObject::tr("Plugin Resource"); - } - if(f.testFlag(Unknown)) { - r << QObject::tr("Unknown"); - } - return r.join(','); + matcher.setPattern(line); } diff --git a/src/filter/filter.h b/src/filter/filter.h index aeababd..bd3e2ca 100644 --- a/src/filter/filter.h +++ b/src/filter/filter.h @@ -18,90 +18,37 @@ ** ******************************************************************************/ -#ifndef FILTERNODE_H -#define FILTERNODE_H +#ifndef FILTERRULE_H +#define FILTERRULE_H -#include <QList> -#include <QVariant> -#include <QUrl> -#include "regexp.h" -#include <QWebEngineUrlRequestInfo> +#include <QStringMatcher> -class Filter +class QUrl; +class FilterRule { public: - enum ResourceType { - NoType = 0, - MainFrame = 1, - SubFrame = 2, - Stylesheet = 4, - Script = 8, - Image = 16, - Font = 32, - SubResource = 64, - Object = 128, - Media = 256, - Worker = 512, - SharedWorker = 1024, - Prefetch = 2048, - Favicon = 4096, - Xhr = 8192, - Ping = 16384, - ServiceWorker = 32768, - CspReport = 65536, - PluginResource = 131072, - Unknown = 262144 - }; - Q_DECLARE_FLAGS(Resources, ResourceType) + FilterRule(const QString &line); - struct ResourceRules { - Resources allowed; - Resources blocked; - }; + // delete the copy constructor and assignment operator + FilterRule(const FilterRule&) = delete; + FilterRule& operator=(const FilterRule&) = delete; - explicit Filter(const QString &domain, const QString &request, ResourceRules rules, bool shouldBlock, Filter *parentItem = 0); - ~Filter(); + // move constructor + FilterRule(FilterRule&& other) { + matcher = other.matcher; + } - void enable(); + ~FilterRule(); - Filter *parentItem(); - - // children - void appendChild(Filter *child); - Filter *child(int row); - int childCount() const; - - // data - QString domain() const; - QString request() const; - bool isBlocking(); - QString allowedTypes() const; - QString blockedTypes() const; - - int row() const; - - // filtering - bool hasDomainMatch(const QString &string); - bool hasRuleMatch(const QString &string); - bool shouldBlock(const QWebEngineUrlRequestInfo &info); - - bool isValid(); + bool shouldBlock(const QUrl &requestUrl) const; private: - bool testFlag(ResourceType flag); - QString flags(Resources f) const; - - Filter *m_parentItem; - QList<Filter*> m_children; - - RegExp m_domainUrl; - RegExp m_requestUrl; + void parse(const QString &line); - ResourceRules m_rules; + // QStringMatcher: holds a pattern you want to repeatedly match against some strings + QStringMatcher matcher; - bool m_valid = false; - bool m_shouldBlock; }; -#endif // FILTERNODE_H +#endif // FILTERRULE_H diff --git a/src/webengine/urlinterceptor.cpp b/src/webengine/urlinterceptor.cpp index 19bc64f..cbf1c86 100644 --- a/src/webengine/urlinterceptor.cpp +++ b/src/webengine/urlinterceptor.cpp @@ -19,31 +19,56 @@ ******************************************************************************/ #include "urlinterceptor.h" -#include "filter/filtercollection.h" +#include <QFile> +#include <QTextStream> -UrlRequestInterceptor::UrlRequestInterceptor(QObject *parent) : +UrlRequestInterceptor::UrlRequestInterceptor(const QString &path, QObject *parent) : QWebEngineUrlRequestInterceptor(parent) { +#ifdef QT_DEBUG + qDebug("Reading request blocklist: %s", qUtf8Printable(path)); +#endif + + int n_rules = 0; + + QFile filter(path); + if(filter.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream out(&filter); + while(!out.atEnd()) { + const QString &line = out.readLine(); + if(!line.startsWith('!')) { + FilterRule r(line); + // check if valid + m_rules.push_back(std::move(r)); + ++n_rules; + } + } + filter.close(); + } + + qDebug("Added %i rules", n_rules); } void UrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) { -#ifdef DEBUG_VERBOSE - qDebug("%s -[%i]-> %s", qUtf8Printable(info.firstPartyUrl().toString()), info.resourceType(), qUtf8Printable(info.requestUrl().toString())); -#endif - for(auto s : m_manager->subscriptions()) { - bool shouldBlock = s->match(info); - if(shouldBlock) { + for(const FilterRule &test : m_rules) { + const QUrl &url = info.requestUrl(); + + if(test.shouldBlock(url)) { info.block(true); -#ifdef DEBUG_VERBOSE - qDebug(">> blocked"); + +#ifdef QT_DEBUG + qDebug("blocked [%s] %s", qUtf8Printable(info.firstPartyUrl().toString()), qUtf8Printable(url.toString())); #endif return; } } } -void UrlRequestInterceptor::setSubscription(BlockerManager *manager) +bool shouldBlock(const QUrl &url, const QString &test) { - m_manager = manager; + if(url.toString().contains(test)) { + return true; + } + return false; } diff --git a/src/webengine/urlinterceptor.h b/src/webengine/urlinterceptor.h index acd076a..4466523 100644 --- a/src/webengine/urlinterceptor.h +++ b/src/webengine/urlinterceptor.h @@ -18,27 +18,31 @@ ** ******************************************************************************/ -#ifndef ADBLOCKINTERCEPTOR_H -#define ADBLOCKINTERCEPTOR_H +#ifndef URLREQUESTINTERCEPTOR_H +#define URLREQUESTINTERCEPTOR_H #include <QWebEngineUrlRequestInterceptor> -#include "filter/blockermanager.h" +#include <vector> +#include "filter/filter.h" class UrlRequestInterceptor : public QWebEngineUrlRequestInterceptor { Q_OBJECT public: - explicit UrlRequestInterceptor(QObject *parent = 0); + explicit UrlRequestInterceptor(const QString &path, QObject *parent = nullptr); + //~UrlRequestInterceptor(); void interceptRequest(QWebEngineUrlRequestInfo &info); - void setSubscription(BlockerManager *manager); signals: public slots: private: - BlockerManager *m_manager; + + std::vector<FilterRule> m_rules; }; -#endif // ADBLOCKINTERCEPTOR_H +bool shouldBlock(const QUrl &url, const QString &test); + +#endif // URLREQUESTINTERCEPTOR_H |