Skip to content
This repository was archived by the owner on Feb 15, 2024. It is now read-only.

Commit dc52f92

Browse files
committed
Bugfixes: Cloudflare bypassing, JS parser; tests, pylint, makefile
1 parent 1055628 commit dc52f92

File tree

19 files changed

+141
-71
lines changed

19 files changed

+141
-71
lines changed

Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
build:
2-
sudo python -m build
2+
python -m build
33

44
upload:
55
python -m twine upload dist/*
66

77
clean:
8-
sudo rm -rf dist/ python_aternos.egg-info/
8+
rm -rf dist/ python_aternos.egg-info/
9+
rm -rf .mypy_cache/ python_aternos/__pycache__/
10+
11+
check:
12+
chmod +x test.sh
13+
bash test.sh

pylintrc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,9 @@ disable=raw-checker-failed,
3939
useless-suppression,
4040
deprecated-pragma,
4141
use-symbolic-message-instead,
42-
wrong-import-order,
43-
unspecified-encoding,
4442
logging-not-lazy,
4543
logging-fstring-interpolation,
4644
no-member,
47-
too-many-branches,
4845
too-many-arguments,
4946
too-many-public-methods,
5047
too-many-instance-attributes

python_aternos/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@
2828
from .aterrors import ServerStartError
2929
from .aterrors import FileError
3030
from .aterrors import AternosPermissionError
31-
from .atjsparse import exec_js, atob
32-
from .atjsparse import to_ecma5_function
31+
from .atjsparse import exec_js
3332

3433
__all__ = [
3534

@@ -43,8 +42,7 @@
4342
'FileManager', 'AternosFile', 'AternosError',
4443
'CloudflareError', 'CredentialsError', 'TokenError',
4544
'ServerError', 'ServerStartError', 'FileError',
46-
'AternosPermissionError',
47-
'exec_js', 'atob', 'to_ecma5_function',
45+
'AternosPermissionError', 'exec_js',
4846

4947
'Edition', 'Status', 'Lists',
5048
'ServerOpts', 'WorldOpts', 'WorldRules',

python_aternos/atclient.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
import os
55
import re
66
import hashlib
7-
import lxml.html
7+
88
from typing import List, Optional
99

10+
import lxml.html
11+
1012
from .atserver import AternosServer
1113
from .atconnect import AternosConnect
1214
from .aterrors import CredentialsError
@@ -119,7 +121,7 @@ def restore_session(cls, file: str = '~/.aternos'):
119121
"""
120122

121123
file = os.path.expanduser(file)
122-
with open(file, 'rt') as f:
124+
with open(file, 'rt', encoding='utf-8') as f:
123125
saved = f.read().replace('\r\n', '\n').split('\n')
124126

125127
session = saved[0].strip()
@@ -164,7 +166,7 @@ def save_session(
164166
"""
165167

166168
file = os.path.expanduser(file)
167-
with open(file, 'wt') as f:
169+
with open(file, 'wt', encoding='utf-8') as f:
168170

169171
f.write(self.atconn.atsession + '\n')
170172
if not incl_servers:

python_aternos/atconf.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import enum
44
import re
5-
import lxml.html
5+
66
from typing import Any, Dict, List, Union, Optional
77
from typing import TYPE_CHECKING
88

9+
import lxml.html
10+
911
if TYPE_CHECKING:
1012
from .atserver import AternosServer
1113

python_aternos/atconnect.py

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
"""Stores API connection session and sends requests"""
22

33
import re
4+
import time
45
import random
56
import logging
7+
from functools import partial
8+
9+
from typing import Optional, Union
610
from requests import Response
11+
712
from cloudscraper import CloudScraper
8-
from typing import Optional, Union
913

1014
from . import atjsparse
1115
from .aterrors import TokenError
@@ -160,8 +164,7 @@ def request_cloudflare(
160164
headers: Optional[dict] = None,
161165
reqcookies: Optional[dict] = None,
162166
sendtoken: bool = False,
163-
redirect: bool = True,
164-
retry: int = 3) -> Response:
167+
retry: int = 5) -> Response:
165168

166169
"""Sends a request to Aternos API bypass Cloudflare
167170
@@ -181,11 +184,8 @@ def request_cloudflare(
181184
:param sendtoken: If the ajax and SEC token
182185
should be sent, defaults to False
183186
:type sendtoken: bool, optional
184-
:param redirect: If requests lib should follow
185-
Location header in 3xx responses, defaults to True
186-
:type redirect: bool, optional
187187
:param retry: How many times parser must retry
188-
connection to API bypass Cloudflare, defaults to 3
188+
connection to API bypass Cloudflare, defaults to 5
189189
:type retry: int, optional
190190
:raises CloudflareError:
191191
When the parser has exceeded retries count
@@ -198,21 +198,26 @@ def request_cloudflare(
198198
if retry <= 0:
199199
raise CloudflareError('Unable to bypass Cloudflare protection')
200200

201+
old_cookies = self.session.cookies
202+
self.session = CloudScraper()
203+
self.session.cookies.update(old_cookies)
204+
201205
try:
202206
self.atsession = self.session.cookies['ATERNOS_SESSION']
203207
except KeyError:
208+
# don't rewrite atsession value
204209
pass
205210

211+
params = params or {}
212+
data = data or {}
213+
headers = headers or {}
214+
reqcookies = reqcookies or {}
215+
206216
method = method or 'GET'
207217
method = method.upper().strip()
208218
if method not in ('GET', 'POST'):
209219
raise NotImplementedError('Only GET and POST are available')
210220

211-
headers = headers or {}
212-
params = params or {}
213-
data = data or {}
214-
reqcookies = reqcookies or {}
215-
216221
if sendtoken:
217222
params['TOKEN'] = self.token
218223
params['SEC'] = self.sec
@@ -230,26 +235,35 @@ def request_cloudflare(
230235
logging.debug(f'session-cookies={self.session.cookies}')
231236

232237
if method == 'POST':
233-
req = self.session.post(
234-
url, data=data, params=params,
235-
headers=headers, cookies=reqcookies,
236-
allow_redirects=redirect
238+
sendreq = partial(
239+
self.session.post,
240+
params=params,
241+
data=data
237242
)
238243
else:
239-
req = self.session.get(
240-
url, params={**params, **data},
241-
headers=headers, cookies=reqcookies,
242-
allow_redirects=redirect
244+
sendreq = partial(
245+
self.session.get,
246+
params={**params, **data}
243247
)
244248

245-
if '<title>Please Wait... | Cloudflare</title>' in req.text:
249+
req = sendreq(
250+
url,
251+
headers=headers,
252+
cookies=reqcookies
253+
)
254+
255+
resp_type = req.headers.get('content-type', '')
256+
html_type = resp_type.find('text/html') != -1
257+
cloudflare = req.status_code == 403
258+
259+
if html_type and cloudflare:
246260
logging.info('Retrying to bypass Cloudflare')
261+
time.sleep(0.2)
247262
return self.request_cloudflare(
248263
url, method,
249264
params, data,
250265
headers, reqcookies,
251-
sendtoken, redirect,
252-
retry - 1
266+
sendtoken, retry - 1
253267
)
254268

255269
logging.debug('AternosConnect received: ' + req.text[:65])

python_aternos/atfile.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"""File info object used by `python_aternos.atfm`"""
22

33
import enum
4-
import lxml.html
4+
55
from typing import Union
66
from typing import TYPE_CHECKING
77

8+
import lxml.html
9+
810
from .aterrors import FileError
911

1012
if TYPE_CHECKING:

python_aternos/atfm.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"""Exploring files in your server directory"""
22

3-
import lxml.html
43
from typing import Union, Optional, Any, List
54
from typing import TYPE_CHECKING
65

6+
import lxml.html
7+
78
from .atfile import AternosFile, FileType
89
if TYPE_CHECKING:
910
from .atserver import AternosServer

python_aternos/atjsparse.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"""Parsing and executing JavaScript code"""
22

3-
import regex
43
import base64
5-
import js2py
4+
65
from typing import Any
76

7+
import regex
8+
import js2py
9+
810
# Thanks to http://regex.inginf.units.it/
911
arrowexp = regex.compile(r'\w[^\}]*+')
1012

@@ -19,6 +21,7 @@ def to_ecma5_function(f: str) -> str:
1921
:rtype: str
2022
"""
2123

24+
f = regex.sub(r'/\*.+?\*/', '', f)
2225
match = arrowexp.search(f)
2326
conv = '(function(){' + match.group(0) + '})()'
2427
return regex.sub(

python_aternos/atplayers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"""Operators, whitelist and banned players lists"""
22

33
import enum
4-
import lxml.html
4+
55
from typing import List, Union
66
from typing import TYPE_CHECKING
77

8+
import lxml.html
9+
810
if TYPE_CHECKING:
911
from .atserver import AternosServer
1012

0 commit comments

Comments
 (0)