Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit a7ca3d97 authored by Sandro Knauß's avatar Sandro Knauß

Add support for text/pgp.

Summary:
If Someone sends an encrypted attachment without any content, we should
display the content of the encrypted attachment.

Test Plan:
show one text/pgp encrypted attachment correctly (included as testdata).

Also make sure, that a "fake" text/pgp attachment don't break the viewer.
This part is not working at the moment, I'll look at it later...

Reviewers: #kde_pim, vkrause

Subscribers: #kde_pim

Tags: #kde_pim

Differential Revision: https://phabricator.kde.org/D8521
parent 45962241
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
<div style="position: relative; word-wrap: break-word">
<a name="att"/>
<div id="attachmentDiv"/>
</div>
</body>
</html>
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
<div style="position: relative; word-wrap: break-word">
<a name="att"/>
<div id="attachmentDiv"/>
</div>
</body>
</html>
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
<div style="position: relative; word-wrap: break-word">
<a name="att"/>
<div id="attachmentDiv">
<a name="att1"/>
<div id="attachmentDiv1">
<div class="noquote">
<div dir="ltr">nothing is encrypted here.</div>
</div>
</div>
</div>
</div>
</body>
</html>
From unknown@example.org Tue Oct 03 10:05:19 2017
Return-Path: <unknown@example.org>
To: konqi@example.org
Subject: only an encrypted attachment
X-PHP-Originating-Script: 1008:rcube.php
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="=_XXXXXXXXXXXXXX"
Date: Tue, 03 Oct 2017 12:13:14 +0000
From: unknown@example.org
Message-ID: <XXXXXXXXXXXXXX12345@example.org>
X-Sender: unknown@example.org
User-Agent: Roundcube Webmail/1.1.9
--=_XXXXXXXXXXXXXX
Content-Transfer-Encoding: 7bit
Content-Type: text/PGP;
name=encrypted.txt.pgp
Content-Disposition: attachment;
filename=encrypted.txt.pgp;
size=1402
nothing is encrypted here.
--=_XXXXXXXXXXXXXX--
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
<div style="position: relative; word-wrap: break-word">
<a name="att"/>
<div id="attachmentDiv">
<a name="att1"/>
<div id="attachmentDiv1">
<hr/>
<div>
<a href="attachment:1?place=body"><img align="center" height="48" width="48" src="file:unknown.svg" border="0" style="max-width: 100%" alt=""/>encrypted.txt.pgp</a>
</div>
<div/>
</div>
</div>
</div>
</body>
</html>
* MimeTreeParser::MessagePartList
* MimeTreeParser::MimeMessagePart
* MimeTreeParser::AttachmentMessagePart
* MimeTreeParser::MessagePart
From unknown@example.org Tue Oct 03 10:05:19 2017
Return-Path: <unknown@example.org>
To: konqi@example.org
Subject: only an encrypted attachment
X-PHP-Originating-Script: 1008:rcube.php
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="=_XXXXXXXXXXXXXX"
Date: Tue, 03 Oct 2017 12:13:14 +0000
From: unknown@example.org
Message-ID: <XXXXXXXXXXXXXX12345@example.org>
X-Sender: unknown@example.org
User-Agent: Roundcube Webmail/1.1.9
--=_XXXXXXXXXXXXXX
Content-Transfer-Encoding: base64
Content-Type: text/PGP;
name=Brotzeiten.txt.pgp
Content-Disposition: attachment;
filename=encrypted.txt.pgp;
size=1402
hQEMAwzOQ1qnzNo7AQf/Z3qYebORMk5Z4R+Pmb6gBLA20G3yLRFyd0z+ygcEp+rc1jYE1ZqK1pFz
Z6WLgPdMcyrKBLrDeDfsQRbKvimR7NaXLSuNkRHFtgqCmaFDyIUMcf9DobAoKvGvmBJhgMW7WPCA
RUDaiJyqBp29nCQuOIqAiT5fm5LyyUmhRxUb9/CnulcxzW85EiITm0wMos30j1dU++3KDp5R6gcc
9uUVbdCWdiF4j3ilE8flCWg9tARTRGinu4ENc9eIjcn1hCotFS+4ccWYIwf6ZkVDS4wNfU7dDg+9
ZwNb+RkXuYXT/tFdir+ewV0Njaj0ZWTUrqZSk2ArmdGo9ou7xl/2mrK6YNJIAUKgVsQlWZ1Kx4PI
0k0+TsJBgRzVNpIBHpmu0MI4CE03XHUslFhzdrjOG2Ts26U3EJw+jjssu0W4MVzYc20u3BgRnzHn
/SFA
--=_XXXXXXXXXXXXXX--
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
<div style="position: relative; word-wrap: break-word">
<a name="att"/>
<div id="attachmentDiv">
<a name="att1"/>
<div id="attachmentDiv1">
<table cellspacing="1" cellpadding="1" class="encr">
<tr class="encrH">
<td dir="ltr">
<div class="enc-simple">Encrypted message<a href="kmail:showEncryptionDetails" style="display:block;float:right;">Show Details</a></div>
<div class="enc-details" style="display:none;">The message is encrypted for the following keys:<a href="kmail:hideEncryptionDetails" style="display:block;float:right;">Hide Details</a><ul style="list-style-type: none;"><li>unittest key (no password) &lt;test@kolab.org&gt; (<a href="kmail:showCertificate#gpg ### OpenPGP ### 8D9860C58F246DE6">0x8D9860C58F246DE6</a>)</li></ul></div>
</td>
</tr>
<tr class="encrB">
<td>
<div style="position: relative; word-wrap: break-word">
<a name="att"/>
<div id="attachmentDiv">
<div class="noquote">
<div dir="ltr">qwertzuiopü</div>
</div>
</div>
</div>
</td>
</tr>
<tr class="encrH">
<td dir="ltr">End of encrypted message</td>
</tr>
</table>
</div>
</div>
</div>
</body>
</html>
* MimeTreeParser::MessagePartList
* MimeTreeParser::MimeMessagePart
* MimeTreeParser::EncryptedMessagePart
* MimeTreeParser::TextMessagePart
* MimeTreeParser::MessagePart
......@@ -11,6 +11,7 @@ include_directories(${GPGME_INCLUDES})
set(libmimetreeparser_main_SRCS
bodyformatter/applicationpgpencrypted.cpp
bodyformatter/applicationpkcs7mime.cpp
bodyformatter/encrypted.cpp
bodyformatter/mailman.cpp
bodyformatter/multipartalternative.cpp
bodyformatter/multipartencrypted.cpp
......
/*
Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include "encrypted.h"
#include "utils.h"
#include "objecttreeparser.h"
#include "messagepart.h"
#include <KMime/Content>
#include <QGpgME/Protocol>
#include <QTextCodec>
#include "mimetreeparser_debug.h"
using namespace MimeTreeParser;
const EncryptedBodyPartFormatter *EncryptedBodyPartFormatter::self;
const Interface::BodyPartFormatter *EncryptedBodyPartFormatter::create()
{
if (!self) {
self = new EncryptedBodyPartFormatter();
}
return self;
}
MessagePart::Ptr EncryptedBodyPartFormatter::process(Interface::BodyPart &part) const
{
KMime::Content *node = part.content();
if (!node->contents().isEmpty()) {
Q_ASSERT(false);
return MessagePart::Ptr();
}
const QGpgME::Protocol *useThisCryptProto = nullptr;
useThisCryptProto = QGpgME::openpgp();
//TODO: Load correct crypto Proto
part.nodeHelper()->setEncryptionState(node, KMMsgFullyEncrypted);
EncryptedMessagePart::Ptr mp(new EncryptedMessagePart(part.objectTreeParser(),
node->decodedText(), useThisCryptProto,
part.nodeHelper()->fromAsString(node), node));
mp->setIsEncrypted(true);
mp->setDecryptMessage(part.source()->decryptMessage());
PartMetaData *messagePart(mp->partMetaData());
if (!part.source()->decryptMessage()) {
part.nodeHelper()->setNodeProcessed(node, false); // Set the data node to done to prevent it from being processed
} else if (KMime::Content *newNode = part.nodeHelper()->decryptedNodeForContent(node)) {
// if we already have a decrypted node for part.objectTreeParser() encrypted node, don't do the decryption again
return MessagePart::Ptr(new MimeMessagePart(part.objectTreeParser(), newNode, true));
} else {
const auto codec = QTextCodec::codecForName("utf-8");
mp->startDecryption(node->decodedContent(), codec);
qCDebug(MIMETREEPARSER_LOG) << "decrypted, signed?:" << messagePart->isSigned;
if (!messagePart->inProgress) {
if (!messagePart->isEncrypted) {
return nullptr;
}
auto tempNode = new KMime::Content();
qDebug() << part.nodeHelper()->codec(node)->name();
tempNode->contentType()->setCharset("utf-8");
tempNode->setBody(KMime::CRLFtoLF(part.nodeHelper()->codec(node)->fromUnicode(mp->text())));
tempNode->parse();
if (!tempNode->head().isEmpty()) {
tempNode->contentDescription()->from7BitString("encrypted data");
}
part.nodeHelper()->cleanExtraContent(node);
mp->clearSubParts();
part.nodeHelper()->attachExtraContent(node, tempNode);
mp->parseInternal(tempNode, false);
part.nodeHelper()->setNodeProcessed(node, false); // Set the data node to done to prevent it from being processed
}
}
return mp;
}
/*
Copyright (c) 2017 Sandro Knauß <sknauss@kde.org>
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#ifndef __MIMETREEPARSER_BODYFORAMATTER_ENCRYPTED_H__
#define __MIMETREEPARSER_BODYFORAMATTER_ENCRYPTED_H__
#include "interfaces/bodypartformatter.h"
#include "interfaces/bodypart.h"
namespace MimeTreeParser {
class EncryptedBodyPartFormatter : public Interface::BodyPartFormatter
{
static const EncryptedBodyPartFormatter *self;
public:
MessagePartPtr process(Interface::BodyPart &part) const override;
static const Interface::BodyPartFormatter *create();
};
}
#endif
......@@ -33,6 +33,7 @@
#include "bodyformatter/applicationpgpencrypted.h"
#include "bodyformatter/applicationpkcs7mime.h"
#include "bodyformatter/encrypted.h"
#include "bodyformatter/mailman.h"
#include "bodyformatter/multipartalternative.h"
#include "bodyformatter/multipartmixed.h"
......@@ -166,6 +167,7 @@ void BodyPartFormatterFactoryPrivate::messageviewer_create_builtin_bodypart_form
insert(QStringLiteral("application/octet-stream"), ApplicationPkcs7MimeBodyPartFormatter::create());
insert(QStringLiteral("application/octet-stream"), AnyTypeBodyPartFormatter::create());
insert(QStringLiteral("text/pgp"), EncryptedBodyPartFormatter::create());
insert(QStringLiteral("text/html"), TextHtmlBodyPartFormatter::create());
insert(QStringLiteral("text/rtf"), AnyTypeBodyPartFormatter::create());
insert(QStringLiteral("text/plain"), MailmanBodyPartFormatter::create());
......
......@@ -242,6 +242,11 @@ bool MessagePart::hasSubParts() const
return !d->mBlocks.isEmpty();
}
void MessagePart::clearSubParts()
{
d->mBlocks.clear();
}
//-----MessagePartList----------------------
MessagePartList::MessagePartList(ObjectTreeParser *otp)
: MessagePart(otp, QString())
......@@ -1221,7 +1226,16 @@ bool EncryptedMessagePart::okDecryptMIME(KMime::Content &data)
}
mDecryptRecipients.clear();
bDecryptionOk = !decryptResult.error();
// std::stringstream ss;
// ss << decryptResult << '\n' << verifyResult;
// qCDebug(MIMETREEPARSER_LOG) << ss.str().c_str();
for (const auto &recipient : decryptResult.recipients()) {
if (!recipient.status()) {
bDecryptionOk = true;
}
GpgME::Key key;
QGpgME::KeyListJob *job = mCryptoProto->keyListJob(false, false, false); // local, no sigs
if (!job) {
......@@ -1246,10 +1260,6 @@ bool EncryptedMessagePart::okDecryptMIME(KMime::Content &data)
}
mDecryptRecipients.push_back(std::make_pair(recipient, key));
}
bDecryptionOk = !decryptResult.error();
// std::stringstream ss;
// ss << decryptResult << '\n' << verifyResult;
// qCDebug(MIMETREEPARSER_LOG) << ss.str().c_str();
if (!bDecryptionOk && partMetaData()->isSigned) {
//Only a signed part
......@@ -1258,7 +1268,7 @@ bool EncryptedMessagePart::okDecryptMIME(KMime::Content &data)
mDecryptedData = plainText;
} else {
mPassphraseError = decryptResult.error().isCanceled() || decryptResult.error().code() == GPG_ERR_NO_SECKEY;
partMetaData()->isEncrypted = decryptResult.error().code() != GPG_ERR_NO_DATA;
partMetaData()->isEncrypted = bDecryptionOk || decryptResult.error().code() != GPG_ERR_NO_DATA;
partMetaData()->errorText = QString::fromLocal8Bit(decryptResult.error().asString());
if (partMetaData()->isEncrypted && decryptResult.numRecipients() > 0) {
partMetaData()->keyId = decryptResult.recipient(0).keyID();
......
......@@ -125,6 +125,7 @@ public:
void appendSubPart(const MessagePart::Ptr &messagePart);
const QVector<MessagePart::Ptr> &subParts() const;
bool hasSubParts() const;
void clearSubParts();
Interface::ObjectTreeSource *source() const;
NodeHelper* nodeHelper() const;
......@@ -375,6 +376,7 @@ protected:
std::vector<std::pair<GpgME::DecryptionResult::Recipient, GpgME::Key>> mDecryptRecipients;
friend class DefaultRendererPrivate;
friend class EncryptedBodyPartFormatter;
};
class MIMETREEPARSER_EXPORT SignedMessagePart : public MessagePart
......
......@@ -815,6 +815,12 @@ void NodeHelper::attachExtraContent(KMime::Content *topLevelNode, KMime::Content
mExtraContents[topLevelNode].append(content);
}
void NodeHelper::cleanExtraContent(KMime::Content *topLevelNode)
{
qCDebug(MIMETREEPARSER_LOG) << "remove all extraContents for" << topLevelNode;
mExtraContents[topLevelNode].clear();
}
QList< KMime::Content * > NodeHelper::extraContents(KMime::Content *topLevelnode) const
{
return mExtraContents.value(topLevelnode);
......
......@@ -87,6 +87,8 @@ public:
/** Attach an extra node to an existing node */
void attachExtraContent(KMime::Content *topLevelNode, KMime::Content *content);
void cleanExtraContent(KMime::Content *topLevelNode);
/** Get the extra nodes attached to the @param topLevelNode and all sub-nodes of @param topLevelNode */
QList<KMime::Content *> extraContents(KMime::Content *topLevelNode) const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment