adblockmanager.cpp 7.97 KB
Newer Older
1
/*
Laurent Montel's avatar
Laurent Montel committed
2
   Copyright (C) 2016-2018 Montel Laurent <montel@kde.org>
Laurent Montel's avatar
Laurent Montel committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

   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 2 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; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
18 19 20
*/

#include "adblockmanager.h"
Laurent Montel's avatar
Laurent Montel committed
21
#include "adblockmatcher.h"
Laurent Montel's avatar
Load  
Laurent Montel committed
22
#include "adblocksubscription.h"
Laurent Montel's avatar
Laurent Montel committed
23 24 25
#include "adblockinterceptor_debug.h"
#include "adblockutil.h"
#include "adblockinterceptor_debug.h"
Laurent Montel's avatar
Laurent Montel committed
26
#include "globalsettings_webengineurlinterceptoradblock.h"
Laurent Montel's avatar
Laurent Montel committed
27 28 29
#include <KConfig>
#include <KConfigGroup>
#include <QDateTime>
30
#include <QDir>
Laurent Montel's avatar
Laurent Montel committed
31 32 33
#include <QSaveFile>
#include <QStandardPaths>
#include <QStandardPaths>
34
#include <QTextStream>
Laurent Montel's avatar
Laurent Montel committed
35
#include <QTimer>
36
#include <QUrl>
37 38 39

using namespace AdBlock;

Laurent Montel's avatar
Laurent Montel committed
40 41
AdblockManager *AdblockManager::self()
{
Laurent Montel's avatar
Laurent Montel committed
42 43
    static AdblockManager s_self;
    return &s_self;
Laurent Montel's avatar
Laurent Montel committed
44 45
}

46
AdblockManager::AdblockManager(QObject *parent)
Laurent Montel's avatar
Laurent Montel committed
47
    : QObject(parent)
48
{
Laurent Montel's avatar
Laurent Montel committed
49
    mAdBlockMatcher = new AdBlockMatcher(this);
Laurent Montel's avatar
Laurent Montel committed
50
    reloadConfig();
51 52 53 54
}

AdblockManager::~AdblockManager()
{
55
    qDeleteAll(mSubscriptions);
56 57 58 59
}

void AdblockManager::reloadConfig()
{
Laurent Montel's avatar
Laurent Montel committed
60
    loadSubscriptions();
Laurent Montel's avatar
Load  
Laurent Montel committed
61
    const bool enabled = AdBlock::AdBlockSettings::self()->adBlockEnabled();
Laurent Montel's avatar
Laurent Montel committed
62
    Q_EMIT enabledChanged(enabled);
63 64
}

Laurent Montel's avatar
Laurent Montel committed
65 66
void AdblockManager::loadSubscriptions()
{
67
    qDeleteAll(mSubscriptions);
Laurent Montel's avatar
Laurent Montel committed
68
    mSubscriptions.clear();
Laurent Montel's avatar
Laurent Montel committed
69 70 71 72 73 74 75 76 77 78
    const bool enabled = AdBlock::AdBlockSettings::self()->adBlockEnabled();
    if (!enabled) {
        return;
    }
    KConfig config(QStringLiteral("AdBlockadblockrc"));
    KConfigGroup general = config.group(QStringLiteral("General"));

    mDisabledRules = general.readEntry(QStringLiteral("disabledRules"), QStringList());
    //Clear subscription
    QDir adblockDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/adblock"));
79
    // Create if necessary
Laurent Montel's avatar
Laurent Montel committed
80
    if (!adblockDir.exists()) {
Laurent Montel's avatar
Laurent Montel committed
81
        QDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)).mkdir(QStringLiteral("adblock"));
Laurent Montel's avatar
Laurent Montel committed
82 83
    }

