/** 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)
{
m_rule = rule;
QString pattern = rule;
// Empty rule or comment
if(pattern.trimmed().isEmpty() || pattern.startsWith("!")) {
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());
}
// Domain
if(pattern.startsWith("||")) {
m_type = RuleType::DomainMatch;
m_domain = pattern.mid(2, pattern.indexOf("^")-2);
return;
}
// Regular expression
if(rule.startsWith("/") && rule.endsWith("/")) {
m_type = RuleType::RegularExpressionMatch;
ruleExpression.setPattern(pattern);
return;
}
// Regular rule
ruleExpression.setPattern(fromWildcardMatch(pattern));
m_type = RuleType::WildcardMatch;
}
bool BlockerRule::match(const QWebEngineUrlRequestInfo &info)
{
bool shouldBlock = false;
switch (m_type) {
case RuleType::Invalid:
shouldBlock = false;
break;
case DomainMatch:
if(info.requestUrl().host() == m_domain) {
if(matchOptions(info, m_whitelistOptions)) {
shouldBlock = false;
} else {
if(matchOptions(info, m_blacklistOptions)) {
shouldBlock = true;
}
}
}
break;
case RegularExpressionMatch:
case WildcardMatch:
shouldBlock = ruleExpression.match(info.requestUrl().toString()).hasMatch();
break;
}
return shouldBlock;
}
bool BlockerRule::isValid()
{
if(m_type == RuleType::Invalid) {
return false;
} else {
return true;
}
}
bool BlockerRule::isException()
{
return m_exception;
}
QString BlockerRule::toString() const
{
return m_rule;
}
QString BlockerRule::fromWildcardMatch(const QString &pattern)
{
QString parsed;
for(int i=0; i