Bugfixes: Cloudflare bypassing, JS parser; tests, pylint, makefile
This commit is contained in:
parent
1055628241
commit
dc52f92985
19 changed files with 142 additions and 72 deletions
|
@ -28,8 +28,7 @@ from .aterrors import ServerError
|
|||
from .aterrors import ServerStartError
|
||||
from .aterrors import FileError
|
||||
from .aterrors import AternosPermissionError
|
||||
from .atjsparse import exec_js, atob
|
||||
from .atjsparse import to_ecma5_function
|
||||
from .atjsparse import exec_js
|
||||
|
||||
__all__ = [
|
||||
|
||||
|
@ -43,8 +42,7 @@ __all__ = [
|
|||
'FileManager', 'AternosFile', 'AternosError',
|
||||
'CloudflareError', 'CredentialsError', 'TokenError',
|
||||
'ServerError', 'ServerStartError', 'FileError',
|
||||
'AternosPermissionError',
|
||||
'exec_js', 'atob', 'to_ecma5_function',
|
||||
'AternosPermissionError', 'exec_js',
|
||||
|
||||
'Edition', 'Status', 'Lists',
|
||||
'ServerOpts', 'WorldOpts', 'WorldRules',
|
||||
|
|
|
@ -4,9 +4,11 @@ and allows to manage your account"""
|
|||
import os
|
||||
import re
|
||||
import hashlib
|
||||
import lxml.html
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
import lxml.html
|
||||
|
||||
from .atserver import AternosServer
|
||||
from .atconnect import AternosConnect
|
||||
from .aterrors import CredentialsError
|
||||
|
@ -119,7 +121,7 @@ class Client:
|
|||
"""
|
||||
|
||||
file = os.path.expanduser(file)
|
||||
with open(file, 'rt') as f:
|
||||
with open(file, 'rt', encoding='utf-8') as f:
|
||||
saved = f.read().replace('\r\n', '\n').split('\n')
|
||||
|
||||
session = saved[0].strip()
|
||||
|
@ -164,7 +166,7 @@ class Client:
|
|||
"""
|
||||
|
||||
file = os.path.expanduser(file)
|
||||
with open(file, 'wt') as f:
|
||||
with open(file, 'wt', encoding='utf-8') as f:
|
||||
|
||||
f.write(self.atconn.atsession + '\n')
|
||||
if not incl_servers:
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
import enum
|
||||
import re
|
||||
import lxml.html
|
||||
|
||||
from typing import Any, Dict, List, Union, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import lxml.html
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .atserver import AternosServer
|
||||
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
"""Stores API connection session and sends requests"""
|
||||
|
||||
import re
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
from requests import Response
|
||||
from cloudscraper import CloudScraper
|
||||
from functools import partial
|
||||
|
||||
from typing import Optional, Union
|
||||
from requests import Response
|
||||
|
||||
from cloudscraper import CloudScraper
|
||||
|
||||
from . import atjsparse
|
||||
from .aterrors import TokenError
|
||||
|
@ -160,8 +164,7 @@ class AternosConnect:
|
|||
headers: Optional[dict] = None,
|
||||
reqcookies: Optional[dict] = None,
|
||||
sendtoken: bool = False,
|
||||
redirect: bool = True,
|
||||
retry: int = 3) -> Response:
|
||||
retry: int = 5) -> Response:
|
||||
|
||||
"""Sends a request to Aternos API bypass Cloudflare
|
||||
|
||||
|
@ -181,11 +184,8 @@ class AternosConnect:
|
|||
:param sendtoken: If the ajax and SEC token
|
||||
should be sent, defaults to False
|
||||
:type sendtoken: bool, optional
|
||||
:param redirect: If requests lib should follow
|
||||
Location header in 3xx responses, defaults to True
|
||||
:type redirect: bool, optional
|
||||
:param retry: How many times parser must retry
|
||||
connection to API bypass Cloudflare, defaults to 3
|
||||
connection to API bypass Cloudflare, defaults to 5
|
||||
:type retry: int, optional
|
||||
:raises CloudflareError:
|
||||
When the parser has exceeded retries count
|
||||
|
@ -198,21 +198,26 @@ class AternosConnect:
|
|||
if retry <= 0:
|
||||
raise CloudflareError('Unable to bypass Cloudflare protection')
|
||||
|
||||
old_cookies = self.session.cookies
|
||||
self.session = CloudScraper()
|
||||
self.session.cookies.update(old_cookies)
|
||||
|
||||
try:
|
||||
self.atsession = self.session.cookies['ATERNOS_SESSION']
|
||||
except KeyError:
|
||||
# don't rewrite atsession value
|
||||
pass
|
||||
|
||||
params = params or {}
|
||||
data = data or {}
|
||||
headers = headers or {}
|
||||
reqcookies = reqcookies or {}
|
||||
|
||||
method = method or 'GET'
|
||||
method = method.upper().strip()
|
||||
if method not in ('GET', 'POST'):
|
||||
raise NotImplementedError('Only GET and POST are available')
|
||||
|
||||
headers = headers or {}
|
||||
params = params or {}
|
||||
data = data or {}
|
||||
reqcookies = reqcookies or {}
|
||||
|
||||
if sendtoken:
|
||||
params['TOKEN'] = self.token
|
||||
params['SEC'] = self.sec
|
||||
|
@ -230,26 +235,35 @@ class AternosConnect:
|
|||
logging.debug(f'session-cookies={self.session.cookies}')
|
||||
|
||||
if method == 'POST':
|
||||
req = self.session.post(
|
||||
url, data=data, params=params,
|
||||
headers=headers, cookies=reqcookies,
|
||||
allow_redirects=redirect
|
||||
sendreq = partial(
|
||||
self.session.post,
|
||||
params=params,
|
||||
data=data
|
||||
)
|
||||
else:
|
||||
req = self.session.get(
|
||||
url, params={**params, **data},
|
||||
headers=headers, cookies=reqcookies,
|
||||
allow_redirects=redirect
|
||||
sendreq = partial(
|
||||
self.session.get,
|
||||
params={**params, **data}
|
||||
)
|
||||
|
||||
if '<title>Please Wait... | Cloudflare</title>' in req.text:
|
||||
req = sendreq(
|
||||
url,
|
||||
headers=headers,
|
||||
cookies=reqcookies
|
||||
)
|
||||
|
||||
resp_type = req.headers.get('content-type', '')
|
||||
html_type = resp_type.find('text/html') != -1
|
||||
cloudflare = req.status_code == 403
|
||||
|
||||
if html_type and cloudflare:
|
||||
logging.info('Retrying to bypass Cloudflare')
|
||||
time.sleep(0.2)
|
||||
return self.request_cloudflare(
|
||||
url, method,
|
||||
params, data,
|
||||
headers, reqcookies,
|
||||
sendtoken, redirect,
|
||||
retry - 1
|
||||
sendtoken, retry - 1
|
||||
)
|
||||
|
||||
logging.debug('AternosConnect received: ' + req.text[:65])
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
"""File info object used by `python_aternos.atfm`"""
|
||||
|
||||
import enum
|
||||
import lxml.html
|
||||
|
||||
from typing import Union
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import lxml.html
|
||||
|
||||
from .aterrors import FileError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
"""Exploring files in your server directory"""
|
||||
|
||||
import lxml.html
|
||||
from typing import Union, Optional, Any, List
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import lxml.html
|
||||
|
||||
from .atfile import AternosFile, FileType
|
||||
if TYPE_CHECKING:
|
||||
from .atserver import AternosServer
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
"""Parsing and executing JavaScript code"""
|
||||
|
||||
import regex
|
||||
import base64
|
||||
import js2py
|
||||
|
||||
from typing import Any
|
||||
|
||||
import regex
|
||||
import js2py
|
||||
|
||||
# Thanks to http://regex.inginf.units.it/
|
||||
arrowexp = regex.compile(r'\w[^\}]*+')
|
||||
|
||||
|
@ -19,6 +21,7 @@ def to_ecma5_function(f: str) -> str:
|
|||
:rtype: str
|
||||
"""
|
||||
|
||||
f = regex.sub(r'/\*.+?\*/', '', f)
|
||||
match = arrowexp.search(f)
|
||||
conv = '(function(){' + match.group(0) + '})()'
|
||||
return regex.sub(
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
"""Operators, whitelist and banned players lists"""
|
||||
|
||||
import enum
|
||||
import lxml.html
|
||||
|
||||
from typing import List, Union
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import lxml.html
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .atserver import AternosServer
|
||||
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
import enum
|
||||
import json
|
||||
from requests import Response
|
||||
|
||||
from typing import Optional, List
|
||||
from requests import Response
|
||||
|
||||
from .atconnect import AternosConnect
|
||||
from .aterrors import ServerStartError
|
||||
|
|
|
@ -5,12 +5,14 @@ import enum
|
|||
import json
|
||||
import asyncio
|
||||
import logging
|
||||
import websockets
|
||||
|
||||
from typing import Union, Any
|
||||
from typing import Dict, Tuple
|
||||
from typing import Tuple, Dict
|
||||
from typing import Callable, Coroutine
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import websockets
|
||||
|
||||
from .atconnect import REQUA
|
||||
if TYPE_CHECKING:
|
||||
from .atserver import AternosServer
|
||||
|
@ -55,10 +57,11 @@ class AternosWss:
|
|||
autoconfirm: bool = False) -> None:
|
||||
|
||||
self.atserv = atserv
|
||||
self.cookies = atserv.atconn.session.cookies
|
||||
self.session = self.cookies['ATERNOS_SESSION']
|
||||
self.servid = atserv.servid
|
||||
|
||||
cookies = atserv.atconn.session.cookies
|
||||
self.session = cookies['ATERNOS_SESSION']
|
||||
|
||||
recvtype = Dict[Streams, ArgsTuple]
|
||||
self.recv: recvtype = {}
|
||||
self.autoconfirm = autoconfirm
|
||||
|
|
Reference in a new issue