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