/* * This file is part of smolbote. It's copyrighted by the contributors recorded * in the version control history of the file, available from its original * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote * * SPDX-License-Identifier: GPL-3.0 */ #ifndef SMOLBOTE_ADBLOCKRULE_H #define SMOLBOTE_ADBLOCKRULE_H #include "../filterleaf.h" #include #include #include class Matcher { public: virtual bool hasMatch(const QString &where) const = 0; }; template class ContentsMatcher : public Matcher { public: ContentsMatcher(const QString &pattern, FilterLeaf::UrlMatchType matchType) { this->matchType = matchType; patternLength = pattern.length(); if constexpr(std::is_same_v) { matcher.setPatternOptions(matcher.patternOptions() | QRegularExpression::CaseInsensitiveOption); matcher.setPattern(pattern); } else if constexpr(std::is_same_v) { matcher.setCaseSensitivity(Qt::CaseInsensitive); matcher.setPattern(pattern); } else if constexpr(std::is_same_v) { matcher = QUrl::fromUserInput(pattern).host(); // qDebug("matcher: %s", qUtf8Printable(matcher)); } } bool hasMatch(const QString &where) const override { if constexpr(std::is_same_v) { switch (matchType) { case FilterLeaf::InvalidMatch: case FilterLeaf::RegularExpressionMatch: case FilterLeaf::DomainMatch: qWarning("ContentsMatcher is a String Matcher, but not doing string matching!"); return false; case FilterLeaf::StringContains: return (matcher.indexIn(where) != -1); case FilterLeaf::StringStartsWith: return (matcher.indexIn(where) == 0); case FilterLeaf::StringEndsWith: return (matcher.indexIn(where) == where.length() - patternLength); case FilterLeaf::StringEquals: return (matcher.indexIn(where) == 0) && (patternLength == where.length()); } } else if constexpr(std::is_same_v) { if(matchType != FilterLeaf::RegularExpressionMatch) qWarning("ContentsMatcher is a regular expression, but not doing a regular expression match!"); return matcher.match(where).hasMatch(); } else if constexpr(std::is_same_v) { // TODO: fix if(matchType == FilterLeaf::DomainMatch) { // qDebug("matching %s", qUtf8Printable(QUrl(where).host())); return QUrl(where).host().endsWith(matcher); } else return matcher == where; } else { qWarning("Matcher has no backend, returning false"); return false; } } private: int patternLength; T matcher; FilterLeaf::UrlMatchType matchType; }; class AdBlockRule : public FilterLeaf { public: explicit AdBlockRule(FilterLeaf::UrlMatchType matchType, const QString &filter, FilterLeaf::Action action); ~AdBlockRule() { delete stringMatcher; delete regExp; }; void mergeOptions(const QHash &options); bool match(const QUrl &requestUrl) const override; bool match(const QUrl &requestUrl, QWebEngineUrlRequestInfo::ResourceType type) const; std::pair action() const override; private: /* Once C++20 comes out, perhaps this can be replaced with a concept template */ QStringMatcher *stringMatcher = nullptr; QRegExp *regExp = nullptr; }; #endif // SMOLBOTE_ADBLOCKRULE_H