/** LICENSE ******************************************************************** ** ** smolbote: yet another qute browser ** Copyright (C) 2017 Xian Nox ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ******************************************************************************/ #include "blockerrule.h" /* AdBlock filter reference * https://adblockplus.org/en/filters * https://adblockplus.org/en/filter-cheatsheet */ BlockerRule::BlockerRule(QString rule, QObject *parent) : QObject(parent) { QString pattern = rule; // Empty rule or comment if(pattern.trimmed().isEmpty() || pattern.startsWith("!")) { m_type = RuleType::Invalid; return; } // Ignore element hiding rules for now if(pattern.contains("##") || pattern.contains("#@#")) { m_type = RuleType::Invalid; return; } // Exception if(pattern.startsWith("@@")) { m_exception = true; pattern.remove(0, 2); } // Options if(pattern.contains("$")) { QString opts = pattern.mid(pattern.indexOf("$")+1); for(QString opt : opts.split(',')) { if(opt.endsWith("script")) { if(opt.startsWith("~")) { m_whitelistOptions.setFlag(RuleOption::script, true); } else { m_blacklistOptions.setFlag(RuleOption::script, true); } } else if(opt.endsWith("image")) { if(opt.startsWith("~")) { m_whitelistOptions.setFlag(RuleOption::image, true); } else { m_blacklistOptions.setFlag(RuleOption::image, true); } } else if(opt.endsWith("stylesheet")) { if(opt.startsWith("~")) { m_whitelistOptions.setFlag(RuleOption::stylesheet, true); } else { m_blacklistOptions.setFlag(RuleOption::stylesheet, true); } } else if(opt.endsWith("object")) { if(opt.startsWith("~")) { m_whitelistOptions.setFlag(RuleOption::object, true); } else { m_blacklistOptions.setFlag(RuleOption::object, true); } } else if(opt.endsWith("object-subrequest")) { if(opt.startsWith("~")) { m_whitelistOptions.setFlag(RuleOption::objectsubrequest, true); } else { m_blacklistOptions.setFlag(RuleOption::objectsubrequest, true); } } else if(opt.endsWith("subdocument")) { if(opt.startsWith("~")) { m_whitelistOptions.setFlag(RuleOption::subdocument, true); } else { m_blacklistOptions.setFlag(RuleOption::subdocument, true); } } } pattern.remove(pattern.indexOf("$"), pattern.length()); } // Regular expression if(rule.startsWith("/") && rule.endsWith("/")) { m_type = RuleType::RegularExpressionMatch; ruleExpression.setPattern(pattern); return; } // Domain rules if(pattern.startsWith("||")) { pattern.remove(0, 2); // find the end point for the domain int end = pattern.indexOf(QRegularExpression("(?:[^\\w\\d\\_\\-\\.\\%]|$)"), 0); domainExpression.setPattern(pattern.mid(0, end)); pattern.remove(0, end+1); } else if(pattern.startsWith("|") && pattern.endsWith("|")) { pattern.remove(0, 1); pattern.chop(1); domainExpression.setPattern(pattern); } else { domainExpression.setPattern(".*"); } // Regular rule ruleExpression.setWildcardPattern(pattern); m_type = RuleType::RegularExpressionMatch; } bool BlockerRule::match(const QWebEngineUrlRequestInfo &info) { switch (m_type) { case RuleType::Invalid: break; case RuleType::RegularExpressionMatch: if(domainExpression.match(info.requestUrl().host())) { if(ruleExpression.match(info.requestUrl().toString())) { if(matchOptions(info, m_whitelistOptions)) { return false; } if(matchOptions(info, m_blacklistOptions)) { return true; } return true; } } break; } return false; } bool BlockerRule::isValid() { if(m_type == RuleType::Invalid) { return false; } else { return true; } } bool BlockerRule::isException() { return m_exception; } QString BlockerRule::toString() const { return QString("On [%1]: %2 %3").arg(domainExpression.pattern()).arg(ruleExpression.pattern()).arg(QString::number(m_blacklistOptions, 2)); } bool BlockerRule::matchOptions(const QWebEngineUrlRequestInfo &info, const RuleOptions &options) { // no options are defined if(options == 0) { return false; } bool ret = false; switch (info.resourceType()) { case QWebEngineUrlRequestInfo::ResourceTypeScript: if(options.testFlag(RuleOption::script)) { ret = true; } break; case QWebEngineUrlRequestInfo::ResourceTypeImage: if(options.testFlag(RuleOption::image)) { ret = true; } break; case QWebEngineUrlRequestInfo::ResourceTypeStylesheet: if(options.testFlag(RuleOption::stylesheet)) { ret = true; } break; case QWebEngineUrlRequestInfo::ResourceTypeObject: if(options.testFlag(RuleOption::object)) { ret = true; } break; case QWebEngineUrlRequestInfo::ResourceTypePluginResource: if(options.testFlag(RuleOption::objectsubrequest)) { ret = true; } break; case QWebEngineUrlRequestInfo::ResourceTypeSubFrame: if(options.testFlag(RuleOption::subdocument)) { ret = true; } break; default: break; } return ret; }