Skip to content

Commit 5b2bc26

Browse files
committed
First commit for clientlogin + 2FA
To be able to login with 2FA enabled, we need to use clientlogin instead of login. In case of 2fa, a second http request is needed to send user, pass, totp (2fa code), fake loginreturnurl, rememberMe boolean and our classical token. It's the first commit, curently the login form works as usual for normal users. users with 2fa enabled wan't be connected yet. So this commit is not ready to be merged for now. Ispirated by https://github.com/commons-app/apps-android-commons/blob/b0e8175003a686789474238dd293aa89d1e925c7/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java#L93 Bug: https://phabricator.wikimedia.org/T180279
1 parent 2e53b2c commit 5b2bc26

File tree

4 files changed

+69
-33
lines changed

4 files changed

+69
-33
lines changed

huggle/Localization/en.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@
298298
<string name="login-ro-title">Switch to read-only</string>
299299
<string name="login-ro-question">One or more projects ($1) do not allow you to login with edit permissions (reason: $2). Do you want to switch to read-only mode instead?</string>
300300
<string name="login-ro-info">Project $1 switched to read-only mode</string>
301+
<string name="not-implemented">This functionality is not yet implemented. Please contact developers at [email protected].</string>
301302
<string name="main-stat">$1 edits per minute, $2 reverts per minute, level $3</string>
302303
<string name="main-menu-provider-stop">Stop provider</string>
303304
<string name="main-menu-provider-resume">Resume provider</string>

huggle/apiquery.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ void ApiQuery::SetAction(const Action action)
407407
this->ActionPart = "clearhasmsg";
408408
this->UsingPOST = true;
409409
return;
410+
///! \todo ActionQuery still used ?
410411
case ActionQuery:
411412
this->ActionPart = "query";
412413
this->IsContinuous = true;
@@ -416,6 +417,10 @@ void ApiQuery::SetAction(const Action action)
416417
this->ActionPart = "login";
417418
this->EnforceLogin = false;
418419
return;
420+
case ClientLogin:
421+
this->ActionPart = "clientlogin";
422+
this->EnforceLogin = false;
423+
return;
419424
case ActionLogout:
420425
this->ActionPart = "logout";
421426
return;

huggle/apiquery.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace Huggle
3131
ActionClearHasMsg,
3232
ActionQuery,
3333
ActionLogin,
34+
ClientLogin,
3435
ActionLogout,
3536
//ActionTokens,
3637
ActionPurge,

huggle/login.cpp

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <QSslSocket>
3434
#include <QDesktopServices>
3535
#include <QMessageBox>
36+
#include <QInputDialog>
3637

