Falkon Develop
Cross-platform Qt-based web browser
cookiemanager.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 3 of the License, or
8* (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17* ============================================================ */
18#include "cookiemanager.h"
19#include "ui_cookiemanager.h"
20#include "browserwindow.h"
21#include "cookiejar.h"
22#include "mainapplication.h"
23#include "qztools.h"
24#include "settings.h"
25#include "iconprovider.h"
26#include "sqldatabase.h"
27#include "sitesettingsmanager.h"
28
29#include <QNetworkCookie>
30#include <QMessageBox>
31#include <QDateTime>
32#include <QShortcut>
33#include <QTimer>
34#include <QInputDialog>
35#include <QCloseEvent>
36
38 : QDialog(parent)
39 , ui(new Ui::CookieManager)
40{
41 setAttribute(Qt::WA_DeleteOnClose);
42
43 ui->setupUi(this);
45
46 if (isRightToLeft()) {
47 ui->cookieTree->headerItem()->setTextAlignment(0, Qt::AlignRight | Qt::AlignVCenter);
48 ui->cookieTree->headerItem()->setTextAlignment(1, Qt::AlignRight | Qt::AlignVCenter);
49 ui->cookieTree->setLayoutDirection(Qt::LeftToRight);
50 ui->whiteList->setLayoutDirection(Qt::LeftToRight);
51 ui->blackList->setLayoutDirection(Qt::LeftToRight);
52 }
53
54 // Stored Cookies
55 connect(ui->cookieTree, &QTreeWidget::currentItemChanged, this, &CookieManager::currentItemChanged);
56 connect(ui->removeAll, &QAbstractButton::clicked, this, &CookieManager::removeAll);
57 connect(ui->removeOne, &QAbstractButton::clicked, this, &CookieManager::remove);
58 connect(ui->close, &QDialogButtonBox::clicked, this, &QWidget::close);
59 connect(ui->close2, &QDialogButtonBox::clicked, this, &QWidget::close);
60 connect(ui->close3, &QDialogButtonBox::clicked, this, &QWidget::close);
61 connect(ui->search, &QLineEdit::textChanged, this, &CookieManager::filterString);
62
63 // Cookie Filtering
64 connect(ui->whiteAdd, &QAbstractButton::clicked, this, &CookieManager::addWhitelist);
65 connect(ui->whiteRemove, &QAbstractButton::clicked, this, &CookieManager::removeWhitelist);
66 connect(ui->blackAdd, SIGNAL(clicked()), this, SLOT(addBlacklist()));
67 connect(ui->blackRemove, &QAbstractButton::clicked, this, &CookieManager::removeBlacklist);
68
69 // Cookie Settings
70 Settings settings;
71 settings.beginGroup(QSL("Cookie-Settings"));
72 ui->saveCookies->setChecked(settings.value(QSL("allowCookies"), true).toBool());
73 ui->filter3rdParty->setChecked(settings.value(QSL("filterThirdPartyCookies"), false).toBool());
74 ui->filterTracking->setChecked(settings.value(QSL("filterTrackingCookie"), false).toBool());
75 ui->deleteCookiesOnClose->setChecked(settings.value(QSL("deleteCookiesOnClose"), false).toBool());
76 settings.endGroup();
77
78 ui->search->setPlaceholderText(tr("Search"));
79 ui->cookieTree->setDefaultItemShowMode(TreeWidget::ItemsCollapsed);
80 ui->cookieTree->sortItems(0, Qt::AscendingOrder);
81 ui->cookieTree->header()->setDefaultSectionSize(220);
82 ui->cookieTree->setFocus();
83
84 initWhiteAndBlacklist();
85
86 ui->whiteList->sortItems(Qt::AscendingOrder);
87 ui->blackList->sortItems(Qt::AscendingOrder);
88
89 auto* removeShortcut = new QShortcut(QKeySequence(QSL("Del")), this);
90 connect(removeShortcut, &QShortcut::activated, this, &CookieManager::deletePressed);
91
92 connect(ui->search, &QLineEdit::textChanged, this, &CookieManager::filterString);
93 connect(mApp->cookieJar(), &CookieJar::cookieAdded, this, &CookieManager::addCookie);
94 connect(mApp->cookieJar(), &CookieJar::cookieRemoved, this, &CookieManager::removeCookie);
95
96 // Load cookies
97 const auto allCookies = mApp->cookieJar()->getAllCookies();
98 for (const QNetworkCookie &cookie : allCookies) {
99 addCookie(cookie);
100 }
101
102 QzTools::setWmClass(QSL("Cookies"), this);
103}
104
105void CookieManager::initWhiteAndBlacklist()
106{
107 QSqlDatabase db = SqlDatabase::instance()->database();
108 QString sqlColumn = mApp->siteSettingsManager()->optionToSqlColumn(SiteSettingsManager::poAllowCookies);
109 QString sqlTable = mApp->siteSettingsManager()->sqlTable();
110
111 QSqlQuery query(SqlDatabase::instance()->database());
112 query.prepare(QSL("SELECT server FROM %1 WHERE %2=?").arg(sqlTable, sqlColumn));
113 query.addBindValue(SiteSettingsManager::Allow);
114 query.exec();
115
116 while (query.next()) {
117 QString server = query.value(0).toString();
118 ui->whiteList->addItem(server);
119 }
120
121 query.addBindValue(SiteSettingsManager::Deny);
122 query.exec();
123
124 while (query.next()) {
125 QString server = query.value(0).toString();
126 ui->blackList->addItem(server);
127 }
128}
129
130
131void CookieManager::removeAll()
132{
133 QMessageBox::StandardButton button = QMessageBox::warning(this, tr("Confirmation"),
134 tr("Are you sure you want to delete all cookies on your computer?"), QMessageBox::Yes | QMessageBox::No);
135 if (button != QMessageBox::Yes) {
136 return;
137 }
138
139 mApp->cookieJar()->deleteAllCookies();
140
141 m_itemHash.clear();
142 m_domainHash.clear();
143 ui->cookieTree->clear();
144}
145
146void CookieManager::remove()
147{
148 QList<QNetworkCookie> cookies;
149 auto selection = ui->cookieTree->selectedItems();
150
151 for (int i = 0; i < selection.count(); i++) {
152 QTreeWidgetItem* current = selection[i];
153
154 if (current->childCount()) {
155 for (int i = 0; i < current->childCount(); ++i) {
156 QTreeWidgetItem *item = current->child(i);
157 if (item && m_itemHash.contains(item)) {
158 cookies.append(m_itemHash.value(item));
159 }
160 }
161 } else if (m_itemHash.contains(current)) {
162 cookies.append(m_itemHash.value(current));
163 }
164 }
165
166 for (const QNetworkCookie &cookie : std::as_const(cookies)) {
167 mApp->cookieJar()->deleteCookie(cookie);
168 }
169}
170
171void CookieManager::currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* parent)
172{
173 Q_UNUSED(parent);
174 if (!current) {
175 return;
176 }
177
178 if (current->text(1).isEmpty()) {
179 ui->name->setText(tr("<cookie not selected>"));
180 ui->value->setText(tr("<cookie not selected>"));
181 ui->server->setText(tr("<cookie not selected>"));
182 ui->path->setText(tr("<cookie not selected>"));
183 ui->secure->setText(tr("<cookie not selected>"));
184 ui->expiration->setText(tr("<cookie not selected>"));
185
186 ui->removeOne->setText(tr("Remove cookies"));
187 return;
188 } else if (ui->cookieTree->selectedItems().count() > 1) {
189 ui->name->setText(tr("<multiple cookies selected>"));
190 ui->value->setText(tr("<multiple cookies selected>"));
191 ui->server->setText(tr("<multiple cookies selected>"));
192 ui->path->setText(tr("<multiple cookies selected>"));
193 ui->secure->setText(tr("<multiple cookies selected>"));
194 ui->expiration->setText(tr("<multiple cookies selected>"));
195
196 ui->removeOne->setText(tr("Remove cookies"));
197 return;
198 }
199
200 const QNetworkCookie cookie = qvariant_cast<QNetworkCookie>(current->data(0, Qt::UserRole + 10));
201
202 ui->name->setText(QString::fromUtf8(cookie.name()));
203 ui->value->setText(QString::fromUtf8(cookie.value()));
204 ui->server->setText(cookie.domain());
205 ui->path->setText(cookie.path());
206 cookie.isSecure() ? ui->secure->setText(tr("Secure only")) : ui->secure->setText(tr("All connections"));
207 cookie.isSessionCookie() ? ui->expiration->setText(tr("Session cookie")) : ui->expiration->setText(QDateTime(cookie.expirationDate()).toString(QSL("hh:mm:ss dddd d. MMMM yyyy")));
208
209 ui->removeOne->setText(tr("Remove cookie"));
210}
211
212void CookieManager::addWhitelist()
213{
214 const QString server = QInputDialog::getText(this, tr("Add to whitelist"), tr("Server:"));
215
216 if (server.isEmpty()) {
217 return;
218 }
219
220 if (!ui->blackList->findItems(server, Qt::MatchFixedString).isEmpty()) {
221 QMessageBox::information(this, tr("Already blacklisted!"), tr("The server \"%1\" is already in blacklist, please remove it first.").arg(server));
222 return;
223 }
224
225 if (ui->whiteList->findItems(server, Qt::MatchFixedString).isEmpty()) {
226 ui->whiteList->addItem(server);
227 m_listModifications[server] = SiteSettingsManager::Allow;
228 }
229}
230
231void CookieManager::removeWhitelist()
232{
233 QString server = ui->whiteList->currentItem()->text();
234 m_listModifications[server] = SiteSettingsManager::Default;
235
236 delete ui->whiteList->currentItem();
237}
238
239void CookieManager::addBlacklist()
240{
241 const QString server = QInputDialog::getText(this, tr("Add to blacklist"), tr("Server:"));
242 addBlacklist(server);
243}
244
245void CookieManager::addBlacklist(const QString &server)
246{
247 if (server.isEmpty()) {
248 return;
249 }
250
251 if (!ui->whiteList->findItems(server, Qt::MatchFixedString).isEmpty()) {
252 QMessageBox::information(this, tr("Already whitelisted!"), tr("The server \"%1\" is already in whitelist, please remove it first.").arg(server));
253 return;
254 }
255
256 if (ui->blackList->findItems(server, Qt::MatchFixedString).isEmpty()) {
257 ui->blackList->addItem(server);
258 m_listModifications[server] = SiteSettingsManager::Deny;
259 }
260}
261
262QString CookieManager::cookieDomain(const QNetworkCookie &cookie) const
263{
264 QString domain = cookie.domain();
265 if (domain.startsWith(QLatin1Char('.'))) {
266 domain.remove(0, 1);
267 }
268 return domain;
269}
270
271QTreeWidgetItem *CookieManager::cookieItem(const QNetworkCookie &cookie) const
272{
273 QHashIterator<QTreeWidgetItem*, QNetworkCookie> it(m_itemHash);
274 while (it.hasNext()) {
275 it.next();
276 if (it.value() == cookie)
277 return it.key();
278 }
279 return nullptr;
280}
281
282void CookieManager::removeBlacklist()
283{
284 QString server = ui->blackList->currentItem()->text();
285 m_listModifications[server] = SiteSettingsManager::Default;
286
287 delete ui->blackList->currentItem();
288}
289
290void CookieManager::deletePressed()
291{
292 if (ui->cookieTree->hasFocus()) {
293 remove();
294 }
295 else if (ui->whiteList->hasFocus()) {
296 removeWhitelist();
297 }
298 else if (ui->blackList->hasFocus()) {
299 removeBlacklist();
300 }
301}
302
303void CookieManager::filterString(const QString &string)
304{
305 if (string.isEmpty()) {
306 for (int i = 0; i < ui->cookieTree->topLevelItemCount(); ++i) {
307 ui->cookieTree->topLevelItem(i)->setHidden(false);
308 ui->cookieTree->topLevelItem(i)->setExpanded(ui->cookieTree->defaultItemShowMode() == TreeWidget::ItemsExpanded);
309 }
310 }
311 else {
312 for (int i = 0; i < ui->cookieTree->topLevelItemCount(); ++i) {
313 QString text = QSL(".") + ui->cookieTree->topLevelItem(i)->text(0);
314 ui->cookieTree->topLevelItem(i)->setHidden(!text.contains(string, Qt::CaseInsensitive));
315 ui->cookieTree->topLevelItem(i)->setExpanded(true);
316 }
317 }
318}
319
320void CookieManager::addCookie(const QNetworkCookie &cookie)
321{
322 QTreeWidgetItem* item;
323 const QString domain = cookieDomain(cookie);
324
325 QTreeWidgetItem* findParent = m_domainHash.value(domain);
326 if (findParent) {
327 item = new QTreeWidgetItem(findParent);
328 }
329 else {
330 auto* newParent = new QTreeWidgetItem(ui->cookieTree);
331 newParent->setText(0, domain);
332 newParent->setIcon(0, IconProvider::standardIcon(QStyle::SP_DirIcon));
333 newParent->setData(0, Qt::UserRole + 10, cookie.domain());
334 ui->cookieTree->addTopLevelItem(newParent);
335 m_domainHash[domain] = newParent;
336
337 item = new QTreeWidgetItem(newParent);
338 }
339
340 item->setText(0, QSL(".") + domain);
341 item->setText(1, QString::fromUtf8(cookie.name()));
342 item->setData(0, Qt::UserRole + 10, QVariant::fromValue(cookie));
343 ui->cookieTree->addTopLevelItem(item);
344
345 m_itemHash[item] = cookie;
346}
347
348void CookieManager::removeCookie(const QNetworkCookie &cookie)
349{
350 QTreeWidgetItem *item = cookieItem(cookie);
351 if (!item)
352 return;
353
354 m_itemHash.remove(item);
355
356 if (item->parent() && item->parent()->childCount() == 1) {
357 m_domainHash.remove(cookieDomain(cookie));
358 delete item->parent();
359 item = nullptr;
360 }
361
362 delete item;
363}
364
365void CookieManager::closeEvent(QCloseEvent* e)
366{
367 QUrl url;
368
369 for (QHash<QString, int>::iterator it = m_listModifications.begin(); it != m_listModifications.end(); ++it) {
370 url.setHost(it.key());
371 mApp->siteSettingsManager()->setOption(SiteSettingsManager::poAllowCookies, url, it.value());
372 }
373
374 Settings settings;
375 settings.beginGroup(QSL("Cookie-Settings"));
376 settings.setValue(QSL("allowCookies"), ui->saveCookies->isChecked());
377 settings.setValue(QSL("filterThirdPartyCookies"), ui->filter3rdParty->isChecked());
378 settings.setValue(QSL("filterTrackingCookie"), ui->filterTracking->isChecked());
379 settings.setValue(QSL("deleteCookiesOnClose"), ui->deleteCookiesOnClose->isChecked());
380 settings.endGroup();
381
382 mApp->cookieJar()->loadSettings();
383
384 e->accept();
385}
386
387void CookieManager::keyPressEvent(QKeyEvent* e)
388{
389 if (e->key() == Qt::Key_Escape) {
390 close();
391 }
392
393 QWidget::keyPressEvent(e);
394}
395
397{
398 delete ui;
399}
static QIcon standardIcon(QStyle::StandardPixmap icon)
static void setWmClass(const QString &name, const QWidget *widget)
Definition: qztools.cpp:874
static void centerWidgetOnScreen(QWidget *w)
Definition: qztools.cpp:116
void beginGroup(const QString &prefix)
Definition: settings.cpp:79
void endGroup()
Definition: settings.cpp:84
QVariant value(const QString &key, const QVariant &defaultValue=QVariant())
Definition: settings.cpp:74
void setValue(const QString &key, const QVariant &defaultValue=QVariant())
Definition: settings.cpp:69
static SqlDatabase * instance()
QSqlDatabase database()
@ ItemsExpanded
Definition: treewidget.h:30
@ ItemsCollapsed
Definition: treewidget.h:30
#define mApp
i
Definition: i18n.py:23
#define QSL(x)
Definition: qzcommon.h:40