File indexing completed on 2024-04-21 05:01:41

0001 /*
0002     This is the wallet manager of Smb4K.
0003 
0004     SPDX-FileCopyrightText: 2008-2022 Alexander Reinholdt <alexander.reinholdt@kdemail.net>
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 // application specific includes
0009 #include "smb4kwalletmanager.h"
0010 #include "smb4kauthinfo.h"
0011 #include "smb4kglobal.h"
0012 #include "smb4khomesshareshandler.h"
0013 #include "smb4khost.h"
0014 #include "smb4knotification.h"
0015 #include "smb4ksettings.h"
0016 #include "smb4kshare.h"
0017 
0018 // Qt includes
0019 #include <QApplication>
0020 #include <QPointer>
0021 
0022 // KDE includes
0023 #include <KWallet>
0024 
0025 using namespace Smb4KGlobal;
0026 
0027 class Smb4KWalletManagerPrivate
0028 {
0029 public:
0030     KWallet::Wallet *wallet;
0031 };
0032 
0033 class Smb4KWalletManagerStatic
0034 {
0035 public:
0036     Smb4KWalletManager instance;
0037 };
0038 
0039 Q_GLOBAL_STATIC(Smb4KWalletManagerStatic, p);
0040 
0041 Smb4KWalletManager::Smb4KWalletManager(QObject *parent)
0042     : QObject(parent)
0043     , d(new Smb4KWalletManagerPrivate)
0044 {
0045     d->wallet = nullptr;
0046 }
0047 
0048 Smb4KWalletManager::~Smb4KWalletManager()
0049 {
0050 }
0051 
0052 Smb4KWalletManager *Smb4KWalletManager::self()
0053 {
0054     return &p->instance;
0055 }
0056 
0057 void Smb4KWalletManager::readLoginCredentials(const NetworkItemPtr &networkItem)
0058 {
0059     if (networkItem) {
0060         if (networkItem->type() == Host || networkItem->type() == Share) {
0061             Smb4KAuthInfo authInfo;
0062 
0063             if (networkItem->type() == Share) {
0064                 SharePtr share = networkItem.staticCast<Smb4KShare>();
0065 
0066                 if (share->isHomesShare()) {
0067                     authInfo.setUrl(share->homeUrl());
0068                 } else {
0069                     authInfo.setUrl(share->url());
0070                 }
0071 
0072                 //
0073                 // Read the credentials for the share. Fall back to the URL of the
0074                 // host, if no credentials for the share could be found.
0075                 //
0076                 if (!read(&authInfo)) {
0077                     authInfo.setUrl(share->url().adjusted(QUrl::RemovePath | QUrl::StripTrailingSlash));
0078                     (void)read(&authInfo);
0079                 }
0080             } else {
0081                 authInfo.setUrl(networkItem->url());
0082                 (void)read(&authInfo);
0083             }
0084 
0085             QUrl url = networkItem->url();
0086 
0087             url.setUserName(authInfo.userName());
0088             url.setPassword(authInfo.password());
0089 
0090             networkItem->setUrl(url);
0091         }
0092     }
0093 }
0094 
0095 void Smb4KWalletManager::readLoginCredentials(Smb4KAuthInfo *authInfo)
0096 {
0097     if (authInfo) {
0098         if (authInfo->type() == Host || authInfo->type() == Share) {
0099             (void)read(authInfo);
0100         }
0101     }
0102 }
0103 
0104 void Smb4KWalletManager::writeLoginCredentials(const NetworkItemPtr &networkItem)
0105 {
0106     if (networkItem) {
0107         if (networkItem->type() == Host || networkItem->type() == Share) {
0108             Smb4KAuthInfo authInfo;
0109 
0110             if (networkItem->type() == Share) {
0111                 SharePtr share = networkItem.staticCast<Smb4KShare>();
0112 
0113                 if (share->isHomesShare()) {
0114                     authInfo.setUrl(share->homeUrl());
0115                 } else {
0116                     authInfo.setUrl(share->url());
0117                 }
0118             } else {
0119                 authInfo.setUrl(networkItem->url());
0120             }
0121 
0122             write(&authInfo);
0123         } else if (networkItem->type() == UnknownNetworkItem) {
0124             Smb4KAuthInfo authInfo;
0125             authInfo.setUserName(networkItem->url().userName());
0126             authInfo.setPassword(networkItem->url().password());
0127             write(&authInfo);
0128         }
0129     }
0130 }
0131 
0132 void Smb4KWalletManager::writeLoginCredentials(Smb4KAuthInfo *authInfo)
0133 {
0134     if (authInfo) {
0135         if (authInfo->type() == Host || authInfo->type() == Share || authInfo->type() == UnknownNetworkItem) {
0136             write(authInfo);
0137         }
0138     }
0139 }
0140 
0141 void Smb4KWalletManager::writeLoginCredentialsList(const QList<Smb4KAuthInfo *> &list)
0142 {
0143     //
0144     // For the sake of simplicity, clear all wallet entries
0145     //
0146     clear();
0147 
0148     //
0149     // Write the new list to the wallet
0150     //
0151     for (Smb4KAuthInfo *authInfo : list) {
0152         write(authInfo);
0153     }
0154 }
0155 
0156 QList<Smb4KAuthInfo *> Smb4KWalletManager::loginCredentialsList()
0157 {
0158     QList<Smb4KAuthInfo *> entries;
0159 
0160     if (init()) {
0161         bool ok = false;
0162         QMap<QString, QMap<QString, QString>> allWalletEntries = d->wallet->mapList(&ok);
0163 
0164         if (ok) {
0165             QMapIterator<QString, QMap<QString, QString>> it(allWalletEntries);
0166 
0167             while (it.hasNext()) {
0168                 it.next();
0169 
0170                 Smb4KAuthInfo *authInfo = new Smb4KAuthInfo();
0171 
0172                 if (it.key() == QStringLiteral("DEFAULT_LOGIN")) {
0173                     authInfo->setUserName(it.value().value(QStringLiteral("Login")));
0174                     authInfo->setPassword(it.value().value(QStringLiteral("Password")));
0175                 } else {
0176                     QUrl url(it.key(), QUrl::TolerantMode);
0177                     authInfo->setUrl(url);
0178                     authInfo->setUserName(it.value().value(QStringLiteral("Login")));
0179                     authInfo->setPassword(it.value().value(QStringLiteral("Password")));
0180                 }
0181 
0182                 entries << authInfo;
0183             }
0184         }
0185     }
0186 
0187     return entries;
0188 }
0189 
0190 bool Smb4KWalletManager::useWalletSystem() const
0191 {
0192     return (KWallet::Wallet::isEnabled() && Smb4KSettings::useWallet());
0193 }
0194 
0195 bool Smb4KWalletManager::hasDefaultCredentials()
0196 {
0197     if (init()) {
0198         if (d->wallet->hasEntry(QStringLiteral("DEFAULT_LOGIN"))) {
0199             return true;
0200         }
0201     }
0202 
0203     return false;
0204 }
0205 
0206 bool Smb4KWalletManager::init()
0207 {
0208     if (useWalletSystem()) {
0209         //
0210         // Get a pointer to the wallet, if we do not have one yet
0211         //
0212         if (!d->wallet) {
0213             //
0214             // Open the wallet synchronously.
0215             //
0216             d->wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), QApplication::activeWindow() ? QApplication::activeWindow()->winId() : 0);
0217 
0218             //
0219             // Check if the wallet was opened successfully. Set the
0220             // right folder in case it was.
0221             //
0222             if (d->wallet) {
0223                 if (d->wallet->isOpen()) {
0224                     if (!d->wallet->hasFolder(QStringLiteral("Smb4K"))) {
0225                         d->wallet->createFolder(QStringLiteral("Smb4K"));
0226                         d->wallet->setFolder(QStringLiteral("Smb4K"));
0227                     } else {
0228                         d->wallet->setFolder(QStringLiteral("Smb4K"));
0229                     }
0230                 } else {
0231                     Smb4KNotification::credentialsNotAccessible();
0232                 }
0233             } else {
0234                 delete d->wallet;
0235                 d->wallet = nullptr;
0236 
0237                 Smb4KNotification::openingWalletFailed(KWallet::Wallet::NetworkWallet());
0238             }
0239         }
0240     } else {
0241         if (d->wallet) {
0242             //
0243             // Close the wallet, if Smb4K is the only application that
0244             // is using it. Thus, use force=false, otherwise it will definitely
0245             // be closed.
0246             //
0247             d->wallet->closeWallet(KWallet::Wallet::NetworkWallet(), false);
0248 
0249             //
0250             // Delete the wallet and set it to 0.
0251             //
0252             delete d->wallet;
0253             d->wallet = nullptr;
0254         }
0255     }
0256 
0257     Q_EMIT initialized();
0258 
0259     return (d->wallet && d->wallet->isOpen());
0260 }
0261 
0262 bool Smb4KWalletManager::read(Smb4KAuthInfo *authInfo)
0263 {
0264     bool success = false;
0265 
0266     if (init()) {
0267         if (authInfo->type() != Smb4KGlobal::UnknownNetworkItem) {
0268             //
0269             // Get the string representation of the URL
0270             //
0271             QString itemUrlString;
0272             QString testString = authInfo->url().toString(QUrl::RemoveUserInfo | QUrl::RemovePort);
0273 
0274             //
0275             // Check if an entry exists for the given URL. If not, try to
0276             // get the correct string / key by a case insensitive comparision.
0277             //
0278             if (!d->wallet->hasEntry(testString)) {
0279                 //
0280                 // Get all keys of the saved login credentials
0281                 //
0282                 QStringList walletEntries = d->wallet->entryList();
0283 
0284                 //
0285                 // Find the correct key for these login credentials
0286                 //
0287                 for (const QString &entry : qAsConst(walletEntries)) {
0288                     if (QString::compare(entry, testString, Qt::CaseInsensitive) == 0) {
0289                         itemUrlString = entry;
0290                         break;
0291                     }
0292                 }
0293             } else {
0294                 itemUrlString = testString;
0295             }
0296 
0297             //
0298             // Read the login credentials from the wallet. Use the default login
0299             // as fallback.
0300             //
0301             if (!itemUrlString.isEmpty()) {
0302                 QMap<QString, QString> credentials;
0303 
0304                 if (d->wallet->readMap(itemUrlString, credentials) == 0) {
0305                     authInfo->setUserName(credentials.value(QStringLiteral("Login")));
0306                     authInfo->setPassword(credentials.value(QStringLiteral("Password")));
0307                     success = true;
0308                 }
0309             } else {
0310                 if (Smb4KSettings::useDefaultLogin()) {
0311                     QMap<QString, QString> credentials;
0312 
0313                     if (d->wallet->readMap(QStringLiteral("DEFAULT_LOGIN"), credentials) == 0) {
0314                         authInfo->setUserName(credentials.value(QStringLiteral("Login")));
0315                         authInfo->setPassword(credentials.value(QStringLiteral("Password")));
0316                         success = true;
0317                     }
0318                 }
0319             }
0320         } else {
0321             if (Smb4KSettings::useDefaultLogin()) {
0322                 QMap<QString, QString> credentials;
0323 
0324                 if (d->wallet->readMap(QStringLiteral("DEFAULT_LOGIN"), credentials) == 0) {
0325                     authInfo->setUserName(credentials.value(QStringLiteral("Login")));
0326                     authInfo->setPassword(credentials.value(QStringLiteral("Password")));
0327                     success = true;
0328                 }
0329             }
0330         }
0331     }
0332 
0333     return success;
0334 }
0335 
0336 void Smb4KWalletManager::write(Smb4KAuthInfo *authInfo)
0337 {
0338     if (init()) {
0339         //
0340         // Get the key for the wallet entry
0341         //
0342         QString key;
0343 
0344         if (authInfo->type() != UnknownNetworkItem) {
0345             key = authInfo->url().toString(QUrl::RemoveUserInfo | QUrl::RemovePort);
0346         } else {
0347             key = QStringLiteral("DEFAULT_LOGIN");
0348         }
0349 
0350         //
0351         // Write the credentials to the wallet.
0352         //
0353         if (!authInfo->userName().isEmpty() /* allow empty passwords */) {
0354             QMap<QString, QString> credentials;
0355             credentials.insert(QStringLiteral("Login"), authInfo->userName());
0356             credentials.insert(QStringLiteral("Password"), authInfo->password());
0357 
0358             if (d->wallet->writeMap(key, credentials) == 0) {
0359                 d->wallet->sync();
0360             }
0361         }
0362 
0363         Q_EMIT credentialsUpdated(authInfo->url());
0364     }
0365 }
0366 
0367 void Smb4KWalletManager::clear()
0368 {
0369     if (init()) {
0370         //
0371         // Get the list of wallet entries
0372         //
0373         QStringList entryList = d->wallet->entryList();
0374 
0375         //
0376         // Remove all wallet entries
0377         //
0378         for (const QString &entry : qAsConst(entryList)) {
0379             d->wallet->removeEntry(entry);
0380         }
0381 
0382         d->wallet->sync();
0383 
0384         Q_EMIT credentialsUpdated(QUrl());
0385     }
0386 }