File indexing completed on 2024-05-12 16:23:45

0001 // SPDX-FileCopyrightText: 2020 Jonah BrĂ¼chert <jbb@kaidan.im>
0002 //
0003 // SPDX-License-Identifier: GPL-2.0-or-later
0004 
0005 #include "adblockfilterlistsmanager.h"
0006 
0007 #include <QDir>
0008 #include <QFile>
0009 #include <QNetworkReply>
0010 #include <QStandardPaths>
0011 
0012 #include "angelfishsettings.h"
0013 
0014 void copyStream(QIODevice &input, QIODevice &output)
0015 {
0016     constexpr auto BUFFER_SIZE = 1024;
0017 
0018     QByteArray buffer;
0019     buffer.reserve(BUFFER_SIZE);
0020 
0021     while (true) {
0022         int64_t read = input.read(buffer.data(), BUFFER_SIZE);
0023 
0024         if (read > 0) {
0025             output.write(buffer.data(), read);
0026         } else {
0027             break;
0028         }
0029     }
0030 }
0031 
0032 const QString filterListIdFromUrl(const QString &url) {
0033     QCryptographicHash fileNameHash(QCryptographicHash::Sha256);
0034     fileNameHash.addData(url.toUtf8());
0035     return QString::fromUtf8(fileNameHash.result().toHex());
0036 }
0037 
0038 AdblockFilterListsManager::AdblockFilterListsManager(QObject *parent)
0039     : QObject(parent)
0040     , m_filterLists(loadFromConfig())
0041 {
0042     connect(&m_networkManager, &QNetworkAccessManager::finished, this, &AdblockFilterListsManager::handleListFetched);
0043     m_networkManager.setRedirectPolicy(QNetworkRequest::SameOriginRedirectPolicy);
0044 }
0045 
0046 void AdblockFilterListsManager::refreshLists()
0047 {
0048     // Delete old lists, in case the names change.
0049     // Otherwise we might not be overwriting all of them.
0050     const QDir dir(filterListPath());
0051     const auto entries = dir.entryList();
0052     for (const auto &entry : entries) {
0053         QFile::remove(dir.path() + QDir::separator() + entry);
0054     }
0055 
0056     for (const auto &list : std::as_const(m_filterLists)) {
0057         m_runningRequests++;
0058         m_networkManager.get(QNetworkRequest(list.url));
0059     }
0060 }
0061 
0062 QString AdblockFilterListsManager::filterListPath()
0063 {
0064     static const auto path = []() -> QString {
0065         QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/filterlists/");
0066         QDir(path).mkpath(QStringLiteral("."));
0067         return path;
0068     }();
0069     return path;
0070 }
0071 
0072 void AdblockFilterListsManager::handleListFetched(QNetworkReply *reply)
0073 {
0074     Q_ASSERT(reply);
0075 
0076     m_runningRequests--;
0077 
0078     if (m_runningRequests < 1) {
0079         Q_EMIT refreshFinished();
0080     }
0081 
0082     const auto id = filterListIdFromUrl(reply->url().toString());
0083 
0084     QFile file(filterListPath() + id);
0085     if (!file.open(QIODevice::WriteOnly)) {
0086         qDebug() << "Failed to open" << file.fileName() << "for writing."
0087                  << "Filter list not updated";
0088         return;
0089     }
0090 
0091     copyStream(*reply, file);
0092 }
0093 
0094 QVector<AdblockFilterListsManager::FilterList> AdblockFilterListsManager::loadFromConfig()
0095 {
0096     const auto &filterNames = AngelfishSettings::adblockFilterNames();
0097     const auto &filterUrls = AngelfishSettings::adblockFilterUrls();
0098 
0099     auto namesIt = filterNames.begin();
0100     auto urlsIt = filterUrls.begin();
0101 
0102     QVector<AdblockFilterListsManager::FilterList> out;
0103 
0104     // Otherwise list is corrupted, but we will still not crash in release mode
0105     Q_ASSERT(filterNames.size() == filterUrls.size());
0106 
0107     while (namesIt != filterNames.end() && urlsIt != filterUrls.end()) {
0108         out.push_back(FilterList{*namesIt, *urlsIt});
0109 
0110         namesIt++;
0111         urlsIt++;
0112     }
0113 
0114     return out;
0115 }
0116 
0117 void AdblockFilterListsManager::writeToConfig(const QVector<AdblockFilterListsManager::FilterList> &filters)
0118 {
0119     QStringList filterNames;
0120     QList<QUrl> filterUrls;
0121 
0122     for (const auto &filterList : filters) {
0123         filterNames.push_back(filterList.name);
0124         filterUrls.push_back(filterList.url);
0125     }
0126 
0127     AngelfishSettings::setAdblockFilterNames(filterNames);
0128     AngelfishSettings::setAdblockFilterUrls(filterUrls);
0129 }
0130 
0131 const QVector<AdblockFilterListsManager::FilterList> &AdblockFilterListsManager::filterLists() const
0132 {
0133     return m_filterLists;
0134 }
0135 
0136 void AdblockFilterListsManager::addFilterList(const QString &name, const QUrl &url)
0137 {
0138     m_filterLists.push_back(FilterList{name, url});
0139     writeToConfig(m_filterLists);
0140 }
0141 
0142 void AdblockFilterListsManager::removeFilterList(const int index)
0143 {
0144     m_filterLists.removeAt(index);
0145     writeToConfig(m_filterLists);
0146 }
0147 
0148 #include "moc_adblockfilterlistsmanager.cpp"