Laurent Montel's avatar
Laurent Montel committed
84
    for (const QString &fileName : adblockDir.entryList(QStringList() << QLatin1String("*.txt"), QDir::Files)) {
Laurent Montel's avatar
Laurent Montel committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
        if (fileName == QLatin1String("customlist.txt")) {
            continue;
        }

        const QString absolutePath = adblockDir.absoluteFilePath(fileName);
        QFile file(absolutePath);
        if (!file.open(QFile::ReadOnly)) {
            continue;
        }

        QTextStream textStream(&file);
        textStream.setCodec("UTF-8");
        QString title = textStream.readLine(1024).remove(QLatin1String("Title: "));
        QUrl url = QUrl(textStream.readLine(1024).remove(QLatin1String("Url: ")));

        if (title.isEmpty() || !url.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
101
            qCWarning(ADBLOCKINTERCEPTOR_LOG) << "AdBlockManager: Invalid subscription file" << absolutePath;
Laurent Montel's avatar
Laurent Montel committed
102 103 104 105 106 107 108 109 110
            continue;
        }

        AdBlockSubscription *subscription = new AdBlockSubscription(title, this);
        subscription->setUrl(url);
        subscription->setFilePath(absolutePath);

        mSubscriptions.append(subscription);
    }
Laurent Montel's avatar
Load  
Laurent Montel committed
111

Laurent Montel's avatar
Laurent Montel committed
112 113
    mCustomList = new AdBlockCustomList(this);
    mSubscriptions.append(mCustomList);
Laurent Montel's avatar
Load  
Laurent Montel committed
114
    // Load all subscriptions
Laurent Montel's avatar
Laurent Montel committed
115 116 117 118 119 120 121 122 123
    foreach (AdBlockSubscription *subscription, mSubscriptions) {
        subscription->loadSubscription(mDisabledRules);
        connect(subscription, &AdBlockSubscription::subscriptionChanged, this, &AdblockManager::updateMatcher);
    }
    if (!mSubscriptions.isEmpty()) {
        const QDateTime lastUpdate = general.readEntry(QStringLiteral("lastUpdate"), QDateTime());
        if (lastUpdate.addDays(AdBlock::AdBlockSettings::self()->adBlockUpdateInterval()) < QDateTime::currentDateTime()) {
            QTimer::singleShot(1000 * 60, this, &AdblockManager::updateAllSubscriptions);
        }
Laurent Montel's avatar
Load  
Laurent Montel committed
124
    }
125 126
}

Laurent Montel's avatar
Laurent Montel committed
127 128
void AdblockManager::save()
{
Laurent Montel's avatar
Laurent Montel committed
129 130 131
    KConfig config(QStringLiteral("AdBlockadblockrc"));
    KConfigGroup general = config.group(QStringLiteral("General"));
    general.writeEntry(QStringLiteral("disabledRules"), mDisabledRules);
Laurent Montel's avatar
Laurent Montel committed
132
    foreach (AdBlockSubscription *subscription, mSubscriptions) {
Laurent Montel's avatar
Laurent Montel committed
133 134 135 136
        subscription->saveSubscription();
    }
}

Laurent Montel's avatar
Laurent Montel committed
137 138 139 140 141
QStringList AdblockManager::disabledRules() const
{
    return mDisabledRules;
}

142 143
void AdblockManager::removeDisabledRule(const QString &filter)
{
Laurent Montel's avatar
Laurent Montel committed
144
    mDisabledRules.removeOne(filter);
145 146 147 148
}

void AdblockManager::addDisabledRule(const QString &filter)
{
Laurent Montel's avatar
Laurent Montel committed
149
    mDisabledRules.append(filter);
Laurent Montel's avatar
Laurent Montel committed
150 151
}

152 153
bool AdblockManager::isEnabled() const
{
Laurent Montel's avatar
Laurent Montel committed
154
    return mAdBlockMatcher->isEnabled();
155 156
}

