Falkon Develop
Cross-platform Qt-based web browser
kwalletpasswordbackend.cpp
Go to the documentation of this file.
1/* ============================================================
2* KDEFrameworksIntegration - KDE support plugin for Falkon
3* Copyright (C) 2013-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* ============================================================ */
20#include "mainapplication.h"
21#include "browserwindow.h"
23
24#include <QDateTime>
25
26#include <kwallet_version.h>
27#include <KWallet>
28
29static PasswordEntry decodeEntry(const QByteArray &data)
30{
31 QDataStream stream(data);
32 PasswordEntry entry;
33 stream >> entry;
34 return entry;
35}
36
37static QMap<QString, QString> encodeEntry(const PasswordEntry &entry)
38{
39 QMap<QString, QString> data = {
40 {QSL("host"), entry.host},
41 {QSL("username"), entry.username},
42 {QSL("password"), entry.password},
43 {QSL("updated"), QString::number(entry.updated)},
44 {QSL("data"), QString::fromUtf8(entry.data)}
45 };
46 return data;
47}
48
51 , m_wallet(nullptr)
52{
53}
54
56{
57 return KDEFrameworksIntegrationPlugin::tr("KWallet");
58}
59
60QVector<PasswordEntry> KWalletPasswordBackend::getEntries(const QUrl &url)
61{
62 initialize();
63
64 const QString host = PasswordManager::createHost(url);
65
66 QVector<PasswordEntry> list;
67
68 for (const PasswordEntry &entry : std::as_const(m_allEntries)) {
69 if (entry.host == host) {
70 list.append(entry);
71 }
72 }
73
74 // Sort to prefer last updated entries
75 std::sort(list.begin(), list.end());
76
77 return list;
78}
79
81{
82 initialize();
83
84 return m_allEntries;
85}
86
87// TODO QT6 - should we just start storing timestamps as 64-bit instead?
88static uint Q_DATETIME_TOTIME_T(const QDateTime &dateTime)
89{
90 if (!dateTime.isValid())
91 return uint(-1);
92 qint64 retval = dateTime.toMSecsSinceEpoch() / 1000;
93 if (quint64(retval) >= Q_UINT64_C(0xFFFFFFFF))
94 return uint(-1);
95 return uint(retval);
96}
97
99{
100 initialize();
101
102 if (!m_wallet) {
103 showErrorNotification();
104 return;
105 }
106
107 PasswordEntry stored = entry;
108 stored.id = QSL("%1/%2").arg(entry.host, entry.username);
109 stored.updated = Q_DATETIME_TOTIME_T(QDateTime::currentDateTime());
110
111 m_wallet->writeMap(stored.id.toString(), encodeEntry(stored));
112 m_allEntries.append(stored);
113}
114
116{
117 initialize();
118
119 if (!m_wallet) {
120 showErrorNotification();
121 return false;
122 }
123
124 m_wallet->removeEntry(entry.id.toString());
125 m_wallet->writeMap(entry.id.toString(), encodeEntry(entry));
126
127 int index = m_allEntries.indexOf(entry);
128
129 if (index > -1) {
130 m_allEntries[index] = entry;
131 }
132
133 return true;
134}
135
137{
138 initialize();
139
140 if (!m_wallet) {
141 showErrorNotification();
142 return;
143 }
144
145 m_wallet->removeEntry(entry.id.toString());
146
147 entry.updated = Q_DATETIME_TOTIME_T(QDateTime::currentDateTime());
148
149 m_wallet->writeMap(entry.id.toString(), encodeEntry(entry));
150
151 int index = m_allEntries.indexOf(entry);
152
153 if (index > -1) {
154 m_allEntries[index] = entry;
155 }
156}
157
159{
160 initialize();
161
162 if (!m_wallet) {
163 showErrorNotification();
164 return;
165 }
166
167 m_wallet->removeEntry(entry.id.toString());
168
169 int index = m_allEntries.indexOf(entry);
170
171 if (index > -1) {
172 m_allEntries.remove(index);
173 }
174}
175
177{
178 initialize();
179
180 if (!m_wallet) {
181 showErrorNotification();
182 return;
183 }
184
185 m_allEntries.clear();
186
187 m_wallet->removeFolder(QSL("FalkonPasswords"));
188 m_wallet->createFolder(QSL("FalkonPasswords"));
189}
190
191void KWalletPasswordBackend::showErrorNotification()
192{
193 static bool initialized;
194
195 if (!initialized) {
196 initialized = true;
197 mApp->desktopNotifications()->showNotification(KDEFrameworksIntegrationPlugin::tr("KWallet disabled"), KDEFrameworksIntegrationPlugin::tr("Please enable KWallet to save password."));
198 }
199}
200
201void KWalletPasswordBackend::initialize()
202{
203 if (m_wallet) {
204 return;
205 }
206
207 WId wid = 0;
208 BrowserWindow *w = mApp->getWindow();
209 if (w && w->window()) {
210 wid = w->window()->winId();
211 }
212 m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), wid);
213
214 if (!m_wallet) {
215 qWarning() << "KWalletPasswordBackend::initialize Cannot open wallet!";
216 return;
217 }
218
219 bool migrationFalkon = !m_wallet->hasFolder(QSL("FalkonPasswords")) && m_wallet->hasFolder(QSL("Falkon"));
220 bool migrateQupzilla = !m_wallet->hasFolder(QSL("FalkonPasswords")) && !m_wallet->hasFolder(QSL("Falkon")) && m_wallet->hasFolder(QSL("QupZilla"));
221 bool migration = false;
222
223 if (!m_wallet->hasFolder(QSL("FalkonPasswords")) && !m_wallet->createFolder(QSL("FalkonPasswords"))) {
224 qWarning() << "KWalletPasswordBackend::initialize Cannot create folder \"FalkonPasswords\"!";
225 return;
226 }
227
228 if (migrationFalkon) {
229 if (!m_wallet->setFolder(QSL("Falkon"))) {
230 qWarning() << "KWalletPasswordBackend::initialize Cannot set folder \"Falkon\"!";
231 return;
232 }
233 migration = true;
234 }
235 else if (migrateQupzilla) {
236 if (!m_wallet->setFolder(QSL("QupZilla"))) {
237 qWarning() << "KWalletPasswordBackend::initialize Cannot set folder \"QupZilla\"!";
238 return;
239 }
240 migration = true;
241 }
242 else {
243 if (!m_wallet->setFolder(QSL("FalkonPasswords"))) {
244 qWarning() << "KWalletPasswordBackend::initialize Cannot set folder \"FalkonPasswords\"!";
245 return;
246 }
247 }
248
249 if (migration) {
250 QMap<QString, QByteArray> entries;
251 bool ok = false;
252 entries = m_wallet->entriesList(&ok);
253 if (!ok) {
254 qWarning() << "KWalletPasswordBackend::initialize Cannot read entries!";
255 return;
256 }
257
258 QMap<QString, QByteArray>::const_iterator i = entries.constBegin();
259 while (i != entries.constEnd()) {
260 PasswordEntry entry = decodeEntry(i.value());
261 if (entry.isValid()) {
262 m_allEntries.append(entry);
263 }
264 ++i;
265 }
266
267 if (!m_wallet->setFolder(QSL("FalkonPasswords"))) {
268 qWarning() << "KWalletPasswordBackend::initialize Cannot set folder \"FalkonPasswords\"!";
269 return;
270 }
271
272 for (const PasswordEntry &entry : std::as_const(m_allEntries)) {
273 m_wallet->writeMap(entry.id.toString(), encodeEntry(entry));
274 }
275 }
276 else {
277 QMap<QString, QMap<QString, QString>> entriesMap;
278 bool ok = false;
279 entriesMap = m_wallet->mapList(&ok);
280 QMap<QString, QMap<QString, QString>>::const_iterator j = entriesMap.constBegin();
281 while (j != entriesMap.constEnd()) {
282 PasswordEntry entry;
283 entry.id = j.key();
284 entry.host = j.value()[QSL("host")];
285 entry.username = j.value()[QSL("username")];
286 entry.password = j.value()[QSL("password")];
287 entry.updated = j.value()[QSL("updated")].toInt();
288 entry.data = j.value()[QSL("data")].toUtf8();
289 if (entry.isValid()) {
290 m_allEntries.append(entry);
291 }
292 ++j;
293 }
294 }
295}
296
298{
299 delete m_wallet;
300}
void removeEntry(const PasswordEntry &entry) override
void updateLastUsed(PasswordEntry &entry) override
bool updateEntry(const PasswordEntry &entry) override
void addEntry(const PasswordEntry &entry) override
QVector< PasswordEntry > getEntries(const QUrl &url) override
QString name() const override
QVector< PasswordEntry > getAllEntries() override
static QString createHost(const QUrl &url)
#define mApp
i
Definition: i18n.py:23
#define QSL(x)
Definition: qzcommon.h:40
QString password
QString host
QByteArray data
bool isValid() const
QString username
int updated
QVariant id