1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2011-03-22
7  * Description : a Iface C++ interface
8  *
9  * Copyright (C) 2011-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C) 2011      by Alexandre Mendes <alex dot mendes1988 at gmail dot com>
11  * Copyright (C) 2011      by Peter Potrowl <peter dot potrowl at gmail dot com>
12  * Copyright (C) 2011      by Manuel Campomanes <campomanes dot manuel at gmail dot com>
13  *
14  * This program is free software; you can redistribute it
15  * and/or modify it under the terms of the GNU General
16  * Public License as published by the Free Software Foundation;
17  * either version 2, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * ============================================================ */
25 
26 #include "mediawiki_login.h"
27 
28 // Qt includes
29 
30 #include <QStringList>
31 #include <QTimer>
32 #include <QUrl>
33 #include <QUrlQuery>
34 #include <QXmlStreamReader>
35 #include <QNetworkCookie>
36 #include <QNetworkReply>
37 #include <QNetworkRequest>
38 
39 // Local includes
40 
41 #include "mediawiki_iface.h"
42 #include "mediawiki_job_p.h"
43 
44 namespace MediaWiki
45 {
46 
47 class Q_DECL_HIDDEN LoginPrivate : public JobPrivate
48 {
49 
50 public:
51 
LoginPrivate(Iface & MediaWiki,const QString & login,const QString & password)52     LoginPrivate(Iface& MediaWiki, const QString& login, const QString& password)
53         : JobPrivate(MediaWiki),
54           login(login),
55           password(password)
56     {
57     }
58 
error(const QString & error)59     static int error(const QString& error)
60     {
61         QStringList list;
62         list << QStringLiteral("NoName")
63              << QStringLiteral("Illegal")
64              << QStringLiteral("NotExists")
65              << QStringLiteral("EmptyPass")
66              << QStringLiteral("WrongPass")
67              << QStringLiteral("WrongPluginPass")
68              << QStringLiteral("CreateBlocked")
69              << QStringLiteral("Throttled")
70              << QStringLiteral("Blocked")
71              << QStringLiteral("NeedToken");
72 
73         int ret = list.indexOf(error);
74 
75         if (ret == -1)
76         {
77             ret = 0;
78         }
79 
80         return (ret + (int)Login::LoginMissing);
81     }
82 
83 public:
84 
85     QUrl    baseUrl;
86     QString login;
87     QString password;
88     QString lgsessionid;
89     QString lgtoken;
90 };
91 
Login(Iface & MediaWiki,const QString & login,const QString & password,QObject * const parent)92 Login::Login(Iface& MediaWiki, const QString& login, const QString& password, QObject* const parent)
93     : Job(*new LoginPrivate(MediaWiki, login, password), parent)
94 {
95 }
96 
~Login()97 Login::~Login()
98 {
99 }
100 
start()101 void Login::start()
102 {
103     QTimer::singleShot(0, this, SLOT(doWorkSendRequest()));
104 }
105 
doWorkSendRequest()106 void Login::doWorkSendRequest()
107 {
108     Q_D(Login);
109 
110     // Set the url
111     QUrl url   = d->MediaWiki.url();
112     d->baseUrl = url;
113 
114     QUrlQuery query;
115     query.addQueryItem(QStringLiteral("format"), QStringLiteral("xml"));
116     query.addQueryItem(QStringLiteral("action"), QStringLiteral("login"));
117     query.addQueryItem(QStringLiteral("lgname"), d->login);
118     query.addQueryItem(QStringLiteral("lgpassword"), d->password);
119 
120     // Set the request
121     QNetworkRequest request(url);
122     request.setRawHeader(QByteArrayLiteral("User-Agent"), d->MediaWiki.userAgent().toUtf8());
123     request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/x-www-form-urlencoded"));
124 
125     // Send the request
126     d->reply = d->manager->post(request, query.toString().toUtf8());
127 
128     connect(d->reply, SIGNAL(finished()),
129             this, SLOT(doWorkProcessReply()));
130 }
131 
doWorkProcessReply()132 void Login::doWorkProcessReply()
133 {
134     Q_D(Login);
135 
136     disconnect(d->reply, SIGNAL(finished()),
137                this, SLOT(doWorkProcessReply()));
138 
139     if (d->reply->error() != QNetworkReply::NoError)
140     {
141         this->setError(Job::NetworkError);
142         d->reply->close();
143         d->reply->deleteLater();
144         emitResult();
145         return;
146     }
147 
148     QXmlStreamReader reader(d->reply);
149 
150     while (!reader.atEnd() && !reader.hasError())
151     {
152         QXmlStreamReader::TokenType token = reader.readNext();
153 
154         if (token == QXmlStreamReader::StartElement)
155         {
156             QXmlStreamAttributes attrs = reader.attributes();
157 
158             if (reader.name() == QLatin1String("login"))
159             {
160                 if (attrs.value(QStringLiteral("result")).toString() == QLatin1String("Success"))
161                 {
162                     this->setError(Job::NoError);
163                     d->lgtoken     = attrs.value(QStringLiteral("lgtoken")).toString();
164                     d->lgsessionid = attrs.value(QStringLiteral("sessionid")).toString();
165 
166                     if (d->manager->cookieJar()->cookiesForUrl(d->MediaWiki.url()).isEmpty())
167                     {
168                         QList<QNetworkCookie> cookies;
169                         QString prefix = attrs.value(QStringLiteral("cookieprefix")).toString();
170 
171                         QString prefixSession = prefix;
172                         prefixSession.append(QStringLiteral("_session"));
173                         QNetworkCookie cookie1(prefixSession.toUtf8(),attrs.value(QStringLiteral("sessionid")).toString().toUtf8());
174                         cookies.append(cookie1);
175 
176                         QString prefixUserName = prefix;
177                         prefixUserName.append(QStringLiteral("UserName"));
178                         QNetworkCookie cookie2(prefixUserName.toUtf8(),attrs.value(QStringLiteral("lgusername")).toString().toUtf8());
179                         cookies.append(cookie2);
180 
181                         QString prefixUserID = prefix;
182                         prefixUserID.append(QStringLiteral("UserID"));
183                         QNetworkCookie cookie3(prefixUserID.toUtf8(),attrs.value(QStringLiteral("lguserid")).toString().toUtf8());
184                         cookies.append(cookie3);
185 
186                         QString prefixToken = prefix;
187                         prefixToken.append(QStringLiteral("Token"));
188                         QNetworkCookie cookie4(prefixToken.toUtf8(),attrs.value(QStringLiteral("lgtoken")).toString().toUtf8());
189                         cookies.append(cookie4);
190 
191                         d->manager->cookieJar()->setCookiesFromUrl(cookies, d->MediaWiki.url());
192                     }
193 
194                     d->reply->close();
195                     d->reply->deleteLater();
196                     emitResult();
197                     return;
198                 }
199                 else if (attrs.value(QStringLiteral("result")).toString() == QLatin1String("NeedToken"))
200                 {
201                     this->setError(Job::NoError);
202                     d->lgtoken     = attrs.value(QStringLiteral("token")).toString();
203                     d->lgsessionid = attrs.value(QStringLiteral("sessionid")).toString();
204 
205                     if (d->manager->cookieJar()->cookiesForUrl(d->MediaWiki.url()).isEmpty())
206                     {
207                         QString prefix = attrs.value(QStringLiteral("cookieprefix")).toString();
208                         prefix.append(QStringLiteral("_session"));
209                         QNetworkCookie cookie(prefix.toUtf8(),QString(d->lgsessionid).toUtf8());
210                         QList<QNetworkCookie> cookies;
211                         cookies.append(cookie);
212                         d->manager->cookieJar()->setCookiesFromUrl(cookies, d->MediaWiki.url());
213                     }
214                 }
215                 else if (attrs.value(QStringLiteral("result")).toString() == QLatin1String("WrongToken"))
216                 {
217                     this->setError(LoginPrivate::error(attrs.value(QStringLiteral("result")).toString()));
218                     d->reply->close();
219                     d->reply->deleteLater();
220                     emitResult();
221                     return;
222                 }
223                 else if (attrs.value(QStringLiteral("result")).toString() == QLatin1String("Failed"))
224                 {
225                     this->setError(LoginPrivate::error(attrs.value(QStringLiteral("result")).toString()));
226                     d->reply->close();
227                     d->reply->deleteLater();
228                     emitResult();
229                     return;
230                 }
231             }
232             else if (reader.name() == QLatin1String("error"))
233             {
234                 this->setError(LoginPrivate::error(attrs.value(QStringLiteral("code")).toString()));
235                 d->reply->close();
236                 d->reply->deleteLater();
237                 emitResult();
238                 return;
239             }
240         }
241         else if (token == QXmlStreamReader::Invalid && reader.error() != QXmlStreamReader::PrematureEndOfDocumentError)
242         {
243             this->setError(XmlError);
244             d->reply->close();
245             d->reply->deleteLater();
246             emitResult();
247             return;
248         }
249     }
250     d->reply->close();
251     d->reply->deleteLater();
252 
253     QUrl url = d->baseUrl;
254 
255     QUrlQuery query;
256     query.addQueryItem(QStringLiteral("format"), QStringLiteral("xml"));
257     query.addQueryItem(QStringLiteral("action"), QStringLiteral("login"));
258     query.addQueryItem(QStringLiteral("lgname"), d->login);
259     query.addQueryItem(QStringLiteral("lgpassword"), d->password);
260     query.addQueryItem(QStringLiteral("lgtoken"), (d->lgtoken).replace(QStringLiteral("+"), QStringLiteral("%2B")));
261 
262     // Set the request
263     QNetworkRequest request(url);
264     request.setRawHeader("User-Agent", d->MediaWiki.userAgent().toUtf8());
265     request.setRawHeader("Cookie", d->manager->cookieJar()->cookiesForUrl(d->MediaWiki.url()).at(0).toRawForm());
266     request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/x-www-form-urlencoded"));
267 
268     // Send the request
269     d->reply = d->manager->post(request, query.toString().toUtf8());
270     connectReply();
271 
272     connect(d->reply, SIGNAL(finished()),
273             this, SLOT(doWorkProcessReply()));
274 }
275 
276 } // namespace MediaWiki
277