3d4cfa922f0a0a56f472b4c25d1bddeb82f3a54f
[gpgme.git] / lang / qt / tests / t-encrypt.cpp
1 /* t-encrypt.cpp
2
3     This file is part of qgpgme, the Qt API binding for gpgme
4     Copyright (c) 2016 Intevation GmbH
5
6     QGpgME is free software; you can redistribute it and/or
7     modify it under the terms of the GNU General Public License as
8     published by the Free Software Foundation; either version 2 of the
9     License, or (at your option) any later version.
10
11     QGpgME is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
20     In addition, as a special exception, the copyright holders give
21     permission to link the code of this program with any edition of
22     the Qt library by Trolltech AS, Norway (or with modified versions
23     of Qt that use the same license as Qt), and distribute linked
24     combinations including the two.  You must obey the GNU General
25     Public License in all respects for all of the code used other than
26     Qt.  If you modify this file, you may extend this exception to
27     your version of the file, but you are not obligated to do so.  If
28     you do not wish to do so, delete this exception statement from
29     your version.
30 */
31 #include <QDebug>
32 #include <QTest>
33 #include <QTemporaryDir>
34 #include <QSignalSpy>
35 #include <QBuffer>
36 #include "keylistjob.h"
37 #include "encryptjob.h"
38 #include "qgpgmeencryptjob.h"
39 #include "encryptionresult.h"
40 #include "decryptionresult.h"
41 #include "qgpgmedecryptjob.h"
42 #include "qgpgmebackend.h"
43 #include "keylistresult.h"
44 #include "engineinfo.h"
45 #include "t-support.h"
46
47 #define PROGRESS_TEST_SIZE 1 * 1024 * 1024
48
49 using namespace QGpgME;
50 using namespace GpgME;
51
52 class EncryptionTest : public QGpgMETest
53 {
54     Q_OBJECT
55
56 Q_SIGNALS:
57     void asyncDone();
58
59 private Q_SLOTS:
60
61     void testSimpleEncryptDecrypt()
62     {
63         auto listjob = openpgp()->keyListJob(false, false, false);
64         std::vector<Key> keys;
65         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
66                                           false, keys);
67         Q_ASSERT(!keylistresult.error());
68         Q_ASSERT(keys.size() == 1);
69         delete listjob;
70
71         auto job = openpgp()->encryptJob(/*ASCII Armor */true, /* Textmode */ true);
72         Q_ASSERT(job);
73         QByteArray cipherText;
74         auto result = job->exec(keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
75         delete job;
76         Q_ASSERT(!result.error());
77         const auto cipherString = QString::fromUtf8(cipherText);
78         Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
79
80         /* Now decrypt */
81         auto ctx = Context::createForProtocol(OpenPGP);
82         TestPassphraseProvider provider;
83         ctx->setPassphraseProvider(&provider);
84         ctx->setPinentryMode(Context::PinentryLoopback);
85         auto decJob = new QGpgMEDecryptJob(ctx);
86         QByteArray plainText;
87         auto decResult = decJob->exec(cipherText, plainText);
88         Q_ASSERT(!result.error());
89         Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello World"));
90         delete decJob;
91     }
92
93     void testProgress()
94     {
95         if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.15") {
96             // We can only test the progress with 2.1.15 as this started to
97             // have total progress for memory callbacks
98             return;
99         }
100         auto listjob = openpgp()->keyListJob(false, false, false);
101         std::vector<Key> keys;
102         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
103                                           false, keys);
104         Q_ASSERT(!keylistresult.error());
105         Q_ASSERT(keys.size() == 1);
106         delete listjob;
107
108         auto job = openpgp()->encryptJob(/*ASCII Armor */false, /* Textmode */ false);
109         Q_ASSERT(job);
110         QByteArray plainBa;
111         plainBa.fill('X', PROGRESS_TEST_SIZE);
112         QByteArray cipherText;
113
114         bool initSeen = false;
115         bool finishSeen = false;
116         connect(job, &Job::progress, this, [this, &initSeen, &finishSeen] (const QString& what, int current, int total) {
117                 // We only check for progress 0 and max progress as the other progress
118                 // lines depend on the system speed and are as such unreliable to test.
119                 Q_ASSERT(total == PROGRESS_TEST_SIZE);
120                 if (current == 0) {
121                     initSeen = true;
122                 }
123                 if (current == total) {
124                     finishSeen = true;
125                 }
126                 Q_ASSERT(current >= 0 && current <= total);
127             });
128         connect(job, &EncryptJob::result, this, [this, &initSeen, &finishSeen] (const GpgME::EncryptionResult &result,
129                                                                                 const QByteArray &cipherText,
130                                                                                 const QString,
131                                                                                 const GpgME::Error) {
132                 Q_ASSERT(initSeen);
133                 Q_ASSERT(finishSeen);
134                 Q_EMIT asyncDone();
135             });
136
137         auto inptr  = std::shared_ptr<QIODevice>(new QBuffer(&plainBa));
138         inptr->open(QIODevice::ReadOnly);
139         auto outptr = std::shared_ptr<QIODevice>(new QBuffer(&cipherText));
140         outptr->open(QIODevice::WriteOnly);
141
142         job->start(keys, inptr, outptr, Context::AlwaysTrust);
143         QSignalSpy spy (this, SIGNAL(asyncDone()));
144         Q_ASSERT(spy.wait());
145     }
146
147     void testSymmetricEncryptDecrypt()
148     {
149         auto ctx = Context::createForProtocol(OpenPGP);
150         TestPassphraseProvider provider;
151         ctx->setPassphraseProvider(&provider);
152         ctx->setPinentryMode(Context::PinentryLoopback);
153         ctx->setArmor(true);
154         ctx->setTextMode(true);
155         auto job = new QGpgMEEncryptJob(ctx);
156         QByteArray cipherText;
157         auto result = job->exec(std::vector<Key>(), QStringLiteral("Hello symmetric World").toUtf8(), Context::AlwaysTrust, cipherText);
158         delete job;
159         Q_ASSERT(!result.error());
160         const auto cipherString = QString::fromUtf8(cipherText);
161         Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
162
163         killAgent(mDir.path());
164
165         auto ctx2 = Context::createForProtocol(OpenPGP);
166         ctx2->setPassphraseProvider(&provider);
167         ctx2->setPinentryMode(Context::PinentryLoopback);
168         auto decJob = new QGpgMEDecryptJob(ctx2);
169         QByteArray plainText;
170         auto decResult = decJob->exec(cipherText, plainText);
171         Q_ASSERT(!result.error());
172         Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
173         delete decJob;
174     }
175
176 private:
177     /* Loopback and passphrase provider don't work for mixed encryption.
178      * So this test is disabled until gnupg(?) is fixed for this. */
179     void testMixedEncryptDecrypt()
180     {
181         auto listjob = openpgp()->keyListJob(false, false, false);
182         std::vector<Key> keys;
183         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
184                                           false, keys);
185         Q_ASSERT(!keylistresult.error());
186         Q_ASSERT(keys.size() == 1);
187         delete listjob;
188
189         auto ctx = Context::createForProtocol(OpenPGP);
190         ctx->setPassphraseProvider(new TestPassphraseProvider);
191         ctx->setPinentryMode(Context::PinentryLoopback);
192         ctx->setArmor(true);
193         ctx->setTextMode(true);
194         auto job = new QGpgMEEncryptJob(ctx);
195         QByteArray cipherText;
196         printf("Before exec, flags: %x\n", Context::Symmetric | Context::AlwaysTrust);
197         auto result = job->exec(keys, QStringLiteral("Hello symmetric World").toUtf8(),
198                                 static_cast<Context::EncryptionFlags>(Context::Symmetric | Context::AlwaysTrust),
199                                 cipherText);
200         printf("After exec\n");
201         delete job;
202         Q_ASSERT(!result.error());
203         printf("Cipher:\n%s\n", cipherText.constData());
204         const auto cipherString = QString::fromUtf8(cipherText);
205         Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
206
207         killAgent(mDir.path());
208
209         /* Now create a new homedir which with we test symetric decrypt. */
210         QTemporaryDir tmp;
211         qputenv("GNUPGHOME", tmp.path().toUtf8());
212         QFile agentConf(tmp.path() + QStringLiteral("/gpg-agent.conf"));
213         Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
214         agentConf.write("allow-loopback-pinentry");
215         agentConf.close();
216
217         auto ctx2 = Context::createForProtocol(OpenPGP);
218         ctx2->setPassphraseProvider(new TestPassphraseProvider);
219         ctx2->setPinentryMode(Context::PinentryLoopback);
220         ctx2->setTextMode(true);
221         auto decJob = new QGpgMEDecryptJob(ctx2);
222         QByteArray plainText;
223         auto decResult = decJob->exec(cipherText, plainText);
224         Q_ASSERT(!decResult.error());
225         qDebug() << "Plain: " << plainText;
226         Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
227         delete decJob;
228
229         killAgent(tmp.path());
230         qputenv("GNUPGHOME", mDir.path().toUtf8());
231     }
232
233 public Q_SLOT:
234
235     void initTestCase()
236     {
237         QGpgMETest::initTestCase();
238         const QString gpgHome = qgetenv("GNUPGHOME");
239         qputenv("GNUPGHOME", mDir.path().toUtf8());
240         Q_ASSERT(mDir.isValid());
241         QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
242         Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
243         agentConf.write("allow-loopback-pinentry");
244         agentConf.close();
245         Q_ASSERT(copyKeyrings(gpgHome, mDir.path()));
246     }
247
248 private:
249     QTemporaryDir mDir;
250 };
251
252 QTEST_MAIN(EncryptionTest)
253
254 #include "t-encrypt.moc"