From 3a3f0b452a9a3d3a99643ad3412f451faacde5e1 Mon Sep 17 00:00:00 2001 From: Ihor Date: Thu, 13 Jun 2024 23:47:35 +0300 Subject: [PATCH 1/8] - Added fix for login; --- .dockerignore | 1 + .gitignore | 1 + Dockerfile | 8 ++-- bot/config/proxies.txt | 2 +- bot/core/headers.py | 4 +- bot/core/tapper.py | 30 ++++++++++----- bot/utils/launcher.py | 9 +++-- bot/utils/scripts.py | 82 ++++++++++++++++++++++++++++------------- docker-compose.yml | 4 +- requirements.txt | Bin 960 -> 1052 bytes 10 files changed, 92 insertions(+), 49 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5ba63ab --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +webdriver diff --git a/.gitignore b/.gitignore index 71d8a95..0f80144 100644 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,4 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ +webdriver/ diff --git a/Dockerfile b/Dockerfile index 53bff59..bd6175d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,12 @@ FROM python:3.10.11-alpine3.18 -WORKDIR app/ +WORKDIR /app -COPY requirements.txt requirements.txt +COPY . /app RUN pip3 install --upgrade pip setuptools wheel RUN pip3 install --no-warn-script-location --no-cache-dir -r requirements.txt -COPY . . +RUN apk add --no-cache firefox -CMD ["python3", "main.py", "-a", "2"] \ No newline at end of file +CMD ["python3", "main.py", "-a", "2"] diff --git a/bot/config/proxies.txt b/bot/config/proxies.txt index b34bca3..424feca 100644 --- a/bot/config/proxies.txt +++ b/bot/config/proxies.txt @@ -2,4 +2,4 @@ type://user:pass@ip:port type://user:pass:ip:port type://ip:port:user:pass type://ip:port@user:pass -type://ip:port \ No newline at end of file +type://ip:port diff --git a/bot/core/headers.py b/bot/core/headers.py index 191f2cb..9b251db 100644 --- a/bot/core/headers.py +++ b/bot/core/headers.py @@ -13,6 +13,6 @@ 'Sec-Ch-Ua-Mobile': '?1', 'Sec-Ch-Ua-Platform': '"Android"', 'X-App': 'tapswap_server', - 'X-Cv': '621', - 'X-bot': 'no' + 'X-Bot': 'no', + 'X-Cv': '624', } diff --git a/bot/core/tapper.py b/bot/core/tapper.py index b0dfeb7..2792e88 100644 --- a/bot/core/tapper.py +++ b/bot/core/tapper.py @@ -1,6 +1,7 @@ import asyncio from time import time from random import randint +import traceback from urllib.parse import unquote import aiohttp @@ -19,10 +20,11 @@ class Tapper: - def __init__(self, tg_client: Client): + def __init__(self, tg_client: Client, lock: asyncio.Lock): self.session_name = tg_client.name self.tg_client = tg_client self.user_id = 0 + self.lock = lock async def get_tg_web_data(self, proxy: str | None) -> str: if proxy: @@ -97,24 +99,32 @@ async def login(self, http_client: aiohttp.ClientSession, tg_web_data: str) -> t response.raise_for_status() response_json = await response.json() + wait_s = response_json.get('wait_s') + if wait_s: + logger.error(f"{self.session_name} | App overloaded, waiting for: {wait_s}") + await asyncio.sleep(delay=wait_s) + return self.login(http_client, tg_web_data) + chq = response_json.get('chq') + if chq: - chq_result = extract_chq(chq=chq) + async with self.lock: + chq_result = extract_chq(chq=chq) - response = await http_client.post(url='https://api.tapswap.ai/api/account/login', - json={"chr": chq_result, "init_data": tg_web_data, "referrer": ""}) - response_text = await response.text() - response.raise_for_status() + response = await http_client.post(url='https://api.tapswap.ai/api/account/login', + json={"chr": chq_result, "init_data": tg_web_data, "referrer": ""}) + response_text = await response.text() + response.raise_for_status() response_json = await response.json() - access_token = response_json['access_token'] profile_data = response_json return profile_data, access_token except Exception as error: + traceback.print_exc() logger.error(f"{self.session_name} | Unknown error while getting Access Token: {error} | " - f"Response text: {escape_html(response_text)[:128]}...") + f"Response text: {escape_html(response_text)}...") await asyncio.sleep(delay=3) async def apply_boost(self, http_client: aiohttp.ClientSession, boost_type: str) -> bool: @@ -391,8 +401,8 @@ async def run(self, proxy: str | None) -> None: await asyncio.sleep(delay=sleep_between_clicks) -async def run_tapper(tg_client: Client, proxy: str | None): +async def run_tapper(tg_client: Client, proxy: str | None, lock: asyncio.Lock): try: - await Tapper(tg_client=tg_client).run(proxy=proxy) + await Tapper(tg_client=tg_client, lock=lock).run(proxy=proxy) except InvalidSession: logger.error(f"{tg_client.name} | Invalid Session") diff --git a/bot/utils/launcher.py b/bot/utils/launcher.py index 7e33a4d..5ea5dc9 100644 --- a/bot/utils/launcher.py +++ b/bot/utils/launcher.py @@ -15,9 +15,9 @@ start_text = """ -▀▀█▀▀ █▀▀█ █▀▀█ ░█▀▀▀█ █ █ █▀▀█ █▀▀█ ░█▀▀█ █▀▀█ ▀▀█▀▀ - ░█ █▄▄█ █ █ ▀▀▀▄▄ █▄█▄█ █▄▄█ █ █ ░█▀▀▄ █ █ █ - ░█ ▀ ▀ █▀▀▀ ░█▄▄▄█ ▀ ▀ ▀ ▀ █▀▀▀ ░█▄▄█ ▀▀▀▀ ▀ +▀▀█▀▀ █▀▀█ █▀▀█ ░█▀▀▀█ █ █ █▀▀█ █▀▀█ ░█▀▀█ █▀▀█ ▀▀█▀▀ + ░█ █▄▄█ █ █ ▀▀▀▄▄ █▄█▄█ █▄▄█ █ █ ░█▀▀▄ █ █ █ + ░█ ▀ ▀ █▀▀▀ ░█▄▄▄█ ▀ ▀ ▀ ▀ █▀▀▀ ░█▄▄█ ▀▀▀▀ ▀ Select an action: @@ -111,11 +111,14 @@ async def process() -> None: async def run_tasks(tg_clients: list[Client]): proxies = get_proxies() proxies_cycle = cycle(proxies) if proxies else None + lock = asyncio.Lock() + tasks = [ asyncio.create_task( run_tapper( tg_client=tg_client, proxy=next(proxies_cycle) if proxies_cycle else None, + lock=lock, ) ) for tg_client in tg_clients diff --git a/bot/utils/scripts.py b/bot/utils/scripts.py index b1d80e8..cf3f032 100644 --- a/bot/utils/scripts.py +++ b/bot/utils/scripts.py @@ -1,12 +1,45 @@ -import re +import os import asyncio from typing import Union from pyrogram import Client from pyrogram.types import Message -from bs4 import BeautifulSoup from bot.utils.emojis import num, StaticEmoji +from bot.utils import logger +from bs4 import BeautifulSoup + +import pathlib +import shutil +from selenium import webdriver + + +if os.name == "posix": + from selenium.webdriver.firefox.service import Service as FirefoxService + from selenium.webdriver.firefox.options import Options as FirefoxOptions + from webdriver_manager.firefox import GeckoDriverManager + + web_options = FirefoxOptions + web_service = FirefoxService + web_manager = GeckoDriverManager +else: + from selenium.webdriver.chrome.service import Service as ChromeService + from selenium.webdriver.chrome.options import Options as ChromeOptions + from webdriver_manager.chrome import ChromeDriverManager + + web_options = ChromeOptions + web_service = ChromeService + web_manager = ChromeDriverManager + + +if not pathlib.Path("webdriver").exists(): + logger.info("Downloading webdriver. It may take some time...") + pathlib.Path("webdriver").mkdir(parents=True) + webdriver_path = pathlib.Path(web_manager().install()) + shutil.move(webdriver_path, f"webdriver/{webdriver_path.name}") + logger.info("Webdriver downloaded successfully") + +webdriver_path = next(pathlib.Path("webdriver").iterdir()).as_posix() def get_command_args( @@ -16,18 +49,14 @@ def get_command_args( ) -> str: if isinstance(message, str): return message.split(f"{prefixes}{command}", maxsplit=1)[-1].strip() - if isinstance(command, str): args = message.text.split(f"{prefixes}{command}", maxsplit=1)[-1].strip() return args - elif isinstance(command, list): for cmd in command: args = message.text.split(f"{prefixes}{cmd}", maxsplit=1)[-1] - if args != message.text: return args.strip() - return "" @@ -54,6 +83,7 @@ def get_help_text(): """ + async def stop_tasks(client: Client = None) -> None: if client: all_tasks = asyncio.all_tasks(loop=client.loop) @@ -70,12 +100,15 @@ async def stop_tasks(client: Client = None) -> None: except: ... - def escape_html(text: str) -> str: return text.replace('<', '\\<').replace('>', '\\>') def extract_chq(chq: str) -> int: + options = web_options() + options.add_argument("--headless") + driver = webdriver.Firefox(service=web_service(webdriver_path), options=options) + chq_length = len(chq) bytes_array = bytearray(chq_length // 2) @@ -85,28 +118,25 @@ def extract_chq(chq: str) -> int: bytes_array[i // 2] = int(chq[i:i + 2], 16) xor_bytes = bytearray(t ^ xor_key for t in bytes_array) - decoded_xor = xor_bytes.decode('unicode_escape') + decoded_xor = xor_bytes.decode('utf-8') - html = re.search(r'innerHTML.+?=(.+?);', decoded_xor, re.DOTALL | re.I | re.M).group(1).strip() - html = re.sub(r"\'\+\'", "", html, flags=re.M | re.I) - soup = BeautifulSoup(html, 'html.parser') + driver.execute_script(""" + var chrStub = document.createElement("div"); + chrStub.id = "_chr_"; + document.body.appendChild(chrStub); + """) - div_elements = soup.find_all('div') - codes = {} - for div in div_elements: - if 'id' in div.attrs and '_v' in div.attrs: - codes[div['id']] = div['_v'] + fixed_xor = repr(decoded_xor).replace("`", "\\`") - va = re.search(r'''var(?:\s+)?i(?:\s+)?=.+?\([\'\"](\w+)[\'\"]\).+?,''', decoded_xor, flags=re.M | re.I).group(1) - vb = re.search(r'''\,(?:\s+)?j(?:\s+)?=.+?\([\'\"](\w+)[\'\"]\).+?,''', decoded_xor, flags=re.M | re.I).group(1) - r = re.search(r'''k(?:\s+)?%=(?:\s+)?(\w+)''', decoded_xor, flags=re.M | re.I).group(1) + k = driver.execute_script(f""" + try {{ + return eval(`{fixed_xor[1:-1]}`); + }} catch (e) {{ + return e; + }} + """) - i = int(codes[va]) - j = int(codes[vb]) - k = int(i) - - k *= k - k *= j - k %= int(r, 16) + driver.quit() return k + diff --git a/docker-compose.yml b/docker-compose.yml index 124954f..3e58133 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,9 @@ version: '3' services: - bot: + tapswap-bot: container_name: 'TapSwapBot' build: context: . stop_signal: SIGINT restart: unless-stopped command: "python3 main.py -a 2" - volumes: - - .:/app \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 08997e5e502a6249bc6123f7eb324e807036d678..f915e69dbbecea65b5e3dbc570d3a4ca43db0c7d 100644 GIT binary patch delta 100 zcmX@WK8It&0p^%uhE#?eAkJgRWGH3GWv~T869zp7BL+htX~4kCz{OAwluu$vVJHHs eDFd>L7<7Ru6M=dX8PdUgm@WgL9z(DmkUjwSiV(a2 delta 7 OcmbQkae#fp0cHRT>H^;Y From 98fad594f48f48d1243ae7d200a982c257c4a528 Mon Sep 17 00:00:00 2001 From: Ihor Date: Thu, 13 Jun 2024 23:58:35 +0300 Subject: [PATCH 2/8] Added webdriver check; --- bot/utils/scripts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/utils/scripts.py b/bot/utils/scripts.py index cf3f032..540daba 100644 --- a/bot/utils/scripts.py +++ b/bot/utils/scripts.py @@ -32,7 +32,7 @@ web_manager = ChromeDriverManager -if not pathlib.Path("webdriver").exists(): +if not pathlib.Path("webdriver").exists() or len(list(pathlib.Path("webdriver").iterdir())) == 0: logger.info("Downloading webdriver. It may take some time...") pathlib.Path("webdriver").mkdir(parents=True) webdriver_path = pathlib.Path(web_manager().install()) From c9e65611bc484ddddf8aebcb70e79779d577cbc8 Mon Sep 17 00:00:00 2001 From: Ihor Date: Fri, 14 Jun 2024 00:02:27 +0300 Subject: [PATCH 3/8] - Fixed exists ok; --- bot/utils/scripts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/utils/scripts.py b/bot/utils/scripts.py index 540daba..b2ddb32 100644 --- a/bot/utils/scripts.py +++ b/bot/utils/scripts.py @@ -34,7 +34,7 @@ if not pathlib.Path("webdriver").exists() or len(list(pathlib.Path("webdriver").iterdir())) == 0: logger.info("Downloading webdriver. It may take some time...") - pathlib.Path("webdriver").mkdir(parents=True) + pathlib.Path("webdriver").mkdir(parents=True, exist_ok=True) webdriver_path = pathlib.Path(web_manager().install()) shutil.move(webdriver_path, f"webdriver/{webdriver_path.name}") logger.info("Webdriver downloaded successfully") From 706c9bebe4a1ff9e2eb7a88f413f2dfaf65f5f65 Mon Sep 17 00:00:00 2001 From: Ihor Date: Fri, 14 Jun 2024 00:35:19 +0300 Subject: [PATCH 4/8] - Added install.sh for Linux; --- install.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 install.sh diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..b0dfb23 --- /dev/null +++ b/install.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Update package list and install prerequisites +echo "Updating package list and installing prerequisites..." +sudo apt update +sudo apt install -y software-properties-common + +# Add Mozilla Team PPA +echo "Adding Mozilla Team PPA..." +sudo add-apt-repository -y ppa:mozillateam/ppa + +# Set package pinning preferences +echo "Setting package pinning preferences..." +sudo tee /etc/apt/preferences.d/mozilla-firefox < Date: Fri, 14 Jun 2024 00:49:55 +0300 Subject: [PATCH 5/8] Typo fix and speedup; --- bot/utils/scripts.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/bot/utils/scripts.py b/bot/utils/scripts.py index b2ddb32..8535510 100644 --- a/bot/utils/scripts.py +++ b/bot/utils/scripts.py @@ -22,6 +22,7 @@ web_options = FirefoxOptions web_service = FirefoxService web_manager = GeckoDriverManager + web_driver = webdriver.Firefox else: from selenium.webdriver.chrome.service import Service as ChromeService from selenium.webdriver.chrome.options import Options as ChromeOptions @@ -30,7 +31,7 @@ web_options = ChromeOptions web_service = ChromeService web_manager = ChromeDriverManager - + web_driver = webdriver.Chrome if not pathlib.Path("webdriver").exists() or len(list(pathlib.Path("webdriver").iterdir())) == 0: logger.info("Downloading webdriver. It may take some time...") @@ -41,6 +42,10 @@ webdriver_path = next(pathlib.Path("webdriver").iterdir()).as_posix() +options = web_options() +options.add_argument("--headless") +driver = web_driver(service=web_service(webdriver_path), options=options) + def get_command_args( message: Union[Message, str], @@ -105,10 +110,6 @@ def escape_html(text: str) -> str: def extract_chq(chq: str) -> int: - options = web_options() - options.add_argument("--headless") - driver = webdriver.Firefox(service=web_service(webdriver_path), options=options) - chq_length = len(chq) bytes_array = bytearray(chq_length // 2) @@ -136,7 +137,5 @@ def extract_chq(chq: str) -> int: }} """) - driver.quit() - return k From 975902cc42482f72b9b9e0e14d07f6aa67dfe597 Mon Sep 17 00:00:00 2001 From: Ihor Date: Fri, 14 Jun 2024 01:19:47 +0300 Subject: [PATCH 6/8] - Added disabling Chrome after sessions are created; --- bot/utils/scripts.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/bot/utils/scripts.py b/bot/utils/scripts.py index 8535510..58e68e2 100644 --- a/bot/utils/scripts.py +++ b/bot/utils/scripts.py @@ -1,3 +1,4 @@ +import glob import os import asyncio from typing import Union @@ -12,6 +13,19 @@ import pathlib import shutil from selenium import webdriver +from multiprocessing import Queue + + + +def get_session_names() -> list[str]: + session_names = glob.glob("sessions/*.session") + session_names = [ + os.path.splitext(os.path.basename(file))[0] for file in session_names + ] + + return session_names + + if os.name == "posix": @@ -46,6 +60,8 @@ options.add_argument("--headless") driver = web_driver(service=web_service(webdriver_path), options=options) +session_queue = Queue() + def get_command_args( message: Union[Message, str], @@ -137,5 +153,11 @@ def extract_chq(chq: str) -> int: }} """) + session_queue.put(1) + + if len(get_session_names()) == session_queue.qsize(): + logger.info("All sessions are closed. Quitting driver...") + driver.quit() + return k From 9ed67302164107eda88aa60db8acdadc977dcb3b Mon Sep 17 00:00:00 2001 From: Ihor Date: Fri, 14 Jun 2024 01:30:01 +0300 Subject: [PATCH 7/8] - Added driver auto-close and open; --- bot/utils/scripts.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bot/utils/scripts.py b/bot/utils/scripts.py index 58e68e2..b32269d 100644 --- a/bot/utils/scripts.py +++ b/bot/utils/scripts.py @@ -58,7 +58,7 @@ def get_session_names() -> list[str]: options = web_options() options.add_argument("--headless") -driver = web_driver(service=web_service(webdriver_path), options=options) +driver = None session_queue = Queue() @@ -126,6 +126,11 @@ def escape_html(text: str) -> str: def extract_chq(chq: str) -> int: + global driver + + if driver is None: + driver = web_driver(service=web_service(webdriver_path), options=options) + chq_length = len(chq) bytes_array = bytearray(chq_length // 2) @@ -158,6 +163,10 @@ def extract_chq(chq: str) -> int: if len(get_session_names()) == session_queue.qsize(): logger.info("All sessions are closed. Quitting driver...") driver.quit() + driver = None + + while session_queue.qsize() > 0: + session_queue.get() return k From 3e26d1c253c9f166868fdf609cfb40decdfd7ce5 Mon Sep 17 00:00:00 2001 From: headNbyte <36804465+headNbyte@users.noreply.github.com> Date: Fri, 14 Jun 2024 05:53:32 +0300 Subject: [PATCH 8/8] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f52a101..a0678ad 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ ~/TapSwapBot >>> pip3 install -r requirements.txt ~/TapSwapBot >>> cp .env-example .env ~/TapSwapBot >>> nano .env # Здесь вы обязательно должны указать ваши API_ID и API_HASH , остальное берется по умолчанию +~/TapSwapBot >>> sh install.sh ~/TapSwapBot >>> python3 main.py # Windows