diff --git a/connect_test.py b/connect_test.py new file mode 100644 index 0000000..38ac8ad --- /dev/null +++ b/connect_test.py @@ -0,0 +1,11 @@ +from python_aternos import Client as AternosClient + +aternos = AternosClient('', password='') + +srvs = aternos.servers + +print(srvs) + +s = srvs[0] + +s.start() diff --git a/python_aternos/atconnect.py b/python_aternos/atconnect.py index 38cf54b..d349244 100644 --- a/python_aternos/atconnect.py +++ b/python_aternos/atconnect.py @@ -8,141 +8,187 @@ from typing import Optional, Union from . import aterrors +#TEST +from py_mini_racer import MiniRacer +import base64 + +presettings = """ +let window = {1: null, 2: null, AJAX_TOKEN: null}; +let i = 1; +function __log() { return {win_var: window["AJAX_TOKEN"], 1: window[1], 2: window[2]} }; +function atob(arg) {window[i++] = arg;}; +""" +postsettings = """__log();""" + + REQGET = 0 REQPOST = 1 REQUA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Goanna/4.8 Firefox/68.0 PaleMoon/29.4.0.2' class AternosConnect: - def __init__(self) -> None: + def __init__(self) -> None: - pass + pass - def parse_token(self, response:Optional[Union[str,bytes]]=None) -> str: + def parse_token(self, response:Optional[Union[str,bytes]]=None) -> str: - if response == None: - loginpage = self.request_cloudflare( - f'https://aternos.org/go/', REQGET - ).content - pagetree = lxml.html.fromstring(loginpage) - else: - pagetree = lxml.html.fromstring(response) + if response == None: + loginpage = self.request_cloudflare( + f'https://aternos.org/go/', REQGET + ).content + pagetree = lxml.html.fromstring(loginpage) + else: + pagetree = lxml.html.fromstring(response) - try: - pagehead = pagetree.head - self.token = re.search( - r'const\s+AJAX_TOKEN\s*=\s*["\'](\w+)["\']', - pagehead.text_content() - )[1] - except (IndexError, TypeError): - raise aterrors.AternosCredentialsError( - 'Unable to parse TOKEN from the page' - ) + try: + # fetch text + pagehead = pagetree.head + text = pagehead.text_content() + #print(text) - return self.token + #search + token_js_func = text[ + text.index("const COOKIE_PREFIX = \"ATERNOS\";") + + len("const COOKIE_PREFIX = \"ATERNOS\";") : + text.index("(function(i,s,o,g,r,a,m)") + ].strip() + print(token_js_func) - def generate_sec(self) -> str: - randkey = self.generate_aternos_rand() - randval = self.generate_aternos_rand() - self.sec = f'{randkey}:{randval}' - self.session.cookies.set( - f'ATERNOS_SEC_{randkey}', randval, - domain='aternos.org' - ) + # run js + ctx = MiniRacer() + result = ctx.eval(presettings + token_js_func) + result = ctx.call('__log') + + print(result) + + if 'win_var' in result and result['win_var']: + result = result['win_var'] + elif '1' in result and ('2' in result and not result['2']): + result = base64.standard_b64decode(result['1']) + else: + result = base64.standard_b64decode(result['2']) - return self.sec - def generate_aternos_rand(self, randlen:int=16) -> str: + print(result) + self.token = result + + """ + self.token = re.search( + r'const\s+AJAX_TOKEN\s*=\s*["\'](\w+)["\']', + text + )[1] + """ + except (IndexError, TypeError): + raise aterrors.AternosCredentialsError( + 'Unable to parse TOKEN from the page' + ) - rand_arr = [] - for i in range(randlen+1): - rand_arr.append('') + return self.token - rand_alphanum = \ - self.convert_num(random.random(),36) + \ - '00000000000000000' - return (rand_alphanum[2:18].join(rand_arr)[:randlen]) + def generate_sec(self) -> str: - def convert_num(self, num:Union[int,float], base:int) -> str: + randkey = self.generate_aternos_rand() + randval = self.generate_aternos_rand() + self.sec = f'{randkey}:{randval}' + self.session.cookies.set( + f'ATERNOS_SEC_{randkey}', randval, + domain='aternos.org' + ) - result = '' - while num > 0: - result = str(num % base) + result - num //= base - return result + return self.sec - def request_cloudflare( - self, url:str, method:int, - retries:int=10, - params:Optional[dict]=None, - data:Optional[dict]=None, - headers:Optional[dict]=None, - reqcookies:Optional[dict]=None, - sendtoken:bool=False) -> Response: + def generate_aternos_rand(self, randlen:int=16) -> str: - cftitle = 'Please Wait... | Cloudflare' + rand_arr = [] + for i in range(randlen+1): + rand_arr.append('') - if sendtoken: - if params == None: - params = {} - params['SEC'] = self.sec - params['TOKEN'] = self.token + rand_alphanum = \ + self.convert_num(random.random(),36) + \ + '00000000000000000' + return (rand_alphanum[2:18].join(rand_arr)[:randlen]) - if headers == None: - headers = {} - headers['User-Agent'] = REQUA + def convert_num(self, num:Union[int,float], base:int) -> str: - try: - cookies = self.session.cookies - except AttributeError: - cookies = None + result = '' + while num > 0: + result = str(num % base) + result + num //= base + return result - self.session = CloudScraper() - if cookies != None: - self.session.cookies = cookies + def request_cloudflare( + self, url:str, method:int, + retries:int=10, + params:Optional[dict]=None, + data:Optional[dict]=None, + headers:Optional[dict]=None, + reqcookies:Optional[dict]=None, + sendtoken:bool=False) -> Response: - if method == REQPOST: - req = self.session.post( - url, - data=data, - headers=headers, - cookies=reqcookies - ) - else: - req = self.session.get( - url, - params=params, - headers=headers, - cookies=reqcookies - ) + cftitle = 'Please Wait... | Cloudflare' - countdown = retries - while cftitle in req.text \ - and (countdown > 0): + if sendtoken: + if params == None: + params = {} + params['SEC'] = self.sec + params['TOKEN'] = self.token - self.session = CloudScraper() - if cookies != None: - self.session.cookies = cookies - if reqcookies != None: - for cookiekey in reqcookies: - self.session.cookies.set(cookiekey, reqcookies[cookiekey]) + if headers == None: + headers = {} + headers['User-Agent'] = REQUA - time.sleep(1) - if method == REQPOST: - req = self.session.post( - url, - data=data, - headers=headers, - cookies=reqcookies - ) - else: - req = self.session.get( - url, - params=params, - headers=headers, - cookies=reqcookies - ) - countdown -= 1 + try: + cookies = self.session.cookies + except AttributeError: + cookies = None - return req + self.session = CloudScraper() + if cookies != None: + self.session.cookies = cookies + + if method == REQPOST: + req = self.session.post( + url, + data=data, + headers=headers, + cookies=reqcookies + ) + else: + req = self.session.get( + url, + params=params, + headers=headers, + cookies=reqcookies + ) + + countdown = retries + while cftitle in req.text \ + and (countdown > 0): + + self.session = CloudScraper() + if cookies != None: + self.session.cookies = cookies + if reqcookies != None: + for cookiekey in reqcookies: + self.session.cookies.set(cookiekey, reqcookies[cookiekey]) + + time.sleep(1) + if method == REQPOST: + req = self.session.post( + url, + data=data, + headers=headers, + cookies=reqcookies + ) + else: + req = self.session.get( + url, + params=params, + headers=headers, + cookies=reqcookies + ) + countdown -= 1 + + return req diff --git a/racer_test.py b/racer_test.py new file mode 100755 index 0000000..23b50ec --- /dev/null +++ b/racer_test.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 + +from py_mini_racer import MiniRacer +import base64 + +# Set function for manage global vars +presettings = """ +let window = {1: null, 2: null, AJAX_TOKEN: null}; +let i = 1; +function __log() { return {win_var: window["AJAX_TOKEN"], 1: window[1], 2: window[2]} }; +function atob(arg) {window[i++] = arg;}; +""" + +# Test cases +tests = [ + """(() => {window[("A" + "J" + "AX_T" + "OKE" + "N")]=("2iXh5W5u" + "EYq" + "5fWJIa" + "zQ6");})();""", + """ (() => {window[["N","TOKE","AJAX_"].reverse().join('')]=["IazQ6","fWJ","h5W5uEYq5","2iX"].reverse().join('');})();""", + """(() => {window["AJAX_TOKEN"] = atob("SGVsbG8sIHdvcmxk")})();""", + """(() => {window[atob('QUpBWF9UT0tFTg==')]=atob('MmlYaDVXNXVFWXE1ZldKSWF6UTY=');})();""", + """(() => {window["AJAX_TOKEN"] = "1234" })();""", + """(() => {window[atob('QUpBWF9UT0tFTg==')]="2iXh5W5uEYq5fWJIazQ6";})();""", +] + +# Emulate 'atob' function +#print(base64.standard_b64decode('MmlYaDVXNXVFWXE1ZldKSWF6UTY=')) + +for js in tests: + ctx = MiniRacer() + result = ctx.eval(presettings + js) + result = ctx.call('__log') + + print(result) + ''' + if 'win_var' in result and result['win_var']: + result = result['win_var'] + elif '1' in result and ('2' in result and not result['2']): + result = base64.standard_b64decode(result['1']) + else: + result = base64.standard_b64decode(result['2']) + ''' + print('Case:\n', js, '\n') + print('Result: \n', result, '\n') + print('-' * 30, '\n') + + diff --git a/requirements.txt b/requirements.txt index 9d74376..8c37f68 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ lxml==4.6.2 requests==2.25.1 cloudscraper==1.2.58 +py-mini-racer==0.6.0