Kgapi

accountstorage_kwallet.cpp
1/*
2 SPDX-FileCopyrightText: 2018 Daniel Vrátil <dvratil@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include "account.h"
8#include "accountstorage_kwallet_p.h"
9#include "debug.h"
10
11#include <KWallet>
12
13#include <QDateTime>
14#include <QJsonArray>
15#include <QJsonDocument>
16#include <QJsonObject>
17
18using namespace KGAPI2;
19
20namespace
21{
22
23static const QString FolderName = QStringLiteral("LibKGAPI");
24static const QString AccountNameKey = QStringLiteral("name");
25static const QString ScopesKey = QStringLiteral("scopes");
26static const QString AccessTokenKey = QStringLiteral("accessToken");
27static const QString RefreshTokenKey = QStringLiteral("refreshToken");
28static const QString ExpiresKey = QStringLiteral("expires");
29
30}
31
32AccountStorage *KWalletStorageFactory::create() const
33{
34 return new KWalletStorage();
35}
36
37KWalletStorage::KWalletStorage()
38{
39}
40
41KWalletStorage::~KWalletStorage()
42{
43 delete mWallet;
44}
45
46void KWalletStorage::open(const std::function<void(bool)> &callback)
47{
48 const auto openedCallback = [this, callback](bool opened) {
49 mWalletOpening = false;
50 if (!opened) {
51 qCWarning(KGAPIDebug, "KWallet: failed to open");
52 mWallet->deleteLater();
53 mWallet = nullptr;
54 callback(false);
55 return;
56 }
57
58 if (mWallet->currentFolder() == FolderName) {
59 callback(true);
60 return;
61 }
62
63 if (!mWallet->hasFolder(FolderName)) {
64 if (!mWallet->createFolder(FolderName)) {
65 qCWarning(KGAPIDebug, "KWallet: failed to create a new folder");
66 callback(false);
67 return;
68 }
69 }
70 if (!mWallet->setFolder(FolderName)) {
71 qCWarning(KGAPIDebug, "KWallet: failed to change folder");
72 callback(false);
73 return;
74 }
75
76 callback(true);
77 };
78
79 if (mWallet) {
80 if (mWallet->isOpen(KWallet::Wallet::NetworkWallet())) {
81 callback(true);
82 return;
83 }
84
85 if (mWalletOpening) {
86 QObject::connect(mWallet, &KWallet::Wallet::walletOpened, mWallet, openedCallback);
87 return;
88 }
89
90 delete mWallet;
91 }
92
93 mWalletOpening = true;
94 mWallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0, KWallet::Wallet::Asynchronous);
95 if (!mWallet) {
96 qCWarning(KGAPIDebug, "KWallet: failed to open wallet (maybe it's disabled?");
97 callback(false);
98 } else {
99 QObject::connect(mWallet, &KWallet::Wallet::walletOpened, mWallet, [this]() {
100 mWalletOpening = false;
101 });
102 QObject::connect(mWallet, &KWallet::Wallet::walletOpened, mWallet, openedCallback);
103 }
104}
105
106bool KWalletStorage::opened() const
107{
108 return mWallet && mWallet->isOpen(KWallet::Wallet::NetworkWallet());
109}
110
111AccountPtr KWalletStorage::getAccount(const QString &apiKey, const QString &accountName)
112{
113 if (!opened()) {
114 qCWarning(KGAPIDebug, "Trying to get an account from a closed wallet!");
115 return {};
116 }
117
118 QMap<QString, QString> accounts;
119 mWallet->readMap(apiKey, accounts);
120 const auto accountIt = accounts.constFind(accountName);
121 if (accountIt == accounts.cend()) {
122 return {};
123 }
124
125 return parseAccount(*accountIt);
126}
127
128bool KWalletStorage::storeAccount(const QString &apiKey, const AccountPtr &account)
129{
130 if (!opened()) {
131 qCWarning(KGAPIDebug, "Trying to store an account in a closed wallet!");
132 return false;
133 }
134
135 QMap<QString, QString> accounts;
136 if (mWallet->readMap(apiKey, accounts) == 0) {
137 accounts[account->accountName()] = serializeAccount(account);
138 if (mWallet->writeMap(apiKey, accounts) != 0) {
139 qCWarning(KGAPIDebug, "KWallet: failed to write accounts map");
140 return false;
141 }
142 } else {
143 qCWarning(KGAPIDebug, "KWallet: failed to read accounts map");
144 return false;
145 }
146
147 return true;
148}
149
150void KWalletStorage::removeAccount(const QString &apiKey, const QString &accountName)
151{
152 if (!opened()) {
153 qCWarning(KGAPIDebug, "Trying to remove an account from a closed wallet!");
154 return;
155 }
156
157 QMap<QString, QString> accounts;
158 if (mWallet->readMap(apiKey, accounts) == 0) {
159 if (accounts.remove(accountName)) {
160 if (!mWallet->writeMap(apiKey, accounts)) {
161 qCWarning(KGAPIDebug, "KWallet: failed to write accounts map");
162 }
163 }
164 } else {
165 qCWarning(KGAPIDebug, "KWallet: failed to read accounts map");
166 }
167}
168
169AccountPtr KWalletStorage::parseAccount(const QString &str) const
170{
171 const auto doc = QJsonDocument::fromJson(str.toUtf8());
172 if (doc.isNull()) {
173 qCWarning(KGAPIDebug, "Failed to parse account returned from KWallet");
174 return {};
175 }
176 const auto obj = doc.object();
177 QJsonArray scopesArray = obj.value(ScopesKey).toArray();
178 QList<QUrl> scopes;
179 scopes.reserve(scopesArray.size());
180 std::transform(scopesArray.constBegin(), scopesArray.constEnd(), std::back_inserter(scopes), [](const QJsonValue &val) {
181 return QUrl::fromEncoded(val.toString().toUtf8());
182 });
183 auto acc = AccountPtr::create(obj.value(AccountNameKey).toString(), obj.value(AccessTokenKey).toString(), obj.value(RefreshTokenKey).toString(), scopes);
184 acc->setExpireDateTime(QDateTime::fromString(obj.value(ExpiresKey).toString(), Qt::ISODate));
185 return acc;
186}
187
188QString KWalletStorage::serializeAccount(const AccountPtr &account) const
189{
190 QJsonArray scopesArray;
191 const auto scopes = account->scopes();
192 std::transform(scopes.cbegin(), scopes.cend(), std::back_inserter(scopesArray), [](const QUrl &scope) {
193 return scope.toString(QUrl::FullyEncoded);
194 });
195 return QString::fromUtf8(QJsonDocument({{AccountNameKey, account->accountName()},
196 {AccessTokenKey, account->accessToken()},
197 {RefreshTokenKey, account->refreshToken()},
198 {ExpiresKey, account->expireDateTime().toString(Qt::ISODate)},
199 {ScopesKey, scopesArray}})
201}
static const QString NetworkWallet()
static Wallet * openWallet(const QString &name, WId w, OpenType ot=Synchronous)
void walletOpened(bool success)
A job to fetch a single map tile described by a StaticMapUrl.
Definition blog.h:16
QDateTime fromString(QStringView string, QStringView format, QCalendar cal)
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype size() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QByteArray toJson(JsonFormat format) const const
const_iterator cbegin() const const
const_iterator cend() const const
void reserve(qsizetype size)
const_iterator cend() const const
const_iterator constFind(const Key &key) const const
size_type remove(const Key &key)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QSharedPointer< T > create(Args &&... args)
QString fromUtf8(QByteArrayView str)
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:17:41 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.