File indexing completed on 2024-05-19 05:00:54

0001 /*
0002     kcookiesmanagement.cpp - Cookies manager
0003 
0004     SPDX-FileCopyrightText: 2000-2001 Marco Pinelli <pinmc@orion.it>
0005     SPDX-FileCopyrightText: 2000-2001 Dawit Alemayehu <adawit@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 // Own
0011 #include "kcookiesmanagement.h"
0012 
0013 // Qt
0014 #include <QDBusConnection>
0015 #include <QDBusInterface>
0016 #include <QDBusReply>
0017 #include <QPushButton>
0018 #include <QDateTime>
0019 #include <QLocale>
0020 #include <QApplication>
0021 
0022 // KDE
0023 #include <KLocalizedString>
0024 #include <KMessageBox>
0025 
0026 // Local
0027 #include "kcookiesmain.h"
0028 #include "kcookiespolicies.h"
0029 #include "interfaces/browser.h"
0030 #include "interfaces/cookiejar.h"
0031 
0032 using namespace KonqInterfaces;
0033 
0034 QString tolerantFromAce(const QByteArray &_domain);
0035 
0036 struct CookieProp {
0037     QNetworkCookie cookie;
0038     QString host;
0039     bool allLoaded;
0040 
0041     QString expireDate() const {
0042         QDateTime expDate = cookie.expirationDate();
0043         if (expDate.isValid()) {
0044             return QLocale().toString(expDate, QLocale::ShortFormat);
0045         } else {
0046             return i18n("End of session");
0047         }
0048     }
0049 
0050     QString secure() const {
0051         return i18n(cookie.isSecure() ? "Yes" : "No");
0052     }
0053 };
0054 
0055 CookieListViewItem::CookieListViewItem(QTreeWidget *parent, const QString &dom)
0056     : QTreeWidgetItem(parent)
0057 {
0058     init(nullptr, dom);
0059 }
0060 
0061 CookieListViewItem::CookieListViewItem(QTreeWidgetItem *parent, CookieProp *cookie)
0062     : QTreeWidgetItem(parent)
0063 {
0064     init(cookie);
0065 }
0066 
0067 CookieListViewItem::~CookieListViewItem()
0068 {
0069     delete mCookie;
0070 }
0071 
0072 void CookieListViewItem::init(CookieProp *cookie, const QString &domain, bool cookieLoaded)
0073 {
0074     mCookie = cookie;
0075     mDomain = domain;
0076     mCookiesLoaded = cookieLoaded;
0077 
0078     if (mCookie) {
0079         if (mDomain.isEmpty()) {
0080             setText(0, tolerantFromAce(mCookie->host.toLatin1()));
0081         } else {
0082             setText(0, tolerantFromAce(mDomain.toLatin1()));
0083         }
0084         setText(1, mCookie->cookie.name());
0085     } else {
0086         QString siteName;
0087         if (mDomain.startsWith(QLatin1Char('.'))) {
0088             siteName = mDomain.mid(1);
0089         } else {
0090             siteName = mDomain;
0091         }
0092         setText(0, tolerantFromAce(siteName.toLatin1()));
0093     }
0094 }
0095 
0096 CookieProp *CookieListViewItem::leaveCookie()
0097 {
0098     CookieProp *ret = mCookie;
0099     mCookie = nullptr;
0100     return ret;
0101 }
0102 
0103 KCookiesManagement::KCookiesManagement(QObject *parent, const KPluginMetaData &md, const QVariantList &)
0104     : KCModule(parent, md)
0105     , mDeleteAllFlag(false)
0106     , mMainWidget(qobject_cast<QWidget*>(parent))
0107 {
0108     mUi.setupUi(widget());
0109     mUi.searchLineEdit->setTreeWidget(mUi.cookiesTreeWidget);
0110     mUi.cookiesTreeWidget->setColumnWidth(0, 150);
0111 
0112     connect(mUi.deleteButton, &QAbstractButton::clicked, this, &KCookiesManagement::deleteCurrent);
0113     connect(mUi.deleteAllButton, &QAbstractButton::clicked, this, &KCookiesManagement::deleteAll);
0114     connect(mUi.reloadButton, &QAbstractButton::clicked, this, &KCookiesManagement::reload);
0115     connect(mUi.cookiesTreeWidget, &QTreeWidget::itemExpanded, this, &KCookiesManagement::listCookiesForDomain);
0116     connect(mUi.cookiesTreeWidget, &QTreeWidget::currentItemChanged, this, &KCookiesManagement::updateForItem);
0117     connect(mUi.cookiesTreeWidget, &QTreeWidget::itemDoubleClicked, this, &KCookiesManagement::showConfigPolicyDialog);
0118     connect(mUi.configPolicyButton, &QAbstractButton::clicked, this, &KCookiesManagement::showConfigPolicyDialog);
0119 }
0120 
0121 KCookiesManagement::~KCookiesManagement()
0122 {
0123 }
0124 
0125 void KCookiesManagement::load()
0126 {
0127     defaults();
0128 }
0129 
0130 void KCookiesManagement::save()
0131 {
0132     Browser *browser = Browser::browser(qApp);
0133     CookieJar *jar = browser ? browser->cookieJar() : nullptr;
0134 
0135     // If delete all cookies was requested!
0136     if (mDeleteAllFlag) {
0137         if (jar) {
0138             jar->removeAllCookies();
0139         }
0140         mDeleteAllFlag = false; // deleted[Cookies|Domains] have been cleared yet
0141     }
0142 
0143     if (!mDeletedDomains.isEmpty()) {
0144         if (jar) {
0145             for (const QString &d :mDeletedDomains) {
0146                 jar->removeCookiesWithDomain(d);
0147             }
0148         }
0149         mDeletedDomains.clear();
0150     }
0151 
0152     // Individual cookies were deleted...
0153     if (jar) {
0154         for (auto it = mDeletedCookies.constBegin(); it != mDeletedCookies.constEnd(); ++it) {
0155             CookiePropList list = it.value();
0156             QVector<QNetworkCookie> toDelete;
0157             std::transform(list.constBegin(), list.constEnd(), std::back_inserter(toDelete), [](CookieProp* p){return p->cookie;});
0158             jar->removeCookies(toDelete);
0159         }
0160     }
0161     mDeletedCookies.clear();
0162     setNeedsSave(false);
0163 }
0164 
0165 void KCookiesManagement::defaults()
0166 {
0167     reset();
0168     reload();
0169 }
0170 
0171 void KCookiesManagement::reset(bool deleteAll)
0172 {
0173     if (!deleteAll) {
0174         mDeleteAllFlag = false;
0175     }
0176 
0177     clearCookieDetails();
0178     mDeletedDomains.clear();
0179     mDeletedCookies.clear();
0180 
0181     mUi.cookiesTreeWidget->clear();
0182     mUi.deleteButton->setEnabled(false);
0183     mUi.deleteAllButton->setEnabled(false);
0184     mUi.configPolicyButton->setEnabled(false);
0185 }
0186 
0187 void KCookiesManagement::clearCookieDetails()
0188 {
0189     mUi.nameLineEdit->clear();
0190     mUi.valueLineEdit->clear();
0191     mUi.domainLineEdit->clear();
0192     mUi.pathLineEdit->clear();
0193     mUi.expiresLineEdit->clear();
0194     mUi.secureLineEdit->clear();
0195 }
0196 
0197 QSet<QNetworkCookie> KCookiesManagement::getCookies()
0198 {
0199     Browser *browser = Browser::browser(qApp);
0200     CookieJar *jar = browser ? browser->cookieJar() : nullptr;
0201     if (!jar) {
0202         return {};
0203     }
0204     return jar->cookies();
0205 }
0206 
0207 void KCookiesManagement::reload()
0208 {
0209 
0210     if (mUi.cookiesTreeWidget->topLevelItemCount() > 0) {
0211         reset();
0212     }
0213 
0214     CookieSet cookies = getCookies();
0215     QStringList domains;
0216     std::transform(cookies.constBegin(), cookies.constEnd(), std::back_inserter(domains), [](const QNetworkCookie &c){return c.domain();});
0217 
0218     CookieListViewItem *dom;
0219     for (const QString &domain : domains) {
0220         const QString siteName = (domain.startsWith(QLatin1Char('.')) ? domain.mid(1) : domain);
0221         if (mUi.cookiesTreeWidget->findItems(siteName, Qt::MatchFixedString).isEmpty()) {
0222             dom = new CookieListViewItem(mUi.cookiesTreeWidget, domain);
0223             dom->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
0224         }
0225     }
0226 
0227     // are there any cookies?
0228     mUi.deleteAllButton->setEnabled(mUi.cookiesTreeWidget->topLevelItemCount() > 0);
0229     mUi.cookiesTreeWidget->sortItems(0, Qt::AscendingOrder);
0230     setNeedsSave(false);
0231 }
0232 
0233 Q_DECLARE_METATYPE(QList<int>)
0234 
0235 void KCookiesManagement::listCookiesForDomain(QTreeWidgetItem *item)
0236 {
0237     CookieListViewItem *cookieDom = static_cast<CookieListViewItem *>(item);
0238     if (!cookieDom || cookieDom->cookiesLoaded()) {
0239         return;
0240     }
0241 
0242     QStringList cookiesString;
0243     // Always check for cookies in both "foo.bar" and ".foo.bar" domains...
0244     const QStringList domains{cookieDom->domain(), QLatin1String(".") + cookieDom->domain()};
0245     CookieSet cookies = getCookies();
0246     QList<QNetworkCookie> filteredCookies;
0247     auto filter = [domains](const QNetworkCookie &c){return domains.contains(c.domain());};
0248     std::copy_if(cookies.constBegin(), cookies.constEnd(), std::back_inserter(filteredCookies), filter);
0249     for (const QNetworkCookie &c : filteredCookies) {
0250         CookieProp *details = new CookieProp;
0251         details->cookie.setDomain(c.domain());
0252         details->cookie.setPath(c.path());
0253         details->cookie.setName(c.name());
0254         details->host = c.domain();
0255         if (details->host.startsWith('.')) {
0256             details->host.remove(0, 1);
0257         }
0258         details->allLoaded = false;
0259         new CookieListViewItem(item, details);
0260     }
0261 
0262     if (!filteredCookies.isEmpty()) {
0263         static_cast<CookieListViewItem *>(item)->setCookiesLoaded();
0264         mUi.searchLineEdit->updateSearch();
0265     }
0266 }
0267 
0268 bool KCookiesManagement::cookieDetails(CookieProp *cookie)
0269 {
0270     CookieSet cookies = getCookies();
0271     const QStringList domains{cookie->cookie.domain(), QLatin1String(".") + cookie->cookie.domain()};
0272     auto filter = [cookie, domains](const QNetworkCookie &c){
0273         return domains.contains(c.domain()) && c.path() == cookie->cookie.path() && c.name() == cookie->cookie.name();
0274     };
0275     auto it = std::find_if(cookies.constBegin(), cookies.constEnd(), filter);
0276     if (it == cookies.constEnd()) {
0277         return false;
0278     }
0279     cookie->cookie = *it;
0280     cookie->allLoaded = true;
0281     return true;
0282 }
0283 
0284 void KCookiesManagement::updateForItem(QTreeWidgetItem *item)
0285 {
0286     if (item) {
0287         CookieListViewItem *cookieItem = static_cast<CookieListViewItem *>(item);
0288         CookieProp *cookie = cookieItem->cookie();
0289 
0290         if (cookie) {
0291             if (cookie->allLoaded || cookieDetails(cookie)) {
0292                 mUi.nameLineEdit->setText(cookie->cookie.name());
0293                 mUi.valueLineEdit->setText(cookie->cookie.value());
0294                 mUi.domainLineEdit->setText(cookie->cookie.domain());
0295                 mUi.pathLineEdit->setText(cookie->cookie.path());
0296                 mUi.expiresLineEdit->setText(cookie->expireDate());
0297                 mUi.secureLineEdit->setText(cookie->secure());
0298             }
0299 
0300             mUi.configPolicyButton->setEnabled(false);
0301         } else {
0302             clearCookieDetails();
0303             mUi.configPolicyButton->setEnabled(true);
0304         }
0305     } else {
0306         mUi.configPolicyButton->setEnabled(false);
0307     }
0308     mUi.deleteButton->setEnabled(item != nullptr);
0309 }
0310 
0311 void KCookiesManagement::showConfigPolicyDialog()
0312 {
0313     // Get current item
0314     CookieListViewItem *item = static_cast<CookieListViewItem *>(mUi.cookiesTreeWidget->currentItem());
0315     Q_ASSERT(item); // the button is disabled otherwise
0316 
0317     if (item) {
0318         KCookiesMain *mainDlg = qobject_cast<KCookiesMain *>(mMainWidget);
0319         // must be present or something is really wrong.
0320         Q_ASSERT(mainDlg);
0321 
0322         KCookiesPolicies *policyDlg = mainDlg->policyDlg();
0323         // must be present unless someone rewrote the widget in which case
0324         // this needs to be re-written as well.
0325         Q_ASSERT(policyDlg);
0326 
0327         policyDlg->setPolicy(item->domain());
0328     }
0329 }
0330 
0331 void KCookiesManagement::deleteCurrent()
0332 {
0333     QTreeWidgetItem *currentItem = mUi.cookiesTreeWidget->currentItem();
0334     Q_ASSERT(currentItem); // the button is disabled otherwise
0335     CookieListViewItem *item = static_cast<CookieListViewItem *>(currentItem);
0336     if (item->cookie()) {
0337         CookieListViewItem *parent = static_cast<CookieListViewItem *>(item->parent());
0338         CookiePropList list = mDeletedCookies.value(parent->domain());
0339         list.append(item->leaveCookie());
0340         mDeletedCookies.insert(parent->domain(), list);
0341         delete item;
0342         if (parent->childCount() == 0) {
0343             delete parent;
0344         }
0345     } else {
0346         mDeletedDomains.append(item->domain());
0347         delete item;
0348     }
0349 
0350     currentItem = mUi.cookiesTreeWidget->currentItem();
0351     if (currentItem) {
0352         mUi.cookiesTreeWidget->setCurrentItem(currentItem);
0353     } else {
0354         clearCookieDetails();
0355     }
0356 
0357     mUi.deleteAllButton->setEnabled(mUi.cookiesTreeWidget->topLevelItemCount() > 0);
0358 
0359     setNeedsSave(true);
0360 }
0361 
0362 void KCookiesManagement::deleteAll()
0363 {
0364     mDeleteAllFlag = true;
0365     reset(true);
0366     setNeedsSave(true);
0367 }