File indexing completed on 2024-12-01 07:38:57
0001 /*************************************************************************** 0002 * Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU General Public License as published by * 0006 * the Free Software Foundation; either version 2 of the License, or * 0007 * (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License * 0015 * along with this program; if not, write to the * 0016 * Free Software Foundation, Inc., * 0017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * 0018 ***************************************************************************/ 0019 0020 #include "signaturedlg.h" 0021 0022 #include "core/filemodel.h" 0023 #include "core/kget.h" 0024 #include "core/signature.h" 0025 #include "core/transferhandler.h" 0026 0027 #include "kget_debug.h" 0028 #include <QDebug> 0029 0030 #ifdef HAVE_QGPGME 0031 #include <gpgme++/context.h> 0032 #include <gpgme++/key.h> 0033 #endif 0034 0035 #include <QLayoutItem> 0036 #include <QStyle> 0037 0038 #include <KLocalizedString> 0039 #include <QFileDialog> 0040 0041 SignatureDlg::SignatureDlg(TransferHandler *transfer, const QUrl &dest, QWidget *parent, Qt::WindowFlags flags) 0042 : KGetSaveSizeDialog("SignatureDlg", parent, flags) 0043 , m_signature(transfer->signature(dest)) 0044 , m_fileModel(transfer->fileModel()) 0045 { 0046 setWindowTitle(i18nc("Signature here is meant in cryptographic terms, so the signature of a file.", "Signature of %1.", dest.fileName())); 0047 0048 ui.setupUi(this); 0049 ui.loadSignature->setIcon(QIcon::fromTheme("document-open")); 0050 ui.verify->setIcon(QIcon::fromTheme("document-encrypt")); 0051 0052 ui.information->setCloseButtonVisible(false); 0053 ui.information->setWordWrap(true); 0054 if (m_signature) { 0055 connect(ui.loadSignature, &QPushButton::clicked, this, &SignatureDlg::loadSignatureClicked); 0056 connect(ui.verify, &QPushButton::clicked, this, &SignatureDlg::verifyClicked); 0057 connect(ui.signature, &QTextEdit::textChanged, this, &SignatureDlg::textChanged); 0058 connect(m_signature, &Signature::verified, this, &SignatureDlg::updateData); 0059 0060 if (m_fileModel) { 0061 m_file = m_fileModel->index(dest, FileItem::File); 0062 connect(m_fileModel, &FileModel::fileFinished, this, &SignatureDlg::fileFinished); 0063 } 0064 0065 updateData(); 0066 updateButtons(); 0067 } else { 0068 ui.information->setMessageType(KMessageWidget::Warning); 0069 ui.information->setText(i18n("This option is not supported for the current transfer.")); 0070 ui.sigGroup->hide(); 0071 ui.keyGroup->hide(); 0072 } 0073 connect(ui.buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); 0074 connect(ui.buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 0075 } 0076 0077 void SignatureDlg::fileFinished(const QUrl &file) 0078 { 0079 if (m_fileModel && (m_fileModel->getUrl(m_file) == file)) { 0080 updateButtons(); 0081 } 0082 } 0083 0084 void SignatureDlg::textChanged() 0085 { 0086 if (m_signature) { 0087 m_signature->setAsciiDetachedSignature(ui.signature->toPlainText()); 0088 0089 clearData(); 0090 updateButtons(); 0091 } 0092 } 0093 0094 void SignatureDlg::loadSignatureClicked() 0095 { 0096 const QUrl url = QFileDialog::getOpenFileUrl(this, 0097 i18n("Load Signature File"), 0098 QUrl::fromLocalFile(KGet::generalDestDir()), 0099 "*.asc|" + i18n("Detached OpenPGP ASCII signature (*.asc)") + '\n' + "*.sig|" 0100 + i18n("Detached OpenPGP binary signature (*.sig)")); 0101 if (url.isEmpty()) { 0102 return; 0103 } 0104 0105 const bool isAsciiSig = url.fileName().endsWith(QLatin1String(".asc")); 0106 clearData(); 0107 handleWidgets(isAsciiSig); 0108 ui.signature->clear(); 0109 0110 QFile file(url.path()); 0111 if (!file.open(QIODevice::ReadOnly)) { 0112 qCWarning(KGET_DEBUG) << "Could not open file" << url; 0113 return; 0114 } 0115 if (file.size() > 1 * 1024) { 0116 qCWarning(KGET_DEBUG) << "File is larger than 1 KiB, which is not supported."; 0117 return; 0118 } 0119 0120 const QByteArray data = file.readAll(); 0121 if (isAsciiSig) { 0122 ui.signature->setText(data); 0123 } else if (m_signature) { 0124 m_signature->setSignature(data, Signature::BinaryDetached); 0125 clearData(); 0126 updateButtons(); 0127 } 0128 } 0129 0130 void SignatureDlg::updateButtons() 0131 { 0132 bool enableVerify = m_signature && m_signature->isVerifyable(); 0133 if (!m_fileModel || !m_fileModel->downloadFinished(m_fileModel->getUrl(m_file))) { 0134 enableVerify = false; 0135 } 0136 ui.verify->setEnabled(enableVerify); 0137 } 0138 0139 void SignatureDlg::updateData() 0140 { 0141 if (!m_signature) { 0142 return; 0143 } 0144 0145 const QString fingerprintString = m_signature->fingerprint(); 0146 const QByteArray signature = m_signature->signature(); 0147 0148 QStringList information; 0149 0150 bool problem = false; 0151 bool error = false; 0152 if (signature.isEmpty()) { 0153 information << i18n("You need to define a signature."); 0154 problem = true; 0155 } 0156 if (fingerprintString.isEmpty()) { 0157 information << i18n("No fingerprint could be found, check if the signature is correct or verify the download."); // TODO get fingerprint from signature! 0158 problem = true; 0159 } 0160 0161 ui.fingerprint->setText(fingerprintString); 0162 0163 const bool isAsciiSig = (m_signature->type() != Signature::BinaryDetached); 0164 handleWidgets(isAsciiSig); 0165 if (isAsciiSig) { 0166 ui.signature->blockSignals(true); 0167 ui.signature->setText(signature); 0168 ui.signature->blockSignals(false); 0169 } 0170 0171 ui.keyGroup->setVisible(!signature.isEmpty()); 0172 0173 const int iconSize = style()->pixelMetric(QStyle::PixelMetric::PM_SmallIconSize); 0174 0175 #ifdef HAVE_QGPGME 0176 if (!fingerprintString.isEmpty()) { 0177 GpgME::initializeLibrary(); 0178 GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP); 0179 QScopedPointer<GpgME::Context> context(GpgME::Context::createForProtocol(GpgME::OpenPGP)); 0180 if (err) { 0181 qCDebug(KGET_DEBUG) << "OpenPGP not supported!"; 0182 } else if (!context.data()) { 0183 qCDebug(KGET_DEBUG) << "Could not create context."; 0184 } else { 0185 QByteArray fingerprint = fingerprintString.toLatin1(); 0186 const GpgME::Key key = context->key(fingerprint.constData(), err); 0187 if (err || key.isNull() || !key.numUserIDs() || !key.numSubkeys()) { 0188 qCDebug(KGET_DEBUG) << "There was an error while loading the key:" << err; 0189 } else { 0190 static const QStringList OWNERTRUST = QStringList() 0191 << i18nc("trust level", "Unknown") << i18nc("trust level", "Undefined") << i18nc("trust level", "Never") << i18nc("trust level", "Marginal") 0192 << i18nc("trust level", "Full") << i18nc("trust level", "Ultimate"); 0193 0194 if (key.isRevoked()) { 0195 information << i18n("The key has been revoked."); 0196 problem = true; 0197 } 0198 if (key.isDisabled()) { 0199 information << i18n("The key is disabled."); 0200 problem = true; 0201 } 0202 if (key.isInvalid()) { 0203 information << i18n("The key is invalid."); 0204 error = true; 0205 } 0206 ui.expirationIcon->clear(); 0207 if (key.isExpired()) { 0208 information << i18n("The key is expired."); 0209 ui.expirationIcon->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(iconSize)); 0210 ui.expirationIcon->show(); 0211 problem = true; 0212 } else { 0213 ui.expirationIcon->hide(); 0214 } 0215 0216 // handle the trust of the key 0217 const GpgME::Key::OwnerTrust ownerTrust = key.ownerTrust(); 0218 ui.trust->setText(OWNERTRUST.value(ownerTrust)); 0219 0220 switch (ownerTrust) { 0221 case GpgME::Key::Never: 0222 information.prepend(i18n("The key is not to be trusted.")); 0223 ui.trustIcon->setPixmap(QIcon::fromTheme("dialog-error").pixmap(iconSize)); 0224 error = true; 0225 break; 0226 case GpgME::Key::Marginal: 0227 information.prepend(i18n("The key is to be trusted marginally.")); 0228 ui.trustIcon->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(iconSize)); 0229 problem = true; 0230 break; 0231 case GpgME::Key::Full: 0232 ui.trustIcon->setPixmap(QIcon::fromTheme("dialog-ok").pixmap(iconSize)); 0233 break; 0234 case GpgME::Key::Ultimate: 0235 ui.trustIcon->setPixmap(QIcon::fromTheme("dialog-ok").pixmap(iconSize)); 0236 break; 0237 case GpgME::Key::Unknown: 0238 case GpgME::Key::Undefined: 0239 default: 0240 information.prepend(i18n("Trust level of the key is unclear.")); 0241 ui.trustIcon->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(iconSize)); 0242 problem = true; 0243 break; 0244 } 0245 0246 // issuer, issuer mail and comment 0247 if (key.numUserIDs()) { 0248 const GpgME::UserID userID = key.userID(0); 0249 ui.issuer->setText(userID.name()); 0250 ui.comment->setText(userID.comment()); 0251 ui.email->setText(userID.email()); 0252 } 0253 0254 // key creation/expiration-time 0255 if (key.numSubkeys()) { 0256 const GpgME::Subkey subKey = key.subkey(0); 0257 0258 time_t creation = subKey.creationTime(); 0259 QDateTime creationTime; 0260 creationTime.setSecsSinceEpoch(creation); 0261 ui.creation->setText(creationTime.toString()); 0262 0263 time_t expiration = subKey.expirationTime(); 0264 if (expiration) { 0265 QDateTime expirationTime; 0266 expirationTime.setSecsSinceEpoch(expiration); 0267 ui.expiration->setText(expirationTime.toString()); 0268 } else { 0269 ui.expiration->setText(i18n("Unlimited")); 0270 } 0271 } 0272 } 0273 } 0274 } 0275 #endif // HAVE_QGPGME 0276 0277 const Signature::VerificationStatus verificationStatus = m_signature->status(); 0278 0279 // display the verification status 0280 ui.verificationIcon->hide(); 0281 switch (verificationStatus) { 0282 case Signature::Verified: 0283 case Signature::VerifiedInformation: 0284 case Signature::VerifiedWarning: 0285 ui.verificationIcon->setPixmap(QIcon::fromTheme("dialog-ok").pixmap(iconSize)); 0286 ui.verificationIcon->show(); 0287 ui.verified->setText(i18nc("pgp signature is verified", "Verified")); 0288 break; 0289 case Signature::NotVerified: 0290 ui.verified->setText(i18nc("pgp signature is not verified", "Failed")); 0291 ui.verificationIcon->setPixmap(QIcon::fromTheme("dialog-error").pixmap(iconSize)); 0292 ui.verificationIcon->show(); 0293 information.prepend(i18n("Caution: Verification failed. Either you entered the wrong signature, or the data has been modified.")); 0294 error = true; 0295 break; 0296 case Signature::NotWorked: // TODO downloading state? --> currently downloading 0297 ui.verified->clear(); // TODO 0298 information.prepend( 0299 i18n("Verification not possible. Check the entered data, whether gpg-agent is running, or whether you have an Internet connection (for retrieving " 0300 "keys.)")); 0301 problem = true; 0302 break; 0303 case Signature::NoResult: 0304 ui.verified->clear(); // TODO 0305 break; 0306 } 0307 0308 if (verificationStatus == Signature::VerifiedWarning) { 0309 problem = true; 0310 } 0311 0312 #ifndef HAVE_QGPGME 0313 ui.sigGroup->hide(); 0314 ui.keyGroup->hide(); 0315 ui.verify->hide(); 0316 information.clear(); 0317 information << i18n("Feature is not supported, as KGet is not compiled with QPGME support."); 0318 resize(350, 200); 0319 #endif // HAVE_QPGME 0320 0321 // TODO more messages, e.g. from result etc. 0322 // TODO enter more error cases 0323 0324 // change the icon of the titlewidget 0325 if (error) { 0326 ui.information->setMessageType(KMessageWidget::Error); 0327 } else if (problem) { 0328 ui.information->setMessageType(KMessageWidget::Warning); 0329 } else { 0330 if (verificationStatus != Signature::Verified) { 0331 ui.information->setMessageType(KMessageWidget::Information); 0332 } 0333 } 0334 0335 const QString text = information.join(" "); 0336 ui.information->setVisible(!text.isEmpty()); 0337 ui.information->setText(text); 0338 } 0339 0340 void SignatureDlg::verifyClicked() 0341 { 0342 clearData(); 0343 0344 m_signature->verify(); 0345 } 0346 0347 void SignatureDlg::clearData() 0348 { 0349 ui.verified->clear(); 0350 ui.verificationIcon->clear(); 0351 ui.issuer->clear(); 0352 ui.email->clear(); 0353 ui.comment->clear(); 0354 ui.creation->clear(); 0355 ui.expiration->clear(); 0356 ui.expirationIcon->hide(); 0357 ui.trust->clear(); 0358 ui.trustIcon->clear(); 0359 ui.fingerprint->clear(); 0360 } 0361 0362 void SignatureDlg::handleWidgets(bool isAsciiSig) 0363 { 0364 ui.asciiLabel->setVisible(isAsciiSig); 0365 ui.signature->setVisible(isAsciiSig); 0366 ui.binaryLabel->setVisible(!isAsciiSig); 0367 QLayoutItem *item = ui.verticalLayout_2->itemAt(ui.verticalLayout_2->count() - 1); 0368 QSpacerItem *spacer = item->spacerItem(); 0369 if (isAsciiSig) { 0370 if (spacer) { 0371 ui.verticalLayout_2->removeItem(item); 0372 delete item; 0373 } 0374 } else if (!spacer) { 0375 ui.verticalLayout_2->addStretch(1); 0376 } 0377 } 0378 0379 #include "moc_signaturedlg.cpp"