Laurent Montel's avatar
Fix api  
Laurent Montel committed
157
bool AdblockManager::interceptRequest(const QWebEngineUrlRequestInfo &info)
158
{
Laurent Montel's avatar
Laurent Montel committed
159
    bool result = false;
Laurent Montel's avatar
Fix api  
Laurent Montel committed
160
    QUrl url = info.requestUrl();
161 162 163 164
    const QString urlString = url.toString().toLower();
    const QString host = url.host().toLower();
    const QString scheme = url.scheme().toLower();

Laurent Montel's avatar
Laurent Montel committed
165
    if (!canRunOnScheme(scheme)) {
Laurent Montel's avatar
Laurent Montel committed
166
        return result;
Laurent Montel's avatar
Laurent Montel committed
167 168
    }

Laurent Montel's avatar
Laurent Montel committed
169
    qCDebug(ADBLOCKINTERCEPTOR_LOG) << " urlString" << urlString;
Laurent Montel's avatar
Laurent Montel committed
170
    const AdBlockRule *blockedRule = mAdBlockMatcher->match(info, host, urlString);
Laurent Montel's avatar
Laurent Montel committed
171 172
    if (blockedRule) {
        result = true;
Laurent Montel's avatar
Laurent Montel committed
173
        qCDebug(ADBLOCKINTERCEPTOR_LOG) << " blocked !!!!!!!!!!!!" << blockedRule->filter();
Laurent Montel's avatar
Laurent Montel committed
174 175 176
        //TODO
    }
    return result;
177
}
Laurent Montel's avatar
Laurent Montel committed
178 179 180

bool AdblockManager::canRunOnScheme(const QString &scheme) const
{
Laurent Montel's avatar
Laurent Montel committed
181
    return scheme != QLatin1String("file");
Laurent Montel's avatar
Laurent Montel committed
182
}
Laurent Montel's avatar
Laurent Montel committed
183 184 185 186 187

QList<AdBlockSubscription *> AdblockManager::subscriptions() const
{
    return mSubscriptions;
}
Laurent Montel's avatar
Laurent Montel committed
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256

void AdblockManager::updateAllSubscriptions()
{
    foreach (AdBlockSubscription *subscription, mSubscriptions) {
        subscription->updateSubscription();
    }

    KConfig config(QStringLiteral("AdBlockadblockrc"));
    KConfigGroup general = config.group(QStringLiteral("General"));
    general.writeEntry(QStringLiteral("lastUpdate"), QDateTime::currentDateTime());
}

AdBlockSubscription *AdblockManager::addSubscription(const QString &title, const QString &url)
{
    if (title.isEmpty() || url.isEmpty()) {
        return nullptr;
    }

    QString fileName = AdBlock::AdblockUtil::filterCharsFromFilename(title.toLower()) + QStringLiteral(".txt");
    QString filePath = AdBlock::AdblockUtil::ensureUniqueFilename(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/adblock/") + fileName);

    QByteArray data = QStringLiteral("Title: %1\nUrl: %2\n[Adblock Plus 1.1.1]").arg(title, url).toLatin1();

    QSaveFile file(filePath);
    if (!file.open(QFile::WriteOnly)) {
        qCWarning(ADBLOCKINTERCEPTOR_LOG) << "AdBlockManager: Cannot write to file" << filePath;
        return nullptr;
    }
    file.write(data);
    file.commit();

    AdBlockSubscription *subscription = new AdBlockSubscription(title, this);
    subscription->setUrl(QUrl(url));
    subscription->setFilePath(filePath);
    subscription->loadSubscription(mDisabledRules);

    mSubscriptions.append(subscription);
    connect(subscription, &AdBlockSubscription::subscriptionChanged, this, &AdblockManager::updateMatcher);

    return subscription;
}

void AdblockManager::updateMatcher()
{
    mAdBlockMatcher->update();
}

bool AdblockManager::removeSubscription(AdBlockSubscription *subscription)
{
    if (!mSubscriptions.contains(subscription) || !subscription->canBeRemoved()) {
        return false;
    }

    QFile(subscription->filePath()).remove();
    mSubscriptions.removeOne(subscription);

    mAdBlockMatcher->update();
    delete subscription;

    return true;
}

void AdblockManager::addCustomRule(const QString &filter)
{
    AdBlockRule *rule = new AdBlockRule(filter, mCustomList);
    mCustomList->addRule(rule);
    mCustomList->saveSubscription();
    updateMatcher();
}