mirror of https://github.com/WikiTeam/wikiteam
feat: Support various login methods.
TODO: Re-login after session regeneration.pull/475/head
parent
638c4df06f
commit
74ead81539
@ -0,0 +1,35 @@
|
||||
""" Provide login functions """
|
||||
|
||||
import requests
|
||||
import time
|
||||
|
||||
from wikiteam3.utils.login.api import botLogin, clientLogin, fetchLoginToken
|
||||
from wikiteam3.utils.login.index import indexLogin
|
||||
|
||||
|
||||
def uniLogin(api: str = '', index: str = '' ,session: requests.Session = requests.Session(), username: str = '', password: str = ''):
|
||||
""" Try to login to a wiki using various methods.\n
|
||||
Return `session` if success, else return `None`.\n
|
||||
Try: `cilent login (api) => bot login (api) => index login (index)` """
|
||||
|
||||
if (not api and not index) or (not username or not password):
|
||||
print('uniLogin: api or index or username or password is empty')
|
||||
return None
|
||||
|
||||
if api:
|
||||
_session = clientLogin(api=api, session=session, username=username, password=password)
|
||||
if _session:
|
||||
return _session
|
||||
time.sleep(5)
|
||||
|
||||
_session = botLogin(api=api, session=session, username=username, password=password)
|
||||
if _session:
|
||||
return _session
|
||||
time.sleep(5)
|
||||
|
||||
if index:
|
||||
_session = indexLogin(index=index, session=session, username=username, password=password)
|
||||
if _session:
|
||||
return _session
|
||||
|
||||
return None
|
@ -0,0 +1,79 @@
|
||||
""" Available since MediaWiki 1.27. login to a wiki using username and password (API) """
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
def fetchLoginToken(session: requests.Session, api: str) -> str|None:
|
||||
""" fetch login token by API .(MediaWiki 1.27+)"""
|
||||
|
||||
response = session.get(
|
||||
url=api,
|
||||
params={
|
||||
'action': "query",
|
||||
'meta': "tokens",
|
||||
'type': "login",
|
||||
'format': "json"})
|
||||
data = response.json()
|
||||
try:
|
||||
token = data['query']['tokens']['logintoken']
|
||||
if type(token) is str:
|
||||
return token
|
||||
except KeyError:
|
||||
print('fetch login token: Oops! Something went wrong -- ', data)
|
||||
return None
|
||||
|
||||
|
||||
def clientLogin(api: str ,session: requests.Session, username: str, password: str):
|
||||
""" login to a wiki using username and password. (MediaWiki 1.27+)"""
|
||||
|
||||
login_token = fetchLoginToken(session=session, api=api)
|
||||
if not login_token:
|
||||
return None
|
||||
|
||||
response = session.post(url=api, data={
|
||||
'action': "clientlogin",
|
||||
'username': username,
|
||||
'password': password,
|
||||
'loginreturnurl': 'http://127.0.0.1:5000/',
|
||||
'logintoken': login_token,
|
||||
'format': "json"
|
||||
})
|
||||
|
||||
data = response.json()
|
||||
|
||||
try:
|
||||
if data['clientlogin']['status'] == 'PASS':
|
||||
print('client login: Success! Welcome, ' + data['clientlogin']['username'] + '!')
|
||||
except KeyError:
|
||||
print('client login: Oops! Something went wrong -- ', data)
|
||||
return None
|
||||
|
||||
|
||||
return session
|
||||
|
||||
|
||||
def botLogin(api:str ,session: requests.Session, username: str, password: str):
|
||||
""" login to a wiki using BOT's name and password. (MediaWiki 1.27+) """
|
||||
|
||||
login_token = fetchLoginToken(session=session, api=api)
|
||||
if not login_token:
|
||||
return None
|
||||
|
||||
response = session.post(url=api, data={
|
||||
'action': "login",
|
||||
'lgname': username,
|
||||
'lgpassword': password,
|
||||
'lgtoken': login_token,
|
||||
'format': "json"
|
||||
})
|
||||
|
||||
data = response.json()
|
||||
|
||||
try:
|
||||
if data['login']['result'] == 'Success':
|
||||
print('bot login: Success! Welcome, ' + data['login']['lgusername'] + '!')
|
||||
except KeyError:
|
||||
print('bot login: Oops! Something went wrong -- ' + data)
|
||||
return None
|
||||
|
||||
return session
|
@ -0,0 +1,49 @@
|
||||
""" Always available login methods.(mw 1.16-1.39)
|
||||
Even oler versions of MW may work, but not tested. """
|
||||
|
||||
import requests
|
||||
import lxml.html
|
||||
|
||||
def indexLogin(index:str ,session: requests.Session, username: str, password: str):
|
||||
""" Try to login to a wiki using username and password through `Special:UserLogin`.
|
||||
(tested on MW 1.16...1.39) """
|
||||
wpEditToken = None
|
||||
wpLoginToken = None
|
||||
|
||||
params = {
|
||||
'title': 'Special:UserLogin',
|
||||
}
|
||||
r = session.get(index, allow_redirects=True, params=params)
|
||||
|
||||
# Sample r.text:
|
||||
# MW 1.16: <input type="hidden" name="wpLoginToken" value="adf5ed40243e9e5db368808b27dc289c" />
|
||||
# MW 1.39: <input name="wpLoginToken" type="hidden" value="ad43f6cc89ef50ac3dbd6d03b56aedca63ec4c90+\"/>
|
||||
html = lxml.html.fromstring(r.text)
|
||||
if 'wpLoginToken' in r.text:
|
||||
wpLoginToken = html.xpath('//input[@name="wpLoginToken"]/@value')[0]
|
||||
|
||||
# Sample r.text:
|
||||
# MW 1.16: None
|
||||
# MW 1.39: <input id="wpEditToken" type="hidden" value="+\" name="wpEditToken"/>
|
||||
if 'wpEditToken' in r.text:
|
||||
wpEditToken = html.xpath('//input[@name="wpEditToken"]/@value')[0]
|
||||
print('index login: wpEditToken found.')
|
||||
|
||||
data = {
|
||||
'wpName': username, # required
|
||||
'wpPassword': password, # required
|
||||
'wpLoginattempt': 'Log in', # required
|
||||
'wpLoginToken': wpLoginToken, # required
|
||||
'wpRemember': '1', # 0: not remember, 1: remember
|
||||
'wpEditToken': wpEditToken, # introduced before MW 1.27, not sure whether it's required.
|
||||
'authAction': 'login', # introduced before MW 1.39.
|
||||
'title': 'Special:UserLogin', # introduced before MW 1.39.
|
||||
'force': '', # introduced before MW 1.39, empty string is OK.
|
||||
}
|
||||
r = session.post(index, allow_redirects=False, params=params, data=data)
|
||||
if r.status_code == 302:
|
||||
print('index login: Success! Welcome, ', username, '!')
|
||||
return session
|
||||
else:
|
||||
print('index login: Oops! Something went wrong -- ', r.status_code, 'wpLoginToken: ', wpLoginToken, 'wpEditToken: ', wpEditToken)
|
||||
return None
|
Loading…
Reference in New Issue