Page MenuHomePhabricator

Wrong CSRF token during watch action
Open, Needs TriagePublic

Description

WARNING: Using OAuth suppresses logout function
WARNING: API error badtoken: Invalid CSRF token.
WARNING: API error badtoken: Invalid CSRF token.
WARNING: API error badtoken: Invalid CSRF token.
…
 299.703s FAILED

https://api.travis-ci.org/v3/job/749969981/log.txt

=================================== FAILURES ===================================
________________________ TestPageUserAction.test_watch _________________________

self = <tests.page_tests.TestPageUserAction testMethod=test_watch>

    def test_watch(self):
        """Test Page.watch, with and without unwatch enabled."""
        # Note: this test uses the userpage, so that it is unwatched and
        # therefore is not listed by script_tests test_watchlist_simulate.
        userpage = self.get_userpage()
>       rv = userpage.watch()

tests/page_tests.py:1010: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
pywikibot/page/__init__.py:1372: in watch
    return self.site.watch(self, unwatch)
pywikibot/site/_decorators.py:94: in callee
    return fn(self, *args, **kwargs)
pywikibot/site/__init__.py:4193: in watch
    results = req.submit()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = pywikibot.data.api.Request<wpbeta:en->'/w/api.php?action=watch&titles=User:Pywikibot-oauth&assert=user&maxlag=5&format=json&token=0477a4b0e20fe8b26065084af718455b5fdb43f5+\\'>

    def submit(self) -> dict:
        """
        Submit a query and parse the response.
    
        @return: a dict containing data retrieved from api.php
        """
        self._add_defaults()
        use_get = self._use_get()
        retries = 0
        while True:
            paramstring = self._http_param_string()
    
            simulate = self._simulate(self.action)
            if simulate:
                return simulate
    
            if self.throttle:
                self.site.throttle(write=self.write)
            else:
                pywikibot.log(
                    "Submitting unthrottled action '{0}'.".format(self.action))
    
            use_get, uri, body, headers = self._get_request_params(use_get,
                                                                   paramstring)
            rawdata, use_get = self._http_request(use_get, uri, body, headers,
                                                  paramstring)
            if rawdata is None:
                continue
    
            result = self._json_loads(rawdata)
            if result is None:
                continue
    
            if self._userinfo_query(result):
                continue
    
            self._handle_warnings(result)
    
            if 'error' not in result:
                return result
    
            error = result['error'].copy()
            for key in result:
                if key in ('error', 'warnings'):
                    continue
                assert key not in error
                assert isinstance(result[key], str), \
                    'Unexpected %s: %r' % (key, result[key])
                error[key] = result[key]
    
            if '*' in result['error']:
                # help text returned
                result['error']['help'] = result['error'].pop('*')
            code = result['error'].setdefault('code', 'Unknown')
            info = result['error'].setdefault('info', None)
    
            if not self._logged_in(code):
                continue
    
            if code == 'maxlag':
                retries += 1
                if retries > max(5, pywikibot.config.max_retries):
                    break
                pywikibot.log('Pausing due to database lag: ' + info)
    
                try:
                    lag = result['error']['lag']
                except KeyError:
                    lag = lagpattern.search(info)
                    lag = float(lag.group('lag')) if lag else 0.0
    
                self.site.throttle.lag(lag * retries)
                continue
    
            elif code == 'help' and self.action == 'help':
                # The help module returns an error result with the complete
                # API information. As this data was requested, return the
                # data instead of raising an exception.
                return {'help': {'mime': 'text/plain',
                                 'help': result['error']['help']}}
    
            pywikibot.warning('API error %s: %s' % (code, info))
    
            if self._internal_api_error(code, error, result):
                continue
    
            # Phab. tickets T48535, T64126, T68494, T68619
            if code == 'failed-save' and \
               self._is_wikibase_error_retryable(result['error']):
                self.wait()
                continue
    
            if code == 'ratelimited':
                self._ratelimited()
                continue
    
            # If readapidenied is returned try to login
            if code == 'readapidenied' \
               and self.site._loginstatus in (LoginStatus.NOT_ATTEMPTED,
                                              LoginStatus.NOT_LOGGED_IN):
                self.site.login()
                continue
    
            if self._bad_token(code):
                continue
    
            if 'mwoauth-invalid-authorization' in code:
                if 'Nonce already used' in info:
                    pywikibot.error(
                        'Retrying failed OAuth authentication for {0}: {1}'
                        .format(self.site, info))
                    continue
                raise NoUsername('Failed OAuth authentication for %s: %s'
                                 % (self.site, info))
            if code == 'cirrussearch-too-busy-error':  # T170647
                self.wait()
                continue
    
            if code == 'urlshortener-blocked':  # T244062
                # add additional informations to result['error']
                result['error']['current site'] = self.site
                if self.site.user():
                    result['error']['current user'] = self.site.user()
                else:  # not logged in; show the IP
                    uinfo = self.site.userinfo
                    result['error']['current user'] = uinfo['name']
    
            # raise error
            try:
                param_repr = str(self._params)
                pywikibot.log('API Error: query=\n%s'
                              % pprint.pformat(param_repr))
                pywikibot.log('           response=\n{}'.format(result))
    
