File indexing completed on 2024-06-23 05:13:45
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 commands/selftestcommand.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include <config-kleopatra.h> 0011 0012 #include "selftestcommand.h" 0013 0014 #include "command_p.h" 0015 0016 #include <dialogs/selftestdialog.h> 0017 0018 #include "kleopatra_debug.h" 0019 0020 #ifdef Q_OS_WIN 0021 #include <selftest/registrycheck.h> 0022 #endif 0023 #include <selftest/compliancecheck.h> 0024 #include <selftest/enginecheck.h> 0025 #include <selftest/gpgagentcheck.h> 0026 #include <selftest/gpgconfcheck.h> 0027 #include <selftest/libkleopatrarccheck.h> 0028 #include <selftest/uiservercheck.h> 0029 0030 #include <Libkleo/Stl_Util> 0031 0032 #include <KConfigGroup> 0033 #include <KSharedConfig> 0034 0035 #include <vector> 0036 0037 #include <QGpgME/CryptoConfig> 0038 #include <QGpgME/Protocol> 0039 0040 using namespace Kleo; 0041 using namespace Kleo::Commands; 0042 using namespace Kleo::Dialogs; 0043 0044 #define CURRENT_SELFTEST_VERSION 1 0045 0046 static const char *const components[] = { 0047 nullptr, // gpgconf 0048 "gpg", 0049 "gpg-agent", 0050 "scdaemon", 0051 "gpgsm", 0052 "dirmngr", 0053 }; 0054 static const unsigned int numComponents = sizeof components / sizeof *components; 0055 0056 class SelfTestCommand::Private : Command::Private 0057 { 0058 friend class ::Kleo::Commands::SelfTestCommand; 0059 SelfTestCommand *q_func() const 0060 { 0061 return static_cast<SelfTestCommand *>(q); 0062 } 0063 0064 public: 0065 explicit Private(SelfTestCommand *qq, KeyListController *c); 0066 ~Private() override; 0067 0068 private: 0069 void init(); 0070 0071 void ensureDialogCreated() 0072 { 0073 if (dialog) { 0074 return; 0075 } 0076 dialog = new SelfTestDialog; 0077 applyWindowID(dialog); 0078 dialog->setAttribute(Qt::WA_DeleteOnClose); 0079 0080 connect(dialog, &SelfTestDialog::updateRequested, q_func(), [this]() { 0081 slotUpdateRequested(); 0082 }); 0083 connect(dialog, &QDialog::accepted, q_func(), [this]() { 0084 slotDialogAccepted(); 0085 }); 0086 connect(dialog, &QDialog::rejected, q_func(), [this]() { 0087 slotDialogRejected(); 0088 }); 0089 0090 dialog->setRunAtStartUp(runAtStartUp()); 0091 dialog->setAutomaticMode(automatic); 0092 } 0093 0094 void ensureDialogShown() 0095 { 0096 ensureDialogCreated(); 0097 if (dialog->isVisible()) { 0098 dialog->raise(); 0099 } else { 0100 dialog->show(); 0101 } 0102 } 0103 0104 bool runAtStartUp() const 0105 { 0106 const KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Self-Test")); 0107 0108 if (config.readEntry("run-at-startup", false)) { 0109 qCDebug(KLEOPATRA_LOG) << "Selftest forced"; 0110 return true; 0111 } 0112 #ifdef Q_OS_WIN 0113 /* On Windows the selftest only needs to run once as we control 0114 * the distribution of both GnuPG and Kleopatra together. While 0115 * under Linux it is more important to check for installation 0116 * incositencies. Under Windows it is also more rarely that 0117 * multiple versions of GnuPG run in the same home directory and 0118 * might interfer with their config files. */ 0119 const int lastVersionRun = config.readEntry("last-selftest-version", 0); 0120 if (lastVersionRun < CURRENT_SELFTEST_VERSION) { 0121 qCDebug(KLEOPATRA_LOG) << "Last successful selftest:" << lastVersionRun << "starting it."; 0122 return true; 0123 } 0124 return false; 0125 #endif 0126 return config.readEntry("run-at-startup", true); 0127 } 0128 0129 void setRunAtStartUp(bool on) 0130 { 0131 KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Self-Test")); 0132 config.writeEntry("run-at-startup", on); 0133 } 0134 0135 void runTests() 0136 { 0137 std::vector<std::shared_ptr<Kleo::SelfTest>> tests; 0138 0139 #if defined(Q_OS_WIN) 0140 qCDebug(KLEOPATRA_LOG) << "Checking Windows Registry..."; 0141 tests.push_back(makeGpgProgramRegistryCheckSelfTest()); 0142 qCDebug(KLEOPATRA_LOG) << "Checking Ui Server connectivity..."; 0143 tests.push_back(makeUiServerConnectivitySelfTest()); 0144 #endif 0145 qCDebug(KLEOPATRA_LOG) << "Checking gpg installation..."; 0146 tests.push_back(makeGpgEngineCheckSelfTest()); 0147 qCDebug(KLEOPATRA_LOG) << "Checking gpgsm installation..."; 0148 tests.push_back(makeGpgSmEngineCheckSelfTest()); 0149 qCDebug(KLEOPATRA_LOG) << "Checking gpgconf installation..."; 0150 tests.push_back(makeGpgConfEngineCheckSelfTest()); 0151 for (unsigned int i = 0; i < numComponents; ++i) { 0152 qCDebug(KLEOPATRA_LOG) << "Checking configuration of:" << components[i]; 0153 tests.push_back(makeGpgConfCheckConfigurationSelfTest(components[i])); 0154 } 0155 #ifndef Q_OS_WIN 0156 tests.push_back(makeGpgAgentConnectivitySelfTest()); 0157 #endif 0158 tests.push_back(makeDeVSComplianceCheckSelfTest()); 0159 tests.push_back(makeLibKleopatraRcSelfTest()); 0160 0161 if (!dialog && std::none_of(tests.cbegin(), tests.cend(), [](const std::shared_ptr<SelfTest> &test) { 0162 return test->failed(); 0163 })) { 0164 finished(); 0165 KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Self-Test")); 0166 config.writeEntry("last-selftest-version", CURRENT_SELFTEST_VERSION); 0167 return; 0168 } 0169 0170 ensureDialogCreated(); 0171 0172 dialog->setTests(tests); 0173 0174 ensureDialogShown(); 0175 } 0176 0177 private: 0178 void slotDialogAccepted() 0179 { 0180 setRunAtStartUp(dialog->runAtStartUp()); 0181 finished(); 0182 } 0183 void slotDialogRejected() 0184 { 0185 if (automatic) { 0186 canceled = true; 0187 Command::Private::canceled(); 0188 } else { 0189 slotDialogAccepted(); 0190 } 0191 } 0192 void slotUpdateRequested() 0193 { 0194 const auto conf = QGpgME::cryptoConfig(); 0195 if (conf) { 0196 conf->clear(); 0197 } 0198 runTests(); 0199 } 0200 0201 private: 0202 QPointer<SelfTestDialog> dialog; 0203 bool canceled; 0204 bool automatic; 0205 }; 0206 0207 SelfTestCommand::Private *SelfTestCommand::d_func() 0208 { 0209 return static_cast<Private *>(d.get()); 0210 } 0211 const SelfTestCommand::Private *SelfTestCommand::d_func() const 0212 { 0213 return static_cast<const Private *>(d.get()); 0214 } 0215 0216 #define d d_func() 0217 #define q q_func() 0218 0219 SelfTestCommand::Private::Private(SelfTestCommand *qq, KeyListController *c) 0220 : Command::Private(qq, c) 0221 , dialog() 0222 , canceled(false) 0223 , automatic(false) 0224 { 0225 } 0226 0227 SelfTestCommand::Private::~Private() 0228 { 0229 } 0230 0231 SelfTestCommand::SelfTestCommand(KeyListController *c) 0232 : Command(new Private(this, c)) 0233 { 0234 d->init(); 0235 } 0236 0237 SelfTestCommand::SelfTestCommand(QAbstractItemView *v, KeyListController *c) 0238 : Command(v, new Private(this, c)) 0239 { 0240 d->init(); 0241 } 0242 0243 void SelfTestCommand::Private::init() 0244 { 0245 } 0246 0247 SelfTestCommand::~SelfTestCommand() 0248 { 0249 } 0250 0251 void SelfTestCommand::setAutomaticMode(bool on) 0252 { 0253 d->automatic = on; 0254 if (d->dialog) { 0255 d->dialog->setAutomaticMode(on); 0256 } 0257 } 0258 0259 bool SelfTestCommand::isCanceled() const 0260 { 0261 return d->canceled; 0262 } 0263 0264 void SelfTestCommand::doStart() 0265 { 0266 if (d->automatic) { 0267 if (!d->runAtStartUp()) { 0268 d->finished(); 0269 return; 0270 } 0271 } else { 0272 d->ensureDialogCreated(); 0273 } 0274 0275 d->runTests(); 0276 } 0277 0278 void SelfTestCommand::doCancel() 0279 { 0280 d->canceled = true; 0281 if (d->dialog) { 0282 d->dialog->close(); 0283 } 0284 d->dialog = nullptr; 0285 } 0286 0287 #undef d 0288 #undef q 0289 0290 #include "moc_selftestcommand.cpp"