cpp, qt: Include config.h
[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 #ifdef HAVE_CONFIG_H
32  #include "config.h"
33 #endif
34
35 #include <QDebug>
36 #include <QTest>
37 #include <QTemporaryDir>
38 #include <QSignalSpy>
39 #include <QBuffer>
40 #include "keylistjob.h"
41 #include "encryptjob.h"
42 #include "qgpgmeencryptjob.h"
43 #include "encryptionresult.h"
44 #include "decryptionresult.h"
45 #include "qgpgmedecryptjob.h"
46 #include "qgpgmebackend.h"
47 #include "keylistresult.h"
48 #include "engineinfo.h"
49 #include "t-support.h"
50
51 #define PROGRESS_TEST_SIZE 1 * 1024 * 1024
52
53 using namespace QGpgME;
54 using namespace GpgME;
55
56 class EncryptionTest : public QGpgMETest
57 {
58     Q_OBJECT
59
60 Q_SIGNALS:
61     void asyncDone();
62
63 private Q_SLOTS:
64
65     void testSimpleEncryptDecrypt()
66     {
67         auto listjob = openpgp()->keyListJob(false, false, false);
68         std::vector<Key> keys;
69         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
70                                           false, keys);
71         Q_ASSERT(!keylistresult.error());
72         Q_ASSERT(keys.size() == 1);
73         delete listjob;
74
75         auto job = openpgp()->encryptJob(/*ASCII Armor */true, /* Textmode */ true);
76         Q_ASSERT(job);
77         QByteArray cipherText;
78         auto result = job->exec(keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
79         delete job;
80         Q_ASSERT(!result.error());
81         const auto cipherString = QString::fromUtf8(cipherText);
82         Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
83
84         /* Now decrypt */
85         auto ctx = Context::createForProtocol(OpenPGP);
86         TestPassphraseProvider provider;
87         ctx->setPassphraseProvider(&provider);
88         ctx->setPinentryMode(Context::PinentryLoopback);
89         auto decJob = new QGpgMEDecryptJob(ctx);
90         QByteArray plainText;
91         auto decResult = decJob->exec(cipherText, plainText);
92         Q_ASSERT(!result.error());
93         Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello World"));
94         delete decJob;
95     }
96
97     void testProgress()
98     {
99         if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.15") {
100             // We can only test the progress with 2.1.15 as this started to
101             // have total progress for memory callbacks
102             return;
103         }
104         auto listjob = openpgp()->keyListJob(false, false, false);
105         std::vector<Key> keys;
106         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
107                                           false, keys);
108         Q_ASSERT(!keylistresult.error());
109         Q_ASSERT(keys.size() == 1);
110         delete listjob;
111
112         auto job = openpgp()->encryptJob(/*ASCII Armor */false, /* Textmode */ false);
113         Q_ASSERT(job);
114         QByteArray plainBa;
115         plainBa.fill('X', PROGRESS_TEST_SIZE);
116         QByteArray cipherText;
117
118         bool initSeen = false;
119         bool finishSeen = false;
120         connect(job, &Job::progress, this, [this, &initSeen, &finishSeen] (const QString& what, int current, int total) {
121                 // We only check for progress 0 and max progress as the other progress
122                 // lines depend on the system speed and are as such unreliable to test.
123                 Q_ASSERT(total == PROGRESS_TEST_SIZE);
124                 if (current == 0) {
125                     initSeen = true;
126                 }
127                 if (current == total) {
128                     finishSeen = true;
129                 }
130                 Q_ASSERT(current >= 0 && current <= total);
131             });
132         connect(job, &EncryptJob::result, this, [this, &initSeen, &finishSeen] (const GpgME::EncryptionResult &result,
133                                                                                 const QByteArray &cipherText,
134                                                                                 const QString,
135                                                                                 const GpgME::Error) {
136                 Q_ASSERT(initSeen);
137                 Q_ASSERT(finishSeen);
138                 Q_EMIT asyncDone();
139             });
140
141         auto inptr  = std::shared_ptr<QIODevice>(new QBuffer(&plainBa));
142         inptr->open(QIODevice::ReadOnly);
143         auto outptr = std::shared_ptr<QIODevice>(new QBuffer(&cipherText));
144         outptr->open(QIODevice::WriteOnly);
145
146         job->start(keys, inptr, outptr, Context::AlwaysTrust);
147         QSignalSpy spy (this, SIGNAL(asyncDone()));
148         Q_ASSERT(spy.wait());
149     }
150
151     void testSymmetricEncryptDecrypt()
152     {
153         auto ctx = Context::createForProtocol(OpenPGP);
154         TestPassphraseProvider provider;
155         ctx->setPassphraseProvider(&provider);
156         ctx->setPinentryMode(Context::PinentryLoopback);
157         ctx->setArmor(true);
158         ctx->setTextMode(true);
159         auto job = new QGpgMEEncryptJob(ctx);
160         QByteArray cipherText;
161         auto result = job->exec(std::vector<Key>(), QStringLiteral("Hello symmetric World").toUtf8(), Context::AlwaysTrust, cipherText);
162         delete job;
163         Q_ASSERT(!result.error());
164         const auto cipherString = QString::fromUtf8(cipherText);
165         Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
166
167         killAgent(mDir.path());
168
169         auto ctx2 = Context::createForProtocol(OpenPGP);
170         ctx2->setPassphraseProvider(&provider);
171         ctx2->setPinentryMode(Context::PinentryLoopback);
172         auto decJob = new QGpgMEDecryptJob(ctx2);
173         QByteArray plainText;
174         auto decResult = decJob->exec(cipherText, plainText);
175         Q_ASSERT(!result.error());
176         Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
177         delete decJob;
178     }
179
180 private:
181     /* Loopback and passphrase provider don't work for mixed encryption.
182      * So this test is disabled until gnupg(?) is fixed for this. */
183     void testMixedEncryptDecrypt()
184     {
185         auto listjob = openpgp()->keyListJob(false, false, false);
186         std::vector<Key> keys;
187         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
188                                           false, keys);
189         Q_ASSERT(!keylistresult.error());
190         Q_ASSERT(keys.size() == 1);
191         delete listjob;
192
193         auto ctx = Context::createForProtocol(OpenPGP);
194         ctx->setPassphraseProvider(new TestPassphraseProvider);
195         ctx->setPinentryMode(Context::PinentryLoopback);
196         ctx->setArmor(true);
197         ctx->setTextMode(true);
198         auto job = new QGpgMEEncryptJob(ctx);
199         QByteArray cipherText;
200         printf("Before exec, flags: %x\n", Context::Symmetric | Context::AlwaysTrust);
201         auto result = job->exec(keys, QStringLiteral("Hello symmetric World").toUtf8(),
202                                 static_cast<Context::EncryptionFlags>(Context::Symmetric | Context::AlwaysTrust),
203                                 cipherText);
204         printf("After exec\n");
205         delete job;
206         Q_ASSERT(!result.error());
207         printf("Cipher:\n%s\n", cipherText.constData());
208         const auto cipherString = QString::fromUtf8(cipherText);
209         Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
210
211         killAgent(mDir.path());
212
213         /* Now create a new homedir which with we test symetric decrypt. */
214         QTemporaryDir tmp;
215         qputenv("GNUPGHOME", tmp.path().toUtf8());
216         QFile agentConf(tmp.path() + QStringLiteral("/gpg-agent.conf"));
217         Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
218         agentConf.write("allow-loopback-pinentry");
219         agentConf.close();
220
221         auto ctx2 = Context::createForProtocol(OpenPGP);
222         ctx2->setPassphraseProvider(new TestPassphraseProvider);
223         ctx2->setPinentryMode(Context::PinentryLoopback);
224         ctx2->setTextMode(true);
225         auto decJob = new QGpgMEDecryptJob(ctx2);
226         QByteArray plainText;
227         auto decResult = decJob->exec(cipherText, plainText);
228         Q_ASSERT(!decResult.error());
229         qDebug() << "Plain: " << plainText;
230         Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
231         delete decJob;
232
233         killAgent(tmp.path());
234         qputenv("GNUPGHOME", mDir.path().toUtf8());
235     }
236
237 public Q_SLOT:
238
239     void initTestCase()
240     {
241         QGpgMETest::initTestCase();
242         const QString gpgHome = qgetenv("GNUPGHOME");
243         qputenv("GNUPGHOME", mDir.path().toUtf8());
244         Q_ASSERT(mDir.isValid());
245         QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
246         Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
247         agentConf.write("allow-loopback-pinentry");
248         agentConf.close();
249         Q_ASSERT(copyKeyrings(gpgHome, mDir.path()));
250     }
251
252 private:
253     QTemporaryDir mDir;
254 };
255
256 QTEST_MAIN(EncryptionTest)
257
258 #include "t-encrypt.moc"