>               raise APIError(**result['error'])
E               pywikibot.data.api.APIError: badtoken: Invalid CSRF token.
E               [help: See https://en.wikipedia.beta.wmflabs.org/w/api.php for API usage. Subscribe to the mediawiki-api-announce mailing list at &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt; for notice of API deprecations and breaking changes.]

pywikibot/data/api.py:1981: APIError
------------------------------ Captured log call -------------------------------
INFO     pywiki:logging.py:102 Sleeping for 9.4 seconds, 2020-12-17 11:41:41
WARNING  pywiki:logging.py:102 API error badtoken: Invalid CSRF token.
VERBOSE  pywiki:logging.py:102 Login status: IN_PROGRESS
VERBOSE  pywiki:logging.py:102 API Error: query=
("{'action': ['watch'], 'token': "
 "['0477a4b0e20fe8b26065084af718455b5fdb43f5+\\\\'], 'unwatch': [False], "
 "'titles': [User('User:Pywikibot-oauth')], 'assert': ['user'], 'maxlag': "
 "['5'], 'format': ['json']}")
VERBOSE  pywiki:logging.py:102            response=
{'error': {'code': 'badtoken', 'info': 'Invalid CSRF token.', 'help': 'See https://en.wikipedia.beta.wmflabs.org/w/api.php for API usage. Subscribe to the mediawiki-api-announce mailing list at &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt; for notice of API deprecations and breaking changes.'}, 'servedby': 'deployment-mediawiki-07'}
______________________ TestLoginLogout.test_login_logout _______________________

self = <tests.site_tests.TestLoginLogout testMethod=test_login_logout>

    def test_login_logout(self):
        """Validate login and logout methods by toggling the state."""
        site = self.get_site()
        loginstatus = pywikibot.login.LoginStatus
    
        self.assertTrue(site.logged_in())
        self.assertIn(site._loginstatus, (loginstatus.IN_PROGRESS,
                                          loginstatus.AS_USER))
        self.assertIn('_userinfo', site.__dict__.keys())
    
        self.assertIsNone(site.login())
    
        if site.is_oauth_token_available():
            with self.assertRaisesRegex(api.APIError, 'cannotlogout.*OAuth'):
>               site.logout()

tests/site_tests.py:3300: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
pywikibot/site/__init__.py:368: in logout
    uirequest.submit()
pywikibot/data/api.py:1872: in submit
    paramstring)
pywikibot/data/api.py:1610: in _http_request
    body=body, headers=headers)
pywikibot/comms/http.py:257: in request
    r = fetch(baseuri, method, params, body, headers, **kwargs)
