feat: Support various login methods.

TODO: Re-login after session regeneration.
pull/475/head
yzqzss 1 year ago committed by yzqzss
parent 638c4df06f
commit 74ead81539

@ -12,6 +12,7 @@ import requests
import urllib3
from wikiteam3.dumpgenerator.api import checkRetryAPI, mwGetAPIAndIndex
from wikiteam3.utils.login import uniLogin
from .delay import Delay
from wikiteam3.utils import domain2prefix
from wikiteam3.dumpgenerator.api.index_check import checkIndex
@ -215,6 +216,8 @@ def getParameters(params=None) -> Tuple[Config, Dict]:
session.cookies = cj
session.headers.update({"User-Agent": getUserAgent()})
setupUserAgent(session)
# set HTTPBasicAuth
if args.user and args.password:
session.auth = (args.user, args.password)
@ -268,7 +271,7 @@ def getParameters(params=None) -> Tuple[Config, Dict]:
# Replace the index URL we got from the API check
index2 = check[1]
api = checkedapi
print("API is OK: " + checkedapi)
print("API is OK: ", checkedapi)
else:
if index and not args.wiki:
print("API not available. Trying with index.php only.")
@ -277,6 +280,17 @@ def getParameters(params=None) -> Tuple[Config, Dict]:
print("Error in API. Please, provide a correct path to API")
sys.exit(1)
# login if needed
# TODO: Re-login after session regeneration.
if api and args.user and args.password:
_session = uniLogin(api=api, session=session, username=args.user, password=args.password)
if _session:
session = _session
print("-- Login OK --")
else:
print("-- Login failed --")
# check index
if index and checkIndex(index=index, cookies=args.cookies, session=session):
print("index.php is OK")
else:

@ -4,4 +4,5 @@ from .util import removeIP, cleanXML, cleanHTML, undoHTMLEntities, sha1File
from .user_agent import getUserAgent
from .domain import domain2prefix
from .wiki_avoid import avoidWikimediaProjects
from .monkey_patch import mod_requests_text
from .monkey_patch import mod_requests_text
from .login import uniLogin, fetchLoginToken, botLogin, clientLogin, indexLogin

@ -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…
Cancel
Save