File indexing completed on 2025-01-12 08:18:47
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><" ) + email + QLatin1String( "></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 }