Changeset View
Standalone View
plugins/messageviewer/bodypartformatter/gnupgwks/pgpkeymessagepart.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | Copyright (c) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net> | ||||
3 | | ||||
4 | This library is free software; you can redistribute it and/or modify it | ||||
5 | under the terms of the GNU Library General Public License as published by | ||||
6 | the Free Software Foundation; either version 2 of the License, or (at your | ||||
7 | option) any later version. | ||||
8 | | ||||
9 | This library is distributed in the hope that it will be useful, but WITHOUT | ||||
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||||
12 | License for more details. | ||||
13 | | ||||
14 | You should have received a copy of the GNU Library General Public License | ||||
15 | along with this library; see the file COPYING.LIB. If not, write to the | ||||
16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||||
17 | 02110-1301, USA. | ||||
18 | */ | ||||
19 | | ||||
20 | #include "pgpkeymessagepart.h" | ||||
21 | | ||||
22 | #include <QProcess> | ||||
23 | | ||||
24 | #include <MimeTreeParser/BodyPart> | ||||
25 | #include <KMime/Content> | ||||
26 | | ||||
27 | PgpKeyMessagePart::PgpKeyMessagePart(MimeTreeParser::Interface::BodyPart *part) | ||||
28 | : mPart(part) | ||||
29 | { | ||||
30 | parseContent(mPart->content()); | ||||
31 | } | ||||
32 | | ||||
33 | QDateTime PgpKeyMessagePart::keyDate() const | ||||
34 | { | ||||
35 | return mKeyDate; | ||||
36 | } | ||||
37 | | ||||
38 | QString PgpKeyMessagePart::keyID() const | ||||
39 | { | ||||
40 | return mKeyID; | ||||
41 | } | ||||
42 | | ||||
43 | QString PgpKeyMessagePart::userID() const | ||||
44 | { | ||||
45 | return mUserID; | ||||
46 | } | ||||
47 | | ||||
48 | QString PgpKeyMessagePart::fingerprint() const | ||||
49 | { | ||||
50 | return mFingerprint; | ||||
51 | } | ||||
52 | | ||||
53 | GpgME::Key PgpKeyMessagePart::key() const | ||||
54 | { | ||||
55 | return mKey; | ||||
56 | } | ||||
57 | | ||||
58 | void PgpKeyMessagePart::setKey(const GpgME::Key &key) | ||||
59 | { | ||||
60 | mKey = key; | ||||
61 | } | ||||
62 | | ||||
63 | QString PgpKeyMessagePart::error() const | ||||
64 | { | ||||
65 | return mError; | ||||
66 | } | ||||
67 | | ||||
68 | void PgpKeyMessagePart::setError(const QString &error) | ||||
69 | { | ||||
70 | mError = error; | ||||
71 | } | ||||
72 | | ||||
73 | QByteArray PgpKeyMessagePart::rawKey() const | ||||
74 | { | ||||
75 | return mPart->content()->decodedContent(); | ||||
76 | } | ||||
77 | | ||||
78 | MimeTreeParser::Interface::ObjectTreeSource *PgpKeyMessagePart::source() const | ||||
79 | { | ||||
80 | return mPart->source(); | ||||
81 | } | ||||
82 | | ||||
knauss: what? gpgme do not offer any function to scan data is a key? | |||||
Yes,... *blushes for gpgme* And we need one here. This is fragile and dangerous. We can have multiple keys in a application/pgp-keys file. This would only show the last one. When a user is then offered to import the key (which I suggested in my other comment) he can be tricked into importing multiple keys with different fingerprints / userids. Also without an action gnupg determines by itself what it does with the data. E.g. try to decrypt it. I can't really think of an attack that could utilize this but maybe. I've written a new gpgme command for this gpgme_op_keylist_from_data which takes a gpgme_data_t and returns a keylistresult. Just need to get it upstream, which is surprisingly a bit difficult as I use "gpg --import-options import-show --dry-run --import" where upstream says that this is not technically a keylisting :-/ In qt this would be a keylistjob that takes a QByteArray. I'll let you know when we have API for that. (But Packagers will not like us if we depend on unreleased again. So maybe we should then use that with an Ifdef version guard.) :-) aheinecke: Yes,... *blushes for gpgme*
And we need one here. This is fragile and dangerous. We can have… | |||||
Upstream didn't accept my first patch as there are multiple ways to implement it and the best way (imo) is only available with a very recent gnupg version. This needs some discussion but it was pushed back with a "There are more important things at the moment". So this feature will come but not super soon. I have an issue for this: https://bugs.gnupg.org/gnupg/issue2819 In the meantime your hack is probably ok (Although as with the other gnupg process call it would be better to use GpgME::Engine info to figure out which "gpg" to call) aheinecke: Upstream didn't accept my first patch as there are multiple ways to implement it and the best… | |||||
83 | MimeTreeParser::Interface::BodyPart *PgpKeyMessagePart::part() const | ||||
84 | { | ||||
85 | return mPart; | ||||
86 | } | ||||
87 | | ||||
88 | | ||||
89 | void PgpKeyMessagePart::parseContent(KMime::Content *node) | ||||
90 | { | ||||
91 | QProcess p; | ||||
92 | p.start(QStringLiteral("gpg"), { QStringLiteral("--with-colons"), | ||||
93 | QStringLiteral("--fixed-list-mode"), | ||||
94 | QStringLiteral("--with-fingerprint") }); | ||||
95 | p.waitForStarted(); | ||||
96 | p.write(node->decodedContent()); | ||||
97 | p.closeWriteChannel(); | ||||
98 | p.waitForReadyRead(); | ||||
99 | const QByteArray result = p.readAllStandardOutput(); | ||||
100 | p.waitForFinished(); | ||||
101 | | ||||
102 | const auto lines = result.split('\n'); | ||||
mlaurent: Perhaps we can cache "cols.size()" to avoid to recall this method no ? | |||||
103 | for (const auto &line : lines) { | ||||
104 | const auto cols = line.split(':'); | ||||
105 | if (cols.isEmpty()) { | ||||
106 | continue; | ||||
107 | } | ||||
108 | | ||||
109 | const int size = cols.size(); | ||||
110 | | ||||
111 | // "pub" line can appear multiple times, but we are only interested in | ||||
112 | // the first one | ||||
113 | if (cols[0] == "pub" && mKeyID.isEmpty()) { | ||||
114 | if (size > 4) { | ||||
115 | mKeyID = QString::fromUtf8(cols[4]); | ||||
116 | } | ||||
117 | // gpg1: "pub" contains UID | ||||
118 | if (size > 9) { | ||||
119 | mUserID = QString::fromUtf8(cols[9]); | ||||
120 | } | ||||
121 | if (size > 6) { | ||||
122 | mKeyDate = QDateTime::fromTime_t(cols[5].toUInt()); | ||||
123 | } | ||||
124 | // gpg2: UID is on a separate line | ||||
125 | } else if (cols[0] == "uid" && size > 9 && mUserID.isEmpty()) { | ||||
126 | mUserID = QString::fromUtf8(cols[9]); | ||||
127 | } else if (cols[0] == "fpr" && size > 9 && mFingerprint.isEmpty()) { | ||||
128 | mFingerprint = QString::fromLatin1(cols[9]); | ||||
129 | } | ||||
130 | } | ||||
131 | } | ||||
132 | |
what? gpgme do not offer any function to scan data is a key?