3738
#define LOGINFORM_LOGIN 0
3839
#define LOGINFORM_SITEINFO 1
@@ -554,21 +555,20 @@ void Login::PerformLoginPart2(WikiSite *site)
554555
this->Statuses[site] = WaitingForToken;
555556
this->LoginQueries.remove(site);
556557
query->DecRef();
557-
query = new ApiQuery(ActionLogin, site);
558+
query = new ApiQuery(ClientLogin, site);
558559
this->LoginQueries.insert(site, query);
559-
query->HiddenQuery = true;
560+
//query->HiddenQuery = true;
560561
query->IncRef();
561562
if (hcfg->SystemConfig_BotPassword)
562563
{
563-
query->Parameters = "lgname=" + QUrl::toPercentEncoding(hcfg->SystemConfig_BotLogin)
564-
+ "&lgpassword=" + QUrl::toPercentEncoding(hcfg->TemporaryConfig_Password)
565-
+ "&lgtoken=" + QUrl::toPercentEncoding(token);
564+
query->Parameters = "username=" + QUrl::toPercentEncoding(hcfg->SystemConfig_BotLogin)
565+
+ "&password=" + QUrl::toPercentEncoding(hcfg->TemporaryConfig_Password);
566566
} else
567567
{
568-
query->Parameters = "lgname=" + QUrl::toPercentEncoding(hcfg->SystemConfig_Username)
569-
+ "&lgpassword=" + QUrl::toPercentEncoding(hcfg->TemporaryConfig_Password)
570-
+ "&lgtoken=" + QUrl::toPercentEncoding(token);
568+
query->Parameters = "username=" + QUrl::toPercentEncoding(hcfg->SystemConfig_Username)
569+
+ "&password=" + QUrl::toPercentEncoding(hcfg->TemporaryConfig_Password);
571570
}
571+
query->Parameters = query->Parameters + "&loginreturnurl=http://example.com/&rememberMe=1&logintoken=" + QUrl::toPercentEncoding(token);
572572
query->UsingPOST = true;
573573
query->Process();
574574
}
@@ -1269,42 +1269,71 @@ bool Login::ProcessOutput(WikiSite *site)
12691269
ApiQuery *query = this->LoginQueries[site];
12701270
// Check what the result was
12711271
ApiQueryResult *result = query->GetApiQueryResult();
1272-
ApiQueryResultNode *ln = result->GetNode("login");
1273-
QString result_code = ln->GetAttribute("result");
1274-
QString reason = ln->GetAttribute("reason");
1275-
if (result_code.isEmpty())
1272+
ApiQueryResultNode *ln = result->GetNode("clientlogin");
1273+
QString status = ln->GetAttribute("status");
1274+
if (status.isEmpty())
12761275
{
12771276
this->DisplayError(_l("api.php-invalid-response"));
12781277
return false;
12791278
}
1280-
if (result_code == "Success")
1279+
1280+
if (status == "PASS")
12811281
return true;
1282-
if (result_code == "EmptyPass")
1283-
{
1284-
this->DisplayError(_l("login-password-empty"));
1282+
if (status == "UI") {
1283+
// Need a user interaction like captacha or 2FA
1284+
//QString v_id = ln->ChildNodes.at(0)->GetAttribute("id", "unknown");
1285+
//if (v_id == "TOTPAuthenticationRequest"){
1286+
if (true){
1287+
// 2FA is requierd (TOTP code needed)
1288+
QString totp = QInputDialog::getText(this, "Two factor authentification", "Please enter the 2FA code from your device:");
1289+
query = new ApiQuery(ClientLogin, site);
1290+
//query->HiddenQuery = true;
1291+
query->IncRef();
1292+
query->Parameters = "username=" + QUrl::toPercentEncoding(hcfg->SystemConfig_BotLogin)
1293+
+ "&password=" + QUrl::toPercentEncoding(hcfg->TemporaryConfig_Password)
1294+
+ "&OATHToken=" + totp + "&loginreturnurl=http://example.com/&rememberMe=1&logintoken=" + QUrl::toPercentEncoding(this->Tokens[site]);
1295+
query->UsingPOST = true;
1296+
query->Process();
1297+
ApiQueryResult *result = query->GetApiQueryResult();
1298+
ApiQueryResultNode *ln = result->GetNode("clientlogin");
1299+
}
12851300
return false;
12861301
}
1287-
if (result_code == "WrongPass")
1288-
{
1289-
/// \bug This sometimes doesn't work properly
1290-
this->ui->lineEdit_password->setFocus();
1291-
this->DisplayError(_l("login-error-password"));
1302+
if (status == "REDIRECT")
1303+
// Need to login using another web service
1304+
this->DisplayError(_l("not-implemented"));
12921305
return false;
1293-
}
1294-
if (result_code == "NoName")
1306+
if (status == "FAIL")
12951307
{
1296-
this->DisplayError(_l("login-fail-wrong-name"));
1297-
return false;
1298-
}
1299-
if (result_code == "NotExists")
1300-
{
1301-
this->DisplayError(_l("login-username-doesnt-exist"));
1308+
QString message = ln->GetAttribute("message");
1309+
QString message_code = ln->GetAttribute("messagecode");
1310+
if (message_code == "wrongpassword") {
1311+
/// \bug This sometimes doesn't work properly
1312+
this->ui->lineEdit_password->setFocus();
1313+
this->DisplayError(_l("login-error-password"));
1314+
return false;
1315+
}
1316+
/// \todo Verify these error codes
1317+
if (message_code == "EmptyPass")
1318+
{
1319+
this->DisplayError(_l("login-password-empty"));
1320+
return false;
1321+
}
1322+
if (message_code == "NoName")
1323+
{
1324+
this->DisplayError(_l("login-fail-wrong-name"));
1325+
return false;
1326+
}
1327+
if (message_code == "NotExists")
1328+
{
1329+
this->DisplayError(_l("login-username-doesnt-exist"));
1330+
return false;
1331+
}
1332+
if (message.isEmpty())
1333+
message = message_code;
1334+
this->DisplayError(_l("login-api", message));
13021335
return false;
13031336
}
1304-
if (reason.isEmpty())
1305-
reason = result_code;
1306-
this->DisplayError(_l("login-api", reason));
1307-
return false;
13081337
}
13091338

13101339
void Login::on_ButtonOK_clicked()

0 commit comments

Comments
 (0)