File indexing completed on 2024-05-19 05:55:45

0001 /*
0002     SPDX-FileCopyrightText: 2003 George Staikos <staikos@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "../kwalletmanager_version.h"
0008 #include "konfigurator.h"
0009 
0010 #include <KAuth/Action>
0011 #include <KAuth/ActionReply>
0012 #include <KAuth/ExecuteJob>
0013 #include <KConfigGroup>
0014 #include <KMessageBox>
0015 #include <KPluginFactory>
0016 #include <KWallet>
0017 #include <QInputDialog>
0018 #include <kauth_version.h>
0019 
0020 #include <KAboutData>
0021 
0022 #include <QDebug>
0023 #include <QCheckBox>
0024 #include <QMenu>
0025 #include <QProcess>
0026 #include <QFile>
0027 #include <QPushButton>
0028 #include <QDBusConnection>
0029 #include <QDBusInterface>
0030 #include <QDBusConnectionInterface>
0031 #include <QVBoxLayout>
0032 
0033 #define KWALLETMANAGERINTERFACE "org.kde.KWallet"
0034 
0035 K_PLUGIN_CLASS_WITH_JSON(KWalletConfig, "kwalletconfig.json")
0036 
0037 KWalletConfig::KWalletConfig(QObject *parent, const KPluginMetaData &data)
0038     : KCModule(parent, data)
0039       , _wcw(new WalletConfigWidget(widget()))
0040       , _cfg(KSharedConfig::openConfig(QStringLiteral("kwalletrc"), KConfig::NoGlobals))
0041 {
0042   setAuthActionName(QStringLiteral("org.kde.kcontrol.kcmkwallet5.save"));
0043     auto vbox = new QVBoxLayout(widget());
0044     vbox->setContentsMargins(0, 0, 0, 0);
0045     vbox->addWidget(_wcw);
0046 
0047     connect(_wcw->_enabled, &QCheckBox::clicked, this, &KWalletConfig::configChanged);
0048     connect(_wcw->_launchManager, &QCheckBox::clicked, this, &KWalletConfig::configChanged);
0049     connect(_wcw->_autocloseManager, &QCheckBox::clicked, this, &KWalletConfig::configChanged);
0050     connect(_wcw->_autoclose, &QCheckBox::clicked, this, &KWalletConfig::configChanged);
0051     connect(_wcw->_closeIdle, &QCheckBox::clicked, this, &KWalletConfig::configChanged);
0052     connect(_wcw->_openPrompt, &QCheckBox::clicked, this, &KWalletConfig::configChanged);
0053     connect(_wcw->_screensaverLock, &QCheckBox::clicked, this, &KWalletConfig::configChanged);
0054     connect(_wcw->_localWalletSelected, &QCheckBox::clicked, this, &KWalletConfig::configChanged);
0055     connect(_wcw->_idleTime, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &KWalletConfig::configChanged);
0056     connect(_wcw->_launch, &QPushButton::clicked, this, &KWalletConfig::launchManager);
0057     connect(_wcw->_newWallet, &QPushButton::clicked, this, &KWalletConfig::newNetworkWallet);
0058     connect(_wcw->_newLocalWallet, &QPushButton::clicked, this, &KWalletConfig::newLocalWallet);
0059     connect(_wcw->_localWallet, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &KWalletConfig::configChanged);
0060     connect(_wcw->_defaultWallet, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &KWalletConfig::configChanged);
0061     connect(_wcw->_accessList, &QTreeWidget::customContextMenuRequested, this, &KWalletConfig::customContextMenuRequested);
0062     connect(_wcw->_secretServiceAPI, &QCheckBox::clicked, this, &KWalletConfig::configChanged);
0063 
0064     _wcw->_accessList->setAllColumnsShowFocus(true);
0065     _wcw->_accessList->setContextMenuPolicy(Qt::CustomContextMenu);
0066     updateWalletLists();
0067 
0068     if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.kwalletmanager"))) {
0069         _wcw->_launch->hide();
0070     }
0071 
0072 }
0073 
0074 KWalletConfig::~KWalletConfig() = default;
0075 
0076 void KWalletConfig::updateWalletLists()
0077 {
0078     const QString p1(_wcw->_localWallet->currentText());
0079     const QString p2(_wcw->_defaultWallet->currentText());
0080 
0081     _wcw->_localWallet->clear();
0082     _wcw->_defaultWallet->clear();
0083 
0084     const QStringList wl = KWallet::Wallet::walletList();
0085     _wcw->_localWallet->addItems(wl);
0086     _wcw->_defaultWallet->addItems(wl);
0087 
0088     int index = wl.indexOf(p1);
0089     if (index != -1) {
0090         _wcw->_localWallet->setCurrentIndex(index);
0091     }
0092 
0093     index = wl.indexOf(p2);
0094     if (index != -1) {
0095         _wcw->_defaultWallet->setCurrentIndex(index);
0096     }
0097 }
0098 
0099 QString KWalletConfig::newWallet()
0100 {
0101     bool ok;
0102     const QString n = QInputDialog::getText(widget(), i18n("New Wallet"),
0103                                             i18n("Please choose a name for the new wallet:"),
0104                                             QLineEdit::Normal, QString(),
0105                                             &ok);
0106     if (!ok) {
0107         return {};
0108     }
0109     KWallet::Wallet *w = KWallet::Wallet::openWallet(n, widget()->topLevelWidget()->winId());
0110     if (!w) {
0111         return {};
0112     }
0113 
0114     delete w;
0115     return n;
0116 }
0117 
0118 void KWalletConfig::newLocalWallet()
0119 {
0120     const QString n = newWallet();
0121     if (n.trimmed().isEmpty()) {
0122         return;
0123     }
0124 
0125     updateWalletLists();
0126 
0127     _wcw->_localWallet->setCurrentIndex(_wcw->_localWallet->findText(n));
0128         setNeedsSave(true);
0129 }
0130 
0131 void KWalletConfig::newNetworkWallet()
0132 {
0133     const QString n = newWallet();
0134     if (n.trimmed().isEmpty()) {
0135         return;
0136     }
0137 
0138     updateWalletLists();
0139 
0140     _wcw->_defaultWallet->setCurrentIndex(_wcw->_defaultWallet->findText(n));
0141         setNeedsSave(true);
0142 }
0143 
0144 void KWalletConfig::launchManager()
0145 {
0146     if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.kwalletmanager5"))) {
0147         QProcess::startDetached(QStringLiteral("kwalletmanager5"), QStringList(QStringLiteral("--show")));
0148     } else {
0149         QDBusInterface kwalletd(QStringLiteral("org.kde.kwalletmanager5"), QStringLiteral("/kwalletmanager5/MainWindow_1"));
0150         kwalletd.call(QStringLiteral("show"));
0151         kwalletd.call(QStringLiteral("raise"));
0152     }
0153 }
0154 
0155 void KWalletConfig::configChanged()
0156 {
0157         setNeedsSave(true);
0158 }
0159 
0160 void KWalletConfig::load()
0161 {
0162     KConfigGroup config(_cfg, QStringLiteral("Wallet"));
0163     _wcw->_enabled->setChecked(config.readEntry("Enabled", true));
0164     _wcw->_openPrompt->setChecked(config.readEntry("Prompt on Open", false));
0165     _wcw->_launchManager->setChecked(config.readEntry("Launch Manager", false));
0166     _wcw->_autocloseManager->setChecked(! config.readEntry("Leave Manager Open", false));
0167     _wcw->_screensaverLock->setChecked(config.readEntry("Close on Screensaver", false));
0168     _wcw->_autoclose->setChecked(!config.readEntry("Leave Open", true));
0169     _wcw->_closeIdle->setChecked(config.readEntry("Close When Idle", false));
0170     _wcw->_idleTime->setValue(config.readEntry("Idle Timeout", 10));
0171     if (config.hasKey("Default Wallet")) {
0172         int defaultWallet_idx = _wcw->_defaultWallet->findText(config.readEntry("Default Wallet"));
0173         if (defaultWallet_idx != -1) {
0174             _wcw->_defaultWallet->setCurrentIndex(defaultWallet_idx);
0175         } else {
0176             _wcw->_defaultWallet->setCurrentIndex(0);
0177         }
0178     } else {
0179         _wcw->_defaultWallet->setCurrentIndex(0);
0180     }
0181     if (config.hasKey("Local Wallet")) {
0182         _wcw->_localWalletSelected->setChecked(!config.readEntry("Use One Wallet", false));
0183         int localWallet_idx = _wcw->_localWallet->findText(config.readEntry("Local Wallet"));
0184         if (localWallet_idx != -1) {
0185             _wcw->_localWallet->setCurrentIndex(localWallet_idx);
0186         } else {
0187             _wcw->_localWallet->setCurrentIndex(0);
0188         }
0189     } else {
0190         _wcw->_localWalletSelected->setChecked(false);
0191     }
0192     _wcw->_accessList->clear();
0193     KConfigGroup ad(_cfg, QStringLiteral("Auto Deny"));
0194     KConfigGroup aa(_cfg, QStringLiteral("Auto Allow"));
0195     QStringList denykeys = ad.entryMap().keys();
0196     const QStringList keys = aa.entryMap().keys();
0197     for (QStringList::const_iterator i = keys.begin(); i != keys.end(); ++i) {
0198         QString walletName = *i;
0199         // perform cleanup in the kwalletrc file, by removing entries that correspond to non-existent
0200         // (previously deleted, for example) wallets
0201         QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
0202         path.append(QStringLiteral("/kwalletd/%1.kwl").arg(walletName));
0203         if (!QFile::exists(path)) {
0204             // if the wallet no longer exists, delete the entries from the configuration file and skip to next entry
0205             KConfigGroup cfgAllow = KSharedConfig::openConfig(QStringLiteral("kwalletrc"))->group(QStringLiteral("Auto Allow"));
0206             cfgAllow.deleteEntry(walletName);
0207 
0208             KConfigGroup cfgDeny = KSharedConfig::openConfig(QStringLiteral("kwalletrc"))->group(QStringLiteral("Auto Deny"));
0209             cfgDeny.deleteEntry(walletName);
0210             continue;
0211         }
0212 
0213         const QStringList apps = aa.readEntry(*i, QStringList());
0214         const QStringList denyapps = ad.readEntry(*i, QStringList());
0215         denykeys.removeAll(walletName);
0216         auto twi = new QTreeWidgetItem(_wcw->_accessList, QStringList() << walletName);
0217 
0218         for (QStringList::const_iterator j = apps.begin(), end = apps.end(); j != end; ++j) {
0219             new QTreeWidgetItem(twi, QStringList() << QString() << *j << i18n("Always Allow"));
0220         }
0221         for (QStringList::const_iterator j = denyapps.begin(), end = denyapps.end(); j != end; ++j) {
0222             new QTreeWidgetItem(twi, QStringList() << QString() << *j << i18n("Always Deny"));
0223         }
0224     }
0225     for (QStringList::const_iterator i = denykeys.constBegin(), denykeysEnd = denykeys.constEnd(); i != denykeysEnd; ++i) {
0226         const QStringList denyapps = ad.readEntry(*i, QStringList());
0227         auto twi = new QTreeWidgetItem(_wcw->_accessList, QStringList() << *i);
0228         for (QStringList::const_iterator j = denyapps.begin(), denyappsEnd = denyapps.end(); j != denyappsEnd; ++j) {
0229             new QTreeWidgetItem(twi, QStringList() << QString() << *j << i18n("Always Deny"));
0230         }
0231     }
0232     _wcw->_accessList->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
0233 
0234     KConfigGroup secretsAPIConfig(_cfg, QStringLiteral("org.freedesktop.secrets"));
0235     _wcw->_secretServiceAPI->setChecked(secretsAPIConfig.readEntry("apiEnabled", true));
0236         setNeedsSave(false);
0237 }
0238 
0239 void KWalletConfig::save()
0240 {
0241     QVariantMap args;
0242     KAuth::Action action(QLatin1String("org.kde.kcontrol.kcmkwallet5.save"));
0243     action.setHelperId(QStringLiteral("org.kde.kcontrol.kcmkwallet5"));
0244 
0245     widget()->window()->winId();
0246     action.setParentWindow(widget()->window()->windowHandle());
0247     if (!action.isValid()) {
0248         qDebug() << "There's no authAction, not saving settings";
0249         return;
0250     }
0251     action.setArguments(args);
0252 
0253     KAuth::ExecuteJob *j = action.execute();
0254 
0255     if (!j->exec()) {
0256         if (j->error() == KAuth::ActionReply::AuthorizationDeniedError) {
0257             KMessageBox::error(widget(), i18n("Permission denied."), i18n("KDE Wallet Control Module"));
0258         } else {
0259             KMessageBox::error(widget(), i18n("Error while authenticating action:\n%1", j->errorString()), i18n("KDE Wallet Control Module"));
0260         }
0261         load();
0262         return;
0263     }
0264 
0265     KConfigGroup config(_cfg, QStringLiteral("Wallet"));
0266     config.writeEntry("Enabled", _wcw->_enabled->isChecked());
0267     config.writeEntry("Launch Manager", _wcw->_launchManager->isChecked());
0268     config.writeEntry("Leave Manager Open", !_wcw->_autocloseManager->isChecked());
0269     config.writeEntry("Leave Open", !_wcw->_autoclose->isChecked());
0270     config.writeEntry("Close When Idle", _wcw->_closeIdle->isChecked());
0271     config.writeEntry("Idle Timeout", _wcw->_idleTime->value());
0272     config.writeEntry("Prompt on Open", _wcw->_openPrompt->isChecked());
0273     config.writeEntry("Close on Screensaver", _wcw->_screensaverLock->isChecked());
0274 
0275     config.writeEntry("Use One Wallet", !_wcw->_localWalletSelected->isChecked());
0276     if (_wcw->_localWalletSelected->isChecked()) {
0277         config.writeEntry("Local Wallet", _wcw->_localWallet->currentText());
0278     } else {
0279         config.deleteEntry("Local Wallet");
0280     }
0281 
0282     if (_wcw->_defaultWallet->currentIndex() != -1) {
0283         config.writeEntry("Default Wallet", _wcw->_defaultWallet->currentText());
0284     } else {
0285         config.deleteEntry("Default Wallet");
0286     }
0287 
0288     // FIXME: won't survive a language change
0289     _cfg->deleteGroup(QStringLiteral("Auto Allow"));
0290     _cfg->deleteGroup(QStringLiteral("Auto Deny"));
0291     config  = _cfg->group(QStringLiteral("Auto Allow"));
0292     for (int i = 0; i < _wcw->_accessList->topLevelItemCount(); ++i) {
0293         QTreeWidgetItem *parentItem = _wcw->_accessList->topLevelItem(i);
0294         QStringList al;
0295         for (int j = 0; j < parentItem->childCount(); ++j) {
0296             QTreeWidgetItem *childItem = parentItem->child(j);
0297             if (childItem->text(2) == i18n("Always Allow")) {
0298                 al << childItem->text(1);
0299             }
0300         }
0301         config.writeEntry(parentItem->text(0), al);
0302     }
0303 
0304     config = _cfg->group(QStringLiteral("Auto Deny"));
0305     for (int i = 0; i < _wcw->_accessList->topLevelItemCount(); ++i) {
0306         QTreeWidgetItem *parentItem = _wcw->_accessList->topLevelItem(i);
0307         QStringList al;
0308         for (int j = 0; j < parentItem->childCount(); ++j) {
0309             QTreeWidgetItem *childItem = parentItem->child(j);
0310             if (childItem->text(2) == i18n("Always Deny")) {
0311                 al << childItem->text(1);
0312             }
0313         }
0314         config.writeEntry(parentItem->text(0), al);
0315     }
0316 
0317     KConfigGroup secretsAPIConfig(_cfg, QStringLiteral("org.freedesktop.secrets"));
0318     secretsAPIConfig.writeEntry("apiEnabled", _wcw->_secretServiceAPI->isChecked());
0319 
0320     _cfg->sync();
0321 
0322     // this restarts kwalletd if necessary
0323     QDBusInterface kwalletd(QStringLiteral("org.kde.kwalletd5"), QStringLiteral("/modules/kwalletd"), QStringLiteral(KWALLETMANAGERINTERFACE));
0324     // if wallet was deactivated, then kwalletd will exit upon start so check
0325     // the status before invoking reconfigure
0326     if (kwalletd.isValid()) {
0327         // this will eventually make kwalletd exit upon deactivation
0328         kwalletd.call(QStringLiteral("reconfigure"));
0329     }
0330         setNeedsSave(false);
0331 }
0332 
0333 void KWalletConfig::defaults()
0334 {
0335     _wcw->_enabled->setChecked(true);
0336     _wcw->_openPrompt->setChecked(false);
0337     _wcw->_launchManager->setChecked(true);
0338     _wcw->_autocloseManager->setChecked(false);
0339     _wcw->_screensaverLock->setChecked(false);
0340     _wcw->_autoclose->setChecked(true);
0341     _wcw->_closeIdle->setChecked(false);
0342     _wcw->_idleTime->setValue(10);
0343     _wcw->_defaultWallet->setCurrentIndex(0);
0344     _wcw->_localWalletSelected->setChecked(false);
0345     _wcw->_localWallet->setCurrentIndex(0);
0346     _wcw->_accessList->clear();
0347     _wcw->_secretServiceAPI->setChecked(true);
0348         setNeedsSave(true);
0349 }
0350 
0351 void KWalletConfig::customContextMenuRequested(const QPoint &pos)
0352 {
0353     QTreeWidgetItem *item = _wcw->_accessList->itemAt(pos);
0354     if (item && item->parent()) {
0355         auto m = new QMenu(widget());
0356         m->setTitle(item->parent()->text(0));
0357         m->addAction(i18n("&Delete"), Qt::Key_Delete, this, &KWalletConfig::deleteEntry);
0358         m->exec(_wcw->_accessList->mapToGlobal(pos));
0359         delete m;
0360     }
0361 }
0362 
0363 void KWalletConfig::deleteEntry()
0364 {
0365     QList<QTreeWidgetItem *> items = _wcw->_accessList->selectedItems();
0366     if (items.count() == 1 && items[0]) {
0367         delete items[0];
0368         setNeedsSave(true);
0369     }
0370 }
0371 
0372 #include "konfigurator.moc"
0373 
0374 #include "moc_konfigurator.cpp"