File indexing completed on 2024-04-21 05:50:45

0001 /*
0002     SPDX-FileCopyrightText: 2002 Jean-Baptiste Mardelle <bj@altern.org>
0003     SPDX-FileCopyrightText: 2007 Jimmy Gilles <jimmygilles@gmail.com>
0004     SPDX-FileCopyrightText: 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017 Rolf Eike Beer <kde@opensource.sf-tec.de>
0005     SPDX-FileCopyrightText: 2011 Philip Greggory Lee <rocketman768@gmail.com>
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "keyinfodialog.h"
0010 
0011 #include "kgpgchangekey.h"
0012 #include <kgpgsettings.h>
0013 #include "selectexpirydate.h"
0014 #include "core/convert.h"
0015 #include "core/images.h"
0016 #include "core/kgpgkey.h"
0017 #include "model/kgpgitemmodel.h"
0018 #include "model/kgpgitemnode.h"
0019 #include "transactions/kgpgchangepass.h"
0020 
0021 #include <KConfigGroup>
0022 #include <KLocalizedString>
0023 #include <KMessageBox>
0024 
0025 #include <QApplication>
0026 #include <QCheckBox>
0027 #include <QDesktopServices>
0028 #include <QDialogButtonBox>
0029 #include <QFormLayout>
0030 #include <QHBoxLayout>
0031 #include <QImage>
0032 #include <QLocale>
0033 #include <QPixmap>
0034 #include <QPushButton>
0035 #include <QVBoxLayout>
0036 
0037 using namespace KgpgCore;
0038 
0039 KgpgTrustLabel::KgpgTrustLabel(QWidget *parent)
0040     : QWidget(parent),
0041     m_text_w(new QLabel(this)),
0042     m_color_w(new QLabel(this))
0043 {
0044     m_text_w->setTextInteractionFlags(Qt::TextSelectableByMouse);
0045 
0046     m_color_w->setLineWidth(1);
0047     m_color_w->setFrameShape(QFrame::Box);
0048     m_color_w->setAutoFillBackground(true);
0049     m_color_w->setMinimumWidth(64);
0050 
0051     QHBoxLayout *layout = new QHBoxLayout(this);
0052     layout->setSpacing(10);
0053     layout->setContentsMargins(2, 2, 2, 2);
0054     layout->addWidget(m_text_w);
0055     layout->addWidget(m_color_w);
0056 
0057     change();
0058 }
0059 
0060 void KgpgTrustLabel::setText(const QString &text)
0061 {
0062     m_text = text;
0063     change();
0064 }
0065 
0066 void KgpgTrustLabel::setColor(const QColor &color)
0067 {
0068     m_color = color;
0069     change();
0070 }
0071 
0072 QString KgpgTrustLabel::text() const
0073 {
0074     return m_text;
0075 }
0076 
0077 QColor KgpgTrustLabel::color() const
0078 {
0079     return m_color;
0080 }
0081 
0082 void KgpgTrustLabel::change()
0083 {
0084     m_text_w->setText(m_text);
0085 
0086     QPalette palette = m_color_w->palette();
0087     palette.setColor(m_color_w->backgroundRole(), m_color);
0088     m_color_w->setPalette(palette);
0089 }
0090 
0091 KgpgKeyInfo::KgpgKeyInfo(KGpgKeyNode *node, KGpgItemModel *model, QWidget *parent)
0092     : QDialog(parent),
0093     keychange(new KGpgChangeKey(node, this)),
0094     m_node(node),
0095     m_model(model),
0096     m_trust(new KgpgTrustLabel(this)),
0097     m_keywaschanged(false),
0098     m_closewhendone(false)
0099 {
0100     Q_ASSERT(m_model != nullptr);
0101     Q_ASSERT(m_node != nullptr);
0102 
0103     setupUi(this);
0104     m_owtrust->addItem(Convert::toString(GPGME_VALIDITY_UNDEFINED));
0105     m_owtrust->addItem(Convert::toString(GPGME_VALIDITY_NEVER));
0106     m_owtrust->addItem(Convert::toString(GPGME_VALIDITY_MARGINAL));
0107     m_owtrust->addItem(Convert::toString(GPGME_VALIDITY_FULL));
0108     m_owtrust->addItem(Convert::toString(GPGME_VALIDITY_ULTIMATE));
0109 
0110     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0111     QWidget *mainWidget = new QWidget(this);
0112     setLayout(mainLayout);
0113     mainLayout->addWidget(mainWidget);
0114     buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel|QDialogButtonBox::Apply);
0115     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0116     okButton->setDefault(true);
0117     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0118     connect(buttonBox, &QDialogButtonBox::accepted, this, &KgpgKeyInfo::okButtonClicked);
0119     connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &KgpgKeyInfo::applyButtonClicked);
0120     connect(buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &KgpgKeyInfo::cancelButtonClicked);
0121     connect(buttonBox, &QDialogButtonBox::rejected, this, &KgpgKeyInfo::reject);
0122     okButton->setDefault(true);
0123     buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
0124 
0125     m_email->setUnderline(false);
0126     int trustRow;
0127     formLayout_keyproperties->getWidgetPosition(tl_trust, &trustRow, nullptr);
0128     formLayout_keyproperties->setWidget(trustRow, QFormLayout::FieldRole, m_trust);
0129 
0130     // Hide some widgets if this is not a secret node.
0131     if ( ! m_node->isSecret() ) {
0132         m_expirationbtn->hide();
0133         m_password->hide();
0134     }
0135 
0136     mainLayout->addWidget(page);
0137     mainLayout->addWidget(buttonBox);
0138 
0139     connect(m_owtrust, QOverload<int>::of(&QComboBox::activated), this, &KgpgKeyInfo::slotChangeTrust);
0140     connect(m_photoid, &QComboBox::textActivated, this, &KgpgKeyInfo::slotLoadPhoto);
0141     connect(m_email, &KUrlLabel::leftClickedUrl, this, &KgpgKeyInfo::slotOpenUrl);
0142     connect(keychange, &KGpgChangeKey::done, this, &KgpgKeyInfo::slotApplied);
0143     connect(m_disable, &QCheckBox::toggled, this, &KgpgKeyInfo::slotDisableKey);
0144     connect(m_expirationbtn, &QPushButton::clicked, this, &KgpgKeyInfo::slotChangeDate);
0145     connect(m_password, &QPushButton::clicked, this, &KgpgKeyInfo::slotChangePass);
0146 
0147     displayKey();
0148     adjustSize();
0149     gr_fingerprint->setMinimumHeight(gr_fingerprint->height());
0150 }
0151 
0152 KgpgKeyInfo::~KgpgKeyInfo()
0153 {
0154     if (keychange) {
0155         // make sure anything that happens as result of the selfdestruct does not call
0156         // out into a method of this object again, as it is under destruction and that
0157         // can cause crashes (see bug 373910). Since ~QObject has not been run yet the
0158         // connections are not yet removed automatically.
0159         disconnect(keychange, &KGpgChangeKey::done, this, &KgpgKeyInfo::slotApplied);
0160         keychange->selfdestruct(false);
0161     }
0162 }
0163 
0164 void KgpgKeyInfo::reloadNode()
0165 {
0166     const QString kid(m_node->getId());
0167 
0168     // this will delete m_node
0169     m_model->refreshKey(m_node);
0170 
0171     m_node = m_model->getRootNode()->findKey(kid);
0172     if (m_node != nullptr) {
0173         displayKey();
0174     } else {
0175         KMessageBox::error(this, i18n("<qt>The requested key is not present in the keyring anymore.<br />Perhaps it was deleted by another application</qt>"), i18n("Key not found"));
0176         m_keywaschanged = false;
0177         close();
0178     }
0179 }
0180 
0181 void KgpgKeyInfo::displayKey()
0182 {
0183     const QString name = m_node->getName();
0184     setWindowTitle(name);
0185     m_name->setText(QLatin1String( "<qt><b>" ) + name + QLatin1String( "</b></qt>" ));
0186 
0187     const QString email = m_node->getEmail();
0188     if (email.isEmpty()) {
0189         m_email->setText(i18nc("no email address", "none"));
0190         m_email->setUrl(QString());
0191         m_email->setEnabled(false);
0192     } else {
0193         m_email->setText(QLatin1String( "<qt><b>&lt;" ) + email + QLatin1String( "&gt;</b></qt>" ));
0194         m_email->setUrl(QLatin1String( "mailto:" ) + name + QLatin1Char( '<' ) + email + QLatin1Char( '>' ));
0195     }
0196 
0197     const KgpgKey *key = m_node->getKey();
0198     m_caps->setText(Convert::toString(key->keytype()));
0199 
0200     QString trust;
0201     QColor trustcolor;
0202 
0203     if (key->valid()) {
0204         QModelIndex idx = m_model->nodeIndex(m_node, KEYCOLUMN_TRUST);
0205         trust = m_model->data(idx, Qt::AccessibleTextRole).toString();
0206         trustcolor = m_model->data(idx, Qt::BackgroundRole).value<QColor>();
0207     } else {
0208         trust = Convert::toString(TRUST_DISABLED);
0209         trustcolor = KGpgSettings::colorBad();
0210     }
0211 
0212     m_id->setText(m_node->getId().right(16));
0213     m_algorithm->setText(Convert::toString(key->algorithm()) + QLatin1String( " / " ) + Convert::toString(key->encryptionAlgorithm()));
0214     m_algorithm->setWhatsThis(i18n("<qt>The left part is the algorithm used by the <b>signature</b> key. The right part is the algorithm used by the <b>encryption</b> key.</qt>"));
0215     m_creation->setText(QLocale().toString(m_node->getCreation().date(), QLocale::ShortFormat));
0216     if (m_node->getExpiration().isNull())
0217         m_expiration->setText(i18nc("Unlimited key lifetime", "Unlimited"));
0218     else
0219         m_expiration->setText(QLocale().toString(m_node->getExpiration().date(), QLocale::ShortFormat));
0220     m_trust->setText(trust);
0221     m_trust->setColor(trustcolor);
0222     m_length->setText(m_node->getSize());
0223     m_length->setWhatsThis(i18n("<qt>The left part is the size of the <b>signature</b> key. The right part is the size of the <b>encryption</b> key.</qt>"));
0224     m_fingerprint->setText(m_node->getBeautifiedFingerprint());
0225 
0226     const QString comment = m_node->getComment();
0227     if (comment.isEmpty()) {
0228         m_comment->setText(i18nc("no key comment", "<em>none</em>"));
0229         m_comment->setTextFormat(Qt::RichText);
0230     } else {
0231         m_comment->setText(comment);
0232         m_comment->setTextFormat(Qt::PlainText);
0233     }
0234 
0235     switch (key->ownerTrust()) {
0236     case GPGME_VALIDITY_NEVER:
0237         m_owtrust->setCurrentIndex(1);
0238         break;
0239     case GPGME_VALIDITY_MARGINAL:
0240         m_owtrust->setCurrentIndex(2);
0241         break;
0242     case GPGME_VALIDITY_FULL:
0243         m_owtrust->setCurrentIndex(3);
0244         break;
0245     case GPGME_VALIDITY_ULTIMATE:
0246         m_owtrust->setCurrentIndex(4);
0247         break;
0248     case GPGME_VALIDITY_UNDEFINED:
0249     default:
0250         m_owtrust->setCurrentIndex(0);
0251         break;
0252     }
0253 
0254     if (!key->valid())
0255         m_disable->setChecked(true);
0256 
0257     connect(m_node, &KGpgKeyNode::expanded, this, &KgpgKeyInfo::slotKeyExpanded);
0258     m_node->expand();
0259     m_photoid->clear();
0260 }
0261 
0262 void KgpgKeyInfo::slotOpenUrl()
0263 {
0264     QDesktopServices::openUrl(QUrl(m_email->url()));
0265 }
0266 
0267 void KgpgKeyInfo::slotLoadPhoto(const QString &uid)
0268 {
0269     int i = uid.toInt();
0270     QPixmap pixmap = m_node->getUid(i)->toUatNode()->getPixmap();
0271     QImage img = pixmap.toImage();
0272     pixmap = QPixmap::fromImage(img.scaled(m_photo->width(), m_photo->height(), Qt::KeepAspectRatio));
0273     m_photo->setPixmap(pixmap);
0274 }
0275 
0276 void KgpgKeyInfo::slotChangeDate()
0277 {
0278     QPointer<SelectExpiryDate> dialog = new SelectExpiryDate(this, m_node->getExpiration());
0279     if (dialog->exec() == QDialog::Accepted) {
0280         keychange->setExpiration(dialog->date());
0281         buttonBox->button(QDialogButtonBox::Apply)->setEnabled(keychange->wasChanged());
0282     }
0283     delete dialog;
0284 }
0285 
0286 void KgpgKeyInfo::slotDisableKey(const bool ison)
0287 {
0288     keychange->setDisable(ison);
0289     buttonBox->button(QDialogButtonBox::Apply)->setEnabled(keychange->wasChanged());
0290 }
0291 
0292 void KgpgKeyInfo::slotChangePass()
0293 {
0294     KGpgChangePass *cp = new KGpgChangePass(this, m_node->getId());
0295 
0296     connect(cp, &KGpgChangePass::done, this, &KgpgKeyInfo::slotInfoPasswordChanged);
0297 
0298     cp->start();
0299     QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
0300 }
0301 
0302 void KgpgKeyInfo::slotInfoPasswordChanged(int result)
0303 {
0304     sender()->deleteLater();
0305 
0306     QApplication::restoreOverrideCursor();
0307 
0308     switch (result) {
0309     case KGpgTransaction::TS_OK:
0310         // when pinentry is used it is indistinguishable if everything went fine
0311         // or the user cancelled the password entries, so simply show nothing
0312         break;
0313     case KGpgTransaction::TS_BAD_PASSPHRASE:
0314         KMessageBox::error(this, i18n("Bad old passphrase, the passphrase for the key was not changed"), i18n("Could not change passphrase"));
0315         break;
0316     case KGpgTransaction::TS_USER_ABORTED:
0317         break;
0318     default:
0319         KMessageBox::error(this, i18n("KGpg was unable to change the passphrase."));
0320     }
0321 }
0322 
0323 void KgpgKeyInfo::slotChangeTrust(const int newtrust)
0324 {
0325     keychange->setOwTrust(static_cast<gpgme_validity_t>(newtrust + 1));
0326     buttonBox->button(QDialogButtonBox::Apply)->setEnabled(keychange->wasChanged());
0327 }
0328 
0329 void KgpgKeyInfo::setControlEnable(const bool b)
0330 {
0331     m_owtrust->setEnabled(b);
0332     m_disable->setEnabled(b);
0333     buttonBox->button(QDialogButtonBox::Apply)->setEnabled(b && keychange->wasChanged());
0334 
0335     if (m_expirationbtn)
0336         m_expirationbtn->setEnabled(b);
0337     if (m_password)
0338         m_password->setEnabled(b);
0339 
0340     if (b)
0341         QApplication::restoreOverrideCursor();
0342     else
0343         QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
0344 }
0345 
0346 void KgpgKeyInfo::okButtonClicked()
0347 {
0348     m_closewhendone = true;
0349     applyButtonClicked();
0350 }
0351 
0352 void KgpgKeyInfo::applyButtonClicked()
0353 {
0354     setControlEnable(false);
0355     keychange->apply();
0356 }
0357 
0358 void KgpgKeyInfo::cancelButtonClicked()
0359 {
0360     if (m_keywaschanged && m_node)
0361         Q_EMIT keyNeedsRefresh(m_node);
0362     reject();
0363 }
0364 
0365 void KgpgKeyInfo::slotApplied(int result)
0366 {
0367     if (result) {
0368         KMessageBox::error(this, i18n("Changing key properties failed."), i18n("Key properties"));
0369     } else {
0370         m_keywaschanged = true;
0371         Q_EMIT keyNeedsRefresh(m_node);
0372         reloadNode();
0373     }
0374     setControlEnable(true);
0375 
0376     if (m_closewhendone)
0377         accept();
0378 }
0379 
0380 void KgpgKeyInfo::slotKeyExpanded()
0381 {
0382     // the counting starts at 1 and that is the primary uid which can't be a photo id
0383     unsigned int i = 2;
0384     const KGpgSignableNode *uat;
0385 
0386     while ((uat = m_node->getUid(i++)) != nullptr) {
0387         if (uat->getType() != KgpgCore::ITYPE_UAT)
0388             continue;
0389 
0390         m_photoid->addItem(uat->getId());
0391     }
0392 
0393     bool hasphoto = (m_photoid->count() > 0);
0394 
0395     m_photoid->setVisible(hasphoto);
0396     m_photoid->setEnabled(hasphoto);
0397     if (hasphoto)
0398         slotLoadPhoto(m_photoid->currentText());
0399 }