KWallet

kwalletfreedesktopattributes.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7#include "kwalletfreedesktopattributes.h"
8
9#include "kwalletd.h"
10#include "kwalletd_debug.h"
11#include "kwalletfreedesktopcollection.h"
12#include <QDir>
13#include <QFile>
14#include <QJsonDocument>
15#include <QSaveFile>
16
17KWalletFreedesktopAttributes::KWalletFreedesktopAttributes(const QString &walletName)
18{
20 _path = writeLocation + QChar::fromLatin1('/') + KWalletD::encodeWalletName(walletName) + QStringLiteral("_attributes.json");
21
22 read();
23
24 if (!_params.contains(FDO_KEY_CREATED)) {
25 const auto currentTime = QString::number(QDateTime::currentSecsSinceEpoch());
26 _params[FDO_KEY_CREATED] = currentTime;
27 _params[FDO_KEY_MODIFIED] = currentTime;
28 }
29}
30
31void KWalletFreedesktopAttributes::read()
32{
33 QByteArray content;
34 {
35 QFile file(_path);
37 if (!file.isOpen()) {
38 qCDebug(KWALLETD_LOG) << "Can't read attributes file " << _path;
39 return;
40 }
41 content = file.readAll();
42 }
43
44 const auto jsonDoc = QJsonDocument::fromJson(content);
45 if (jsonDoc.isObject()) {
46 _params = jsonDoc.object();
47 } else {
48 qCWarning(KWALLETD_LOG) << "Can't read attributes: the root element must be an JSON-object: " << _path;
49 _params = QJsonObject();
50 }
51}
52
53void KWalletFreedesktopAttributes::write()
54{
55 if (_params.empty()) {
56 QFile::remove(_path);
57 return;
58 }
59
60 updateLastModified();
61
62 QSaveFile sf(_path);
64 qCWarning(KWALLETD_LOG) << "Can't write attributes file: " << _path;
65 return;
66 }
67 sf.setPermissions(QSaveFile::ReadUser | QSaveFile::WriteUser);
68
69 const QJsonDocument saveDoc(_params);
70
71 const QByteArray jsonBytes = saveDoc.toJson();
72 if (sf.write(jsonBytes) != jsonBytes.size()) {
73 sf.cancelWriting();
74 qCWarning(KWALLETD_LOG) << "Cannot write attributes file " << _path;
75 return;
76 }
77 if (!sf.commit()) {
78 qCWarning(KWALLETD_LOG) << "Cannot commit attributes file " << _path;
79 }
80}
81
82static QString entryLocationToStr(const EntryLocation &entryLocation)
83{
84 return entryLocation.folder + QChar::fromLatin1('/') + entryLocation.key;
85}
86
87static EntryLocation splitToEntryLocation(const QString &entryLocation)
88{
89 const int slashPos = entryLocation.indexOf(QChar::fromLatin1('/'));
90 if (slashPos == -1) {
91 qCWarning(KWALLETD_LOG) << "Entry location '" << entryLocation << "' has no slash '/'";
92 return {};
93 } else {
94 return {entryLocation.left(slashPos), entryLocation.right((entryLocation.size() - slashPos) - 1)};
95 }
96}
97
98void KWalletFreedesktopAttributes::remove(const EntryLocation &entryLocation)
99{
100 _params.remove(entryLocationToStr(entryLocation));
101 if (_params.empty()) {
102 QFile::remove(_path);
103 } else {
104 write();
105 }
106}
107
108void KWalletFreedesktopAttributes::deleteFile()
109{
110 QFile::remove(_path);
111}
112
113void KWalletFreedesktopAttributes::renameLabel(const EntryLocation &oldLocation, const EntryLocation &newLocation)
114{
115 const QString oldLoc = entryLocationToStr(oldLocation);
116
117 const auto found = _params.find(oldLoc);
118 if (found == _params.end() || !found->isObject()) {
119 qCWarning(KWALLETD_LOG) << "Can't rename label (!?)";
120 return;
121 }
122 const auto obj = found->toObject();
123 _params.erase(found);
124 _params.insert(entryLocationToStr(newLocation), obj);
125
126 write();
127}
128
129void KWalletFreedesktopAttributes::renameWallet(const QString &newName)
130{
132 const QString newPath = writeLocation + QChar::fromLatin1('/') + newName + QStringLiteral("_attributes.json");
133
134 QFile::rename(_path, newPath);
135 _path = newPath;
136}
137
138void KWalletFreedesktopAttributes::newItem(const EntryLocation &entryLocation)
139{
140 _params[entryLocationToStr(entryLocation)] = QJsonObject();
141}
142
143QList<EntryLocation> KWalletFreedesktopAttributes::matchAttributes(const StrStrMap &attributes) const
144{
146
147 for (auto i = _params.constBegin(); i != _params.constEnd(); ++i) {
148 if (!i->isObject()) {
149 continue;
150 }
151
152 bool match = true;
153 const auto itemParams = i->toObject();
154 const auto foundItemAttribs = itemParams.find(QStringLiteral("attributes"));
155 if (foundItemAttribs == itemParams.end() || !foundItemAttribs->isObject()) {
156 continue;
157 }
158 const auto itemAttribs = foundItemAttribs->toObject();
159
160 for (auto i = attributes.constBegin(); i != attributes.constEnd(); ++i) {
161 const auto foundKey = itemAttribs.find(i.key());
162 if (foundKey == itemAttribs.end() || !foundKey->isString() || foundKey->toString() != i.value()) {
163 match = false;
164 break;
165 }
166 }
167
168 if (match) {
169 items += splitToEntryLocation(i.key());
170 }
171 }
172
173 return items;
174}
175
176void KWalletFreedesktopAttributes::setAttributes(const EntryLocation &entryLocation, const StrStrMap &attributes)
177{
178 QJsonObject jsonAttrs;
179 for (auto i = attributes.constBegin(); i != attributes.constEnd(); ++i) {
180 jsonAttrs.insert(i.key(), i.value());
181 }
182
183 const QString strLocation = entryLocationToStr(entryLocation);
184
185 const auto foundParams = _params.find(strLocation);
186 QJsonObject params;
187 if (foundParams != _params.end() && foundParams->isObject()) {
188 params = foundParams->toObject();
189 } else {
190 return;
191 }
192
193 if (jsonAttrs.empty()) {
194 params.remove(QStringLiteral("attributes"));
195 } else {
196 params[QStringLiteral("attributes")] = jsonAttrs;
197 }
198
199 _params[strLocation] = params;
200
201 write();
202}
203
204StrStrMap KWalletFreedesktopAttributes::getAttributes(const EntryLocation &entryLocation) const
205{
206 const auto foundObj = _params.find(entryLocationToStr(entryLocation));
207 if (foundObj == _params.end() || !foundObj->isObject()) {
208 return StrStrMap();
209 }
210 const auto jsonParams = foundObj->toObject();
211
212 const auto foundAttrs = jsonParams.find(QStringLiteral("attributes"));
213 if (foundAttrs == jsonParams.end() || !foundAttrs->isObject()) {
214 return StrStrMap();
215 }
216 const auto jsonAttrs = foundAttrs->toObject();
217
218 StrStrMap itemAttrs;
219
220 for (auto i = jsonAttrs.constBegin(); i != jsonAttrs.constEnd(); ++i) {
221 if (i.value().isString()) {
222 itemAttrs.insert(i.key(), i.value().toString());
223 }
224 }
225
226 return itemAttrs;
227}
228
229QString KWalletFreedesktopAttributes::getStringParam(const EntryLocation &entryLocation, const QString &paramName, const QString &defaultParam) const
230{
231 const auto foundParams = _params.find(entryLocationToStr(entryLocation));
232 if (foundParams == _params.end() || !foundParams->isObject()) {
233 return defaultParam;
234 }
235 const auto params = foundParams->toObject();
236
237 const auto foundParam = params.find(paramName);
238 if (foundParam == params.end() || !foundParam->isString()) {
239 return defaultParam;
240 }
241
242 return foundParam->toString();
243}
244
245qulonglong KWalletFreedesktopAttributes::getULongLongParam(const EntryLocation &entryLocation, const QString &paramName, qulonglong defaultParam) const
246{
247 const auto str = getStringParam(entryLocation, paramName, QString::number(defaultParam));
248 bool ok = false;
249 const auto result = str.toULongLong(&ok);
250 return ok ? result : defaultParam;
251}
252
253void KWalletFreedesktopAttributes::setParam(const EntryLocation &entryLocation, const QString &paramName, const QString &param)
254{
255 const auto entryLoc = entryLocationToStr(entryLocation);
256 const auto foundParams = _params.find(entryLoc);
257 if (foundParams == _params.end() || !foundParams->isObject()) {
258 return;
259 }
260
261 auto params = foundParams->toObject();
262
263 params[paramName] = param;
264 _params[entryLoc] = params;
265
266 write();
267}
268
269void KWalletFreedesktopAttributes::setParam(const EntryLocation &entryLocation, const QString &paramName, qulonglong param)
270{
271 setParam(entryLocation, paramName, QString::number(param));
272}
273
274void KWalletFreedesktopAttributes::remove(const FdoUniqueLabel &itemUniqLabel)
275{
276 remove(itemUniqLabel.toEntryLocation());
277}
278
279void KWalletFreedesktopAttributes::setAttributes(const FdoUniqueLabel &itemUniqLabel, const StrStrMap &attributes)
280{
281 setAttributes(itemUniqLabel.toEntryLocation(), attributes);
282}
283
284StrStrMap KWalletFreedesktopAttributes::getAttributes(const FdoUniqueLabel &itemUniqLabel) const
285{
286 return getAttributes(itemUniqLabel.toEntryLocation());
287}
288
289QString KWalletFreedesktopAttributes::getStringParam(const FdoUniqueLabel &itemUniqLabel, const QString &paramName, const QString &defaultParam) const
290{
291 return getStringParam(itemUniqLabel.toEntryLocation(), paramName, defaultParam);
292}
293
294qulonglong KWalletFreedesktopAttributes::getULongLongParam(const FdoUniqueLabel &itemUniqLabel, const QString &paramName, qulonglong defaultParam) const
295{
296 return getULongLongParam(itemUniqLabel.toEntryLocation(), paramName, defaultParam);
297}
298
299void KWalletFreedesktopAttributes::setParam(const FdoUniqueLabel &itemUniqLabel, const QString &paramName, const QString &param)
300{
301 setParam(itemUniqLabel.toEntryLocation(), paramName, param);
302}
303
304void KWalletFreedesktopAttributes::setParam(const FdoUniqueLabel &itemUniqLabel, const QString &paramName, qulonglong param)
305{
306 setParam(itemUniqLabel.toEntryLocation(), paramName, param);
307}
308
309QList<EntryLocation> KWalletFreedesktopAttributes::listItems() const
310{
312 for (auto i = _params.constBegin(); i != _params.constEnd(); ++i) {
313 if (i->isObject()) {
314 items.push_back(splitToEntryLocation(i.key()));
315 }
316 }
317 return items;
318}
319
320qulonglong KWalletFreedesktopAttributes::lastModified() const
321{
322 auto found = _params.constFind(FDO_KEY_MODIFIED);
323 if (found == _params.constEnd()) {
324 return 0;
325 }
326 return found->toString().toULongLong();
327}
328
329qulonglong KWalletFreedesktopAttributes::birthTime() const
330{
331 auto found = _params.constFind(FDO_KEY_CREATED);
332 if (found == _params.constEnd()) {
333 return 0;
334 }
335 return found->toString().toULongLong();
336}
337
338void KWalletFreedesktopAttributes::updateLastModified()
339{
340 _params[FDO_KEY_MODIFIED] = QString::number(QDateTime::currentSecsSinceEpoch());
341}
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
qsizetype size() const const
QChar fromLatin1(char c)
qint64 currentSecsSinceEpoch()
bool remove()
bool rename(const QString &newName)
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
const_iterator constBegin() const const
const_iterator constEnd() const const
const_iterator constFind(QLatin1StringView key) const const
bool contains(QLatin1StringView key) const const
bool empty() const const
iterator end()
iterator erase(iterator it)
iterator find(QLatin1StringView key)
iterator insert(QLatin1StringView key, const QJsonValue &value)
void remove(QLatin1StringView key)
void push_back(parameter_type value)
const_iterator constBegin() const const
const_iterator constEnd() const const
iterator insert(const Key &key, const T &value)
QString writableLocation(StandardLocation type)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
QString left(qsizetype n) const const
QString number(double n, char format, int precision)
QString right(qsizetype n) const const
qsizetype size() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:16:05 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.