File indexing completed on 2024-05-12 04:57:59

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com>
0004 *
0005 * This program is free software: you can redistribute it and/or modify
0006 * it under the terms of the GNU General Public License as published by
0007 * the Free Software Foundation, either version 3 of the License, or
0008 * (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 * GNU General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU General Public License
0016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 * ============================================================ */
0018 #include "cookiejar.h"
0019 #include "mainapplication.h"
0020 #include "datapaths.h"
0021 #include "autosaver.h"
0022 #include "settings.h"
0023 #include "qztools.h"
0024 
0025 #include <QNetworkCookie>
0026 #include <QWebEngineProfile>
0027 #include <QWebEngineSettings>
0028 #include <QDateTime>
0029 
0030 //#define COOKIE_DEBUG
0031 
0032 CookieJar::CookieJar(QObject* parent)
0033     : QObject(parent)
0034     , m_client(mApp->webProfile()->cookieStore())
0035 {
0036     loadSettings();
0037     m_client->loadAllCookies();
0038 
0039     m_client->setCookieFilter(std::bind(&CookieJar::cookieFilter, this, std::placeholders::_1));
0040 
0041     connect(m_client, &QWebEngineCookieStore::cookieAdded, this, &CookieJar::slotCookieAdded);
0042     connect(m_client, &QWebEngineCookieStore::cookieRemoved, this, &CookieJar::slotCookieRemoved);
0043 }
0044 
0045 CookieJar::~CookieJar()
0046 {
0047     m_client->setCookieFilter(nullptr);
0048 }
0049 
0050 void CookieJar::loadSettings()
0051 {
0052     Settings settings;
0053     settings.beginGroup(QSL("Cookie-Settings"));
0054     m_allowCookies = settings.value(QSL("allowCookies"), true).toBool();
0055     m_filterThirdParty = settings.value(QSL("filterThirdPartyCookies"), false).toBool();
0056     m_filterTrackingCookie = settings.value(QSL("filterTrackingCookie"), false).toBool();
0057     m_whitelist = settings.value(QSL("whitelist"), QStringList()).toStringList();
0058     m_blacklist = settings.value(QSL("blacklist"), QStringList()).toStringList();
0059     settings.endGroup();
0060 }
0061 
0062 void CookieJar::setAllowCookies(bool allow)
0063 {
0064     m_allowCookies = allow;
0065 }
0066 
0067 void CookieJar::deleteCookie(const QNetworkCookie &cookie)
0068 {
0069     m_client->deleteCookie(cookie);
0070 }
0071 
0072 QVector<QNetworkCookie> CookieJar::getAllCookies() const
0073 {
0074     return m_cookies;
0075 }
0076 
0077 void CookieJar::deleteAllCookies(bool deleteAll)
0078 {
0079     if (deleteAll || m_whitelist.isEmpty()) {
0080         m_client->deleteAllCookies();
0081         return;
0082     }
0083 
0084     for (const QNetworkCookie &cookie : std::as_const(m_cookies)) {
0085         if (!listMatchesDomain(m_whitelist, cookie.domain())) {
0086             m_client->deleteCookie(cookie);
0087         }
0088     }
0089 }
0090 
0091 bool CookieJar::matchDomain(QString cookieDomain, QString siteDomain) const
0092 {
0093     // According to RFC 6265
0094 
0095     // Remove leading dot
0096     if (cookieDomain.startsWith(QLatin1Char('.'))) {
0097         cookieDomain.remove(0, 1);
0098     }
0099 
0100     if (siteDomain.startsWith(QLatin1Char('.'))) {
0101         siteDomain.remove(0, 1);
0102     }
0103 
0104     return QzTools::matchDomain(cookieDomain, siteDomain);
0105 }
0106 
0107 bool CookieJar::listMatchesDomain(const QStringList &list, const QString &cookieDomain) const
0108 {
0109     for (const QString &d : list) {
0110         if (matchDomain(d, cookieDomain)) {
0111             return true;
0112         }
0113     }
0114 
0115     return false;
0116 }
0117 
0118 void CookieJar::slotCookieAdded(const QNetworkCookie &cookie)
0119 {
0120     if (rejectCookie(QString(), cookie, cookie.domain())) {
0121         m_client->deleteCookie(cookie);
0122         return;
0123     }
0124 
0125     m_cookies.append(cookie);
0126     Q_EMIT cookieAdded(cookie);
0127 }
0128 
0129 void CookieJar::slotCookieRemoved(const QNetworkCookie &cookie)
0130 {
0131     if (m_cookies.removeOne(cookie))
0132         Q_EMIT cookieRemoved(cookie);
0133 }
0134 
0135 bool CookieJar::cookieFilter(const QWebEngineCookieStore::FilterRequest &request) const
0136 {
0137     if (!m_allowCookies) {
0138         bool result = listMatchesDomain(m_whitelist, request.origin.host());
0139         if (!result) {
0140 #ifdef COOKIE_DEBUG
0141             qDebug() << "not in whitelist" << request.origin;
0142 #endif
0143             return false;
0144         }
0145     }
0146 
0147     if (m_allowCookies) {
0148         bool result = listMatchesDomain(m_blacklist, request.origin.host());
0149         if (result) {
0150 #ifdef COOKIE_DEBUG
0151             qDebug() << "found in blacklist" << request.origin.host();
0152 #endif
0153             return false;
0154         }
0155     }
0156 
0157     if (m_filterThirdParty && request.thirdParty) {
0158 #ifdef COOKIE_DEBUG
0159         qDebug() << "thirdParty" << request.firstPartyUrl << request.origin;
0160 #endif
0161         return false;
0162     }
0163 
0164     return true;
0165 }
0166 
0167 bool CookieJar::rejectCookie(const QString &domain, const QNetworkCookie &cookie, const QString &cookieDomain) const
0168 {
0169     Q_UNUSED(domain)
0170 
0171     if (!m_allowCookies) {
0172         bool result = listMatchesDomain(m_whitelist, cookieDomain);
0173         if (!result) {
0174 #ifdef COOKIE_DEBUG
0175             qDebug() << "not in whitelist" << cookie;
0176 #endif
0177             return true;
0178         }
0179     }
0180 
0181     if (m_allowCookies) {
0182         bool result = listMatchesDomain(m_blacklist, cookieDomain);
0183         if (result) {
0184 #ifdef COOKIE_DEBUG
0185             qDebug() << "found in blacklist" << cookie;
0186 #endif
0187             return true;
0188         }
0189     }
0190 
0191 #ifdef QTWEBENGINE_DISABLED
0192     if (m_filterThirdParty) {
0193         bool result = matchDomain(cookieDomain, domain);
0194         if (!result) {
0195 #ifdef COOKIE_DEBUG
0196             qDebug() << "purged for domain mismatch" << cookie << cookieDomain << domain;
0197 #endif
0198             return true;
0199         }
0200     }
0201 #endif
0202 
0203     if (m_filterTrackingCookie && cookie.name().startsWith("__utm")) {
0204 #ifdef COOKIE_DEBUG
0205         qDebug() << "purged as tracking " << cookie;
0206 #endif
0207         return true;
0208     }
0209 
0210     return false;
0211 }