File indexing completed on 2024-06-23 05:14:10
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 newcertificatewizard/resultpage.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB 0006 SPDX-FileCopyrightText: 2016, 2017 Bundesamt für Sicherheit in der Informationstechnik 0007 SPDX-FileContributor: Intevation GmbH 0008 SPDX-FileCopyrightText: 2022 g10 Code GmbH 0009 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de> 0010 0011 SPDX-License-Identifier: GPL-2.0-or-later 0012 */ 0013 0014 #include <config-kleopatra.h> 0015 0016 #include "resultpage_p.h" 0017 0018 #include "commands/exportcertificatecommand.h" 0019 #include "commands/exportopenpgpcertstoservercommand.h" 0020 #include "commands/exportsecretkeycommand.h" 0021 #include "utils/dragqueen.h" 0022 #include "utils/email.h" 0023 #include "utils/filedialog.h" 0024 #include "utils/scrollarea.h" 0025 0026 #include <Libkleo/KeyCache> 0027 0028 #include <KConfigGroup> 0029 #include <KLocalizedString> 0030 #include <KMessageBox> 0031 #include <KSharedConfig> 0032 0033 #include <QGroupBox> 0034 #include <QHBoxLayout> 0035 #include <QLineEdit> 0036 #include <QPushButton> 0037 #include <QTextBrowser> 0038 #include <QVBoxLayout> 0039 0040 #include <gpgme++/key.h> 0041 0042 #include "kleopatra_debug.h" 0043 0044 using namespace Kleo; 0045 using namespace Kleo::Commands; 0046 using namespace Kleo::NewCertificateUi; 0047 using namespace GpgME; 0048 0049 struct ResultPage::UI { 0050 QTextBrowser *resultTB = nullptr; 0051 QTextBrowser *errorTB = nullptr; 0052 DragQueen *dragQueen = nullptr; 0053 QPushButton *restartWizardPB = nullptr; 0054 QGroupBox *nextStepsGB = nullptr; 0055 QPushButton *saveRequestToFilePB = nullptr; 0056 QPushButton *sendRequestByEMailPB = nullptr; 0057 QPushButton *makeBackupPB = nullptr; 0058 QPushButton *sendCertificateByEMailPB = nullptr; 0059 QPushButton *uploadToKeyserverPB = nullptr; 0060 QPushButton *createRevocationRequestPB = nullptr; 0061 QPushButton *createSigningCertificatePB = nullptr; 0062 QPushButton *createEncryptionCertificatePB = nullptr; 0063 0064 UI(QWizardPage *parent) 0065 { 0066 auto mainLayout = new QVBoxLayout{parent}; 0067 const auto margins = mainLayout->contentsMargins(); 0068 mainLayout->setContentsMargins(margins.left(), 0, margins.right(), 0); 0069 0070 auto scrollArea = new ScrollArea{parent}; 0071 scrollArea->setFocusPolicy(Qt::NoFocus); 0072 scrollArea->setFrameStyle(QFrame::NoFrame); 0073 scrollArea->setBackgroundRole(parent->backgroundRole()); 0074 scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0075 scrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents); 0076 auto scrollAreaLayout = qobject_cast<QBoxLayout *>(scrollArea->widget()->layout()); 0077 scrollAreaLayout->setContentsMargins(0, margins.top(), 0, margins.bottom()); 0078 0079 auto resultGB = new QGroupBox{i18nc("@title:group", "Result"), parent}; 0080 auto resultGBLayout = new QHBoxLayout{resultGB}; 0081 0082 resultTB = new QTextBrowser{resultGB}; 0083 resultGBLayout->addWidget(resultTB); 0084 0085 errorTB = new QTextBrowser{resultGB}; 0086 resultGBLayout->addWidget(errorTB); 0087 0088 dragQueen = new Kleo::DragQueen{resultGB}; 0089 dragQueen->setToolTip(i18n("Drag this icon to your mail application's composer to attach the request to a mail.")); 0090 dragQueen->setAlignment(Qt::AlignCenter); 0091 resultGBLayout->addWidget(dragQueen); 0092 0093 scrollAreaLayout->addWidget(resultGB); 0094 0095 restartWizardPB = new QPushButton{i18n("Restart This Wizard (Keeps Your Parameters)"), parent}; 0096 0097 scrollAreaLayout->addWidget(restartWizardPB); 0098 0099 nextStepsGB = new QGroupBox{i18nc("@title:group", "Next Steps"), parent}; 0100 auto nextStepsGBLayout = new QVBoxLayout{nextStepsGB}; 0101 0102 saveRequestToFilePB = new QPushButton{i18n("Save Certificate Request To File..."), nextStepsGB}; 0103 nextStepsGBLayout->addWidget(saveRequestToFilePB); 0104 0105 sendRequestByEMailPB = new QPushButton{i18n("Send Certificate Request By EMail..."), nextStepsGB}; 0106 nextStepsGBLayout->addWidget(sendRequestByEMailPB); 0107 0108 makeBackupPB = new QPushButton{i18n("Make a Backup Of Your Key Pair..."), nextStepsGB}; 0109 nextStepsGBLayout->addWidget(makeBackupPB); 0110 0111 sendCertificateByEMailPB = new QPushButton{i18n("Send Public Key By EMail..."), nextStepsGB}; 0112 nextStepsGBLayout->addWidget(sendCertificateByEMailPB); 0113 0114 uploadToKeyserverPB = new QPushButton{i18n("Upload Public Key To Directory Service..."), nextStepsGB}; 0115 nextStepsGBLayout->addWidget(uploadToKeyserverPB); 0116 0117 createRevocationRequestPB = new QPushButton{i18n("Create Revocation Request..."), nextStepsGB}; 0118 nextStepsGBLayout->addWidget(createRevocationRequestPB); 0119 0120 createSigningCertificatePB = new QPushButton{i18n("Create Signing Certificate With Same Parameters"), nextStepsGB}; 0121 nextStepsGBLayout->addWidget(createSigningCertificatePB); 0122 0123 createEncryptionCertificatePB = new QPushButton{i18n("Create Encryption Certificate With Same Parameters"), nextStepsGB}; 0124 nextStepsGBLayout->addWidget(createEncryptionCertificatePB); 0125 0126 scrollAreaLayout->addWidget(nextStepsGB); 0127 0128 mainLayout->addWidget(scrollArea); 0129 } 0130 }; 0131 0132 ResultPage::ResultPage(QWidget *p) 0133 : WizardPage{p} 0134 , ui{new UI{this}} 0135 , initialized{false} 0136 , successfullyCreatedSigningCertificate{false} 0137 , successfullyCreatedEncryptionCertificate{false} 0138 { 0139 setObjectName(QString::fromUtf8("Kleo__NewCertificateUi__ResultPage")); 0140 0141 connect(ui->saveRequestToFilePB, &QPushButton::clicked, this, &ResultPage::slotSaveRequestToFile); 0142 connect(ui->sendRequestByEMailPB, &QPushButton::clicked, this, &ResultPage::slotSendRequestByEMail); 0143 connect(ui->sendCertificateByEMailPB, &QPushButton::clicked, this, &ResultPage::slotSendCertificateByEMail); 0144 connect(ui->uploadToKeyserverPB, &QPushButton::clicked, this, &ResultPage::slotUploadCertificateToDirectoryServer); 0145 connect(ui->makeBackupPB, &QPushButton::clicked, this, &ResultPage::slotBackupCertificate); 0146 connect(ui->createRevocationRequestPB, &QPushButton::clicked, this, &ResultPage::slotCreateRevocationRequest); 0147 connect(ui->createSigningCertificatePB, &QPushButton::clicked, this, &ResultPage::slotCreateSigningCertificate); 0148 connect(ui->createEncryptionCertificatePB, &QPushButton::clicked, this, &ResultPage::slotCreateEncryptionCertificate); 0149 0150 ui->dragQueen->setPixmap(QIcon::fromTheme(QStringLiteral("kleopatra")).pixmap(64, 64)); 0151 registerField(QStringLiteral("error"), ui->errorTB, "plainText"); 0152 registerField(QStringLiteral("result"), ui->resultTB, "plainText"); 0153 registerField(QStringLiteral("url"), ui->dragQueen, "url"); 0154 // hidden field, since QWizard can't deal with non-widget-backed fields... 0155 auto le = new QLineEdit(this); 0156 le->hide(); 0157 registerField(QStringLiteral("fingerprint"), le); 0158 } 0159 0160 ResultPage::~ResultPage() = default; 0161 0162 void ResultPage::initializePage() 0163 { 0164 const bool error = isError(); 0165 0166 if (error) { 0167 setTitle(i18nc("@title", "Key Creation Failed")); 0168 setSubTitle(i18n("Key pair creation failed. Please find details about the failure below.")); 0169 } else { 0170 setTitle(i18nc("@title", "Key Pair Successfully Created")); 0171 setSubTitle(i18n("Your new key pair was created successfully. Please find details on the result and some suggested next steps below.")); 0172 } 0173 0174 ui->resultTB->setVisible(!error); 0175 ui->errorTB->setVisible(error); 0176 ui->dragQueen->setVisible(!error && !pgp()); 0177 ui->restartWizardPB->setVisible(error); 0178 ui->nextStepsGB->setVisible(!error); 0179 ui->saveRequestToFilePB->setVisible(!pgp()); 0180 ui->makeBackupPB->setVisible(pgp()); 0181 ui->createRevocationRequestPB->setVisible(pgp() && false); // not implemented 0182 0183 ui->sendCertificateByEMailPB->setVisible(pgp()); 0184 ui->sendRequestByEMailPB->setVisible(!pgp()); 0185 ui->uploadToKeyserverPB->setVisible(pgp()); 0186 0187 if (!error && !pgp()) { 0188 if (signingAllowed() && !encryptionAllowed()) { 0189 successfullyCreatedSigningCertificate = true; 0190 } else if (!signingAllowed() && encryptionAllowed()) { 0191 successfullyCreatedEncryptionCertificate = true; 0192 } else { 0193 successfullyCreatedEncryptionCertificate = successfullyCreatedSigningCertificate = true; 0194 } 0195 } 0196 0197 ui->createSigningCertificatePB->setVisible(successfullyCreatedEncryptionCertificate && !successfullyCreatedSigningCertificate); 0198 ui->createEncryptionCertificatePB->setVisible(successfullyCreatedSigningCertificate && !successfullyCreatedEncryptionCertificate); 0199 0200 if (error) { 0201 wizard()->setOptions(wizard()->options() & ~QWizard::NoCancelButtonOnLastPage); 0202 } else { 0203 wizard()->setOptions(wizard()->options() | QWizard::NoCancelButtonOnLastPage); 0204 } 0205 0206 if (!initialized) { 0207 connect(ui->restartWizardPB, &QAbstractButton::clicked, this, [this]() { 0208 restartAtEnterDetailsPage(); 0209 }); 0210 } 0211 initialized = true; 0212 } 0213 0214 bool ResultPage::isError() const 0215 { 0216 return !ui->errorTB->document()->isEmpty(); 0217 } 0218 0219 bool ResultPage::isComplete() const 0220 { 0221 return !isError(); 0222 } 0223 0224 Key ResultPage::key() const 0225 { 0226 return KeyCache::instance()->findByFingerprint(fingerprint().toLatin1().constData()); 0227 } 0228 0229 void ResultPage::slotSaveRequestToFile() 0230 { 0231 QString fileName = FileDialog::getSaveFileName(this, i18nc("@title", "Save Request"), QStringLiteral("imp"), i18n("PKCS#10 Requests (*.p10)")); 0232 if (fileName.isEmpty()) { 0233 return; 0234 } 0235 if (!fileName.endsWith(QLatin1StringView(".p10"), Qt::CaseInsensitive)) { 0236 fileName += QLatin1StringView(".p10"); 0237 } 0238 QFile src(QUrl(url()).toLocalFile()); 0239 if (!src.copy(fileName)) 0240 KMessageBox::error(this, 0241 xi18nc("@info", 0242 "Could not copy temporary file <filename>%1</filename> " 0243 "to file <filename>%2</filename>: <message>%3</message>", 0244 src.fileName(), 0245 fileName, 0246 src.errorString()), 0247 i18nc("@title", "Error Saving Request")); 0248 else 0249 KMessageBox::information(this, 0250 xi18nc("@info", 0251 "<para>Successfully wrote request to <filename>%1</filename>.</para>" 0252 "<para>You should now send the request to the Certification Authority (CA).</para>", 0253 fileName), 0254 i18nc("@title", "Request Saved")); 0255 } 0256 0257 void ResultPage::slotSendRequestByEMail() 0258 { 0259 if (pgp()) { 0260 return; 0261 } 0262 const KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CertificateCreationWizard")); 0263 invokeMailer(config.readEntry("CAEmailAddress"), // to 0264 i18n("Please process this certificate."), // subject 0265 i18n("Please process this certificate and inform the sender about the location to fetch the resulting certificate.\n\nThanks,\n"), // body 0266 QFileInfo{QUrl(url()).toLocalFile()}); // attachment 0267 KMessageBox::information(this, 0268 xi18nc("@info", 0269 "<para><application>Kleopatra</application> tried to send a mail via your default mail client.</para>" 0270 "<para>Some mail clients are known not to support attachments when invoked this way.</para>" 0271 "<para>If your mail client does not have an attachment, then drag the <application>Kleopatra</application> icon and drop " 0272 "it on the message compose window of your mail client.</para>" 0273 "<para>If that does not work, either, save the request to a file, and then attach that.</para>"), 0274 i18nc("@title", "Sending Mail"), 0275 QStringLiteral("newcertificatewizard-mailto-troubles")); 0276 } 0277 0278 void ResultPage::slotSendCertificateByEMail() 0279 { 0280 if (!pgp() || exportCertificateCommand) { 0281 return; 0282 } 0283 auto cmd = new ExportCertificateCommand(key()); 0284 connect(cmd, &ExportCertificateCommand::finished, this, &ResultPage::slotSendCertificateByEMailContinuation); 0285 cmd->setOpenPGPFileName(tmpDir().absoluteFilePath(fingerprint() + QLatin1StringView(".asc"))); 0286 cmd->start(); 0287 exportCertificateCommand = cmd; 0288 } 0289 0290 void ResultPage::slotSendCertificateByEMailContinuation() 0291 { 0292 if (!exportCertificateCommand) { 0293 return; 0294 } 0295 // ### better error handling? 0296 const QString fileName = exportCertificateCommand->openPGPFileName(); 0297 qCDebug(KLEOPATRA_LOG) << "fileName" << fileName; 0298 exportCertificateCommand = nullptr; 0299 if (fileName.isEmpty()) { 0300 return; 0301 } 0302 invokeMailer(i18n("My new public OpenPGP key"), // subject 0303 i18n("Please find attached my new public OpenPGP key."), // body 0304 QFileInfo{fileName}); 0305 KMessageBox::information(this, 0306 xi18nc("@info", 0307 "<para><application>Kleopatra</application> tried to send a mail via your default mail client.</para>" 0308 "<para>Some mail clients are known not to support attachments when invoked this way.</para>" 0309 "<para>If your mail client does not have an attachment, then attach the file <filename>%1</filename> manually.</para>", 0310 fileName), 0311 i18nc("@title", "Sending Mail"), 0312 QStringLiteral("newcertificatewizard-openpgp-mailto-troubles")); 0313 } 0314 0315 void ResultPage::slotUploadCertificateToDirectoryServer() 0316 { 0317 if (pgp()) { 0318 (new ExportOpenPGPCertsToServerCommand(key()))->start(); 0319 } 0320 } 0321 0322 void ResultPage::slotBackupCertificate() 0323 { 0324 if (pgp()) { 0325 (new ExportSecretKeyCommand(key()))->start(); 0326 } 0327 } 0328 0329 void ResultPage::slotCreateRevocationRequest() 0330 { 0331 } 0332 0333 void ResultPage::slotCreateSigningCertificate() 0334 { 0335 if (successfullyCreatedSigningCertificate) { 0336 return; 0337 } 0338 toggleSignEncryptAndRestart(); 0339 } 0340 0341 void ResultPage::slotCreateEncryptionCertificate() 0342 { 0343 if (successfullyCreatedEncryptionCertificate) { 0344 return; 0345 } 0346 toggleSignEncryptAndRestart(); 0347 } 0348 0349 void ResultPage::toggleSignEncryptAndRestart() 0350 { 0351 if (!wizard()) { 0352 return; 0353 } 0354 if (KMessageBox::warningContinueCancel(this, 0355 i18nc("@info", 0356 "This operation will delete the certification request. " 0357 "Please make sure that you have sent or saved it before proceeding."), 0358 i18nc("@title", "Certification Request About To Be Deleted")) 0359 != KMessageBox::Continue) { 0360 return; 0361 } 0362 const bool sign = signingAllowed(); 0363 const bool encr = encryptionAllowed(); 0364 setField(QStringLiteral("signingAllowed"), !sign); 0365 setField(QStringLiteral("encryptionAllowed"), !encr); 0366 restartAtEnterDetailsPage(); 0367 } 0368 0369 #include "moc_resultpage_p.cpp"