1 /*
2  * Copyright (C) 2008-2021 The QXmpp developers
3  *
4  * Author:
5  *  Jeremy Lainé
6  *  Linus Jahn
7  *
8  * Source:
9  *  https://github.com/qxmpp-project/qxmpp
10  *
11  * This file is a part of QXmpp library.
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  */
24 
25 #include "QXmppBitsOfBinaryContentId.h"
26 #include "QXmppBitsOfBinaryData.h"
27 #include "QXmppBitsOfBinaryDataList.h"
28 #include "QXmppRegisterIq.h"
29 
30 #include "util.h"
31 #include <QObject>
32 
33 class tst_QXmppRegisterIq : public QObject
34 {
35     Q_OBJECT
36 
37 private slots:
38     void testGet();
39     void testResult();
40     void testResultWithForm();
41     void testSet();
42     void testSetWithForm();
43     void testBobData();
44     void testRegistered();
45     void testRemove();
46     void testChangePassword();
47     void testUnregistration();
48 };
49 
testGet()50 void tst_QXmppRegisterIq::testGet()
51 {
52     const QByteArray xml(
53         "<iq id=\"reg1\" to=\"shakespeare.lit\" type=\"get\">"
54         "<query xmlns=\"jabber:iq:register\"/>"
55         "</iq>");
56 
57     QXmppRegisterIq iq;
58     parsePacket(iq, xml);
59     QCOMPARE(iq.id(), QLatin1String("reg1"));
60     QCOMPARE(iq.to(), QLatin1String("shakespeare.lit"));
61     QCOMPARE(iq.from(), QString());
62     QCOMPARE(iq.type(), QXmppIq::Get);
63     QCOMPARE(iq.instructions(), QString());
64     QVERIFY(!iq.isRegistered());
65     QVERIFY(!iq.isRemove());
66     QVERIFY(iq.username().isNull());
67     QVERIFY(iq.password().isNull());
68     QVERIFY(iq.email().isNull());
69     QVERIFY(iq.form().isNull());
70     serializePacket(iq, xml);
71 }
72 
testResult()73 void tst_QXmppRegisterIq::testResult()
74 {
75     const QByteArray xml(
76         "<iq id=\"reg1\" type=\"result\">"
77         "<query xmlns=\"jabber:iq:register\">"
78         "<instructions>Choose a username and password for use with this service. Please also provide your email address.</instructions>"
79         "<username/>"
80         "<password/>"
81         "<email/>"
82         "</query>"
83         "</iq>");
84 
85     QXmppRegisterIq iq;
86     parsePacket(iq, xml);
87     QCOMPARE(iq.id(), QLatin1String("reg1"));
88     QCOMPARE(iq.to(), QString());
89     QCOMPARE(iq.from(), QString());
90     QCOMPARE(iq.type(), QXmppIq::Result);
91     QCOMPARE(iq.instructions(), QLatin1String("Choose a username and password for use with this service. Please also provide your email address."));
92     QVERIFY(!iq.username().isNull());
93     QVERIFY(iq.username().isEmpty());
94     QVERIFY(!iq.password().isNull());
95     QVERIFY(iq.password().isEmpty());
96     QVERIFY(!iq.email().isNull());
97     QVERIFY(iq.email().isEmpty());
98     QVERIFY(iq.form().isNull());
99     serializePacket(iq, xml);
100 }
101 
testResultWithForm()102 void tst_QXmppRegisterIq::testResultWithForm()
103 {
104     const QByteArray xml(
105         "<iq id=\"reg3\" to=\"juliet@capulet.com/balcony\" from=\"contests.shakespeare.lit\" type=\"result\">"
106         "<query xmlns=\"jabber:iq:register\">"
107         "<instructions>Use the enclosed form to register. If your Jabber client does not support Data Forms, visit http://www.shakespeare.lit/contests.php</instructions>"
108         "<x xmlns=\"jabber:x:data\" type=\"form\">"
109         "<title>Contest Registration</title>"
110         "<instructions>"
111         "Please provide the following information"
112         "to sign up for our special contests!"
113         "</instructions>"
114         "<field type=\"hidden\" var=\"FORM_TYPE\">"
115         "<value>jabber:iq:register</value>"
116         "</field>"
117         "<field type=\"text-single\" label=\"Given Name\" var=\"first\">"
118         "<required/>"
119         "</field>"
120         "<field type=\"text-single\" label=\"Family Name\" var=\"last\">"
121         "<required/>"
122         "</field>"
123         "<field type=\"text-single\" label=\"Email Address\" var=\"email\">"
124         "<required/>"
125         "</field>"
126         "<field type=\"list-single\" label=\"Gender\" var=\"x-gender\">"
127         "<option label=\"Male\"><value>M</value></option>"
128         "<option label=\"Female\"><value>F</value></option>"
129         "</field>"
130         "</x>"
131         "</query>"
132         "</iq>");
133 
134     QXmppRegisterIq iq;
135     parsePacket(iq, xml);
136     QCOMPARE(iq.id(), QLatin1String("reg3"));
137     QCOMPARE(iq.to(), QLatin1String("juliet@capulet.com/balcony"));
138     QCOMPARE(iq.from(), QLatin1String("contests.shakespeare.lit"));
139     QCOMPARE(iq.type(), QXmppIq::Result);
140     QCOMPARE(iq.instructions(), QLatin1String("Use the enclosed form to register. If your Jabber client does not support Data Forms, visit http://www.shakespeare.lit/contests.php"));
141     QVERIFY(iq.username().isNull());
142     QVERIFY(iq.password().isNull());
143     QVERIFY(iq.email().isNull());
144     QVERIFY(!iq.form().isNull());
145     QCOMPARE(iq.form().title(), QLatin1String("Contest Registration"));
146     serializePacket(iq, xml);
147 }
148 
testSet()149 void tst_QXmppRegisterIq::testSet()
150 {
151     const QByteArray xml(
152         "<iq id=\"reg2\" type=\"set\">"
153         "<query xmlns=\"jabber:iq:register\">"
154         "<username>bill</username>"
155         "<password>Calliope</password>"
156         "<email>bard@shakespeare.lit</email>"
157         "</query>"
158         "</iq>");
159 
160     QXmppRegisterIq iq;
161     parsePacket(iq, xml);
162     QCOMPARE(iq.id(), QLatin1String("reg2"));
163     QCOMPARE(iq.to(), QString());
164     QCOMPARE(iq.from(), QString());
165     QCOMPARE(iq.type(), QXmppIq::Set);
166     QCOMPARE(iq.username(), QLatin1String("bill"));
167     QCOMPARE(iq.password(), QLatin1String("Calliope"));
168     QCOMPARE(iq.email(), QLatin1String("bard@shakespeare.lit"));
169     QVERIFY(iq.form().isNull());
170     serializePacket(iq, xml);
171 }
172 
testSetWithForm()173 void tst_QXmppRegisterIq::testSetWithForm()
174 {
175     const QByteArray xml(
176         "<iq id=\"reg4\" to=\"contests.shakespeare.lit\" from=\"juliet@capulet.com/balcony\" type=\"set\">"
177         "<query xmlns=\"jabber:iq:register\">"
178         "<x xmlns=\"jabber:x:data\" type=\"submit\">"
179         "<field type=\"hidden\" var=\"FORM_TYPE\">"
180         "<value>jabber:iq:register</value>"
181         "</field>"
182         "<field type=\"text-single\" label=\"Given Name\" var=\"first\">"
183         "<value>Juliet</value>"
184         "</field>"
185         "<field type=\"text-single\" label=\"Family Name\" var=\"last\">"
186         "<value>Capulet</value>"
187         "</field>"
188         "<field type=\"text-single\" label=\"Email Address\" var=\"email\">"
189         "<value>juliet@capulet.com</value>"
190         "</field>"
191         "<field type=\"list-single\" label=\"Gender\" var=\"x-gender\">"
192         "<value>F</value>"
193         "</field>"
194         "</x>"
195         "</query>"
196         "</iq>");
197 
198     QXmppRegisterIq iq;
199     parsePacket(iq, xml);
200     QCOMPARE(iq.id(), QLatin1String("reg4"));
201     QCOMPARE(iq.to(), QLatin1String("contests.shakespeare.lit"));
202     QCOMPARE(iq.from(), QLatin1String("juliet@capulet.com/balcony"));
203     QCOMPARE(iq.type(), QXmppIq::Set);
204     QVERIFY(iq.username().isNull());
205     QVERIFY(iq.password().isNull());
206     QVERIFY(iq.email().isNull());
207     QVERIFY(!iq.form().isNull());
208     serializePacket(iq, xml);
209 
210     QXmppRegisterIq sIq;
211     sIq.setId(QLatin1String("reg4"));
212     sIq.setTo(QLatin1String("contests.shakespeare.lit"));
213     sIq.setFrom(QLatin1String("juliet@capulet.com/balcony"));
214     sIq.setType(QXmppIq::Set);
215     sIq.setForm(QXmppDataForm(
216         QXmppDataForm::Submit,
217         QList<QXmppDataForm::Field>()
218             << QXmppDataForm::Field(
219                    QXmppDataForm::Field::HiddenField,
220                    QStringLiteral("FORM_TYPE"),
221                    QStringLiteral("jabber:iq:register"))
222             << QXmppDataForm::Field(
223                    QXmppDataForm::Field::TextSingleField,
224                    QStringLiteral("first"),
225                    QStringLiteral("Juliet"),
226                    false,
227                    QStringLiteral("Given Name"))
228             << QXmppDataForm::Field(
229                    QXmppDataForm::Field::TextSingleField,
230                    QStringLiteral("last"),
231                    QStringLiteral("Capulet"),
232                    false,
233                    QStringLiteral("Family Name"))
234             << QXmppDataForm::Field(
235                    QXmppDataForm::Field::TextSingleField,
236                    QStringLiteral("email"),
237                    QStringLiteral("juliet@capulet.com"),
238                    false,
239                    QStringLiteral("Email Address"))
240             << QXmppDataForm::Field(
241                    QXmppDataForm::Field::ListSingleField,
242                    QStringLiteral("x-gender"),
243                    QStringLiteral("F"),
244                    false,
245                    QStringLiteral("Gender"))));
246     serializePacket(sIq, xml);
247 }
248 
testBobData()249 void tst_QXmppRegisterIq::testBobData()
250 {
251     const QByteArray xml = QByteArrayLiteral(
252         "<iq type=\"result\">"
253         "<query xmlns=\"jabber:iq:register\">"
254         "<data xmlns=\"urn:xmpp:bob\" "
255         "cid=\"sha1+5a4c38d44fc64805cbb2d92d8b208be13ff40c0f@bob.xmpp.org\" "
256         "type=\"image/png\">"
257         "iVBORw0KGgoAAAANSUhEUgAAALQAAAA8BAMAAAA9AI20AAAAG1BMVEX///8AAADf39+"
258         "/v79/f39fX1+fn58/Pz8fHx/8ACGJAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADS0lEQV"
259         "RYhe2WS3MSQRCAYTf7OKY1kT0CxsRjHmh5BENIjqEk6pHVhFzdikqO7CGyP9t59Ox2z"
260         "y6UeWBVqugLzM70Nz39mqnV1lIWgBWiYXV0BYfNZ0mvwypds1r62vH/gf76ZL/88Qlc"
261         "41zeAnQrpx5H3z1Npfr5ovmHusa9SpRiNNIOcdrto6PJ5LLfb5bp9zM+VDq/vptxDEa"
262         "a1sql9I3R5KhtfQsA5gNCWYyulV3TyTUDdfL56BvdDl4x7RiybDq9uBgxh1TTPUHDvA"
263         "qNQb+LpT5sWehxJZKKcU2MZ6sDE7PMgW2mdlBGdy6ODe6fJFdMI+us95dNqftDMdwU6"
264         "+MhpuTS9slcy5TFAcwq0Jt6qssJMTQGp4BGURlmSsNoo5oHL4kqc66NdkDO75mIfCxm"
265         "RAlvHxMLdcb7JONavMJbttXXKoMSneYu3OQTlwkUh4mNayi6js55/2VcsZOQfXIYelz"
266         "xLcntEGc3WVCsCORJVCc5r0ajAcq+EO1Q0oPm7n7+X/3jEReGdL6qT7Ml6FCjY+quJC"
267         "r+D01f6BG0SaHG56ZG32DnY2jcEV1+pU0kxTaEwaGcekN7jyu50U/TV4q6YeieyiNTu"
268         "klDKZLukyjKVNwotCUB3B0XO1WjHT3c0DHSO2zACwut8GOiljJIHaJsrlof/fpWNzGM"
269         "os6TgIY0hZNpJshzSi4igOhy3cl4qK+YgnqHkAYcZEgdW6/HyrEK7afoY7RCFzArLl2"
270         "LLDdrdmmHZfROajwIDfWj8yQG+rzwlA3WvdJiMHtjUekiNrp1oCbmyZDEyKROGjFVDr"
271         "PRzlkR9UAfG/OErnPxrop5BwpoEpXQorq2zcGxbnBJndx8Bh0yljGiGv0B4E8+YP3Xp"
272         "2rGydZNy4csW8W2pIvWhvijoujRJ0luXsoymV+8AXvE9HjII72+oReS6OfomHe3xWg/"
273         "f2coSbDa1XZ1CvGMjy1nH9KBl83oPnQKi+vAXKLjCrRvvT2WCMkPmSFbquiVuTH1qjv"
274         "p4j/u7CWyI5/Hn3KAaJJ90eP0Zp1Kjets4WPaElkxheF7cpBESzXuIdLwyFjSub07tB"
275         "6JjxH3DGiu+zwHHimdtFsMvKqG/nBxm2TwbvyU6LWs5RnJX4dSldg3QhDLAAAAAElFT"
276         "kSuQmCC"
277         "</data>"
278         "</query>"
279         "</iq>");
280 
281     QXmppBitsOfBinaryData data;
282     data.setCid(QXmppBitsOfBinaryContentId::fromContentId(
283         QStringLiteral("sha1+5a4c38d44fc64805cbb2d92d8b208be13ff40c0f@bob.xmpp.org")));
284     data.setContentType(QMimeDatabase().mimeTypeForName(QStringLiteral("image/png")));
285     data.setData(QByteArray::fromBase64(QByteArrayLiteral(
286         "iVBORw0KGgoAAAANSUhEUgAAALQAAAA8BAMAAAA9AI20AAAAG1BMVEX///8AAADf39+"
287         "/v79/f39fX1+fn58/Pz8fHx/8ACGJAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADS0lEQV"
288         "RYhe2WS3MSQRCAYTf7OKY1kT0CxsRjHmh5BENIjqEk6pHVhFzdikqO7CGyP9t59Ox2z"
289         "y6UeWBVqugLzM70Nz39mqnV1lIWgBWiYXV0BYfNZ0mvwypds1r62vH/gf76ZL/88Qlc"
290         "41zeAnQrpx5H3z1Npfr5ovmHusa9SpRiNNIOcdrto6PJ5LLfb5bp9zM+VDq/vptxDEa"
291         "a1sql9I3R5KhtfQsA5gNCWYyulV3TyTUDdfL56BvdDl4x7RiybDq9uBgxh1TTPUHDvA"
292         "qNQb+LpT5sWehxJZKKcU2MZ6sDE7PMgW2mdlBGdy6ODe6fJFdMI+us95dNqftDMdwU6"
293         "+MhpuTS9slcy5TFAcwq0Jt6qssJMTQGp4BGURlmSsNoo5oHL4kqc66NdkDO75mIfCxm"
294         "RAlvHxMLdcb7JONavMJbttXXKoMSneYu3OQTlwkUh4mNayi6js55/2VcsZOQfXIYelz"
295         "xLcntEGc3WVCsCORJVCc5r0ajAcq+EO1Q0oPm7n7+X/3jEReGdL6qT7Ml6FCjY+quJC"
296         "r+D01f6BG0SaHG56ZG32DnY2jcEV1+pU0kxTaEwaGcekN7jyu50U/TV4q6YeieyiNTu"
297         "klDKZLukyjKVNwotCUB3B0XO1WjHT3c0DHSO2zACwut8GOiljJIHaJsrlof/fpWNzGM"
298         "os6TgIY0hZNpJshzSi4igOhy3cl4qK+YgnqHkAYcZEgdW6/HyrEK7afoY7RCFzArLl2"
299         "LLDdrdmmHZfROajwIDfWj8yQG+rzwlA3WvdJiMHtjUekiNrp1oCbmyZDEyKROGjFVDr"
300         "PRzlkR9UAfG/OErnPxrop5BwpoEpXQorq2zcGxbnBJndx8Bh0yljGiGv0B4E8+YP3Xp"
301         "2rGydZNy4csW8W2pIvWhvijoujRJ0luXsoymV+8AXvE9HjII72+oReS6OfomHe3xWg/"
302         "f2coSbDa1XZ1CvGMjy1nH9KBl83oPnQKi+vAXKLjCrRvvT2WCMkPmSFbquiVuTH1qjv"
303         "p4j/u7CWyI5/Hn3KAaJJ90eP0Zp1Kjets4WPaElkxheF7cpBESzXuIdLwyFjSub07tB"
304         "6JjxH3DGiu+zwHHimdtFsMvKqG/nBxm2TwbvyU6LWs5RnJX4dSldg3QhDLAAAAAElFT"
305         "kSuQmCC")));
306 
307     QXmppRegisterIq parsedIq;
308     parsePacket(parsedIq, xml);
309     QCOMPARE(parsedIq.type(), QXmppIq::Result);
310     QCOMPARE(parsedIq.id(), QStringLiteral(""));
311     QCOMPARE(parsedIq.bitsOfBinaryData().size(), 1);
312     QCOMPARE(parsedIq.bitsOfBinaryData().first().cid().algorithm(), data.cid().algorithm());
313     QCOMPARE(parsedIq.bitsOfBinaryData().first().cid().hash(), data.cid().hash());
314     QCOMPARE(parsedIq.bitsOfBinaryData().first().cid(), data.cid());
315     QCOMPARE(parsedIq.bitsOfBinaryData().first().contentType(), data.contentType());
316     QCOMPARE(parsedIq.bitsOfBinaryData().first().maxAge(), data.maxAge());
317     QCOMPARE(parsedIq.bitsOfBinaryData().first().data(), data.data());
318     QCOMPARE(parsedIq.bitsOfBinaryData().first(), data);
319     serializePacket(parsedIq, xml);
320 
321     QXmppRegisterIq iq;
322     iq.setType(QXmppIq::Result);
323     iq.setId(QStringLiteral(""));
324     QXmppBitsOfBinaryDataList bobDataList;
325     bobDataList << data;
326     iq.setBitsOfBinaryData(bobDataList);
327     serializePacket(iq, xml);
328 
329     QXmppRegisterIq iq2;
330     iq2.setType(QXmppIq::Result);
331     iq2.setId(QStringLiteral(""));
332     iq2.bitsOfBinaryData() << data;
333     serializePacket(iq2, xml);
334 
335     // test const getter
336     const QXmppRegisterIq constIq = iq;
337     QCOMPARE(constIq.bitsOfBinaryData(), iq.bitsOfBinaryData());
338 }
339 
testRegistered()340 void tst_QXmppRegisterIq::testRegistered()
341 {
342     const QByteArray xml = QByteArrayLiteral(
343         "<iq type=\"result\">"
344         "<query xmlns=\"jabber:iq:register\">"
345         "<registered/>"
346         "<username>juliet</username>"
347         "</query>"
348         "</iq>");
349 
350     QXmppRegisterIq iq;
351     parsePacket(iq, xml);
352     QVERIFY(iq.isRegistered());
353     QCOMPARE(iq.username(), QStringLiteral("juliet"));
354     serializePacket(iq, xml);
355 
356     iq = QXmppRegisterIq();
357     iq.setId(QStringLiteral(""));
358     iq.setType(QXmppIq::Result);
359     iq.setIsRegistered(true);
360     iq.setUsername(QStringLiteral("juliet"));
361     serializePacket(iq, xml);
362 }
363 
testRemove()364 void tst_QXmppRegisterIq::testRemove()
365 {
366     const QByteArray xml = QByteArrayLiteral(
367         "<iq type=\"result\">"
368         "<query xmlns=\"jabber:iq:register\">"
369         "<remove/>"
370         "<username>juliet</username>"
371         "</query>"
372         "</iq>");
373 
374     QXmppRegisterIq iq;
375     parsePacket(iq, xml);
376     QVERIFY(iq.isRemove());
377     QCOMPARE(iq.username(), QStringLiteral("juliet"));
378     serializePacket(iq, xml);
379 
380     iq = QXmppRegisterIq();
381     iq.setId(QStringLiteral(""));
382     iq.setType(QXmppIq::Result);
383     iq.setIsRemove(true);
384     iq.setUsername(QStringLiteral("juliet"));
385     serializePacket(iq, xml);
386 }
387 
testChangePassword()388 void tst_QXmppRegisterIq::testChangePassword()
389 {
390     const QByteArray xml = QByteArrayLiteral(
391         "<iq id=\"changePassword1\" to=\"shakespeare.lit\" type=\"set\">"
392         "<query xmlns=\"jabber:iq:register\">"
393         "<username>bill</username>"
394         "<password>m1cr0$0ft</password>"
395         "</query>"
396         "</iq>");
397 
398     auto iq = QXmppRegisterIq::createChangePasswordRequest(
399         QStringLiteral("bill"),
400         QStringLiteral("m1cr0$0ft"),
401         QStringLiteral("shakespeare.lit"));
402     iq.setId(QStringLiteral("changePassword1"));
403     serializePacket(iq, xml);
404 }
405 
testUnregistration()406 void tst_QXmppRegisterIq::testUnregistration()
407 {
408     const QByteArray xml = QByteArrayLiteral(
409         "<iq id=\"unreg1\" to=\"shakespeare.lit\" type=\"set\">"
410         "<query xmlns=\"jabber:iq:register\">"
411         "<remove/>"
412         "</query>"
413         "</iq>");
414 
415     auto iq = QXmppRegisterIq::createUnregistrationRequest(QStringLiteral("shakespeare.lit"));
416     iq.setId(QStringLiteral("unreg1"));
417     serializePacket(iq, xml);
418 }
419 
420 QTEST_MAIN(tst_QXmppRegisterIq)
421 #include "tst_qxmppregisteriq.moc"
422