pywikibot/tools/__init__.py:1481: in wrapper
    return obj(*__args, **__kw)
pywikibot/comms/http.py:412: in fetch
    **kwargs)
../../../virtualenv/python3.6.7/lib/python3.6/site-packages/requests/sessions.py:542: in request
    resp = self.send(prep, **send_kwargs)
../../../virtualenv/python3.6.7/lib/python3.6/site-packages/requests/sessions.py:655: in send
    r = adapter.send(request, **kwargs)
../../../virtualenv/python3.6.7/lib/python3.6/site-packages/requests/adapters.py:449: in send
    timeout=timeout
../../../virtualenv/python3.6.7/lib/python3.6/site-packages/urllib3/connectionpool.py:706: in urlopen
    chunked=chunked,
../../../virtualenv/python3.6.7/lib/python3.6/site-packages/urllib3/connectionpool.py:445: in _make_request
    six.raise_from(e, None)
<string>:3: in raise_from
    ???
../../../virtualenv/python3.6.7/lib/python3.6/site-packages/urllib3/connectionpool.py:440: in _make_request
    httplib_response = conn.getresponse()
/opt/python/3.6.7/lib/python3.6/http/client.py:1331: in getresponse
    response.begin()
/opt/python/3.6.7/lib/python3.6/http/client.py:297: in begin
    version, status, reason = self._read_status()
/opt/python/3.6.7/lib/python3.6/http/client.py:258: in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
/opt/python/3.6.7/lib/python3.6/socket.py:586: in readinto
    return self._sock.recv_into(b)
/opt/python/3.6.7/lib/python3.6/ssl.py:1012: in recv_into
    return self.read(nbytes, buffer)
/opt/python/3.6.7/lib/python3.6/ssl.py:874: in read
    return self._sslobj.read(len, buffer)
/opt/python/3.6.7/lib/python3.6/ssl.py:631: in read
    v = self._sslobj.read(len, buffer)
../../../virtualenv/python3.6.7/lib/python3.6/site-packages/pytest_timeout.py:200: in handler
    timeout_sigalrm(item, params.timeout)
../../../virtualenv/python3.6.7/lib/python3.6/site-packages/pytest_timeout.py:375: in timeout_sigalrm
    pytest.fail("Timeout >%ss" % timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @_with_exception(Failed)
    def fail(msg: str = "", pytrace: bool = True) -> "NoReturn":
        """Explicitly fail an executing test with the given message.
    
        :param str msg:
            The message to show the user as reason for the failure.
        :param bool pytrace:
            If False, msg represents the full failure information and no
            python traceback will be reported.
        """
        __tracebackhide__ = True
>       raise Failed(msg=msg, pytrace=pytrace)
E       Failed: Timeout >300.0s
../../../virtualenv/python3.6.7/lib/python3.6/site-packages/_pytest/outcomes.py:153: Failed
------------------------------ Captured log setup ------------------------------
VERBOSE  pywiki:logging.py:102 Found 1 wpbeta:en processes running, including this one.
------------------------------ Captured log call -------------------------------
VERBOSE  pywiki:logging.py:102 APISite("en", "wpbeta").login() called when a previous login was in progress.
WARNING  pywiki:logging.py:102 Using OAuth suppresses logout function
WARNING  pywiki:logging.py:102 API error badtoken: Invalid CSRF token.
VERBOSE  pywiki:logging.py:102 Bad token error for Pywikibot-oauth. Tokens for "csrf" used in request; invalidated them.
WARNING  pywiki:logging.py:102 API error badtoken: Invalid CSRF token.
VERBOSE  pywiki:logging.py:102 Bad token error for Pywikibot-oauth. Tokens for "csrf" used in request; invalidated them.
WARNING  pywiki:logging.py:102 API error badtoken: Invalid CSRF token.
...

Related Objects

StatusSubtypeAssignedTask
OpenNone
OpenNone