File indexing completed on 2024-06-23 05:13:37

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     commands/changeownertrustcommand.cpp
0003 
0004     This file is part of Kleopatra, the KDE keymanager
0005     SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
0006     SPDX-FileCopyrightText: 2022 g10 Code GmbH
0007     SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include <config-kleopatra.h>
0013 
0014 #include "changeownertrustcommand.h"
0015 
0016 #include "command_p.h"
0017 
0018 #include <Libkleo/Compliance>
0019 #include <Libkleo/Formatting>
0020 #include <Libkleo/KeyCache>
0021 
0022 #include <KLocalizedString>
0023 
0024 #include <QGpgME/ChangeOwnerTrustJob>
0025 #include <QGpgME/Protocol>
0026 
0027 #include <gpgme++/key.h>
0028 
0029 #include "kleopatra_debug.h"
0030 
0031 using namespace Kleo;
0032 using namespace Kleo::Commands;
0033 using namespace GpgME;
0034 using namespace QGpgME;
0035 
0036 class ChangeOwnerTrustCommand::Private : public Command::Private
0037 {
0038     friend class ::Kleo::Commands::ChangeOwnerTrustCommand;
0039     ChangeOwnerTrustCommand *q_func() const
0040     {
0041         return static_cast<ChangeOwnerTrustCommand *>(q);
0042     }
0043 
0044 public:
0045     Private(ChangeOwnerTrustCommand *qq, KeyListController *c);
0046 
0047 private:
0048     void startJob(Key::OwnerTrust trust);
0049     void createJob();
0050     void slotResult(const Error &err);
0051     void showErrorDialog(const Error &error);
0052     void showSuccessDialog();
0053 
0054 private:
0055     QPointer<ChangeOwnerTrustJob> job;
0056     Key::OwnerTrust trustToSet = Key::OwnerTrust::Unknown;
0057 };
0058 
0059 ChangeOwnerTrustCommand::Private *ChangeOwnerTrustCommand::d_func()
0060 {
0061     return static_cast<Private *>(d.get());
0062 }
0063 const ChangeOwnerTrustCommand::Private *ChangeOwnerTrustCommand::d_func() const
0064 {
0065     return static_cast<const Private *>(d.get());
0066 }
0067 
0068 #define d d_func()
0069 #define q q_func()
0070 
0071 ChangeOwnerTrustCommand::Private::Private(ChangeOwnerTrustCommand *qq, KeyListController *c)
0072     : Command::Private{qq, c}
0073 {
0074 }
0075 
0076 ChangeOwnerTrustCommand::ChangeOwnerTrustCommand(QAbstractItemView *v, KeyListController *c)
0077     : Command{v, new Private{this, c}}
0078 {
0079 }
0080 
0081 ChangeOwnerTrustCommand::~ChangeOwnerTrustCommand()
0082 {
0083     qCDebug(KLEOPATRA_LOG) << this << __func__;
0084 }
0085 
0086 void ChangeOwnerTrustCommand::doStart()
0087 {
0088     if (d->keys().size() != 1) {
0089         d->finished();
0090         return;
0091     }
0092 
0093     const Key key = d->key();
0094     if (key.protocol() != GpgME::OpenPGP) {
0095         d->finished();
0096         return;
0097     }
0098 
0099     const auto keyInfo = Formatting::formatForComboBox(key);
0100 
0101     if (key.hasSecret()) {
0102         const auto answer = KMessageBox::questionTwoActionsCancel(d->parentWidgetOrView(),
0103                                                                   xi18nc("@info", "Is '%1' your own certificate?", keyInfo),
0104                                                                   i18nc("@title:window", "Mark Own Certificate"),
0105                                                                   KGuiItem(i18nc("@action:button", "Yes, it's mine")),
0106                                                                   KGuiItem(i18nc("@action:button", "No, it's not mine")),
0107                                                                   KStandardGuiItem::cancel());
0108         switch (answer) {
0109         case KMessageBox::ButtonCode::PrimaryAction: {
0110             if (key.ownerTrust() < Key::Ultimate) {
0111                 d->startJob(Key::OwnerTrust::Ultimate);
0112             }
0113             return;
0114         }
0115         case KMessageBox::ButtonCode::SecondaryAction: {
0116             if (key.ownerTrust() == Key::Ultimate) {
0117                 d->startJob(Key::OwnerTrust::Unknown);
0118                 return;
0119             }
0120             // else ask next question
0121             break;
0122         }
0123         case KMessageBox::Cancel: {
0124             d->canceled();
0125             return;
0126         }
0127         default:; // cannot happen
0128         }
0129     }
0130 
0131     if (key.ownerTrust() < Key::OwnerTrust::Full) {
0132         const auto text = (DeVSCompliance::isCompliant() && DeVSCompliance::allSubkeysAreCompliant(key))
0133             ? xi18nc("@info %1: a certificate, %2: name of a compliance mode",
0134                      "<para>Do you want to grant '%1' the power to mark certificates as %2 for you?</para>"
0135                      "<para><emphasis>This means that the owner of this certificate properly checks fingerprints "
0136                      "and confirms the identities of others.</emphasis></para>",
0137                      keyInfo,
0138                      DeVSCompliance::name())
0139             : xi18nc("@info %1: a certificate",
0140                      "<para>Do you want to grant '%1' the power to mark certificates as valid for you?</para>"
0141                      "<para><emphasis>This means that the owner of this certificate properly checks fingerprints "
0142                      "and confirms the identities of others.</emphasis></para>",
0143                      keyInfo);
0144         const auto answer = KMessageBox::questionTwoActions(d->parentWidgetOrView(),
0145                                                             text,
0146                                                             i18nc("@title:window", "Grant Certification Power"),
0147                                                             KGuiItem(i18nc("@action:button", "Grant Power")),
0148                                                             KStandardGuiItem::cancel());
0149         if (answer == KMessageBox::ButtonCode::PrimaryAction) {
0150             d->startJob(Key::OwnerTrust::Full);
0151         } else {
0152             d->canceled();
0153         }
0154     } else {
0155         const auto text = (DeVSCompliance::isCompliant() && DeVSCompliance::allSubkeysAreCompliant(key))
0156             ? xi18nc("@info %1: a certificate, %2: name of a compliance mode",
0157                      "<para>The certificate '%1' is empowered to mark other certificates as %2 for you.</para>"
0158                      "<para>Do you want to revoke this power?</para>",
0159                      keyInfo,
0160                      DeVSCompliance::name())
0161             : xi18nc("@info %1: a certificate",
0162                      "<para>The certificate '%1' is empowered to mark other certificates as valid for you.</para>"
0163                      "<para>Do you want to revoke this power?</para>",
0164                      keyInfo);
0165         const auto answer = KMessageBox::questionTwoActions(d->parentWidgetOrView(),
0166                                                             text,
0167                                                             i18nc("@title:window", "Revoke Certification Power"),
0168                                                             KGuiItem(i18nc("@action:button", "Revoke Power")),
0169                                                             KStandardGuiItem::cancel());
0170         if (answer == KMessageBox::ButtonCode::PrimaryAction) {
0171             d->startJob(Key::OwnerTrust::Unknown);
0172         } else {
0173             d->canceled();
0174         }
0175     }
0176 }
0177 
0178 void ChangeOwnerTrustCommand::Private::startJob(Key::OwnerTrust trust)
0179 {
0180     trustToSet = trust;
0181 
0182     createJob();
0183     Q_ASSERT(job);
0184 
0185     if (const Error err = job->start(key(), trust)) {
0186         showErrorDialog(err);
0187         finished();
0188     }
0189 }
0190 
0191 void ChangeOwnerTrustCommand::Private::slotResult(const Error &err)
0192 {
0193     if (err.isCanceled())
0194         ;
0195     else if (err) {
0196         showErrorDialog(err);
0197     } else {
0198         showSuccessDialog();
0199     }
0200     finished();
0201 }
0202 
0203 void ChangeOwnerTrustCommand::doCancel()
0204 {
0205     qCDebug(KLEOPATRA_LOG) << this << __func__;
0206     if (d->job) {
0207         d->job->slotCancel();
0208     }
0209 }
0210 
0211 void ChangeOwnerTrustCommand::Private::createJob()
0212 {
0213     Q_ASSERT(!job);
0214 
0215     ChangeOwnerTrustJob *const j = QGpgME::openpgp()->changeOwnerTrustJob();
0216     if (!j) {
0217         return;
0218     }
0219 
0220     connect(j, &QGpgME::Job::jobProgress, q, &Command::progress);
0221     connect(j, &ChangeOwnerTrustJob::result, q, [this](const GpgME::Error &result) {
0222         slotResult(result);
0223     });
0224 
0225     job = j;
0226 }
0227 
0228 void ChangeOwnerTrustCommand::Private::showErrorDialog(const Error &err)
0229 {
0230     const auto keyInfo = Formatting::formatForComboBox(key());
0231     switch (trustToSet) {
0232     case Key::OwnerTrust::Ultimate:
0233         error(xi18nc("@info",
0234                      "<para>An error occurred while marking certificate '%1' as your certificate.</para>"
0235                      "<para><message>%2</message></para>",
0236                      keyInfo,
0237                      Formatting::errorAsString(err)));
0238         break;
0239     case Key::OwnerTrust::Full:
0240         error(xi18nc("@info",
0241                      "<para>An error occurred while granting certification power to '%1'.</para>"
0242                      "<para><message>%2</message></para>",
0243                      keyInfo,
0244                      Formatting::errorAsString(err)));
0245         break;
0246     default:
0247         error(xi18nc("@info",
0248                      "<para>An error occurred while revoking the certification power of '%1'.</para>"
0249                      "<para><message>%2</message></para>",
0250                      keyInfo,
0251                      Formatting::errorAsString(err)));
0252     }
0253 }
0254 
0255 void ChangeOwnerTrustCommand::Private::showSuccessDialog()
0256 {
0257     auto updatedKey = key();
0258     updatedKey.update();
0259     KeyCache::mutableInstance()->insert(updatedKey);
0260 
0261     const auto keyInfo = Formatting::formatForComboBox(updatedKey);
0262     switch (updatedKey.ownerTrust()) {
0263     case Key::OwnerTrust::Ultimate:
0264         success(i18nc("@info", "Certificate '%1' was marked as your certificate.", keyInfo));
0265         break;
0266     case Key::OwnerTrust::Full:
0267         success(i18nc("@info", "Certification power was granted to '%1'.", keyInfo));
0268         break;
0269     default:
0270         success(i18nc("@info", "The certification power of '%1' was revoked.", keyInfo));
0271     }
0272 }
0273 
0274 #undef d
0275 #undef q
0276 
0277 #include "moc_changeownertrustcommand.cpp"