File indexing completed on 2024-11-10 04:50:05
0001 /* 0002 * SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 * 0006 */ 0007 0008 #include "filteractionwithcrypto.h" 0009 0010 #include <QProcess> 0011 #include <QStandardPaths> 0012 0013 using namespace MailCommon; 0014 0015 QStringList FilterActionWithCrypto::getEncryptionKeysFromContent(const KMime::Message::Ptr &msg, GpgME::Protocol protocol) const 0016 { 0017 if (protocol == GpgME::CMS && mGpgSmPath.isNull()) { 0018 const auto path = QStandardPaths::findExecutable(QStringLiteral("gpgsm")); 0019 mGpgSmPath = path.isEmpty() ? QString() : path; 0020 } else if (protocol == GpgME::OpenPGP && mGpgPath.isNull()) { 0021 auto path = QStandardPaths::findExecutable(QStringLiteral("gpg2")); 0022 if (path.isEmpty()) { 0023 path = QStandardPaths::findExecutable(QStringLiteral("gpg")); 0024 mGpgPath = path.isEmpty() ? QString() : path; 0025 } else { 0026 mGpgPath = path; 0027 } 0028 } 0029 0030 if ((protocol == GpgME::CMS && mGpgSmPath.isEmpty()) || (protocol == GpgME::OpenPGP && mGpgPath.isEmpty())) { 0031 return {}; 0032 } 0033 0034 QProcess gpg; 0035 QStringList keyIds; 0036 // TODO: contribute an API for this into gpgme 0037 if (protocol == GpgME::OpenPGP) { 0038 gpg.setProgram(mGpgPath); 0039 // --list-packets will give us list of keys used to encrypt the message 0040 // --batch will prevent gpg from asking for decryption password (we don't need it yet) 0041 gpg.setArguments({QStringLiteral("--list-packets"), QStringLiteral("--batch")}); 0042 gpg.start(QIODevice::ReadWrite); 0043 gpg.waitForStarted(); 0044 gpg.write(msg->encodedContent()); 0045 gpg.closeWriteChannel(); 0046 gpg.waitForFinished(); 0047 while (!gpg.atEnd()) { 0048 const auto l = gpg.readLine(); 0049 if (l.startsWith(":pubkey")) { 0050 const int pos = l.indexOf("keyid "); 0051 if (pos < 0) { 0052 continue; 0053 } 0054 const int start = pos + 6; // strlen("keyid ") 0055 const int len = l.size() - start - 1; // -1 to skip trailing \n 0056 keyIds << QString::fromUtf8(l.mid(start, len)); 0057 } 0058 } 0059 } else if (protocol == GpgME::CMS) { 0060 gpg.setProgram(mGpgSmPath); 0061 // --decrypt - the only way how to get the keys from gpgsm, sadly, is to decrypt the email 0062 // --status-fd 2 - make sure the status output is not mangled with the decrypted content 0063 // --assume-base64 - so that we don't have to decode it ourselves 0064 gpg.setArguments({QStringLiteral("--decrypt"), 0065 QStringLiteral("--status-fd"), 0066 QStringLiteral("2"), 0067 QStringLiteral("--debug-level"), 0068 QStringLiteral("basic"), 0069 QStringLiteral("--assume-base64")}); 0070 gpg.start(QIODevice::ReadWrite); 0071 gpg.waitForStarted(); 0072 gpg.write(msg->encodedBody()); // just the body! 0073 gpg.closeWriteChannel(); 0074 gpg.waitForFinished(); 0075 gpg.setReadChannel(QProcess::StandardError); 0076 while (!gpg.atEnd()) { 0077 const auto l = gpg.readLine(); 0078 if (l.startsWith("gpgsm: DBG: recp ")) { 0079 const int pos = l.indexOf("serial: "); 0080 if (pos < 0) { 0081 continue; 0082 } 0083 const int start = pos + 8; // strlen("serial: ") 0084 const int len = l.size() - start - 1; // -1 to skip trailing \n 0085 keyIds << QString::fromUtf8(l.mid(start, len)); 0086 } 0087 } 0088 } 0089 0090 return keyIds; 0091 } 0092 0093 #include "moc_filteractionwithcrypto.cpp"