jenkins-bot submitted this change.

View Change

Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
[bugfix] don't try to retrieve data until logged in

mw_version Site property does an API call but this may fail
if a user is not logged in already. Therefore api.LoginManager
should not make an api call except for login purposes.

- move parameters preparation to api.LoginManager.parameters method.
- call get_login_token() to determine the mw version dispatching
- generate a fresh token if status in ('NeedToken', 'WrongToken', 'badtoken')

Bug: T284577
Change-Id: Ib7c24513fb08c475dcebe28ebd6b0411b2822372
---
M pywikibot/data/api.py
1 file changed, 55 insertions(+), 58 deletions(-)

diff --git a/pywikibot/data/api.py b/pywikibot/data/api.py
index 2b8ebee..5bbaf38 100644
--- a/pywikibot/data/api.py
+++ b/pywikibot/data/api.py
@@ -28,7 +28,6 @@
from pywikibot.backports import Tuple, removeprefix
from pywikibot.comms import http
from pywikibot.exceptions import (
- CaptchaError,
Error,
FatalServerError,
InvalidTitleError,
@@ -1240,8 +1239,9 @@
self['prop'] = sorted(prop)
# When neither 'continue' nor 'rawcontinue' is present and the
# version number is at least 1.25wmf5 we add a dummy rawcontinue
- # parameter. Querying siteinfo is save as it adds 'continue'.
- if ('continue' not in self._params
+ # parameter. Querying siteinfo is save as it adds 'continue'
+ # except for 'tokens' (T284577)
+ if ('tokens' not in meta and 'continue' not in self._params
and self.site.mw_version >= '1.25wmf5'):
self._params.setdefault('rawcontinue', [''])
elif self.action == 'help' and self.site.mw_version > '1.24':
@@ -2848,32 +2848,16 @@
"""Get API keyword from mapping."""
return self.mapping[key][self.action != 'login']

- def login_to_site(self) -> None:
- """Login to the site.
-
- Note, this doesn't do anything with cookies. The http module
- takes care of all the cookie stuff. Throws exception on failure.
- """
- if hasattr(self, '_waituntil'):
- if datetime.datetime.now() < self._waituntil:
- diff = self._waituntil - datetime.datetime.now()
- pywikibot.warning(
- 'Too many tries, waiting {} seconds before retrying.'
- .format(diff.seconds))
- pywikibot.sleep(diff.seconds)
-
- below_mw_1_27 = self.site.mw_version < '1.27'
-
- if '@' in self.login_name or '@' in self.password or below_mw_1_27:
- # Since MW 1.27 only for bot passwords.
- # Bot passwords username contains @,
- # otherwise @ is not allowed in usernames.
- # @ in bot password is deprecated,
- # but we don't want to break bots using it.
- self.action = 'login'
- else:
- # Standard login request since MW 1.27
- self.action = 'clientlogin'
+ def parameters(self, botpassword: bool) -> dict:
+ """Return login parameters."""
+ # Since MW 1.27 only for bot passwords.
+ self.action = 'login'
+ if not botpassword:
+ # get token using meta=tokens if supported
+ token = self.get_login_token()
+ if token:
+ # Standard login request since MW 1.27
+ self.action = 'clientlogin'

# prepare default login parameters
parameters = {'action': self.action,
@@ -2884,20 +2868,41 @@
# clientlogin requires non-empty loginreturnurl
parameters['loginreturnurl'] = 'https://example.com'
parameters['rememberMe'] = '1'
+ parameters['logintoken'] = token
+
+ if self.site.family.ldapDomain:
+ parameters[self.keyword('ldap')] = self.site.family.ldapDomain
+
+ return parameters
+
+ def login_to_site(self) -> None:
+ """Login to the site.
+
+ Note, this doesn't do anything with cookies. The http module
+ takes care of all the cookie stuff. Throws exception on failure.
+ """
+ self.below_mw_1_27 = False
+ if hasattr(self, '_waituntil'):
+ if datetime.datetime.now() < self._waituntil:
+ diff = self._waituntil - datetime.datetime.now()
+ pywikibot.warning(
+ 'Too many tries, waiting {} seconds before retrying.'
+ .format(diff.seconds))
+ pywikibot.sleep(diff.seconds)
+
+ self.site._loginstatus = LoginStatus.IN_PROGRESS
+
+ # Bot passwords username contains @,
+ # otherwise @ is not allowed in usernames.
+ # @ in bot password is deprecated,
+ # but we don't want to break bots using it.
+ parameters = self.parameters(
+ botpassword='@' in self.login_name or '@' in self.password)

# base login request
login_request = self.site._request(use_get=False,
parameters=parameters)
-
- if self.site.family.ldapDomain:
- login_request[self.keyword('ldap')] = self.site.family.ldapDomain
-
- self.site._loginstatus = LoginStatus.IN_PROGRESS
while True:
- # get token using meta=tokens if supported
- if not below_mw_1_27:
- login_request[self.keyword('token')] = self.get_login_token()
-
# try to login
try:
login_result = login_request.submit()
@@ -2921,11 +2926,10 @@

if status in ('NeedToken', 'WrongToken', 'badtoken'):
token = response.get('token')
- if token and below_mw_1_27:
+ if token and self.below_mw_1_27:
# fetched token using action=login
login_request['lgtoken'] = token
- pywikibot.log('Received login token, '
- 'proceed with login.')
+ pywikibot.log('Received login token, proceed with login.')
else:
# if incorrect login token was used,
# force relogin and generate fresh one
@@ -2933,22 +2937,13 @@
'Forcing re-login.')
# invalidate superior wiki cookies (T224712)
_invalidate_superior_cookies(self.site.family)
+ login_request[
+ self.keyword('token')] = self.get_login_token()
continue

# messagecode was introduced with 1.29.0-wmf.14
- login_throttled = False
- if self.site.mw_version >= '1.29.0-wmf.14':
- try:
- login_throttled = \
- response['messagecode'] == 'login-throttled'
- except KeyError:
- pywikibot.log(
- "Missing 'messagecode' key encountered\n"
- 'Please file the following debug message to '
- 'Phabricator task T261061:\n{}'
- .format(login_result))
- raise CaptchaError('Captcha encountered which cannot be '
- 'handled:\n{}'.format(response))
+ # but older wikis are still supported
+ login_throttled = response.get('messagecode') == 'login-throttled'

if (status == 'Throttled' or status == self.keyword('fail')
and (login_throttled or 'wait' in fail_reason)):
@@ -2978,15 +2973,17 @@

:return: login token
"""
- if self.site.mw_version < '1.27':
- raise NotImplementedError('The method get_login_token() requires '
- 'at least MediaWiki version 1.27.')
login_token_request = self.site._request(
use_get=False,
parameters={'action': 'query', 'meta': 'tokens', 'type': 'login'},
)
login_token_result = login_token_request.submit()
- return login_token_result['query']['tokens'].get('logintoken')
+ # check if we have to use old implementation of mw < 1.27
+ if 'query' in login_token_result:
+ return login_token_result['query']['tokens'].get('logintoken')
+
+ self.below_mw_1_27 = True
+ return None


def encode_url(query) -> str:

To view, visit change 699152. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ib7c24513fb08c475dcebe28ebd6b0411b2822372
Gerrit-Change-Number: 699152
Gerrit-PatchSet: 3
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-CC: Chris Blom <chrisblom@chrisblom.net>
Gerrit-CC: Dvorapa <dvorapa@seznam.cz>
Gerrit-CC: JJMC89 <JJMC89.Wikimedia@gmail.com>
Gerrit-CC: Mpaa <mpaa.wiki@gmail.com>
Gerrit-MessageType: merged