Warning, file /plasma/plasma-workspace/soliduiserver/soliduiserver.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2005 Jean-Remy Falleri <jr.falleri@laposte.net>
0003     SPDX-FileCopyrightText: 2005-2007 Kevin Ottens <ervin@kde.org>
0004     SPDX-FileCopyrightText: 2007 Alexis Ménard <darktears31@gmail.com>
0005     SPDX-FileCopyrightText: 2011, 2014 Lukas Tinkl <ltinkl@redhat.com>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-only
0008 */
0009 
0010 #include "soliduiserver.h"
0011 #include "config-X11.h"
0012 #include "soliduiserver_debug.h"
0013 
0014 #include <QDBusInterface>
0015 #include <QDBusReply>
0016 #include <QDebug>
0017 #include <QIcon>
0018 
0019 #include <KLocalizedString>
0020 #include <KPluginFactory>
0021 #include <KUserTimestamp>
0022 
0023 #include <kpassworddialog.h>
0024 #include <kwallet.h>
0025 #include <kwindowsystem.h>
0026 
0027 // solid specific includes
0028 #include <solid/device.h>
0029 #include <solid/deviceinterface.h>
0030 #include <solid/devicenotifier.h>
0031 #include <solid/predicate.h>
0032 #include <solid/storagevolume.h>
0033 
0034 K_PLUGIN_CLASS_WITH_JSON(SolidUiServer, "soliduiserver.json")
0035 
0036 SolidUiServer::SolidUiServer(QObject *parent, const QList<QVariant> &)
0037     : KDEDModule(parent)
0038 {
0039 }
0040 
0041 SolidUiServer::~SolidUiServer()
0042 {
0043 }
0044 
0045 void SolidUiServer::showPassphraseDialog(const QString &udi, const QString &returnService, const QString &returnObject, uint wId, const QString &appId)
0046 {
0047     if (m_idToPassphraseDialog.contains(returnService + ':' + udi)) {
0048         KPasswordDialog *dialog = m_idToPassphraseDialog[returnService + ':' + udi];
0049         dialog->activateWindow();
0050         return;
0051     }
0052 
0053     Solid::Device device(udi);
0054 
0055     KPasswordDialog *dialog = new KPasswordDialog(nullptr, KPasswordDialog::ShowKeepPassword);
0056 
0057     QString label = device.vendor();
0058     if (!label.isEmpty())
0059         label += ' ';
0060     label += device.product();
0061 
0062     dialog->setPrompt(i18n("'%1' needs a password to be accessed. Please enter a password.", label));
0063     dialog->setIcon(QIcon::fromTheme(device.icon()));
0064     dialog->setProperty("soliduiserver.udi", udi);
0065     dialog->setProperty("soliduiserver.returnService", returnService);
0066     dialog->setProperty("soliduiserver.returnObject", returnObject);
0067 
0068     QString uuid;
0069     if (device.is<Solid::StorageVolume>())
0070         uuid = device.as<Solid::StorageVolume>()->uuid();
0071 
0072     // read the password from wallet and prefill it to the dialog
0073     if (!uuid.isEmpty()) {
0074         dialog->setProperty("soliduiserver.uuid", uuid);
0075 
0076         KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::LocalWallet(), (WId)wId);
0077         const QString folderName = QString::fromLatin1("SolidLuks");
0078         if (wallet && wallet->hasFolder(folderName)) {
0079             wallet->setFolder(folderName);
0080             QString savedPassword;
0081             if (wallet->readPassword(uuid, savedPassword) == 0) {
0082                 dialog->setKeepPassword(true);
0083                 dialog->setPassword(savedPassword);
0084             }
0085             wallet->closeWallet(wallet->walletName(), false);
0086         }
0087         delete wallet;
0088     }
0089 
0090     connect(dialog, &KPasswordDialog::gotPassword, this, &SolidUiServer::onPassphraseDialogCompleted);
0091     connect(dialog, &KPasswordDialog::rejected, this, &SolidUiServer::onPassphraseDialogRejected);
0092 
0093     m_idToPassphraseDialog[returnService + ':' + udi] = dialog;
0094 
0095     reparentDialog(dialog, (WId)wId, appId, true);
0096     dialog->show();
0097 }
0098 
0099 void SolidUiServer::onPassphraseDialogCompleted(const QString &pass, bool keep)
0100 {
0101     KPasswordDialog *dialog = qobject_cast<KPasswordDialog *>(sender());
0102 
0103     if (dialog) {
0104         QString returnService = dialog->property("soliduiserver.returnService").toString();
0105         QString returnObject = dialog->property("soliduiserver.returnObject").toString();
0106         QDBusInterface returnIface(returnService, returnObject);
0107 
0108         QDBusReply<void> reply = returnIface.call(QStringLiteral("passphraseReply"), pass);
0109 
0110         QString udi = dialog->property("soliduiserver.udi").toString();
0111         m_idToPassphraseDialog.remove(returnService + ':' + udi);
0112 
0113         if (!reply.isValid()) {
0114             qCWarning(SOLIDUISERVER_DEBUG) << "Impossible to send the passphrase to the application, D-Bus said: " << reply.error().name() << ", "
0115                                            << reply.error().message() << Qt::endl;
0116             return; // don't save into wallet if an error occurs
0117         }
0118 
0119         if (keep) { // save the password into the wallet
0120             KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::LocalWallet(), 0);
0121             if (wallet) {
0122                 const QString folderName = QString::fromLatin1("SolidLuks");
0123                 const QString uuid = dialog->property("soliduiserver.uuid").toString();
0124                 if (!wallet->hasFolder(folderName))
0125                     wallet->createFolder(folderName);
0126                 if (wallet->setFolder(folderName))
0127                     wallet->writePassword(uuid, pass);
0128                 wallet->closeWallet(wallet->walletName(), false);
0129                 delete wallet;
0130             }
0131         }
0132     }
0133 }
0134 
0135 void SolidUiServer::onPassphraseDialogRejected()
0136 {
0137     onPassphraseDialogCompleted(QString(), false);
0138 }
0139 
0140 void SolidUiServer::reparentDialog(QWidget *dialog, WId wId, const QString &appId, bool modal)
0141 {
0142     Q_UNUSED(appId);
0143     // Code borrowed from kwalletd
0144 
0145     dialog->setAttribute(Qt::WA_NativeWindow, true);
0146     KWindowSystem::setMainWindow(dialog->windowHandle(), wId); // correct, set dialog parent
0147 
0148 #if HAVE_X11
0149     if (modal) {
0150         KWindowSystem::setState(dialog->winId(), NET::Modal);
0151     } else {
0152         KWindowSystem::clearState(dialog->winId(), NET::Modal);
0153     }
0154 #endif
0155 
0156     // allow dialog activation even if it interrupts, better than trying hacks
0157     // with keeping the dialog on top or on all desktops
0158     KUserTimestamp::updateUserTimestamp();
0159 }
0160 
0161 #include "soliduiserver.moc"