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