File indexing completed on 2023-10-01 08:39:29
0001 /************************************************************************** 0002 * Copyright (C) 2009-2011 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 "keydownloader.h" 0021 #include "settings.h" 0022 #include "signature_p.h" 0023 0024 #include "kget_debug.h" 0025 #include <QDebug> 0026 0027 #include <KLocalizedString> 0028 #include <KMessageBox> 0029 #include <kwidgetsaddons_version.h> 0030 0031 #include <QDomElement> 0032 #include <QGlobalStatic> 0033 0034 #ifdef HAVE_QGPGME 0035 #include <gpgme++/context.h> 0036 #include <gpgme++/data.h> 0037 #include <qgpgme/dataprovider.h> 0038 0039 #include <QFile> 0040 #endif 0041 0042 #ifdef HAVE_QGPGME 0043 Q_GLOBAL_STATIC(KeyDownloader, signatureDownloader) 0044 #endif // HAVE_QGPGME 0045 0046 SignaturePrivate::SignaturePrivate(Signature *signature) 0047 : q(signature) 0048 , type(Signature::NoType) 0049 , status(Signature::NoResult) 0050 , verifyTried(false) 0051 , sigSummary(0) 0052 , error(0) 0053 { 0054 } 0055 0056 SignaturePrivate::~SignaturePrivate() 0057 { 0058 } 0059 0060 void SignaturePrivate::signatureDownloaded() 0061 { 0062 if (verifyTried) { 0063 qCDebug(KGET_DEBUG) << "Rerun verification."; 0064 q->verify(); 0065 } 0066 } 0067 0068 #ifdef HAVE_QGPGME 0069 GpgME::VerificationResult SignaturePrivate::verify(const QUrl &dest, const QByteArray &sig) 0070 { 0071 GpgME::VerificationResult result; 0072 if (!QFile::exists(dest.toDisplayString(QUrl::PreferLocalFile)) || sig.isEmpty()) { 0073 return result; 0074 } 0075 0076 GpgME::initializeLibrary(); 0077 GpgME::Error error = GpgME::checkEngine(GpgME::OpenPGP); 0078 if (error) { 0079 qCDebug(KGET_DEBUG) << "OpenPGP not supported!"; 0080 return result; 0081 } 0082 0083 QScopedPointer<GpgME::Context> context(GpgME::Context::createForProtocol(GpgME::OpenPGP)); 0084 if (!context.data()) { 0085 qCDebug(KGET_DEBUG) << "Could not create context."; 0086 return result; 0087 } 0088 0089 std::shared_ptr<QFile> qFile(new QFile(dest.toDisplayString(QUrl::PreferLocalFile))); 0090 qFile->open(QIODevice::ReadOnly); 0091 auto *file = new QGpgME::QIODeviceDataProvider(qFile); 0092 GpgME::Data dFile(file); 0093 0094 QGpgME::QByteArrayDataProvider signatureBA(sig); 0095 GpgME::Data signature(&signatureBA); 0096 0097 return context->verifyDetachedSignature(signature, dFile); 0098 } 0099 #endif // HAVE_QGPGME 0100 0101 Signature::Signature(const QUrl &dest, QObject *object) 0102 : QObject(object) 0103 , d(new SignaturePrivate(this)) 0104 { 0105 d->dest = dest; 0106 #ifdef HAVE_QGPGME 0107 qRegisterMetaType<GpgME::VerificationResult>("GpgME::VerificationResult"); 0108 connect(&d->thread, &SignatureThread::verified, this, &Signature::slotVerified); 0109 #endif // HAVE_QGPGME 0110 } 0111 0112 Signature::~Signature() 0113 { 0114 delete d; 0115 } 0116 0117 QUrl Signature::destination() const 0118 { 0119 return d->dest; 0120 } 0121 0122 void Signature::setDestination(const QUrl &destination) 0123 { 0124 d->dest = destination; 0125 } 0126 0127 Signature::VerificationStatus Signature::status() const 0128 { 0129 return d->status; 0130 } 0131 0132 #ifdef HAVE_QGPGME 0133 GpgME::VerificationResult Signature::verificationResult() 0134 { 0135 return d->verificationResult; 0136 } 0137 #endif // HAVE_QGPGME 0138 0139 QByteArray Signature::signature() 0140 { 0141 return d->signature; 0142 } 0143 0144 void Signature::setAsciiDetachedSignature(const QString &signature) 0145 { 0146 setSignature(signature.toLatin1(), AsciiDetached); 0147 } 0148 0149 void Signature::setSignature(const QByteArray &signature, SignatureType type) 0150 { 0151 if ((signature == d->signature) && (type == d->type)) { 0152 return; 0153 } 0154 0155 d->type = type; 0156 d->signature = signature; 0157 0158 d->fingerprint.clear(); 0159 d->error = 0; 0160 d->sigSummary = 0; 0161 d->status = Signature::NoResult; 0162 0163 #ifdef HAVE_QGPGME 0164 d->verificationResult = GpgME::VerificationResult(); 0165 #endif // HAVE_QGPGME 0166 0167 Q_EMIT verified(d->status); // FIXME 0168 } 0169 0170 Signature::SignatureType Signature::type() const 0171 { 0172 return d->type; 0173 } 0174 0175 QString Signature::fingerprint() 0176 { 0177 return d->fingerprint; 0178 } 0179 0180 void Signature::downloadKey(QString fingerprint) // krazy:exclude=passbyvalue 0181 { 0182 #ifdef HAVE_QGPGME 0183 qCDebug(KGET_DEBUG) << "Downloading key:" << fingerprint; 0184 signatureDownloader->downloadKey(fingerprint, this); 0185 #else 0186 Q_UNUSED(fingerprint) 0187 #endif // HAVE_QGPGME 0188 } 0189 0190 bool Signature::isVerifyable() 0191 { 0192 #ifdef HAVE_QGPGME 0193 return QFile::exists(d->dest.toDisplayString(QUrl::PreferLocalFile)) && !d->signature.isEmpty(); 0194 #else 0195 return false; 0196 #endif // HAVE_QGPGME 0197 } 0198 0199 void Signature::verify() 0200 { 0201 #ifdef HAVE_QGPGME 0202 d->thread.verify(d->dest, d->signature); 0203 #endif // HAVE_QGPGME 0204 } 0205 0206 #ifdef HAVE_QGPGME 0207 void Signature::slotVerified(const GpgME::VerificationResult &result) 0208 { 0209 d->verificationResult = result; 0210 d->status = Signature::NotWorked; 0211 0212 if (!d->verificationResult.numSignatures()) { 0213 qCDebug(KGET_DEBUG) << "No signatures\n"; 0214 Q_EMIT verified(d->status); 0215 return; 0216 } 0217 0218 GpgME::Signature signature = d->verificationResult.signature(0); 0219 d->sigSummary = signature.summary(); 0220 d->error = signature.status().code(); 0221 d->fingerprint = signature.fingerprint(); 0222 0223 qCDebug(KGET_DEBUG) << "Fingerprint:" << d->fingerprint; 0224 qCDebug(KGET_DEBUG) << "Signature summary:" << d->sigSummary; 0225 qCDebug(KGET_DEBUG) << "Error code:" << d->error; 0226 0227 if (d->sigSummary & GpgME::Signature::KeyMissing) { 0228 qCDebug(KGET_DEBUG) << "Public key missing."; 0229 if (Settings::signatureAutomaticDownloading() || 0230 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0231 (KMessageBox::warningTwoActions(nullptr, 0232 #else 0233 (KMessageBox::warningYesNo(nullptr, 0234 #endif 0235 i18n("The key to verify the signature is missing, do you want to download it?"), 0236 QString(), 0237 KGuiItem(i18nc("@action:button", "Download"), QStringLiteral("document-save")), 0238 KGuiItem(i18nc("@action:button", "Continue Without"), QStringLiteral("dialog-cancel"))) 0239 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0240 == KMessageBox::PrimaryAction)) { 0241 #else 0242 == KMessageBox::Yes)) { 0243 #endif 0244 d->verifyTried = true; 0245 downloadKey(d->fingerprint); 0246 Q_EMIT verified(d->status); 0247 return; 0248 } 0249 } 0250 0251 if (!signature.status()) { 0252 if (d->sigSummary & GpgME::Signature::Valid) { 0253 d->status = Signature::Verified; 0254 } else if ((d->sigSummary & GpgME::Signature::Green) || (d->sigSummary == 0)) { 0255 d->status = Signature::VerifiedInformation; 0256 } 0257 } else if (signature.status()) { 0258 if ((d->sigSummary & GpgME::Signature::KeyExpired) || (d->sigSummary & GpgME::Signature::KeyRevoked)) { 0259 d->status = Signature::VerifiedWarning; 0260 } 0261 if (d->sigSummary & GpgME::Signature::Red) { // TODO handle more cases! 0262 d->status = Signature::NotVerified; 0263 // TODO handle that dialog better in 4.5 0264 KMessageBox::error(nullptr, 0265 i18n("The signature could not be verified for %1. See transfer settings for more information.", d->dest.fileName()), 0266 i18n("Signature not verified")); 0267 } 0268 } 0269 0270 Q_EMIT verified(d->status); 0271 } 0272 #endif // HAVE_QGPGME 0273 0274 void Signature::save(const QDomElement &element) 0275 { 0276 QDomElement e = element; 0277 0278 QDomElement verification = e.ownerDocument().createElement("signature"); 0279 verification.setAttribute("status", d->status); 0280 verification.setAttribute("sigStatus", d->sigSummary); 0281 verification.setAttribute("error", d->error); 0282 verification.setAttribute("fingerprint", d->fingerprint); 0283 verification.setAttribute("type", d->type); 0284 QDomText value; 0285 switch (d->type) { 0286 case NoType: 0287 case AsciiDetached: 0288 value = e.ownerDocument().createTextNode(d->signature); 0289 break; 0290 case BinaryDetached: 0291 value = e.ownerDocument().createTextNode(d->signature.toBase64()); 0292 break; 0293 } 0294 verification.appendChild(value); 0295 0296 e.appendChild(verification); 0297 } 0298 0299 void Signature::load(const QDomElement &e) 0300 { 0301 QDomElement verification = e.firstChildElement("signature"); 0302 d->status = static_cast<VerificationStatus>(verification.attribute("status").toInt()); 0303 d->sigSummary = verification.attribute("sigStatus").toInt(); 0304 d->error = verification.attribute("error").toInt(); 0305 d->fingerprint = verification.attribute("fingerprint"); 0306 d->type = static_cast<SignatureType>(verification.attribute("type").toInt()); 0307 switch (d->type) { 0308 case NoType: 0309 case AsciiDetached: 0310 d->signature = verification.text().toLatin1(); 0311 break; 0312 case BinaryDetached: 0313 d->signature = QByteArray::fromBase64(verification.text().toLatin1()); 0314 } 0315 } 0316 0317 #include "moc_signature.cpp"