Falkon Develop
Cross-platform Qt-based web browser
gnomekeyringpasswordbackend.cpp
Go to the documentation of this file.
1/* ============================================================
2* GnomeKeyringPasswords - gnome-keyring support plugin for Falkon
3* Copyright (C) 2013-2014 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* ============================================================ */
19#include "gnomekeyringplugin.h"
20
21#include <QDateTime>
22
23extern "C" {
24#include "gnome-keyring.h"
25}
26
27// TODO QT6 - should we just start storing timestamps as 64-bit instead?
28static uint Q_DATETIME_TOTIME_T(const QDateTime &dateTime)
29{
30 if (!dateTime.isValid())
31 return uint(-1);
32 qint64 retval = dateTime.toMSecsSinceEpoch() / 1000;
33 if (quint64(retval) >= Q_UINT64_C(0xFFFFFFFF))
34 return uint(-1);
35 return uint(retval);
36}
37
38static PasswordEntry createEntry(GnomeKeyringFound* item)
39{
40 PasswordEntry entry;
41 entry.id = item->item_id;
42 entry.password = QString::fromUtf8(item->secret);
43
44 for (unsigned i = 0; i < item->attributes->len; ++i) {
45 GnomeKeyringAttribute attr = g_array_index(item->attributes, GnomeKeyringAttribute, i);
46
47 if (strcmp(attr.name, "host") == 0) {
48 entry.host = QString::fromUtf8(attr.value.string);
49 }
50 else if (strcmp(attr.name, "username") == 0) {
51 entry.username = QString::fromUtf8(attr.value.string);
52 }
53 else if (strcmp(attr.name, "data") == 0) {
54 entry.data = attr.value.string;
55 }
56 else if (strcmp(attr.name, "updated") == 0) {
57 entry.updated = attr.value.integer;
58 }
59 }
60
61 entry.data.replace(QByteArray("___PASSWORD-VALUE___"), PasswordManager::urlEncodePassword(entry.password));
62
63 return entry;
64}
65
66static GnomeKeyringAttributeList* createAttributes(const PasswordEntry &entry)
67{
68 GnomeKeyringAttributeList* attributes = gnome_keyring_attribute_list_new();
69
70 gnome_keyring_attribute_list_append_string(attributes, "application", "Falkon");
71
72 QByteArray value = entry.username.toUtf8();
73 gnome_keyring_attribute_list_append_string(attributes, "username", value.constData());
74
75 value = entry.data;
76 value.replace(PasswordManager::urlEncodePassword(entry.password), "___PASSWORD-VALUE___");
77 gnome_keyring_attribute_list_append_string(attributes, "data", value.constData());
78
79 value = entry.host.toUtf8();
80 gnome_keyring_attribute_list_append_string(attributes, "host", value.constData());
81
82 gnome_keyring_attribute_list_append_uint32(attributes, "updated", entry.updated);
83
84 return attributes;
85}
86
87static void storeEntry(PasswordEntry &entry)
88{
89 guint32 itemId;
90 GnomeKeyringAttributeList* attributes = createAttributes(entry);
91
92 QByteArray pass = entry.password.toUtf8();
93 QByteArray host = entry.host.toUtf8();
94
95 GnomeKeyringResult result = gnome_keyring_item_create_sync(GNOME_KEYRING_DEFAULT,
96 GNOME_KEYRING_ITEM_GENERIC_SECRET,
97 host.constData(),
98 attributes,
99 pass.constData(),
100 TRUE, // Update if exists
101 &itemId);
102
103 gnome_keyring_attribute_list_free(attributes);
104
105 if (result != GNOME_KEYRING_RESULT_OK) {
106 qWarning() << "GnomeKeyringPasswordBackend::addEntry Cannot add entry to keyring!";
107 }
108
109 entry.id = itemId;
110}
111
114 , m_loaded(false)
115{
116}
117
119{
120 return GnomeKeyringPlugin::tr("Gnome Keyring");
121}
122
123QVector<PasswordEntry> GnomeKeyringPasswordBackend::getEntries(const QUrl &url)
124{
125 initialize();
126
127 const QString host = PasswordManager::createHost(url);
128
129 QVector<PasswordEntry> list;
130
131 for (const PasswordEntry &entry : std::as_const(m_allEntries)) {
132 if (entry.host == host) {
133 list.append(entry);
134 }
135 }
136
137 // Sort to prefer last updated entries
138 std::sort(list.begin(), list.end());
139
140 return list;
141}
142
144{
145 initialize();
146
147 return m_allEntries;
148}
149
151{
152 initialize();
153
154 PasswordEntry stored = entry;
155 stored.updated = Q_DATETIME_TOTIME_T(QDateTime::currentDateTime());
156
157 storeEntry(stored);
158
159 m_allEntries.append(stored);
160}
161
163{
164 initialize();
165
166 // Update item attributes
167 GnomeKeyringAttributeList* attributes = createAttributes(entry);
168
169 GnomeKeyringResult result = gnome_keyring_item_set_attributes_sync(GNOME_KEYRING_DEFAULT,
170 entry.id.toUInt(),
171 attributes);
172
173 gnome_keyring_attribute_list_free(attributes);
174
175 if (result != GNOME_KEYRING_RESULT_OK) {
176 qWarning() << "GnomeKeyringPasswordBackend::updateEntry Cannot updated entry attributes in keyring!";
177 return false;
178 }
179
180 // Update secret
181 GnomeKeyringItemInfo* info;
182 result = gnome_keyring_item_get_info_full_sync(GNOME_KEYRING_DEFAULT, entry.id.toUInt(),
183 GNOME_KEYRING_ITEM_INFO_SECRET, &info);
184
185 if (result != GNOME_KEYRING_RESULT_OK) {
186 qWarning() << "GnomeKeyringPasswordBackend::updateEntry Cannot get entry info from keyring!";
187 return false;
188 }
189
190 QByteArray pass = entry.password.toUtf8();
191 gnome_keyring_item_info_set_secret(info, pass.constData());
192
193 result = gnome_keyring_item_set_info_sync(GNOME_KEYRING_DEFAULT, entry.id.toUInt(), info);
194
195 gnome_keyring_item_info_free(info);
196
197 if (result != GNOME_KEYRING_RESULT_OK) {
198 qWarning() << "GnomeKeyringPasswordBackend::updateEntry Cannot set entry info in keyring!";
199 return false;
200 }
201
202 int index = m_allEntries.indexOf(entry);
203
204 if (index > -1) {
205 m_allEntries[index] = entry;
206 }
207
208 return true;
209}
210
212{
213 initialize();
214
215 entry.updated = Q_DATETIME_TOTIME_T(QDateTime::currentDateTime());
216
217 GnomeKeyringAttributeList* attributes = createAttributes(entry);
218
219 GnomeKeyringResult result = gnome_keyring_item_set_attributes_sync(GNOME_KEYRING_DEFAULT,
220 entry.id.toUInt(),
221 attributes);
222
223 gnome_keyring_attribute_list_free(attributes);
224
225 if (result != GNOME_KEYRING_RESULT_OK) {
226 qWarning() << "GnomeKeyringPasswordBackend::updateLastUsed Cannot updated entry in keyring!";
227 return;
228 }
229
230 int index = m_allEntries.indexOf(entry);
231
232 if (index > -1) {
233 m_allEntries[index] = entry;
234 }
235}
236
238{
239 initialize();
240
241 GnomeKeyringResult result = gnome_keyring_item_delete_sync(GNOME_KEYRING_DEFAULT, entry.id.toUInt());
242
243 if (result != GNOME_KEYRING_RESULT_OK) {
244 qWarning() << "GnomeKeyringPasswordBackend::removeEntry Cannot remove entry from keyring!";
245 return;
246 }
247
248 int index = m_allEntries.indexOf(entry);
249
250 if (index > -1) {
251 m_allEntries.remove(index);
252 }
253}
254
256{
257 initialize();
258
259 for (const PasswordEntry &entry : std::as_const(m_allEntries)) {
260 removeEntry(entry);
261 }
262
263 m_allEntries.clear();
264}
265
266void GnomeKeyringPasswordBackend::initialize()
267{
268 if (m_loaded) {
269 return;
270 }
271
272 GList* found;
273 GnomeKeyringResult result = gnome_keyring_find_itemsv_sync(GNOME_KEYRING_ITEM_GENERIC_SECRET, &found,
274 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, "Falkon",
275 NULL);
276
277 if (result != GNOME_KEYRING_RESULT_OK && result != GNOME_KEYRING_RESULT_NO_MATCH) {
278 qWarning() << "GnomeKeyringPasswordBackend::initialize Cannot read items from keyring!";
279 return;
280 }
281
282 bool migrate = false;
283 if (result == GNOME_KEYRING_RESULT_NO_MATCH) {
284 result = gnome_keyring_find_itemsv_sync(GNOME_KEYRING_ITEM_GENERIC_SECRET, &found,
285 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, "QupZilla",
286 NULL);
287
288 if (result != GNOME_KEYRING_RESULT_OK && result != GNOME_KEYRING_RESULT_NO_MATCH) {
289 qWarning() << "GnomeKeyringPasswordBackend::initialize Cannot read items from keyring!";
290 return;
291 }
292
293 if (result == GNOME_KEYRING_RESULT_OK) {
294 migrate = true;
295 }
296 }
297
298 GList* tmp = found;
299
300 while (tmp) {
301 GnomeKeyringFound* item = (GnomeKeyringFound*) tmp->data;
302 m_allEntries.append(createEntry(item));
303 tmp = tmp->next;
304 }
305
306 gnome_keyring_found_list_free(found);
307
308 if (migrate) {
309 for (PasswordEntry &entry : m_allEntries) {
310 storeEntry(entry);
311 }
312 }
313
314 m_loaded = true;
315}
QVector< PasswordEntry > getAllEntries()
QVector< PasswordEntry > getEntries(const QUrl &url)
void addEntry(const PasswordEntry &entry)
bool updateEntry(const PasswordEntry &entry)
void removeEntry(const PasswordEntry &entry)
void updateLastUsed(PasswordEntry &entry)
static QString createHost(const QUrl &url)
static QByteArray urlEncodePassword(const QString &password)
int value(const QColor &c)
Definition: colors.cpp:238
i
Definition: i18n.py:23
QString password
QString host
QByteArray data
QString username
int updated
QVariant id