KWallet

kwallet.cpp
1 /*
2  This file is part of the KDE project
3 
4  SPDX-FileCopyrightText: 2002-2004 George Staikos <[email protected]>
5  SPDX-FileCopyrightText: 2008 Michael Leupold <[email protected]>
6  SPDX-FileCopyrightText: 2011 Valentin Rusu <[email protected]>
7 
8  SPDX-License-Identifier: LGPL-2.0-or-later
9 */
10 
11 #include "kwallet.h"
12 #include "kwallet_api_debug.h"
13 #include <config-kwallet.h>
14 
15 #include <QApplication>
16 #include <QDBusConnection>
17 #include <QRegularExpression>
18 
19 #include <KConfigGroup>
20 #include <KSharedConfig>
21 #include <kwindowsystem.h>
22 
23 #if HAVE_KSECRETSSERVICE
24 #include "ksecretsservice/ksecretsservicecollection.h"
25 #endif
26 
27 #include "kwallet_interface.h"
28 
29 #if HAVE_KSECRETSSERVICE
31 Q_DECLARE_METATYPE(StringToStringStringMapMap)
32 #endif
34 Q_DECLARE_METATYPE(StringByteArrayMap)
35 
36 namespace KWallet
37 {
38 class KWalletDLauncher
39 {
40 public:
41  KWalletDLauncher();
42  ~KWalletDLauncher();
43  KWalletDLauncher(const KWalletDLauncher &) = delete;
44  KWalletDLauncher &operator=(const KWalletDLauncher &) = delete;
45  org::kde::KWallet &getInterface();
46 
47  // this static variable is used below to switch between old KWallet
48  // infrastructure and the new one which is built on top of the new
49  // KSecretsService infrastructure. It's value can be changed via the
50  // the Wallet configuration module in System Settings
51  bool m_useKSecretsService;
52  org::kde::KWallet *m_wallet_deamon;
53  KConfigGroup m_cgroup;
54  bool m_walletEnabled;
55 };
56 
57 Q_GLOBAL_STATIC(KWalletDLauncher, walletLauncher)
58 
59 static QString appid()
60 {
61  return qApp->applicationName();
62 }
63 
64 static void registerTypes()
65 {
66  static bool registered = false;
67  if (!registered) {
68 #if HAVE_KSECRETSSERVICE
69  qDBusRegisterMetaType<KSecretsService::StringStringMap>();
70  qDBusRegisterMetaType<StringToStringStringMapMap>();
71 #endif
72  qDBusRegisterMetaType<StringByteArrayMap>();
73  registered = true;
74  }
75 }
76 
77 bool Wallet::isUsingKSecretsService()
78 {
79  return walletLauncher()->m_useKSecretsService;
80 }
81 
82 const QString Wallet::LocalWallet()
83 {
84  // NOTE: This method stays unchanged for KSecretsService
85  KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("kwalletrc"))->group("Wallet"));
86  if (!cfg.readEntry("Use One Wallet", true)) {
87  QString tmp = cfg.readEntry("Local Wallet", "localwallet");
88  if (tmp.isEmpty()) {
89  return QStringLiteral("localwallet");
90  }
91  return tmp;
92  }
93 
94  QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
95  if (tmp.isEmpty()) {
96  return QStringLiteral("kdewallet");
97  }
98  return tmp;
99 }
100 
101 const QString Wallet::NetworkWallet()
102 {
103  // NOTE: This method stays unchanged for KSecretsService
104  KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("kwalletrc"))->group("Wallet"));
105 
106  QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
107  if (tmp.isEmpty()) {
108  return QStringLiteral("kdewallet");
109  }
110  return tmp;
111 }
112 
113 const QString Wallet::PasswordFolder()
114 {
115  return QStringLiteral("Passwords");
116 }
117 
118 const QString Wallet::FormDataFolder()
119 {
120  return QStringLiteral("Form Data");
121 }
122 
123 class Q_DECL_HIDDEN Wallet::WalletPrivate
124 {
125 public:
126  WalletPrivate(Wallet *wallet, int h, const QString &n)
127  : q(wallet)
128  , name(n)
129  , handle(h)
130 #if HAVE_KSECRETSSERVICE
131  , secretsCollection(0)
132 #endif
133  {
134  }
135 
136  void walletServiceUnregistered();
137 
138 #if HAVE_KSECRETSSERVICE
139  template<typename T>
140  int writeEntry(const QString &key, const T &value, Wallet::EntryType entryType)
141  {
142  int rc = -1;
143  KSecretsService::Secret secret;
144  secret.setValue(QVariant::fromValue<T>(value));
145 
146  KSecretsService::StringStringMap attrs;
147  attrs[KSS_ATTR_ENTRYFOLDER] = folder;
148  attrs[KSS_ATTR_WALLETTYPE] = QString("%1").arg((int)entryType);
149  KSecretsService::CreateCollectionItemJob *createItemJob = secretsCollection->createItem(key, attrs, secret);
150 
151  if (!createItemJob->exec()) {
152  qCDebug(KWALLET_API_LOG) << "Cannot execute CreateCollectionItemJob : " << createItemJob->errorString();
153  }
154  rc = createItemJob->error();
155  return rc;
156  }
157 
159  template<typename T>
160  int readEntry(const QString &key, T &value) const;
161  bool readSecret(const QString &key, KSecretsService::Secret &value) const;
162 
163 #if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
164  template<typename V>
165  int forEachItemThatMatches(const QString &key, V verb)
166  {
167  int rc = -1;
168  KSecretsService::StringStringMap attrs;
169  attrs[KSS_ATTR_ENTRYFOLDER] = folder;
170  KSecretsService::SearchCollectionItemsJob *searchItemsJob = secretsCollection->searchItems(attrs);
171  // TODO: Make this, and similar jobs, async
172  if (searchItemsJob->exec()) {
173  // HACK: QRegularExpression::wildcardToRegularExpression() mainly handles file pattern
174  // globbing (e.g. "*.txt") which means it doesn't allow "/" in the file name (which is
175  // technically correct); we have to subvert it because the keys in kwallet are in the
176  // form e.g. "foo.com/<User name>" which does have a "/" in it
178  const QRegularExpression re(pattern);
179  const auto list = searchItemsJob->items();
180  for (KSecretsService::SearchCollectionItemsJob::Item item : list) {
181  KSecretsService::ReadItemPropertyJob *readLabelJob = item->label();
182  if (readLabelJob->exec()) {
183  QString label = readLabelJob->propertyValue().toString();
184  if (re.match(label).hasMatch()) {
185  if (verb(this, label, item.data())) {
186  rc = 0; // one successful iteration already produced results, so success return
187  }
188  }
189  } else {
190  qCDebug(KWALLET_API_LOG) << "Cannot execute ReadItemPropertyJob " << readLabelJob->errorString();
191  }
192  }
193  } else {
194  qCDebug(KWALLET_API_LOG) << "Cannot execute KSecretsService::SearchCollectionItemsJob " << searchItemsJob->errorString();
195  }
196  return rc;
197  }
198 #endif
199 
200  template<typename V>
201  int checkItems(V verb)
202  {
203  int rc = -1;
204  KSecretsService::StringStringMap attrs;
205  attrs[KSS_ATTR_ENTRYFOLDER] = folder;
206  KSecretsService::SearchCollectionItemsJob *searchItemsJob = secretsCollection->searchItems(attrs);
207  if (searchItemsJob->exec()) {
208  const auto list = searchItemsJob->items();
209  for (KSecretsService::SearchCollectionItemsJob::Item item : list) {
210  KSecretsService::ReadItemPropertyJob *readLabelJob = item->label();
211  if (readLabelJob->exec()) {
212  const QString label = readLabelJob->propertyValue().toString();
213  if (verb(this, label, item.data())) {
214  rc = 0; // one successful iteration already produced results, so success return
215  }
216  } else {
217  qCDebug(KWALLET_API_LOG) << "Cannot execute ReadItemPropertyJob " << readLabelJob->errorString();
218  }
219  }
220  } else {
221  qCDebug(KWALLET_API_LOG) << "Cannot execute KSecretsService::SearchCollectionItemsJob " << searchItemsJob->errorString();
222  }
223  return rc;
224  }
225 
226  void createDefaultFolders();
227 
228  struct InsertIntoEntryList;
229  struct InsertIntoMapList;
230  struct InsertIntoPasswordList;
231 
232  KSecretsService::Collection *secretsCollection;
233 #endif // HAVE_KSECRETSSERVICE
234 
235  Wallet *q;
236  QString name;
237  QString folder;
238  int handle;
239  int transactionId;
240 };
241 
242 #if HAVE_KSECRETSSERVICE
243 void Wallet::WalletPrivate::createDefaultFolders()
244 {
245  // NOTE: KWalletManager expects newly created wallets to have two default folders
246  // b->createFolder(KWallet::Wallet::PasswordFolder());
247  // b->createFolder(KWallet::Wallet::FormDataFolder());
248  QString strDummy("");
249  folder = PasswordFolder();
250  writeEntry(PasswordFolder(), strDummy, KWallet::Wallet::Unknown);
251 
252  folder = FormDataFolder();
253  writeEntry(FormDataFolder(), strDummy, KWallet::Wallet::Unknown);
254 }
255 #endif // HAVE_KSECRETSSERVICE
256 
257 static const char s_kwalletdServiceName[] = "org.kde.kwalletd5";
258 
259 Wallet::Wallet(int handle, const QString &name)
260  : QObject(nullptr)
261  , d(new WalletPrivate(this, handle, name))
262 {
263  if (walletLauncher()->m_useKSecretsService) {
264  // see openWallet for initialization code; this constructor does not have any code
265  } else {
266  QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QString::fromLatin1(s_kwalletdServiceName),
269  this);
270  connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, [this]() {
271  d->walletServiceUnregistered();
272  });
273 
274  connect(&walletLauncher()->getInterface(), &org::kde::KWallet::walletClosedId, this, &KWallet::Wallet::slotWalletClosed);
275  connect(&walletLauncher()->getInterface(), &org::kde::KWallet::folderListUpdated, this, &KWallet::Wallet::slotFolderListUpdated);
276  connect(&walletLauncher()->getInterface(), &org::kde::KWallet::folderUpdated, this, &KWallet::Wallet::slotFolderUpdated);
277  connect(&walletLauncher()->getInterface(), &org::kde::KWallet::applicationDisconnected, this, &KWallet::Wallet::slotApplicationDisconnected);
278 
279  // Verify that the wallet is still open
280  if (d->handle != -1) {
281  QDBusReply<bool> r = walletLauncher()->getInterface().isOpen(d->handle);
282  if (r.isValid() && !r) {
283  d->handle = -1;
284  d->name.clear();
285  }
286  }
287  }
288 }
289 
291 {
292 #if HAVE_KSECRETSSERVICE
293  if (walletLauncher()->m_useKSecretsService) {
294  d->folder.clear();
295  d->name.clear();
296  delete d->secretsCollection;
297  } else {
298 #endif
299  if (d->handle != -1) {
300  if (!walletLauncher.isDestroyed()) {
301  walletLauncher()->getInterface().close(d->handle, false, appid());
302  } else {
303  qCDebug(KWALLET_API_LOG) << "Problem with static destruction sequence."
304  "Destroy any static Wallet before the event-loop exits.";
305  }
306  d->handle = -1;
307  d->folder.clear();
308  d->name.clear();
309  }
310 #if HAVE_KSECRETSSERVICE
311  }
312 #endif
313  delete d;
314 }
315 
317 {
318  QStringList result;
319 #if HAVE_KSECRETSSERVICE
320  if (walletLauncher()->m_useKSecretsService) {
321  KSecretsService::ListCollectionsJob *listJob = KSecretsService::Collection::listCollections();
322  if (listJob->exec()) {
323  result = listJob->collections();
324  } else {
325  qCDebug(KWALLET_API_LOG) << "Cannot execute ListCollectionsJob: " << listJob->errorString();
326  }
327  } else {
328 #endif
329  if (walletLauncher()->m_walletEnabled) {
330  QDBusReply<QStringList> r = walletLauncher()->getInterface().wallets();
331 
332  if (!r.isValid()) {
333  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
334  } else {
335  result = r;
336  }
337  }
338 #if HAVE_KSECRETSSERVICE
339  }
340 #endif
341  return result;
342 }
343 
344 void Wallet::changePassword(const QString &name, WId w)
345 {
346  if (w == 0) {
347  qCDebug(KWALLET_API_LOG) << "Pass a valid window to KWallet::Wallet::changePassword().";
348  }
349 
350  // Make sure the password prompt window will be visible and activated
352 #if HAVE_KSECRETSSERVICE
353  if (walletLauncher()->m_useKSecretsService) {
354  KSecretsService::Collection *coll = KSecretsService::Collection::findCollection(name);
355  KSecretsService::ChangeCollectionPasswordJob *changePwdJob = coll->changePassword();
356  if (!changePwdJob->exec()) {
357  qCDebug(KWALLET_API_LOG) << "Cannot execute change password job: " << changePwdJob->errorString();
358  }
359  coll->deleteLater();
360  } else {
361 #endif
362  if (walletLauncher()->m_walletEnabled) {
363  walletLauncher()->getInterface().changePassword(name, (qlonglong)w, appid());
364  }
365 #if HAVE_KSECRETSSERVICE
366  }
367 #endif
368 }
369 
371 {
372 #if HAVE_KSECRETSSERVICE
373  if (walletLauncher()->m_useKSecretsService) {
374  return walletLauncher()->m_cgroup.readEntry("Enabled", true);
375  } else {
376 #endif
377  return walletLauncher()->m_walletEnabled;
378 #if HAVE_KSECRETSSERVICE
379  }
380 #endif
381 }
382 
383 bool Wallet::isOpen(const QString &name)
384 {
385 #if HAVE_KSECRETSSERVICE
386  if (walletLauncher()->m_useKSecretsService) {
387  KSecretsService::Collection *coll = KSecretsService::Collection::findCollection(name, KSecretsService::Collection::OpenOnly);
388  KSecretsService::ReadCollectionPropertyJob *readLocked = coll->isLocked();
389  if (readLocked->exec()) {
390  return !readLocked->propertyValue().toBool();
391  } else {
392  qCDebug(KWALLET_API_LOG) << "ReadLocked job failed";
393  return false;
394  }
395  } else {
396 #endif
397  if (walletLauncher()->m_walletEnabled) {
398  QDBusReply<bool> r = walletLauncher()->getInterface().isOpen(name);
399 
400  if (!r.isValid()) {
401  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
402  return false;
403  } else {
404  return r;
405  }
406  } else {
407  return false;
408  }
409 #if HAVE_KSECRETSSERVICE
410  }
411 #endif
412 }
413 
414 int Wallet::closeWallet(const QString &name, bool force)
415 {
416 #if HAVE_KSECRETSSERVICE
417  if (walletLauncher()->m_useKSecretsService) {
418  qCDebug(KWALLET_API_LOG) << "Wallet::closeWallet NOOP";
419  return 0;
420  } else {
421 #endif
422  if (walletLauncher()->m_walletEnabled) {
423  QDBusReply<int> r = walletLauncher()->getInterface().close(name, force);
424 
425  if (!r.isValid()) {
426  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
427  return -1;
428  } else {
429  return r;
430  }
431  } else {
432  return -1;
433  }
434 #if HAVE_KSECRETSSERVICE
435  }
436 #endif
437 }
438 
440 {
441 #if HAVE_KSECRETSSERVICE
442  if (walletLauncher()->m_useKSecretsService) {
443  KSecretsService::Collection *coll = KSecretsService::Collection::findCollection(name, KSecretsService::Collection::OpenOnly);
444  KJob *deleteJob = coll->deleteCollection();
445  if (!deleteJob->exec()) {
446  qCDebug(KWALLET_API_LOG) << "Cannot execute delete job " << deleteJob->errorString();
447  }
448  return deleteJob->error();
449  } else {
450 #endif
451  if (walletLauncher->m_walletEnabled) {
452  QDBusReply<int> r = walletLauncher()->getInterface().deleteWallet(name);
453 
454  if (!r.isValid()) {
455  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
456  return -1;
457  } else {
458  return r;
459  }
460  } else {
461  return -1;
462  }
463 #if HAVE_KSECRETSSERVICE
464  }
465 #endif
466 }
467 
468 Wallet *Wallet::openWallet(const QString &name, WId w, OpenType ot)
469 {
470  if (w == 0) {
471  qCDebug(KWALLET_API_LOG) << "Pass a valid window to KWallet::Wallet::openWallet().";
472  }
473 
474  if (!walletLauncher()->m_walletEnabled) {
475  qCDebug(KWALLET_API_LOG) << "User disabled the wallet system so returning 0 here.";
476  return nullptr;
477  }
478 
479 #if HAVE_KSECRETSSERVICE
480  if (walletLauncher()->m_useKSecretsService) {
481  Wallet *wallet = new Wallet(-1, name);
482  // FIXME: should we specify CreateCollection or OpenOnly here?
483  wallet->d->secretsCollection = KSecretsService::Collection::findCollection(name, KSecretsService::Collection::CreateCollection, QVariantMap(), w);
484  connect(wallet->d->secretsCollection, SIGNAL(statusChanged(int)), wallet, SLOT(slotCollectionStatusChanged(int)));
485  connect(wallet->d->secretsCollection, SIGNAL(deleted()), wallet, SLOT(slotCollectionDeleted()));
486  if (ot == Synchronous) {
487  qCDebug(KWALLET_API_LOG) << "WARNING openWallet OpenType=Synchronous requested";
488  // TODO: not sure what to do with in this case; however, all other KSecretsService API methods are already
489  // async and will perform sync inside this API because of it's design
490  }
491  return wallet;
492  } else {
493 #endif
494  Wallet *wallet = new Wallet(-1, name);
495 
496  // connect the daemon's opened signal to the slot filtering the
497  // signals we need
498  connect(&walletLauncher()->getInterface(), &org::kde::KWallet::walletAsyncOpened, wallet, &KWallet::Wallet::walletAsyncOpened);
499 
500  // Make sure the password prompt window will be visible and activated
502 
503  org::kde::KWallet &interface = walletLauncher->getInterface();
504 
505  // do the call
506  QDBusReply<int> r;
507  if (ot == Synchronous) {
508  interface.setTimeout(0x7FFFFFFF); // Don't timeout after 25s, but 24 days
509  r = interface.open(name, (qlonglong)w, appid());
510  interface.setTimeout(-1); // Back to the default 25s
511  // after this call, r would contain a transaction id >0 if OK or -1 if NOK
512  // if OK, the slot walletAsyncOpened should have been received, but the transaction id
513  // will not match. We'll get that handle from the reply - see below
514  } else if (ot == Asynchronous) {
515  r = interface.openAsync(name, (qlonglong)w, appid(), true);
516  } else if (ot == Path) {
517  r = interface.openPathAsync(name, (qlonglong)w, appid(), true);
518  } else {
519  delete wallet;
520  return nullptr;
521  }
522  // error communicating with the daemon (maybe not running)
523  if (!r.isValid()) {
524  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
525  delete wallet;
526  return nullptr;
527  }
528  wallet->d->transactionId = r.value();
529 
530  if (ot == Synchronous || ot == Path) {
531  // check for an immediate error
532  if (wallet->d->transactionId < 0) {
533  delete wallet;
534  wallet = nullptr;
535  } else {
536  wallet->d->handle = r.value();
537  }
538  } else if (ot == Asynchronous) {
539  if (wallet->d->transactionId < 0) {
540  QTimer::singleShot(0, wallet, SLOT(emitWalletAsyncOpenError()));
541  // client code is responsible for deleting the wallet
542  }
543  }
544 
545  return wallet;
546 #if HAVE_KSECRETSSERVICE
547  }
548 #endif
549 }
550 
551 void Wallet::slotCollectionStatusChanged(int status)
552 {
553 #if HAVE_KSECRETSSERVICE
554  KSecretsService::Collection::Status collStatus = (KSecretsService::Collection::Status)status;
555  switch (collStatus) {
556  case KSecretsService::Collection::NewlyCreated:
557  d->createDefaultFolders();
558  // fall through
559  case KSecretsService::Collection::FoundExisting:
560  emitWalletOpened();
561  break;
562  case KSecretsService::Collection::Deleted:
563  case KSecretsService::Collection::Invalid:
564  case KSecretsService::Collection::Pending:
565  // nothing to do
566  break;
567  case KSecretsService::Collection::NotFound:
568  emitWalletAsyncOpenError();
569  break;
570  }
571 #else
572  Q_UNUSED(status)
573 #endif
574 }
575 
576 void Wallet::slotCollectionDeleted()
577 {
578  d->folder.clear();
579  d->name.clear();
581 }
582 
583 bool Wallet::disconnectApplication(const QString &wallet, const QString &app)
584 {
585 #if HAVE_KSECRETSSERVICE
586  if (walletLauncher()->m_useKSecretsService) {
587  qCDebug(KWALLET_API_LOG) << "Wallet::disconnectApplication NOOP";
588  return true;
589  } else {
590 #endif
591  if (walletLauncher()->m_walletEnabled) {
592  QDBusReply<bool> r = walletLauncher()->getInterface().disconnectApplication(wallet, app);
593 
594  if (!r.isValid()) {
595  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
596  return false;
597  } else {
598  return r;
599  }
600  } else {
601  return -1;
602  }
603 #if HAVE_KSECRETSSERVICE
604  }
605 #endif
606 }
607 
609 {
610 #if HAVE_KSECRETSSERVICE
611  if (walletLauncher()->m_useKSecretsService) {
612  qCDebug(KWALLET_API_LOG) << "KSecretsService does not handle users list";
613  return QStringList();
614  } else {
615 #endif
616  if (walletLauncher()->m_walletEnabled) {
617  QDBusReply<QStringList> r = walletLauncher()->getInterface().users(name);
618  if (!r.isValid()) {
619  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
620  return QStringList();
621  } else {
622  return r;
623  }
624  } else {
625  return QStringList();
626  }
627 #if HAVE_KSECRETSSERVICE
628  }
629 #endif
630 }
631 
633 {
634 #if HAVE_KSECRETSSERVICE
635  if (walletLauncher()->m_useKSecretsService) {
636  // NOOP with KSecretsService
637  } else {
638 #endif
639  if (d->handle == -1) {
640  return -1;
641  }
642 
643  walletLauncher()->getInterface().sync(d->handle, appid());
644 #if HAVE_KSECRETSSERVICE
645  }
646 #endif
647  return 0;
648 }
649 
651 {
652 #if HAVE_KSECRETSSERVICE
653  if (walletLauncher()->m_useKSecretsService) {
654  KSecretsService::CollectionLockJob *lockJob = d->secretsCollection->lock();
655  if (lockJob->exec()) {
656  d->folder.clear();
657  d->name.clear();
658  } else {
659  qCDebug(KWALLET_API_LOG) << "Cannot execute KSecretsService::CollectionLockJob : " << lockJob->errorString();
660  return -1;
661  }
662  return lockJob->error();
663  } else {
664 #endif
665  if (d->handle == -1) {
666  return -1;
667  }
668 
669  QDBusReply<int> r = walletLauncher()->getInterface().close(d->handle, true, appid());
670  d->handle = -1;
671  d->folder.clear();
672  d->name.clear();
673  if (r.isValid()) {
674  return r;
675  } else {
676  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
677  return -1;
678  }
679 #if HAVE_KSECRETSSERVICE
680  }
681 #endif
682 }
683 
685 {
686  return d->name;
687 }
688 
689 bool Wallet::isOpen() const
690 {
691 #if HAVE_KSECRETSSERVICE
692  if (walletLauncher()->m_useKSecretsService) {
693  return !d->secretsCollection->isLocked();
694  } else {
695 #endif
696  return d->handle != -1;
697 #if HAVE_KSECRETSSERVICE
698  }
699 #endif
700 }
701 
703 {
704  if (w == 0) {
705  qCDebug(KWALLET_API_LOG) << "Pass a valid window to KWallet::Wallet::requestChangePassword().";
706  }
707 
708 #if HAVE_KSECRETSSERVICE
709  if (walletLauncher()->m_useKSecretsService) {
710  KSecretsService::ChangeCollectionPasswordJob *changePwdJob = d->secretsCollection->changePassword();
711  if (!changePwdJob->exec()) {
712  qCDebug(KWALLET_API_LOG) << "Cannot execute ChangeCollectionPasswordJob : " << changePwdJob->errorString();
713  }
714  } else {
715 #endif
716  if (d->handle == -1) {
717  return;
718  }
719 
720  // Make sure the password prompt window will be visible and activated
722 
723  walletLauncher()->getInterface().changePassword(d->name, (qlonglong)w, appid());
724 #if HAVE_KSECRETSSERVICE
725  }
726 #endif
727 }
728 
729 void Wallet::slotWalletClosed(int handle)
730 {
731 #if HAVE_KSECRETSSERVICE
732  if (walletLauncher()->m_useKSecretsService) {
733  // TODO: implement this
734  Q_ASSERT(0);
735  } else {
736 #endif
737  if (d->handle == handle) {
738  d->handle = -1;
739  d->folder.clear();
740  d->name.clear();
742  }
743 #if HAVE_KSECRETSSERVICE
744  }
745 #endif
746 }
747 
749 {
750 #if HAVE_KSECRETSSERVICE
751  if (walletLauncher()->m_useKSecretsService) {
752  QStringList result;
753 
754  KSecretsService::StringStringMap attrs;
755  attrs[KSS_ATTR_ENTRYFOLDER] = ""; // search for items having this attribute no matter what value it has
756  KSecretsService::SearchCollectionItemsJob *searchJob = d->secretsCollection->searchItems(attrs);
757 
758  if (searchJob->exec()) {
759  const KSecretsService::ReadCollectionItemsJob::ItemList itemList = searchJob->items();
760  for (const KSecretsService::ReadCollectionItemsJob::Item &item : itemList) {
761  KSecretsService::ReadItemPropertyJob *readAttrsJob = item->attributes();
762  if (readAttrsJob->exec()) {
763  KSecretsService::StringStringMap attrs = readAttrsJob->propertyValue().value<KSecretsService::StringStringMap>();
764  const QString folder = attrs[KSS_ATTR_ENTRYFOLDER];
765  if (!folder.isEmpty() && !result.contains(folder)) {
766  result.append(folder);
767  }
768  } else {
769  qCDebug(KWALLET_API_LOG) << "Cannot read item attributes : " << readAttrsJob->errorString();
770  }
771  }
772  } else {
773  qCDebug(KWALLET_API_LOG) << "Cannot execute ReadCollectionItemsJob : " << searchJob->errorString();
774  }
775  return result;
776  } else {
777 #endif
778  if (d->handle == -1) {
779  return QStringList();
780  }
781 
782  QDBusReply<QStringList> r = walletLauncher()->getInterface().folderList(d->handle, appid());
783  if (!r.isValid()) {
784  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
785  return QStringList();
786  } else {
787  return r;
788  }
789 #if HAVE_KSECRETSSERVICE
790  }
791 #endif
792 }
793 
795 {
796 #if HAVE_KSECRETSSERVICE
797  if (walletLauncher()->m_useKSecretsService) {
798  QStringList result;
799  KSecretsService::StringStringMap attrs;
800  attrs[KSS_ATTR_ENTRYFOLDER] = d->folder;
801  KSecretsService::SearchCollectionItemsJob *readItemsJob = d->secretsCollection->searchItems(attrs);
802  if (readItemsJob->exec()) {
803  const auto list = readItemsJob->items();
804  for (KSecretsService::SearchCollectionItemsJob::Item item : list) {
805  KSecretsService::ReadItemPropertyJob *readLabelJob = item->label();
806  if (readLabelJob->exec()) {
807  result.append(readLabelJob->propertyValue().toString());
808  } else {
809  qCDebug(KWALLET_API_LOG) << "Cannot execute readLabelJob" << readItemsJob->errorString();
810  }
811  }
812  } else {
813  qCDebug(KWALLET_API_LOG) << "Cannot execute readItemsJob" << readItemsJob->errorString();
814  }
815  return result;
816  } else {
817 #endif
818  if (d->handle == -1) {
819  return QStringList();
820  }
821 
822  QDBusReply<QStringList> r = walletLauncher()->getInterface().entryList(d->handle, d->folder, appid());
823  if (!r.isValid()) {
824  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
825  return QStringList();
826  } else {
827  return r;
828  }
829 #if HAVE_KSECRETSSERVICE
830  }
831 #endif
832 }
833 
835 {
836 #if HAVE_KSECRETSSERVICE
837  if (walletLauncher()->m_useKSecretsService) {
838  // FIXME: well, this is not the best implementation, but it's done quickly :)
839  // the best way would be to searchItems with the attribute label having the value f
840  // doing that would reduce DBus traffic. But KWallet API will not last.
841  QStringList folders = folderList();
842  return folders.contains(f);
843  } else {
844 #endif
845  if (d->handle == -1) {
846  return false;
847  }
848 
849  QDBusReply<bool> r = walletLauncher()->getInterface().hasFolder(d->handle, f, appid());
850  if (!r.isValid()) {
851  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
852  return false;
853  } else {
854  return r;
855  }
856 #if HAVE_KSECRETSSERVICE
857  }
858 #endif
859 }
860 
862 {
863 #if HAVE_KSECRETSSERVICE
864  if (walletLauncher()->m_useKSecretsService) {
865  QString strDummy("");
866  d->folder = f;
867  d->writeEntry(f, strDummy, KWallet::Wallet::Unknown);
868  return true;
869  } else {
870 #endif
871  if (d->handle == -1) {
872  return false;
873  }
874 
875  if (!hasFolder(f)) {
876  QDBusReply<bool> r = walletLauncher()->getInterface().createFolder(d->handle, f, appid());
877 
878  if (!r.isValid()) {
879  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
880  return false;
881  } else {
882  return r;
883  }
884  }
885 
886  return true; // folder already exists
887 #if HAVE_KSECRETSSERVICE
888  }
889 #endif
890 }
891 
893 {
894  bool rc = false;
895 
896 #if HAVE_KSECRETSSERVICE
897  if (walletLauncher()->m_useKSecretsService) {
898  if (hasFolder(f)) {
899  d->folder = f;
900  rc = true;
901  }
902  } else {
903 #endif
904  if (d->handle == -1) {
905  return rc;
906  }
907 
908  // Don't do this - the folder could have disappeared?
909 #if 0
910  if (f == d->folder) {
911  return true;
912  }
913 #endif
914 
915  if (hasFolder(f)) {
916  d->folder = f;
917  rc = true;
918  }
919 #if HAVE_KSECRETSSERVICE
920  }
921 #endif
922 
923  return rc;
924 }
925 
927 {
928 #if HAVE_KSECRETSSERVICE
929  if (walletLauncher()->m_useKSecretsService) {
930  bool result = false;
931  // search for all items having the folder f then delete them
932  KSecretsService::StringStringMap attrs;
933  attrs[KSS_ATTR_ENTRYFOLDER] = f;
934  KSecretsService::SearchCollectionItemsJob *searchJob = d->secretsCollection->searchItems(attrs);
935  if (searchJob->exec()) {
936  const KSecretsService::SearchCollectionItemsJob::ItemList itemList = searchJob->items();
937  if (!itemList.isEmpty()) {
938  result = true;
939  for (const KSecretsService::SearchCollectionItemsJob::Item &item : itemList) {
940  KSecretsService::SecretItemDeleteJob *deleteJob = item->deleteItem();
941  if (!deleteJob->exec()) {
942  qCDebug(KWALLET_API_LOG) << "Cannot delete item : " << deleteJob->errorString();
943  result = false;
944  }
945  result &= true;
946  }
947  }
948  } else {
949  qCDebug(KWALLET_API_LOG) << "Cannot execute KSecretsService::SearchCollectionItemsJob : " << searchJob->errorString();
950  }
951  return result;
952  } else {
953 #endif
954  if (d->handle == -1) {
955  return false;
956  }
957 
958  QDBusReply<bool> r = walletLauncher()->getInterface().removeFolder(d->handle, f, appid());
959  if (d->folder == f) {
960  setFolder(QString());
961  }
962 
963  if (!r.isValid()) {
964  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
965  return false;
966  } else {
967  return r;
968  }
969 #if HAVE_KSECRETSSERVICE
970  }
971 #endif
972 }
973 
975 {
976  return d->folder;
977 }
978 
979 #if HAVE_KSECRETSSERVICE
980 QExplicitlySharedDataPointer<KSecretsService::SecretItem> Wallet::WalletPrivate::findItem(const QString &key) const
981 {
983  KSecretsService::StringStringMap attrs;
984  attrs[KSS_ATTR_ENTRYFOLDER] = folder;
985  attrs["Label"] = key;
986  KSecretsService::SearchCollectionItemsJob *searchJob = secretsCollection->searchItems(attrs);
987  if (searchJob->exec()) {
988  KSecretsService::SearchCollectionItemsJob::ItemList itemList = searchJob->items();
989  if (!itemList.isEmpty()) {
990  result = itemList.first();
991  } else {
992  qCDebug(KWALLET_API_LOG) << "entry named " << key << " not found in folder " << folder;
993  }
994  } else {
995  qCDebug(KWALLET_API_LOG) << "Cannot exec KSecretsService::SearchCollectionItemsJob : " << searchJob->errorString();
996  }
997 
998  return result;
999 }
1000 
1001 template<typename T>
1002 int Wallet::WalletPrivate::readEntry(const QString &key, T &value) const
1003 {
1004  int rc = -1;
1006  if (item) {
1007  KSecretsService::GetSecretItemSecretJob *readJob = item->getSecret();
1008  if (readJob->exec()) {
1009  KSecretsService::Secret theSecret = readJob->secret();
1010  qCDebug(KWALLET_API_LOG) << "Secret contentType is " << theSecret.contentType();
1011  value = theSecret.value().value<T>();
1012  rc = 0;
1013  } else {
1014  qCDebug(KWALLET_API_LOG) << "Cannot exec GetSecretItemSecretJob : " << readJob->errorString();
1015  }
1016  }
1017  return rc;
1018 }
1019 
1020 bool Wallet::WalletPrivate::readSecret(const QString &key, KSecretsService::Secret &value) const
1021 {
1022  bool result = false;
1024  if (item) {
1025  KSecretsService::GetSecretItemSecretJob *readJob = item->getSecret();
1026  if (readJob->exec()) {
1027  value = readJob->secret();
1028  result = true;
1029  } else {
1030  qCDebug(KWALLET_API_LOG) << "Cannot exec GetSecretItemSecretJob : " << readJob->errorString();
1031  }
1032  }
1033  return result;
1034 }
1035 #endif
1036 
1037 int Wallet::readEntry(const QString &key, QByteArray &value)
1038 {
1039  int rc = -1;
1040 
1041 #if HAVE_KSECRETSSERVICE
1042  if (walletLauncher()->m_useKSecretsService) {
1043  return d->readEntry<QByteArray>(key, value);
1044  } else {
1045 #endif
1046  if (d->handle == -1) {
1047  return rc;
1048  }
1049 
1050  QDBusReply<QByteArray> r = walletLauncher()->getInterface().readEntry(d->handle, d->folder, key, appid());
1051  if (r.isValid()) {
1052  value = r;
1053  rc = 0;
1054  }
1055 #if HAVE_KSECRETSSERVICE
1056  }
1057 #endif
1058 
1059  return rc;
1060 }
1061 
1062 #if HAVE_KSECRETSSERVICE
1063 struct Wallet::WalletPrivate::InsertIntoEntryList {
1064  InsertIntoEntryList(QMap<QString, QByteArray> &value)
1065  : _value(value)
1066  {
1067  }
1068  bool operator()(Wallet::WalletPrivate *, const QString &label, KSecretsService::SecretItem *item)
1069  {
1070  bool result = false;
1071  KSecretsService::GetSecretItemSecretJob *readSecretJob = item->getSecret();
1072  if (readSecretJob->exec()) {
1073  _value.insert(label, readSecretJob->secret().value().toByteArray());
1074  result = true;
1075  } else {
1076  qCDebug(KWALLET_API_LOG) << "Cannot execute GetSecretItemSecretJob " << readSecretJob->errorString();
1077  }
1078  return result;
1079  }
1081 };
1082 #endif
1083 
1084 #if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
1086 {
1087  int rc = -1;
1088 
1089 #if HAVE_KSECRETSSERVICE
1090  if (walletLauncher()->m_useKSecretsService) {
1091  rc = d->forEachItemThatMatches(key, WalletPrivate::InsertIntoEntryList(value));
1092  } else {
1093 #endif
1094  registerTypes();
1095 
1096  if (d->handle == -1) {
1097  return rc;
1098  }
1099 
1100  QT_WARNING_PUSH
1101  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
1102  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
1103  QDBusReply<QVariantMap> r = walletLauncher()->getInterface().readEntryList(d->handle, d->folder, key, appid());
1104  QT_WARNING_POP
1105  if (r.isValid()) {
1106  rc = 0;
1107  // convert <QString, QVariant> to <QString, QByteArray>
1108  const QVariantMap val = r.value();
1109  for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
1110  value.insert(it.key(), it.value().toByteArray());
1111  }
1112  }
1113 #if HAVE_KSECRETSSERVICE
1114  }
1115 #endif
1116 
1117  return rc;
1118 }
1119 #endif
1120 
1122 {
1123  QMap<QString, QByteArray> entries;
1124 
1125 #if HAVE_KSECRETSSERVICE
1126  if (walletLauncher()->m_useKSecretsService) {
1127  const int ret = d->checkItems(WalletPrivate::InsertIntoEntryList(entries));
1128  if (ok) {
1129  *ok = ret == 0;
1130  }
1131  } else {
1132 #endif
1133  registerTypes();
1134 
1135  if (d->handle == -1) {
1136  if (ok) {
1137  *ok = false;
1138  }
1139  return entries;
1140  }
1141 
1142  QDBusReply<QVariantMap> reply = walletLauncher()->getInterface().entriesList(d->handle, d->folder, appid());
1143  if (reply.isValid()) {
1144  if (ok) {
1145  *ok = true;
1146  }
1147  // convert <QString, QVariant> to <QString, QByteArray>
1148  const QVariantMap val = reply.value();
1149  for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
1150  entries.insert(it.key(), it.value().toByteArray());
1151  }
1152  }
1153 #if HAVE_KSECRETSSERVICE
1154  }
1155 #endif
1156 
1157  return entries;
1158 }
1159 
1160 int Wallet::renameEntry(const QString &oldName, const QString &newName)
1161 {
1162  int rc = -1;
1163 
1164 #if HAVE_KSECRETSSERVICE
1165  if (walletLauncher()->m_useKSecretsService) {
1167  if (item) {
1168  KSecretsService::WriteItemPropertyJob *writeJob = item->setLabel(newName);
1169  if (!writeJob->exec()) {
1170  qCDebug(KWALLET_API_LOG) << "Cannot exec WriteItemPropertyJob : " << writeJob->errorString();
1171  }
1172  rc = writeJob->error();
1173  } else {
1174  qCDebug(KWALLET_API_LOG) << "Cannot locate item " << oldName << " in folder " << d->folder;
1175  }
1176  } else {
1177 #endif
1178  if (d->handle == -1) {
1179  return rc;
1180  }
1181 
1182  QT_WARNING_PUSH
1183  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
1184  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
1185  QDBusReply<int> r = walletLauncher()->getInterface().renameEntry(d->handle, d->folder, oldName, newName, appid());
1186  QT_WARNING_POP
1187  if (r.isValid()) {
1188  rc = r;
1189  }
1190 #if HAVE_KSECRETSSERVICE
1191  }
1192 #endif
1193 
1194  return rc;
1195 }
1196 
1198 {
1199  int rc = -1;
1200 
1201 #if HAVE_KSECRETSSERVICE
1202  if (walletLauncher()->m_useKSecretsService) {
1203  QByteArray ba;
1204  rc = d->readEntry<QByteArray>(key, ba);
1205  if (rc == 0 && !ba.isEmpty()) {
1207  ds >> value;
1208  }
1209  } else {
1210 #endif
1211  registerTypes();
1212 
1213  if (d->handle == -1) {
1214  return rc;
1215  }
1216 
1217  QDBusReply<QByteArray> r = walletLauncher()->getInterface().readMap(d->handle, d->folder, key, appid());
1218  if (r.isValid()) {
1219  rc = 0;
1220  QByteArray v = r;
1221  if (!v.isEmpty()) {
1223  ds >> value;
1224  }
1225  }
1226 #if HAVE_KSECRETSSERVICE
1227  }
1228 #endif
1229 
1230  return rc;
1231 }
1232 
1233 #if HAVE_KSECRETSSERVICE
1234 struct Wallet::WalletPrivate::InsertIntoMapList {
1235  InsertIntoMapList(QMap<QString, QMap<QString, QString>> &value)
1236  : _value(value)
1237  {
1238  }
1239  bool operator()(Wallet::WalletPrivate *d, const QString &label, KSecretsService::SecretItem *)
1240  {
1241  bool result = false;
1243  if (d->readEntry<QMap<QString, QString>>(label, map)) {
1244  _value.insert(label, map);
1245  result = true;
1246  }
1247  return result;
1248  }
1250 };
1251 #endif
1252 
1253 #if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
1255 {
1256  int rc = -1;
1257 
1258 #if HAVE_KSECRETSSERVICE
1259  if (walletLauncher()->m_useKSecretsService) {
1260  rc = d->forEachItemThatMatches(key, WalletPrivate::InsertIntoMapList(value));
1261  } else {
1262 #endif
1263  registerTypes();
1264 
1265  if (d->handle == -1) {
1266  return rc;
1267  }
1268 
1269  QT_WARNING_PUSH
1270  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
1271  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
1272  QDBusReply<QVariantMap> r = walletLauncher()->getInterface().readMapList(d->handle, d->folder, key, appid());
1273  QT_WARNING_POP
1274  if (r.isValid()) {
1275  rc = 0;
1276  const QVariantMap val = r.value();
1277  for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
1278  QByteArray mapData = it.value().toByteArray();
1279  if (!mapData.isEmpty()) {
1280  QDataStream ds(&mapData, QIODevice::ReadOnly);
1282  ds >> v;
1283  value.insert(it.key(), v);
1284  }
1285  }
1286  }
1287 #if HAVE_KSECRETSSERVICE
1288  }
1289 #endif
1290 
1291  return rc;
1292 }
1293 #endif
1294 
1296 {
1298 
1299 #if HAVE_KSECRETSSERVICE
1300  if (walletLauncher()->m_useKSecretsService) {
1301  const int ret = d->checkItems(WalletPrivate::InsertIntoMapList(list));
1302  if (ok) {
1303  *ok = ret == 0;
1304  }
1305  } else {
1306 #endif
1307  registerTypes();
1308 
1309  if (d->handle == -1) {
1310  if (ok) {
1311  *ok = false;
1312  }
1313  return list;
1314  }
1315 
1316  QDBusReply<QVariantMap> reply = walletLauncher()->getInterface().mapList(d->handle, d->folder, appid());
1317  if (reply.isValid()) {
1318  if (ok) {
1319  *ok = true;
1320  }
1321  const QVariantMap val = reply.value();
1322  for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
1323  QByteArray mapData = it.value().toByteArray();
1324  if (!mapData.isEmpty()) {
1325  QDataStream ds(&mapData, QIODevice::ReadOnly);
1327  ds >> v;
1328  list.insert(it.key(), v);
1329  }
1330  }
1331  }
1332 #if HAVE_KSECRETSSERVICE
1333  }
1334 #endif
1335 
1336  return list;
1337 }
1338 
1339 int Wallet::readPassword(const QString &key, QString &value)
1340 {
1341  int rc = -1;
1342 
1343 #if HAVE_KSECRETSSERVICE
1344  if (walletLauncher()->m_useKSecretsService) {
1345  rc = d->readEntry<QString>(key, value);
1346  } else {
1347 #endif
1348  if (d->handle == -1) {
1349  return rc;
1350  }
1351 
1352  QDBusReply<QString> r = walletLauncher()->getInterface().readPassword(d->handle, d->folder, key, appid());
1353  if (r.isValid()) {
1354  value = r;
1355  rc = 0;
1356  }
1357 #if HAVE_KSECRETSSERVICE
1358  }
1359 #endif
1360 
1361  return rc;
1362 }
1363 
1364 #if HAVE_KSECRETSSERVICE
1365 struct Wallet::WalletPrivate::InsertIntoPasswordList {
1366  InsertIntoPasswordList(QMap<QString, QString> &value)
1367  : _value(value)
1368  {
1369  }
1370  bool operator()(Wallet::WalletPrivate *d, const QString &label, KSecretsService::SecretItem *)
1371  {
1372  bool result = false;
1373  QString pwd;
1374  if (d->readEntry<QString>(label, pwd) == 0) {
1375  _value.insert(label, pwd);
1376  result = true;
1377  }
1378  return result;
1379  }
1380  QMap<QString, QString> &_value;
1381 };
1382 #endif
1383 
1384 #if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
1386 {
1387  int rc = -1;
1388 
1389 #if HAVE_KSECRETSSERVICE
1390  if (walletLauncher()->m_useKSecretsService) {
1391  rc = d->forEachItemThatMatches(key, WalletPrivate::InsertIntoPasswordList(value));
1392  } else {
1393 #endif
1394  registerTypes();
1395 
1396  if (d->handle == -1) {
1397  return rc;
1398  }
1399 
1400  QT_WARNING_PUSH
1401  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
1402  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
1403  QDBusReply<QVariantMap> r = walletLauncher()->getInterface().readPasswordList(d->handle, d->folder, key, appid());
1404  QT_WARNING_POP
1405  if (r.isValid()) {
1406  rc = 0;
1407  const QVariantMap val = r.value();
1408  for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
1409  value.insert(it.key(), it.value().toString());
1410  }
1411  }
1412 #if HAVE_KSECRETSSERVICE
1413  }
1414 #endif
1415 
1416  return rc;
1417 }
1418 #endif
1419 
1421 {
1422  QMap<QString, QString> passList;
1423 
1424 #if HAVE_KSECRETSSERVICE
1425  if (walletLauncher()->m_useKSecretsService) {
1426  const int ret = d->checkItems(WalletPrivate::InsertIntoPasswordList(passList));
1427  if (ok) {
1428  *ok = ret == 0;
1429  } else {
1430 #endif
1431  registerTypes();
1432 
1433  if (d->handle == -1) {
1434  if (ok) {
1435  *ok = false;
1436  }
1437  return passList;
1438  }
1439 
1440  QDBusReply<QVariantMap> reply = walletLauncher()->getInterface().passwordList(d->handle, d->folder, appid());
1441  if (reply.isValid()) {
1442  if (ok) {
1443  *ok = true;
1444  }
1445  const QVariantMap val = reply.value();
1446  for (QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it) {
1447  passList.insert(it.key(), it.value().toString());
1448  }
1449  }
1450 #if HAVE_KSECRETSSERVICE
1451  }
1452 #endif
1453 
1454  return passList;
1455  }
1456 
1457  int Wallet::writeEntry(const QString &key, const QByteArray &value, EntryType entryType)
1458  {
1459  int rc = -1;
1460 
1461 #if HAVE_KSECRETSSERVICE
1462  if (walletLauncher()->m_useKSecretsService) {
1463  rc = d->writeEntry(key, value, entryType);
1464  } else {
1465 #endif
1466  if (d->handle == -1) {
1467  return rc;
1468  }
1469 
1470  QDBusReply<int> r = walletLauncher()->getInterface().writeEntry(d->handle, d->folder, key, value, int(entryType), appid());
1471  if (r.isValid()) {
1472  rc = r;
1473  }
1474 #if HAVE_KSECRETSSERVICE
1475  }
1476 #endif
1477 
1478  return rc;
1479  }
1480 
1481  int Wallet::writeEntry(const QString &key, const QByteArray &value)
1482  {
1483  int rc = -1;
1484 
1485 #if HAVE_KSECRETSSERVICE
1486  if (walletLauncher()->m_useKSecretsService) {
1487  rc = writeEntry(key, value, Stream);
1488  } else {
1489 #endif
1490  if (d->handle == -1) {
1491  return rc;
1492  }
1493 
1494  QDBusReply<int> r = walletLauncher()->getInterface().writeEntry(d->handle, d->folder, key, value, appid());
1495  if (r.isValid()) {
1496  rc = r;
1497  }
1498 #if HAVE_KSECRETSSERVICE
1499  }
1500 #endif
1501 
1502  return rc;
1503  }
1504 
1505  int Wallet::writeMap(const QString &key, const QMap<QString, QString> &value)
1506  {
1507  int rc = -1;
1508 
1509 #if HAVE_KSECRETSSERVICE
1510  if (walletLauncher()->m_useKSecretsService) {
1511  d->writeEntry(key, value, Map);
1512  } else {
1513 #endif
1514  registerTypes();
1515 
1516  if (d->handle == -1) {
1517  return rc;
1518  }
1519 
1520  QByteArray mapData;
1521  QDataStream ds(&mapData, QIODevice::WriteOnly);
1522  ds << value;
1523  QDBusReply<int> r = walletLauncher()->getInterface().writeMap(d->handle, d->folder, key, mapData, appid());
1524  if (r.isValid()) {
1525  rc = r;
1526  }
1527 #if HAVE_KSECRETSSERVICE
1528  }
1529 #endif
1530 
1531  return rc;
1532  }
1533 
1534  int Wallet::writePassword(const QString &key, const QString &value)
1535  {
1536  int rc = -1;
1537 
1538 #if HAVE_KSECRETSSERVICE
1539  if (walletLauncher()->m_useKSecretsService) {
1540  rc = d->writeEntry(key, value, Password);
1541  } else {
1542 #endif
1543  if (d->handle == -1) {
1544  return rc;
1545  }
1546 
1547  QDBusReply<int> r = walletLauncher()->getInterface().writePassword(d->handle, d->folder, key, value, appid());
1548  if (r.isValid()) {
1549  rc = r;
1550  }
1551 #if HAVE_KSECRETSSERVICE
1552  }
1553 #endif
1554 
1555  return rc;
1556  }
1557 
1558  bool Wallet::hasEntry(const QString &key)
1559  {
1560 #if HAVE_KSECRETSSERVICE
1561  if (walletLauncher()->m_useKSecretsService) {
1563  return item;
1564  } else {
1565 #endif
1566  if (d->handle == -1) {
1567  return false;
1568  }
1569 
1570  QDBusReply<bool> r = walletLauncher()->getInterface().hasEntry(d->handle, d->folder, key, appid());
1571  if (!r.isValid()) {
1572  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
1573  return false;
1574  } else {
1575  return r;
1576  }
1577 #if HAVE_KSECRETSSERVICE
1578  }
1579 #endif
1580  }
1581 
1583  {
1584  int rc = -1;
1585 
1586 #if HAVE_KSECRETSSERVICE
1587  if (walletLauncher()->m_useKSecretsService) {
1589  if (item) {
1590  KSecretsService::SecretItemDeleteJob *deleteJob = item->deleteItem();
1591  if (!deleteJob->exec()) {
1592  qCDebug(KWALLET_API_LOG) << "Cannot execute SecretItemDeleteJob " << deleteJob->errorString();
1593  }
1594  rc = deleteJob->error();
1595  }
1596  } else {
1597 #endif
1598  if (d->handle == -1) {
1599  return rc;
1600  }
1601 
1602  QDBusReply<int> r = walletLauncher()->getInterface().removeEntry(d->handle, d->folder, key, appid());
1603  if (r.isValid()) {
1604  rc = r;
1605  }
1606 #if HAVE_KSECRETSSERVICE
1607  }
1608 #endif
1609 
1610  return rc;
1611  }
1612 
1613  Wallet::EntryType Wallet::entryType(const QString &key)
1614  {
1615  int rc = 0;
1616 
1617 #if HAVE_KSECRETSSERVICE
1618  if (walletLauncher()->m_useKSecretsService) {
1620  if (item) {
1621  KSecretsService::ReadItemPropertyJob *readAttrsJob = item->attributes();
1622  if (readAttrsJob->exec()) {
1623  KSecretsService::StringStringMap attrs = readAttrsJob->propertyValue().value<KSecretsService::StringStringMap>();
1624  if (attrs.contains(KSS_ATTR_WALLETTYPE)) {
1625  QString entryType = attrs[KSS_ATTR_WALLETTYPE];
1626  bool ok = false;
1627  rc = entryType.toInt(&ok);
1628  if (!ok) {
1629  rc = 0;
1630  qCDebug(KWALLET_API_LOG) << KSS_ATTR_WALLETTYPE << " attribute holds non int value " << attrs[KSS_ATTR_WALLETTYPE];
1631  }
1632  }
1633  } else {
1634  qCDebug(KWALLET_API_LOG) << "Cannot execute GetSecretItemSecretJob " << readAttrsJob->errorString();
1635  }
1636  }
1637  } else {
1638 #endif
1639  if (d->handle == -1) {
1640  return Wallet::Unknown;
1641  }
1642 
1643  QDBusReply<int> r = walletLauncher()->getInterface().entryType(d->handle, d->folder, key, appid());
1644  if (r.isValid()) {
1645  rc = r;
1646  }
1647 #if HAVE_KSECRETSSERVICE
1648  }
1649 #endif
1650  return static_cast<EntryType>(rc);
1651  }
1652 
1653  void Wallet::WalletPrivate::walletServiceUnregistered()
1654  {
1655  if (handle >= 0) {
1656  q->slotWalletClosed(handle);
1657  }
1658  }
1659 
1660  void Wallet::slotFolderUpdated(const QString &wallet, const QString &folder)
1661  {
1662 #if HAVE_KSECRETSSERVICE
1663  if (walletLauncher()->m_useKSecretsService) {
1664  // TODO: implement this
1665  Q_ASSERT(0);
1666  } else {
1667 #endif
1668  if (d->name == wallet) {
1669  Q_EMIT folderUpdated(folder);
1670  }
1671 #if HAVE_KSECRETSSERVICE
1672  }
1673 #endif
1674  }
1675 
1676  void Wallet::slotFolderListUpdated(const QString &wallet)
1677  {
1678 #if HAVE_KSECRETSSERVICE
1679  if (walletLauncher()->m_useKSecretsService) {
1680  // TODO: implement this
1681  Q_ASSERT(0);
1682  } else {
1683 #endif
1684  if (d->name == wallet) {
1686  }
1687 #if HAVE_KSECRETSSERVICE
1688  }
1689 #endif
1690  }
1691 
1692  void Wallet::slotApplicationDisconnected(const QString &wallet, const QString &application)
1693  {
1694 #if HAVE_KSECRETSSERVICE
1695  if (walletLauncher()->m_useKSecretsService) {
1696  // TODO: implement this
1697  Q_ASSERT(0);
1698  } else {
1699 #endif
1700  if (d->handle >= 0 && d->name == wallet && application == appid()) {
1701  slotWalletClosed(d->handle);
1702  }
1703 #if HAVE_KSECRETSSERVICE
1704  }
1705 #endif
1706  }
1707 
1708  void Wallet::walletAsyncOpened(int tId, int handle)
1709  {
1710 #if HAVE_KSECRETSSERVICE
1711  if (walletLauncher()->m_useKSecretsService) {
1712  // TODO: implement this
1713  Q_ASSERT(0);
1714  } else {
1715 #endif
1716  // ignore responses to calls other than ours
1717  if (d->transactionId != tId || d->handle != -1) {
1718  return;
1719  }
1720 
1721  // disconnect the async signal
1722  disconnect(this, SLOT(walletAsyncOpened(int, int)));
1723 
1724  d->handle = handle;
1725  Q_EMIT walletOpened(handle > 0);
1726 #if HAVE_KSECRETSSERVICE
1727  }
1728 #endif
1729  }
1730 
1731  void Wallet::emitWalletAsyncOpenError()
1732  {
1733  Q_EMIT walletOpened(false);
1734  }
1735 
1736  void Wallet::emitWalletOpened()
1737  {
1738  Q_EMIT walletOpened(true);
1739  }
1740 
1741  bool Wallet::folderDoesNotExist(const QString &wallet, const QString &folder)
1742  {
1743 #if HAVE_KSECRETSSERVICE
1744  if (walletLauncher()->m_useKSecretsService) {
1745  qCDebug(KWALLET_API_LOG) << "WARNING: changing semantics of folderDoesNotExist with KSS: will prompt for the password";
1746  Wallet *w = openWallet(wallet, 0, Synchronous);
1747  if (w) {
1748  return !w->hasFolder(folder);
1749  } else {
1750  return true;
1751  }
1752  } else {
1753 #endif
1754  if (walletLauncher()->m_walletEnabled) {
1755  QDBusReply<bool> r = walletLauncher()->getInterface().folderDoesNotExist(wallet, folder);
1756  if (!r.isValid()) {
1757  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
1758  return false;
1759  } else {
1760  return r;
1761  }
1762  } else {
1763  return false;
1764  }
1765 #if HAVE_KSECRETSSERVICE
1766  }
1767 #endif
1768  }
1769 
1770  bool Wallet::keyDoesNotExist(const QString &wallet, const QString &folder, const QString &key)
1771  {
1772 #if HAVE_KSECRETSSERVICE
1773  if (walletLauncher()->m_useKSecretsService) {
1774  qCDebug(KWALLET_API_LOG) << "WARNING: changing semantics of keyDoesNotExist with KSS: will prompt for the password";
1775  Wallet *w = openWallet(wallet, 0, Synchronous);
1776  if (w) {
1777  return !w->hasEntry(key);
1778  }
1779  return false;
1780  } else {
1781 #endif
1782  if (walletLauncher()->m_walletEnabled) {
1783  QDBusReply<bool> r = walletLauncher()->getInterface().keyDoesNotExist(wallet, folder, key);
1784  if (!r.isValid()) {
1785  qCDebug(KWALLET_API_LOG) << "Invalid DBus reply: " << r.error();
1786  return false;
1787  } else {
1788  return r;
1789  }
1790  } else {
1791  return false;
1792  }
1793 #if HAVE_KSECRETSSERVICE
1794  }
1795 #endif
1796  }
1797 
1798  void Wallet::virtual_hook(int, void *)
1799  {
1800  // BASE::virtual_hook( id, data );
1801  }
1802 
1803  KWalletDLauncher::KWalletDLauncher()
1804  : m_wallet_deamon(nullptr)
1805  , m_cgroup(KSharedConfig::openConfig(QStringLiteral("kwalletrc"), KConfig::NoGlobals)->group("Wallet"))
1806  , m_walletEnabled(false)
1807  {
1808  m_useKSecretsService = m_cgroup.readEntry("UseKSecretsService", false);
1809  m_walletEnabled = m_cgroup.readEntry("Enabled", true);
1810  if (!m_walletEnabled) {
1811  qCDebug(KWALLET_API_LOG) << "The wallet service was disabled by the user";
1812  return;
1813  }
1814 #if HAVE_KSECRETSSERVICE
1815  if (m_useKSecretsService) {
1816  // NOOP
1817  } else {
1818 #endif
1819  m_wallet_deamon =
1820  new org::kde::KWallet(QString::fromLatin1(s_kwalletdServiceName), QStringLiteral("/modules/kwalletd5"), QDBusConnection::sessionBus());
1821 #if HAVE_KSECRETSSERVICE
1822  }
1823 #endif
1824  }
1825 
1826  KWalletDLauncher::~KWalletDLauncher()
1827  {
1828  delete m_wallet_deamon;
1829  }
1830 
1831  org::kde::KWallet &KWalletDLauncher::getInterface()
1832  {
1833  // Q_ASSERT(!m_useKSecretsService);
1834  Q_ASSERT(m_wallet_deamon != nullptr);
1835 
1836  // check if kwalletd is already running
1838  if (!bus->isServiceRegistered(QString::fromLatin1(s_kwalletdServiceName))) {
1839  // not running! check if it is enabled.
1840  if (m_walletEnabled) {
1841  // wallet is enabled! try launching it
1842  QDBusReply<void> reply = bus->startService(QString::fromLatin1(s_kwalletdServiceName));
1843  if (!reply.isValid()) {
1844  qCritical() << "Couldn't start kwalletd: " << reply.error();
1845  }
1846 
1847  if (!bus->isServiceRegistered(QString::fromLatin1(s_kwalletdServiceName))) {
1848  qCDebug(KWALLET_API_LOG) << "The kwalletd service is still not registered";
1849  } else {
1850  qCDebug(KWALLET_API_LOG) << "The kwalletd service has been registered";
1851  }
1852  } else {
1853  qCritical() << "The kwalletd service has been disabled";
1854  }
1855  }
1856 
1857  return *m_wallet_deamon;
1858  }
1859 
1860 } // namespace KWallet
1861 
1862 #include "moc_kwallet.cpp"
virtual bool hasEntry(const QString &key)
Determine if the current folder has they entry key.
Definition: kwallet.cpp:1558
virtual void requestChangePassword(WId w)
Request to the wallet service to change the password of the current wallet.
Definition: kwallet.cpp:702
Wallet(int handle, const QString &name)
Construct a KWallet object.
Definition: kwallet.cpp:259
QMap< QString, QMap< QString, QString > > mapList(bool *ok) const
Get a list of all the maps in the current folder.
Definition: kwallet.cpp:1295
QRegularExpressionMatch match(const QString &subject, int offset, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions) const const
virtual const QString & walletName() const
The name of the current wallet.
Definition: kwallet.cpp:684
QDBusReply< void > startService(const QString &name)
virtual bool setFolder(const QString &f)
Set the current working folder to f.
Definition: kwallet.cpp:892
virtual int renameEntry(const QString &oldName, const QString &newName)
Rename the entry oldName to newName.
Definition: kwallet.cpp:1160
virtual EntryType entryType(const QString &key)
Determine the type of the entry key in this folder.
Definition: kwallet.cpp:1613
void folderListUpdated()
Emitted when the folder list is changed in this wallet.
virtual void virtual_hook(int id, void *data)
Definition: kwallet.cpp:1798
virtual QString errorString() const
QDBusConnectionInterface * interface() const const
bool exec()
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
static bool isEnabled()
Determine if the KDE wallet is enabled.
Definition: kwallet.cpp:370
virtual int readMap(const QString &key, QMap< QString, QString > &value)
Read the map entry key from the current folder.
Definition: kwallet.cpp:1197
bool isValid() const const
Q_GLOBAL_STATIC(Internal::StaticControl, s_instance) class ControlPrivate
QDBusConnection sessionBus()
virtual int removeEntry(const QString &key)
Remove the entry key from the current folder.
Definition: kwallet.cpp:1582
int readPasswordList(const QString &key, QMap< QString, QString > &value)
Read the password entry key from the current folder.
Definition: kwallet.cpp:1385
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
const QLatin1String name
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
static Wallet * openWallet(const QString &name, WId w, OpenType ot=Synchronous)
Open the wallet name.
Definition: kwallet.cpp:468
virtual int writePassword(const QString &key, const QString &value)
Write key = value as a password to the current folder.
Definition: kwallet.cpp:1534
void walletOpened(bool success)
Emitted when a wallet is opened in asynchronous mode.
QString wildcardToRegularExpression(const QString &pattern)
virtual int lockWallet()
This closes and locks the current wallet.
Definition: kwallet.cpp:650
virtual bool hasFolder(const QString &f)
Determine if the folder f exists in the wallet.
Definition: kwallet.cpp:834
QMap< QString, QByteArray > entriesList(bool *ok) const
Get a list of all the entries in the current folder.
Definition: kwallet.cpp:1121
void folderUpdated(const QString &folder)
Emitted when a folder in this wallet is updated.
virtual bool removeFolder(const QString &f)
Remove the folder f and all its entries from the wallet.
Definition: kwallet.cpp:926
void append(const T &value)
QString & insert(int position, QChar ch)
QDBusReply::Type value() const const
virtual int readPassword(const QString &key, QString &value)
Read the password entry key from the current folder.
Definition: kwallet.cpp:1339
int toInt(bool *ok, int base) const const
virtual QStringList entryList()
Return the list of keys of all entries in this folder.
Definition: kwallet.cpp:794
int readEntryList(const QString &key, QMap< QString, QByteArray > &value)
Read the entries matching key from the current folder.
Definition: kwallet.cpp:1085
bool isEmpty() const const
void serviceUnregistered(const QString &serviceName)
bool hasMatch() const const
static QStringList walletList()
List all the wallets available.
Definition: kwallet.cpp:316
static bool disconnectApplication(const QString &wallet, const QString &app)
Disconnect the application app from wallet.
Definition: kwallet.cpp:583
int readMapList(const QString &key, QMap< QString, QMap< QString, QString >> &value)
Read the map entry key from the current folder.
Definition: kwallet.cpp:1254
void walletClosed()
Emitted when this wallet is closed.
virtual int readEntry(const QString &key, QByteArray &value)
Read the entry key from the current folder.
Definition: kwallet.cpp:1037
static void changePassword(const QString &name, WId w)
Request to the wallet service to change the password of the wallet name.
Definition: kwallet.cpp:344
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
static void allowExternalProcessWindowActivation(int pid=-1)
const QDBusError & error()
QString & replace(int position, int n, QChar after)
static QStringList users(const QString &wallet)
List the applications that are using the wallet wallet.
Definition: kwallet.cpp:608
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
virtual bool createFolder(const QString &f)
Created the folder f.
Definition: kwallet.cpp:861
virtual int sync()
This syncs the wallet file on disk with what is in memory.
Definition: kwallet.cpp:632
static int closeWallet(const QString &name, bool force)
Close the wallet name.
Definition: kwallet.cpp:414
virtual QStringList folderList()
Obtain the list of all folders contained in the wallet.
Definition: kwallet.cpp:748
static bool keyDoesNotExist(const QString &wallet, const QString &folder, const QString &key)
Determine if an entry in a folder does not exist in a wallet.
Definition: kwallet.cpp:1770
static int deleteWallet(const QString &name)
Delete the wallet name.
Definition: kwallet.cpp:439
QString fromLatin1(const char *str, int size)
QMap::iterator insert(const Key &key, const T &value)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual const QString & currentFolder() const
Determine the current working folder in the wallet.
Definition: kwallet.cpp:974
QChar * data()
T readEntry(const QString &key, const T &aDefault) const
QMap< QString, QString > passwordList(bool *ok) const
Get a list of all the passwords in the current folder, which can be used to populate a list view in a...
Definition: kwallet.cpp:1420
virtual int writeEntry(const QString &key, const QByteArray &value, EntryType entryType)
Write key = value as a binary entry to the current folder.
Definition: kwallet.cpp:1457
virtual bool isOpen() const
Determine if the current wallet is open, and is a valid wallet handle.
Definition: kwallet.cpp:689
Q_EMITQ_EMIT
static bool folderDoesNotExist(const QString &wallet, const QString &folder)
Determine if a folder does not exist in a wallet.
Definition: kwallet.cpp:1741
int error() const
virtual int writeMap(const QString &key, const QMap< QString, QString > &value)
Write key = value as a map to the current folder.
Definition: kwallet.cpp:1505
~Wallet() override
Destroy a KWallet object.
Definition: kwallet.cpp:290
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Tue Jan 25 2022 22:53:06 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.