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

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2010-2018 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 "cookiemanager.h"
0019 #include "ui_cookiemanager.h"
0020 #include "browserwindow.h"
0021 #include "cookiejar.h"
0022 #include "mainapplication.h"
0023 #include "qztools.h"
0024 #include "settings.h"
0025 #include "iconprovider.h"
0026 
0027 #include <QNetworkCookie>
0028 #include <QMessageBox>
0029 #include <QDateTime>
0030 #include <QShortcut>
0031 #include <QTimer>
0032 #include <QInputDialog>
0033 #include <QCloseEvent>
0034 
0035 CookieManager::CookieManager(QWidget *parent)
0036     : QDialog(parent)
0037     , ui(new Ui::CookieManager)
0038 {
0039     setAttribute(Qt::WA_DeleteOnClose);
0040 
0041     ui->setupUi(this);
0042     QzTools::centerWidgetOnScreen(this);
0043 
0044     if (isRightToLeft()) {
0045         ui->cookieTree->headerItem()->setTextAlignment(0, Qt::AlignRight | Qt::AlignVCenter);
0046         ui->cookieTree->headerItem()->setTextAlignment(1, Qt::AlignRight | Qt::AlignVCenter);
0047         ui->cookieTree->setLayoutDirection(Qt::LeftToRight);
0048         ui->whiteList->setLayoutDirection(Qt::LeftToRight);
0049         ui->blackList->setLayoutDirection(Qt::LeftToRight);
0050     }
0051 
0052     // Stored Cookies
0053     connect(ui->cookieTree, &QTreeWidget::currentItemChanged, this, &CookieManager::currentItemChanged);
0054     connect(ui->removeAll, &QAbstractButton::clicked, this, &CookieManager::removeAll);
0055     connect(ui->removeOne, &QAbstractButton::clicked, this, &CookieManager::remove);
0056     connect(ui->close, &QDialogButtonBox::clicked, this, &QWidget::close);
0057     connect(ui->close2, &QDialogButtonBox::clicked, this, &QWidget::close);
0058     connect(ui->close3, &QDialogButtonBox::clicked, this, &QWidget::close);
0059     connect(ui->search, &QLineEdit::textChanged, this, &CookieManager::filterString);
0060 
0061     // Cookie Filtering
0062     connect(ui->whiteAdd, &QAbstractButton::clicked, this, &CookieManager::addWhitelist);
0063     connect(ui->whiteRemove, &QAbstractButton::clicked, this, &CookieManager::removeWhitelist);
0064     connect(ui->blackAdd, SIGNAL(clicked()), this, SLOT(addBlacklist()));
0065     connect(ui->blackRemove, &QAbstractButton::clicked, this, &CookieManager::removeBlacklist);
0066 
0067     // Cookie Settings
0068     Settings settings;
0069     settings.beginGroup(QSL("Cookie-Settings"));
0070     ui->saveCookies->setChecked(settings.value(QSL("allowCookies"), true).toBool());
0071     ui->filter3rdParty->setChecked(settings.value(QSL("filterThirdPartyCookies"), false).toBool());
0072     ui->filterTracking->setChecked(settings.value(QSL("filterTrackingCookie"), false).toBool());
0073     ui->deleteCookiesOnClose->setChecked(settings.value(QSL("deleteCookiesOnClose"), false).toBool());
0074     ui->whiteList->addItems(settings.value(QSL("whitelist"), QStringList()).toStringList());
0075     ui->blackList->addItems(settings.value(QSL("blacklist"), QStringList()).toStringList());
0076     settings.endGroup();
0077 
0078     ui->search->setPlaceholderText(tr("Search"));
0079     ui->cookieTree->setDefaultItemShowMode(TreeWidget::ItemsCollapsed);
0080     ui->cookieTree->sortItems(0, Qt::AscendingOrder);
0081     ui->cookieTree->header()->setDefaultSectionSize(220);
0082     ui->cookieTree->setFocus();
0083 
0084     ui->whiteList->sortItems(Qt::AscendingOrder);
0085     ui->blackList->sortItems(Qt::AscendingOrder);
0086 
0087     auto* removeShortcut = new QShortcut(QKeySequence(QSL("Del")), this);
0088     connect(removeShortcut, &QShortcut::activated, this, &CookieManager::deletePressed);
0089 
0090     connect(ui->search, &QLineEdit::textChanged, this, &CookieManager::filterString);
0091     connect(mApp->cookieJar(), &CookieJar::cookieAdded, this, &CookieManager::addCookie);
0092     connect(mApp->cookieJar(), &CookieJar::cookieRemoved, this, &CookieManager::removeCookie);
0093 
0094     // Load cookies
0095     const auto allCookies = mApp->cookieJar()->getAllCookies();
0096     for (const QNetworkCookie &cookie : allCookies) {
0097         addCookie(cookie);
0098     }
0099 
0100     QzTools::setWmClass(QSL("Cookies"), this);
0101 }
0102 
0103 void CookieManager::removeAll()
0104 {
0105     QMessageBox::StandardButton button = QMessageBox::warning(this, tr("Confirmation"),
0106                                          tr("Are you sure you want to delete all cookies on your computer?"), QMessageBox::Yes | QMessageBox::No);
0107     if (button != QMessageBox::Yes) {
0108         return;
0109     }
0110 
0111     mApp->cookieJar()->deleteAllCookies();
0112 
0113     m_itemHash.clear();
0114     m_domainHash.clear();
0115     ui->cookieTree->clear();
0116 }
0117 
0118 void CookieManager::remove()
0119 {
0120     QList<QNetworkCookie> cookies;
0121     auto selection = ui->cookieTree->selectedItems();
0122 
0123     for (int i = 0; i < selection.count(); i++) {
0124         QTreeWidgetItem* current = selection[i];
0125 
0126         if (current->childCount()) {
0127             for (int i = 0; i < current->childCount(); ++i) {
0128                 QTreeWidgetItem *item = current->child(i);
0129                 if (item && m_itemHash.contains(item)) {
0130                     cookies.append(m_itemHash.value(item));
0131                 }
0132             }
0133         } else if (m_itemHash.contains(current)) {
0134             cookies.append(m_itemHash.value(current));
0135         }
0136     }
0137 
0138     for (const QNetworkCookie &cookie : std::as_const(cookies)) {
0139         mApp->cookieJar()->deleteCookie(cookie);
0140     }
0141 }
0142 
0143 void CookieManager::currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* parent)
0144 {
0145     Q_UNUSED(parent);
0146     if (!current) {
0147         return;
0148     }
0149 
0150     if (current->text(1).isEmpty()) {
0151         ui->name->setText(tr("<cookie not selected>"));
0152         ui->value->setText(tr("<cookie not selected>"));
0153         ui->server->setText(tr("<cookie not selected>"));
0154         ui->path->setText(tr("<cookie not selected>"));
0155         ui->secure->setText(tr("<cookie not selected>"));
0156         ui->expiration->setText(tr("<cookie not selected>"));
0157 
0158         ui->removeOne->setText(tr("Remove cookies"));
0159         return;
0160     } else if (ui->cookieTree->selectedItems().count() > 1) {
0161         ui->name->setText(tr("<multiple cookies selected>"));
0162         ui->value->setText(tr("<multiple cookies selected>"));
0163         ui->server->setText(tr("<multiple cookies selected>"));
0164         ui->path->setText(tr("<multiple cookies selected>"));
0165         ui->secure->setText(tr("<multiple cookies selected>"));
0166         ui->expiration->setText(tr("<multiple cookies selected>"));
0167 
0168         ui->removeOne->setText(tr("Remove cookies"));
0169         return;
0170     }
0171 
0172     const QNetworkCookie cookie = qvariant_cast<QNetworkCookie>(current->data(0, Qt::UserRole + 10));
0173 
0174     ui->name->setText(QString::fromUtf8(cookie.name()));
0175     ui->value->setText(QString::fromUtf8(cookie.value()));
0176     ui->server->setText(cookie.domain());
0177     ui->path->setText(cookie.path());
0178     cookie.isSecure() ? ui->secure->setText(tr("Secure only")) : ui->secure->setText(tr("All connections"));
0179     cookie.isSessionCookie() ? ui->expiration->setText(tr("Session cookie")) : ui->expiration->setText(QDateTime(cookie.expirationDate()).toString(QSL("hh:mm:ss dddd d. MMMM yyyy")));
0180 
0181     ui->removeOne->setText(tr("Remove cookie"));
0182 }
0183 
0184 void CookieManager::addWhitelist()
0185 {
0186     const QString server = QInputDialog::getText(this, tr("Add to whitelist"), tr("Server:"));
0187 
0188     if (server.isEmpty()) {
0189         return;
0190     }
0191 
0192     if (!ui->blackList->findItems(server, Qt::MatchFixedString).isEmpty()) {
0193         QMessageBox::information(this, tr("Already blacklisted!"), tr("The server \"%1\" is already in blacklist, please remove it first.").arg(server));
0194         return;
0195     }
0196 
0197     if (ui->whiteList->findItems(server, Qt::MatchFixedString).isEmpty()) {
0198         ui->whiteList->addItem(server);
0199     }
0200 }
0201 
0202 void CookieManager::removeWhitelist()
0203 {
0204     delete ui->whiteList->currentItem();
0205 }
0206 
0207 void CookieManager::addBlacklist()
0208 {
0209     const QString server = QInputDialog::getText(this, tr("Add to blacklist"), tr("Server:"));
0210     addBlacklist(server);
0211 }
0212 
0213 void CookieManager::addBlacklist(const QString &server)
0214 {
0215     if (server.isEmpty()) {
0216         return;
0217     }
0218 
0219     if (!ui->whiteList->findItems(server, Qt::MatchFixedString).isEmpty()) {
0220         QMessageBox::information(this, tr("Already whitelisted!"), tr("The server \"%1\" is already in whitelist, please remove it first.").arg(server));
0221         return;
0222     }
0223 
0224     if (ui->blackList->findItems(server, Qt::MatchFixedString).isEmpty()) {
0225         ui->blackList->addItem(server);
0226     }
0227 }
0228 
0229 QString CookieManager::cookieDomain(const QNetworkCookie &cookie) const
0230 {
0231     QString domain = cookie.domain();
0232     if (domain.startsWith(QLatin1Char('.'))) {
0233         domain.remove(0, 1);
0234     }
0235     return domain;
0236 }
0237 
0238 QTreeWidgetItem *CookieManager::cookieItem(const QNetworkCookie &cookie) const
0239 {
0240     QHashIterator<QTreeWidgetItem*, QNetworkCookie> it(m_itemHash);
0241     while (it.hasNext()) {
0242         it.next();
0243         if (it.value() == cookie)
0244             return it.key();
0245     }
0246     return nullptr;
0247 }
0248 
0249 void CookieManager::removeBlacklist()
0250 {
0251     delete ui->blackList->currentItem();
0252 }
0253 
0254 void CookieManager::deletePressed()
0255 {
0256     if (ui->cookieTree->hasFocus()) {
0257         remove();
0258     }
0259     else if (ui->whiteList->hasFocus()) {
0260         removeWhitelist();
0261     }
0262     else if (ui->blackList->hasFocus()) {
0263         removeBlacklist();
0264     }
0265 }
0266 
0267 void CookieManager::filterString(const QString &string)
0268 {
0269     if (string.isEmpty()) {
0270         for (int i = 0; i < ui->cookieTree->topLevelItemCount(); ++i) {
0271             ui->cookieTree->topLevelItem(i)->setHidden(false);
0272             ui->cookieTree->topLevelItem(i)->setExpanded(ui->cookieTree->defaultItemShowMode() == TreeWidget::ItemsExpanded);
0273         }
0274     }
0275     else {
0276         for (int i = 0; i < ui->cookieTree->topLevelItemCount(); ++i) {
0277             QString text = QSL(".") + ui->cookieTree->topLevelItem(i)->text(0);
0278             ui->cookieTree->topLevelItem(i)->setHidden(!text.contains(string, Qt::CaseInsensitive));
0279             ui->cookieTree->topLevelItem(i)->setExpanded(true);
0280         }
0281     }
0282 }
0283 
0284 void CookieManager::addCookie(const QNetworkCookie &cookie)
0285 {
0286     QTreeWidgetItem* item;
0287     const QString domain = cookieDomain(cookie);
0288 
0289     QTreeWidgetItem* findParent = m_domainHash.value(domain);
0290     if (findParent) {
0291         item = new QTreeWidgetItem(findParent);
0292     }
0293     else {
0294         auto* newParent = new QTreeWidgetItem(ui->cookieTree);
0295         newParent->setText(0, domain);
0296         newParent->setIcon(0, IconProvider::standardIcon(QStyle::SP_DirIcon));
0297         newParent->setData(0, Qt::UserRole + 10, cookie.domain());
0298         ui->cookieTree->addTopLevelItem(newParent);
0299         m_domainHash[domain] = newParent;
0300 
0301         item = new QTreeWidgetItem(newParent);
0302     }
0303 
0304     item->setText(0, QSL(".") + domain);
0305     item->setText(1, QString::fromUtf8(cookie.name()));
0306     item->setData(0, Qt::UserRole + 10, QVariant::fromValue(cookie));
0307     ui->cookieTree->addTopLevelItem(item);
0308 
0309     m_itemHash[item] = cookie;
0310 }
0311 
0312 void CookieManager::removeCookie(const QNetworkCookie &cookie)
0313 {
0314     QTreeWidgetItem *item = cookieItem(cookie);
0315     if (!item)
0316         return;
0317 
0318     m_itemHash.remove(item);
0319 
0320     if (item->parent() && item->parent()->childCount() == 1) {
0321         m_domainHash.remove(cookieDomain(cookie));
0322         delete item->parent();
0323         item = nullptr;
0324     }
0325 
0326     delete item;
0327 }
0328 
0329 void CookieManager::closeEvent(QCloseEvent* e)
0330 {
0331     QStringList whitelist;
0332     QStringList blacklist;
0333 
0334     for (int i = 0; i < ui->whiteList->count(); ++i) {
0335         whitelist.append(ui->whiteList->item(i)->text());
0336     }
0337 
0338     for (int i = 0; i < ui->blackList->count(); ++i) {
0339         blacklist.append(ui->blackList->item(i)->text());
0340     }
0341 
0342     Settings settings;
0343     settings.beginGroup(QSL("Cookie-Settings"));
0344     settings.setValue(QSL("allowCookies"), ui->saveCookies->isChecked());
0345     settings.setValue(QSL("filterThirdPartyCookies"), ui->filter3rdParty->isChecked());
0346     settings.setValue(QSL("filterTrackingCookie"), ui->filterTracking->isChecked());
0347     settings.setValue(QSL("deleteCookiesOnClose"), ui->deleteCookiesOnClose->isChecked());
0348     settings.setValue(QSL("whitelist"), whitelist);
0349     settings.setValue(QSL("blacklist"), blacklist);
0350     settings.endGroup();
0351 
0352     mApp->cookieJar()->loadSettings();
0353 
0354     e->accept();
0355 }
0356 
0357 void CookieManager::keyPressEvent(QKeyEvent* e)
0358 {
0359     if (e->key() == Qt::Key_Escape) {
0360         close();
0361     }
0362 
0363     QWidget::keyPressEvent(e);
0364 }
0365 
0366 CookieManager::~CookieManager()
0367 {
0368     delete ui;
0369 }